Skip to content
This repository was archived by the owner on Oct 1, 2021. It is now read-only.

Commit 4fb3e8c

Browse files
author
Owen McAree
committed
PX4IO: Added support for JR XBus Mode B
JR XBus Mode B uses the same serial port parameters as the DSM port (3.3V logic, 115200, 8n1), this update adds support for decoding it. XBus Mode B is effectively the SRXL protocol, using the Multiplex 12-channel format (start charachter 0xA1) Decoding of XBus packets only occurs if a valid checksum is received, so this should not interfere with DSM packets. - RC Failsafe is now disabled when XBus data is bein received
1 parent 548f37a commit 4fb3e8c

File tree

5 files changed

+194
-20
lines changed

5 files changed

+194
-20
lines changed

src/modules/px4iofirmware/controls.c

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,19 @@
5353
#define RC_CHANNEL_LOW_THRESH -8000 /* 10% threshold */
5454

5555
static bool ppm_input(uint16_t *values, uint16_t *num_values, uint16_t *frame_len);
56-
static bool dsm_port_input(uint16_t *rssi, bool *dsm_updated, bool *st24_updated);
56+
static bool dsm_port_input(uint16_t *rssi, bool *dsm_updated, bool *st24_updated, bool *xbus_updated);
57+
5758

5859
static perf_counter_t c_gather_dsm;
5960
static perf_counter_t c_gather_sbus;
6061
static perf_counter_t c_gather_ppm;
6162

63+
6264
static int _dsm_fd;
6365

6466
static uint16_t rc_value_override = 0;
6567

66-
bool dsm_port_input(uint16_t *rssi, bool *dsm_updated, bool *st24_updated)
68+
bool dsm_port_input(uint16_t *rssi, bool *dsm_updated, bool *st24_updated, bool *xbus_updated)
6769
{
6870
perf_begin(c_gather_dsm);
6971
uint16_t temp_count = r_raw_rc_count;
@@ -106,19 +108,30 @@ bool dsm_port_input(uint16_t *rssi, bool *dsm_updated, bool *st24_updated)
106108
r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FAILSAFE);
107109
}
108110

109-
return (*dsm_updated | *st24_updated);
111+
/* Attempt to parse serial data as XBus Mode B
112+
* Will only override DSM if valid XBus checksum found
113+
*/
114+
*xbus_updated = xbus_input(bytes, n_bytes, r_raw_rc_values, &r_raw_rc_count);
115+
if (*xbus_updated) {
116+
r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_XBUS;
117+
r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FRAME_DROP);
118+
r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FAILSAFE);
119+
}
120+
121+
return (*dsm_updated | *st24_updated | *xbus_updated);
110122
}
111123

112124
void
113125
controls_init(void)
114126
{
127+
115128
/* no channels */
116129
r_raw_rc_count = 0;
117130
system_state.rc_channels_timestamp_received = 0;
118131
system_state.rc_channels_timestamp_valid = 0;
119132

120-
/* DSM input (USART1) */
121-
_dsm_fd = dsm_init("/dev/ttyS0");
133+
/* DSM input (USART1) */
134+
_dsm_fd = dsm_init("/dev/ttyS0");
122135

123136
/* S.bus input (USART3) */
124137
sbus_init("/dev/ttyS2");
@@ -135,8 +148,8 @@ controls_init(void)
135148
r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_ASSIGNMENT] = i;
136149
r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_OPTIONS] = PX4IO_P_RC_CONFIG_OPTIONS_ENABLED;
137150
}
138-
139-
c_gather_dsm = perf_alloc(PC_ELAPSED, "c_gather_dsm");
151+
152+
c_gather_dsm = perf_alloc(PC_ELAPSED, "c_gather_dsm");
140153
c_gather_sbus = perf_alloc(PC_ELAPSED, "c_gather_sbus");
141154
c_gather_ppm = perf_alloc(PC_ELAPSED, "c_gather_ppm");
142155
}
@@ -168,16 +181,21 @@ controls_tick() {
168181
}
169182
#endif
170183

