PX4 Firmware
PX4 Autopilot Software http://px4.io
lis3mdl_main.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file lis3mdl_main.cpp
36  *
37  * Driver for the LIS3MDL magnetometer connected via I2C or SPI.
38  */
39 
40 #include "lis3mdl_main.h"
41 #include <px4_platform_common/getopt.h>
42 
43 /**
44  * Driver 'main' command.
45  */
46 extern "C" __EXPORT int lis3mdl_main(int argc, char *argv[]);
47 
48 int
50 {
51  int ret;
52  const char *path = bus.devpath;
53 
54  PX4_INFO("running on bus: %u (%s)", (unsigned)bus.bus_id, bus.devpath);
55 
56  int fd = open(path, O_RDONLY);
57 
58  if (fd < 0) {
59  PX4_WARN("%s open failed (try 'lis3mdl start' if the driver is not running", path);
60  return PX4_ERROR;
61  }
62 
63  if ((ret = ioctl(fd, MAGIOCCALIBRATE, fd)) != OK) {
64  PX4_WARN("failed to enable sensor calibration mode");
65  }
66 
67  close(fd);
68 
69  return ret;
70 }
71 
72 int
74 {
75  PX4_INFO("running on bus: %u (%s)", (unsigned)bus.bus_id, bus.devpath);
76  bus.dev->print_info();
77  return PX4_OK;
78 }
79 
80 int
82 {
83  const char *path = bus.devpath;
84 
85  int fd = open(path, O_RDONLY);
86 
87  if (fd < 0) {
88  return PX4_ERROR;
89  }
90 
91  if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) {
92  close(fd);
93  errx(1, "Failed to setup poll rate");
94  return PX4_ERROR;
95 
96  } else {
97  PX4_INFO("Poll rate set to max (80hz)");
98  }
99 
100  close(fd);
101 
102  return PX4_OK;
103 }
104 
105 int
107 {
108  if (bus.dev != nullptr) {
109  errx(1, "bus option already started");
110  return PX4_ERROR;
111  }
112 
113  device::Device *interface = bus.interface_constructor(bus.busnum);
114 
115  if (interface->init() != OK) {
116  delete interface;
117  warnx("no device on bus %u", (unsigned)bus.bus_id);
118  return PX4_ERROR;
119  }
120 
121  bus.dev = new LIS3MDL(interface, bus.devpath, rotation);
122 
123  if (bus.dev != nullptr &&
124  bus.dev->init() != OK) {
125  delete bus.dev;
126  bus.dev = NULL;
127  return PX4_ERROR;
128  }
129 
130  return PX4_OK;
131 }
132 
133 int
135 {
136  if (bus.dev == NULL) {
137  return start_bus(bus, rotation);
138 
139  } else {
140  // this device is already started
141  return PX4_ERROR;
142  }
143 }
144 
145 int
147 {
148  if (bus.dev != NULL) {
149  bus.dev->stop();
150  delete bus.dev;
151  bus.dev = nullptr;
152  return PX4_OK;
153 
154  } else {
155  // this device is already stopped
156  return PX4_ERROR;
157  }
158 }
159 
160 int
162 {
163  struct mag_report report;
164  ssize_t sz;
165  int ret;
166  const char *path = bus.devpath;
167 
168  PX4_INFO("running on bus: %u (%s)", (unsigned)bus.bus_id, bus.devpath);
169 
170  int fd = open(path, O_RDONLY);
171 
172  if (fd < 0) {
173  PX4_WARN("%s open failed (try 'lis3mdl start')", path);
174  return PX4_ERROR;
175  }
176 
177  /* do a simple demand read */
178  sz = read(fd, &report, sizeof(report));
179 
180  if (sz != sizeof(report)) {
181  PX4_WARN("immediate read failed");
182  return PX4_ERROR;
183  }
184 
185  print_message(report);
186 
187  /* check if mag is onboard or external */
188  if (ioctl(fd, MAGIOCGEXTERNAL, 0) < 0) {
189  PX4_WARN("failed to get if mag is onboard or external");
190  return PX4_ERROR;
191  }
192 
193  /* start the sensor polling at 2Hz */
194  if (ioctl(fd, SENSORIOCSPOLLRATE, 2) != OK) {
195  PX4_WARN("failed to set 2Hz poll rate");
196  return PX4_ERROR;
197  }
198 
199  struct pollfd fds;
200 
201  /* read the sensor 5x and report each value */
202  for (unsigned i = 0; i < 5; i++) {
203 
204  /* wait for data to be ready */
205  fds.fd = fd;
206  fds.events = POLLIN;
207  ret = poll(&fds, 1, 2000);
208 
209  if (ret != 1) {
210  PX4_WARN("timed out waiting for sensor data");
211  return PX4_ERROR;
212  }
213 
214  /* now go get it */
215  sz = read(fd, &report, sizeof(report));
216 
217  if (sz != sizeof(report)) {
218  PX4_WARN("periodic read failed");
219  return PX4_ERROR;
220  }
221 
222  print_message(report);
223  }
224 
225  PX4_INFO("PASS");
226  return PX4_OK;
227 }
228 
229 int
231 {
232  const char *path = bus.devpath;
233 
234  PX4_INFO("running on bus: %u (%s)", (unsigned)bus.bus_id, bus.devpath);
235 
236  int fd = open(path, O_RDONLY);
237 
238  if (fd < 0) {
239  PX4_WARN("open failed ");
240  return PX4_ERROR;
241  }
242 
243  if (ioctl(fd, SENSORIOCRESET, 0) < 0) {
244  PX4_WARN("driver reset failed");
245  return PX4_ERROR;
246  }
247 
248  if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) {
249  PX4_WARN("driver poll restart failed");
250  return PX4_ERROR;
251  }
252 
253  return PX4_OK;
254 }
255 
256 void
258 {
259  PX4_WARN("missing command: try 'start', 'info', 'test', 'reset', 'info', 'calibrate'");
260  PX4_WARN("options:");
261  PX4_WARN(" -R rotation");
262  PX4_WARN(" -C calibrate on start");
263  PX4_WARN(" -X only external bus");
264  PX4_WARN(" -S only spi bus");
265 #if (PX4_I2C_BUS_ONBOARD || PX4_SPIDEV_LIS)
266  PX4_WARN(" -I only internal bus");
267 #endif
268 }
269 
270 int
271 lis3mdl_main(int argc, char *argv[])
272 {
273  int myoptind = 1;
274  int ch;
275  const char *myoptarg = nullptr;
276 
277  bool calibrate = false;
278  enum LIS3MDL_BUS bus_id = LIS3MDL_BUS_ALL;
279  enum Rotation rotation = ROTATION_NONE;
280 
281  while ((ch = px4_getopt(argc, argv, "XISR:CT", &myoptind, &myoptarg)) != EOF) {
282  switch (ch) {
283  case 'R':
284  rotation = (enum Rotation)atoi(myoptarg);
285  break;
286 #if (PX4_I2C_BUS_ONBOARD || PX4_SPIDEV_LIS)
287 
288  case 'I':
289  bus_id = LIS3MDL_BUS_I2C_INTERNAL;
290  break;
291 #endif
292 
293  case 'X':
294  bus_id = LIS3MDL_BUS_I2C_EXTERNAL;
295  break;
296 
297  case 'S':
298  bus_id = LIS3MDL_BUS_SPI;
299  break;
300 
301  case 'C':
302  calibrate = true;
303  break;
304 
305  default:
306  lis3mdl::usage();
307  return PX4_ERROR;
308  }
309  }
310 
311  if (myoptind >= argc) {
312  lis3mdl::usage();
313  return PX4_ERROR;
314  }
315 
316  const char *verb = argv[myoptind];
317  int ret;
318  bool dev_found = false;
319  bool cmd_found = false;
320 
321  if (!strcmp(verb, "start")) {
322  // Start/load the driver
323 
324  cmd_found = true;
325  ret = 1; // default: failed, will be set to success if one start succeeds
326 
327  for (unsigned i = 0; i < NUM_BUS_OPTIONS; i++) {
328  if (bus_id != LIS3MDL_BUS_ALL && bus_id != lis3mdl::bus_options[i].bus_id) {
329  // not the one that is asked for
330  continue;
331  }
332 
333  dev_found = true;
334 
335  // Start/load the driver
336  if (lis3mdl::start(lis3mdl::bus_options[i], rotation) == OK) {
337  if (calibrate) {
339  PX4_WARN("calibration failed");
340  lis3mdl::stop(lis3mdl::bus_options[i]); //Stop, failed
341 
342  } else {
343  PX4_INFO("calibration successful");
345  ret = 0; // one succeed
346  }
347 
348  } else {
350  ret = 0; // one succeed
351  }
352  }
353  }
354 
355  } else {
356  // Other commands
357 
358  ret = 0; // default: success, will be set to failed if one action fails
359 
360  for (unsigned i = 0; i < NUM_BUS_OPTIONS; i++) {
361  if (bus_id != LIS3MDL_BUS_ALL && bus_id != lis3mdl::bus_options[i].bus_id) {
362  // not the one that is asked for
363  continue;
364  }
365 
366  if (lis3mdl::bus_options[i].dev == NULL) {
367  if (bus_id != LIS3MDL_BUS_ALL) {
368  PX4_ERR("bus %u not started", (unsigned)bus_id);
369  return PX4_ERROR;
370 
371  } else {
372  continue;
373  }
374  }
375 
376  dev_found = true;
377 
378  // Stop the driver
379  if (!strcmp(verb, "stop")) {
380  cmd_found = true;
382  }
383 
384  // Test the driver/device
385  if (!strcmp(verb, "test")) {
386  cmd_found = true;
388  }
389 
390  // Reset the driver
391  if (!strcmp(verb, "reset")) {
392  cmd_found = true;
394  }
395 
396  // Print driver information
397  if (!strcmp(verb, "info") ||
398  !strcmp(verb, "status")) {
399  cmd_found = true;
401  }
402 
403  // Autocalibrate the scaling
404  if (!strcmp(verb, "calibrate")) {
405  cmd_found = true;
406 
408  PX4_INFO("calibration successful");
409 
410  } else {
411  PX4_WARN("calibration failed");
412  ret = 1;
413  }
414  }
415  }
416  }
417 
418  if (!dev_found) {
419  PX4_WARN("no device found, please start driver first");
420  return PX4_ERROR;
421 
422  } else if (!cmd_found) {
423  PX4_WARN("unrecognized command, try 'start', 'test', 'reset', 'calibrate' 'or 'info'");
424  return PX4_ERROR;
425 
426  } else {
427  return ret;
428  }
429 }
void print_info()
Diagnostics - print some basic information about the driver.
Definition: lis3mdl.cpp:602
#define MAGIOCGEXTERNAL
determine if mag is external or onboard
Definition: drv_mag.h:88
int init(struct lis3mdl_bus_option &bus)
Initializes the driver – sets defaults and starts a cycle.
#define SENSOR_POLLRATE_DEFAULT
poll at driver normal rate
Definition: drv_sensor.h:136
Definition: I2C.hpp:51
struct lis3mdl::lis3mdl_bus_option bus_options[]
int reset(struct lis3mdl_bus_option &bus)
Resets the driver.
void stop()
Stop the automatic measurement state machine.
Definition: lis3mdl.cpp:797
static void read(bootloader_app_shared_t *pshared)
#define SENSORIOCSPOLLRATE
Set the driver polling rate to (arg) Hz, or one of the SENSOR_POLLRATE constants. ...
Definition: drv_sensor.h:134
LIS3MDL_BUS
Definition: lis3mdl.h:98
#define MAGIOCCALIBRATE
perform self-calibration, update scale factors to canonical units
Definition: drv_mag.h:82
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
__EXPORT int lis3mdl_main(int argc, char *argv[])
Driver &#39;main&#39; command.
#define warnx(...)
Definition: err.h:95
#define NUM_BUS_OPTIONS
static bool start_bus(bmp280_bus_option &bus)
Definition: bmp280_main.cpp:88
int fd
Definition: dataman.cpp:146
int info(struct lis3mdl_bus_option &bus)
Prints info about the driver.
#define SENSORIOCRESET
Reset the sensor to its default configuration.
Definition: drv_sensor.h:141
Fundamental base class for all physical drivers (I2C, SPI).
Definition: Device.hpp:65
#define errx(eval,...)
Definition: err.h:89
void usage()
Prints info about the driver argument usage.
int calibrate(struct lis3mdl_bus_option &bus)
Calibrate and self test.
#define OK
Definition: uavcan_main.cpp:71
int stop(struct lis3mdl_bus_option &bus)
Stop the driver.
static int calibrate(enum HMC5883_BUS busid)
Automatic scale calibration.
int test(struct lis3mdl_bus_option &bus)
Perform some basic functional tests on the driver; make sure we can collect data from the sensor in p...
int start(struct lis3mdl_bus_option &bus, Rotation rotation)
Starts the driver.
int start_bus(struct lis3mdl_bus_option &bus, Rotation rotation)
Starts the driver for a specific bus option.
#define mag_report
Definition: drv_mag.h:53