PX4 Firmware
PX4 Autopilot Software http://px4.io
bst.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 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 bst.cpp
36  *
37  * Black Sheep Telemetry driver
38  *
39  * @author Anton Babushkin <anton.babushkin@me.com>
40  */
41 
42 #include <px4_platform_common/px4_config.h>
43 #include <px4_platform_common/getopt.h>
44 #include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
45 #include <drivers/device/i2c.h>
46 #include <systemlib/err.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <math.h>
50 #include <uORB/Subscription.hpp>
54 #include <matrix/math.hpp>
55 
56 using namespace matrix;
57 
58 static const char commandline_usage[] = "usage: bst start|status|stop";
59 
60 #define BST_ADDR 0x76
61 
62 namespace px4
63 {
64 namespace bst
65 {
66 
67 #pragma pack(push, 1)
68 
69 template <typename T>
70 struct BSTPacket {
71  uint8_t length;
72  uint8_t type;
74  uint8_t crc;
75 };
76 
78  uint8_t cmd;
79 };
80 
82  uint32_t hw_id;
83  uint16_t fw_id;
84  uint8_t dev_name_len;
85  char dev_name[32];
86 };
87 
89  int32_t lat;
90  int32_t lon;
91  uint16_t gs;
92  uint16_t heading;
93  uint16_t alt;
94  uint8_t sats;
95 };
96 
97 struct BSTAttitude {
98  int16_t pitch;
99  int16_t roll;
100  int16_t yaw;
101 };
102 
103 struct BSTBattery {
104  uint16_t voltage;
105  uint16_t current;
106  uint8_t capacity[3];
107 };
108 
109 #pragma pack(pop)
110 
111 class BST : public device::I2C, public px4::ScheduledWorkItem
112 {
113 public:
114  BST(int bus);
115 
116  virtual ~BST();
117 
118  virtual int init();
119 
120  virtual int probe();
121 
122  virtual int info() { return 0; }
123 
124  virtual int ioctl(device::file_t *filp, int cmd, unsigned long arg) { return 0; }
125 
126  void stop();
127 
128  static void start_trampoline(void *arg);
129 
130 private:
131 
132  bool _should_run = false;
133  unsigned _interval = 100;
134 
135  uORB::Subscription _gps_sub{ORB_ID(vehicle_gps_position)};
136  uORB::Subscription _attitude_sub{ORB_ID(vehicle_attitude)};
138 
139  void start();
140 
141  void Run() override;
142 
143  template <typename T>
144  void send_packet(BSTPacket<T> &packet)
145  {
146  packet.length = sizeof(packet) - 1; // Length
147  packet.crc = crc8(reinterpret_cast<uint8_t *>(&packet.type), sizeof(packet) - 2);
148 
149  transfer(reinterpret_cast<uint8_t *>(&packet), sizeof(packet), nullptr, 0);
150  }
151 
152  template <typename T_SEND, typename T_RECV>
153  void send_packet(BSTPacket<T_SEND> &packet_send, BSTPacket<T_RECV> &packet_recv)
154  {
155  packet_send.length = sizeof(packet_send) - 1; // Length
156  packet_send.crc = crc8(reinterpret_cast<uint8_t *>(&packet_send.type), sizeof(packet_send) - 2);
157  transfer(reinterpret_cast<uint8_t *>(&packet_send), sizeof(packet_send), reinterpret_cast<uint8_t *>(&packet_recv),
158  sizeof(packet_recv));
159  }
160 
161  static uint8_t crc8(uint8_t *data, size_t len);
162 
163  //! Byte swap unsigned short
164  uint16_t swap_uint16(uint16_t val)
165  {
166  return (val << 8) | (val >> 8);
167  }
168 
169  //! Byte swap short
170  int16_t swap_int16(int16_t val)
171  {
172  return (val << 8) | ((val >> 8) & 0xFF);
173  }
174 
175  //! Byte swap unsigned int
176  uint32_t swap_uint32(uint32_t val)
177  {
178  val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
179  return (val << 16) | (val >> 16);
180  }
181 
182  //! Byte swap int
183  int32_t swap_int32(int32_t val)
184  {
185  val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
186  return (val << 16) | ((val >> 16) & 0xFFFF);
187  }
188 };
189 
190 static BST *g_bst = nullptr;
191 
192 BST::BST(int bus) :
193  I2C("bst", nullptr, bus, BST_ADDR, 100000),
194  ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(get_device_id()))
195 {
196 }
197 
199 {
200  ScheduleClear();
201 
202  _should_run = false;
203 }
204 
206 {
207  int retries_prev = _retries;
208  _retries = 3;
209 
210  BSTPacket<BSTDeviceInfoRequest> dev_info_req = {};
211  dev_info_req.type = 0x0A;
212  dev_info_req.payload.cmd = 0x04;
213  BSTPacket<BSTDeviceInfoReply> dev_info_reply = {};
214  send_packet(dev_info_req, dev_info_reply);
215 
216  if (dev_info_reply.type != 0x05) {
217  warnx("no devices found");
218  return -EIO;
219  }
220 
221  uint8_t *reply_raw = reinterpret_cast<uint8_t *>(&dev_info_reply);
222  uint8_t crc_calc = crc8(reinterpret_cast<uint8_t *>(&dev_info_reply.type), dev_info_reply.length - 1);
223  uint8_t crc_recv = reply_raw[dev_info_reply.length];
224 
225  if (crc_recv != crc_calc) {
226  warnx("CRC error: got %02x, should be %02x", (int)crc_recv, (int)crc_calc);
227  return -EIO;
228  }
229 
230  dev_info_reply.payload.dev_name[dev_info_reply.payload.dev_name_len] = '\0';
231  warnx("device info: hardware ID: 0x%08X, firmware ID: 0x%04X, device name: %s",
232  (int)swap_uint32(dev_info_reply.payload.hw_id), (int)swap_uint16(dev_info_reply.payload.fw_id),
233  dev_info_reply.payload.dev_name);
234 
235  _retries = retries_prev;
236 
237  return OK;
238 }
239 
241 {
242  int ret = I2C::init();
243 
244  if (ret != OK) {
245  return ret;
246  }
247 
248  ScheduleNow();
249 
250  return OK;
251 }
252 
253 void BST::Run()
254 {
255  if (!_should_run) {
256  _should_run = true;
257  set_device_address(0x00); // General call address
258  }
259 
260  if (_should_run) {
261  if (_attitude_sub.updated()) {
262  vehicle_attitude_s att;
263  _attitude_sub.copy(&att);
264  Quatf q(att.q);
265  Eulerf euler(q);
266 
267  BSTPacket<BSTAttitude> bst_att = {};
268  bst_att.type = 0x1E;
269  bst_att.payload.roll = swap_int32(euler.phi() * 10000);
270  bst_att.payload.pitch = swap_int32(euler.theta() * 10000);
271  bst_att.payload.yaw = swap_int32(euler.psi() * 10000);
272 
273  send_packet(bst_att);
274  }
275 
276  if (_battery_sub.updated()) {
277  battery_status_s batt;
278  _battery_sub.copy(&batt);
279 
280  BSTPacket<BSTBattery> bst_batt = {};
281  bst_batt.type = 0x08;
282  bst_batt.payload.voltage = swap_uint16(batt.voltage_v * 10.0f);
283  bst_batt.payload.current = swap_uint16(batt.current_a * 10.0f);
284  uint32_t discharged = batt.discharged_mah;
285  bst_batt.payload.capacity[0] = static_cast<uint8_t>(discharged >> 16);
286  bst_batt.payload.capacity[1] = static_cast<uint8_t>(discharged >> 8);
287  bst_batt.payload.capacity[2] = static_cast<uint8_t>(discharged);
288 
289  send_packet(bst_batt);
290  }
291 
292  if (_gps_sub.updated()) {
294  _gps_sub.copy(&gps);
295 
296  if (gps.fix_type >= 3 && gps.eph < 50.0f) {
297  BSTPacket<BSTGPSPosition> bst_gps = {};
298  bst_gps.type = 0x02;
299  bst_gps.payload.lat = swap_int32(gps.lat);
300  bst_gps.payload.lon = swap_int32(gps.lon);
301  bst_gps.payload.alt = swap_int16(gps.alt / 1000 + 1000);
302  bst_gps.payload.gs = swap_int16(gps.vel_m_s * 360.0f);
303  bst_gps.payload.heading = swap_int16(gps.cog_rad * 18000.0f / M_PI_F);
304  bst_gps.payload.sats = gps.satellites_used;
305 
306  send_packet(bst_gps);
307  }
308  }
309 
310  ScheduleDelayed(_interval);
311  }
312 }
313 
314 uint8_t BST::crc8(uint8_t *data, size_t len)
315 {
316  uint8_t crc = 0x00;
317 
318  while (len--) {
319  crc ^= *data++;
320 
321  for (int i = 0; i < 8; i++) {
322  crc = crc & 0x80 ? (crc << 1) ^ 0xD5 : crc << 1;
323  }
324  }
325 
326  return crc;
327 }
328 
329 }
330 }
331 
332 using namespace px4::bst;
333 
334 extern "C" __EXPORT int bst_main(int argc, char *argv[])
335 {
336  if (argc < 2) {
337  errx(1, "missing command\n%s", commandline_usage);
338  }
339 
340  if (!strcmp(argv[1], "start")) {
341 
342  if (g_bst) {
343  warnx("already running");
344  exit(0);
345  }
346 
347  g_bst = new BST(PX4_I2C_BUS_EXPANSION);
348 
349  if (g_bst != nullptr && OK != g_bst->init()) {
350  delete g_bst;
351  g_bst = nullptr;
352  }
353 
354  exit(0);
355  }
356 
357  if (!strcmp(argv[1], "stop")) {
358  if (!g_bst) {
359  warnx("not running");
360  exit(0);
361  }
362 
363  delete g_bst;
364  g_bst = nullptr;
365  warnx("stopped");
366 
367  exit(0);
368  }
369 
370  if (!strcmp(argv[1], "status")) {
371  if (g_bst) {
372  warnx("is running");
373 
374  } else {
375  warnx("is not running");
376  }
377 
378  exit(0);
379  }
380 
381  PX4_WARN("unrecognized command\n%s", commandline_usage);
382  return 1;
383 }
__EXPORT int bst_main(int argc, char *argv[])
Definition: bst.cpp:334
Type theta() const
Definition: Euler.hpp:132
unsigned _interval
Definition: bst.cpp:133
uORB::Subscription _battery_sub
Definition: bst.cpp:137
uint8_t type
Definition: bst.cpp:72
static int _battery_sub
Definition: messages.cpp:60
virtual int init()
Definition: bst.cpp:240
uORB::Subscription _attitude_sub
Definition: bst.cpp:136
virtual ~BST()
Definition: bst.cpp:198
Definition: I2C.hpp:51
static void stop()
Definition: dataman.cpp:1491
static BST * g_bst
Definition: bst.cpp:190
virtual int ioctl(device::file_t *filp, int cmd, unsigned long arg)
Definition: bst.cpp:124
bool _should_run
Definition: bst.cpp:132
Type phi() const
Definition: Euler.hpp:128
Quaternion class.
Definition: Dcm.hpp:24
int32_t swap_int32(int32_t val)
Byte swap int.
Definition: bst.cpp:183
Type psi() const
Definition: Euler.hpp:136
uint8_t capacity[3]
Definition: bst.cpp:106
uint8_t crc
Definition: bst.cpp:74
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
static const char commandline_usage[]
Definition: bst.cpp:58
uint16_t voltage
Definition: bst.cpp:104
void init()
Activates/configures the hardware registers.
uORB::Subscription _gps_sub
Definition: bst.cpp:135
uint32_t swap_uint32(uint32_t val)
Byte swap unsigned int.
Definition: bst.cpp:176
int16_t swap_int16(int16_t val)
Byte swap short.
Definition: bst.cpp:170
uint8_t * data
Definition: dataman.cpp:149
static uint8_t crc8(uint8_t *p, uint8_t len)
Definition: teraranger.cpp:180
#define warnx(...)
Definition: err.h:95
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
#define BST_ADDR
Definition: bst.cpp:60
Euler angles class.
Definition: AxisAngle.hpp:18
bool updated()
Check if there is a new update.
static int start()
Definition: dataman.cpp:1452
BST(int bus)
Definition: bst.cpp:192
virtual int probe()
Definition: bst.cpp:205
#define errx(eval,...)
Definition: err.h:89
Definition: bst.cpp:62
static int _gps_sub
Definition: messages.cpp:61
void send_packet(BSTPacket< T > &packet)
Definition: bst.cpp:144
virtual int info()
Definition: bst.cpp:122
#define OK
Definition: uavcan_main.cpp:71
#define M_PI_F
Definition: ashtech.cpp:44
Definition: bst.cpp:64
void Run() override
Definition: bst.cpp:253
bool copy(void *dst)
Copy the struct.
uint8_t length
Definition: bst.cpp:71
uint16_t swap_uint16(uint16_t val)
Byte swap unsigned short.
Definition: bst.cpp:164
static uint8_t crc8(uint8_t *data, size_t len)
Definition: bst.cpp:314
uint16_t current
Definition: bst.cpp:105
void send_packet(BSTPacket< T_SEND > &packet_send, BSTPacket< T_RECV > &packet_recv)
Definition: bst.cpp:153
Base class for devices connected via I2C.