PX4 Firmware
PX4 Autopilot Software http://px4.io
frsky_telemetry.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013-2014 PX4 Development Team. All rights reserved.
4  * Author: Stefan Rado <px4@sradonia.net>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * 3. Neither the name PX4 nor the names of its contributors may be
17  * used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  ****************************************************************************/
34 
35 /**
36  * @file frsky_telemetry.c
37  * @author Stefan Rado <px4@sradonia.net>
38  * @author Mark Whitehorn <kd0aij@github.com>
39  * @author Gianni Carbone <gianni.carbone@gmail.com>
40  *
41  * FrSky D8 mode and SmartPort (D16 mode) telemetry implementation.
42  * Compatibility with hardware flow control serial port.
43  *
44  * This daemon emulates the FrSky Sensor Hub for D8 mode.
45  * For X series receivers (D16 mode) it emulates SmartPort sensors by responding to polling
46  * packets received from an attached FrSky X series receiver.
47  *
48  */
49 
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <stdbool.h>
53 #include <string.h>
54 #include <sys/ioctl.h>
55 #include <sys/types.h>
56 #include <poll.h>
57 #include <fcntl.h>
58 #include <unistd.h>
59 
60 #include <px4_platform_common/tasks.h>
61 #include <px4_platform_common/module.h>
62 #include <px4_platform_common/getopt.h>
63 #include <systemlib/err.h>
64 #include <termios.h>
65 #include <drivers/drv_hrt.h>
67 #include <math.h> // NAN
68 
69 #include "sPort_data.h"
70 #include "frsky_data.h"
71 #include "common.h"
72 
73 using namespace time_literals;
74 
75 /* thread state */
76 static volatile bool thread_should_exit = false;
77 static volatile bool thread_running = false;
78 static int frsky_task;
81 
82 static unsigned long int sentPackets = 0;
83 /* Default values for arguments */
84 const char *device_name = NULL;
85 
86 /* functions */
87 static int sPort_open_uart(const char *uart_name, struct termios *uart_config, struct termios *uart_config_original);
88 static int set_uart_speed(int uart, struct termios *uart_config, speed_t speed);
89 static void usage(void);
90 static int frsky_telemetry_thread_main(int argc, char *argv[]);
91 
92 extern "C" __EXPORT int frsky_telemetry_main(int argc, char *argv[]);
93 
94 uint16_t get_telemetry_flight_mode(int px4_flight_mode)
95 {
96  // map the flight modes (see https://github.com/ilihack/LuaPilot_Taranis_Telemetry/blob/master/SCRIPTS/TELEMETRY/LuaPil.lua#L790)
97  switch (px4_flight_mode) {
98  case 0: return 18; // manual
99 
100  case 1: return 23; // alt control
101 
102  case 2: return 22; // pos control
103 
104  case 3: return 27; // mission
105 
106  case 4: return 26; // loiter
107 
108  case 5:
109  case 6:
110  case 7: return 28; // rtl
111 
112  case 10: return 19; // acro
113 
114  case 14: return 24; // offboard
115 
116  case 15: return 20; // stabilized
117 
118  case 16: return 21; // rattitude
119 
120  case 17: return 25; // takeoff
121 
122  case 8:
123  case 9:
124  case 18: return 29; // land
125 
126  case 19: return 30; // follow target
127  }
128 
129  return -1;
130 }
131 
132 /**
133  * Opens the UART device and sets all required serial parameters.
134  */
135 static int sPort_open_uart(const char *uart_name, struct termios *uart_config, struct termios *uart_config_original)
136 {
137  /* Open UART */
138  const int uart = open(uart_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
139 
140  if (uart < 0) {
141  PX4_ERR("Error opening port: %s (%i)", uart_name, errno);
142  return -1;
143  }
144 
145  /* Back up the original UART configuration to restore it after exit */
146  int termios_state;
147 
148  if ((termios_state = tcgetattr(uart, uart_config_original)) < 0) {
149  PX4_ERR("tcgetattr %s: %d\n", uart_name, termios_state);
150  close(uart);
151  return -1;
152  }
153 
154  /* Fill the struct for the new configuration */
155  tcgetattr(uart, uart_config);
156 
157  /* Disable output post-processing */
158  uart_config->c_oflag &= ~OPOST;
159 
160  uart_config->c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
161  uart_config->c_cflag &= ~CSIZE;
162  uart_config->c_cflag |= CS8; /* 8-bit characters */
163  uart_config->c_cflag &= ~PARENB; /* no parity bit */
164  uart_config->c_cflag &= ~CSTOPB; /* only need 1 stop bit */
165  uart_config->c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
166 
167  /* setup for non-canonical mode */
168  uart_config->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
169  uart_config->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
170 
171  /* Set baud rate */
172  const speed_t speed = B9600;
173 
174  if (cfsetispeed(uart_config, speed) < 0 || cfsetospeed(uart_config, speed) < 0) {
175  PX4_ERR("%s: %d (cfsetispeed, cfsetospeed)\n", uart_name, termios_state);
176  close(uart);
177  return -1;
178  }
179 
180  if ((termios_state = tcsetattr(uart, TCSANOW, uart_config)) < 0) {
181  PX4_ERR("%s (tcsetattr)\n", uart_name);
182  close(uart);
183  return -1;
184  }
185 
186  return uart;
187 }
188 
189 static int set_uart_speed(int uart, struct termios *uart_config, speed_t speed)
190 {
191 
192  if (cfsetispeed(uart_config, speed) < 0) {
193  return -1;
194  }
195 
196  if (tcsetattr(uart, TCSANOW, uart_config) < 0) {
197  return -1;
198  }
199 
200  return uart;
201 }
202 
203 static void set_uart_single_wire(int uart, bool single_wire)
204 {
205  if (ioctl(uart, TIOCSSINGLEWIRE, single_wire ? SER_SINGLEWIRE_ENABLED : 0) < 0) {
206  PX4_WARN("setting TIOCSSINGLEWIRE failed");
207  }
208 }
209 
210 /**
211  * The daemon thread.
212  */
213 static int frsky_telemetry_thread_main(int argc, char *argv[])
214 {
215  device_name = "/dev/ttyS6"; /* default USART8 */
216  unsigned scanning_timeout_ms = 0;
218  frsky_state_t baudRate = DTYPE;
219 
220  int myoptind = 1;
221  int ch;
222  const char *myoptarg = nullptr;
223 
224  while ((ch = px4_getopt(argc, argv, "d:t:m:", &myoptind, &myoptarg)) != EOF) {
225  switch (ch) {
226  case 'd':
227  device_name = myoptarg;
228  break;
229 
230  case 't':
231  scanning_timeout_ms = strtoul(myoptarg, nullptr, 10) * 1000;
232  break;
233 
234  case 'm':
235  if (!strcmp(myoptarg, "sport")) {
236  frsky_state = baudRate = SPORT;
237 
238  } else if (!strcmp(myoptarg, "sport_single")) {
239  frsky_state = baudRate = SPORT_SINGLE_WIRE;
240 
241  } else if (!strcmp(myoptarg, "dtype")) {
242  frsky_state = baudRate = DTYPE;
243 
244  } else if (!strcmp(myoptarg, "auto")) {
245  } else {
246  usage();
247  return -1;
248  }
249 
250  break;
251 
252  default:
253  usage();
254  return -1;
255  break;
256  }
257  }
258 
259  /* Open UART */
260  struct termios uart_config_original;
261  struct termios uart_config;
262  const int uart = sPort_open_uart(device_name, &uart_config, &uart_config_original);
263 
264  if (uart < 0) {
265  device_name = NULL;
266  return -1;
267  }
268 
269  /* poll descriptor */
270  struct pollfd fds[1];
271  fds[0].fd = uart;
272  fds[0].events = POLLIN;
273 
274  thread_running = true;
275 
276  /* Main thread loop */
277  char sbuf[20];
278 
279  const hrt_abstime start_time = hrt_absolute_time();
280 
281  while (!thread_should_exit && frsky_state == SCANNING) {
282  /* 2 byte polling frames indicate SmartPort telemetry
283  * 11 byte packets indicate D type telemetry
284  */
285  int status = poll(fds, sizeof(fds) / sizeof(fds[0]), 1000);
286 
287  if (status > 0) {
288  /* traffic on the port, D type is 11 bytes per frame, SmartPort is only 2
289  * Wait long enough for 11 bytes at 9600 baud
290  */
291  usleep(50_ms);
292  int nbytes = read(uart, &sbuf[0], sizeof(sbuf));
293  PX4_DEBUG("frsky input: %d bytes: %x %x, speed: %d", nbytes, sbuf[0], sbuf[1], baudRate);
294 
295  // look for valid header byte
296  if (baudRate == DTYPE) {
297  if (nbytes > 10) {
298  // see if we got a valid D-type hostframe
299  struct adc_linkquality host_frame;
300 
301  if (frsky_parse_host((uint8_t *)&sbuf[0], nbytes, &host_frame)) {
302  frsky_state = baudRate;
303  break;
304  }
305  }
306 
307  } else {
308  if (nbytes > 1) {
309  // check for alternating S.port start bytes
310  int index = 0;
311 
312  while (index < 2 && sbuf[index] != 0x7E) { index++; }
313 
314  if (index < 2) {
315 
316  int success = 1;
317 
318  for (int i = index + 2; i < nbytes; i += 2) {
319  if (sbuf[i] != 0x7E) { success = 0; break; }
320  }
321 
322  if (success) {
323  frsky_state = baudRate;
324  break;
325  }
326  }
327  }
328 
329  }
330  }
331 
332  // alternate between S.port and D-type baud rates
333  if (baudRate == SPORT) {
334  PX4_DEBUG("setting baud rate to %d (single wire)", 57600);
335  set_uart_speed(uart, &uart_config, B57600);
336  // switch to single-wire (half-duplex) mode, because S.Port uses only a single wire
337  set_uart_single_wire(uart, true);
338  baudRate = SPORT_SINGLE_WIRE;
339 
340  } else if (baudRate == SPORT_SINGLE_WIRE) {
341  PX4_DEBUG("setting baud rate to %d", 9600);
342  set_uart_speed(uart, &uart_config, B9600);
343  set_uart_single_wire(uart, false);
344  baudRate = DTYPE;
345 
346  } else {
347  PX4_DEBUG("setting baud rate to %d", 57600);
348  set_uart_speed(uart, &uart_config, B57600);
349  // in case S.Port is connected via external inverter (e.g. via Sipex 3232EE), we need to use duplex mode
350  set_uart_single_wire(uart, false);
351  baudRate = SPORT;
352  }
353 
354  usleep(100_ms);
355  // flush buffer
356  read(uart, &sbuf[0], sizeof(sbuf));
357 
358  // check for a timeout
359  if (scanning_timeout_ms > 0 && (hrt_absolute_time() - start_time) / 1000 > scanning_timeout_ms) {
360  PX4_INFO("Scanning timeout: exiting");
361  break;
362  }
363  }
364 
366  set_uart_speed(uart, &uart_config, B57600);
368 
369  /* Subscribe to topics */
370  if (!sPort_init()) {
371  PX4_ERR("could not allocate memory");
372  return -1;
373  }
374 
375  PX4_INFO("sending FrSky SmartPort telemetry");
376 
377  float filtered_alt = NAN;
378  float last_baro_alt = 0.f;
379  int airdata_sub = orb_subscribe(ORB_ID(vehicle_air_data));
380 
381  uint32_t lastBATV_ms = 0;
382  uint32_t lastCUR_ms = 0;
383  uint32_t lastALT_ms = 0;
384  uint32_t lastSPD_ms = 0;
385  uint32_t lastFUEL_ms = 0;
386  uint32_t lastVSPD_ms = 0;
387  uint32_t lastGPS_ms = 0;
388  uint32_t lastNAV_STATE_ms = 0;
389  uint32_t lastGPS_FIX_ms = 0;
390 
391  /* send S.port telemetry */
392  while (!thread_should_exit) {
393 
394  /* wait for poll frame starting with value 0x7E
395  * note that only the bus master is supposed to put a 0x7E on the bus.
396  * slaves use byte stuffing to send 0x7E and 0x7D.
397  * we expect a poll frame every 12msec
398  */
399  int status = poll(fds, sizeof(fds) / sizeof(fds[0]), 50);
400 
401  if (status < 1) { continue; }
402 
403  // read 1 byte
404  int newBytes = read(uart, &sbuf[0], 1);
405 
406  if (newBytes < 1 || sbuf[0] != 0x7E) { continue; }
407 
408  /* wait for ID byte */
409  status = poll(fds, sizeof(fds) / sizeof(fds[0]), 50);
410 
411  if (status < 1) { continue; }
412 
413  uint32_t now_ms = hrt_absolute_time() / 1000;
414 
415  newBytes = read(uart, &sbuf[1], 1);
416 
417  /* get a local copy of the current sensor values
418  * in order to apply a lowpass filter to baro pressure.
419  */
420  bool sensor_updated = false;
421  orb_check(airdata_sub, &sensor_updated);
422 
423  if (sensor_updated) {
424  struct vehicle_air_data_s airdata;
425  orb_copy(ORB_ID(vehicle_air_data), airdata_sub, &airdata);
426 
427  if (isnan(filtered_alt)) {
428  filtered_alt = airdata.baro_alt_meter;
429 
430  } else {
431  filtered_alt = .05f * airdata.baro_alt_meter + .95f * filtered_alt;
432  }
433  }
434 
435  // allow a minimum of 500usec before reply
436  usleep(500);
437 
439 
440  switch (sbuf[1]) {
441 
442  case SMARTPORT_POLL_1:
443 
444  /* report BATV at 1Hz */
445  if (now_ms - lastBATV_ms > 1000) {
446  lastBATV_ms = now_ms;
447  /* send battery voltage */
448  sPort_send_BATV(uart);
449  sentPackets++;
450  }
451 
452  break;
453 
454 
455  case SMARTPORT_POLL_2:
456 
457  /* report battery current at 5Hz */
458  if (now_ms - lastCUR_ms > 200) {
459  lastCUR_ms = now_ms;
460  /* send battery current */
461  sPort_send_CUR(uart);
462  sentPackets++;
463  }
464 
465  break;
466 
467 
468  case SMARTPORT_POLL_3:
469 
470  /* report altitude at 5Hz */
471  if (now_ms - lastALT_ms > 200) {
472  lastALT_ms = now_ms;
473  /* send altitude */
474  sPort_send_ALT(uart);
475  sentPackets++;
476  }
477 
478  break;
479 
480 
481  case SMARTPORT_POLL_4:
482 
483  /* report speed at 5Hz */
484  if (now_ms - lastSPD_ms > 200) {
485  lastSPD_ms = now_ms;
486  /* send speed */
487  sPort_send_SPD(uart);
488  sentPackets++;
489  }
490 
491  break;
492 
493  case SMARTPORT_POLL_5:
494 
495  /* report fuel at 1Hz */
496  if (now_ms - lastFUEL_ms > 1000) {
497  lastFUEL_ms = now_ms;
498  /* send fuel */
499  sPort_send_FUEL(uart);
500  sentPackets++;
501  }
502 
503  break;
504 
505  case SMARTPORT_POLL_6:
506 
507  /* report vertical speed at 10Hz */
508  if (now_ms - lastVSPD_ms > 100) {
509  /* estimate vertical speed using first difference and delta t */
510  uint32_t dt = now_ms - lastVSPD_ms;
511  float speed = (filtered_alt - last_baro_alt) / (1e-3f * (float)dt);
512 
513  /* save current alt and timestamp */
514  last_baro_alt = filtered_alt;
515  lastVSPD_ms = now_ms;
516 
517  sPort_send_VSPD(uart, speed);
518  sentPackets++;
519  }
520 
521  break;
522 
523  case SMARTPORT_POLL_7:
524 
525  /* report GPS data elements at 5*5Hz */
526  if (now_ms - lastGPS_ms > 100) {
527  static int elementCount = 0;
528 
529  switch (elementCount) {
530 
531  case 0:
532  sPort_send_GPS_LON(uart);
533  elementCount++;
534  break;
535 
536  case 1:
537  sPort_send_GPS_LAT(uart);
538  elementCount++;
539  break;
540 
541  case 2:
542  sPort_send_GPS_CRS(uart);
543  elementCount++;
544  break;
545 
546  case 3:
547  sPort_send_GPS_ALT(uart);
548  elementCount++;
549  break;
550 
551  case 4:
552  sPort_send_GPS_SPD(uart);
553  elementCount++;
554  break;
555 
556  case 5:
557  sPort_send_GPS_TIME(uart);
558  elementCount = 0;
559  sentPackets += elementCount;
560  break;
561  }
562 
563  }
564 
565  /* FALLTHROUGH */
566 
567  case SMARTPORT_POLL_8:
568 
569  /* report nav_state as DIY_NAVSTATE 2Hz */
570  if (now_ms - lastNAV_STATE_ms > 500) {
571  lastNAV_STATE_ms = now_ms;
572  /* send T1 */
573  sPort_send_NAV_STATE(uart);
574  sentPackets++;
575  }
576 
577  /* report satcount and fix as DIY_GPSFIX at 2Hz */
578  else if (now_ms - lastGPS_FIX_ms > 500) {
579  lastGPS_FIX_ms = now_ms;
580  /* send T2 */
581  sPort_send_GPS_FIX(uart);
582  sentPackets++;
583  }
584 
585  break;
586 
588  static int elementCount = 0;
589 
590  switch (elementCount++ % 2) {
591  case 0:
593  sentPackets++;
594  break;
595 
596  default:
597  sPort_send_GPS_info(uart);
598  sentPackets++;
599  break;
600  }
601  }
602 
603  break;
604  }
605  }
606 
607  PX4_DEBUG("freeing sPort memory");
608  sPort_deinit();
609 
610  /* either no traffic on the port (0=>timeout), or D type packet */
611 
612  } else if (frsky_state == DTYPE) {
613  /* detected D type telemetry: reconfigure UART */
614  PX4_INFO("sending FrSky D type telemetry");
615  int status = set_uart_speed(uart, &uart_config, B9600);
616  set_uart_single_wire(uart, false);
617 
618  if (status < 0) {
619  PX4_DEBUG("error setting speed for %s, quitting", device_name);
620  /* Reset the UART flags to original state */
621  tcsetattr(uart, TCSANOW, &uart_config_original);
622  close(uart);
623 
624  thread_running = false;
625  return 0;
626  }
627 
628  int iteration = 0;
629 
630  /* Subscribe to topics */
631  if (!frsky_init()) {
632  PX4_ERR("could not allocate memory");
633  return -1;
634  }
635 
636  struct adc_linkquality host_frame;
637 
638  /* send D8 mode telemetry */
639  while (!thread_should_exit) {
640 
641  /* Sleep 100 ms */
642  usleep(100000);
643 
644  /* parse incoming data */
645  int nbytes = read(uart, &sbuf[0], sizeof(sbuf));
646  bool new_input = frsky_parse_host((uint8_t *)&sbuf[0], nbytes, &host_frame);
647 
648  /* the RSSI value could be useful */
649  if (new_input) {
650  PX4_DEBUG("host frame: ad1:%u, ad2: %u, rssi: %u",
651  host_frame.ad1, host_frame.ad2, host_frame.linkq);
652  }
653 
655 
656  /* Send frame 1 (every 200ms): acceleration values, altitude (vario), temperatures, current & voltages, RPM */
657  if (iteration % 2 == 0) {
658  frsky_send_frame1(uart);
659  sentPackets++;
660  }
661 
662  /* Send frame 2 (every 1000ms): course, latitude, longitude, speed, altitude (GPS), fuel level */
663  if (iteration % 10 == 0) {
664  frsky_send_frame2(uart);
665  sentPackets++;
666  }
667 
668  /* Send frame 3 (every 5000ms): date, time */
669  if (iteration % 50 == 0) {
670  frsky_send_frame3(uart);
671  sentPackets++;
672  iteration = 0;
673  }
674 
675  iteration++;
676  }
677 
678 // /* TODO: flush the input buffer if in full duplex mode */
679 // read(uart, &sbuf[0], sizeof(sbuf));
680  PX4_DEBUG("freeing frsky memory");
681  frsky_deinit();
682 
683  }
684 
685  /* Reset the UART flags to original state */
686  tcsetattr(uart, TCSANOW, &uart_config_original);
687 
688  close(uart);
689 
690  device_name = NULL;
691 
692  thread_running = false;
693 
694  return 0;
695 }
696 
697 /**
698  * The main command function.
699  * Processes command line arguments and starts the daemon.
700  */
701 int frsky_telemetry_main(int argc, char *argv[])
702 {
703 
704 
705  if (argc < 2) {
706  PX4_ERR("missing command");
707  usage();
708  return -1;
709  }
710 
711  if (!strcmp(argv[1], "start")) {
712 
713  if (thread_running) {
714  PX4_INFO("frsky_telemetry already running");
715  return 0;
716  }
717 
718  thread_should_exit = false;
719  frsky_task = px4_task_spawn_cmd("frsky_telemetry",
720  SCHED_DEFAULT,
721  SCHED_PRIORITY_DEFAULT + 4,
722  1380,
724  (char *const *)argv);
725 
726  while (!thread_running) {
727  usleep(200);
728  }
729 
730  return 0;
731  }
732 
733  if (!strcmp(argv[1], "stop")) {
734 
735  if (!thread_running) {
736  PX4_WARN("frsky_telemetry already stopped");
737  return 0;
738  }
739 
740  thread_should_exit = true;
741 
742  while (thread_running) {
743  usleep(1000000);
744  PX4_INFO(".");
745  }
746 
747  PX4_INFO("terminated.");
748  device_name = NULL;
749  return 0;
750  }
751 
752  if (!strcmp(argv[1], "status")) {
753  if (thread_running) {
754  switch (frsky_state) {
755 
756  case SCANNING:
757  PX4_INFO("running: SCANNING");
758  PX4_INFO("port: %s", device_name);
759  break;
760 
761  case SPORT:
762  PX4_INFO("running: SPORT");
763  PX4_INFO("port: %s", device_name);
764  PX4_INFO("packets sent: %ld", sentPackets);
765  break;
766 
767  case SPORT_SINGLE_WIRE:
768  PX4_INFO("running: SPORT (single wire)");
769  PX4_INFO("port: %s", device_name);
770  PX4_INFO("packets sent: %ld", sentPackets);
771  break;
772 
773  case DTYPE:
774  PX4_INFO("running: DTYPE");
775  PX4_INFO("port: %s", device_name);
776  PX4_INFO("packets sent: %ld", sentPackets);
777  break;
778  }
779 
780  return 0;
781 
782  } else {
783  PX4_INFO("not running");
784  return 0;
785  }
786  }
787 
788  PX4_ERR("unrecognized command");
789  usage();
790  return 0;
791 }
792 
793 /**
794  * Print command usage information
795  */
796 static void usage()
797 {
798  PRINT_MODULE_DESCRIPTION("FrSky Telemetry support. Auto-detects D or S.PORT protocol.");
799 
800  PRINT_MODULE_USAGE_NAME("frsky_telemetry", "communication");
801  PRINT_MODULE_USAGE_COMMAND("start");
802  PRINT_MODULE_USAGE_PARAM_STRING('d', "/dev/ttyS6", "<file:dev>", "Select Serial Device", true);
803  PRINT_MODULE_USAGE_PARAM_INT('t', 0, 0, 60, "Scanning timeout [s] (default: no timeout)", true);
804  PRINT_MODULE_USAGE_PARAM_STRING('m', "auto", "sport|sport_single|dtype", "Select protocol (default: auto-detect)",
805  true);
806  PRINT_MODULE_USAGE_COMMAND("stop");
807  PRINT_MODULE_USAGE_COMMAND("status");
808 }
bool frsky_parse_host(uint8_t *sbuf, int nbytes, struct adc_linkquality *v)
Definition: frsky_data.cpp:277
#define SMARTPORT_POLL_5
Definition: sPort_data.h:53
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
Definition: uORB.cpp:90
void sPort_deinit()
Definition: sPort_data.cpp:94
static struct vehicle_status_s status
Definition: Commander.cpp:138
static void usage(void)
Print command usage information.
void sPort_send_GPS_ALT(int uart)
Definition: sPort_data.cpp:256
#define SMARTPORT_POLL_6
Definition: sPort_data.h:54
static void set_uart_single_wire(int uart, bool single_wire)
void sPort_send_GPS_TIME(int uart)
Definition: sPort_data.cpp:275
void sPort_send_SPD(int uart)
Definition: sPort_data.cpp:205
frsky_state_t
static volatile bool thread_should_exit
Definition: I2C.hpp:51
void frsky_send_frame3(int uart)
Sends frame 3 (every 5000ms): GPS date & time.
Definition: frsky_data.cpp:261
void sPort_send_ALT(int uart)
Definition: sPort_data.cpp:197
#define SMARTPORT_POLL_4
Definition: sPort_data.h:52
void sPort_send_FUEL(int uart)
Definition: sPort_data.cpp:224
High-resolution timer with callouts and timekeeping.
static int frsky_telemetry_thread_main(int argc, char *argv[])
The daemon thread.
#define SMARTPORT_POLL_2
Definition: sPort_data.h:50
static frsky_state_t frsky_state
void frsky_update_topics()
Definition: frsky_data.cpp:147
static void read(bootloader_app_shared_t *pshared)
#define SMARTPORT_POLL_8
Definition: sPort_data.h:56
int orb_subscribe(const struct orb_metadata *meta)
Definition: uORB.cpp:75
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
static int frsky_task
bool frsky_init()
Initializes the uORB subscriptions.
Definition: frsky_data.cpp:81
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
void sPort_send_VSPD(int uart, float speed)
Definition: sPort_data.cpp:216
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
static unsigned long int sentPackets
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
void sPort_update_topics()
Definition: sPort_data.cpp:102
void sPort_send_NAV_STATE(int uart)
Definition: sPort_data.cpp:311
void sPort_send_GPS_info(int uart)
Definition: sPort_data.cpp:337
static volatile bool thread_running
const char * device_name
void frsky_send_frame1(int uart)
Sends frame 1 (every 200ms): acceleration values, barometer altitude, temperature, battery voltage & current.
Definition: frsky_data.cpp:161
void sPort_send_flight_mode(int uart)
Definition: sPort_data.cpp:330
#define SMARTPORT_POLL_3
Definition: sPort_data.h:51
float dt
Definition: px4io.c:73
int orb_check(int handle, bool *updated)
Definition: uORB.cpp:95
void sPort_send_GPS_CRS(int uart)
Definition: sPort_data.cpp:263
static int set_uart_speed(int uart, struct termios *uart_config, speed_t speed)
void sPort_send_GPS_LON(int uart)
Definition: sPort_data.cpp:231
void sPort_send_GPS_FIX(int uart)
Definition: sPort_data.cpp:321
static int sPort_open_uart(const char *uart_name, struct termios *uart_config, struct termios *uart_config_original)
Opens the UART device and sets all required serial parameters.
__EXPORT int frsky_telemetry_main(int argc, char *argv[])
The main command function.
#define SMARTPORT_POLL_7
Definition: sPort_data.h:55
void sPort_send_CUR(int uart)
Definition: sPort_data.cpp:187
void sPort_send_GPS_SPD(int uart)
Definition: sPort_data.cpp:298
void sPort_send_BATV(int uart)
Definition: sPort_data.cpp:179
void sPort_send_GPS_LAT(int uart)
Definition: sPort_data.cpp:245
void frsky_deinit()
Definition: frsky_data.cpp:92
void frsky_send_frame2(int uart)
Sends frame 2 (every 1000ms): GPS course, latitude, longitude, ground speed, GPS altitude, remaining battery level.
Definition: frsky_data.cpp:199
bool sPort_init()
Initializes the uORB subscriptions.
Definition: sPort_data.cpp:83
#define SMARTPORT_SENSOR_ID_SP2UR
Definition: sPort_data.h:57
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint8_t linkq
Definition: frsky_data.h:58
uint16_t get_telemetry_flight_mode(int px4_flight_mode)
Map the PX4 flight mode (vehicle_status_s::nav_state) to the telemetry flight mode.
#define SMARTPORT_POLL_1
Definition: sPort_data.h:49