Classes | |
struct | sbp_msg_callbacks_node |
struct | sbp_state_t |
Modules | |
SBP Utils | |
Defines | |
#define | SBP_CALLBACK_ERROR -1 |
#define | SBP_CRC_ERROR -2 |
#define | SBP_NULL_ERROR -4 |
#define | SBP_OK 0 |
#define | SBP_OK_CALLBACK_EXECUTED 1 |
#define | SBP_OK_CALLBACK_UNDEFINED 2 |
#define | SBP_SEND_ERROR -3 |
Typedefs | |
typedef void(* | sbp_msg_callback_t )(u16 sender_id, u8 len, u8 msg[], void *context) |
typedef struct sbp_msg_callbacks_node | sbp_msg_callbacks_node_t |
Functions | |
void | sbp_clear_callbacks (sbp_state_t *s) |
sbp_msg_callbacks_node_t * | sbp_find_callback (sbp_state_t *s, u16 msg_type) |
s8 | sbp_process (sbp_state_t *s, u32(*read)(u8 *buff, u32 n, void *context)) |
s8 | sbp_register_callback (sbp_state_t *s, u16 msg_type, sbp_msg_callback_t cb, void *context, sbp_msg_callbacks_node_t *node) |
s8 | sbp_send_message (sbp_state_t *s, u16 msg_type, u16 sender_id, u8 len, u8 *payload, u32(*write)(u8 *buff, u32 n, void *context)) |
void | sbp_state_init (sbp_state_t *s) |
void | sbp_state_set_io_context (sbp_state_t *s, void *context) |
Send and receive messages using Swift Binary Protocol.
Examples ========
Receiving ---------
First setup a callback for the message you will be receiving. Our callback function must have type sbp_msg_callback_t, i.e. it must be of the form:
~~~ void my_callback(u16 sender_id, u8 len, u8 msg[], void *context) { // Process msg. } ~~~
You must also statically allocate a sbp_msg_callbacks_node_t that will be used to keep track of the callback function. You do not need to initialize it as this will be done by sbp_register_callback().
~~~ static sbp_msg_callbacks_node_t my_callback_node; ~~~
Now register your callback function with the SBP library as follows:
~~~ sbp_register_callback(&sbp_state, SBP_MY_MSG_TYPE, &my_callback, &context, &my_callback_node); ~~~
where `SBP_MY_MSG_TYPE` is the numerical identifier of your message type.
You must now call sbp_process() periodically whenever you have received SBP data to be processed, e.g. from the serial port. Remember sbp_process() may not use all available data so keep calling sbp_process() until all the received serial data has been consumed.
sbp_process() stores its internal state in an sbp_state_t struct which must be initialized by calling sbp_state_init() before its first use.
Here is an example based on reading from a typical UART interface:
~~~ u32 my_read(u8 *buff, u32 n, void *context) { for (u32 i=0; i<n; i++) { if (uart_has_data()) buff[i] = uart_read_char(); else break; } return i; }
int main() { ...
sbp_state_t s; sbp_state_init(&s);
while(uart_has_data()) { sbp_process(&s, &my_read); }
... } ~~~
If you're writing C++ code that wants to reference a pointer to an object in the my_read function, you can use the context set by calling sbp_state_set_io_context()
Sending -------
To send an SBP message simply call the sbp_send_message() function, providing a `write` function that writes data to your output.
Often the data to be sent will simply be a struct cast to a `u8` buffer. As a convenience you may want to define a macro that automatically includes your write function and calculates the size of the item to be sent.
~~~ // Convenience macro for sending an SBP message. #define SBP_MSG(sbp_state, msg_type, item) \ sbp_send_message(&sbp_state, msg_type, MY_SENDER_ID, \ sizeof(item), (u8 *)&(item), &my_write)
typedef struct { u8 x, y; } my_awesome_struct;
u32 my_write(u8 *buff, u32 n, void *context) { for (u32 i=0; i<n; i++) { if (uart_write_char(buff[i]) == ERROR) break; } return i; }
int main() { ...
sbp_state_t s; sbp_state_init(&s);
my_awesome_struct payload = { 0x22, 0x33 };
sbp_send_message(&s, SBP_MY_MSG_TYPE, MY_SENDER_ID, sizeof(payload), (u8*)&payload, &my_write);
// or
SBP_MSG(s, SBP_MY_MSG_TYPE, payload);
... } ~~~
#define SBP_CALLBACK_ERROR -1 |
#define SBP_CRC_ERROR -2 |
#define SBP_NULL_ERROR -4 |
#define SBP_OK_CALLBACK_EXECUTED 1 |
#define SBP_OK_CALLBACK_UNDEFINED 2 |
#define SBP_SEND_ERROR -3 |
typedef void(* sbp_msg_callback_t)(u16 sender_id, u8 len, u8 msg[], void *context) |
typedef struct sbp_msg_callbacks_node sbp_msg_callbacks_node_t |
SBP callback node. Forms a linked list of callbacks.
void sbp_clear_callbacks | ( | sbp_state_t * | s | ) |
sbp_msg_callbacks_node_t* sbp_find_callback | ( | sbp_state_t * | s, |
u16 | msg_type | ||
) |
Find the callback function associated with a message type. Searches through the list of registered callbacks to find the callback associated with the passed message type.
msg_type | Message type to find callback for |
s8 sbp_process | ( | sbp_state_t * | s, |
u32(*)(u8 *buff, u32 n, void *context) | read | ||
) |
Read and process SBP messages. Reads bytes from an input source using the provided `read` function, decodes the SBP framing and performs a CRC check on the message.
When an SBP message is successfully received then the list of callbacks is searched for a callback corresponding to the received message type. If a callback is found then it is called with the ID of the sender, the message length and the message payload data buffer as arguments.
The supplied `read` function must have the prototype:
~~~ u32 read(u8 *buff, u32 n, void* context) ~~~
where `n` is the number of bytes requested and `buff` is the buffer into which to write the received data, and `context` is the arbitrary pointer set by `sbp_state_set_io_context`. The function should return the number of bytes successfully written into `buff` which may be between 0 and `n` inclusive, but must never be greater than `n`.
Note that `sbp_process` may not read all available bytes from the `read` function so the caller should loop until all bytes available from the input source have been consumed.
s | State structure |
read | Function pointer to a function that reads `n` bytes from the input source into `buff` and returns the number of bytes successfully read. |
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. Register a callback that is called when a message with type msg_type is received.
msg_type | Message type associated with callback |
cb | Pointer to message callback function |
context | Pointer to context for callback function |
node | Statically allocated sbp_msg_callbacks_node_t struct |
s8 sbp_send_message | ( | sbp_state_t * | s, |
u16 | msg_type, | ||
u16 | sender_id, | ||
u8 | len, | ||
u8 * | payload, | ||
u32(*)(u8 *buff, u32 n, void *context) | write | ||
) |
Send SBP messages. Takes an SBP message payload, type and sender ID then writes a message to the output stream using the supplied `write` function with the correct framing and CRC.
The supplied `write` function must have the prototype:
~~~ u32 write(u8 *buff, u32 n, void* context) ~~~
where `n` is the number of bytes to be written and `buff` is the buffer from which to read the data to be written, and `context` is the arbitrary pointer set by `sbp_state_set_io_context`. The function should return the number of bytes successfully written which may be between 0 and `n`. Currently, if the number of bytes written is different from `n` then `sbp_send_message` will immediately return with an error.
Note that `sbp_send_message` makes multiple calls to write and therefore if a `write` call fails then this may result in a partial message being written to the output. This should be caught by the CRC check on the receiving end but will result in lost messages.
write | Function pointer to a function that writes `n` bytes from `buff` to the output stream and returns the number of bytes successfully written. |
void sbp_state_init | ( | sbp_state_t * | s | ) |
Initialize an sbp_state_t struct before use. This resets the entire state, including all callbacks. Remember to use this function to initialize the state before calling sbp_process() for the first time.
s | State structure |
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 void* context pointer in sbp_state. Whenever `sbp_process` calls the `read` function pointer, it passes this context. Whenever `sbp_send_message` calls the `write` function pointer, it passes this context. This allows C++ code to get a pointer to an object inside these functions.