2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_DSM Spektrum/JR DSMx satellite receiver functions
6 * @brief Code to bind and read Spektrum/JR DSMx satellite receiver serial stream
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
11 * @brief Code bind and read Spektrum/JR DSMx satellite 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_DSM
35 #include "pios_dsm_priv.h"
37 // *** UNTESTED CODE ***
38 #undef DSM_LINK_QUALITY
40 /* Forward Declarations */
41 static int32_t PIOS_DSM_Get(uint32_t rcvr_id
, uint8_t channel
);
42 static uint8_t PIOS_DSM_Quality_Get(uint32_t rcvr_id
);
43 static uint16_t PIOS_DSM_RxInCallback(uint32_t context
,
48 static void PIOS_DSM_Supervisor(uint32_t dsm_id
);
51 const struct pios_rcvr_driver pios_dsm_rcvr_driver
= {
53 .get_quality
= PIOS_DSM_Quality_Get
56 enum pios_dsm_dev_magic
{
57 PIOS_DSM_DEV_MAGIC
= 0x44534d78,
60 struct pios_dsm_state
{
61 uint16_t channel_data
[PIOS_DSM_NUM_INPUTS
];
62 uint8_t received_data
[DSM_FRAME_LENGTH
];
63 uint8_t receive_timer
;
64 uint8_t failsafe_timer
;
67 uint8_t frames_lost_last
;
71 /* With an DSM frame rate of 11ms (90Hz) averaging over 18 samples
72 * gives about a 200ms response.
74 #define DSM_FL_WEIGHTED_AVE 18
77 enum pios_dsm_dev_magic magic
;
78 const struct pios_dsm_cfg
*cfg
;
79 struct pios_dsm_state state
;
82 /* Allocate DSM device descriptor */
83 #if defined(PIOS_INCLUDE_FREERTOS)
84 static struct pios_dsm_dev
*PIOS_DSM_Alloc(void)
86 struct pios_dsm_dev
*dsm_dev
;
88 dsm_dev
= (struct pios_dsm_dev
*)pios_malloc(sizeof(*dsm_dev
));
93 dsm_dev
->magic
= PIOS_DSM_DEV_MAGIC
;
97 static struct pios_dsm_dev pios_dsm_devs
[PIOS_DSM_MAX_DEVS
];
98 static uint8_t pios_dsm_num_devs
;
99 static struct pios_dsm_dev
*PIOS_DSM_Alloc(void)
101 struct pios_dsm_dev
*dsm_dev
;
103 if (pios_dsm_num_devs
>= PIOS_DSM_MAX_DEVS
) {
107 dsm_dev
= &pios_dsm_devs
[pios_dsm_num_devs
++];
108 dsm_dev
->magic
= PIOS_DSM_DEV_MAGIC
;
112 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
114 /* Validate DSM device descriptor */
115 static bool PIOS_DSM_Validate(struct pios_dsm_dev
*dsm_dev
)
117 return dsm_dev
->magic
== PIOS_DSM_DEV_MAGIC
;
120 /* Try to bind DSMx satellite using specified number of pulses */
121 static void PIOS_DSM_Bind(struct pios_dsm_dev
*dsm_dev
, uint8_t bind
)
123 const struct pios_dsm_cfg
*cfg
= dsm_dev
->cfg
;
125 GPIO_InitTypeDef GPIO_InitStructure
;
127 GPIO_InitStructure
.GPIO_Pin
= cfg
->bind
.init
.GPIO_Pin
;
128 GPIO_InitStructure
.GPIO_Speed
= cfg
->bind
.init
.GPIO_Speed
;
129 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_IPU
;
131 /* just to limit bind pulses */
136 GPIO_Init(cfg
->bind
.gpio
, &cfg
->bind
.init
);
138 /* RX line, set high */
139 GPIO_SetBits(cfg
->bind
.gpio
, cfg
->bind
.init
.GPIO_Pin
);
141 /* on CC works up to 140ms, guess bind window is around 20-140ms after power up */
142 PIOS_DELAY_WaitmS(20);
144 for (int i
= 0; i
< bind
; i
++) {
145 /* RX line, drive low for 120us */
146 GPIO_ResetBits(cfg
->bind
.gpio
, cfg
->bind
.init
.GPIO_Pin
);
147 PIOS_DELAY_WaituS(120);
148 /* RX line, drive high for 120us */
149 GPIO_SetBits(cfg
->bind
.gpio
, cfg
->bind
.init
.GPIO_Pin
);
150 PIOS_DELAY_WaituS(120);
152 /* RX line, set input and wait for data */
153 GPIO_Init(cfg
->bind
.gpio
, &GPIO_InitStructure
);
156 /* Reset channels in case of lost signal or explicit failsafe receiver flag */
157 static void PIOS_DSM_ResetChannels(struct pios_dsm_dev
*dsm_dev
)
159 struct pios_dsm_state
*state
= &(dsm_dev
->state
);
161 for (int i
= 0; i
< PIOS_DSM_NUM_INPUTS
; i
++) {
162 state
->channel_data
[i
] = PIOS_RCVR_TIMEOUT
;
166 /* Reset DSM receiver state */
167 static void PIOS_DSM_ResetState(struct pios_dsm_dev
*dsm_dev
)
169 struct pios_dsm_state
*state
= &(dsm_dev
->state
);
171 state
->receive_timer
= 0;
172 state
->failsafe_timer
= 0;
173 state
->frame_found
= 0;
174 state
->quality
= 0.0f
;
175 state
->frames_lost_last
= 0;
176 PIOS_DSM_ResetChannels(dsm_dev
);
180 * Check and unroll complete frame data.
181 * \output 0 frame data accepted
182 * \output -1 frame error found
184 static int PIOS_DSM_UnrollChannels(struct pios_dsm_dev
*dsm_dev
)
186 struct pios_dsm_state
*state
= &(dsm_dev
->state
);
187 /* Fix resolution for detection. */
188 static uint8_t resolution
= 11;
189 uint32_t channel_log
= 0;
191 // *** UNTESTED CODE ***
192 #ifdef DSM_LINK_QUALITY
193 /* increment the lost frame counter */
194 uint8_t frames_lost
= state
->received_data
[0];
196 /* We only get a lost frame count when the next good frame comes in */
197 /* Present quality as a weighted average of good frames */
198 /* First consider the bad frames */
199 for (int i
= 0; i
< frames_lost
- state
->frames_lost_last
; i
++) {
200 state
->quality
= (state
->quality
* (DSM_FL_WEIGHTED_AVE
- 1)) /
203 /* And now the good frame */
204 state
->quality
= ((state
->quality
* (DSM_FL_WEIGHTED_AVE
- 1)) +
205 100) / DSM_FL_WEIGHTED_AVE
;
207 state
->frames_lost_last
= frames_lost
;
208 #endif /* DSM_LINK_QUALITY */
210 /* unroll channels */
211 uint8_t *s
= &(state
->received_data
[2]);
212 uint16_t mask
= (resolution
== 10) ? 0x03ff : 0x07ff;
214 for (int i
= 0; i
< DSM_CHANNELS_PER_FRAME
; i
++) {
215 uint16_t word
= ((uint16_t)s
[0] << 8) | s
[1];
218 /* skip empty channel slot */
219 if (word
== 0xffff) {
223 /* minimal data validation */
224 if ((i
> 0) && (word
& DSM_2ND_FRAME_MASK
)) {
225 /* invalid frame data, ignore rest of the frame */
229 /* extract and save the channel value */
230 uint8_t channel_num
= (word
>> resolution
) & 0x0f;
231 if (channel_num
< PIOS_DSM_NUM_INPUTS
) {
232 if (channel_log
& (1 << channel_num
)) {
233 /* Found duplicate. This should happen when in 11 bit */
234 /* mode and the data is 10 bits */
235 if (resolution
== 10) {
239 return PIOS_DSM_UnrollChannels(dsm_dev
);
242 if ((channel_log
& 0xFF) == 0x55) {
243 /* This pattern indicates 10 bit pattern */
244 if (resolution
== 11) {
248 return PIOS_DSM_UnrollChannels(dsm_dev
);
251 state
->channel_data
[channel_num
] = (word
& mask
);
252 /* keep track of this channel */
253 channel_log
|= (1 << channel_num
);
257 /* all channels processed */
261 /* either DSM2 selected with DSMX stream found, or vice-versa */
265 /* Update decoder state processing input byte from the DSMx stream */
266 static void PIOS_DSM_UpdateState(struct pios_dsm_dev
*dsm_dev
, uint8_t byte
)
268 struct pios_dsm_state
*state
= &(dsm_dev
->state
);
270 if (state
->frame_found
) {
271 /* receiving the data frame */
272 if (state
->byte_count
< DSM_FRAME_LENGTH
) {
273 /* store next byte */
274 state
->received_data
[state
->byte_count
++] = byte
;
275 if (state
->byte_count
== DSM_FRAME_LENGTH
) {
276 /* full frame received - process and wait for new one */
277 if (!PIOS_DSM_UnrollChannels(dsm_dev
)) {
278 /* data looking good */
279 state
->failsafe_timer
= 0;
282 /* prepare for the next frame */
283 state
->frame_found
= 0;
289 /* Initialise DSM receiver interface */
290 int32_t PIOS_DSM_Init(uint32_t *dsm_id
,
291 const struct pios_dsm_cfg
*cfg
,
292 const struct pios_com_driver
*driver
,
296 PIOS_DEBUG_Assert(dsm_id
);
297 PIOS_DEBUG_Assert(cfg
);
298 PIOS_DEBUG_Assert(driver
);
300 struct pios_dsm_dev
*dsm_dev
;
302 dsm_dev
= (struct pios_dsm_dev
*)PIOS_DSM_Alloc();
307 /* Bind the configuration to the device instance */
310 /* Bind the receiver if requested */
312 PIOS_DSM_Bind(dsm_dev
, bind
);
315 PIOS_DSM_ResetState(dsm_dev
);
317 *dsm_id
= (uint32_t)dsm_dev
;
319 /* Set comm driver callback */
320 (driver
->bind_rx_cb
)(lower_id
, PIOS_DSM_RxInCallback
, *dsm_id
);
322 if (!PIOS_RTC_RegisterTickCallback(PIOS_DSM_Supervisor
, *dsm_id
)) {
323 PIOS_DEBUG_Assert(0);
329 /* Comm byte received callback */
330 static uint16_t PIOS_DSM_RxInCallback(uint32_t context
,
336 struct pios_dsm_dev
*dsm_dev
= (struct pios_dsm_dev
*)context
;
338 bool valid
= PIOS_DSM_Validate(dsm_dev
);
342 /* process byte(s) and clear receive timer */
343 for (uint8_t i
= 0; i
< buf_len
; i
++) {
344 PIOS_DSM_UpdateState(dsm_dev
, buf
[i
]);
345 dsm_dev
->state
.receive_timer
= 0;
348 /* Always signal that we can accept another byte */
350 *headroom
= DSM_FRAME_LENGTH
;
353 /* We never need a yield */
356 /* Always indicate that all bytes were consumed */
361 * Get the value of an input channel
362 * \param[in] channel Number of the channel desired (zero based)
363 * \output PIOS_RCVR_INVALID channel not available
364 * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver
365 * \output >=0 channel value
367 static int32_t PIOS_DSM_Get(uint32_t rcvr_id
, uint8_t channel
)
369 struct pios_dsm_dev
*dsm_dev
= (struct pios_dsm_dev
*)rcvr_id
;
371 if (!PIOS_DSM_Validate(dsm_dev
)) {
372 return PIOS_RCVR_INVALID
;
375 /* return error if channel is not available */
376 if (channel
>= PIOS_DSM_NUM_INPUTS
) {
377 return PIOS_RCVR_INVALID
;
380 /* may also be PIOS_RCVR_TIMEOUT set by other function */
381 return dsm_dev
->state
.channel_data
[channel
];
385 * Input data supervisor is called periodically and provides
386 * two functions: frame syncing and failsafe triggering.
388 * DSM frames come at 11ms or 22ms rate at 115200bps.
389 * RTC timer is running at 625Hz (1.6ms). So with divider 5 it gives
390 * 8ms pause between frames which is good for both DSM frame rates.
392 * Data receive function must clear the receive_timer to confirm new
393 * data reception. If no new data received in 100ms, we must call the
394 * failsafe function which clears all channels.
396 static void PIOS_DSM_Supervisor(uint32_t dsm_id
)
398 struct pios_dsm_dev
*dsm_dev
= (struct pios_dsm_dev
*)dsm_id
;
400 bool valid
= PIOS_DSM_Validate(dsm_dev
);
404 struct pios_dsm_state
*state
= &(dsm_dev
->state
);
406 /* waiting for new frame if no bytes were received in 8ms */
407 if (++state
->receive_timer
> 4) {
408 state
->frame_found
= 1;
409 state
->byte_count
= 0;
410 state
->receive_timer
= 0;
413 /* activate failsafe if no frames have arrived in 102.4ms */
414 if (++state
->failsafe_timer
> 64) {
415 PIOS_DSM_ResetChannels(dsm_dev
);
416 state
->failsafe_timer
= 0;
420 static uint8_t PIOS_DSM_Quality_Get(uint32_t dsm_id
)
422 struct pios_dsm_dev
*dsm_dev
= (struct pios_dsm_dev
*)dsm_id
;
424 bool valid
= PIOS_DSM_Validate(dsm_dev
);
428 struct pios_dsm_state
*state
= &(dsm_dev
->state
);
430 return (uint8_t)(state
->quality
+ 0.5f
);
433 #endif /* PIOS_INCLUDE_DSM */