54 #include <sys/ioctl.h> 55 #include <sys/types.h> 60 #include <px4_platform_common/tasks.h> 61 #include <px4_platform_common/module.h> 62 #include <px4_platform_common/getopt.h> 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);
97 switch (px4_flight_mode) {
135 static int sPort_open_uart(
const char *uart_name,
struct termios *uart_config,
struct termios *uart_config_original)
138 const int uart = open(uart_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
141 PX4_ERR(
"Error opening port: %s (%i)", uart_name, errno);
148 if ((termios_state = tcgetattr(uart, uart_config_original)) < 0) {
149 PX4_ERR(
"tcgetattr %s: %d\n", uart_name, termios_state);
155 tcgetattr(uart, uart_config);
158 uart_config->c_oflag &= ~OPOST;
160 uart_config->c_cflag |= (CLOCAL | CREAD);
161 uart_config->c_cflag &= ~CSIZE;
162 uart_config->c_cflag |= CS8;
163 uart_config->c_cflag &= ~PARENB;
164 uart_config->c_cflag &= ~CSTOPB;
165 uart_config->c_cflag &= ~CRTSCTS;
168 uart_config->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
169 uart_config->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
172 const speed_t speed = B9600;
174 if (cfsetispeed(uart_config, speed) < 0 || cfsetospeed(uart_config, speed) < 0) {
175 PX4_ERR(
"%s: %d (cfsetispeed, cfsetospeed)\n", uart_name, termios_state);
180 if ((termios_state = tcsetattr(uart, TCSANOW, uart_config)) < 0) {
181 PX4_ERR(
"%s (tcsetattr)\n", uart_name);
192 if (cfsetispeed(uart_config, speed) < 0) {
196 if (tcsetattr(uart, TCSANOW, uart_config) < 0) {
205 if (ioctl(uart, TIOCSSINGLEWIRE, single_wire ? SER_SINGLEWIRE_ENABLED : 0) < 0) {
206 PX4_WARN(
"setting TIOCSSINGLEWIRE failed");
216 unsigned scanning_timeout_ms = 0;
222 const char *myoptarg =
nullptr;
224 while ((ch = px4_getopt(argc, argv,
"d:t:m:", &myoptind, &myoptarg)) != EOF) {
231 scanning_timeout_ms = strtoul(myoptarg,
nullptr, 10) * 1000;
235 if (!strcmp(myoptarg,
"sport")) {
238 }
else if (!strcmp(myoptarg,
"sport_single")) {
241 }
else if (!strcmp(myoptarg,
"dtype")) {
244 }
else if (!strcmp(myoptarg,
"auto")) {
260 struct termios uart_config_original;
261 struct termios uart_config;
270 struct pollfd fds[1];
272 fds[0].events = POLLIN;
285 int status = poll(fds,
sizeof(fds) /
sizeof(fds[0]), 1000);
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);
296 if (baudRate ==
DTYPE) {
312 while (index < 2 && sbuf[index] != 0x7E) { index++; }
318 for (
int i = index + 2; i < nbytes; i += 2) {
319 if (sbuf[i] != 0x7E) { success = 0;
break; }
333 if (baudRate ==
SPORT) {
334 PX4_DEBUG(
"setting baud rate to %d (single wire)", 57600);
341 PX4_DEBUG(
"setting baud rate to %d", 9600);
347 PX4_DEBUG(
"setting baud rate to %d", 57600);
356 read(uart, &sbuf[0],
sizeof(sbuf));
359 if (scanning_timeout_ms > 0 && (
hrt_absolute_time() - start_time) / 1000 > scanning_timeout_ms) {
360 PX4_INFO(
"Scanning timeout: exiting");
371 PX4_ERR(
"could not allocate memory");
375 PX4_INFO(
"sending FrSky SmartPort telemetry");
377 float filtered_alt = NAN;
378 float last_baro_alt = 0.f;
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;
399 int status = poll(fds,
sizeof(fds) /
sizeof(fds[0]), 50);
401 if (status < 1) {
continue; }
404 int newBytes =
read(uart, &sbuf[0], 1);
406 if (newBytes < 1 || sbuf[0] != 0x7E) {
continue; }
409 status = poll(fds,
sizeof(fds) /
sizeof(fds[0]), 50);
411 if (status < 1) {
continue; }
415 newBytes =
read(uart, &sbuf[1], 1);
420 bool sensor_updated =
false;
423 if (sensor_updated) {
427 if (isnan(filtered_alt)) {
431 filtered_alt = .05f * airdata.
baro_alt_meter + .95f * filtered_alt;
445 if (now_ms - lastBATV_ms > 1000) {
446 lastBATV_ms = now_ms;
458 if (now_ms - lastCUR_ms > 200) {
471 if (now_ms - lastALT_ms > 200) {
484 if (now_ms - lastSPD_ms > 200) {
496 if (now_ms - lastFUEL_ms > 1000) {
497 lastFUEL_ms = now_ms;
508 if (now_ms - lastVSPD_ms > 100) {
510 uint32_t
dt = now_ms - lastVSPD_ms;
511 float speed = (filtered_alt - last_baro_alt) / (1e-3
f * (
float)
dt);
514 last_baro_alt = filtered_alt;
515 lastVSPD_ms = now_ms;
526 if (now_ms - lastGPS_ms > 100) {
527 static int elementCount = 0;
529 switch (elementCount) {
570 if (now_ms - lastNAV_STATE_ms > 500) {
571 lastNAV_STATE_ms = now_ms;
578 else if (now_ms - lastGPS_FIX_ms > 500) {
579 lastGPS_FIX_ms = now_ms;
588 static int elementCount = 0;
590 switch (elementCount++ % 2) {
607 PX4_DEBUG(
"freeing sPort memory");
614 PX4_INFO(
"sending FrSky D type telemetry");
619 PX4_DEBUG(
"error setting speed for %s, quitting",
device_name);
621 tcsetattr(uart, TCSANOW, &uart_config_original);
632 PX4_ERR(
"could not allocate memory");
645 int nbytes =
read(uart, &sbuf[0],
sizeof(sbuf));
646 bool new_input =
frsky_parse_host((uint8_t *)&sbuf[0], nbytes, &host_frame);
650 PX4_DEBUG(
"host frame: ad1:%u, ad2: %u, rssi: %u",
657 if (iteration % 2 == 0) {
663 if (iteration % 10 == 0) {
669 if (iteration % 50 == 0) {
680 PX4_DEBUG(
"freeing frsky memory");
686 tcsetattr(uart, TCSANOW, &uart_config_original);
706 PX4_ERR(
"missing command");
711 if (!strcmp(argv[1],
"start")) {
714 PX4_INFO(
"frsky_telemetry already running");
719 frsky_task = px4_task_spawn_cmd(
"frsky_telemetry",
721 SCHED_PRIORITY_DEFAULT + 4,
724 (
char *
const *)argv);
733 if (!strcmp(argv[1],
"stop")) {
736 PX4_WARN(
"frsky_telemetry already stopped");
747 PX4_INFO(
"terminated.");
752 if (!strcmp(argv[1],
"status")) {
757 PX4_INFO(
"running: SCANNING");
762 PX4_INFO(
"running: SPORT");
768 PX4_INFO(
"running: SPORT (single wire)");
774 PX4_INFO(
"running: DTYPE");
783 PX4_INFO(
"not running");
788 PX4_ERR(
"unrecognized command");
798 PRINT_MODULE_DESCRIPTION(
"FrSky Telemetry support. Auto-detects D or S.PORT protocol.");
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)",
806 PRINT_MODULE_USAGE_COMMAND(
"stop");
807 PRINT_MODULE_USAGE_COMMAND(
"status");
bool frsky_parse_host(uint8_t *sbuf, int nbytes, struct adc_linkquality *v)
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
static struct vehicle_status_s status
static void usage(void)
Print command usage information.
void sPort_send_GPS_ALT(int uart)
static void set_uart_single_wire(int uart, bool single_wire)
void sPort_send_GPS_TIME(int uart)
void sPort_send_SPD(int uart)
static volatile bool thread_should_exit
void frsky_send_frame3(int uart)
Sends frame 3 (every 5000ms): GPS date & time.
void sPort_send_ALT(int uart)
void sPort_send_FUEL(int uart)
High-resolution timer with callouts and timekeeping.
static int frsky_telemetry_thread_main(int argc, char *argv[])
The daemon thread.
static frsky_state_t frsky_state
void frsky_update_topics()
static void read(bootloader_app_shared_t *pshared)
int orb_subscribe(const struct orb_metadata *meta)
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
bool frsky_init()
Initializes the uORB subscriptions.
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
void sPort_send_VSPD(int uart, float speed)
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.
void sPort_update_topics()
void sPort_send_NAV_STATE(int uart)
void sPort_send_GPS_info(int uart)
static volatile bool thread_running
void frsky_send_frame1(int uart)
Sends frame 1 (every 200ms): acceleration values, barometer altitude, temperature, battery voltage & current.
void sPort_send_flight_mode(int uart)
int orb_check(int handle, bool *updated)
void sPort_send_GPS_CRS(int uart)
static int set_uart_speed(int uart, struct termios *uart_config, speed_t speed)
void sPort_send_GPS_LON(int uart)
void sPort_send_GPS_FIX(int uart)
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.
void sPort_send_CUR(int uart)
void sPort_send_GPS_SPD(int uart)
void sPort_send_BATV(int uart)
void sPort_send_GPS_LAT(int uart)
void frsky_send_frame2(int uart)
Sends frame 2 (every 1000ms): GPS course, latitude, longitude, ground speed, GPS altitude, remaining battery level.
bool sPort_init()
Initializes the uORB subscriptions.
#define SMARTPORT_SENSOR_ID_SP2UR
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
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.