MAMBAF405_2022A target
[inav.git] / src / main / rx / sbus.c
bloba206e0d41f99561972484bf7bfcf7e11cfc5cb94
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "platform.h"
24 FILE_COMPILE_FOR_SPEED
26 #ifdef USE_SERIAL_RX
28 #include "build/debug.h"
30 #include "common/utils.h"
32 #include "drivers/time.h"
34 #include "io/serial.h"
36 #ifdef USE_TELEMETRY
37 #include "telemetry/telemetry.h"
38 #endif
40 #include "rx/rx.h"
41 #include "rx/sbus.h"
42 #include "rx/sbus_channels.h"
45 * Observations
47 * FrSky X8R
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.
56 enum {
57 DEBUG_SBUS_INTERFRAME_TIME = 0,
58 DEBUG_SBUS_FRAME_FLAGS = 1,
59 DEBUG_SBUS_DESYNC_COUNTER = 2
62 typedef enum {
63 STATE_SBUS_SYNC = 0,
64 STATE_SBUS_PAYLOAD,
65 STATE_SBUS_WAIT_SYNC
66 } sbusDecoderState_e;
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];
73 uint8_t position;
74 timeUs_t lastActivityTimeUs;
75 } sbusFrameData_t;
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) {
94 case STATE_SBUS_SYNC:
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;
100 break;
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
116 frameValid = true;
117 sbusFrameData->state = STATE_SBUS_WAIT_SYNC;
118 break;
120 default: // Failed end marker
121 sbusFrameData->state = STATE_SBUS_WAIT_SYNC;
122 sbusDesyncCounter++;
123 DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_DESYNC_COUNTER, sbusDesyncCounter);
124 break;
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;
135 break;
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
140 break;
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);
163 return retValue;
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);
182 if (!portConfig) {
183 return false;
186 #ifdef USE_TELEMETRY
187 bool portShared = telemetryCheckRxPortShared(portConfig);
188 #else
189 bool portShared = false;
190 #endif
192 serialPort_t *sBusPort = openSerialPort(portConfig->identifier,
193 FUNCTION_RX_SERIAL,
194 sbusDataReceive,
195 &sbusFrameData,
196 sbusBaudRate,
197 portShared ? MODE_RXTX : MODE_RX,
198 SBUS_PORT_OPTIONS |
199 (rxConfig->serialrx_inverted ? 0 : SERIAL_INVERTED) |
200 (tristateWithDefaultOffIsActive(rxConfig->halfDuplex) ? SERIAL_BIDIR : 0)
203 #ifdef USE_TELEMETRY
204 if (portShared) {
205 telemetrySharedPort = sBusPort;
207 #endif
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);
221 #endif