From fff138400cc21c07e4431caa7cb2591f16148643 Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Wed, 6 Nov 2024 13:16:54 +0100 Subject: [PATCH] stream: support decoding multiple bytes at once --- include/cobs/stream.h | 21 +++++++++++++++++++-- stream.c | 36 ++++++++++++++++++++++++++++++++++-- testutils/common.c | 4 ++-- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/include/cobs/stream.h b/include/cobs/stream.h index e4cad68..26369be 100644 --- a/include/cobs/stream.h +++ b/include/cobs/stream.h @@ -129,8 +129,25 @@ struct cobs_encode { * A frame is only fully received and decoded when the mentioned zero byte was * received and the decoder is in the finished state. */ -enum cobs_decode_result cobs_decode_stream(struct cobs_decode *decode, uint8_t input_byte, - uint8_t *output_byte, bool *output_available); +enum cobs_decode_result cobs_decode_stream_single(struct cobs_decode *decode, uint8_t input_byte, + uint8_t *output_byte, bool *output_available); + +/** + * Pass multiple bytes to the decoder. + * + * This calls #cobs_decode_stream_single in a loop, but it's more efficient + * thanks to inlining. This function will stop the loop if: + * - The current frame is complete. + * - All input bytes where consumed. + * - We need to write to the output buffer but there is no space left. + * + * That means, you can't expect this function to consume all input bytes. You + * have to possibly reset the decoder or allocate more data and call this + * function again with the rest of the data. + */ +enum cobs_decode_result cobs_decode_stream(struct cobs_decode *decode, const uint8_t *input, + size_t input_size, uint8_t *output, size_t output_size, + size_t *num_read, size_t *num_written); /** * Reset decoder. diff --git a/stream.c b/stream.c index 3bc66f2..4146081 100644 --- a/stream.c +++ b/stream.c @@ -81,8 +81,10 @@ static int cursor_find_zero(struct cobs_buf_cursor *cursor, size_t *num_processe return -ENOENT; } -enum cobs_decode_result cobs_decode_stream(struct cobs_decode *decode, uint8_t input_byte, - uint8_t *output_byte, bool *output_available) +/* NOTE: It's important to inline this, to make cobs_decode_stream faster. */ +ALWAYS_INLINE +enum cobs_decode_result cobs_decode_stream_single(struct cobs_decode *decode, uint8_t input_byte, + uint8_t *output_byte, bool *output_available) { *output_available = false; @@ -131,6 +133,36 @@ enum cobs_decode_result cobs_decode_stream(struct cobs_decode *decode, uint8_t i } } +enum cobs_decode_result cobs_decode_stream(struct cobs_decode *decode, const uint8_t *input, + size_t input_size, uint8_t *output, size_t output_size, + size_t *num_read, size_t *num_written) +{ + *num_read = 0; + *num_written = 0; + + while (input_size > 0 && (output_size > 0 || input[0] == 0)) { + bool output_available = false; + enum cobs_decode_result result = + cobs_decode_stream_single(decode, input[0], output, &output_available); + + *num_read += 1; + input++; + input_size -= 1; + + if (output_available) { + *num_written += 1; + output++; + output_size -= 1; + } + + if (result != COBS_DECODE_RESULT_CONSUMED) { + return result; + } + } + + return COBS_DECODE_RESULT_CONSUMED; +} + void cobs_encode_stream_init(struct cobs_encode *encode, struct net_buf *buf) { *encode = (struct cobs_encode){ diff --git a/testutils/common.c b/testutils/common.c index 2b97d5e..787a5f5 100644 --- a/testutils/common.c +++ b/testutils/common.c @@ -66,8 +66,8 @@ int cobs_decode_stream_simple(const uint8_t *const input, const size_t input_len output_length); bool available = false; - const enum cobs_decode_result res = - cobs_decode_stream(&decode, input[i], &output[output_length], &available); + const enum cobs_decode_result res = cobs_decode_stream_single( + &decode, input[i], &output[output_length], &available); if (available) { output_length += 1;