dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_dsm.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 /* Project Includes */
32 #include "pios.h"
33 #include "pios_dsm_priv.h"
34 
35 #if defined(PIOS_INCLUDE_DSM)
36 
37 #if !defined(PIOS_INCLUDE_RTC)
38 #error PIOS_INCLUDE_RTC must be used to use DSM
39 #endif
40 
41 static uint16_t PIOS_DSM_RxInCallback(uintptr_t context,
42  uint8_t *buf,
43  uint16_t buf_len,
44  uint16_t *headroom,
45  bool *need_yield);
46 static void PIOS_DSM_Supervisor(uintptr_t dsm_id);
47 
48 #if defined(PIOS_INCLUDE_RCVR)
49 static int32_t PIOS_DSM_Get(uintptr_t rcvr_id, uint8_t channel);
50 
52  .read = PIOS_DSM_Get,
53 };
54 #endif
55 
56 enum dsm_resolution {
57  DSM_UNKNOWN, DSM_10BIT, DSM_11BIT
58 };
59 
60 enum pios_dsm_dev_magic {
61  PIOS_DSM_DEV_MAGIC = 0x44534d78,
62 };
63 
64 struct pios_dsm_state {
65  uint16_t channel_data[PIOS_DSM_NUM_INPUTS];
66  uint8_t received_data[DSM_FRAME_LENGTH];
67  uint8_t receive_timer;
68  uint8_t failsafe_timer;
69  uint8_t frame_found;
70  uint8_t byte_count;
71 #ifdef DSM_LOST_FRAME_COUNTER
72  uint8_t frames_lost_last;
73  uint16_t frames_lost;
74 #endif
75 };
76 
77 struct pios_dsm_dev {
78  enum pios_dsm_dev_magic magic;
79  const struct pios_dsm_cfg *cfg;
80  struct pios_dsm_state state;
81  enum dsm_resolution resolution;
82 };
83 
84 /* Allocate DSM device descriptor */
85 static struct pios_dsm_dev *PIOS_DSM_Alloc(void)
86 {
87  struct pios_dsm_dev *dsm_dev;
88 
89  dsm_dev = (struct pios_dsm_dev *)PIOS_malloc(sizeof(*dsm_dev));
90  if (!dsm_dev)
91  return NULL;
92 
93  dsm_dev->resolution = DSM_UNKNOWN;
94  dsm_dev->magic = PIOS_DSM_DEV_MAGIC;
95  return dsm_dev;
96 }
97 
98 /* Validate DSM device descriptor */
99 static bool PIOS_DSM_Validate(struct pios_dsm_dev *dsm_dev)
100 {
101  return (dsm_dev->magic == PIOS_DSM_DEV_MAGIC);
102 }
103 
104 /* Try to bind DSMx satellite using specified number of pulses */
105 static void PIOS_DSM_Bind(struct pios_dsm_dev *dsm_dev, uint8_t num_pulses)
106 {
107 #ifndef FLIGHT_POSIX
108  const struct pios_dsm_cfg *cfg = dsm_dev->cfg;
109 
110  GPIO_InitTypeDef GPIO_InitStructure = cfg->bind.init;
111  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
112 
113  /* just to limit bind pulses */
114  if (num_pulses > 10)
115  num_pulses = 10;
116 
117  GPIO_Init(cfg->bind.gpio, (GPIO_InitTypeDef*)&cfg->bind.init);
118 
119  /* RX line, set high */
120  GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin);
121 
122  /* on CC works up to 140ms, guess bind window is around 20-140ms after power up */
123  while (((float) PIOS_DELAY_GetRaw() / (float) PIOS_SYSCLK) < 0.02f);
124 
125  for (int i = 0; i < num_pulses ; i++) {
126  /* RX line, drive low for 120us */
127  GPIO_ResetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin);
128  PIOS_DELAY_WaituS(120);
129  /* RX line, drive high for 120us */
130  GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin);
131  PIOS_DELAY_WaituS(120);
132  }
133  /* RX line, set input and wait for data */
134  GPIO_Init(cfg->bind.gpio, &GPIO_InitStructure);
135 #else
136  (void) dsm_dev; (void) num_pulses;
137 #endif
138 }
139 
140 /* Reset channels in case of lost signal or explicit failsafe receiver flag */
141 static void PIOS_DSM_ResetChannels(struct pios_dsm_dev *dsm_dev)
142 {
143  struct pios_dsm_state *state = &(dsm_dev->state);
144  for (int i = 0; i < PIOS_DSM_NUM_INPUTS; i++) {
145  state->channel_data[i] = PIOS_RCVR_TIMEOUT;
146  }
147 }
148 
149 /* Reset DSM receiver state */
150 static void PIOS_DSM_ResetState(struct pios_dsm_dev *dsm_dev)
151 {
152  struct pios_dsm_state *state = &(dsm_dev->state);
153  state->receive_timer = 0;
154  state->failsafe_timer = 0;
155  state->frame_found = 0;
156 #ifdef DSM_LOST_FRAME_COUNTER
157  state->frames_lost_last = 0;
158  state->frames_lost = 0;
159 #endif
160  PIOS_DSM_ResetChannels(dsm_dev);
161 }
162 
171 enum dsm_resolution PIOS_DSM_DetectResolution(uint8_t *packet)
172 {
173  uint8_t channel0, channel1;
174  uint16_t word0, word1;
175  bool bit_10, bit_11;
176 
177  // Form data words
178  word0 = ((uint16_t)packet[2] << 8) | packet[3];
179  word1 = ((uint16_t)packet[4] << 8) | packet[5];
180 
181  // Can't detect on the second data packet
182  if (word0 & DSM_2ND_FRAME_MASK)
183  return DSM_UNKNOWN;
184 
185  // If transmitter information byte != 0, master satellite.
186  // Interpret the value for type.
187  switch (packet[1]) {
188  case 0xb2: // 11ms 2048 DSMX
189  case 0xa2: // 22ms 2048 DSMX
190  case 0x12: // 11ms 2048 DSM2
191  return DSM_11BIT;
192  case 0x01: // 22ms 1024 DSM2
193  return DSM_10BIT;
194  default:
195  break;
196  }
197 
198  // Check for 10 bit
199  channel0 = (word0 >> 10) & 0x0f;
200  channel1 = (word1 >> 10) & 0x0f;
201  bit_10 = (channel0 == 1) && (channel1 == 5);
202 
203  // Check for 11 bit
204  channel0 = (word0 >> 11) & 0x0f;
205  channel1 = (word1 >> 11) & 0x0f;
206  bit_11 = (channel0 == 1) && (channel1 == 5);
207 
208  if (bit_10 && !bit_11)
209  return DSM_10BIT;
210 
211  if (bit_11 && !bit_10)
212  return DSM_11BIT;
213 
214  return DSM_UNKNOWN;
215 }
216 
220 int PIOS_DSM_UnrollChannels(struct pios_dsm_dev *dsm_dev)
221 {
222  struct pios_dsm_state *state = &(dsm_dev->state);
223  /* Fix resolution for detection. */
224 
225 #ifdef DSM_LOST_FRAME_COUNTER
226  /* increment the lost frame counter */
227  uint8_t frames_lost = state->received_data[0];
228  state->frames_lost += (frames_lost - state->frames_lost_last);
229  state->frames_lost_last = frames_lost;
230 #endif
231 
232  // If no stream type has yet been detected, then try to probe for it
233  // this should only happen once per power cycle
234  if (dsm_dev->resolution == DSM_UNKNOWN) {
235  dsm_dev->resolution = PIOS_DSM_DetectResolution(state->received_data);
236  }
237 
238  /* Stream type still not detected */
239  if (dsm_dev->resolution == DSM_UNKNOWN) {
240  return -2;
241  }
242  uint8_t resolution = (dsm_dev->resolution == DSM_10BIT) ? 10 : 11;
243  uint16_t mask = (dsm_dev->resolution == DSM_10BIT) ? 0x03ff : 0x07ff;
244 
245  /* unroll channels */
246  uint8_t *s = &(state->received_data[2]);
247 
248  for (int i = 0; i < DSM_CHANNELS_PER_FRAME; i++) {
249  uint16_t word = ((uint16_t)s[0] << 8) | s[1];
250  s += 2;
251 
252  /* skip empty channel slot */
253  if (word == 0xffff)
254  continue;
255 
256  /* minimal data validation */
257  if ((i > 0) && (word & DSM_2ND_FRAME_MASK)) {
258  /* invalid frame data, ignore rest of the frame */
259  goto stream_error;
260  }
261 
262  /* extract and save the channel value */
263  uint8_t channel_num = (word >> resolution) & 0x0f;
264  state->channel_data[channel_num] = (word & mask);
265  }
266 
267 #ifdef DSM_LOST_FRAME_COUNTER
268  /* put lost frames counter into the last channel for debugging */
269  state->channel_data[PIOS_DSM_NUM_INPUTS-1] = state->frames_lost;
270 #endif
271 
272  /* all channels processed */
273  return 0;
274 
275 stream_error:
276  /* either DSM2 selected with DSMX stream found, or vice-versa */
277  return -1;
278 }
279 
280 /* Update decoder state processing input byte from the DSMx stream */
281 static void PIOS_DSM_UpdateState(struct pios_dsm_dev *dsm_dev, uint8_t byte)
282 {
283  struct pios_dsm_state *state = &(dsm_dev->state);
284  if (state->frame_found) {
285  /* receiving the data frame */
286  if (state->byte_count < DSM_FRAME_LENGTH) {
287  /* store next byte */
288  state->received_data[state->byte_count++] = byte;
289  if (state->byte_count == DSM_FRAME_LENGTH) {
290  /* full frame received - process and wait for new one */
291  if (!PIOS_DSM_UnrollChannels(dsm_dev)) {
292  /* data looking good */
293  state->failsafe_timer = 0;
294 #ifdef PIOS_INCLUDE_RCVR
296 #endif
297  }
298 
299  /* prepare for the next frame */
300  state->frame_found = 0;
301  }
302  }
303  }
304 }
305 
306 /* Initialise DSM receiver interface */
307 int32_t PIOS_DSM_Init(uintptr_t *dsm_id,
308  const struct pios_dsm_cfg *cfg,
309  const struct pios_com_driver *driver,
310  uintptr_t lower_id,
311  HwSharedDSMxModeOptions mode)
312 {
313  PIOS_DEBUG_Assert(dsm_id);
314  PIOS_DEBUG_Assert(cfg);
315  PIOS_DEBUG_Assert(driver);
316 
317  struct pios_dsm_dev *dsm_dev;
318 
319  dsm_dev = (struct pios_dsm_dev *)PIOS_DSM_Alloc();
320  if (!dsm_dev)
321  return -1;
322 
323  /* Bind the configuration to the device instance */
324  dsm_dev->cfg = cfg;
325 
326  uint8_t num_pulses = 0;
327 
328  // check user settings to determine which resolution mode to use
329  // if invalid mode selected, bail
330  if (mode > HWSHARED_DSMXMODE_BIND10PULSES)
331  return -1;
332 
333  // set resolution or bind mode depending on user selection
334  switch (mode)
335  {
336  case HWSHARED_DSMXMODE_AUTODETECT:
337  dsm_dev->resolution = DSM_UNKNOWN;
338  break;
339  case HWSHARED_DSMXMODE_FORCE10BIT:
340  dsm_dev->resolution = DSM_10BIT;
341  break;
342  case HWSHARED_DSMXMODE_FORCE11BIT:
343  dsm_dev->resolution = DSM_11BIT;
344  break;
345  case HWSHARED_DSMXMODE_BIND3PULSES:
346  case HWSHARED_DSMXMODE_BIND4PULSES:
347  case HWSHARED_DSMXMODE_BIND5PULSES:
348  case HWSHARED_DSMXMODE_BIND6PULSES:
349  case HWSHARED_DSMXMODE_BIND7PULSES:
350  case HWSHARED_DSMXMODE_BIND8PULSES:
351  case HWSHARED_DSMXMODE_BIND9PULSES:
352  case HWSHARED_DSMXMODE_BIND10PULSES:
353  num_pulses = 3 + mode - HWSHARED_DSMXMODE_BIND3PULSES;
354  break;
355  }
356 
357  /* Bind the receiver if requested */
358  if (num_pulses > 0)
359  PIOS_DSM_Bind(dsm_dev, num_pulses);
360 
361  PIOS_DSM_ResetState(dsm_dev);
362 
363  *dsm_id = (uintptr_t)dsm_dev;
364 
365  /* Set comm driver callback */
366  (driver->bind_rx_cb)(lower_id, PIOS_DSM_RxInCallback, *dsm_id);
367 
368  if (!PIOS_RTC_RegisterTickCallback(PIOS_DSM_Supervisor, *dsm_id)) {
370  }
371 
372  return 0;
373 }
374 
375 /* Comm byte received callback */
376 static uint16_t PIOS_DSM_RxInCallback(uintptr_t context,
377  uint8_t *buf,
378  uint16_t buf_len,
379  uint16_t *headroom,
380  bool *need_yield)
381 {
382  struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)context;
383 
384  bool valid = PIOS_DSM_Validate(dsm_dev);
385  PIOS_Assert(valid);
386 
387  /* process byte(s) and clear receive timer */
388  for (uint8_t i = 0; i < buf_len; i++) {
389  PIOS_DSM_UpdateState(dsm_dev, buf[i]);
390  dsm_dev->state.receive_timer = 0;
391  }
392 
393  /* Always signal that we can accept another byte */
394  if (headroom)
395  *headroom = DSM_FRAME_LENGTH;
396 
397  /* We never need a yield */
398  *need_yield = false;
399 
400  /* Always indicate that all bytes were consumed */
401  return buf_len;
402 }
403 
411 #if defined(PIOS_INCLUDE_RCVR)
412 static int32_t PIOS_DSM_Get(uintptr_t rcvr_id, uint8_t channel)
413 {
414  struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)rcvr_id;
415 
416  if (!PIOS_DSM_Validate(dsm_dev))
417  return PIOS_RCVR_INVALID;
418 
419  /* return error if channel is not available */
420  if (channel >= PIOS_DSM_NUM_INPUTS)
421  return PIOS_RCVR_INVALID;
422 
423  /* may also be PIOS_RCVR_TIMEOUT set by other function */
424  return dsm_dev->state.channel_data[channel];
425 }
426 #endif
427 
440 static void PIOS_DSM_Supervisor(uintptr_t dsm_id)
441 {
442  struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)dsm_id;
443 
444  bool valid = PIOS_DSM_Validate(dsm_dev);
445  PIOS_Assert(valid);
446 
447  struct pios_dsm_state *state = &(dsm_dev->state);
448 
449  /* waiting for new frame if no bytes were received in 8ms */
450  if (++state->receive_timer > 4) {
451  state->frame_found = 1;
452  state->byte_count = 0;
453  state->receive_timer = 0;
454  }
455 
456  /* activate failsafe if no frames have arrived in ~250ms */
457  if (++state->failsafe_timer > 156) {
458  PIOS_DSM_ResetChannels(dsm_dev);
459  state->failsafe_timer = 0;
460  }
461 }
462 
463 #endif /* PIOS_INCLUDE_DSM */
464 
#define DSM_CHANNELS_PER_FRAME
int32_t(* read)(uintptr_t id, uint8_t channel)
Definition: pios_rcvr.h:35
int32_t PIOS_DSM_Init(uintptr_t *dsm_id, const struct pios_dsm_cfg *cfg, const struct pios_com_driver *driver, uintptr_t lower_id, HwSharedDSMxModeOptions mode)
Main PiOS header to include all the compiled in PiOS options.
GPIO_InitTypeDef init
Definition: pios_stm32.h:61
struct stm32_gpio bind
GPIO_TypeDef * gpio
Definition: pios_stm32.h:60
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
#define DSM_2ND_FRAME_MASK
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
bool PIOS_RTC_RegisterTickCallback(void(*fn)(uintptr_t id), uintptr_t data)
Definition: pios_delay.c:185
void PIOS_RCVR_ActiveFromISR()
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
Spektrum/JR DSMx satellite receiver private structures.
uint8_t i
Definition: msp_messages.h:97
enum channel_mode mode
Definition: pios_servo.c:58
uint32_t magic
tuple f
Definition: px_mkfw.py:81
#define PIOS_DSM_NUM_INPUTS
Definition: pios_board.h:193
const struct pios_rcvr_driver pios_dsm_rcvr_driver
#define DSM_FRAME_LENGTH
#define PIOS_SYSCLK
Definition: pios_board.h:143
void(* bind_rx_cb)(uintptr_t id, pios_com_callback rx_in_cb, uintptr_t context)
Definition: pios_com.h:47
#define PIOS_Assert(test)
Definition: pios_debug.h:52
int32_t PIOS_DELAY_WaituS(uint32_t uS)
Definition: pios_delay.c:116
enum arena_state state
uint32_t PIOS_DELAY_GetRaw()
Get the raw delay timer, useful for timing.
Definition: pios_delay.c:153