int LIS3MDL::collect() { #pragma pack(push, 1) struct { /* status register and data as read back from the device */ uint8_t x[2]; uint8_t y[2]; uint8_t z[2]; uint8_t t[2]; } lis_report; struct { int16_t x; int16_t y; int16_t z; int16_t t; } report; #pragma pack(pop) int ret; // uint8_t check_counter; perf_begin(_sample_perf); struct mag_report new_report; bool sensor_is_onboard = false; float xraw_f; float yraw_f; float zraw_f; /* this should be fairly close to the end of the measurement, so the best approximation of the time */ new_report.timestamp = hrt_absolute_time(); new_report.error_count = perf_event_count(_comms_errors); /* * @note We could read the status register here, which could tell us that * we were too early and that the output registers are still being * written. In the common case that would just slow us down, and * we're better off just never being early. */ /* get measurements from the device */ ret = _interface->read(ADDR_OUT_X_L, (uint8_t *)&lis_report, sizeof(lis_report)); if (ret != OK) { perf_count(_comms_errors); DEVICE_DEBUG("data/status read error"); goto out; } /* convert the data we just received */ report.x = (((int16_t)lis_report.x[1]) << 8) + lis_report.x[0]; report.y = (((int16_t)lis_report.y[1]) << 8) + lis_report.y[0]; report.z = (((int16_t)lis_report.z[1]) << 8) + lis_report.z[0]; report.t = (((int16_t)lis_report.t[1]) << 8) + lis_report.t[0]; /* get measurements from the device */ new_report.temperature = report.t; new_report.temperature = 25 + (report.t / (16 * 8.0f)); // XXX revisit for SPI part, might require a bus type IOCTL unsigned dummy; sensor_is_onboard = !_interface->ioctl(MAGIOCGEXTERNAL, dummy); /* * RAW outputs * */ new_report.x_raw = report.x; new_report.y_raw = report.y; new_report.z_raw = report.z; /* the LIS3MDL mag on Pixhawk Pro by Drotek has x pointing towards, * y pointing to the right, and z down, therefore no switch needed, * it is better to have no artificial rotation inside the * driver and then use the startup script with -R command with the * real rotation between the sensor and body frame */ xraw_f = report.x; yraw_f = report.y; zraw_f = report.z; // apply user specified rotation rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); new_report.x = ((xraw_f * _range_scale) - _scale.x_offset) * _scale.x_scale; /* flip axes and negate value for y */ new_report.y = ((yraw_f * _range_scale) - _scale.y_offset) * _scale.y_scale; /* z remains z */ new_report.z = ((zraw_f * _range_scale) - _scale.z_offset) * _scale.z_scale; if (!(_pub_blocked)) { if (_mag_topic != nullptr) { /* publish it */ orb_publish(ORB_ID(sensor_mag), _mag_topic, &new_report); } else { _mag_topic = orb_advertise_multi(ORB_ID(sensor_mag), &new_report, &_orb_class_instance, (sensor_is_onboard) ? ORB_PRIO_HIGH : ORB_PRIO_MAX); if (_mag_topic == nullptr) { DEVICE_DEBUG("ADVERT FAIL"); } } } _last_report = new_report; /* post a report to the ring */ if (_reports->force(&new_report)) { perf_count(_buffer_overflows); } /* notify anyone waiting for data */ poll_notify(POLLIN); check_conf(); ret = OK; out: perf_end(_sample_perf); return ret; }
int SRF02_I2C::ioctl(struct file *filp, int cmd, unsigned long arg) { switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _measure_ticks = 0; return OK; /* external signalling (DRDY) not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* set interval for next measurement to minimum legal value */ _measure_ticks = USEC2TICK(_cycling_rate); /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* convert hz to tick interval via microseconds */ int ticks = USEC2TICK(1000000 / arg); /* check against maximum rate */ if (ticks < USEC2TICK(_cycling_rate)) { return -EINVAL; } /* update interval for next measurement */ _measure_ticks = ticks; /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_measure_ticks == 0) { return SENSOR_POLLRATE_MANUAL; } return (1000 / _measure_ticks); case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } irqstate_t flags = px4_enter_critical_section(); if (!_reports->resize(arg)) { px4_leave_critical_section(flags); return -ENOMEM; } px4_leave_critical_section(flags); return OK; } case SENSORIOCGQUEUEDEPTH: return _reports->size(); case SENSORIOCRESET: /* XXX implement this */ return -EINVAL; case RANGEFINDERIOCSETMINIUMDISTANCE: { set_minimum_distance(*(float *)arg); return 0; } break; case RANGEFINDERIOCSETMAXIUMDISTANCE: { set_maximum_distance(*(float *)arg); return 0; } break; default: /* give it to the superclass */ return I2C::ioctl(filp, cmd, arg); } }
ssize_t BAROSIM::devRead(void *buffer, size_t buflen) { unsigned count = buflen / sizeof(struct baro_report); struct baro_report *brp = reinterpret_cast<struct baro_report *>(buffer); int ret = 0; /* buffer must be large enough */ if (count < 1) { return -ENOSPC; } /* if automatic measurement is enabled */ if (m_sample_interval_usecs > 0) { /* * While there is space in the caller's buffer, and reports, copy them. * Note that we may be pre-empted by the workq thread while we are doing this; * we are careful to avoid racing with them. */ while (count--) { if (_reports->get(brp)) { ret += sizeof(*brp); brp++; } } /* if there was no data, warn the caller */ return ret ? ret : -EAGAIN; } /* manual measurement - run one conversion */ do { _measure_phase = 0; _reports->flush(); /* do temperature first */ if (OK != measure()) { ret = -EIO; break; } usleep(BAROSIM_CONVERSION_INTERVAL); if (OK != collect()) { ret = -EIO; break; } /* now do a pressure measurement */ if (OK != measure()) { ret = -EIO; break; } usleep(BAROSIM_CONVERSION_INTERVAL); if (OK != collect()) { ret = -EIO; break; } /* state machine will have generated a report, copy it out */ if (_reports->get(brp)) { ret = sizeof(*brp); } } while (0); return ret; }
void ACCELSIM::_measure() { #if 0 static int x = 0; // Verify the samples are being taken at the expected rate if (x == 99) { x = 0; PX4_INFO("ACCELSIM::measure %" PRIu64, hrt_absolute_time()); } else { x++; } #endif /* status register and data as read back from the device */ #pragma pack(push, 1) struct { uint8_t cmd; uint8_t status; float temperature; float x; float y; float z; } raw_accel_report; #pragma pack(pop) accel_report accel_report = {}; /* start the performance counter */ perf_begin(_accel_sample_perf); /* fetch data from the sensor */ memset(&raw_accel_report, 0, sizeof(raw_accel_report)); raw_accel_report.cmd = DIR_READ | ACC_READ; if (OK != transfer((uint8_t *)&raw_accel_report, (uint8_t *)&raw_accel_report, sizeof(raw_accel_report))) { return; } /* * 1) Scale raw value to SI units using scaling from datasheet. * 2) Subtract static offset (in SI units) * 3) Scale the statically calibrated values with a linear * dynamically obtained factor * * Note: the static sensor offset is the number the sensor outputs * at a nominally 'zero' input. Therefore the offset has to * be subtracted. * * Example: A gyro outputs a value of 74 at zero angular rate * the offset is 74 from the origin and subtracting * 74 from all measurements centers them around zero. */ accel_report.timestamp = hrt_absolute_time(); // use the temperature from the last mag reading accel_report.temperature = _last_temperature; // report the error count as the sum of the number of bad // register reads and bad values. This allows the higher level // code to decide if it should use this sensor based on // whether it has had failures accel_report.error_count = perf_event_count(_bad_registers) + perf_event_count(_bad_values); accel_report.x_raw = (int16_t)(raw_accel_report.x / _accel_range_scale); accel_report.y_raw = (int16_t)(raw_accel_report.y / _accel_range_scale); accel_report.z_raw = (int16_t)(raw_accel_report.z / _accel_range_scale); accel_report.x = raw_accel_report.x; accel_report.y = raw_accel_report.y; accel_report.z = raw_accel_report.z; accel_report.scaling = _accel_range_scale; accel_report.range_m_s2 = _accel_range_m_s2; _accel_reports->force(&accel_report); /* notify anyone waiting for data */ DevMgr::updateNotify(*this); if (!(m_pub_blocked)) { /* publish it */ // The first call to measure() is from init() and _accel_topic is not // yet initialized if (_accel_topic != nullptr) { orb_publish(ORB_ID(sensor_accel), _accel_topic, &accel_report); } } _accel_read++; /* stop the perf counter */ perf_end(_accel_sample_perf); }
int TFMINI::ioctl(device::file_t *filp, int cmd, unsigned long arg) { switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _measure_ticks = 0; return OK; /* external signalling (DRDY) not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* set interval for next measurement to minimum legal value */ _measure_ticks = USEC2TICK(_conversion_interval); /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* convert hz to tick interval via microseconds */ int ticks = USEC2TICK(1000000 / arg); /* check against maximum rate */ if (ticks < USEC2TICK(_conversion_interval)) { return -EINVAL; } /* update interval for next measurement */ _measure_ticks = ticks; /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_measure_ticks == 0) { return SENSOR_POLLRATE_MANUAL; } return (1000 / _measure_ticks); case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } ATOMIC_ENTER; if (!_reports->resize(arg)) { ATOMIC_LEAVE; return -ENOMEM; } ATOMIC_LEAVE; return OK; } case SENSORIOCRESET: /* XXX implement this */ return -EINVAL; default: /* give it to the superclass */ return CDev::ioctl(filp, cmd, arg); } }
int HMC5883::collect() { #pragma pack(push, 1) struct { /* status register and data as read back from the device */ uint8_t x[2]; uint8_t z[2]; uint8_t y[2]; } hmc_report; #pragma pack(pop) struct { int16_t x, y, z; } report; int ret; uint8_t check_counter; perf_begin(_sample_perf); struct mag_report new_report; bool sensor_is_onboard = false; float xraw_f; float yraw_f; float zraw_f; /* this should be fairly close to the end of the measurement, so the best approximation of the time */ new_report.timestamp = hrt_absolute_time(); new_report.error_count = perf_event_count(_comms_errors); new_report.range_ga = _range_ga; new_report.scaling = _range_scale; new_report.device_id = _device_id.devid; /* * @note We could read the status register here, which could tell us that * we were too early and that the output registers are still being * written. In the common case that would just slow us down, and * we're better off just never being early. */ /* get measurements from the device */ ret = _interface->read(ADDR_DATA_OUT_X_MSB, (uint8_t *)&hmc_report, sizeof(hmc_report)); if (ret != OK) { perf_count(_comms_errors); DEVICE_DEBUG("data/status read error"); goto out; } /* swap the data we just received */ report.x = (((int16_t)hmc_report.x[0]) << 8) + hmc_report.x[1]; report.y = (((int16_t)hmc_report.y[0]) << 8) + hmc_report.y[1]; report.z = (((int16_t)hmc_report.z[0]) << 8) + hmc_report.z[1]; /* * If any of the values are -4096, there was an internal math error in the sensor. * Generalise this to a simple range check that will also catch some bit errors. */ if ((abs(report.x) > 2048) || (abs(report.y) > 2048) || (abs(report.z) > 2048)) { perf_count(_comms_errors); goto out; } /* get measurements from the device */ new_report.temperature = 0; if (_conf_reg & HMC5983_TEMP_SENSOR_ENABLE) { /* if temperature compensation is enabled read the temperature too. We read the temperature every 10 samples to avoid excessive I2C traffic */ if (_temperature_counter++ == 10) { uint8_t raw_temperature[2]; _temperature_counter = 0; ret = _interface->read(ADDR_TEMP_OUT_MSB, raw_temperature, sizeof(raw_temperature)); if (ret == OK) { int16_t temp16 = (((int16_t)raw_temperature[0]) << 8) + raw_temperature[1]; new_report.temperature = 25 + (temp16 / (16 * 8.0f)); _temperature_error_count = 0; } else { _temperature_error_count++; if (_temperature_error_count == 10) { /* it probably really is an old HMC5883, and can't do temperature. Disable it */ _temperature_error_count = 0; DEVICE_DEBUG("disabling temperature compensation"); set_temperature_compensation(0); } } } else { new_report.temperature = _last_report.temperature; } } /* * RAW outputs * * to align the sensor axes with the board, x and y need to be flipped * and y needs to be negated */ new_report.x_raw = report.y; new_report.y_raw = -report.x; /* z remains z */ new_report.z_raw = report.z; /* scale values for output */ // XXX revisit for SPI part, might require a bus type IOCTL unsigned dummy; sensor_is_onboard = !_interface->ioctl(MAGIOCGEXTERNAL, dummy); new_report.is_external = !sensor_is_onboard; if (sensor_is_onboard) { // convert onboard so it matches offboard for the // scaling below report.y = -report.y; report.x = -report.x; } /* the standard external mag by 3DR has x pointing to the * right, y pointing backwards, and z down, therefore switch x * and y and invert y */ xraw_f = -report.y; yraw_f = report.x; zraw_f = report.z; // apply user specified rotation rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); new_report.x = ((xraw_f * _range_scale) - _scale.x_offset) * _scale.x_scale; /* flip axes and negate value for y */ new_report.y = ((yraw_f * _range_scale) - _scale.y_offset) * _scale.y_scale; /* z remains z */ new_report.z = ((zraw_f * _range_scale) - _scale.z_offset) * _scale.z_scale; if (!(_pub_blocked)) { if (_mag_topic != nullptr) { /* publish it */ orb_publish(ORB_ID(sensor_mag), _mag_topic, &new_report); } else { _mag_topic = orb_advertise_multi(ORB_ID(sensor_mag), &new_report, &_orb_class_instance, (sensor_is_onboard) ? ORB_PRIO_HIGH : ORB_PRIO_MAX); if (_mag_topic == nullptr) { DEVICE_DEBUG("ADVERT FAIL"); } } } _last_report = new_report; /* post a report to the ring */ _reports->force(&new_report); /* notify anyone waiting for data */ poll_notify(POLLIN); /* periodically check the range register and configuration registers. With a bad I2C cable it is possible for the registers to become corrupt, leading to bad readings. It doesn't happen often, but given the poor cables some vehicles have it is worth checking for. */ check_counter = perf_event_count(_sample_perf) % 256; if (check_counter == 0) { check_range(); } if (check_counter == 128) { check_conf(); } ret = OK; out: perf_end(_sample_perf); return ret; }
int ACCELSIM::devIOCTL(unsigned long cmd, unsigned long arg) { unsigned long ul_arg = (unsigned long)arg; switch (cmd) { case SENSORIOCSPOLLRATE: { switch (ul_arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); m_sample_interval_usecs = 0; return OK; /* external signalling not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: return devIOCTL(SENSORIOCSPOLLRATE, 1600); case SENSOR_POLLRATE_DEFAULT: return devIOCTL(SENSORIOCSPOLLRATE, ACCELSIM_ACCEL_DEFAULT_RATE); /* adjust to a legal polling interval in Hz */ default: { /* convert hz to hrt interval via microseconds */ unsigned interval = 1000000 / ul_arg; /* check against maximum sane rate */ if (interval < 500) { return -EINVAL; } /* adjust filters */ accel_set_driver_lowpass_filter((float)ul_arg, _accel_filter_x.get_cutoff_freq()); bool want_start = (m_sample_interval_usecs == 0); /* update interval for next measurement */ setSampleInterval(interval); if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (m_sample_interval_usecs == 0) { return SENSOR_POLLRATE_MANUAL; } return 1000000 / m_sample_interval_usecs; case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((ul_arg < 1) || (ul_arg > 100)) { return -EINVAL; } if (!_accel_reports->resize(ul_arg)) { return -ENOMEM; } return OK; } case SENSORIOCGQUEUEDEPTH: return _accel_reports->size(); case SENSORIOCRESET: // Nothing to do for simulator return OK; case ACCELIOCSSAMPLERATE: // No need to set internal sampling rate for simulator return OK; case ACCELIOCGSAMPLERATE: return _accel_samplerate; case ACCELIOCSLOWPASS: { return accel_set_driver_lowpass_filter((float)_accel_samplerate, (float)ul_arg); } case ACCELIOCSSCALE: { /* copy scale, but only if off by a few percent */ struct accel_calibration_s *s = (struct accel_calibration_s *) arg; float sum = s->x_scale + s->y_scale + s->z_scale; if (sum > 2.0f && sum < 4.0f) { memcpy(&_accel_scale, s, sizeof(_accel_scale)); return OK; } else { return -EINVAL; } } case ACCELIOCSRANGE: /* arg needs to be in G */ return accel_set_range(ul_arg); case ACCELIOCGRANGE: /* convert to m/s^2 and return rounded in G */ return (unsigned long)((_accel_range_m_s2) / ACCELSIM_ONE_G + 0.5f); case ACCELIOCGSCALE: /* copy scale out */ memcpy((struct accel_calibration_s *) arg, &(_accel_scale), sizeof(_accel_scale)); return OK; case ACCELIOCSELFTEST: return OK; default: /* give it to the superclass */ return VirtDevObj::devIOCTL(cmd, arg); } }
void FXOS8700CQ::measure() { /* status register and data as read back from the device */ #pragma pack(push, 1) struct { uint8_t cmd[2]; uint8_t status; int16_t x; int16_t y; int16_t z; int16_t mx; int16_t my; int16_t mz; } raw_accel_mag_report; #pragma pack(pop) accel_report accel_report; /* start the performance counter */ perf_begin(_accel_sample_perf); check_registers(); if (_register_wait != 0) { // we are waiting for some good transfers before using // the sensor again. _register_wait--; perf_end(_accel_sample_perf); return; } /* fetch data from the sensor */ memset(&raw_accel_mag_report, 0, sizeof(raw_accel_mag_report)); raw_accel_mag_report.cmd[0] = DIR_READ(FXOS8700CQ_DR_STATUS); raw_accel_mag_report.cmd[1] = ADDR_7(FXOS8700CQ_DR_STATUS); transfer((uint8_t *)&raw_accel_mag_report, (uint8_t *)&raw_accel_mag_report, sizeof(raw_accel_mag_report)); if (!(raw_accel_mag_report.status & DR_STATUS_ZYXDR)) { perf_end(_accel_sample_perf); perf_count(_accel_duplicates); return; } /* * 1) Scale raw value to SI units using scaling from datasheet. * 2) Subtract static offset (in SI units) * 3) Scale the statically calibrated values with a linear * dynamically obtained factor * * Note: the static sensor offset is the number the sensor outputs * at a nominally 'zero' input. Therefore the offset has to * be subtracted. * * Example: A gyro outputs a value of 74 at zero angular rate * the offset is 74 from the origin and subtracting * 74 from all measurements centers them around zero. */ accel_report.timestamp = hrt_absolute_time(); /* * Eight-bit 2’s complement sensor temperature value with 0.96 °C/LSB sensitivity. * Temperature data is only valid between –40 °C and 125 °C. The temperature sensor * output is only valid when M_CTRL_REG1[m_hms] > 0b00. Please note that the * temperature sensor is uncalibrated and its output for a given temperature will vary from * one device to the next */ write_checked_reg(FXOS8700CQ_M_CTRL_REG1, M_CTRL_REG1_HMS_A | M_CTRL_REG1_OS(7)); _last_temperature = (read_reg(FXOS8700CQ_TEMP)) * 0.96f; write_checked_reg(FXOS8700CQ_M_CTRL_REG1, M_CTRL_REG1_HMS_AM | M_CTRL_REG1_OS(7)); accel_report.temperature = _last_temperature; // report the error count as the sum of the number of bad // register reads and bad values. This allows the higher level // code to decide if it should use this sensor based on // whether it has had failures accel_report.error_count = perf_event_count(_bad_registers) + perf_event_count(_bad_values); accel_report.x_raw = swap16RightJustify14(raw_accel_mag_report.x); accel_report.y_raw = swap16RightJustify14(raw_accel_mag_report.y); accel_report.z_raw = swap16RightJustify14(raw_accel_mag_report.z); /* Save off the Mag readings todo: revist integrating theses */ _last_raw_mag_x = swap16(raw_accel_mag_report.mx); _last_raw_mag_y = swap16(raw_accel_mag_report.my); _last_raw_mag_z = swap16(raw_accel_mag_report.mz); float xraw_f = accel_report.x_raw; float yraw_f = accel_report.y_raw; float zraw_f = accel_report.z_raw; // apply user specified rotation rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); float x_in_new = ((xraw_f * _accel_range_scale) - _accel_scale.x_offset) * _accel_scale.x_scale; float y_in_new = ((yraw_f * _accel_range_scale) - _accel_scale.y_offset) * _accel_scale.y_scale; float z_in_new = ((zraw_f * _accel_range_scale) - _accel_scale.z_offset) * _accel_scale.z_scale; /* we have logs where the accelerometers get stuck at a fixed large value. We want to detect this and mark the sensor as being faulty */ if (fabsf(_last_accel[0] - x_in_new) < 0.001f && fabsf(_last_accel[1] - y_in_new) < 0.001f && fabsf(_last_accel[2] - z_in_new) < 0.001f && fabsf(x_in_new) > 20 && fabsf(y_in_new) > 20 && fabsf(z_in_new) > 20) { _constant_accel_count += 1; } else { _constant_accel_count = 0; } if (_constant_accel_count > 100) { // we've had 100 constant accel readings with large // values. The sensor is almost certainly dead. We // will raise the error_count so that the top level // flight code will know to avoid this sensor, but // we'll still give the data so that it can be logged // and viewed perf_count(_bad_values); _constant_accel_count = 0; } _last_accel[0] = x_in_new; _last_accel[1] = y_in_new; _last_accel[2] = z_in_new; accel_report.x = _accel_filter_x.apply(x_in_new); accel_report.y = _accel_filter_y.apply(y_in_new); accel_report.z = _accel_filter_z.apply(z_in_new); math::Vector<3> aval(x_in_new, y_in_new, z_in_new); math::Vector<3> aval_integrated; bool accel_notify = _accel_int.put(accel_report.timestamp, aval, aval_integrated, accel_report.integral_dt); accel_report.x_integral = aval_integrated(0); accel_report.y_integral = aval_integrated(1); accel_report.z_integral = aval_integrated(2); accel_report.scaling = _accel_range_scale; accel_report.range_m_s2 = _accel_range_m_s2; /* return device ID */ accel_report.device_id = _device_id.devid; _accel_reports->force(&accel_report); /* notify anyone waiting for data */ if (accel_notify) { poll_notify(POLLIN); if (!(_pub_blocked)) { /* publish it */ orb_publish(ORB_ID(sensor_accel), _accel_topic, &accel_report); } } _accel_read++; /* stop the perf counter */ perf_end(_accel_sample_perf); }
void FXOS8700CQ::mag_measure() { /* status register and data as read back from the device */ mag_report mag_report {}; /* start the performance counter */ perf_begin(_mag_sample_perf); /* * 1) Scale raw value to SI units using scaling from datasheet. * 2) Subtract static offset (in SI units) * 3) Scale the statically calibrated values with a linear * dynamically obtained factor * * Note: the static sensor offset is the number the sensor outputs * at a nominally 'zero' input. Therefore the offset has to * be subtracted. * * Example: A gyro outputs a value of 74 at zero angular rate * the offset is 74 from the origin and subtracting * 74 from all measurements centers them around zero. */ mag_report.timestamp = hrt_absolute_time(); mag_report.is_external = is_external(); mag_report.x_raw = _last_raw_mag_x; mag_report.y_raw = _last_raw_mag_y; mag_report.z_raw = _last_raw_mag_z; float xraw_f = mag_report.x_raw; float yraw_f = mag_report.y_raw; float zraw_f = mag_report.z_raw; /* apply user specified rotation */ rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); mag_report.x = ((xraw_f * _mag_range_scale) - _mag_scale.x_offset) * _mag_scale.x_scale; mag_report.y = ((yraw_f * _mag_range_scale) - _mag_scale.y_offset) * _mag_scale.y_scale; mag_report.z = ((zraw_f * _mag_range_scale) - _mag_scale.z_offset) * _mag_scale.z_scale; mag_report.scaling = _mag_range_scale; mag_report.range_ga = (float)_mag_range_ga; mag_report.error_count = perf_event_count(_bad_registers) + perf_event_count(_bad_values); mag_report.temperature = _last_temperature; mag_report.device_id = _mag->_device_id.devid; _mag_reports->force(&mag_report); /* notify anyone waiting for data */ poll_notify(POLLIN); if (!(_pub_blocked)) { /* publish it */ orb_publish(ORB_ID(sensor_mag), _mag->_mag_topic, &mag_report); } _mag_read++; /* stop the perf counter */ perf_end(_mag_sample_perf); }
int PMW3901::collect() { int ret = OK; int16_t delta_x_raw, delta_y_raw; float delta_x, delta_y; perf_begin(_sample_perf); uint64_t timestamp = hrt_absolute_time(); uint64_t dt_flow = timestamp - _previous_collect_timestamp; _previous_collect_timestamp = timestamp; _flow_dt_sum_usec += dt_flow; readMotionCount(delta_x_raw, delta_y_raw); _flow_sum_x += delta_x_raw; _flow_sum_y += delta_y_raw; // returns if the collect time has not been reached if (_flow_dt_sum_usec < _collect_time) { return ret; } delta_x = (float)_flow_sum_x / 500.0f; // proportional factor + convert from pixels to radians delta_y = (float)_flow_sum_y / 500.0f; // proportional factor + convert from pixels to radians struct optical_flow_s report; report.timestamp = timestamp; report.pixel_flow_x_integral = static_cast<float>(delta_x); report.pixel_flow_y_integral = static_cast<float>(delta_y); // rotate measurements in yaw from sensor frame to body frame according to parameter SENS_FLOW_ROT float zeroval = 0.0f; rotate_3f(_yaw_rotation, report.pixel_flow_x_integral, report.pixel_flow_y_integral, zeroval); rotate_3f(_yaw_rotation, report.gyro_x_rate_integral, report.gyro_y_rate_integral, report.gyro_z_rate_integral); report.frame_count_since_last_readout = 4; //microseconds report.integration_timespan = _flow_dt_sum_usec; //microseconds report.sensor_id = 0; // This sensor doesn't provide any quality metric. However if the sensor is unable to calculate the optical flow it will // output 0 for the delta. Hence, we set the measurement to "invalid" (quality = 0) if the values are smaller than FLT_EPSILON if (fabsf(report.pixel_flow_x_integral) < FLT_EPSILON && fabsf(report.pixel_flow_y_integral) < FLT_EPSILON) { report.quality = 0; } else { report.quality = 255; } /* No gyro on this board */ report.gyro_x_rate_integral = NAN; report.gyro_y_rate_integral = NAN; report.gyro_z_rate_integral = NAN; // set (conservative) specs according to datasheet report.max_flow_rate = 5.0f; // Datasheet: 7.4 rad/s report.min_ground_distance = 0.1f; // Datasheet: 80mm report.max_ground_distance = 30.0f; // Datasheet: infinity _flow_dt_sum_usec = 0; _flow_sum_x = 0; _flow_sum_y = 0; if (_optical_flow_pub == nullptr) { _optical_flow_pub = orb_advertise(ORB_ID(optical_flow), &report); } else { orb_publish(ORB_ID(optical_flow), _optical_flow_pub, &report); } /* post a report to the ring */ _reports->force(&report); /* notify anyone waiting for data */ poll_notify(POLLIN); perf_end(_sample_perf); return ret; }
int IST8310::collect() { #pragma pack(push, 1) struct { /* status register and data as read back from the device */ uint8_t x[2]; uint8_t y[2]; uint8_t z[2]; } report_buffer; #pragma pack(pop) struct { int16_t x, y, z; } report; int ret; uint8_t check_counter; perf_begin(_sample_perf); struct mag_report new_report; const bool sensor_is_external = external(); float xraw_f; float yraw_f; float zraw_f; /* this should be fairly close to the end of the measurement, so the best approximation of the time */ new_report.timestamp = hrt_absolute_time(); new_report.is_external = sensor_is_external; new_report.error_count = perf_event_count(_comms_errors); new_report.scaling = _range_scale; new_report.device_id = _device_id.devid; /* * @note We could read the status register here, which could tell us that * we were too early and that the output registers are still being * written. In the common case that would just slow us down, and * we're better off just never being early. */ /* get measurements from the device */ ret = read(ADDR_DATA_OUT_X_LSB, (uint8_t *)&report_buffer, sizeof(report_buffer)); if (ret != OK) { perf_count(_comms_errors); DEVICE_DEBUG("I2C read error"); goto out; } /* swap the data we just received */ report.x = (((int16_t)report_buffer.x[1]) << 8) | (int16_t)report_buffer.x[0]; report.y = (((int16_t)report_buffer.y[1]) << 8) | (int16_t)report_buffer.y[0]; report.z = (((int16_t)report_buffer.z[1]) << 8) | (int16_t)report_buffer.z[0]; /* * Check if value makes sense according to the FSR and Resolution of * this sensor, discarding outliers */ if (report.x > IST8310_MAX_VAL_XY || report.x < IST8310_MIN_VAL_XY || report.y > IST8310_MAX_VAL_XY || report.y < IST8310_MIN_VAL_XY || report.z > IST8310_MAX_VAL_Z || report.z < IST8310_MIN_VAL_Z) { perf_count(_range_errors); DEVICE_DEBUG("data/status read error"); goto out; } /* temperature measurement is not available on IST8310 */ new_report.temperature = 0; /* * raw outputs * * Sensor doesn't follow right hand rule, swap x and y to make it obey * it. */ new_report.x_raw = report.y; new_report.y_raw = report.x; new_report.z_raw = report.z; /* scale values for output */ xraw_f = report.y; yraw_f = report.x; zraw_f = report.z; /* apply user specified rotation */ rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); new_report.x = ((xraw_f * _range_scale) - _scale.x_offset) * _scale.x_scale; new_report.y = ((yraw_f * _range_scale) - _scale.y_offset) * _scale.y_scale; new_report.z = ((zraw_f * _range_scale) - _scale.z_offset) * _scale.z_scale; if (!(_pub_blocked)) { if (_mag_topic != nullptr) { /* publish it */ orb_publish(ORB_ID(sensor_mag), _mag_topic, &new_report); } else { _mag_topic = orb_advertise_multi(ORB_ID(sensor_mag), &new_report, &_orb_class_instance, sensor_is_external ? ORB_PRIO_MAX : ORB_PRIO_HIGH); if (_mag_topic == nullptr) { DEVICE_DEBUG("ADVERT FAIL"); } } } _last_report = new_report; /* post a report to the ring */ _reports->force(&new_report); /* notify anyone waiting for data */ poll_notify(POLLIN); /* periodically check the range register and configuration registers. With a bad I2C cable it is possible for the registers to become corrupt, leading to bad readings. It doesn't happen often, but given the poor cables some vehicles have it is worth checking for. */ check_counter = perf_event_count(_sample_perf) % 256; if (check_counter == 128) { check_conf(); } ret = OK; out: perf_end(_sample_perf); return ret; }
int PX4FLOW::collect() { int ret = -EIO; /* read from the sensor */ uint8_t val[I2C_FRAME_SIZE + I2C_INTEGRAL_FRAME_SIZE] = { 0 }; perf_begin(_sample_perf); if (PX4FLOW_REG == 0x00) { ret = transfer(nullptr, 0, &val[0], I2C_FRAME_SIZE + I2C_INTEGRAL_FRAME_SIZE); } if (PX4FLOW_REG == 0x16) { ret = transfer(nullptr, 0, &val[0], I2C_INTEGRAL_FRAME_SIZE); } if (ret < 0) { DEVICE_DEBUG("error reading from sensor: %d", ret); perf_count(_comms_errors); perf_end(_sample_perf); return ret; } if (PX4FLOW_REG == 0) { memcpy(&f, val, I2C_FRAME_SIZE); memcpy(&f_integral, &(val[I2C_FRAME_SIZE]), I2C_INTEGRAL_FRAME_SIZE); } if (PX4FLOW_REG == 0x16) { memcpy(&f_integral, val, I2C_INTEGRAL_FRAME_SIZE); } struct optical_flow_s report; report.timestamp = hrt_absolute_time(); report.pixel_flow_x_integral = static_cast<float>(f_integral.pixel_flow_x_integral) / 10000.0f;//convert to radians report.pixel_flow_y_integral = static_cast<float>(f_integral.pixel_flow_y_integral) / 10000.0f;//convert to radians report.frame_count_since_last_readout = f_integral.frame_count_since_last_readout; report.ground_distance_m = static_cast<float>(f_integral.ground_distance) / 1000.0f;//convert to meters report.quality = f_integral.qual; //0:bad ; 255 max quality report.gyro_x_rate_integral = static_cast<float>(f_integral.gyro_x_rate_integral) / 10000.0f; //convert to radians report.gyro_y_rate_integral = static_cast<float>(f_integral.gyro_y_rate_integral) / 10000.0f; //convert to radians report.gyro_z_rate_integral = static_cast<float>(f_integral.gyro_z_rate_integral) / 10000.0f; //convert to radians report.integration_timespan = f_integral.integration_timespan; //microseconds report.time_since_last_sonar_update = f_integral.sonar_timestamp;//microseconds report.gyro_temperature = f_integral.gyro_temperature;//Temperature * 100 in centi-degrees Celsius report.sensor_id = 0; /* rotate measurements according to parameter */ float zeroval = 0.0f; rotate_3f(_sensor_rotation, report.pixel_flow_x_integral, report.pixel_flow_y_integral, zeroval); if (_px4flow_topic == nullptr) { _px4flow_topic = orb_advertise(ORB_ID(optical_flow), &report); } else { /* publish it */ orb_publish(ORB_ID(optical_flow), _px4flow_topic, &report); } /* publish to the distance_sensor topic as well */ struct distance_sensor_s distance_report; distance_report.timestamp = report.timestamp; distance_report.min_distance = PX4FLOW_MIN_DISTANCE; distance_report.max_distance = PX4FLOW_MAX_DISTANCE; distance_report.current_distance = report.ground_distance_m; distance_report.covariance = 0.0f; distance_report.type = distance_sensor_s::MAV_DISTANCE_SENSOR_ULTRASOUND; /* TODO: the ID needs to be properly set */ distance_report.id = 0; distance_report.orientation = 8; orb_publish(ORB_ID(distance_sensor), _distance_sensor_topic, &distance_report); /* post a report to the ring */ if (_reports->force(&report)) { perf_count(_buffer_overflows); } /* notify anyone waiting for data */ poll_notify(POLLIN); ret = OK; perf_end(_sample_perf); return ret; }
int PX4FLOW::ioctl(struct file *filp, int cmd, unsigned long arg) { switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _measure_ticks = 0; return OK; /* external signalling (DRDY) not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* set interval for next measurement to minimum legal value */ _measure_ticks = USEC2TICK(PX4FLOW_CONVERSION_INTERVAL); /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* convert hz to tick interval via microseconds */ unsigned ticks = USEC2TICK(1000000 / arg); /* check against maximum rate */ if (ticks < USEC2TICK(PX4FLOW_CONVERSION_INTERVAL)) { return -EINVAL; } /* update interval for next measurement */ _measure_ticks = ticks; /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_measure_ticks == 0) { return SENSOR_POLLRATE_MANUAL; } return (1000 / _measure_ticks); case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } irqstate_t flags = irqsave(); if (!_reports->resize(arg)) { irqrestore(flags); return -ENOMEM; } irqrestore(flags); return OK; } case SENSORIOCGQUEUEDEPTH: return _reports->size(); case SENSORIOCSROTATION: _sensor_rotation = (enum Rotation)arg; return OK; case SENSORIOCGROTATION: return _sensor_rotation; case SENSORIOCRESET: /* XXX implement this */ return -EINVAL; default: /* give it to the superclass */ return I2C::ioctl(filp, cmd, arg); } }
void FXAS21002C::measure() { /* status register and data as read back from the device */ #pragma pack(push, 1) struct { uint8_t cmd; uint8_t status; int16_t x; int16_t y; int16_t z; } raw_gyro_report; #pragma pack(pop) sensor_gyro_s gyro_report; /* start the performance counter */ perf_begin(_sample_perf); check_registers(); if (_register_wait != 0) { // we are waiting for some good transfers before using // the sensor again. _register_wait--; perf_end(_sample_perf); return; } /* fetch data from the sensor */ memset(&raw_gyro_report, 0, sizeof(raw_gyro_report)); raw_gyro_report.cmd = DIR_READ(FXAS21002C_STATUS); transfer((uint8_t *)&raw_gyro_report, (uint8_t *)&raw_gyro_report, sizeof(raw_gyro_report)); if (!(raw_gyro_report.status & DR_STATUS_ZYXDR)) { perf_end(_sample_perf); perf_count(_duplicates); return; } /* * The TEMP register contains an 8-bit 2's complement temperature value with a range * of –128 °C to +127 °C and a scaling of 1 °C/LSB. The temperature data is only * compensated (factory trim values applied) when the device is operating in the Active * mode and actively measuring the angular rate. */ if ((_read % _current_rate) == 0) { _last_temperature = read_reg(FXAS21002C_TEMP) * 1.0f; gyro_report.temperature = _last_temperature; } /* * 1) Scale raw value to SI units using scaling from datasheet. * 2) Subtract static offset (in SI units) * 3) Scale the statically calibrated values with a linear * dynamically obtained factor * * Note: the static sensor offset is the number the sensor outputs * at a nominally 'zero' input. Therefore the offset has to * be subtracted. * * Example: A gyro outputs a value of 74 at zero angular rate * the offset is 74 from the origin and subtracting * 74 from all measurements centers them around zero. */ gyro_report.timestamp = hrt_absolute_time(); // report the error count as the number of bad // register reads. This allows the higher level // code to decide if it should use this sensor based on // whether it has had failures gyro_report.error_count = perf_event_count(_bad_registers); gyro_report.x_raw = swap16(raw_gyro_report.x); gyro_report.y_raw = swap16(raw_gyro_report.y); gyro_report.z_raw = swap16(raw_gyro_report.z); float xraw_f = gyro_report.x_raw; float yraw_f = gyro_report.y_raw; float zraw_f = gyro_report.z_raw; // apply user specified rotation rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); float x_in_new = ((xraw_f * _gyro_range_scale) - _gyro_scale.x_offset) * _gyro_scale.x_scale; float y_in_new = ((yraw_f * _gyro_range_scale) - _gyro_scale.y_offset) * _gyro_scale.y_scale; float z_in_new = ((zraw_f * _gyro_range_scale) - _gyro_scale.z_offset) * _gyro_scale.z_scale; gyro_report.x = _gyro_filter_x.apply(x_in_new); gyro_report.y = _gyro_filter_y.apply(y_in_new); gyro_report.z = _gyro_filter_z.apply(z_in_new); matrix::Vector3f gval(x_in_new, y_in_new, z_in_new); matrix::Vector3f gval_integrated; bool gyro_notify = _gyro_int.put(gyro_report.timestamp, gval, gval_integrated, gyro_report.integral_dt); gyro_report.x_integral = gval_integrated(0); gyro_report.y_integral = gval_integrated(1); gyro_report.z_integral = gval_integrated(2); gyro_report.scaling = _gyro_range_scale; /* return device ID */ gyro_report.device_id = _device_id.devid; _reports->force(&gyro_report); /* notify anyone waiting for data */ if (gyro_notify) { poll_notify(POLLIN); if (!(_pub_blocked)) { /* publish it */ orb_publish(ORB_ID(sensor_gyro), _gyro_topic, &gyro_report); } } _read++; /* stop the perf counter */ perf_end(_sample_perf); }
int LPS25H::collect() { #pragma pack(push, 1) struct { uint8_t status; uint8_t p_xl, p_l, p_h; int16_t t; } report; #pragma pack(pop) int ret; perf_begin(_sample_perf); struct baro_report new_report; bool sensor_is_onboard = false; /* this should be fairly close to the end of the measurement, so the best approximation of the time */ new_report.timestamp = hrt_absolute_time(); new_report.error_count = perf_event_count(_comms_errors); /* * @note We could read the status register 1 here, which could tell us that * we were too early and that the output registers are still being * written. In the common case that would just slow us down, and * we're better off just never being early. */ /* get measurements from the device : MSB enables register address auto-increment */ ret = _interface->read(ADDR_STATUS_REG | (1 << 7), (uint8_t *)&report, sizeof(report)); if (ret != OK) { perf_count(_comms_errors); perf_end(_sample_perf); return ret; } /* get measurements from the device */ new_report.temperature = 42.5 + (report.t / 480); /* raw pressure */ uint32_t raw = report.p_xl + (report.p_l << 8) + (report.p_h << 16); /* Pressure and MSL in mBar */ double p = raw / 4096.0; double msl = _msl_pressure / 100.0; double alt = (1.0 - pow(p / msl, 0.190263)) * 44330.8; new_report.pressure = p; new_report.altitude = alt; /* get device ID */ new_report.device_id = _device_id.devid; if (!(_pub_blocked)) { if (_baro_topic != nullptr) { /* publish it */ orb_publish(ORB_ID(sensor_baro), _baro_topic, &new_report); } else { _baro_topic = orb_advertise_multi(ORB_ID(sensor_baro), &new_report, &_orb_class_instance, (sensor_is_onboard) ? ORB_PRIO_HIGH : ORB_PRIO_MAX); if (_baro_topic == nullptr) { DEVICE_DEBUG("ADVERT FAIL"); } } } _last_report = new_report; /* post a report to the ring */ if (_reports->force(&new_report)) { perf_count(_buffer_overflows); } /* notify anyone waiting for data */ poll_notify(POLLIN); ret = OK; perf_end(_sample_perf); return ret; }
int FXOS8700CQ::init() { int ret = PX4_ERROR; /* do SPI init (and probe) first */ if (SPI::init() != OK) { PX4_ERR("SPI init failed"); goto out; } /* allocate basic report buffers */ _accel_reports = new ringbuffer::RingBuffer(2, sizeof(accel_report)); if (_accel_reports == nullptr) { goto out; } _mag_reports = new ringbuffer::RingBuffer(2, sizeof(mag_report)); if (_mag_reports == nullptr) { goto out; } reset(); /* do CDev init for the mag device node */ ret = _mag->init(); if (ret != OK) { PX4_ERR("MAG init failed"); goto out; } /* fill report structures */ measure(); /* advertise sensor topic, measure manually to initialize valid report */ struct mag_report mrp; _mag_reports->get(&mrp); /* measurement will have generated a report, publish */ _mag->_mag_topic = orb_advertise_multi(ORB_ID(sensor_mag), &mrp, &_mag->_mag_orb_class_instance, ORB_PRIO_LOW); if (_mag->_mag_topic == nullptr) { PX4_ERR("ADVERT ERR"); } _accel_class_instance = register_class_devname(ACCEL_BASE_DEVICE_PATH); /* advertise sensor topic, measure manually to initialize valid report */ struct accel_report arp; _accel_reports->get(&arp); /* measurement will have generated a report, publish */ _accel_topic = orb_advertise_multi(ORB_ID(sensor_accel), &arp, &_accel_orb_class_instance, (is_external()) ? ORB_PRIO_VERY_HIGH : ORB_PRIO_DEFAULT); if (_accel_topic == nullptr) { PX4_ERR("ADVERT ERR"); } out: return ret; }
int HMC5883::ioctl(struct file *filp, int cmd, unsigned long arg) { unsigned dummy = arg; switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _measure_ticks = 0; return OK; /* external signalling (DRDY) not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* set interval for next measurement to minimum legal value */ _measure_ticks = USEC2TICK(HMC5883_CONVERSION_INTERVAL); /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* convert hz to tick interval via microseconds */ unsigned ticks = USEC2TICK(1000000 / arg); /* check against maximum rate */ if (ticks < USEC2TICK(HMC5883_CONVERSION_INTERVAL)) { return -EINVAL; } /* update interval for next measurement */ _measure_ticks = ticks; /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_measure_ticks == 0) { return SENSOR_POLLRATE_MANUAL; } return 1000000 / TICK2USEC(_measure_ticks); case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } irqstate_t flags = px4_enter_critical_section(); if (!_reports->resize(arg)) { px4_leave_critical_section(flags); return -ENOMEM; } px4_leave_critical_section(flags); return OK; } case SENSORIOCGQUEUEDEPTH: return _reports->size(); case SENSORIOCRESET: return reset(); case MAGIOCSSAMPLERATE: /* same as pollrate because device is in single measurement mode*/ return ioctl(filp, SENSORIOCSPOLLRATE, arg); case MAGIOCGSAMPLERATE: /* same as pollrate because device is in single measurement mode*/ return 1000000 / TICK2USEC(_measure_ticks); case MAGIOCSRANGE: return set_range(arg); case MAGIOCGRANGE: return _range_ga; case MAGIOCSLOWPASS: case MAGIOCGLOWPASS: /* not supported, no internal filtering */ return -EINVAL; case MAGIOCSSCALE: /* set new scale factors */ memcpy(&_scale, (struct mag_calibration_s *)arg, sizeof(_scale)); /* check calibration, but not actually return an error */ (void)check_calibration(); return 0; case MAGIOCGSCALE: /* copy out scale factors */ memcpy((struct mag_calibration_s *)arg, &_scale, sizeof(_scale)); return 0; case MAGIOCCALIBRATE: return calibrate(filp, arg); case MAGIOCEXSTRAP: return set_excitement(arg); case MAGIOCSELFTEST: return check_calibration(); case MAGIOCGEXTERNAL: DEVICE_DEBUG("MAGIOCGEXTERNAL in main driver"); return _interface->ioctl(cmd, dummy); case MAGIOCSTEMPCOMP: return set_temperature_compensation(arg); default: /* give it to the superclass */ return CDev::ioctl(filp, cmd, arg); } }
int FXOS8700CQ::ioctl(struct file *filp, int cmd, unsigned long arg) { switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _call_accel_interval = 0; return OK; /* external signalling not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: return ioctl(filp, SENSORIOCSPOLLRATE, 1600); case SENSOR_POLLRATE_DEFAULT: return ioctl(filp, SENSORIOCSPOLLRATE, FXOS8700C_ACCEL_DEFAULT_RATE); /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_call_accel_interval == 0); /* convert hz to hrt interval via microseconds */ unsigned ticks = 1000000 / arg; /* check against maximum sane rate */ if (ticks < 500) { return -EINVAL; } /* adjust filters */ accel_set_driver_lowpass_filter((float)arg, _accel_filter_x.get_cutoff_freq()); /* update interval for next measurement */ /* XXX this is a bit shady, but no other way to adjust... */ _call_accel_interval = ticks; _accel_call.period = _call_accel_interval - FXOS8700C_TIMER_REDUCTION; /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_call_accel_interval == 0) { return SENSOR_POLLRATE_MANUAL; } return 1000000 / _call_accel_interval; case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } irqstate_t flags = px4_enter_critical_section(); if (!_accel_reports->resize(arg)) { px4_leave_critical_section(flags); return -ENOMEM; } px4_leave_critical_section(flags); return OK; } case SENSORIOCGQUEUEDEPTH: return _accel_reports->size(); case SENSORIOCRESET: reset(); return OK; case ACCELIOCSSAMPLERATE: return accel_set_samplerate(arg); case ACCELIOCGSAMPLERATE: return _accel_samplerate; case ACCELIOCSLOWPASS: { return accel_set_driver_lowpass_filter((float)_accel_samplerate, (float)arg); } case ACCELIOCGLOWPASS: return static_cast<int>(_accel_filter_x.get_cutoff_freq()); case ACCELIOCSSCALE: { /* copy scale, but only if off by a few percent */ struct accel_calibration_s *s = (struct accel_calibration_s *) arg; float sum = s->x_scale + s->y_scale + s->z_scale; if (sum > 2.0f && sum < 4.0f) { memcpy(&_accel_scale, s, sizeof(_accel_scale)); return OK; } else { return -EINVAL; } } case ACCELIOCSRANGE: /* arg needs to be in G */ return accel_set_range(arg); case ACCELIOCGRANGE: /* convert to m/s^2 and return rounded in G */ return (unsigned long)((_accel_range_m_s2) / FXOS8700C_ONE_G + 0.5f); case ACCELIOCGSCALE: /* copy scale out */ memcpy((struct accel_calibration_s *) arg, &_accel_scale, sizeof(_accel_scale)); return OK; case ACCELIOCSELFTEST: return accel_self_test(); default: /* give it to the superclass */ return SPI::ioctl(filp, cmd, arg); } }
int ACCELSIM::init() { int ret = -1; struct mag_report mrp = {}; struct accel_report arp = {}; /* do SIM init first */ if (VirtDevObj::init() != 0) { PX4_WARN("SIM init failed"); goto out; } /* allocate basic report buffers */ _accel_reports = new ringbuffer::RingBuffer(2, sizeof(accel_report)); if (_accel_reports == nullptr) { goto out; } _mag_reports = new ringbuffer::RingBuffer(2, sizeof(mag_report)); if (_mag_reports == nullptr) { goto out; } /* do init for the mag device node */ ret = _mag->init(); if (ret != OK) { PX4_WARN("MAG init failed"); goto out; } /* fill report structures */ _measure(); /* advertise sensor topic, measure manually to initialize valid report */ _mag_reports->get(&mrp); /* measurement will have generated a report, publish */ _mag->_mag_topic = orb_advertise_multi(ORB_ID(sensor_mag), &mrp, &_mag->_mag_orb_class_instance, ORB_PRIO_LOW); if (_mag->_mag_topic == nullptr) { PX4_WARN("ADVERT ERR"); } /* advertise sensor topic, measure manually to initialize valid report */ _accel_reports->get(&arp); /* measurement will have generated a report, publish */ _accel_topic = orb_advertise_multi(ORB_ID(sensor_accel), &arp, &_accel_orb_class_instance, ORB_PRIO_DEFAULT); if (_accel_topic == nullptr) { PX4_WARN("ADVERT ERR"); } out: return ret; }
int FXOS8700CQ::mag_ioctl(struct file *filp, int cmd, unsigned long arg) { switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _call_mag_interval = 0; return OK; /* external signalling not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: /* 100 Hz is max for mag */ return mag_ioctl(filp, SENSORIOCSPOLLRATE, 100); /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_call_mag_interval == 0); /* convert hz to hrt interval via microseconds */ unsigned ticks = 1000000 / arg; /* check against maximum sane rate */ if (ticks < 1000) { return -EINVAL; } /* update interval for next measurement */ /* XXX this is a bit shady, but no other way to adjust... */ _mag_call.period = _call_mag_interval = ticks; /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_call_mag_interval == 0) { return SENSOR_POLLRATE_MANUAL; } return 1000000 / _call_mag_interval; case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } irqstate_t flags = px4_enter_critical_section(); if (!_mag_reports->resize(arg)) { px4_leave_critical_section(flags); return -ENOMEM; } px4_leave_critical_section(flags); return OK; } case SENSORIOCGQUEUEDEPTH: return _mag_reports->size(); case SENSORIOCRESET: reset(); return OK; case MAGIOCSSAMPLERATE: return mag_set_samplerate(arg); case MAGIOCGSAMPLERATE: return _mag_samplerate; case MAGIOCSLOWPASS: case MAGIOCGLOWPASS: /* not supported, no internal filtering */ return -EINVAL; case MAGIOCSSCALE: /* copy scale in */ memcpy(&_mag_scale, (struct mag_calibration_s *) arg, sizeof(_mag_scale)); return OK; case MAGIOCGSCALE: /* copy scale out */ memcpy((struct mag_calibration_s *) arg, &_mag_scale, sizeof(_mag_scale)); return OK; case MAGIOCSRANGE: return mag_set_range(arg); case MAGIOCGRANGE: return _mag_range_ga; case MAGIOCSELFTEST: return mag_self_test(); case MAGIOCGEXTERNAL: /* Even if this sensor is on the "external" SPI bus * it is still fixed to the autopilot assembly, * so always return 0. */ return 0; default: /* give it to the superclass */ return SPI::ioctl(filp, cmd, arg); } }
int ACCELSIM::mag_ioctl(unsigned long cmd, unsigned long arg) { unsigned long ul_arg = (unsigned long)arg; switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: _mag->stop(); _mag->m_sample_interval_usecs = 0; return OK; /* external signalling not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: /* 100 Hz is max for mag */ return mag_ioctl(SENSORIOCSPOLLRATE, 100); /* adjust to a legal polling interval in Hz */ default: { /* convert hz to hrt interval via microseconds */ unsigned interval = 1000000 / ul_arg; /* check against maximum sane rate (1ms) */ if (interval < 10000) { return -EINVAL; } bool want_start = (_mag->m_sample_interval_usecs == 0); /* update interval for next measurement */ _mag->setSampleInterval(interval); if (want_start) { _mag->start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_mag->m_sample_interval_usecs == 0) { return SENSOR_POLLRATE_MANUAL; } return 1000000 / _mag->m_sample_interval_usecs; case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } if (!_mag_reports->resize(arg)) { return -ENOMEM; } return OK; } case SENSORIOCGQUEUEDEPTH: return _mag_reports->size(); case SENSORIOCRESET: // Nothing to do for simulator return OK; case MAGIOCSSAMPLERATE: // No need to set internal sampling rate for simulator return OK; case MAGIOCGSAMPLERATE: return _mag_samplerate; case MAGIOCSLOWPASS: case MAGIOCGLOWPASS: /* not supported, no internal filtering */ return -EINVAL; case MAGIOCSSCALE: /* copy scale in */ memcpy(&_mag_scale, (struct mag_calibration_s *) arg, sizeof(_mag_scale)); return OK; case MAGIOCGSCALE: /* copy scale out */ memcpy((struct mag_calibration_s *) arg, &_mag_scale, sizeof(_mag_scale)); return OK; case MAGIOCSRANGE: return mag_set_range(arg); case MAGIOCGRANGE: return _mag_range_ga; case MAGIOCGEXTERNAL: /* Even if this sensor is on the "external" SPI bus * it is still fixed to the autopilot assembly, * so always return 0. */ return 0; case MAGIOCSELFTEST: return OK; default: /* give it to the superclass */ return VirtDevObj::devIOCTL(cmd, arg); } }
int L3GD20::ioctl(struct file *filp, int cmd, unsigned long arg) { switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _call_interval = 0; return OK; /* external signalling not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: if (_is_l3g4200d) { return ioctl(filp, SENSORIOCSPOLLRATE, L3G4200D_DEFAULT_RATE); } return ioctl(filp, SENSORIOCSPOLLRATE, L3GD20_DEFAULT_RATE); /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_call_interval == 0); /* convert hz to hrt interval via microseconds */ unsigned ticks = 1000000 / arg; /* check against maximum sane rate */ if (ticks < 1000) return -EINVAL; /* update interval for next measurement */ /* XXX this is a bit shady, but no other way to adjust... */ _call_interval = ticks; _call.period = _call_interval - L3GD20_TIMER_REDUCTION; /* adjust filters */ float cutoff_freq_hz = _gyro_filter_x.get_cutoff_freq(); float sample_rate = 1.0e6f/ticks; set_driver_lowpass_filter(sample_rate, cutoff_freq_hz); /* if we need to start the poll state machine, do it */ if (want_start) start(); return OK; } } } case SENSORIOCGPOLLRATE: if (_call_interval == 0) return SENSOR_POLLRATE_MANUAL; return 1000000 / _call_interval; case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) return -EINVAL; irqstate_t flags = irqsave(); if (!_reports->resize(arg)) { irqrestore(flags); return -ENOMEM; } irqrestore(flags); return OK; } case SENSORIOCGQUEUEDEPTH: return _reports->size(); case SENSORIOCRESET: reset(); return OK; case GYROIOCSSAMPLERATE: return set_samplerate(arg, _current_bandwidth); case GYROIOCGSAMPLERATE: return _current_rate; case GYROIOCSLOWPASS: { // set the software lowpass cut-off in Hz float cutoff_freq_hz = arg; float sample_rate = 1.0e6f / _call_interval; set_driver_lowpass_filter(sample_rate, cutoff_freq_hz); return OK; } case GYROIOCGLOWPASS: return static_cast<int>(_gyro_filter_x.get_cutoff_freq()); case GYROIOCSSCALE: /* copy scale in */ memcpy(&_gyro_scale, (struct gyro_scale *) arg, sizeof(_gyro_scale)); return OK; case GYROIOCGSCALE: /* copy scale out */ memcpy((struct gyro_scale *) arg, &_gyro_scale, sizeof(_gyro_scale)); return OK; case GYROIOCSRANGE: /* arg should be in dps */ return set_range(arg); case GYROIOCGRANGE: /* convert to dps and round */ return (unsigned long)(_gyro_range_rad_s * 180.0f / M_PI_F + 0.5f); case GYROIOCSELFTEST: return self_test(); case GYROIOCSHWLOWPASS: return set_samplerate(_current_rate, arg); case GYROIOCGHWLOWPASS: return _current_bandwidth; default: /* give it to the superclass */ return SPI::ioctl(filp, cmd, arg); } }
void ACCELSIM::mag_measure() { /* status register and data as read back from the device */ #pragma pack(push, 1) struct { uint8_t cmd; uint8_t status; float temperature; float x; float y; float z; } raw_mag_report; #pragma pack(pop) mag_report mag_report; memset(&mag_report, 0, sizeof(mag_report)); /* start the performance counter */ perf_begin(_mag_sample_perf); /* fetch data from the sensor */ memset(&raw_mag_report, 0, sizeof(raw_mag_report)); raw_mag_report.cmd = DIR_READ | MAG_READ; if (OK != transfer((uint8_t *)&raw_mag_report, (uint8_t *)&raw_mag_report, sizeof(raw_mag_report))) { return; } /* * 1) Scale raw value to SI units using scaling from datasheet. * 2) Subtract static offset (in SI units) * 3) Scale the statically calibrated values with a linear * dynamically obtained factor * * Note: the static sensor offset is the number the sensor outputs * at a nominally 'zero' input. Therefore the offset has to * be subtracted. * * Example: A gyro outputs a value of 74 at zero angular rate * the offset is 74 from the origin and subtracting * 74 from all measurements centers them around zero. */ mag_report.timestamp = hrt_absolute_time(); mag_report.x_raw = (int16_t)(raw_mag_report.x / _mag_range_scale); mag_report.y_raw = (int16_t)(raw_mag_report.y / _mag_range_scale); mag_report.z_raw = (int16_t)(raw_mag_report.z / _mag_range_scale); float xraw_f = (int16_t)(raw_mag_report.x / _mag_range_scale); float yraw_f = (int16_t)(raw_mag_report.y / _mag_range_scale); float zraw_f = (int16_t)(raw_mag_report.z / _mag_range_scale); /* apply user specified rotation */ rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); /* remember the temperature. The datasheet isn't clear, but it * seems to be a signed offset from 25 degrees C in units of 0.125C */ _last_temperature = raw_mag_report.temperature; mag_report.temperature = _last_temperature; mag_report.x = raw_mag_report.x; mag_report.y = raw_mag_report.y; mag_report.z = raw_mag_report.z; _mag_reports->force(&mag_report); /* notify anyone waiting for data */ DevMgr::updateNotify(*this); if (!(m_pub_blocked)) { /* publish it */ orb_publish(ORB_ID(sensor_mag), _mag->_mag_topic, &mag_report); } _mag_read++; /* stop the perf counter */ perf_end(_mag_sample_perf); }
void L3GD20::measure() { /* status register and data as read back from the device */ #pragma pack(push, 1) struct { uint8_t cmd; int8_t temp; uint8_t status; int16_t x; int16_t y; int16_t z; } raw_report; #pragma pack(pop) gyro_report report; /* start the performance counter */ perf_begin(_sample_perf); check_registers(); /* fetch data from the sensor */ memset(&raw_report, 0, sizeof(raw_report)); raw_report.cmd = ADDR_OUT_TEMP | DIR_READ | ADDR_INCREMENT; transfer((uint8_t *)&raw_report, (uint8_t *)&raw_report, sizeof(raw_report)); if (!(raw_report.status & STATUS_ZYXDA)) { perf_end(_sample_perf); perf_count(_duplicates); return; } /* * 1) Scale raw value to SI units using scaling from datasheet. * 2) Subtract static offset (in SI units) * 3) Scale the statically calibrated values with a linear * dynamically obtained factor * * Note: the static sensor offset is the number the sensor outputs * at a nominally 'zero' input. Therefore the offset has to * be subtracted. * * Example: A gyro outputs a value of 74 at zero angular rate * the offset is 74 from the origin and subtracting * 74 from all measurements centers them around zero. */ report.timestamp = hrt_absolute_time(); report.error_count = perf_event_count(_bad_registers); switch (_orientation) { case SENSOR_BOARD_ROTATION_000_DEG: /* keep axes in place */ report.x_raw = raw_report.x; report.y_raw = raw_report.y; break; case SENSOR_BOARD_ROTATION_090_DEG: /* swap x and y */ report.x_raw = raw_report.y; report.y_raw = raw_report.x; break; case SENSOR_BOARD_ROTATION_180_DEG: /* swap x and y and negate both */ report.x_raw = ((raw_report.x == -32768) ? 32767 : -raw_report.x); report.y_raw = ((raw_report.y == -32768) ? 32767 : -raw_report.y); break; case SENSOR_BOARD_ROTATION_270_DEG: /* swap x and y and negate y */ report.x_raw = raw_report.y; report.y_raw = ((raw_report.x == -32768) ? 32767 : -raw_report.x); break; } report.z_raw = raw_report.z; report.temperature_raw = raw_report.temp; float xraw_f = report.x_raw; float yraw_f = report.y_raw; float zraw_f = report.z_raw; // apply user specified rotation rotate_3f(_rotation, xraw_f, yraw_f, zraw_f); report.x = ((xraw_f * _gyro_range_scale) - _gyro_scale.x_offset) * _gyro_scale.x_scale; report.y = ((yraw_f * _gyro_range_scale) - _gyro_scale.y_offset) * _gyro_scale.y_scale; report.z = ((zraw_f * _gyro_range_scale) - _gyro_scale.z_offset) * _gyro_scale.z_scale; report.x = _gyro_filter_x.apply(report.x); report.y = _gyro_filter_y.apply(report.y); report.z = _gyro_filter_z.apply(report.z); report.temperature = L3GD20_TEMP_OFFSET_CELSIUS - raw_report.temp; report.scaling = _gyro_range_scale; report.range_rad_s = _gyro_range_rad_s; _reports->force(&report); /* notify anyone waiting for data */ poll_notify(POLLIN); /* publish for subscribers */ if (!(_pub_blocked)) { /* publish it */ orb_publish(ORB_ID(sensor_gyro), _gyro_topic, &report); } _read++; /* stop the perf counter */ perf_end(_sample_perf); }
int TFMINI::collect() { int ret; perf_begin(_sample_perf); /* clear buffer if last read was too long ago */ int64_t read_elapsed = hrt_elapsed_time(&_last_read); /* the buffer for read chars is buflen minus null termination */ char readbuf[sizeof(_linebuf)]; unsigned readlen = sizeof(readbuf) - 1; /* read from the sensor (uart buffer) */ ret = ::read(_fd, &readbuf[0], readlen); if (ret < 0) { DEVICE_DEBUG("read err: %d", ret); perf_count(_comms_errors); perf_end(_sample_perf); /* only throw an error if we time out */ if (read_elapsed > (_conversion_interval * 2)) { return ret; } else { return -EAGAIN; } } else if (ret == 0) { return -EAGAIN; } _last_read = hrt_absolute_time(); float distance_m = -1.0f; bool valid = false; for (int i = 0; i < ret; i++) { if (OK == tfmini_parser(readbuf[i], _linebuf, &_linebuf_index, &_parse_state, &distance_m)) { valid = true; } } if (!valid) { return -EAGAIN; } DEVICE_DEBUG("val (float): %8.4f, raw: %s, valid: %s", (double)distance_m, _linebuf, ((valid) ? "OK" : "NO")); struct distance_sensor_s report; report.timestamp = hrt_absolute_time(); report.type = distance_sensor_s::MAV_DISTANCE_SENSOR_LASER; report.orientation = _rotation; report.current_distance = distance_m; report.min_distance = get_minimum_distance(); report.max_distance = get_maximum_distance(); report.covariance = 0.0f; report.signal_quality = -1; /* TODO: set proper ID */ report.id = 0; /* publish it */ orb_publish(ORB_ID(distance_sensor), _distance_sensor_topic, &report); _reports->force(&report); /* notify anyone waiting for data */ poll_notify(POLLIN); ret = OK; perf_end(_sample_perf); return ret; }
int /* * Method: collect() * * This method reads data from serial UART and places it into a buffer */ CM8JL65::collect() { int bytes_read = 0; int bytes_processed = 0; int i = 0; bool crc_valid = false; perf_begin(_sample_perf); /* read from the sensor (uart buffer) */ bytes_read = ::read(_fd, &_linebuf[0], sizeof(_linebuf)); if (bytes_read < 0) { PX4_DEBUG("read err: %d \n", bytes_read); perf_count(_comms_errors); perf_end(_sample_perf); } else if (bytes_read > 0) { // printf("Bytes read: %d \n",bytes_read); i = bytes_read - 6 ; while ((i >= 0) && (!crc_valid)) { if (_linebuf[i] == START_FRAME_DIGIT1) { bytes_processed = i; while ((bytes_processed < bytes_read) && (!crc_valid)) { // printf("In the cycle, processing byte %d, 0x%02X \n",bytes_processed, _linebuf[bytes_processed]); if (OK == cm8jl65_parser(_linebuf[bytes_processed], _frame_data, _parse_state, _crc16, _distance_mm)) { crc_valid = true; } bytes_processed++; } _parse_state = STATE0_WAITING_FRAME; } i--; } } if (!crc_valid) { return -EAGAIN; } //printf("val (int): %d, raw: 0x%08X, valid: %s \n", _distance_mm, _frame_data, ((crc_valid) ? "OK" : "NO")); struct distance_sensor_s report; report.timestamp = hrt_absolute_time(); report.type = distance_sensor_s::MAV_DISTANCE_SENSOR_LASER; report.orientation = _rotation; report.current_distance = _distance_mm / 1000.0f; report.min_distance = get_minimum_distance(); report.max_distance = get_maximum_distance(); report.variance = 0.0f; report.signal_quality = -1; /* TODO: set proper ID */ report.id = 0; /* publish it */ orb_publish(ORB_ID(distance_sensor), _distance_sensor_topic, &report); _reports->force(&report); /* notify anyone waiting for data */ poll_notify(POLLIN); bytes_read = OK; perf_end(_sample_perf); return OK; }
int BAROSIM::init() { int ret; struct baro_report brp = {}; //PX4_DEBUG("BAROSIM::init"); ret = VirtDevObj::init(); if (ret != OK) { PX4_ERR("VirtDevObj init failed"); goto out; } /* allocate basic report buffers */ _reports = new ringbuffer::RingBuffer(2, sizeof(baro_report)); if (_reports == nullptr) { PX4_ERR("can't get memory for reports"); ret = -ENOMEM; goto out; } /* do a first measurement cycle to populate reports with valid data */ _measure_phase = 0; _reports->flush(); _baro_topic = orb_advertise_multi(ORB_ID(sensor_baro), &brp, &_orb_class_instance, (is_external()) ? ORB_PRIO_HIGH : ORB_PRIO_DEFAULT); if (_baro_topic == nullptr) { PX4_ERR("failed to create sensor_baro publication"); } /* this do..while is goto without goto */ do { /* do temperature first */ if (OK != measure()) { ret = -EIO; PX4_ERR("temp measure failed"); break; } usleep(BAROSIM_CONVERSION_INTERVAL); if (OK != collect()) { ret = -EIO; PX4_ERR("temp collect failed"); break; } /* now do a pressure measurement */ if (OK != measure()) { ret = -EIO; PX4_ERR("pressure collect failed"); break; } usleep(BAROSIM_CONVERSION_INTERVAL); if (OK != collect()) { ret = -EIO; PX4_ERR("pressure collect failed"); break; } /* state machine will have generated a report, copy it out */ _reports->get(&brp); ret = OK; //PX4_WARN("sensor_baro publication %ld", _baro_topic); } while (0); out: return ret; }
int LPS25H::ioctl(struct file *filp, int cmd, unsigned long arg) { unsigned dummy = arg; switch (cmd) { case SENSORIOCSPOLLRATE: { switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop(); _measure_ticks = 0; return OK; /* external signalling (DRDY) not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* set interval for next measurement to minimum legal value */ _measure_ticks = USEC2TICK(LPS25H_CONVERSION_INTERVAL); /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } /* adjust to a legal polling interval in Hz */ default: { /* do we need to start internal polling? */ bool want_start = (_measure_ticks == 0); /* convert hz to tick interval via microseconds */ unsigned ticks = USEC2TICK(1000000 / arg); /* check against maximum rate */ if (ticks < USEC2TICK(LPS25H_CONVERSION_INTERVAL)) { return -EINVAL; } /* update interval for next measurement */ _measure_ticks = ticks; /* if we need to start the poll state machine, do it */ if (want_start) { start(); } return OK; } } } case SENSORIOCGPOLLRATE: if (_measure_ticks == 0) { return SENSOR_POLLRATE_MANUAL; } return (1000 / _measure_ticks); case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } irqstate_t flags = px4_enter_critical_section(); if (!_reports->resize(arg)) { px4_leave_critical_section(flags); return -ENOMEM; } px4_leave_critical_section(flags); return OK; } case SENSORIOCGQUEUEDEPTH: return _reports->size(); case SENSORIOCRESET: return reset(); case BAROIOCSMSLPRESSURE: /* range-check for sanity */ if ((arg < 80000) || (arg > 120000)) { return -EINVAL; } _msl_pressure = arg; return OK; case BAROIOCGMSLPRESSURE: return _msl_pressure; case DEVIOCGDEVICEID: return _interface->ioctl(cmd, dummy); default: /* give it to the superclass */ return CDev::ioctl(filp, cmd, arg); } }
int BAROSIM::devIOCTL(unsigned long cmd, unsigned long arg) { PX4_WARN("baro IOCTL %llu", hrt_absolute_time()); switch (cmd) { case SENSORIOCSPOLLRATE: switch (arg) { /* switching to manual polling */ case SENSOR_POLLRATE_MANUAL: stop_cycle(); setSampleInterval(0); m_sample_interval_usecs = 0; return OK; /* external signalling not supported */ case SENSOR_POLLRATE_EXTERNAL: /* zero would be bad */ case 0: return -EINVAL; /* set default/max polling rate */ case SENSOR_POLLRATE_MAX: case SENSOR_POLLRATE_DEFAULT: { setSampleInterval(BAROSIM_CONVERSION_INTERVAL); return OK; } /* adjust to a legal polling interval in Hz */ default: { /* convert hz to tick interval via microseconds */ unsigned long interval = 1000000 / arg; /* check against maximum rate */ if (interval < BAROSIM_CONVERSION_INTERVAL) { return -EINVAL; } bool want_start = (m_sample_interval_usecs == 0); /* update interval for next measurement */ setSampleInterval(interval); if (want_start) { start(); } return OK; } } case SENSORIOCGPOLLRATE: if (m_sample_interval_usecs == 0) { return SENSOR_POLLRATE_MANUAL; } return (1000000 / m_sample_interval_usecs); case SENSORIOCSQUEUEDEPTH: { /* lower bound is mandatory, upper bound is a sanity check */ if ((arg < 1) || (arg > 100)) { return -EINVAL; } if (!_reports->resize(arg)) { return -ENOMEM; } return OK; } case SENSORIOCGQUEUEDEPTH: return _reports->size(); case SENSORIOCRESET: /* * Since we are initialized, we do not need to do anything, since the * PROM is correctly read and the part does not need to be configured. */ return OK; case BAROIOCSMSLPRESSURE: /* range-check for sanity */ if ((arg < 80000) || (arg > 120000)) { return -EINVAL; } _msl_pressure = arg; return OK; case BAROIOCGMSLPRESSURE: return _msl_pressure; default: break; } /* give it to the bus-specific superclass */ // return bus_ioctl(filp, cmd, arg); return VirtDevObj::devIOCTL(cmd, arg); }
int TFMINI::collect() { perf_begin(_sample_perf); /* clear buffer if last read was too long ago */ int64_t read_elapsed = hrt_elapsed_time(&_last_read); /* the buffer for read chars is buflen minus null termination */ char readbuf[sizeof(_linebuf)]; unsigned readlen = sizeof(readbuf) - 1; int ret = 0; float distance_m = -1.0f; /* Check the number of bytes available in the buffer*/ int bytes_available = 0; ::ioctl(_fd, FIONREAD, (unsigned long)&bytes_available); if (!bytes_available) { return -EAGAIN; } /* parse entire buffer */ do { /* read from the sensor (uart buffer) */ ret = ::read(_fd, &readbuf[0], readlen); if (ret < 0) { PX4_ERR("read err: %d", ret); perf_count(_comms_errors); perf_end(_sample_perf); /* only throw an error if we time out */ if (read_elapsed > (_conversion_interval * 2)) { /* flush anything in RX buffer */ tcflush(_fd, TCIFLUSH); return ret; } else { return -EAGAIN; } } _last_read = hrt_absolute_time(); /* parse buffer */ for (int i = 0; i < ret; i++) { tfmini_parse(readbuf[i], _linebuf, &_linebuf_index, &_parse_state, &distance_m); } /* bytes left to parse */ bytes_available -= ret; } while (bytes_available > 0); /* no valid measurement after parsing buffer */ if (distance_m < 0.0f) { return -EAGAIN; } /* publish most recent valid measurement from buffer */ distance_sensor_s report{}; report.timestamp = hrt_absolute_time(); report.type = distance_sensor_s::MAV_DISTANCE_SENSOR_LASER; report.orientation = _rotation; report.current_distance = distance_m; report.min_distance = get_minimum_distance(); report.max_distance = get_maximum_distance(); report.covariance = 0.0f; report.signal_quality = -1; /* TODO: set proper ID */ report.id = 0; /* publish it */ orb_publish(ORB_ID(distance_sensor), _distance_sensor_topic, &report); _reports->force(&report); /* notify anyone waiting for data */ poll_notify(POLLIN); ret = OK; perf_end(_sample_perf); return ret; }