/* * Copyright (c) 2024 Kelly Helmut Lord * * SPDX-License-Identifier: Apache-2.0 */ #include <errno.h> #include <stdint.h> #include <zephyr/data/cobs.h> int cobs_encode(struct net_buf *src, struct net_buf *dst, uint32_t flags) { uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); /* 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) { 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); } return 0; } int cobs_decode(struct net_buf *src, struct net_buf *dst, uint32_t flags) { uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); if (flags & COBS_FLAG_TRAILING_DELIMITER) { uint8_t end_delim = net_buf_remove_u8(src); if (end_delim != delimiter) { return -EINVAL; } } while (src->len > 0) { /* Pull the COBS offset byte */ uint8_t offset = net_buf_pull_u8(src); 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); } } return 0; }