PX4 Firmware
PX4 Autopilot Software http://px4.io
bmi088_main.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2018 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 "BMI088_accel.hpp"
35 #include "BMI088_gyro.hpp"
36 
37 /** driver 'main' command */
38 extern "C" { __EXPORT int bmi088_main(int argc, char *argv[]); }
39 
44 };
45 
46 namespace bmi088
47 {
48 
49 BMI088_accel *g_acc_dev_int; // on internal bus (accel)
50 BMI088_accel *g_acc_dev_ext; // on external bus (accel)
51 BMI088_gyro *g_gyr_dev_int; // on internal bus (gyro)
52 BMI088_gyro *g_gyr_dev_ext; // on external bus (gyro)
53 
54 void start(bool, enum Rotation, enum sensor_type);
55 void stop(bool, enum sensor_type);
56 void info(bool, enum sensor_type);
57 void regdump(bool, enum sensor_type);
58 void testerror(bool, enum sensor_type);
59 void usage();
60 
61 /**
62  * Start the driver.
63  *
64  * This function only returns if the driver is up and running
65  * or failed to detect the sensor.
66  */
67 void
68 start(bool external_bus, enum Rotation rotation, enum sensor_type sensor)
69 {
70 
71  BMI088_accel **g_dev_acc_ptr = external_bus ? &g_acc_dev_ext : &g_acc_dev_int;
72  const char *path_accel = external_bus ? BMI088_DEVICE_PATH_ACCEL_EXT : BMI088_DEVICE_PATH_ACCEL;
73 
74  BMI088_gyro **g_dev_gyr_ptr = external_bus ? &g_gyr_dev_ext : &g_gyr_dev_int;
75  const char *path_gyro = external_bus ? BMI088_DEVICE_PATH_GYRO_EXT : BMI088_DEVICE_PATH_GYRO;
76 
77  if (sensor == BMI088_ACCEL) {
78  if (*g_dev_acc_ptr != nullptr)
79  /* if already started, the still command succeeded */
80  {
81  errx(0, "bmi088 accel sensor already started");
82  }
83 
84  /* create the driver */
85  if (external_bus) {
86 #if defined(PX4_SPI_BUS_EXT) && defined(PX4_SPIDEV_EXT_BMI)
87  *g_dev_acc_ptr = new BMI088_accel(PX4_SPI_BUS_EXT, path_accel, PX4_SPIDEV_EXT_BMI, rotation);
88 #else
89  errx(0, "External SPI not available");
90 #endif
91 
92  } else {
93  *g_dev_acc_ptr = new BMI088_accel(PX4_SPI_BUS_SENSORS3, path_accel, PX4_SPIDEV_BMI088_ACC, rotation);
94  }
95 
96  if (*g_dev_acc_ptr == nullptr) {
97  goto fail_accel;
98  }
99 
100  if (OK != (*g_dev_acc_ptr)->init()) {
101  goto fail_accel;
102  }
103 
104  // start automatic data collection
105  (*g_dev_acc_ptr)->start();
106  }
107 
108  if (sensor == BMI088_GYRO) {
109 
110  if (*g_dev_gyr_ptr != nullptr) {
111  errx(0, "bmi088 gyro sensor already started");
112  }
113 
114  /* create the driver */
115  if (external_bus) {
116 #if defined(PX4_SPI_BUS_EXT) && defined(PX4_SPIDEV_EXT_BMI)
117  *g_dev_ptr = new BMI088_gyro(PX4_SPI_BUS_EXT, path_gyro, PX4_SPIDEV_EXT_BMI, rotation);
118 #else
119  errx(0, "External SPI not available");
120 #endif
121 
122  } else {
123  *g_dev_gyr_ptr = new BMI088_gyro(PX4_SPI_BUS_SENSORS3, path_gyro, PX4_SPIDEV_BMI088_GYR, rotation);
124  }
125 
126  if (*g_dev_gyr_ptr == nullptr) {
127  goto fail_gyro;
128  }
129 
130  if (OK != (*g_dev_gyr_ptr)->init()) {
131  goto fail_gyro;
132  }
133 
134  // start automatic data collection
135  (*g_dev_gyr_ptr)->start();
136  }
137 
138  exit(PX4_OK);
139 
140 fail_accel:
141 
142  if (*g_dev_acc_ptr != nullptr) {
143  delete (*g_dev_acc_ptr);
144  *g_dev_acc_ptr = nullptr;
145  }
146 
147  PX4_WARN("No BMI088 accel found");
148  exit(PX4_ERROR);
149 
150 fail_gyro:
151 
152  if (*g_dev_gyr_ptr != nullptr) {
153  delete (*g_dev_gyr_ptr);
154  *g_dev_gyr_ptr = nullptr;
155  }
156 
157  PX4_WARN("No BMI088 gyro found");
158  exit(PX4_ERROR);
159 }
160 
161 void
162 stop(bool external_bus, enum sensor_type sensor)
163 {
164  BMI088_accel **g_dev_acc_ptr = external_bus ? &g_acc_dev_ext : &g_acc_dev_int;
165  BMI088_gyro **g_dev_gyr_ptr = external_bus ? &g_gyr_dev_ext : &g_gyr_dev_int;
166 
167  if (sensor == BMI088_ACCEL) {
168  if (*g_dev_acc_ptr != nullptr) {
169  delete *g_dev_acc_ptr;
170  *g_dev_acc_ptr = nullptr;
171 
172  } else {
173  /* warn, but not an error */
174  warnx("bmi088 accel sensor already stopped.");
175  }
176  }
177 
178  if (sensor == BMI088_GYRO) {
179  if (*g_dev_gyr_ptr != nullptr) {
180  delete *g_dev_gyr_ptr;
181  *g_dev_gyr_ptr = nullptr;
182 
183  } else {
184  /* warn, but not an error */
185  warnx("bmi088 gyro sensor already stopped.");
186  }
187  }
188 
189  exit(0);
190 
191 }
192 
193 /**
194  * Print a little info about the driver.
195  */
196 void
197 info(bool external_bus, enum sensor_type sensor)
198 {
199  BMI088_accel **g_dev_acc_ptr = external_bus ? &g_acc_dev_ext : &g_acc_dev_int;
200  BMI088_gyro **g_dev_gyr_ptr = external_bus ? &g_gyr_dev_ext : &g_gyr_dev_int;
201 
202  if (sensor == BMI088_ACCEL) {
203  if (*g_dev_acc_ptr == nullptr) {
204  errx(1, "bmi088 accel driver not running");
205  }
206 
207  printf("state @ %p\n", *g_dev_acc_ptr);
208  (*g_dev_acc_ptr)->print_info();
209  }
210 
211  if (sensor == BMI088_GYRO) {
212  if (*g_dev_gyr_ptr == nullptr) {
213  errx(1, "bmi088 gyro driver not running");
214  }
215 
216  printf("state @ %p\n", *g_dev_gyr_ptr);
217  (*g_dev_gyr_ptr)->print_info();
218  }
219 
220  exit(0);
221 }
222 
223 /**
224  * Dump the register information
225  */
226 void
227 regdump(bool external_bus, enum sensor_type sensor)
228 {
229  BMI088_accel **g_dev_acc_ptr = external_bus ? &g_acc_dev_ext : &g_acc_dev_int;
230  BMI088_gyro **g_dev_gyr_ptr = external_bus ? &g_gyr_dev_ext : &g_gyr_dev_int;
231 
232  if (sensor == BMI088_ACCEL) {
233  if (*g_dev_acc_ptr == nullptr) {
234  errx(1, "bmi088 accel driver not running");
235  }
236 
237  printf("regdump @ %p\n", *g_dev_acc_ptr);
238  (*g_dev_acc_ptr)->print_registers();
239  }
240 
241  if (sensor == BMI088_GYRO) {
242  if (*g_dev_gyr_ptr == nullptr) {
243  errx(1, "bmi088 gyro driver not running");
244  }
245 
246  printf("regdump @ %p\n", *g_dev_gyr_ptr);
247  (*g_dev_gyr_ptr)->print_registers();
248  }
249 
250  exit(0);
251 }
252 
253 /**
254  * deliberately produce an error to test recovery
255  */
256 void
257 testerror(bool external_bus, enum sensor_type sensor)
258 {
259  BMI088_accel **g_dev_acc_ptr = external_bus ? &g_acc_dev_ext : &g_acc_dev_int;
260  BMI088_gyro **g_dev_gyr_ptr = external_bus ? &g_gyr_dev_ext : &g_gyr_dev_int;
261 
262  if (sensor == BMI088_ACCEL) {
263  if (*g_dev_acc_ptr == nullptr) {
264  errx(1, "bmi088 accel driver not running");
265  }
266 
267  (*g_dev_acc_ptr)->test_error();
268  }
269 
270  if (sensor == BMI088_GYRO) {
271  if (*g_dev_gyr_ptr == nullptr) {
272  errx(1, "bmi088 gyro driver not running");
273  }
274 
275  (*g_dev_gyr_ptr)->test_error();
276  }
277 
278  exit(0);
279 }
280 
281 void
283 {
284  warnx("missing command: try 'start', 'info', 'stop', 'regdump', 'testerror'");
285  warnx("options:");
286  warnx(" -X (external bus)");
287  warnx(" -R rotation");
288  warnx(" -A (Enable Accelerometer)");
289  warnx(" -G (Enable Gyroscope)");
290 }
291 
292 }//namespace ends
293 
294 
295 BMI088::BMI088(const char *name, const char *devname, int bus, uint32_t device, enum spi_mode_e mode,
296  uint32_t frequency, enum Rotation rotation):
297  SPI(name, devname, bus, device, mode, frequency),
298  _whoami(0),
299  _register_wait(0),
300  _reset_wait(0),
301  _rotation(rotation),
302  _checked_next(0)
303 {
304 }
305 
306 uint8_t
307 BMI088::read_reg(unsigned reg)
308 {
309  uint8_t cmd[2] = { (uint8_t)(reg | DIR_READ), 0};
310 
311  transfer(cmd, cmd, sizeof(cmd));
312 
313  return cmd[1];
314 }
315 
316 uint16_t
317 BMI088::read_reg16(unsigned reg)
318 {
319  uint8_t cmd[3] = { (uint8_t)(reg | DIR_READ), 0, 0 };
320 
321  transfer(cmd, cmd, sizeof(cmd));
322 
323  return (uint16_t)(cmd[1] << 8) | cmd[2];
324 }
325 
326 void
327 BMI088::write_reg(unsigned reg, uint8_t value)
328 {
329  uint8_t cmd[2];
330 
331  cmd[0] = reg | DIR_WRITE;
332  cmd[1] = value;
333 
334  transfer(cmd, nullptr, sizeof(cmd));
335 }
336 
337 int
338 bmi088_main(int argc, char *argv[])
339 {
340  bool external_bus = false;
341  int ch;
342  enum Rotation rotation = ROTATION_NONE;
343  enum sensor_type sensor = BMI088_NONE;
344  int myoptind = 1;
345  const char *myoptarg = NULL;
346 
347  /* jump over start/off/etc and look at options first */
348  while ((ch = px4_getopt(argc, argv, "XR:AG", &myoptind, &myoptarg)) != EOF) {
349  switch (ch) {
350  case 'X':
351  external_bus = true;
352  break;
353 
354  case 'R':
355  rotation = (enum Rotation)atoi(myoptarg);
356  break;
357 
358  case 'A':
359  sensor = BMI088_ACCEL;
360  break;
361 
362  case 'G':
363  sensor = BMI088_GYRO;
364  break;
365 
366  default:
367  bmi088::usage();
368  exit(0);
369  }
370  }
371 
372  const char *verb = argv[myoptind];
373 
374  if (sensor == BMI088_NONE) {
375  bmi088::usage();
376  exit(0);
377  }
378 
379  /*
380  * Start/load the driver.
381  */
382  if (!strcmp(verb, "start")) {
383  bmi088::start(external_bus, rotation, sensor);
384  }
385 
386  /*
387  * Stop the driver.
388  */
389  if (!strcmp(verb, "stop")) {
390  bmi088::stop(external_bus, sensor);
391  }
392 
393  /*
394  * Print driver information.
395  */
396  if (!strcmp(verb, "info")) {
397  bmi088::info(external_bus, sensor);
398  }
399 
400  /*
401  * Print register information.
402  */
403  if (!strcmp(verb, "regdump")) {
404  bmi088::regdump(external_bus, sensor);
405  }
406 
407  if (!strcmp(verb, "testerror")) {
408  bmi088::testerror(external_bus, sensor);
409  }
410 
411  bmi088::usage();
412  exit(1);
413 }
spi_mode_e
Definition: SPI.hpp:46
void testerror(bool, enum sensor_type)
deliberately produce an error to test recovery
BMI088(const BMI088 &)
virtual uint8_t read_reg(unsigned reg)
Read a register from the BMI088.
Definition: I2C.hpp:51
#define BMI088_DEVICE_PATH_GYRO_EXT
Definition: BMI088_gyro.hpp:41
BMI088_accel * g_acc_dev_int
Definition: bmi088_main.cpp:49
void stop(bool, enum sensor_type)
Namespace encapsulating all device framework classes, functions and data.
Definition: CDev.cpp:47
void start(bool, enum Rotation, enum sensor_type)
Start the driver.
Definition: bmi088_main.cpp:68
BMI088_gyro * g_gyr_dev_ext
Definition: bmi088_main.cpp:52
void usage()
Prints info about the driver argument usage.
BMI088_accel * g_acc_dev_ext
Definition: bmi088_main.cpp:50
#define DIR_READ
Definition: bmp388_spi.cpp:46
sensor_type
Definition: bmi055_main.cpp:40
virtual uint16_t read_reg16(unsigned reg)
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
void info(bool, enum sensor_type)
Print a little info about the driver.
void regdump(bool, enum sensor_type)
Dump the register information.
#define warnx(...)
Definition: err.h:95
#define BMI088_DEVICE_PATH_ACCEL
#define DIR_WRITE
Definition: bmp388_spi.cpp:47
const char * name
Definition: tests_main.c:58
BMI088_gyro * g_gyr_dev_int
Definition: bmi088_main.cpp:51
#define errx(eval,...)
Definition: err.h:89
#define OK
Definition: uavcan_main.cpp:71
#define BMI088_DEVICE_PATH_GYRO
Definition: BMI088_gyro.hpp:40
mode
Definition: vtol_type.h:76
#define BMI088_DEVICE_PATH_ACCEL_EXT
__EXPORT int bmi088_main(int argc, char *argv[])
driver &#39;main&#39; command
void write_reg(unsigned reg, uint8_t value)
Write a register in the BMI088.