libsbp  v2.4.7
sbp.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011-2014 Swift Navigation Inc.
3  * Contact: Fergus Noble <fergus@swift-nav.com>
4  *
5  * This source is subject to the license found in the file 'LICENSE' which must
6  * be be distributed together with this source. All other rights reserved.
7  *
8  * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
9  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 #include "libsbp/edc.h"
14 #include "libsbp/sbp.h"
15 
16 #define SBP_PREAMBLE 0x55
17 
163 {
164  /* Check our callback function pointer isn't NULL. */
165  if (cb == 0)
166  return SBP_NULL_ERROR;
167 
168  /* Check our callback node pointer isn't NULL. */
169  if (node == 0)
170  return SBP_NULL_ERROR;
171 
172  for (sbp_msg_callbacks_node_t *n = s->sbp_msg_callbacks_head; n; n = n->next)
173  if ((n == node) ||
174  ((n->cb == cb) && (n->msg_type == msg_type) && (n->context == context)))
175  return SBP_CALLBACK_ERROR;
176 
177  /* Fill in our new sbp_msg_callback_node_t. */
178  node->msg_type = msg_type;
179  node->cb = cb;
180  node->context = context;
181  /* The next pointer is set to NULL, i.e. this
182  * will be the new end of the linked list.
183  */
184  node->next = 0;
185 
186  /* If our linked list is empty then just
187  * add the new node to the start.
188  */
189  if (s->sbp_msg_callbacks_head == 0) {
190  s->sbp_msg_callbacks_head = node;
191  return SBP_OK;
192  }
193 
194  /* Find the tail of our linked list and
195  * add our new node to the end.
196  */
198  while (p->next)
199  p = p->next;
200 
201  p->next = node;
202 
203  return SBP_OK;
204 }
205 
213 {
215 
216  if (s->sbp_msg_callbacks_head == node) {
217  s->sbp_msg_callbacks_head = node->next;
218  return SBP_OK;
219  } else {
220  for (n = s->sbp_msg_callbacks_head; n; n = n->next) {
221  if (n->next == node) {
222  n->next = node->next;
223  return SBP_OK;
224  }
225  }
226  }
227  return SBP_CALLBACK_ERROR;
228 }
229 
234 {
235  /* Reset the head of the callbacks list to NULL. */
236  s->sbp_msg_callbacks_head = 0;
237 }
238 
247 {
248  s->state = WAITING;
249 
250  /* Set the IO context pointer, passed to read and write functions, to NULL. */
251  s->io_context = 0;
252 
253  /* Clear the callbacks, if any, currently in s */
255 }
256 
257 
264 void sbp_state_set_io_context(sbp_state_t *s, void *context)
265 {
266  s->io_context = context;
267 }
268 
308 s8 sbp_process(sbp_state_t *s, s32 (*read)(u8 *buff, u32 n, void *context))
309 {
310  /* Sanity checks */
311  if ((0 == s) || (0 == read)) {
312  return SBP_NULL_ERROR;
313  }
314 
315  u8 temp;
316  u16 crc;
317  s32 rd = 0;
318 
319  switch (s->state) {
320  case WAITING:
321  rd = (*read)(&temp, 1, s->io_context);
322  if (0 > rd) return SBP_READ_ERROR;
323  if (1 == rd)
324  if (temp == SBP_PREAMBLE) {
325  s->n_read = 0;
326  s->state = GET_TYPE;
327  }
328  break;
329 
330  case GET_TYPE:
331  rd = (*read)((u8*)&(s->msg_type) + s->n_read, 2-s->n_read, s->io_context);
332  if (0 > rd) return SBP_READ_ERROR;
333  s->n_read += rd;
334  if (s->n_read >= 2) {
335  /* Swap bytes to little endian. */
336  s->n_read = 0;
337  s->state = GET_SENDER;
338  }
339  break;
340 
341  case GET_SENDER:
342  rd = (*read)((u8*)&(s->sender_id) + s->n_read, 2-s->n_read, s->io_context);
343  if (0 > rd) return SBP_READ_ERROR;
344  s->n_read += rd;
345  if (s->n_read >= 2) {
346  /* Swap bytes to little endian. */
347  s->state = GET_LEN;
348  }
349  break;
350 
351  case GET_LEN:
352  rd = (*read)(&(s->msg_len), 1, s->io_context);
353  if (0 > rd) return SBP_READ_ERROR;
354  if (1 == rd) {
355  s->n_read = 0;
356  s->state = GET_MSG;
357  }
358  break;
359 
360  case GET_MSG:
361  /* Not received whole message yet, try and read some more. */
362  rd = (*read)(&(s->msg_buff[s->n_read]), s->msg_len - s->n_read, s->io_context);
363  if (0 > rd) return SBP_READ_ERROR;
364  s->n_read += rd;
365  if (s->msg_len - s->n_read <= 0) {
366  s->n_read = 0;
367  s->state = GET_CRC;
368  }
369  break;
370 
371  case GET_CRC:
372  rd = (*read)((u8*)&(s->crc) + s->n_read, 2-s->n_read, s->io_context);
373  if (0 > rd) return SBP_READ_ERROR;
374  s->n_read += rd;
375  if (s->n_read >= 2) {
376  s->state = WAITING;
377 
378  /* Swap bytes to little endian. */
379  crc = crc16_ccitt((u8*)&(s->msg_type), 2, 0);
380  crc = crc16_ccitt((u8*)&(s->sender_id), 2, crc);
381  crc = crc16_ccitt(&(s->msg_len), 1, crc);
382  crc = crc16_ccitt(s->msg_buff, s->msg_len, crc);
383  if (s->crc == crc) {
384 
385  /* Message complete, process it. */
386  s8 ret = sbp_process_payload(s, s->sender_id, s->msg_type, s->msg_len,
387  s->msg_buff);
388  return ret;
389  } else {
390  return SBP_CRC_ERROR;
391  }
392  }
393  break;
394 
395  default:
396  s->state = WAITING;
397  break;
398  }
399 
400  return SBP_OK;
401 }
402 
416 s8 sbp_process_payload(sbp_state_t *s, u16 sender_id, u16 msg_type, u8 msg_len,
417  u8 payload[]) {
420  for (node = s->sbp_msg_callbacks_head; node; node = node->next) {
421  if (node->msg_type == msg_type) {
422  (*node->cb)(sender_id, msg_len, payload, node->context);
424  }
425  }
426  return ret;
427 }
428 
429 
459 s8 sbp_send_message(sbp_state_t *s, u16 msg_type, u16 sender_id, u8 len, u8 *payload,
460  s32 (*write)(u8 *buff, u32 n, void *context))
461 {
462  /* Check our payload data pointer isn't NULL unless len = 0. */
463  if (len != 0 && payload == 0)
464  return SBP_NULL_ERROR;
465 
466  /* Check our write function pointer isn't NULL. */
467  if ((0 == s) || (0 == write))
468  return SBP_NULL_ERROR;
469 
470  u16 crc;
471  s32 wr = 0;
472 
473  u8 preamble = SBP_PREAMBLE;
474  wr = (*write)(&preamble, 1, s->io_context);
475  if (0 > wr) return SBP_WRITE_ERROR;
476  if (wr != 1) return SBP_SEND_ERROR;
477 
478  wr = (*write)((u8*)&msg_type, 2, s->io_context);
479  if (0 > wr) return SBP_WRITE_ERROR;
480  if (wr != 2) return SBP_SEND_ERROR;
481 
482  wr = (*write)((u8*)&sender_id, 2, s->io_context);
483  if (0 > wr) return SBP_WRITE_ERROR;
484  if (wr != 2) return SBP_SEND_ERROR;
485 
486  wr = (*write)(&len, 1, s->io_context);
487  if (0 > wr) return SBP_WRITE_ERROR;
488  if (wr != 1) return SBP_SEND_ERROR;
489 
490  if (len > 0) {
491  wr = (*write)(payload, len, s->io_context);
492  if (0 > wr) return SBP_WRITE_ERROR;
493  if (wr != len) return SBP_SEND_ERROR;
494  }
495 
496  crc = crc16_ccitt((u8*)&(msg_type), 2, 0);
497  crc = crc16_ccitt((u8*)&(sender_id), 2, crc);
498  crc = crc16_ccitt(&(len), 1, crc);
499  crc = crc16_ccitt(payload, len, crc);
500 
501  wr = (*write)((u8*)&crc, 2, s->io_context);
502  if (0 > wr) return SBP_WRITE_ERROR;
503  if (wr != 2) return SBP_SEND_ERROR;
504 
505  return SBP_OK;
506 }
507 
SBP callback node.
Definition: sbp.h:54
void sbp_clear_callbacks(sbp_state_t *s)
Clear all registered callbacks.
Definition: sbp.c:233
void(* sbp_msg_callback_t)(u16 sender_id, u8 len, u8 msg[], void *context)
SBP callback function prototype definition.
Definition: sbp.h:48
#define SBP_CALLBACK_ERROR
Return value indicating an error with the callback (function defined).
Definition: sbp.h:32
s8 sbp_send_message(sbp_state_t *s, u16 msg_type, u16 sender_id, u8 len, u8 *payload, s32(*write)(u8 *buff, u32 n, void *context))
Send SBP messages.
Definition: sbp.c:459
u16 sender_id
Definition: sbp.h:72
u16 msg_type
Message ID associated with callback.
Definition: sbp.h:55
int8_t s8
Signed 8-bit integer.
Definition: common.h:32
#define SBP_CRC_ERROR
Return value indicating a CRC error.
Definition: sbp.h:34
sbp_msg_callbacks_node_t * sbp_msg_callbacks_head
Definition: sbp.h:78
s8 sbp_register_callback(sbp_state_t *s, u16 msg_type, sbp_msg_callback_t cb, void *context, sbp_msg_callbacks_node_t *node)
Register a callback for a message type.
Definition: sbp.c:161
#define SBP_WRITE_ERROR
Return value indicating an error occured in the write() operation.
Definition: sbp.h:40
u8 msg_buff[256]
Definition: sbp.h:76
uint8_t u8
Unsigned 8-bit integer.
Definition: common.h:40
#define SBP_SEND_ERROR
Return value indicating an error occured whilst sending an SBP message.
Definition: sbp.h:36
s8 sbp_remove_callback(sbp_state_t *s, sbp_msg_callbacks_node_t *node)
Remove a registered callback.
Definition: sbp.c:212
#define SBP_OK_CALLBACK_EXECUTED
Return value indicating message decoded and callback executed by sbp_process.
Definition: sbp.h:28
#define SBP_OK_CALLBACK_UNDEFINED
Return value indicating message decoded with no associated callback in sbp_process.
Definition: sbp.h:30
u16 crc
Definition: sbp.h:73
s8 sbp_process_payload(sbp_state_t *s, u16 sender_id, u16 msg_type, u8 msg_len, u8 payload[])
Directly process a SBP message.
Definition: sbp.c:416
enum sbp_state_t::@0 state
void sbp_state_set_io_context(sbp_state_t *s, void *context)
Set a context to pass to all function pointer calls made by sbp functions This helper function sets a...
Definition: sbp.c:264
#define SBP_OK
Return value indicating success.
Definition: sbp.h:26
State structure for processing SBP messages.
Definition: sbp.h:62
uint16_t u16
Unsigned 16-bit integer.
Definition: common.h:42
u8 msg_len
Definition: sbp.h:74
uint32_t u32
Unsigned 32-bit integer.
Definition: common.h:44
u16 msg_type
Definition: sbp.h:71
#define SBP_READ_ERROR
Return value indicating an error occured in the read() operation.
Definition: sbp.h:42
void sbp_state_init(sbp_state_t *s)
Initialize an sbp_state_t struct before use.
Definition: sbp.c:246
#define SBP_NULL_ERROR
Return value indicating an error occured because an argument was NULL.
Definition: sbp.h:38
sbp_msg_callback_t cb
Pointer to callback function.
Definition: sbp.h:56
s8 sbp_process(sbp_state_t *s, s32(*read)(u8 *buff, u32 n, void *context))
Read and process SBP messages.
Definition: sbp.c:308
u16 crc16_ccitt(const u8 *buf, u32 len, u16 crc)
Calculate CCITT 16-bit Cyclical Redundancy Check (CRC16).
Definition: edc.c:74
void * io_context
Definition: sbp.h:77
int32_t s32
Signed 32-bit integer.
Definition: common.h:36
u8 n_read
Definition: sbp.h:75
void * context
Pointer to a context.
Definition: sbp.h:57
struct sbp_msg_callbacks_node * next
Pointer to next node in list.
Definition: sbp.h:58
#define SBP_PREAMBLE
Definition: sbp.c:16