/* Get the mean for one of the coarse estimate points. If it seems that this * value might be (or close) causing us to clamp, adjust it and retry */ static int rx_cal_coarse_means(struct rx_cal *cal, int16_t *corr_value, float *mean_i, float *mean_q) { int status; const int16_t mean_limit_high = 2000; const int16_t mean_limit_low = -mean_limit_high; const int16_t corr_limit = 128; bool retry = false; do { status = set_rx_dc_corr(cal->dev, *corr_value, *corr_value); if (status != 0) { return status; } status = rx_samples(cal->dev, cal->samples, cal->num_samples, &cal->ts, RX_CAL_TS_INC); if (status != 0) { return status; } sample_mean(cal->samples, cal->num_samples, mean_i, mean_q); if (*mean_i > mean_limit_high || *mean_q > mean_limit_high || *mean_i < mean_limit_low || *mean_q < mean_limit_low ) { if (*corr_value < 0) { retry = (*corr_value <= -corr_limit); } else { retry = (*corr_value >= corr_limit); } if (retry) { PR_DBG("Coarse estimate point Corr=%4d yields extreme means: " "(%4f, %4f). Retrying...\n", *corr_value, *mean_i, *mean_q); *corr_value = *corr_value / 2; } } else { retry = false; } } while (retry); if (retry) { PR_DBG("Non-ideal values are being used.\n"); } return 0; }
/* Estimate the DC correction values that yield zero DC offset via a linear * approximation */ static int rx_cal_coarse_estimate(struct rx_cal *cal, int16_t *i_est, int16_t *q_est) { int status; int16_t x1 = -2048; int16_t x2 = 2048; float y1i, y1q, y2i, y2q; float mi, mq; float bi, bq; float i_guess, q_guess; status = rx_cal_coarse_means(cal, &x1, &y1i, &y1q); if (status != 0) { *i_est = 0; *q_est = 0; return status; } PR_VERBOSE("Means for x1=%d: y1i=%f, y1q=%f\n", x1, y1i, y1q); status = rx_cal_coarse_means(cal, &x2, &y2i, &y2q); if (status != 0) { *i_est = 0; *q_est = 0; return status; } PR_VERBOSE("Means for x2: y2i=%f, y2q=%f\n", y2i, y2q); mi = (y2i - y1i) / (x2 - x1); mq = (y2q - y1q) / (x2 - x1); bi = y1i - mi * x1; bq = y1q - mq * x1; PR_VERBOSE("mi=%f, bi=%f, mq=%f, bq=%f\n", mi, bi, mq, bq); i_guess = -bi/mi + 0.5f; if (i_guess < -2048) { i_guess = -2048; } else if (i_guess > 2048) { i_guess = 2048; } q_guess = -bq/mq + 0.5f; if (q_guess < -2048) { q_guess = -2048; } else if (q_guess > 2048) { q_guess = 2048; } *i_est = (int16_t) i_guess; *q_est = (int16_t) q_guess; PR_DBG("Coarse estimate: I=%d, Q=%d\n", *i_est, *q_est); return 0; }
/* Ensure TX >= 1 MHz away from the RX frequency to avoid any potential * artifacts from the PLLs interfering with one another */ static int rx_cal_update_frequency(struct rx_cal *cal, uint64_t rx_freq) { int status = 0; uint64_t f_diff; if (rx_freq < cal->tx_freq) { f_diff = cal->tx_freq - rx_freq; } else { f_diff = rx_freq - cal->tx_freq; } PR_DBG("Set F_RX = %u\n", rx_freq); PR_DBG("F_diff(RX, TX) = %u\n", f_diff); if (f_diff < 1000000) { if (rx_freq >= (BLADERF_FREQUENCY_MIN + 1000000)) { cal->tx_freq = rx_freq - 1000000; } else { cal->tx_freq = rx_freq + 1000000; } status = bladerf_set_frequency(cal->dev, BLADERF_MODULE_TX, cal->tx_freq); if (status != 0) { return status; } PR_DBG("Adjusted TX frequency: %u\n", cal->tx_freq); } status = bladerf_set_frequency(cal->dev, BLADERF_MODULE_RX, rx_freq); if (status != 0) { return status; } cal->ts += RX_CAL_TS_INC; return status; }
static void init_rx_cal_sweep(int16_t *corr, unsigned int *sweep_len, int16_t i_est, int16_t q_est) { unsigned int actual_len = 0; unsigned int i; int16_t sweep_min, sweep_max, sweep_val; /* LMS6002D RX DC calibrations have a limited range. libbladeRF throws away * the lower 5 bits. */ const int16_t sweep_inc = 32; const int16_t min_est = (i_est < q_est) ? i_est : q_est; const int16_t max_est = (i_est > q_est) ? i_est : q_est; sweep_min = min_est - 12 * 32; if (sweep_min < -2048) { sweep_min = -2048; } sweep_max = max_est + 12 * 32; if (sweep_max > 2048) { sweep_max = 2048; } /* Given that these lower bits are thrown away, it can be confusing to * see that values change in their LSBs that don't matter. Therefore, * we'll adjust to muliples of sweep_inc */ sweep_min = (sweep_min / 32) * 32; sweep_max = (sweep_max / 32) * 32; PR_DBG("Sweeping [%d : %d : %d]\n", sweep_min, sweep_inc, sweep_max); sweep_val = sweep_min; for (i = 0; sweep_val < sweep_max && i < RX_CAL_MAX_SWEEP_LEN; i++) { corr[i] = sweep_val; sweep_val += sweep_inc; actual_len++; } *sweep_len = actual_len; }
/* * Check getting attributes. */ static sns_ddf_status_e bmp085_get_all_attrib(sns_ddf_handle_t dd_handle, sns_ddf_memhandler_s memhandler) { sns_ddf_status_e status; uint32_t num_elements = 0; sns_ddf_power_info_s *power_info = NULL; sns_ddf_range_s *range = NULL; sns_ddf_resolution_t *resolution = NULL; sns_ddf_lowpass_freq_t *freq = NULL; sns_ddf_delays_s *delay = NULL; sns_ddf_driver_info_s *driver_info = NULL; sns_ddf_device_info_s *device_info = NULL; int i; status = sns_alt_bmp085_driver_fn_list.get_attrib(dd_handle, SNS_DDF_SENSOR_PRESSURE, SNS_DDF_ATTRIB_POWER_INFO, &memhandler, (void **)&power_info, &num_elements); if (status) { return status; } for (i = 0; i < num_elements; i++) { PR_DBG("BMP085: active_current[i] = %d. uA\n", power_info->active_current); PR_DBG("BMP085: low-power current[i] = %d. uA \n", power_info->lowpower_current); } status = sns_alt_bmp085_driver_fn_list.get_attrib(dd_handle, SNS_DDF_SENSOR_PRESSURE, SNS_DDF_ATTRIB_RANGE, &memhandler, (void **)&range, &num_elements); if (status) { return status; } for (i = 0; i < num_elements; i++) { PR_DBG("BMP085: range[i]: min=%d, max=%d.\n", FX_TRUNC_Q16(range[i].min), FX_TRUNC_Q16(range[i].max)); } status = sns_alt_bmp085_driver_fn_list.get_attrib(dd_handle, SNS_DDF_SENSOR_PRESSURE, SNS_DDF_ATTRIB_RESOLUTION, &memhandler, (void **)&resolution, &num_elements); if (status) { return status; } for (i = 0; i < num_elements; i++) { PR_DBG("BMP085: resolution[i] = %d.\n", resolution[i]); } status = sns_alt_bmp085_driver_fn_list.get_attrib(dd_handle, SNS_DDF_SENSOR_PRESSURE, SNS_DDF_ATTRIB_LOWPASS, &memhandler, (void **)&freq, &num_elements); if (status == 0) { return SNS_DDF_EFAIL; /* LOWPASS NOT SUPPORTED */ } status = sns_alt_bmp085_driver_fn_list.get_attrib(dd_handle, SNS_DDF_SENSOR_PRESSURE, SNS_DDF_ATTRIB_DELAYS, &memhandler, (void **)&delay, &num_elements); if (status) { return status; } for (i = 0; i < num_elements; i++) { PR_DBG("BMP085: delay time_to_active= %d usec.\n", delay->time_to_active); PR_DBG("BMP085: delay time_to_data= %d usec.\n", delay->time_to_data); } status = sns_alt_bmp085_driver_fn_list.get_attrib(dd_handle, SNS_DDF_SENSOR_PRESSURE, SNS_DDF_ATTRIB_DRIVER_INFO, &memhandler, (void **)&driver_info, &num_elements); if (status) { return status; } for (i = 0; i < num_elements; i++) { PR_DBG("BMP085: driver_info name=%s,version=%s.\n", driver_info->name, driver_info->version); } status = sns_alt_bmp085_driver_fn_list.get_attrib(dd_handle, SNS_DDF_SENSOR_PRESSURE, SNS_DDF_ATTRIB_DEVICE_INFO, &memhandler, (void **)&device_info, &num_elements); if (status) { return status; } for (i = 0; i < num_elements; i++) { PR_DBG("BMP085: device_info name=%s,vendor=%s,model=%s,version=%s.\n", device_info->name, device_info->vendor, device_info->model, device_info->version); } return SNS_DDF_SUCCESS; }
/* * Test main function. */ sns_ddf_status_e sns_dd_alt_bmp085_on_target_test_main(void) { sns_ddf_device_access_s device_info; sns_ddf_i2c_config_s i2c_config; uint32_t num_sensors = 0; sns_ddf_sensor_e *sensors = NULL; sns_ddf_handle_t dd_handle = NULL; sns_ddf_handle_t smgr_handle = NULL; sns_ddf_nv_params_s *nv_params = NULL; sns_ddf_memhandler_s memhandler; sns_ddf_sensor_data_s *data = NULL; sns_ddf_status_e status; /* Device Info */ device_info.device_select = 0; device_info.port_config.bus = SNS_DDF_BUS_I2C; device_info.port_config.bus_config.i2c = &i2c_config; /* I2C Info */ i2c_config.addr_type = SNS_DDF_I2C_ADDR_7BIT; i2c_config.bus_acq_timeout = -1; i2c_config.xfer_timeout = -1; i2c_config.bus_freq = 400; i2c_config.dev_type = SNS_DDF_I2C_DEVICE_REGADDR; i2c_config.read_opt = SNS_DDF_I2C_START_BEFORE_RD; i2c_config.slave_addr = 0xEE/2; /* get memory handler */ sns_ddf_memhandler_init(&memhandler); status = sns_alt_bmp085_driver_fn_list.init( &dd_handle, smgr_handle, nv_params, &device_info, 1, &memhandler, &sensors, &num_sensors); if (status != SNS_DDF_SUCCESS) { PR_ERR("error initializing\n", status); return status; } PR_DBG("num_sensors = %d.\n", num_sensors); PR_DBG("sensor type is %d.\n", *sensors); status = sns_alt_bmp085_driver_fn_list.get_data( dd_handle, &sensors[0], 1, &memhandler, &data); if (data[0].sensor != SNS_DDF_SENSOR_PRESSURE) { return SNS_DDF_EFAIL; } /* Expected Range 80K-120K Pascals = 800-1200 hPa*/ /* P=1013.25 hPa At sea level */ if ((data[0].samples->sample < FX_FLTTOFIX_Q16(800.0)) || (data[0].samples->sample > FX_FLTTOFIX_Q16(1200.0))) { return SNS_DDF_EFAIL; } status = sns_alt_bmp085_driver_fn_list.get_data( dd_handle, &sensors[1], 1, &memhandler, &data); if (data[0].sensor != SNS_DDF_SENSOR_TEMP) { return SNS_DDF_EFAIL; } /* Expected Range 30-40 °C (Celcius). Expected 22°C at the lab + It is hotter inside the Fluid/Surf/FFA. */ if ((data[0].samples->sample < FX_FLTTOFIX_Q16(30.0)) || (data[0].samples->sample > FX_FLTTOFIX_Q16(40.0))) { return SNS_DDF_EFAIL; } status = bmp085_get_all_attrib(dd_handle, memhandler); if (status != SNS_DDF_SUCCESS) { PR_ERR("Get attrib err=%d.\n", status); return SNS_DDF_EFAIL; } status = bmp085_set_all_attrib(dd_handle); if (status != SNS_DDF_SUCCESS) { PR_ERR("Set attrib err=%d.\n", status); return SNS_DDF_EFAIL; } return SNS_DDF_SUCCESS; }