40 #include <px4_platform_common/px4_config.h> 41 #include <px4_platform_common/defines.h> 45 #include <sys/types.h> 49 #include <semaphore.h> 58 #include <nuttx/arch.h> 59 #include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> 60 #include <nuttx/clock.h> 62 #include <board_config.h> 85 #define QMC5883_CONVERSION_INTERVAL (1000000 / 150) 86 #define QMC5883_MAX_COUNT 32767 88 #define QMC5883_ADDR_DATA_OUT_X_LSB 0x00 89 #define QMC5883_ADDR_DATA_OUT_X_MSB 0x01 90 #define QMC5883_ADDR_DATA_OUT_Y_LSB 0x02 91 #define QMC5883_ADDR_DATA_OUT_Y_MSB 0x03 92 #define QMC5883_ADDR_DATA_OUT_Z_LSB 0x04 93 #define QMC5883_ADDR_DATA_OUT_Z_MSB 0x05 94 #define QMC5883_ADDR_STATUS 0x06 95 #define QMC5883_ADDR_TEMP_OUT_LSB 0x07 96 #define QMC5883_ADDR_TEMP_OUT_MSB 0x08 97 #define QMC5883_ADDR_CONTROL_1 0x09 98 #define QMC5883_ADDR_CONTROL_2 0x0A 99 #define QMC5883_ADDR_SET_RESET 0x0B 102 #define QMC5883_STATUS_REG_DRDY (1 << 0) 103 #define QMC5883_STATUS_REG_OVL (1 << 1) 104 #define QMC5883_STATUS_REG_DOR (1 << 2) 107 #define QMC5883_MODE_REG_STANDBY (0 << 0) 108 #define QMC5883_MODE_REG_CONTINOUS_MODE (1 << 0) 109 #define QMC5883_OUTPUT_DATA_RATE_10 (0 << 2) 110 #define QMC5883_OUTPUT_DATA_RATE_50 (1 << 2) 111 #define QMC5883_OUTPUT_DATA_RATE_100 (2 << 2) 112 #define QMC5883_OUTPUT_DATA_RATE_200 (3 << 2) 113 #define QMC5883_OUTPUT_RANGE_2G (0 << 4) 114 #define QMC5883_OUTPUT_RANGE_8G (1 << 4) 115 #define QMC5883_OVERSAMPLE_512 (0 << 6) 116 #define QMC5883_OVERSAMPLE_256 (1 << 6) 117 #define QMC5883_OVERSAMPLE_128 (2 << 6) 118 #define QMC5883_OVERSAMPLE_64 (3 << 6) 121 #define QMC5883_INT_ENB (1 << 0) 122 #define QMC5883_ROL_PNT (1 << 6) 123 #define QMC5883_SOFT_RESET (1 << 7) 126 #define QMC5883_SET_DEFAULT (1 << 0) 128 #define QMC5883_TEMP_OFFSET 50 145 virtual ssize_t
read(
struct file *filp,
char *buffer,
size_t buflen);
146 virtual int ioctl(
struct file *filp,
int cmd,
unsigned long arg);
244 int read_reg(uint8_t reg, uint8_t &val);
263 CDev(
"QMC5883", path),
264 ScheduledWorkItem(MODULE_NAME,
px4::device_bus_to_wq(interface->
get_device_id())),
360 uint8_t conf_reg_in = 0;
381 unsigned count = buflen /
sizeof(
struct mag_report);
405 return ret ? ret : -EAGAIN;
433 unsigned dummy = arg;
465 unsigned interval = (1000000 / arg);
507 return CDev::ioctl(filp, cmd, arg);
536 uint8_t data_bits_in = 0;
605 #pragma pack(push, 1) 617 uint8_t check_counter;
621 bool sensor_is_onboard =
false;
650 report.x = (((int16_t)qmc_report.x[1]) << 8) + qmc_report.x[0];
651 report.y = (((int16_t)qmc_report.y[1]) << 8) + qmc_report.y[0];
652 report.z = (((int16_t)qmc_report.z[1]) << 8) + qmc_report.z[0];
666 new_report.temperature = 0;
669 uint8_t raw_temperature[2];
674 raw_temperature,
sizeof(raw_temperature));
677 int16_t temp16 = (((int16_t)raw_temperature[1]) << 8) +
693 new_report.x_raw = -report.y;
694 new_report.y_raw = report.x;
696 new_report.z_raw = report.z;
703 new_report.is_external = !sensor_is_onboard;
705 if (sensor_is_onboard) {
708 report.y = -report.y;
709 report.x = -report.x;
763 if (check_counter == 0) {
797 _reports->print_info(
"report queue");
817 #ifdef PX4_I2C_BUS_EXPANSION1 820 #ifdef PX4_I2C_BUS_EXPANSION2 823 #ifdef PX4_I2C_BUS_ONBOARD 826 #ifdef PX4_SPIDEV_HMC 830 #define NUM_BUS_OPTIONS (sizeof(bus_options)/sizeof(bus_options[0])) 848 if (bus.
dev !=
nullptr) {
849 errx(1,
"bus option already started");
852 device::Device *
interface = bus.interface_constructor(bus.busnum);
854 if (interface->init() !=
OK) {
856 warnx(
"no device on bus %u (type: %u)", (
unsigned)bus.busnum, (
unsigned)bus.busid);
860 bus.dev =
new QMC5883(interface, bus.devpath, rotation);
862 if (bus.dev !=
nullptr &&
OK != bus.dev->init()) {
868 int fd =
open(bus.devpath, O_RDONLY);
876 errx(1,
"Failed to setup poll rate");
893 bool started =
false;
917 bool stopped =
false;
943 errx(1,
"bus %u not started", (
unsigned)busid);
959 const char *path = bus.
devpath;
961 int fd =
open(path, O_RDONLY);
964 err(1,
"%s open failed (try 'qmc5883 start')", path);
968 sz =
read(fd, &report,
sizeof(report));
970 if (sz !=
sizeof(report)) {
971 err(1,
"immediate read failed");
974 print_message(report);
978 errx(1,
"failed to get if mag is onboard or external");
981 warnx(
"device active: %s", ret ?
"external" :
"onboard");
984 for (
unsigned i = 0; i < 5; i++) {
990 ret =
poll(&fds, 1, 2000);
993 errx(1,
"timed out waiting for sensor data");
997 sz =
read(fd, &report,
sizeof(report));
999 if (sz !=
sizeof(report)) {
1000 err(1,
"periodic read failed");
1003 print_message(report);
1017 const char *path = bus.
devpath;
1019 int fd =
open(path, O_RDONLY);
1026 err(1,
"driver reset failed");
1030 err(1,
"driver poll restart failed");
1053 warnx(
"missing command: try 'start', 'info', 'test', 'reset', 'info'");
1055 warnx(
" -R rotation");
1056 warnx(
" -X only external bus");
1057 #if (PX4_I2C_BUS_ONBOARD || PX4_SPIDEV_HMC) 1058 warnx(
" -I only internal bus");
1076 while ((ch = getopt(argc, argv,
"XISR:CT")) != EOF) {
1079 rotation = (
enum Rotation)atoi(optarg);
1081 #if (PX4_I2C_BUS_ONBOARD || PX4_SPIDEV_HMC) 1102 const char *verb = argv[optind];
1107 if (!strcmp(verb,
"start")) {
1116 if (!strcmp(verb,
"stop")) {
1123 if (!strcmp(verb,
"test")) {
1130 if (!strcmp(verb,
"reset")) {
1138 if (!strcmp(verb,
"info") || !strcmp(verb,
"status")) {
1142 errx(1,
"unrecognized command, try 'start', 'test', 'reset', or 'info'");
#define QMC5883_ADDR_TEMP_OUT_LSB
#define MAGIOCGSCALE
copy the mag scaling constants to the structure pointed to by (arg)
#define MAGIOCGEXTERNAL
determine if mag is external or onboard
Local functions in support of the shell command.
virtual int open(file_t *filep)
Handle an open of the device.
void start(enum QMC5883_BUS busid, enum Rotation rotation)
Start the driver.
measure the time elapsed performing an event
uint8_t _temperature_counter
API for the uORB lightweight object broker.
__EXPORT int qmc5883_main(int argc, char *argv[])
virtual int register_class_devname(const char *class_devname)
Register a class device name, automatically adding device class instance suffix if need be...
#define SENSOR_POLLRATE_DEFAULT
poll at driver normal rate
__EXPORT void rotate_3f(enum Rotation rot, float &x, float &y, float &z)
rotate a 3 element float vector in-place
void usage(const char *reason)
Print the correct usage.
device::Device * QMC5883_SPI_interface(int bus)
#define QMC5883_CONVERSION_INTERVAL
mag scaling factors; Vout = (Vin * Vscale) + Voffset
struct qmc5883_bus_option & find_bus(enum QMC5883_BUS busid)
find a bus structure for a busid
Device(const Device &)=delete
struct mag_calibration_s _scale
QMC5883(device::Device *interface, const char *path, enum Rotation rotation)
count the number of times an event occurs
perf_counter_t _range_errors
#define QMC5883_MODE_REG_CONTINOUS_MODE
Shared defines for the qmc5883 driver.
#define QMC5883_SOFT_RESET
perf_counter_t _conf_errors
High-resolution timer with callouts and timekeeping.
#define QMC5883_ADDR_CONTROL_2
#define QMC5883_TEMP_OFFSET
virtual int close(file_t *filep)
Handle a close of the device.
Abstract class for any character device.
virtual void poll_notify(pollevent_t events)
Report new poll events.
#define MAGIOCSRANGE
set the measurement range to handle (at least) arg Gauss
QMC5883_constructor interface_constructor
uint32_t get_device_id() const
#define SENSORIOCSPOLLRATE
Set the driver polling rate to (arg) Hz, or one of the SENSOR_POLLRATE constants. ...
int read_reg(uint8_t reg, uint8_t &val)
Read a register.
void Run() override
Perform a poll cycle; collect from the previous measurement and start a new one.
Generic device / sensor interface.
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
#define QMC5883_ADDR_SET_RESET
device identifier information
void perf_count(perf_counter_t handle)
Count a performance event.
void usage()
Prints info about the driver argument usage.
bool start_bus(struct qmc5883_bus_option &bus, enum Rotation rotation)
start driver for a specific bus option
#define MAGIOCSSCALE
set the mag scaling constants to the structure pointed to by (arg)
void print_info()
Diagnostics - print some basic information about the driver.
device::Device *(* QMC5883_constructor)(int)
void perf_free(perf_counter_t handle)
Free a counter.
#define MAG_BASE_DEVICE_PATH
#define QMC5883_MAX_COUNT
void init()
Activates/configures the hardware registers.
perf_counter_t _sample_perf
virtual int unregister_class_devname(const char *class_devname, unsigned class_instance)
Register a class device name, automatically adding device class instance suffix if need be...
Rotation
Enum for board and external compass rotations.
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
#define QMC5883_OUTPUT_DATA_RATE_200
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
virtual int ioctl(struct file *filp, int cmd, unsigned long arg)
void perf_end(perf_counter_t handle)
End a performance event.
void start()
Initialise the automatic measurement state machine and start it.
int write_reg(uint8_t reg, uint8_t val)
Write a register.
int info(enum QMC5883_BUS busid)
Print a little info about the driver.
void test(enum QMC5883_BUS busid)
Perform some basic functional tests on the driver; make sure we can collect data from the sensor in p...
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
void reset(enum QMC5883_BUS busid)
Reset the driver.
void stop()
Stop the automatic measurement state machine.
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
uint8_t _temperature_error_count
QMC5883 operator=(const QMC5883 &)
void check_conf(void)
check the sensor configuration.
#define DRV_MAG_DEVTYPE_QMC5883
unsigned _measure_interval
virtual ssize_t read(struct file *filp, char *buffer, size_t buflen)
#define QMC5883_SET_DEFAULT
#define QMC5883_ADDR_DATA_OUT_X_LSB
struct @83::@85::@87 file
#define QMC5883_OVERSAMPLE_512
void perf_print_counter(perf_counter_t handle)
Print one performance counter to stdout.
#define SENSORIOCRESET
Reset the sensor to its default configuration.
uint64_t perf_event_count(perf_counter_t handle)
Return current event_count.
Fundamental base class for all physical drivers (I2C, SPI).
CDev(const char *name, const char *devname)
Constructor.
#define QMC5883_ADDR_CONTROL_1
int temp_enable(QMC5883_BUS busid, bool enable)
bool _sensor_ok
sensor was found and reports ok
perf_counter_t _comms_errors
#define QMC5883_OUTPUT_RANGE_2G
int reset()
Reset the device.
bool _pub_blocked
true if publishing should be blocked
Dual< Scalar, N > abs(const Dual< Scalar, N > &a)
orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
device::Device * QMC5883_I2C_interface(int bus)
void perf_begin(perf_counter_t handle)
Begin a performance event.
struct qmc5883::qmc5883_bus_option bus_options[]
#define DEVICE_DEBUG(FMT,...)
ringbuffer::RingBuffer * _reports
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
int collect()
Collect the result of the most recent measurement.
int stop()
Stop the driver.
virtual int poll(file_t *filep, px4_pollfd_struct_t *fds, bool setup)
Perform a poll setup/teardown operation.
Performance measuring tools.
Base class for devices connected via I2C.