2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_SBus Futaba S.Bus receiver functions
6 * @brief Code to read Futaba S.Bus receiver serial stream
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
11 * @brief Code to read Futaba S.Bus receiver serial stream
12 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #ifdef PIOS_INCLUDE_SBUS
35 // Define to report number of frames since last dropped instead of weighted ave
36 #undef SBUS_GOOD_FRAME_COUNT
38 #include <uavobjectmanager.h>
39 #include "pios_sbus_priv.h"
41 /* Forward Declarations */
42 static int32_t PIOS_SBus_Get(uint32_t rcvr_id
, uint8_t channel
);
43 static uint16_t PIOS_SBus_RxInCallback(uint32_t context
,
48 static void PIOS_SBus_Supervisor(uint32_t sbus_id
);
49 static uint8_t PIOS_SBus_Quality_Get(uint32_t rcvr_id
);
52 const struct pios_rcvr_driver pios_sbus_rcvr_driver
= {
53 .read
= PIOS_SBus_Get
,
54 .get_quality
= PIOS_SBus_Quality_Get
57 enum pios_sbus_dev_magic
{
58 PIOS_SBUS_DEV_MAGIC
= 0x53427573,
61 struct pios_sbus_state
{
62 uint16_t channel_data
[PIOS_SBUS_NUM_INPUTS
];
63 uint8_t received_data
[SBUS_FRAME_LENGTH
- 2];
64 uint8_t receive_timer
;
65 uint8_t failsafe_timer
;
69 #ifdef SBUS_GOOD_FRAME_COUNT
71 #endif /* SBUS_GOOD_FRAME_COUNT */
74 /* With an S.Bus frame rate of 7ms (130Hz) averaging over 26 samples
75 * gives about a 200ms response.
77 #define SBUS_FL_WEIGHTED_AVE 26
79 struct pios_sbus_dev
{
80 enum pios_sbus_dev_magic magic
;
81 const struct pios_sbus_cfg
*cfg
;
82 struct pios_sbus_state state
;
85 /* Allocate S.Bus device descriptor */
86 #if defined(PIOS_INCLUDE_FREERTOS)
87 static struct pios_sbus_dev
*PIOS_SBus_Alloc(void)
89 struct pios_sbus_dev
*sbus_dev
;
91 sbus_dev
= (struct pios_sbus_dev
*)pios_malloc(sizeof(*sbus_dev
));
96 sbus_dev
->magic
= PIOS_SBUS_DEV_MAGIC
;
100 static struct pios_sbus_dev pios_sbus_devs
[PIOS_SBUS_MAX_DEVS
];
101 static uint8_t pios_sbus_num_devs
;
102 static struct pios_sbus_dev
*PIOS_SBus_Alloc(void)
104 struct pios_sbus_dev
*sbus_dev
;
106 if (pios_sbus_num_devs
>= PIOS_SBUS_MAX_DEVS
) {
110 sbus_dev
= &pios_sbus_devs
[pios_sbus_num_devs
++];
111 sbus_dev
->magic
= PIOS_SBUS_DEV_MAGIC
;
115 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
117 /* Validate S.Bus device descriptor */
118 static bool PIOS_SBus_Validate(struct pios_sbus_dev
*sbus_dev
)
120 return sbus_dev
->magic
== PIOS_SBUS_DEV_MAGIC
;
123 /* Reset channels in case of lost signal or explicit failsafe receiver flag */
124 static void PIOS_SBus_ResetChannels(struct pios_sbus_state
*state
)
126 for (int i
= 0; i
< PIOS_SBUS_NUM_INPUTS
; i
++) {
127 state
->channel_data
[i
] = PIOS_RCVR_TIMEOUT
;
131 /* Reset S.Bus receiver state */
132 static void PIOS_SBus_ResetState(struct pios_sbus_state
*state
)
134 state
->receive_timer
= 0;
135 state
->failsafe_timer
= 0;
136 state
->frame_found
= 0;
137 state
->quality
= 0.0f
;
138 #ifdef SBUS_GOOD_FRAME_COUNT
139 state
->frame_count
= 0;
140 #endif /* SBUS_GOOD_FRAME_COUNT */
141 PIOS_SBus_ResetChannels(state
);
144 /* Initialise S.Bus receiver interface */
145 int32_t PIOS_SBus_Init(uint32_t *sbus_id
,
146 const struct pios_sbus_cfg
*cfg
,
147 const struct pios_com_driver
*driver
,
150 PIOS_DEBUG_Assert(sbus_id
);
151 PIOS_DEBUG_Assert(cfg
);
152 PIOS_DEBUG_Assert(driver
);
154 struct pios_sbus_dev
*sbus_dev
;
156 sbus_dev
= (struct pios_sbus_dev
*)PIOS_SBus_Alloc();
161 /* Bind the configuration to the device instance */
164 PIOS_SBus_ResetState(&(sbus_dev
->state
));
166 *sbus_id
= (uint32_t)sbus_dev
;
168 /* Enable inverter clock and enable the inverter */
169 (*cfg
->gpio_clk_func
)(cfg
->gpio_clk_periph
, ENABLE
);
170 GPIO_Init(cfg
->inv
.gpio
, &cfg
->inv
.init
);
171 GPIO_WriteBit(cfg
->inv
.gpio
, cfg
->inv
.init
.GPIO_Pin
, cfg
->gpio_inv_enable
);
173 /* Set comm driver callback */
174 (driver
->bind_rx_cb
)(lower_id
, PIOS_SBus_RxInCallback
, *sbus_id
);
176 if (!PIOS_RTC_RegisterTickCallback(PIOS_SBus_Supervisor
, *sbus_id
)) {
177 PIOS_DEBUG_Assert(0);
187 * Get the value of an input channel
188 * \param[in] channel Number of the channel desired (zero based)
189 * \output PIOS_RCVR_INVALID channel not available
190 * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver
191 * \output >=0 channel value
193 static int32_t PIOS_SBus_Get(uint32_t rcvr_id
, uint8_t channel
)
195 struct pios_sbus_dev
*sbus_dev
= (struct pios_sbus_dev
*)rcvr_id
;
197 if (!PIOS_SBus_Validate(sbus_dev
)) {
198 return PIOS_RCVR_INVALID
;
201 /* return error if channel is not available */
202 if (channel
>= PIOS_SBUS_NUM_INPUTS
) {
203 return PIOS_RCVR_INVALID
;
206 return sbus_dev
->state
.channel_data
[channel
];
210 * Compute channel_data[] from received_data[].
211 * For efficiency it unrolls first 8 channels without loops and does the
212 * same for other 8 channels. Also 2 discrete channels will be set.
214 static void PIOS_SBus_UnrollChannels(struct pios_sbus_state
*state
)
216 uint8_t *s
= state
->received_data
;
217 uint16_t *d
= state
->channel_data
;
219 #define F(v, s) (((v) >> (s)) & 0x7ff)
221 /* unroll channels 1-8 */
222 *d
++ = F(s
[0] | s
[1] << 8, 0);
223 *d
++ = F(s
[1] | s
[2] << 8, 3);
224 *d
++ = F(s
[2] | s
[3] << 8 | s
[4] << 16, 6);
225 *d
++ = F(s
[4] | s
[5] << 8, 1);
226 *d
++ = F(s
[5] | s
[6] << 8, 4);
227 *d
++ = F(s
[6] | s
[7] << 8 | s
[8] << 16, 7);
228 *d
++ = F(s
[8] | s
[9] << 8, 2);
229 *d
++ = F(s
[9] | s
[10] << 8, 5);
231 /* unroll channels 9-16 */
232 *d
++ = F(s
[11] | s
[12] << 8, 0);
233 *d
++ = F(s
[12] | s
[13] << 8, 3);
234 *d
++ = F(s
[13] | s
[14] << 8 | s
[15] << 16, 6);
235 *d
++ = F(s
[15] | s
[16] << 8, 1);
236 *d
++ = F(s
[16] | s
[17] << 8, 4);
237 *d
++ = F(s
[17] | s
[18] << 8 | s
[19] << 16, 7);
238 *d
++ = F(s
[19] | s
[20] << 8, 2);
239 *d
++ = F(s
[20] | s
[21] << 8, 5);
241 /* unroll discrete channels 17 and 18 */
242 *d
++ = (s
[22] & SBUS_FLAG_DC1
) ? SBUS_VALUE_MAX
: SBUS_VALUE_MIN
;
243 *d
++ = (s
[22] & SBUS_FLAG_DC2
) ? SBUS_VALUE_MAX
: SBUS_VALUE_MIN
;
246 /* Update decoder state processing input byte from the S.Bus stream */
247 static void PIOS_SBus_UpdateState(struct pios_sbus_state
*state
, uint8_t b
)
249 /* should not process any data until new frame is found */
250 if (!state
->frame_found
) {
254 if (state
->byte_count
== 0) {
255 if (b
!= SBUS_SOF_BYTE
) {
256 /* discard the whole frame if the 1st byte is not correct */
257 state
->frame_found
= 0;
259 /* do not store the SOF byte */
265 /* do not store last frame byte as well */
266 if (state
->byte_count
< SBUS_FRAME_LENGTH
- 1) {
267 /* store next byte */
268 state
->received_data
[state
->byte_count
- 1] = b
;
271 if (b
== SBUS_EOF_BYTE
|| (b
& SBUS_R7008SB_EOF_COUNTER_MASK
) == 0) {
272 #ifndef SBUS_GOOD_FRAME_COUNT
273 /* Quality trend is towards 0% by default*/
274 uint8_t quality_trend
= 0;
275 #endif /* SBUS_GOOD_FRAME_COUNT */
277 /* full frame received */
278 uint8_t flags
= state
->received_data
[SBUS_FRAME_LENGTH
- 3];
279 if (flags
& SBUS_FLAG_FL
) {
280 /* frame lost, do not update */
281 #ifdef SBUS_GOOD_FRAME_COUNT
282 state
->quality
= state
->frame_count
;
283 state
->frame_count
= 0;
284 #endif /* SBUS_GOOD_FRAME_COUNT */
286 #ifdef SBUS_GOOD_FRAME_COUNT
287 if (++state
->frame_count
== 255) {
288 state
->quality
= state
->frame_count
--;
290 #else /* SBUS_GOOD_FRAME_COUNT */
291 /* Quality trend is towards 100% */
293 #endif /* SBUS_GOOD_FRAME_COUNT */
294 if (flags
& SBUS_FLAG_FS
) {
295 /* failsafe flag active */
296 PIOS_SBus_ResetChannels(state
);
298 /* data looking good */
299 PIOS_SBus_UnrollChannels(state
);
300 state
->failsafe_timer
= 0;
303 #ifndef SBUS_GOOD_FRAME_COUNT
304 /* Present quality as a weighted average of good frames */
305 state
->quality
= ((state
->quality
* (SBUS_FL_WEIGHTED_AVE
- 1)) +
306 quality_trend
) / SBUS_FL_WEIGHTED_AVE
;
307 #endif /* SBUS_GOOD_FRAME_COUNT */
309 /* discard whole frame */
312 /* prepare for the next frame */
313 state
->frame_found
= 0;
317 /* Comm byte received callback */
318 static uint16_t PIOS_SBus_RxInCallback(uint32_t context
,
324 struct pios_sbus_dev
*sbus_dev
= (struct pios_sbus_dev
*)context
;
326 bool valid
= PIOS_SBus_Validate(sbus_dev
);
330 struct pios_sbus_state
*state
= &(sbus_dev
->state
);
332 /* process byte(s) and clear receive timer */
333 for (uint8_t i
= 0; i
< buf_len
; i
++) {
334 PIOS_SBus_UpdateState(state
, buf
[i
]);
335 state
->receive_timer
= 0;
338 /* Always signal that we can accept another byte */
340 *headroom
= SBUS_FRAME_LENGTH
;
343 /* We never need a yield */
346 /* Always indicate that all bytes were consumed */
351 * Input data supervisor is called periodically and provides
352 * two functions: frame syncing and failsafe triggering.
354 * S.Bus frames come at 7ms (HS) or 14ms (FS) rate at 100000bps.
355 * RTC timer is running at 625Hz (1.6ms). So with divider 2 it gives
356 * 3.2ms pause between frames which is good for both S.Bus frame rates.
358 * Data receive function must clear the receive_timer to confirm new
359 * data reception. If no new data received in 100ms, we must call the
360 * failsafe function which clears all channels.
362 static void PIOS_SBus_Supervisor(uint32_t sbus_id
)
364 struct pios_sbus_dev
*sbus_dev
= (struct pios_sbus_dev
*)sbus_id
;
366 bool valid
= PIOS_SBus_Validate(sbus_dev
);
370 struct pios_sbus_state
*state
= &(sbus_dev
->state
);
372 /* waiting for new frame if no bytes were received in 3.2ms */
373 if (++state
->receive_timer
> 2) {
374 state
->frame_found
= 1;
375 state
->byte_count
= 0;
376 state
->receive_timer
= 0;
379 /* activate failsafe if no frames have arrived in 102.4ms */
380 if (++state
->failsafe_timer
> 64) {
381 PIOS_SBus_ResetChannels(state
);
382 state
->failsafe_timer
= 0;
386 static uint8_t PIOS_SBus_Quality_Get(uint32_t sbus_id
)
388 struct pios_sbus_dev
*sbus_dev
= (struct pios_sbus_dev
*)sbus_id
;
390 bool valid
= PIOS_SBus_Validate(sbus_dev
);
394 struct pios_sbus_state
*state
= &(sbus_dev
->state
);
396 return (uint8_t)(state
->quality
+ 0.5f
);
399 #endif /* PIOS_INCLUDE_SBUS */