dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_hsum.c
Go to the documentation of this file.
1 
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, see <http://www.gnu.org/licenses/>
24  */
25 /* Project Includes */
26 #include "pios_hsum_priv.h"
27 
28 #if defined(PIOS_INCLUDE_HSUM)
29 
30 #if !defined(PIOS_INCLUDE_RTC)
31 #error PIOS_INCLUDE_RTC must be used to use HSUM
32 #endif
33 
77 /* HSUM frame size and contents definitions */
78 #define HSUM_HEADER_LENGTH 3
79 #define HSUM_CRC_LENGTH 2
80 #define HSUM_MAX_CHANNELS_PER_FRAME 32
81 #define HSUM_OVERHEAD_LENGTH (HSUM_HEADER_LENGTH+HSUM_CRC_LENGTH)
82 #define HSUM_MAX_FRAME_LENGTH (HSUM_MAX_CHANNELS_PER_FRAME*2+HSUM_OVERHEAD_LENGTH)
83 
84 #define HSUM_GRAUPNER_ID 0xA8
85 #define HSUM_STATUS_LIVING_SUMH 0x00
86 #define HSUM_STATUS_LIVING_SUMD 0x01
87 #define HSUM_STATUS_FAILSAFE 0x81
88 
89 /* Forward Declarations */
90 static int32_t PIOS_HSUM_Get(uintptr_t rcvr_id, uint8_t channel);
91 static uint16_t PIOS_HSUM_RxInCallback(uintptr_t context,
92  uint8_t *buf,
93  uint16_t buf_len,
94  uint16_t *headroom,
95  bool *need_yield);
96 static void PIOS_HSUM_Supervisor(uintptr_t hsum_id);
97 
98 /* Local Variables */
100  .read = PIOS_HSUM_Get,
101 };
102 
103 enum pios_hsum_dev_magic {
104  PIOS_HSUM_DEV_MAGIC = 0x4853554D,
105 };
106 
107 struct pios_hsum_state {
108  uint16_t channel_data[PIOS_HSUM_NUM_INPUTS];
109  uint8_t received_data[HSUM_MAX_FRAME_LENGTH];
110  uint8_t receive_timer;
111  uint8_t failsafe_timer;
112  uint8_t frame_found;
113  uint8_t tx_connected;
114  uint8_t byte_count;
115  uint8_t frame_length;
116 };
117 
118 struct pios_hsum_dev {
119  enum pios_hsum_dev_magic magic;
120  const struct pios_hsum_cfg *cfg;
121  enum pios_hsum_proto proto;
122  struct pios_hsum_state state;
123 };
124 
125 /* Allocate HSUM device descriptor */
126 static struct pios_hsum_dev *PIOS_HSUM_Alloc(void)
127 {
128  struct pios_hsum_dev *hsum_dev;
129 
130  hsum_dev = (struct pios_hsum_dev *)PIOS_malloc(sizeof(*hsum_dev));
131  if (!hsum_dev)
132  return NULL;
133 
134  hsum_dev->magic = PIOS_HSUM_DEV_MAGIC;
135  return hsum_dev;
136 }
137 
138 /* Validate HSUM device descriptor */
139 static bool PIOS_HSUM_Validate(struct pios_hsum_dev *hsum_dev)
140 {
141  return (hsum_dev->magic == PIOS_HSUM_DEV_MAGIC);
142 }
143 
144 /* Reset channels in case of lost signal or explicit failsafe receiver flag */
145 static void PIOS_HSUM_ResetChannels(struct pios_hsum_dev *hsum_dev)
146 {
147  struct pios_hsum_state *state = &(hsum_dev->state);
148  for (int i = 0; i < PIOS_HSUM_NUM_INPUTS; i++) {
149  state->channel_data[i] = PIOS_RCVR_TIMEOUT;
150  }
151 }
152 
153 /* Reset HSUM receiver state */
154 static void PIOS_HSUM_ResetState(struct pios_hsum_dev *hsum_dev)
155 {
156  struct pios_hsum_state *state = &(hsum_dev->state);
157  state->receive_timer = 0;
158  state->failsafe_timer = 0;
159  state->frame_found = 0;
160  state->tx_connected = 0;
161  PIOS_HSUM_ResetChannels(hsum_dev);
162 }
163 
169 static int PIOS_HSUM_UnrollChannels(struct pios_hsum_dev *hsum_dev)
170 {
171  struct pios_hsum_state *state = &(hsum_dev->state);
172 
173  /* check the header and crc for a valid HoTT SUM stream */
174  uint8_t vendor = state->received_data[0];
175  uint8_t status = state->received_data[1];
176  if (vendor != HSUM_GRAUPNER_ID)
177  /* Graupner ID was expected */
178  goto stream_error;
179 
180  switch (status) {
181  case HSUM_STATUS_LIVING_SUMH:
182  case HSUM_STATUS_LIVING_SUMD:
183  case HSUM_STATUS_FAILSAFE:
184  /* check crc before processing */
185  if (hsum_dev->proto == PIOS_HSUM_PROTO_SUMD) {
186  /* SUMD has 16 bit CCITT CRC */
187  uint16_t crc = 0;
188  uint8_t *s = &(state->received_data[0]);
189  int len = state->byte_count - 2;
190  for (int n = 0; n < len; n++) {
191  crc ^= (uint16_t)s[n] << 8;
192  for (int i = 0; i < 8; i++)
193  crc = (crc & 0x8000) ? (crc << 1) ^ 0x1021 : (crc << 1);
194  }
195  if (crc ^ (((uint16_t)s[len] << 8) | s[len + 1]))
196  /* wrong crc checksum found */
197  goto stream_error;
198  }
199  if (hsum_dev->proto == PIOS_HSUM_PROTO_SUMH) {
200  /* SUMH has only 8 bit added CRC */
201  uint8_t crc = 0;
202  uint8_t *s = &(state->received_data[0]);
203  int len = state->byte_count - 1;
204  for (int n = 0; n < len; n++)
205  crc += s[n];
206  if (crc ^ s[len])
207  /* wrong crc checksum found */
208  goto stream_error;
209  }
210  /* check for a living connect */
211  state->tx_connected |= (status != HSUM_STATUS_FAILSAFE);
212  break;
213  default:
214  /* wrong header format */
215  goto stream_error;
216  }
217 
218  /* check initial connection since reset or timeout */
219  if (!(state->tx_connected)) {
220  /* these are failsafe data without a first connect. ignore it */
221  PIOS_HSUM_ResetChannels(hsum_dev);
222  return 0;
223  }
224 
225  /* unroll channels */
226  uint8_t n_channels = state->received_data[2];
227  uint8_t *s = &(state->received_data[3]);
228  uint16_t word;
229 
230  for (int i = 0; i < HSUM_MAX_CHANNELS_PER_FRAME; i++) {
231  if (i < n_channels) {
232  word = ((uint16_t)s[0] << 8) | s[1];
233  s += sizeof(uint16_t);
234  /* save the channel value */
235  if (i < PIOS_HSUM_NUM_INPUTS) {
236  state->channel_data[i] = word;
237  }
238  } else
239  /* this channel was not received */
240  state->channel_data[i] = PIOS_RCVR_INVALID;
241  }
242 
244 
245  /* all channels processed */
246  return 0;
247 
248 stream_error:
249  /* either SUMD selected with SUMH stream found, or vice-versa */
250  return -1;
251 }
252 
253 /* Update decoder state processing input byte from the HoTT stream */
254 static void PIOS_HSUM_UpdateState(struct pios_hsum_dev *hsum_dev, uint8_t byte)
255 {
256  struct pios_hsum_state *state = &(hsum_dev->state);
257  if (state->frame_found) {
258  /* receiving the data frame */
259  if (state->byte_count < HSUM_MAX_FRAME_LENGTH) {
260  /* store next byte */
261  state->received_data[state->byte_count++] = byte;
262  if (state->byte_count == HSUM_HEADER_LENGTH) {
263  /* 3rd byte contains the number of channels. calculate frame size */
264  state->frame_length = HSUM_OVERHEAD_LENGTH + 2 * byte;
265  }
266  if (state->byte_count == state->frame_length) {
267  /* full frame received - process and wait for new one */
268  if (!PIOS_HSUM_UnrollChannels(hsum_dev))
269  /* data looking good */
270  state->failsafe_timer = 0;
271  /* prepare for the next frame */
272  state->frame_found = 0;
273  }
274  }
275  }
276 }
277 
278 /* Initialise HoTT receiver interface */
279 int32_t PIOS_HSUM_Init(uintptr_t *hsum_id,
280  const struct pios_com_driver *driver,
281  uintptr_t lower_id,
282  enum pios_hsum_proto proto)
283 {
284  PIOS_DEBUG_Assert(hsum_id);
285  PIOS_DEBUG_Assert(driver);
286 
287  struct pios_hsum_dev *hsum_dev;
288 
289  hsum_dev = (struct pios_hsum_dev *)PIOS_HSUM_Alloc();
290  if (!hsum_dev)
291  return -1;
292 
293  /* Bind the configuration to the device instance */
294  hsum_dev->proto = proto;
295 
296  PIOS_HSUM_ResetState(hsum_dev);
297 
298  *hsum_id = (uintptr_t)hsum_dev;
299 
300  /* Set comm driver callback */
301  (driver->bind_rx_cb)(lower_id, PIOS_HSUM_RxInCallback, *hsum_id);
302 
303  if (!PIOS_RTC_RegisterTickCallback(PIOS_HSUM_Supervisor, *hsum_id)) {
305  }
306 
307  return 0;
308 }
309 
310 /* Comm byte received callback */
311 static uint16_t PIOS_HSUM_RxInCallback(uintptr_t context,
312  uint8_t *buf,
313  uint16_t buf_len,
314  uint16_t *headroom,
315  bool *need_yield)
316 {
317  struct pios_hsum_dev *hsum_dev = (struct pios_hsum_dev *)context;
318 
319  bool valid = PIOS_HSUM_Validate(hsum_dev);
320  PIOS_Assert(valid);
321 
322  /* process byte(s) and clear receive timer */
323  for (uint8_t i = 0; i < buf_len; i++) {
324  PIOS_HSUM_UpdateState(hsum_dev, buf[i]);
325  hsum_dev->state.receive_timer = 0;
326  }
327 
328  /* Always signal that we can accept more data */
329  if (headroom)
330  *headroom = HSUM_MAX_FRAME_LENGTH;
331 
332  /* We never need a yield */
333  *need_yield = false;
334 
335  /* Always indicate that all bytes were consumed */
336  return buf_len;
337 }
338 
346 static int32_t PIOS_HSUM_Get(uintptr_t rcvr_id, uint8_t channel)
347 {
348  struct pios_hsum_dev *hsum_dev = (struct pios_hsum_dev *)rcvr_id;
349 
350  if (!PIOS_HSUM_Validate(hsum_dev))
351  return PIOS_RCVR_INVALID;
352 
353  /* return error if channel is not available */
354  if (channel >= PIOS_HSUM_NUM_INPUTS)
355  return PIOS_RCVR_INVALID;
356 
357  /* may also be PIOS_RCVR_TIMEOUT set by other function */
358  return hsum_dev->state.channel_data[channel];
359 }
360 
373 static void PIOS_HSUM_Supervisor(uintptr_t hsum_id)
374 {
375  struct pios_hsum_dev *hsum_dev = (struct pios_hsum_dev *)hsum_id;
376 
377  bool valid = PIOS_HSUM_Validate(hsum_dev);
378  PIOS_Assert(valid);
379 
380  struct pios_hsum_state *state = &(hsum_dev->state);
381 
382  /* waiting for new frame if no bytes were received in 8ms */
383  if (++state->receive_timer > 4) {
384  state->frame_found = 1;
385  state->byte_count = 0;
386  state->receive_timer = 0;
387  state->frame_length = HSUM_MAX_FRAME_LENGTH;
388  }
389 
390  /* activate failsafe if no frames have arrived in ~250ms */
391  if (++state->failsafe_timer > 156) {
392  PIOS_HSUM_ResetChannels(hsum_dev);
393  state->failsafe_timer = 0;
394  state->tx_connected = 0;
395  }
396 }
397 
398 #endif /* PIOS_INCLUDE_HSUM */
399 
union @12 crc
const struct pios_rcvr_driver pios_hsum_rcvr_driver
int32_t(* read)(uintptr_t id, uint8_t channel)
Definition: pios_rcvr.h:35
#define PIOS_HSUM_NUM_INPUTS
Definition: pios_board.h:199
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
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
int16_t status
Definition: main.c:61
pios_hsum_proto
uint8_t i
Definition: msp_messages.h:97
uint32_t magic
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
enum arena_state state
int32_t PIOS_HSUM_Init(uintptr_t *hsum_id, const struct pios_com_driver *driver, uintptr_t lower_id, enum pios_hsum_proto proto)