From f344ab6b98cc58b3e1c5addc18e92c3930bf09df Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 7 Jan 2026 16:48:11 +0100 Subject: [PATCH] cobs: Introduce streaming This commit does: - Introduce COBS streaming - Refactor custom delimiter with XOR'ed encoded data - Update tests Signed-off-by: Pieter De Gendt --- include/zephyr/data/cobs.h | 216 +++++++++++++++++++++++++-- lib/utils/cobs.c | 290 ++++++++++++++++++++++++++++--------- tests/lib/cobs/src/main.c | 62 ++++---- 3 files changed, 458 insertions(+), 110 deletions(-) diff --git a/include/zephyr/data/cobs.h b/include/zephyr/data/cobs.h index e22f1d2aaaf..da9f2e0339a 100644 --- a/include/zephyr/data/cobs.h +++ b/include/zephyr/data/cobs.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 Kelly Helmut Lord + * Copyright (c) 2026 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,20 +17,53 @@ extern "C" { #endif + +/** + * @name COBS Encoder/Decoder Flags + * @anchor COBS_FLAGS + * + * @{ + */ + +/** + * @brief Default COBS delimiter value + * + * The standard COBS delimiter is zero (0x00). This is the delimiter value + * used when COBS_FLAG_CUSTOM_DELIMITER is not specified. + */ #define COBS_DEFAULT_DELIMITER 0x00 /** - * Flag indicating that encode and decode should include an implicit end delimiter + * @brief Flag indicating that encode or decode should include a trailing delimiter + * + * When set, the encoder will append a delimiter byte after the encoded data, + * and the decoder will accept a delimiter byte at the end of the encoded data. */ #define COBS_FLAG_TRAILING_DELIMITER BIT(8) /** - * Macro for extracting delimiter from flags. 8 LSB of "flags" is used for the delimiter + * @brief Macro for setting a custom delimiter in flags + * + * The 8 LSB of "flags" is used for the delimiter value. When a custom delimiter is + * configured, the implementation applies an XOR operation with the delimiter value + * on the encoded data after encoding and before decoding. This allows COBS to work + * with delimiters other than zero. + * + * @param x Custom delimiter value (0-255) + * + * @return Delimiter value masked to 8 bits + * * Example usage: + * @code{.c} * cobs_encode(src_buf, dst_buf, COBS_FLAG_TRAILING_DELIMITER | COBS_FLAG_CUSTOM_DELIMITER(0x7F)); + * @endcode */ #define COBS_FLAG_CUSTOM_DELIMITER(x) ((x) & 0xff) +/** + * @} + */ + /** * @defgroup cobs COBS (Consistent Overhead Byte Stuffing) * @ingroup utilities @@ -46,7 +80,7 @@ extern "C" { * @brief Calculate maximum encoded buffer size * * @param decoded_size Size of input data to be encoded - * @param flags COBS_FLAG_TRAILING_DELIMITER to include termination byte in calculation + * @param flags Encoding flags @ref COBS_FLAGS * * @return Required buffer size for worst-case encoding scenario */ @@ -60,11 +94,13 @@ static inline size_t cobs_max_encoded_len(size_t decoded_size, uint32_t flags) } /** - * @brief Standard COBS encoding + * @brief COBS encoding * - * @param src Source buffer to decode - * @param dst Destination buffer for decoded data - * @param flags Decoding flags (reserved) + * Encodes data from source buffer to destination buffer using COBS encoding. + * + * @param src Source buffer to encode + * @param dst Destination buffer for encoded data + * @param flags Encoding flags @ref COBS_FLAGS * * @retval 0 Success * @retval -ENOMEM Insufficient destination space @@ -74,11 +110,13 @@ static inline size_t cobs_max_encoded_len(size_t decoded_size, uint32_t flags) int cobs_encode(struct net_buf *src, struct net_buf *dst, uint32_t flags); /** - * @brief Standard COBS decoding + * @brief COBS decoding + * + * Decodes COBS-encoded data from source buffer to destination buffer. * * @param src Source buffer to decode * @param dst Destination buffer for decoded data - * @param flags Decoding flags (reserved) + * @param flags Decoding flags @ref COBS_FLAGS * * @retval 0 Success * @retval -ENOMEM Insufficient destination space @@ -86,6 +124,166 @@ int cobs_encode(struct net_buf *src, struct net_buf *dst, uint32_t flags); */ int cobs_decode(struct net_buf *src, struct net_buf *dst, uint32_t flags); +/** + * @brief Callback function type for streaming COBS encoder/decoder + * + * This callback is invoked by the streaming encoder/decoder to output + * processed data chunks. + * A decoder that allows trailing delimiters and encounters one will invoke + * this callback with a NULL pointer and zero length indicating a completed frame. + * + * When this callback function returns a negative error value, the encoder or decoder + * stream is aborted and the error will be propagated. + * + * @param buf Buffer containing processed data + * @param len Length of data in buffer + * @param user_data User-provided context pointer + * + * @return 0 on success, negative errno code on failure + */ +typedef int (*cobs_stream_cb)(const uint8_t *buf, size_t len, void *user_data); + +/** + * @brief COBS streaming encoder state + * + * This structure maintains the state for incremental COBS encoding. + * It should be initialized with cobs_encoder_init() before use. + */ +struct cobs_encoder { + /** @cond INTERNAL_HIDDEN */ + /** Callback function to output encoded data */ + cobs_stream_cb cb; + /** User data pointer passed to callback */ + void *cb_user_data; + + /** Internal buffer for partial encoding */ + uint8_t fragment[255]; + /** Encoding flags @ref COBS_FLAGS */ + uint32_t flags; + /** @endcond */ +}; + +/** + * @brief COBS streaming decoder state + * + * This structure maintains the state for incremental COBS decoding. + * It should be initialized with cobs_decoder_init() before use. + */ +struct cobs_decoder { + /** @cond INTERNAL_HIDDEN */ + /** Callback function to output decoded data */ + cobs_stream_cb cb; + /** User data pointer passed to callback */ + void *cb_user_data; + + /** Current COBS code byte being processed */ + uint8_t code; + /** Position within current code block */ + uint8_t code_index; + /** Decoding flags @ref COBS_FLAGS */ + uint32_t flags; + /** @endcond */ +}; + +/** + * @brief Initialize COBS streaming encoder + * + * Initializes a COBS encoder for streaming operation. The encoder will call + * the provided callback function to output encoded data chunks as they become + * available. + * + * @param enc Pointer to encoder structure to initialize + * @param cb Callback function for output data + * @param user_data User data pointer passed to callback + * @param flags Encoding flags @ref COBS_FLAGS + * + * @return 0 on success, negative errno code on failure + */ +int cobs_encoder_init(struct cobs_encoder *enc, cobs_stream_cb cb, void *user_data, uint32_t flags); + +/** + * @brief Finalize COBS streaming encoder + * + * Flushes any remaining data and optionally writes trailing delimiter if + * COBS_FLAG_TRAILING_DELIMITER was set during initialization. + * + * The encoder state will be reset. + * + * @param enc Pointer to encoder structure + * + * @return 0 on success, negative errno code on failure + */ +int cobs_encoder_close(struct cobs_encoder *enc); + +/** + * @brief Write data to COBS streaming encoder + * + * Encodes the provided data and outputs encoded chunks via the registered + * callback function. This function can be called multiple times to encode + * data incrementally. + * + * In case an error is returned, the encoder state will be reset. + * + * @param enc Pointer to encoder structure + * @param buf Buffer containing data to encode + * @param len Length of data in buffer + * + * @return Number of bytes used from @p buf on success, negative errno code on failure + */ +int cobs_encoder_write(struct cobs_encoder *enc, const uint8_t *buf, size_t len); + +/** + * @brief Initialize COBS streaming decoder + * + * Initializes a COBS decoder for streaming operation. The decoder will call + * the provided callback function to output decoded data chunks as they become + * available. + * + * @param dec Pointer to decoder structure to initialize + * @param cb Callback function for output data + * @param user_data User data pointer passed to callback + * @param flags Decoding flags @ref COBS_FLAGS + * + * @return 0 on success, negative errno code on failure + */ +int cobs_decoder_init(struct cobs_decoder *dec, cobs_stream_cb cb, void *user_data, uint32_t flags); + +/** + * @brief Finalize COBS streaming decoder + * + * Completes the decoding process and verifies that the stream ended properly. + * Should be called after all data has been written to the decoder. + * + * The decoder state will be reset. + * + * @param dec Pointer to decoder structure + * + * @retval 0 Success + * @retval -EINVAL More data was expected before closing + */ +int cobs_decoder_close(struct cobs_decoder *dec); + +/** + * @brief Write data to COBS streaming decoder + * + * Decodes the provided encoded data and outputs decoded chunks via the + * registered callback function. This function can be called multiple times + * to decode data incrementally. + * + * In case an error is returned, the decoder state will be reset. + * + * @note If a delimiter is encountered, and the @ref COBS_FLAG_TRAILING_DELIMITER flag + * is set, the registered callback function will be called with a NULL pointer + * indicating a frame end. + * + * @param dec Pointer to decoder structure + * @param buf Buffer containing encoded data + * @param len Length of data in buffer + * + * @return Number of bytes used from @p buf on success, negative errno code on failure + */ +int cobs_decoder_write(struct cobs_decoder *dec, const uint8_t *buf, size_t len); + /** @} */ #ifdef __cplusplus diff --git a/lib/utils/cobs.c b/lib/utils/cobs.c index d500eb2b86f..e364d1729bb 100644 --- a/lib/utils/cobs.c +++ b/lib/utils/cobs.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 Kelly Helmut Lord + * Copyright (c) 2026 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,97 +9,242 @@ #include #include -int cobs_encode(struct net_buf *src, struct net_buf *dst, uint32_t flags) +static int cobs_net_buf_cb(const uint8_t *buf, size_t len, void *user_data) { - uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); + struct net_buf *dst = user_data; - /* Calculate required space for worst case */ - size_t max_encoded_size = cobs_max_encoded_len(src->len, flags); - - /* Check if destination has enough space */ - if (net_buf_tailroom(dst) < max_encoded_size) { + if (net_buf_tailroom(dst) < len) { return -ENOMEM; } - uint8_t *code_ptr = net_buf_add(dst, 1); - uint8_t code = 1; - - /* Process all input bytes */ - uint8_t data = 0; - - while (src->len > 0) { - data = net_buf_pull_u8(src); - if (data == delimiter) { - /* Delimiter found - write current code and start new block */ - *code_ptr = code; - code_ptr = net_buf_add(dst, 1); - code = 1; - } else { - /* Add non-zero byte to output */ - net_buf_add_u8(dst, data); - code++; - - /* If we've reached maximum block size, start a new block */ - if (code == 0xFF && (src->len - 1 >= 0)) { - *code_ptr = code; - code_ptr = net_buf_add(dst, 1); - code = 1; - } - } - } - - *code_ptr = code; - - if (flags & COBS_FLAG_TRAILING_DELIMITER) { - /* Add final delimiter */ - net_buf_add_u8(dst, delimiter); - } + (void)net_buf_add_mem(dst, buf, len); return 0; } +int cobs_encode(struct net_buf *src, struct net_buf *dst, uint32_t flags) +{ + struct cobs_encoder enc; + size_t len = src->len; + int ret; + + (void)cobs_encoder_init(&enc, cobs_net_buf_cb, dst, flags); + + ret = cobs_encoder_write(&enc, net_buf_pull_mem(src, len), len); + if (ret < 0) { + return ret; + } + + return cobs_encoder_close(&enc); +} + int cobs_decode(struct net_buf *src, struct net_buf *dst, uint32_t flags) { - uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); + struct cobs_decoder dec; + size_t len = src->len; + int ret; - if (flags & COBS_FLAG_TRAILING_DELIMITER) { - uint8_t end_delim = net_buf_remove_u8(src); + (void)cobs_decoder_init(&dec, cobs_net_buf_cb, dst, flags); - if (end_delim != delimiter) { - return -EINVAL; + ret = cobs_decoder_write(&dec, net_buf_pull_mem(src, len), len); + if (ret < 0) { + return ret; + } + + return cobs_decoder_close(&dec); +} + +static inline void cobs_encoder_reset(struct cobs_encoder *enc) +{ + /* Reset buffer */ + enc->fragment[0] = 1; +} + +static int cobs_encoder_finish(struct cobs_encoder *enc, bool close) +{ + uint8_t sentinel = COBS_FLAG_CUSTOM_DELIMITER(enc->flags); + size_t len = enc->fragment[0]; + int ret; + + if (sentinel != 0x00) { + for (size_t i = 0; i < len; ++i) { + enc->fragment[i] ^= sentinel; } } - while (src->len > 0) { - /* Pull the COBS offset byte */ - uint8_t offset = net_buf_pull_u8(src); + ret = enc->cb(enc->fragment, len, enc->cb_user_data); + if (ret < 0) { + cobs_encoder_reset(enc); + return ret; + } - if (offset == delimiter && !(flags & COBS_FLAG_TRAILING_DELIMITER)) { - return -EINVAL; - } - - /* Verify we have enough data */ - if (src->len < (offset - 1)) { - return -EINVAL; - } - - /* Copy offset-1 bytes */ - for (uint8_t i = 0; i < offset - 1; i++) { - uint8_t byte = net_buf_pull_u8(src); - - if (byte == delimiter) { - return -EINVAL; - } - net_buf_add_u8(dst, byte); - } - - /* If this wasn't a maximum offset and we have more data, - * there was a delimiter here in the original data - */ - if (offset != 0xFF && src->len > 0) { - net_buf_add_u8(dst, delimiter); + if (close && (enc->flags & COBS_FLAG_TRAILING_DELIMITER) != 0U) { + ret = enc->cb(&sentinel, 1, enc->cb_user_data); + if (ret < 0) { + cobs_encoder_reset(enc); + return ret; } } + cobs_encoder_reset(enc); + return 0; } + +int cobs_encoder_init(struct cobs_encoder *enc, cobs_stream_cb cb, void *user_data, uint32_t flags) +{ + if (cb == NULL) { + return -EINVAL; + } + + __ASSERT_NO_MSG(enc != NULL); + + enc->cb = cb; + enc->cb_user_data = user_data; + enc->flags = flags; + + cobs_encoder_reset(enc); + + return 0; +} + +int cobs_encoder_close(struct cobs_encoder *enc) +{ + __ASSERT_NO_MSG(enc != NULL); + + return cobs_encoder_finish(enc, true); +} + +int cobs_encoder_write(struct cobs_encoder *enc, const uint8_t *buf, size_t len) +{ + int ret; + + __ASSERT_NO_MSG(enc != NULL); + __ASSERT_NO_MSG(len <= INT_MAX); + + for (size_t i = 0; i < len; ++i) { + /* Finish if group is full */ + if (enc->fragment[0] == 0xff) { + ret = cobs_encoder_finish(enc, false); + if (ret < 0) { + return ret; + } + } + + if (buf[i] == 0x00) { + ret = cobs_encoder_finish(enc, false); + if (ret < 0) { + return ret; + } + + continue; + } + + enc->fragment[enc->fragment[0]] = buf[i]; + enc->fragment[0]++; + } + + return len; +} + +static inline void cobs_decoder_reset(struct cobs_decoder *dec) +{ + dec->code = 0xff; + dec->code_index = 0; +} + +static inline bool cobs_decoder_needs_more_data(struct cobs_decoder *dec) +{ + return dec->code_index != 0; +} + +int cobs_decoder_init(struct cobs_decoder *dec, cobs_stream_cb cb, void *user_data, uint32_t flags) +{ + if (cb == NULL) { + return -EINVAL; + } + + __ASSERT_NO_MSG(dec != NULL); + + dec->cb = cb; + dec->cb_user_data = user_data; + dec->flags = flags; + + cobs_decoder_reset(dec); + + return 0; +} + +int cobs_decoder_close(struct cobs_decoder *dec) +{ + int ret; + + __ASSERT_NO_MSG(dec != NULL); + + ret = cobs_decoder_needs_more_data(dec) ? -EINVAL : 0; + cobs_decoder_reset(dec); + + return ret; +} + +int cobs_decoder_write(struct cobs_decoder *dec, const uint8_t *buf, size_t len) +{ + uint8_t sentinel = COBS_FLAG_CUSTOM_DELIMITER(dec->flags); + int ret; + + __ASSERT_NO_MSG(dec != NULL); + __ASSERT_NO_MSG(len <= INT_MAX); + + for (size_t i = 0; i < len; ++i) { + uint8_t data = buf[i] ^ sentinel; + + if (data == 0x00) { + if ((dec->flags & COBS_FLAG_TRAILING_DELIMITER) == 0U || + cobs_decoder_needs_more_data(dec)) { + /* Decoder shouldn't get delimiters or unexpected end of data */ + cobs_decoder_reset(dec); + return -EINVAL; + } + + /* Notify frame delimiter was seen */ + ret = dec->cb(NULL, 0, dec->cb_user_data); + if (ret < 0) { + cobs_decoder_reset(dec); + return ret; + } + + /* Reset state */ + cobs_decoder_reset(dec); + continue; + } + + if (dec->code_index > 0) { + ret = dec->cb(&data, 1, dec->cb_user_data); + if (ret < 0) { + cobs_decoder_reset(dec); + return ret; + } + + dec->code_index--; + continue; + } + + dec->code_index = data; + + if (dec->code != 0xff) { + /* Group finished, output zero byte */ + data = 0x00; + + ret = dec->cb(&data, 1, dec->cb_user_data); + if (ret < 0) { + cobs_decoder_reset(dec); + return ret; + } + } + + dec->code = dec->code_index; + dec->code_index--; + } + + return len; +} diff --git a/tests/lib/cobs/src/main.c b/tests/lib/cobs/src/main.c index c58bace63de..5ccaeb55340 100644 --- a/tests/lib/cobs/src/main.c +++ b/tests/lib/cobs/src/main.c @@ -60,18 +60,20 @@ struct cobs_test_item { size_t decoded_len; const uint8_t *encoded; size_t encoded_len; - uint8_t delimiter; + uint32_t flags; }; #define U8(...) (uint8_t[]) __VA_ARGS__ -#define COBS_ITEM(d, e, del, n) \ - {.name = n, \ - .decoded = d, \ - .decoded_len = sizeof(d), \ - .encoded = e, \ - .encoded_len = sizeof(e), \ - .delimiter = del} +#define COBS_ITEM(d, e, f, n) \ + { \ + .name = n, \ + .decoded = d, \ + .decoded_len = sizeof(d), \ + .encoded = e, \ + .encoded_len = sizeof(e), \ + .flags = f, \ + } static const struct cobs_test_item cobs_dataset[] = { COBS_ITEM(U8({}), U8({0x01}), COBS_DEFAULT_DELIMITER, "Empty"), @@ -91,12 +93,16 @@ static const struct cobs_test_item cobs_dataset[] = { COBS_ITEM(U8({'1', '2', '3', '4', '5', 0x00, '6', '7', '8', '9', 0x00}), U8({0x06, '1', '2', '3', '4', '5', 0x05, '6', '7', '8', '9', 0x01}), COBS_DEFAULT_DELIMITER, "Trailing zero"), - COBS_ITEM(U8({}), U8({0x01}), 0x7F, "Empty with custom delimiter 0x7F"), - COBS_ITEM(U8({'1'}), U8({0x02, '1'}), 0x7F, "One char with custom delimiter 0x7F"), - COBS_ITEM(U8({0x7F}), U8({0x01, 0x01}), 0x7F, "One 0x7F delimiter"), - COBS_ITEM(U8({0x7F, 0x7F}), U8({0x01, 0x01, 0x01}), 0x7F, "Two 0x7F delimiters"), - COBS_ITEM(U8({0x7F, 0x7F, 0x7F}), U8({0x01, 0x01, 0x01, 0x01}), 0x7F, - "Three 0x7F delimiters"), + COBS_ITEM(U8({}), U8({0x01 ^ 0x7F}), COBS_FLAG_CUSTOM_DELIMITER(0x7F), + "Empty with custom delimiter 0x7F"), + COBS_ITEM(U8({'1'}), U8({0x7D, '1' ^ 0x7F}), COBS_FLAG_CUSTOM_DELIMITER(0x7F), + "One char with custom delimiter 0x7F"), + COBS_ITEM(U8({0x7F}), U8({0x7D, 0x00}), COBS_FLAG_CUSTOM_DELIMITER(0x7F), + "One 0x7F delimiter"), + COBS_ITEM(U8({0x7F, 0x7F}), U8({0x7C, 0x00, 0x00}), COBS_FLAG_CUSTOM_DELIMITER(0x7F), + "Two 0x7F delimiters"), + COBS_ITEM(U8({0x7F, 0x7F, 0x7F}), U8({0x7B, 0x00, 0x00, 0x00}), + COBS_FLAG_CUSTOM_DELIMITER(0x7F), "Three 0x7F delimiters"), COBS_ITEM( U8({'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'a', 'b', @@ -354,13 +360,12 @@ ZTEST_F(cobs_tests, test_encode) int ret; ARRAY_FOR_EACH(cobs_dataset, idx) { - uint8_t delimiter = cobs_dataset[idx].delimiter; + uint32_t flags = cobs_dataset[idx].flags; net_buf_add_mem(fixture->test_data, cobs_dataset[idx].decoded, cobs_dataset[idx].decoded_len); - ret = cobs_encode(fixture->test_data, fixture->encoded, - COBS_FLAG_CUSTOM_DELIMITER(delimiter)); + ret = cobs_encode(fixture->test_data, fixture->encoded, flags); zassert_ok(ret, "COBS encoding failed for %s", cobs_dataset[idx].name); zassert_equal(cobs_dataset[idx].encoded_len, fixture->encoded->len, "Encoded length does not match expected for %s", @@ -383,13 +388,12 @@ ZTEST_F(cobs_tests, test_decode) int ret; ARRAY_FOR_EACH(cobs_dataset, idx) { - uint8_t delimiter = cobs_dataset[idx].delimiter; + uint32_t flags = cobs_dataset[idx].flags; net_buf_add_mem(fixture->test_data, cobs_dataset[idx].decoded, cobs_dataset[idx].decoded_len); - ret = cobs_decode(fixture->encoded, fixture->test_data, - COBS_FLAG_CUSTOM_DELIMITER(delimiter)); + ret = cobs_decode(fixture->encoded, fixture->test_data, flags); zassert_ok(ret, "COBS decoding failed for %s", cobs_dataset[idx].name); zassert_equal(cobs_dataset[idx].decoded_len, fixture->test_data->len, "Decoded length does not match expected for %s", @@ -412,14 +416,14 @@ ZTEST_F(cobs_tests, test_encode_trailing_delimiter) int ret; ARRAY_FOR_EACH(cobs_dataset, idx) { - uint8_t delimiter = cobs_dataset[idx].delimiter; + uint32_t flags = cobs_dataset[idx].flags; + uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); net_buf_add_mem(fixture->test_data, cobs_dataset[idx].decoded, cobs_dataset[idx].decoded_len); ret = cobs_encode(fixture->test_data, fixture->encoded, - COBS_FLAG_TRAILING_DELIMITER | - COBS_FLAG_CUSTOM_DELIMITER(delimiter)); + COBS_FLAG_TRAILING_DELIMITER | flags); zassert_ok(ret, "COBS encoding failed for %s", cobs_dataset[idx].name); zassert_equal(cobs_dataset[idx].encoded_len + 1, fixture->encoded->len, "Encoded length does not match expected for %s", @@ -445,7 +449,8 @@ ZTEST_F(cobs_tests, test_decode_trailing_delimiter) int ret; ARRAY_FOR_EACH(cobs_dataset, idx) { - uint8_t delimiter = cobs_dataset[idx].delimiter; + uint32_t flags = cobs_dataset[idx].flags; + uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); net_buf_add_mem(fixture->test_data, cobs_dataset[idx].decoded, cobs_dataset[idx].decoded_len); @@ -453,8 +458,7 @@ ZTEST_F(cobs_tests, test_decode_trailing_delimiter) net_buf_add_u8(fixture->encoded, delimiter); ret = cobs_decode(fixture->encoded, fixture->test_data, - COBS_FLAG_TRAILING_DELIMITER | - COBS_FLAG_CUSTOM_DELIMITER(delimiter)); + COBS_FLAG_TRAILING_DELIMITER | flags); zassert_ok(ret, "COBS decoding failed for %s", cobs_dataset[idx].name); zassert_equal(cobs_dataset[idx].decoded_len, fixture->test_data->len, "Decoded length does not match expected for %s", @@ -479,7 +483,7 @@ ZTEST_F(cobs_tests, test_cobs_invalid_delim_pos) net_buf_add_mem(fixture->encoded, data_enc, sizeof(data_enc)); ret = cobs_decode(fixture->encoded, fixture->decoded, 0); - zassert_true(ret == -EINVAL, "Decoding invalid delimiter caught"); + zassert_equal(ret, -EINVAL, "Decoding invalid delimiter caught"); } ZTEST_F(cobs_tests, test_cobs_consecutive_delims) @@ -489,7 +493,7 @@ ZTEST_F(cobs_tests, test_cobs_consecutive_delims) net_buf_add_mem(fixture->encoded, data_enc, sizeof(data_enc)); ret = cobs_decode(fixture->encoded, fixture->decoded, 0); - zassert_true(ret == -EINVAL, "Decoding consecutive delimiters not caught"); + zassert_equal(ret, -EINVAL, "Decoding consecutive delimiters not caught"); } ZTEST_F(cobs_tests, test_cobs_invalid_overrun) @@ -499,5 +503,5 @@ ZTEST_F(cobs_tests, test_cobs_invalid_overrun) net_buf_add_mem(fixture->encoded, data_enc, sizeof(data_enc)); ret = cobs_decode(fixture->encoded, fixture->decoded, 0); - zassert_true(ret == -EINVAL, "Decoding insufficient data not caught"); + zassert_equal(ret, -EINVAL, "Decoding insufficient data not caught"); }