-
Notifications
You must be signed in to change notification settings - Fork 97
Add c api to call user function for every successfully deframed SBP message. [ESD-998] #723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,9 @@ extern "C" { | |
| #define SBP_OK_CALLBACK_EXECUTED 1 | ||
| /** Return value indicating message decoded with no associated callback in sbp_process. */ | ||
| #define SBP_OK_CALLBACK_UNDEFINED 2 | ||
| /** Return value indicating message decoded and only an all_msg function was | ||
| * executed. */ | ||
| #define SBP_OK_ALLMSG_FN_EXECUTED_ONLY 3 | ||
| /** Return value indicating an error with the callback (function defined). */ | ||
| #define SBP_CALLBACK_ERROR -1 | ||
| /** Return value indicating a CRC error. */ | ||
|
|
@@ -46,6 +49,8 @@ extern "C" { | |
|
|
||
| /** SBP callback function prototype definition. */ | ||
| typedef void (*sbp_msg_callback_t)(u16 sender_id, u8 len, u8 msg[], void *context); | ||
| typedef void (*sbp_allmsg_fn_t)(u16 sender_id, u16 msg_type, u8 len, u8 msg[], | ||
| void *context); | ||
|
|
||
| /** SBP callback node. | ||
| * Forms a linked list of callbacks. | ||
|
|
@@ -76,12 +81,20 @@ typedef struct { | |
| u8 msg_buff[256]; | ||
| void* io_context; | ||
| sbp_msg_callbacks_node_t* sbp_msg_callbacks_head; | ||
| sbp_allmsg_fn_t allmsg_fn; | ||
| void *allmsg_context; | ||
| } sbp_state_t; | ||
|
|
||
| /** \} */ | ||
|
|
||
| /* registers a callback to be called on a particular msg_type */ | ||
| s8 sbp_register_callback(sbp_state_t* s, u16 msg_type, sbp_msg_callback_t cb, void* context, | ||
| sbp_msg_callbacks_node_t *node); | ||
| /* sets a function to be called on ANY deframed message */ | ||
| s8 sbp_set_allmsg_fn(sbp_state_t *s, sbp_allmsg_fn_t fn, void *context); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe I suggested
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was worried about calling it a "callback". If I do, then I think it makes sense that sbp_clear_callbacks clears this allmsg callback as well, which is kind of a change in behavior for that part of the API that Ben wasn't too fond of. |
||
| /* gets the function to be called on ANY deframed message */ | ||
| sbp_allmsg_fn_t sbp_get_allmsg_fn(sbp_state_t *s); | ||
| s8 sbp_remove_allmsg_fn(sbp_state_t *s); | ||
| s8 sbp_remove_callback(sbp_state_t *s, sbp_msg_callbacks_node_t *node); | ||
| void sbp_clear_callbacks(sbp_state_t* s); | ||
| void sbp_state_init(sbp_state_t *s); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,7 @@ | |
| /** Protocol minor version. */ | ||
| #define SBP_MINOR_VERSION 6 | ||
| /** Protocol patch version. */ | ||
| #define SBP_PATCH_VERSION 4 | ||
| #define SBP_PATCH_VERSION 6 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should need to touch this, it's bumped automatically during a release. |
||
|
|
||
| /** \} */ | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,21 @@ | |
| * | ||
| * where `SBP_MY_MSG_TYPE` is the numerical identifier of your message type. | ||
| * | ||
| * If you'd like to call a function for EVERY sbp message, setup an allmsg function | ||
| * with the type sbp_allmsg_fn_t. It must be of the form: | ||
| * | ||
| * ~~~ | ||
| * void my_allmsg_fn(u16 sender_id, u16 msg_type, u8 len, u8 msg[], void *context) | ||
| * { | ||
| * // Process msg. | ||
| * } | ||
| * ~~~ | ||
| * | ||
| * Then register the allmsg callback with the SBP library as follows: | ||
| * ~~~ | ||
| * sbp_register_allmsg_fn(&sbp_state, &my_allmsg_fn, &context); | ||
| * ~~~ | ||
| * | ||
| * 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 | ||
|
|
@@ -227,6 +242,44 @@ s8 sbp_remove_callback(sbp_state_t *s, sbp_msg_callbacks_node_t *node) | |
| return SBP_CALLBACK_ERROR; | ||
| } | ||
|
|
||
| /** Set a function to be called for ANY message type. | ||
| * | ||
| * \param s pointer to sbp_state_t struct in use | ||
| * \param fn Pointer to message callback function | ||
| * \param context Pointer to context for callback function | ||
| * \return `SBP_OK` (0) if successful, `SBP_NULL_ERROR` if fn is NULL | ||
| * | ||
| */ | ||
| s8 sbp_set_allmsg_fn(sbp_state_t *s, sbp_allmsg_fn_t fn, void *context) { | ||
| /* Check our callback function pointer isn't NULL. */ | ||
| if (0 == fn) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, but in order to do this it requires adding a new #include that wasn't here when the original author wrote. I thought perhaps there was a portability reason to not include stddefs. I'm happy to follow up with a separate PR to add in NULL for null pointer and the new include, but for now I wanted to follow the existing pattern. |
||
| return SBP_NULL_ERROR; | ||
| } | ||
| s->allmsg_fn = fn; | ||
| s->allmsg_context = context; | ||
| return SBP_OK; | ||
| } | ||
|
|
||
| /** Retrieve the callback for ANY message type. | ||
| * | ||
| * \param s pointer to sbp_state_t struct in use | ||
| * \return sbp_allmsg_fn_t* to allmsg fn pointer or NULL if none | ||
| * | ||
| */ | ||
| sbp_allmsg_fn_t sbp_get_allmsg_fn(sbp_state_t *s) { | ||
| return s->allmsg_fn; | ||
| } | ||
|
|
||
| /** Remove allmsg function pointer and context. | ||
| * | ||
| * \return `SBP_OK` (0) if successful | ||
| */ | ||
| s8 sbp_remove_allmsg_fn(sbp_state_t *s) { | ||
| s->allmsg_fn = 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clear
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes I agree. |
||
| s->allmsg_context = 0; | ||
| return SBP_OK; | ||
| } | ||
|
|
||
| /** Clear all registered callbacks. | ||
| * This is probably only useful for testing but who knows! | ||
| */ | ||
|
|
@@ -252,6 +305,9 @@ void sbp_state_init(sbp_state_t *s) | |
|
|
||
| /* Clear the callbacks, if any, currently in s */ | ||
| sbp_clear_callbacks(s); | ||
|
|
||
| /* Clear the allmsg_fn, if any, currently set on s */ | ||
| sbp_remove_allmsg_fn(s); | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -302,7 +358,8 @@ void sbp_state_set_io_context(sbp_state_t *s, void *context) | |
| * \return `SBP_OK` (0) if successful but no complete message yet, | ||
| * `SBP_OK_CALLBACK_EXECUTED` (1) if message decoded and callback executed, | ||
| * `SBP_OK_CALLBACK_UNDEFINED` (2) if message decoded with no associated | ||
| * callback, and `SBP_CRC_ERROR` (-2) if a CRC error | ||
| * callback, SBP_OK_ALLMSG_FN_EXECUTED_ONLY (3) if only the generic | ||
| * callback for every msg was called, and `SBP_CRC_ERROR` (-2) if a CRC error | ||
| * has occurred. Thus can check for >0 to ensure good processing. | ||
| */ | ||
| s8 sbp_process(sbp_state_t *s, s32 (*read)(u8 *buff, u32 n, void *context)) | ||
|
|
@@ -412,6 +469,8 @@ s8 sbp_process(sbp_state_t *s, s32 (*read)(u8 *buff, u32 n, void *context)) | |
| * \return `SBP_OK_CALLBACK_EXECUTED` (1) if message decoded and callback executed, | ||
| * `SBP_OK_CALLBACK_UNDEFINED` (2) if message decoded with no associated | ||
| * callback. | ||
| * `SBP_OK_ALLMSG_FN_EXECUTED_ONLY` (3) if message decoded and only | ||
| * allmsg callback was called | ||
| */ | ||
| s8 sbp_process_payload(sbp_state_t *s, u16 sender_id, u16 msg_type, u8 msg_len, | ||
| u8 payload[]) { | ||
|
|
@@ -423,6 +482,12 @@ s8 sbp_process_payload(sbp_state_t *s, u16 sender_id, u16 msg_type, u8 msg_len, | |
| ret = SBP_OK_CALLBACK_EXECUTED; | ||
| } | ||
| } | ||
| if (0 != s->allmsg_fn) { | ||
| (s->allmsg_fn)(sender_id, msg_type, msg_len, payload, s->allmsg_context); | ||
| if (ret == SBP_OK_CALLBACK_UNDEFINED) { | ||
| ret = SBP_OK_ALLMSG_FN_EXECUTED_ONLY; | ||
| } | ||
| } | ||
| return ret; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No a huge fall of
allmsg, would preferall_msg, but I can live with it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just didn't want anyone to be confused that all_msg meant all messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree on this point, considering one of the use cases of this function (hence the different signature) is to receive the entire raw frame so the binary blob can be written to file. from this perspective I would almost prefer a name like
sbp_raw_frame_handleror something to that effect