Added generated timer definitions for STM32F7X2 universal target.
[betaflight.git] / src / main / rx / sbus.c
blob463ad3f0385c8a719483a5e9e0d42df66ef0444b
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdlib.h>
25 #include "platform.h"
27 #ifdef USE_SERIAL_RX
29 #include "build/debug.h"
31 #include "common/utils.h"
33 #include "drivers/time.h"
35 #include "io/serial.h"
37 #ifdef USE_TELEMETRY
38 #include "telemetry/telemetry.h"
39 #endif
41 #include "rx/rx.h"
42 #include "rx/sbus.h"
43 #include "rx/sbus_channels.h"
46 * Observations
48 * FrSky X8R
49 * time between frames: 6ms.
50 * time to send frame: 3ms.
52 * Futaba R6208SB/R6303SB
53 * time between frames: 11ms.
54 * time to send frame: 3ms.
57 #define SBUS_TIME_NEEDED_PER_FRAME 3000
59 #define SBUS_STATE_FAILSAFE (1 << 0)
60 #define SBUS_STATE_SIGNALLOSS (1 << 1)
62 #define SBUS_FRAME_SIZE (SBUS_CHANNEL_DATA_LENGTH + 2)
64 #define SBUS_FRAME_BEGIN_BYTE 0x0F
66 #define SBUS_BAUDRATE 100000
68 #if !defined(SBUS_PORT_OPTIONS)
69 #define SBUS_PORT_OPTIONS (SERIAL_STOPBITS_2 | SERIAL_PARITY_EVEN)
70 #endif
72 #define SBUS_DIGITAL_CHANNEL_MIN 173
73 #define SBUS_DIGITAL_CHANNEL_MAX 1812
75 enum {
76 DEBUG_SBUS_FRAME_FLAGS = 0,
77 DEBUG_SBUS_STATE_FLAGS,
78 DEBUG_SBUS_FRAME_TIME,
82 struct sbusFrame_s {
83 uint8_t syncByte;
84 sbusChannels_t channels;
85 /**
86 * The endByte is 0x00 on FrSky and some futaba RX's, on Some SBUS2 RX's the value indicates the telemetry byte that is sent after every 4th sbus frame.
88 * See https://github.com/cleanflight/cleanflight/issues/590#issuecomment-101027349
89 * and
90 * https://github.com/cleanflight/cleanflight/issues/590#issuecomment-101706023
92 uint8_t endByte;
93 } __attribute__ ((__packed__));
95 typedef union sbusFrame_u {
96 uint8_t bytes[SBUS_FRAME_SIZE];
97 struct sbusFrame_s frame;
98 } sbusFrame_t;
100 typedef struct sbusFrameData_s {
101 sbusFrame_t frame;
102 uint32_t startAtUs;
103 uint16_t stateFlags;
104 uint8_t position;
105 bool done;
106 } sbusFrameData_t;
109 // Receive ISR callback
110 static void sbusDataReceive(uint16_t c, void *data)
112 sbusFrameData_t *sbusFrameData = data;
114 const uint32_t nowUs = micros();
116 const int32_t sbusFrameTime = nowUs - sbusFrameData->startAtUs;
118 if (sbusFrameTime > (long)(SBUS_TIME_NEEDED_PER_FRAME + 500)) {
119 sbusFrameData->position = 0;
122 if (sbusFrameData->position == 0) {
123 if (c != SBUS_FRAME_BEGIN_BYTE) {
124 return;
126 sbusFrameData->startAtUs = nowUs;
129 if (sbusFrameData->position < SBUS_FRAME_SIZE) {
130 sbusFrameData->frame.bytes[sbusFrameData->position++] = (uint8_t)c;
131 if (sbusFrameData->position < SBUS_FRAME_SIZE) {
132 sbusFrameData->done = false;
133 } else {
134 sbusFrameData->done = true;
135 DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_FRAME_TIME, sbusFrameTime);
140 static uint8_t sbusFrameStatus(rxRuntimeConfig_t *rxRuntimeConfig)
142 sbusFrameData_t *sbusFrameData = rxRuntimeConfig->frameData;
143 if (!sbusFrameData->done) {
144 return RX_FRAME_PENDING;
146 sbusFrameData->done = false;
148 DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_FRAME_FLAGS, sbusFrameData->frame.frame.channels.flags);
150 if (sbusFrameData->frame.frame.channels.flags & SBUS_FLAG_SIGNAL_LOSS) {
151 sbusFrameData->stateFlags |= SBUS_STATE_SIGNALLOSS;
152 DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_STATE_FLAGS, sbusFrameData->stateFlags);
154 if (sbusFrameData->frame.frame.channels.flags & SBUS_FLAG_FAILSAFE_ACTIVE) {
155 sbusFrameData->stateFlags |= SBUS_STATE_FAILSAFE;
156 DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_STATE_FLAGS, sbusFrameData->stateFlags);
159 DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_STATE_FLAGS, sbusFrameData->stateFlags);
161 return sbusChannelsDecode(rxRuntimeConfig, &sbusFrameData->frame.frame.channels);
164 bool sbusInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig)
166 static uint16_t sbusChannelData[SBUS_MAX_CHANNEL];
167 static sbusFrameData_t sbusFrameData;
169 rxRuntimeConfig->channelData = sbusChannelData;
170 rxRuntimeConfig->frameData = &sbusFrameData;
171 sbusChannelsInit(rxConfig, rxRuntimeConfig);
173 rxRuntimeConfig->channelCount = SBUS_MAX_CHANNEL;
174 rxRuntimeConfig->rxRefreshRate = 11000;
176 rxRuntimeConfig->rcFrameStatusFn = sbusFrameStatus;
178 const serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_RX_SERIAL);
179 if (!portConfig) {
180 return false;
183 #ifdef USE_TELEMETRY
184 bool portShared = telemetryCheckRxPortShared(portConfig);
185 #else
186 bool portShared = false;
187 #endif
189 serialPort_t *sBusPort = openSerialPort(portConfig->identifier,
190 FUNCTION_RX_SERIAL,
191 sbusDataReceive,
192 &sbusFrameData,
193 SBUS_BAUDRATE,
194 portShared ? MODE_RXTX : MODE_RX,
195 SBUS_PORT_OPTIONS | (rxConfig->serialrx_inverted ? 0 : SERIAL_INVERTED) | (rxConfig->halfDuplex ? SERIAL_BIDIR : 0)
198 if (rxConfig->rssi_src_frame_errors) {
199 rssiSource = RSSI_SOURCE_FRAME_ERRORS;
202 #ifdef USE_TELEMETRY
203 if (portShared) {
204 telemetrySharedPort = sBusPort;
206 #endif
208 return sBusPort != NULL;
210 #endif