2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
24 FILE_COMPILE_FOR_SPEED
28 #include "build/debug.h"
30 #include "common/utils.h"
32 #include "drivers/time.h"
34 #include "io/serial.h"
37 #include "telemetry/telemetry.h"
42 #include "rx/sbus_channels.h"
48 * time between frames: 6ms.
49 * time to send frame: 3ms.
51 * Futaba R6208SB/R6303SB
52 * time between frames: 11ms.
53 * time to send frame: 3ms.
57 DEBUG_SBUS_INTERFRAME_TIME
= 0,
58 DEBUG_SBUS_FRAME_FLAGS
= 1,
59 DEBUG_SBUS_DESYNC_COUNTER
= 2
68 typedef struct sbusFrameData_s
{
69 sbusDecoderState_e state
;
70 volatile sbusFrame_t frame
;
71 volatile bool frameDone
;
72 uint8_t buffer
[SBUS_FRAME_SIZE
];
74 timeUs_t lastActivityTimeUs
;
77 // Receive ISR callback
78 static void sbusDataReceive(uint16_t c
, void *data
)
80 static uint16_t sbusDesyncCounter
= 0;
82 sbusFrameData_t
*sbusFrameData
= data
;
83 const timeUs_t currentTimeUs
= micros();
84 const timeDelta_t timeSinceLastByteUs
= cmpTimeUs(currentTimeUs
, sbusFrameData
->lastActivityTimeUs
);
85 sbusFrameData
->lastActivityTimeUs
= currentTimeUs
;
87 // Handle inter-frame gap. We dwell in STATE_SBUS_WAIT_SYNC state ignoring all incoming bytes until we get long enough quite period on the wire
88 if (sbusFrameData
->state
== STATE_SBUS_WAIT_SYNC
&& timeSinceLastByteUs
>= rxConfig()->sbusSyncInterval
) {
89 DEBUG_SET(DEBUG_SBUS
, DEBUG_SBUS_INTERFRAME_TIME
, timeSinceLastByteUs
);
90 sbusFrameData
->state
= STATE_SBUS_SYNC
;
93 switch (sbusFrameData
->state
) {
95 if (c
== SBUS_FRAME_BEGIN_BYTE
) {
96 sbusFrameData
->position
= 0;
97 sbusFrameData
->buffer
[sbusFrameData
->position
++] = (uint8_t)c
;
98 sbusFrameData
->state
= STATE_SBUS_PAYLOAD
;
102 case STATE_SBUS_PAYLOAD
:
103 sbusFrameData
->buffer
[sbusFrameData
->position
++] = (uint8_t)c
;
105 if (sbusFrameData
->position
== SBUS_FRAME_SIZE
) {
106 const sbusFrame_t
* frame
= (sbusFrame_t
*)&sbusFrameData
->buffer
[0];
107 bool frameValid
= false;
109 // Do some sanity check
110 switch (frame
->endByte
) {
111 case 0x00: // This is S.BUS 1
112 case 0x04: // S.BUS 2 receiver voltage
113 case 0x14: // S.BUS 2 GPS/baro
114 case 0x24: // Unknown SBUS2 data
115 case 0x34: // Unknown SBUS2 data
117 sbusFrameData
->state
= STATE_SBUS_WAIT_SYNC
;
120 default: // Failed end marker
121 sbusFrameData
->state
= STATE_SBUS_WAIT_SYNC
;
123 DEBUG_SET(DEBUG_SBUS
, DEBUG_SBUS_DESYNC_COUNTER
, sbusDesyncCounter
);
127 // Frame seems sane, pass data to decoder
128 if (!sbusFrameData
->frameDone
&& frameValid
) {
129 DEBUG_SET(DEBUG_SBUS
, DEBUG_SBUS_FRAME_FLAGS
, frame
->channels
.flags
);
131 memcpy((void *)&sbusFrameData
->frame
, (void *)&sbusFrameData
->buffer
[0], SBUS_FRAME_SIZE
);
132 sbusFrameData
->frameDone
= true;
137 case STATE_SBUS_WAIT_SYNC
:
138 // Stay at this state and do nothing. Exit will be handled before byte is processed if the
139 // inter-frame gap is long enough
144 static uint8_t sbusFrameStatus(rxRuntimeConfig_t
*rxRuntimeConfig
)
146 sbusFrameData_t
*sbusFrameData
= rxRuntimeConfig
->frameData
;
148 if (!sbusFrameData
->frameDone
) {
149 return RX_FRAME_PENDING
;
152 // Decode channel data and store return value
153 const uint8_t retValue
= sbusChannelsDecode(rxRuntimeConfig
, (void *)&sbusFrameData
->frame
.channels
);
155 // Reset the frameDone flag - tell ISR that we're ready to receive next frame
156 sbusFrameData
->frameDone
= false;
158 // Calculate "virtual link quality based on packet loss metric"
159 if (retValue
& RX_FRAME_COMPLETE
) {
160 lqTrackerAccumulate(rxRuntimeConfig
->lqTracker
, ((retValue
& RX_FRAME_DROPPED
) || (retValue
& RX_FRAME_FAILSAFE
)) ? 0 : RSSI_MAX_VALUE
);
166 static bool sbusInitEx(const rxConfig_t
*rxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
, uint32_t sbusBaudRate
)
168 static uint16_t sbusChannelData
[SBUS_MAX_CHANNEL
];
169 static sbusFrameData_t sbusFrameData
;
171 rxRuntimeConfig
->channelData
= sbusChannelData
;
172 rxRuntimeConfig
->frameData
= &sbusFrameData
;
174 sbusChannelsInit(rxRuntimeConfig
);
176 rxRuntimeConfig
->channelCount
= SBUS_MAX_CHANNEL
;
177 rxRuntimeConfig
->rxRefreshRate
= 11000;
179 rxRuntimeConfig
->rcFrameStatusFn
= sbusFrameStatus
;
181 const serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_RX_SERIAL
);
187 bool portShared
= telemetryCheckRxPortShared(portConfig
);
189 bool portShared
= false;
192 serialPort_t
*sBusPort
= openSerialPort(portConfig
->identifier
,
197 portShared
? MODE_RXTX
: MODE_RX
,
199 (rxConfig
->serialrx_inverted
? 0 : SERIAL_INVERTED
) |
200 (tristateWithDefaultOffIsActive(rxConfig
->halfDuplex
) ? SERIAL_BIDIR
: 0)
205 telemetrySharedPort
= sBusPort
;
209 return sBusPort
!= NULL
;
212 bool sbusInit(const rxConfig_t
*rxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
)
214 return sbusInitEx(rxConfig
, rxRuntimeConfig
, SBUS_BAUDRATE
);
217 bool sbusInitFast(const rxConfig_t
*rxConfig
, rxRuntimeConfig_t
*rxRuntimeConfig
)
219 return sbusInitEx(rxConfig
, rxRuntimeConfig
, SBUS_BAUDRATE_FAST
);