diff --git a/C/test/yahdlc_test.cpp b/C/test/yahdlc_test.cpp index 4563c59..544e7ba 100644 --- a/C/test/yahdlc_test.cpp +++ b/C/test/yahdlc_test.cpp @@ -39,6 +39,10 @@ BOOST_AUTO_TEST_CASE(yahdlcTestGetDataInvalidInputs) { unsigned int recv_length = 0; char frame_data[8], recv_data[8]; + ret = yahdlc_get_data_with_state(NULL, &control, frame_data, sizeof(frame_data), + recv_data, &recv_length); + BOOST_CHECK_EQUAL(ret, -EINVAL); + // Check invalid control field parameter ret = yahdlc_get_data(NULL, frame_data, sizeof(frame_data), recv_data, &recv_length); @@ -60,6 +64,45 @@ BOOST_AUTO_TEST_CASE(yahdlcTestGetDataInvalidInputs) { BOOST_CHECK_EQUAL(ret, -EINVAL); } +BOOST_AUTO_TEST_CASE(yahdlcTestSetGetState) { + int ret; + yahdlc_state_t state, yahdlc_state; + + state.fcs = 123; + + ret = yahdlc_set_state(NULL); + BOOST_CHECK_EQUAL(ret, -EINVAL); + + ret = yahdlc_set_state(&state); + BOOST_CHECK_EQUAL(ret, 0); + + ret = yahdlc_get_state(NULL); + BOOST_CHECK_EQUAL(ret, -EINVAL); + + ret = yahdlc_get_state(&yahdlc_state); + BOOST_CHECK_EQUAL(ret, 0); + BOOST_CHECK_EQUAL(state.control_escape, yahdlc_state.control_escape); + BOOST_CHECK_EQUAL(state.fcs, yahdlc_state.fcs); + BOOST_CHECK_EQUAL(state.start_index, yahdlc_state.start_index); + BOOST_CHECK_EQUAL(state.end_index, yahdlc_state.end_index); + BOOST_CHECK_EQUAL(state.src_index, yahdlc_state.src_index); + BOOST_CHECK_EQUAL(state.dest_index, yahdlc_state.dest_index); +} + +BOOST_AUTO_TEST_CASE(yahdlcTestGetDataReset) { + yahdlc_state_t state, yahdlc_state; + + yahdlc_get_data_reset(); + yahdlc_get_data_reset_with_state(&state); + yahdlc_get_state(&yahdlc_state); + BOOST_CHECK_EQUAL(state.control_escape, yahdlc_state.control_escape); + BOOST_CHECK_EQUAL(state.fcs, yahdlc_state.fcs); + BOOST_CHECK_EQUAL(state.start_index, yahdlc_state.start_index); + BOOST_CHECK_EQUAL(state.end_index, yahdlc_state.end_index); + BOOST_CHECK_EQUAL(state.src_index, yahdlc_state.src_index); + BOOST_CHECK_EQUAL(state.dest_index, yahdlc_state.dest_index); +} + BOOST_AUTO_TEST_CASE(yahdlcTestDataFrameControlField) { int ret; char frame_data[8], recv_data[8]; diff --git a/C/yahdlc.c b/C/yahdlc.c index c03102d..8119656 100644 --- a/C/yahdlc.c +++ b/C/yahdlc.c @@ -14,11 +14,33 @@ #define YAHDLC_CONTROL_TYPE_REJECT 2 #define YAHDLC_CONTROL_TYPE_SELECTIVE_REJECT 3 -// Variables used in yahdlc_get_data to keep track of received buffers -static char yahdlc_control_escape = 0; -static unsigned short yahdlc_fcs = FCS16_INIT_VALUE; -static int yahdlc_start_index = -1, yahdlc_end_index = -1, yahdlc_src_index = 0, - yahdlc_dest_index = 0; +static yahdlc_state_t yahdlc_state = { + .control_escape = 0, + .fcs = FCS16_INIT_VALUE, + .start_index = -1, + .end_index = -1, + .src_index = 0, + .dest_index = 0, +}; + +int yahdlc_set_state(yahdlc_state_t *state) { + if (!state) { + return -EINVAL; + } + + yahdlc_state = *state; + return 0; +} + + +int yahdlc_get_state(yahdlc_state_t *state) { + if (!state) { + return -EINVAL; + } + + *state = yahdlc_state; + return 0; +} void yahdlc_escape_value(char value, char *dest, int *dest_index) { // Check and escape the value if needed @@ -83,27 +105,36 @@ unsigned char yahdlc_frame_control_type(yahdlc_control_t *control) { } void yahdlc_get_data_reset() { - yahdlc_fcs = FCS16_INIT_VALUE; - yahdlc_start_index = yahdlc_end_index = -1; - yahdlc_src_index = yahdlc_dest_index = 0; - yahdlc_control_escape = 0; + yahdlc_get_data_reset_with_state(&yahdlc_state); +} + +void yahdlc_get_data_reset_with_state(yahdlc_state_t *state) { + state->fcs = FCS16_INIT_VALUE; + state->start_index = state->end_index = -1; + state->src_index = state->dest_index = 0; + state->control_escape = 0; } int yahdlc_get_data(yahdlc_control_t *control, const char *src, unsigned int src_len, char *dest, unsigned int *dest_len) { + return yahdlc_get_data_with_state(&yahdlc_state, control, src, src_len, dest, dest_len); +} + +int yahdlc_get_data_with_state(yahdlc_state_t *state, yahdlc_control_t *control, const char *src, + unsigned int src_len, char *dest, unsigned int *dest_len) { int ret; char value; unsigned int i; // Make sure that all parameters are valid - if (!control || !src || !dest || !dest_len) { + if (!state || !control || !src || !dest || !dest_len) { return -EINVAL; } // Run through the data bytes for (i = 0; i < src_len; i++) { // First find the start flag sequence - if (yahdlc_start_index < 0) { + if (state->start_index < 0) { if (src[i] == YAHDLC_FLAG_SEQUENCE) { // Check if an additional flag sequence byte is present if ((i < (src_len - 1)) && (src[i + 1] == YAHDLC_FLAG_SEQUENCE)) { @@ -111,66 +142,66 @@ int yahdlc_get_data(yahdlc_control_t *control, const char *src, continue; } - yahdlc_start_index = yahdlc_src_index; + state->start_index = state->src_index; } } else { // Check for end flag sequence if (src[i] == YAHDLC_FLAG_SEQUENCE) { // Check if an additional flag sequence byte is present or earlier received if (((i < (src_len - 1)) && (src[i + 1] == YAHDLC_FLAG_SEQUENCE)) - || ((yahdlc_start_index + 1) == yahdlc_src_index)) { + || ((state->start_index + 1) == state->src_index)) { // Just loop again to silently discard it (accordingly to HDLC) continue; } - yahdlc_end_index = yahdlc_src_index; + state->end_index = state->src_index; break; } else if (src[i] == YAHDLC_CONTROL_ESCAPE) { - yahdlc_control_escape = 1; + state->control_escape = 1; } else { // Update the value based on any control escape received - if (yahdlc_control_escape) { - yahdlc_control_escape = 0; + if (state->control_escape) { + state->control_escape = 0; value = src[i] ^ 0x20; } else { value = src[i]; } // Now update the FCS value - yahdlc_fcs = fcs16(yahdlc_fcs, value); + state->fcs = fcs16(state->fcs, value); - if (yahdlc_src_index == yahdlc_start_index + 2) { + if (state->src_index == state->start_index + 2) { // Control field is the second byte after the start flag sequence *control = yahdlc_get_control_type(value); - } else if (yahdlc_src_index > (yahdlc_start_index + 2)) { + } else if (state->src_index > (state->start_index + 2)) { // Start adding the data values after the Control field to the buffer - dest[yahdlc_dest_index++] = value; + dest[state->dest_index++] = value; } } } - yahdlc_src_index++; + state->src_index++; } // Check for invalid frame (no start or end flag sequence) - if ((yahdlc_start_index < 0) || (yahdlc_end_index < 0)) { + if ((state->start_index < 0) || (state->end_index < 0)) { // Return no message and make sure destination length is 0 *dest_len = 0; ret = -ENOMSG; } else { // A frame is at least 4 bytes in size and has a valid FCS value - if ((yahdlc_end_index < (yahdlc_start_index + 4)) - || (yahdlc_fcs != FCS16_GOOD_VALUE)) { + if ((state->end_index < (state->start_index + 4)) + || (state->fcs != FCS16_GOOD_VALUE)) { // Return FCS error and indicate that data up to end flag sequence in buffer should be discarded *dest_len = i; ret = -EIO; } else { // Return success and indicate that data up to end flag sequence in buffer should be discarded - *dest_len = yahdlc_dest_index - sizeof(yahdlc_fcs); + *dest_len = state->dest_index - sizeof(state->fcs); ret = i; } // Reset values for next frame - yahdlc_get_data_reset(); + yahdlc_get_data_reset_with_state(state); } return ret; diff --git a/C/yahdlc.h b/C/yahdlc.h index d01e180..a8b18c4 100644 --- a/C/yahdlc.h +++ b/C/yahdlc.h @@ -29,10 +29,40 @@ typedef struct { unsigned char seq_no :3; } yahdlc_control_t; +/** Variables used in yahdlc_get_data and yahdlc_get_data_with_state + * to keep track of received buffers + */ +typedef struct { + char control_escape; + unsigned short fcs; + int start_index; + int end_index; + int src_index; + int dest_index; +} yahdlc_state_t; + #ifdef __cplusplus extern "C" { #endif +/** + * Set the yahdlc state + * + * @param[in] state The new yahdlc state to be used + * @retval 0 Success + * @retval -EINVAL Invalid parameter + */ +int yahdlc_set_state(yahdlc_state_t *state); + +/** + * Get current yahdlc state + * + * @param[out] state Current yahdlc state + * @retval 0 Success + * @retval -EINVAL Invalid parameter + */ +int yahdlc_get_state(yahdlc_state_t *state); + /** * Retrieves data from specified buffer containing the HDLC frame. Frames can be * parsed from multiple buffers e.g. when received via UART. @@ -46,15 +76,42 @@ extern "C" { * @retval -EINVAL Invalid parameter * @retval -ENOMSG Invalid message * @retval -EIO Invalid FCS (size of dest_len should be discarded from source buffer) + * + * @see yahdlc_get_data_with_state */ int yahdlc_get_data(yahdlc_control_t *control, const char *src, unsigned int src_len, char *dest, unsigned int *dest_len); +/** + * Retrieves data from specified buffer containing the HDLC frame. Frames can be + * parsed from multiple buffers e.g. when received via UART. + * + * This function is a variation of @ref yahdlc_get_data + * The difference is only in first argument: yahdlc_state_t *state + * Data under that pointer is used to keep track of internal buffers. + * + * @see yahdlc_get_data + */ +int yahdlc_get_data_with_state(yahdlc_state_t *state, yahdlc_control_t *control, const char *src, + unsigned int src_len, char *dest, unsigned int *dest_len); + + /** * Resets values used in yahdlc_get_data function to keep track of received buffers */ void yahdlc_get_data_reset(); +/** + * This is a variation of @ref yahdlc_get_data_reset + * Resets state values that are under the pointer provided as argument + * + * This function need to be called before the first call to yahdlc_get_data_with_state + * when custom state storage is used. + * + * @see yahdlc_get_data_reset + */ +void yahdlc_get_data_reset_with_state(yahdlc_state_t *state); + /** * Creates HDLC frame with specified data buffer. *