171-
perf_begin(c_gather_dsm);
172-
bool dsm_updated, st24_updated;
173-
(void)dsm_port_input(&rssi, &dsm_updated, &st24_updated);
174-
if (dsm_updated) {
175-
r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_DSM;
176-
}
177-
if (st24_updated) {
178-
r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_ST24;
179-
}
180-
perf_end(c_gather_dsm);
184+
bool dsm_updated, st24_updated, xbus_updated;
185+
186+
perf_begin(c_gather_dsm);
187+
188+
(void)dsm_port_input(&rssi, &dsm_updated, &st24_updated, &xbus_updated);
189+
if (dsm_updated) {
190+
r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_DSM;
191+
}
192+
if (st24_updated) {
193+
r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_ST24;
194+
}
195+
if (xbus_updated) {
196+
r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_XBUS;
197+
}
198+
perf_end(c_gather_dsm);
181199

182200
perf_begin(c_gather_sbus);
183201

@@ -238,7 +256,7 @@ controls_tick() {
238256
/*
239257
* If we received a new frame from any of the RC sources, process it.
240258
*/
241-
if (dsm_updated || sbus_updated || ppm_updated || st24_updated) {
259+
if (dsm_updated || xbus_updated || sbus_updated || ppm_updated || st24_updated) {
242260

243261
/* record a bitmask of channels assigned */
244262
unsigned assigned_channels = 0;
@@ -367,6 +385,7 @@ controls_tick() {
367385
r_status_flags &= ~(
368386
PX4IO_P_STATUS_FLAGS_RC_PPM |
369387
PX4IO_P_STATUS_FLAGS_RC_DSM |
388+
PX4IO_P_STATUS_FLAGS_RC_XBUS |
370389
PX4IO_P_STATUS_FLAGS_RC_SBUS);
371390

372391
}
@@ -438,7 +457,7 @@ controls_tick() {
438457
r_status_flags |= PX4IO_P_STATUS_FLAGS_OVERRIDE;
439458

440459
/* mix new RC input control values to servos */
441-
if (dsm_updated || sbus_updated || ppm_updated || st24_updated)
460+
if (dsm_updated || xbus_updated || sbus_updated || ppm_updated || st24_updated)
442461
mixer_tick();
443462

444463
} else {

src/modules/px4iofirmware/module.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
SRCS = adc.c \
33
controls.c \
44
dsm.c \
5+
xbus.c \
56
px4io.c \
67
registers.c \
78
safety.c \
@@ -26,4 +27,4 @@ endif
2627

2728
SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
2829
include $(SELF_DIR)../systemlib/mixer/multi_tables.mk
29-
30+

src/modules/px4iofirmware/protocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
#define PX4IO_P_STATUS_FLAGS_SAFETY_OFF (1 << 12) /* safety is off */
116116
#define PX4IO_P_STATUS_FLAGS_FMU_INITIALIZED (1 << 13) /* FMU was initialized and OK once */
117117
#define PX4IO_P_STATUS_FLAGS_RC_ST24 (1 << 14) /* ST24 input is valid */
118+
#define PX4IO_P_STATUS_FLAGS_RC_XBUS (1 << 15) /* XBus input is valid */
118119

119120
#define PX4IO_P_STATUS_ALARMS 3 /* alarm flags - alarms latch, write 1 to a bit to clear it */
120121
#define PX4IO_P_STATUS_ALARMS_VBATT_LOW (1 << 0) /* [1] VBatt is very close to regulator dropout */

src/modules/px4iofirmware/px4io.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ extern void controls_init(void);
217217
extern void controls_tick(void);
218218
extern int dsm_init(const char *device);
219219
extern bool dsm_input(uint16_t *values, uint16_t *num_values, uint8_t *n_bytes, uint8_t **bytes);
220+
extern bool xbus_input(uint8_t *bytes, uint16_t num_bytes, uint16_t *values, uint16_t *num_values);
220221
extern void dsm_bind(uint16_t cmd, int pulses);
221222
extern int sbus_init(const char *device);
222223
extern bool sbus_input(uint16_t *values, uint16_t *num_values, bool *sbus_failsafe, bool *sbus_frame_drop, uint16_t max_channels);

src/modules/px4iofirmware/xbus.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/****************************************************************************
2+
*
3+
* Copyright (c) 2012-2014 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 dsm.c
36+
*
37+
* Serial protocol decoder for the JR XBus protocol.
38+
*
39+
* Uses XBus Mode B which is the Multiplex SRXL protocol, details here
40+
* http://www.multiplex-rc.de/en/service/downloads/interface-descriptions.html?eID=dam_frontend_push&docID=4233
41+
*
42+
* Decodes into the global PPM buffer and updates accordingly.
43+
*/
44+
45+
#include <nuttx/config.h>
46+
#include <nuttx/arch.h>
47+
48+
#include <fcntl.h>
49+
#include <unistd.h>
50+
#include <termios.h>
51+
#include <string.h>
52+
53+
#include <drivers/drv_hrt.h>
54+
55+
#include "px4io.h"
56+
57+
#define XBUS_NUM_CHANNELS 12 /**<Number of XBus channels*/
58+
#define XBUS_PACKET_LENGTH 3 + XBUS_NUM_CHANNELS*2
59+
60+
static int bytesReceived = 0; /**<Number of bytes received since start character */
61+
static uint8_t xbus_buffer[XBUS_PACKET_LENGTH];
62+
63+
uint16_t CRC16(uint16_t crc, uint8_t value);
64+
65+
uint16_t CRC16(uint16_t crc, uint8_t value)
66+
{
67+
uint8_t i;
68+
crc = crc ^ (int16_t)value<<8;
69+
for(i = 0; i < 8; i++) {
70+
if(crc & 0x8000)
71+
crc = crc << 1^0x1021;
72+
else
73+
crc = crc << 1;
74+
}
75+
return crc;
76+
}
77+
78+
/**
79+
* Called periodically to check for input data from the XBus UART
80+
*
81+
*
82+
*
83+
* @param[in] bytes received through DSM serial port
84+
* @param[in] number of bytes received through DSM serial port
85+
* @param[out] values pointer to per channel array of decoded values
86+
* @param[out] num_values pointer to number of raw channel values returned
87+
88+
* @return true=decoded raw channel values updated, false=no update
89+
*/
90+
bool
91+
xbus_input(uint8_t *bytes, uint16_t num_bytes, uint16_t *values, uint16_t *num_values)
92+
{
93+
/* If we have no new data, return here */
94+
if (num_bytes < 1)
95+
return false;
96+
97+
/* Copy new bytes in to our buffer */
98+
memcpy(xbus_buffer + bytesReceived, bytes, num_bytes);
99+
100+
/* If start character is not correct, reset everything */
101+
if (xbus_buffer[0] != 0xA1) {
102+
memset(xbus_buffer, '\0', XBUS_PACKET_LENGTH);
103+
bytesReceived = 0;
104+
return false;
105+
}
106+
107+
/* Increment buffer length */
108+
bytesReceived += num_bytes;
109+
110+
/* If we don't have a full packet, return here */
111+
if (bytesReceived < XBUS_PACKET_LENGTH)
112+
return false;
113+
114+
/* Reset counter ready for next packet */
115+
bytesReceived = 0;
116+
117+
/* Check CRC of packet */
118+
uint16_t crc_calc = 0;
119+
for (int i=0; i< XBUS_PACKET_LENGTH-2; i++) {
120+
crc_calc = CRC16(crc_calc, xbus_buffer[i]);
121+
}
122+
uint16_t crc_buffer = ((uint16_t)(xbus_buffer[XBUS_PACKET_LENGTH - 2]))<<8 | (uint16_t)(xbus_buffer[XBUS_PACKET_LENGTH - 1]);
123+
if (crc_calc != crc_buffer)
124+
return false;
125+
126+
127+
/* Apply this channel mapping to get correct order
128+
* JR XBus Mode B order is:
129+
* - Aileron
130+
* - Elevator
131+
* - Rudder
132+
* - Aux 2 (Flap)
133+
* - Throttle
134+
* - Aux 1 (Gear)
135+
* - Aux 3
136+
* - Aux 4
137+
* - etc...
138+
**/
139+
uint8_t chMap[] = {1, 2, 3, 5, 0, 4, 6, 7, 8, 9, 10, 11};
140+
*num_values = XBUS_NUM_CHANNELS;
141+
142+
/* Channel scaling is linear between
143+
* - 0x000: 800us
144+
* - 0xfff: 2200us
145+
**/
146+
for (int channel = 0; channel<XBUS_NUM_CHANNELS; channel++) {
147+
uint32_t value = (((uint16_t)xbus_buffer[2*channel+1])<<8) | ((uint16_t)xbus_buffer[2*channel+2]);
148+
double dblVal = value*(2200.0-800.0)/4095.0 + 800.0;
149+
values[chMap[channel]] = (uint16_t)dblVal;
150+
}
151+
return true;
152+
}

0 commit comments

Comments
 (0)