PX4 Firmware
PX4 Autopilot Software http://px4.io
mpu6000_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 #include "MPU6000.hpp"
35 
36 /**
37  * Local functions in support of the shell command.
38  */
39 namespace mpu6000
40 {
41 
42 /*
43  list of supported bus configurations
44  */
45 
50  uint8_t busnum;
51  bool external;
53 } bus_options[] = {
54 #if defined (USE_I2C)
55 # if defined(PX4_I2C_BUS_ONBOARD)
56  { MPU6000_BUS_I2C_INTERNAL, MPU_DEVICE_TYPE_MPU6000, &MPU6000_I2C_interface, PX4_I2C_BUS_ONBOARD, false, NULL },
57 # endif
58 # if defined(PX4_I2C_BUS_EXPANSION)
59  { MPU6000_BUS_I2C_EXTERNAL, MPU_DEVICE_TYPE_MPU6000, &MPU6000_I2C_interface, PX4_I2C_BUS_EXPANSION, true, NULL },
60 # endif
61 # if defined(PX4_I2C_BUS_EXPANSION1)
62  { MPU6000_BUS_I2C_EXTERNAL, MPU_DEVICE_TYPE_MPU6000, &MPU6000_I2C_interface, PX4_I2C_BUS_EXPANSION1, true, NULL },
63 # endif
64 # if defined(PX4_I2C_BUS_EXPANSION2)
65  { MPU6000_BUS_I2C_EXTERNAL, MPU_DEVICE_TYPE_MPU6000, &MPU6000_I2C_interface, PX4_I2C_BUS_EXPANSION2, true, NULL },
66 # endif
67 #endif
68 #ifdef PX4_SPIDEV_MPU
69  { MPU6000_BUS_SPI_INTERNAL1, MPU_DEVICE_TYPE_MPU6000, &MPU6000_SPI_interface, PX4_SPI_BUS_SENSORS, false, NULL },
70 #endif
71 #if defined(PX4_SPI_BUS_EXT)
73 #endif
74 #if defined(PX4_SPIDEV_ICM_20602) && defined(PX4_SPI_BUS_SENSORS)
75  { MPU6000_BUS_SPI_INTERNAL1, MPU_DEVICE_TYPE_ICM20602, &MPU6000_SPI_interface, PX4_SPI_BUS_SENSORS, false, NULL },
76 #endif
77 #if defined(PX4_SPIDEV_ICM_20602) && defined(PX4_SPI_BUS_SENSORS1)
78  { MPU6000_BUS_SPI_INTERNAL1, MPU_DEVICE_TYPE_ICM20602, &MPU6000_SPI_interface, PX4_SPI_BUS_SENSORS1, false, NULL },
79 #endif
80 #if defined(PX4_SPIDEV_ICM_20602) && defined(PX4_SPI_BUS_1)
82 #endif
83 #ifdef PX4_SPIDEV_ICM_20608
84  { MPU6000_BUS_SPI_INTERNAL1, MPU_DEVICE_TYPE_ICM20608, &MPU6000_SPI_interface, PX4_SPI_BUS_SENSORS, false, NULL },
85 #endif
86 #ifdef PX4_SPIDEV_ICM_20689
87  { MPU6000_BUS_SPI_INTERNAL2, MPU_DEVICE_TYPE_ICM20689, &MPU6000_SPI_interface, PX4_SPI_BUS_SENSORS, false, NULL },
88 #endif
89 #if defined(PX4_SPI_BUS_EXTERNAL)
90  { MPU6000_BUS_SPI_EXTERNAL1, MPU_DEVICE_TYPE_MPU6000, &MPU6000_SPI_interface, PX4_SPI_BUS_EXTERNAL, true, NULL },
91  { MPU6000_BUS_SPI_EXTERNAL2, MPU_DEVICE_TYPE_MPU6000, &MPU6000_SPI_interface, PX4_SPI_BUS_EXTERNAL, true, NULL },
92 #endif
93 };
94 
95 #define NUM_BUS_OPTIONS (sizeof(bus_options)/sizeof(bus_options[0]))
96 
97 
98 void start(enum MPU6000_BUS busid, enum Rotation rotation, int device_type);
99 bool start_bus(struct mpu6000_bus_option &bus, enum Rotation rotation, int device_type);
100 void stop(enum MPU6000_BUS busid);
101 static struct mpu6000_bus_option &find_bus(enum MPU6000_BUS busid);
102 void reset(enum MPU6000_BUS busid);
103 void info(enum MPU6000_BUS busid);
104 void regdump(enum MPU6000_BUS busid);
105 void testerror(enum MPU6000_BUS busid);
106 #ifndef CONSTRAINED_FLASH
107 void factorytest(enum MPU6000_BUS busid);
108 #endif
109 void usage();
110 
111 /**
112  * find a bus structure for a busid
113  */
115 {
116  for (uint8_t i = 0; i < NUM_BUS_OPTIONS; i++) {
117  if ((busid == MPU6000_BUS_ALL ||
118  busid == bus_options[i].busid) && bus_options[i].dev != NULL) {
119  return bus_options[i];
120  }
121  }
122 
123  errx(1, "bus %u not started", (unsigned)busid);
124 }
125 
126 /**
127  * start driver for a specific bus option
128  */
129 bool
130 start_bus(struct mpu6000_bus_option &bus, enum Rotation rotation, int device_type)
131 {
132  if (bus.dev != nullptr) {
133  warnx("%s SPI not available", bus.external ? "External" : "Internal");
134  return false;
135  }
136 
137  device::Device *interface = bus.interface_constructor(bus.busnum, device_type, bus.external);
138 
139  if (interface == nullptr) {
140  warnx("failed creating interface for bus #%u (SPI%u)", (unsigned)bus.busid, (unsigned)bus.busnum);
141  return false;
142  }
143 
144  if (interface->init() != OK) {
145  delete interface;
146  warnx("no device on bus #%u (SPI%u)", (unsigned)bus.busid, (unsigned)bus.busnum);
147  return false;
148  }
149 
150  bus.dev = new MPU6000(interface, rotation, device_type);
151 
152  if (bus.dev == nullptr) {
153  delete interface;
154  return false;
155  }
156 
157  if (OK != bus.dev->init()) {
158  goto fail;
159  }
160 
161  /* set the poll rate to default, starts automatic data collection */
162 
163  bus.dev->start();
164 
165  return true;
166 
167 fail:
168 
169  if (bus.dev != nullptr) {
170  delete bus.dev;
171  bus.dev = nullptr;
172  }
173 
174  return false;
175 }
176 
177 /**
178  * Start the driver.
179  *
180  * This function only returns if the driver is up and running
181  * or failed to detect the sensor.
182  */
183 void
184 start(enum MPU6000_BUS busid, enum Rotation rotation, int device_type)
185 {
186  bool started = false;
187 
188  for (unsigned i = 0; i < NUM_BUS_OPTIONS; i++) {
189  if (busid == MPU6000_BUS_ALL && bus_options[i].dev != NULL) {
190  // this device is already started
191  continue;
192  }
193 
194  if (busid != MPU6000_BUS_ALL && bus_options[i].busid != busid) {
195  // not the one that is asked for
196  continue;
197  }
198 
199  if (bus_options[i].device_type != device_type) {
200  // not the one that is asked for
201  continue;
202  }
203 
204  started |= start_bus(bus_options[i], rotation, device_type);
205  }
206 
207  exit(started ? 0 : 1);
208 }
209 
210 void
212 {
213  struct mpu6000_bus_option &bus = find_bus(busid);
214 
215  if (bus.dev != nullptr) {
216  delete bus.dev;
217  bus.dev = nullptr;
218 
219  } else {
220  /* warn, but not an error */
221  warnx("already stopped.");
222  }
223 
224  exit(0);
225 }
226 
227 /**
228  * Reset the driver.
229  */
230 void
232 {
233  struct mpu6000_bus_option &bus = find_bus(busid);
234 
235  if (bus.dev == nullptr) {
236  errx(1, "driver not running");
237  }
238 
239  bus.dev->reset();
240 
241  exit(0);
242 }
243 
244 /**
245  * Print a little info about the driver.
246  */
247 void
249 {
250  struct mpu6000_bus_option &bus = find_bus(busid);
251 
252  if (bus.dev == nullptr) {
253  errx(1, "driver not running");
254  }
255 
256  bus.dev->print_info();
257 
258  exit(0);
259 }
260 
261 /**
262  * Dump the register information
263  */
264 void
266 {
267  struct mpu6000_bus_option &bus = find_bus(busid);
268 
269  if (bus.dev == nullptr) {
270  errx(1, "driver not running");
271  }
272 
273  printf("regdump @ %p\n", bus.dev);
274  bus.dev->print_registers();
275 
276  exit(0);
277 }
278 
279 /**
280  * deliberately produce an error to test recovery
281  */
282 void
284 {
285  struct mpu6000_bus_option &bus = find_bus(busid);
286 
287 
288  if (bus.dev == nullptr) {
289  errx(1, "driver not running");
290  }
291 
292  bus.dev->test_error();
293 
294  exit(0);
295 }
296 
297 #ifndef CONSTRAINED_FLASH
298 /**
299  * Dump the register information
300  */
301 void
303 {
304  struct mpu6000_bus_option &bus = find_bus(busid);
305 
306 
307  if (bus.dev == nullptr) {
308  errx(1, "driver not running");
309  }
310 
311  bus.dev->factory_self_test();
312 
313  exit(0);
314 }
315 #endif
316 
317 void
319 {
320  warnx("missing command: try 'start', 'info', 'stop',\n'reset', 'regdump', 'testerror'"
321 #ifndef CONSTRAINED_FLASH
322  ", 'factorytest'"
323 #endif
324  );
325  warnx("options:");
326  warnx(" -X external I2C bus");
327  warnx(" -I internal I2C bus");
328  warnx(" -S external SPI bus");
329  warnx(" -s internal SPI bus");
330  warnx(" -Z external1 SPI bus");
331  warnx(" -z internal2 SPI bus");
332  warnx(" -T 6000|20608|20602 (default 6000)");
333  warnx(" -R rotation");
334 }
335 
336 } // namespace
337 
338 /** driver 'main' command */
339 extern "C" { __EXPORT int mpu6000_main(int argc, char *argv[]); }
340 
341 int
342 mpu6000_main(int argc, char *argv[])
343 {
344  int myoptind = 1;
345  int ch;
346  const char *myoptarg = nullptr;
347 
350  enum Rotation rotation = ROTATION_NONE;
351 
352  while ((ch = px4_getopt(argc, argv, "T:XISsZzR:a:", &myoptind, &myoptarg)) != EOF) {
353  switch (ch) {
354  case 'X':
355  busid = MPU6000_BUS_I2C_EXTERNAL;
356  break;
357 
358  case 'I':
359  busid = MPU6000_BUS_I2C_INTERNAL;
360  break;
361 
362  case 'S':
364  break;
365 
366  case 's':
368  break;
369 
370  case 'Z':
372  break;
373 
374  case 'z':
376  break;
377 
378  case 'T':
379  device_type = atoi(myoptarg);
380  break;
381 
382  case 'R':
383  rotation = (enum Rotation)atoi(myoptarg);
384  break;
385 
386  default:
387  mpu6000::usage();
388  return 0;
389  }
390  }
391 
392  if (myoptind >= argc) {
393  mpu6000::usage();
394  return -1;
395  }
396 
397  const char *verb = argv[myoptind];
398 
399  /*
400  * Start/load the driver.
401  */
402  if (!strcmp(verb, "start")) {
403  mpu6000::start(busid, rotation, device_type);
404  }
405 
406  if (!strcmp(verb, "stop")) {
407  mpu6000::stop(busid);
408  }
409 
410  /*
411  * Reset the driver.
412  */
413  if (!strcmp(verb, "reset")) {
414  mpu6000::reset(busid);
415  }
416 
417  /*
418  * Print driver information.
419  */
420  if (!strcmp(verb, "info") || !strcmp(verb, "status")) {
421  mpu6000::info(busid);
422  }
423 
424  /*
425  * Print register information.
426  */
427  if (!strcmp(verb, "regdump")) {
428  mpu6000::regdump(busid);
429  }
430 
431 #ifndef CONSTRAINED_FLASH
432 
433  if (!strcmp(verb, "factorytest")) {
434  mpu6000::factorytest(busid);
435  }
436 
437 #endif
438 
439  if (!strcmp(verb, "testerror")) {
440  mpu6000::testerror(busid);
441  }
442 
443  mpu6000::usage();
444  return -1;
445 }
device::Device * MPU6000_SPI_interface(int bus, int device_type, bool external_bus)
device::Device *(* MPU6000_constructor)(int, int, bool)
Definition: MPU6000.hpp:270
void start(enum MPU6000_BUS busid, enum Rotation rotation, int device_type)
Start the driver.
int factory_self_test()
Test behaviour against factory offsets.
Definition: MPU6000.cpp:383
Definition: I2C.hpp:51
void usage()
Prints info about the driver argument usage.
__EXPORT int mpu6000_main(int argc, char *argv[])
driver &#39;main&#39; command
Local functions in support of the shell command.
static struct mpu6000_bus_option & find_bus(enum MPU6000_BUS busid)
find a bus structure for a busid
void info(enum MPU6000_BUS busid)
Print a little info about the driver.
bool start_bus(struct mpu6000_bus_option &bus, enum Rotation rotation, int device_type)
start driver for a specific bus option
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
void regdump(enum MPU6000_BUS busid)
Dump the register information.
int reset()
Reset chip.
Definition: MPU6000.cpp:110
#define warnx(...)
Definition: err.h:95
void test_error()
Definition: MPU6000.cpp:526
struct mpu6000::mpu6000_bus_option bus_options[]
void testerror(enum MPU6000_BUS busid)
deliberately produce an error to test recovery
device::Device * MPU6000_I2C_interface(int bus, int device_type, bool external_bus)
Fundamental base class for all physical drivers (I2C, SPI).
Definition: Device.hpp:65
#define errx(eval,...)
Definition: err.h:89
void reset(enum MPU6000_BUS busid)
Reset the driver.
void print_info()
Diagnostics - print some basic information about the driver.
Definition: MPU6000.cpp:886
void print_registers()
Definition: MPU6000.cpp:899
#define OK
Definition: uavcan_main.cpp:71
void factorytest(enum MPU6000_BUS busid)
Dump the register information.
#define NUM_BUS_OPTIONS
void stop(enum MPU6000_BUS busid)
MPU_DEVICE_TYPE
Definition: MPU6000.hpp:91
MPU6000_BUS
Definition: MPU6000.hpp:275
MPU6000_constructor interface_constructor