boot_serial: Port encoding to use cddl-gen
Non-generated. Using cbor_encode directly
This removes the dependence on TinyCBOR.
Fixes #978
Signed-off-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no>
diff --git a/boot/boot_serial/pkg.yml b/boot/boot_serial/pkg.yml
index f1431c7..19f9a32 100644
--- a/boot/boot_serial/pkg.yml
+++ b/boot/boot_serial/pkg.yml
@@ -28,7 +28,6 @@
pkg.deps:
- "@apache-mynewt-core/hw/hal"
- "@apache-mynewt-core/kernel/os"
- - "@apache-mynewt-core/encoding/tinycbor"
- "@apache-mynewt-core/encoding/base64"
- "@mcuboot/boot/mynewt/flash_map_backend"
- "@mcuboot/boot/mynewt/boot_uart"
diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c
index 5fa794a..88c0029 100644
--- a/boot/boot_serial/src/boot_serial.c
+++ b/boot/boot_serial/src/boot_serial.c
@@ -25,6 +25,7 @@
#include "sysflash/sysflash.h"
#include "bootutil/bootutil_log.h"
+#include "cbor_encode.h"
#ifdef __ZEPHYR__
#include <power/reboot.h>
@@ -33,8 +34,6 @@
#include <drivers/flash.h>
#include <sys/crc.h>
#include <sys/base64.h>
-#include <tinycbor/cbor.h>
-#include <tinycbor/cbor_buf_reader.h>
#else
#include <bsp/bsp.h>
#include <hal/hal_system.h>
@@ -42,7 +41,6 @@
#include <os/os_cputime.h>
#include <crc/crc16.h>
#include <base64/base64.h>
-#include <tinycbor/cbor.h>
#endif /* __ZEPHYR__ */
#include <flash_map_backend/flash_map_backend.h>
@@ -97,28 +95,13 @@
static char bs_obuf[BOOT_SERIAL_OUT_MAX];
-static int bs_cbor_writer(struct cbor_encoder_writer *, const char *data,
- int len);
static void boot_serial_output(void);
-static struct cbor_encoder_writer bs_writer = {
- .write = bs_cbor_writer
+static cbor_state_backups_t dummy_backups;
+static cbor_state_t cbor_state = {
+ .backups = &dummy_backups
};
-static CborEncoder bs_root;
-static CborEncoder bs_rsp;
-int
-bs_cbor_writer(struct cbor_encoder_writer *cew, const char *data, int len)
-{
- if (cew->bytes_written + len > sizeof(bs_obuf)) {
- return CborErrorOutOfMemory;
- }
-
- memcpy(&bs_obuf[cew->bytes_written], data, len);
- cew->bytes_written += len;
-
- return 0;
-}
/*
* Convert version into string without use of snprintf().
@@ -172,17 +155,15 @@
static void
bs_list(char *buf, int len)
{
- CborEncoder images;
- CborEncoder image;
struct image_header hdr;
uint8_t tmpbuf[64];
- int slot, area_id;
+ uint32_t slot, area_id;
const struct flash_area *fap;
uint8_t image_index;
- cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
- cbor_encode_text_stringz(&bs_rsp, "images");
- cbor_encoder_create_array(&bs_rsp, &images, CborIndefiniteLength);
+ map_start_encode(&cbor_state, 1);
+ tstrx_put(&cbor_state, "images");
+ list_start_encode(&cbor_state, 5);
image_index = 0;
IMAGES_ITER(image_index) {
for (slot = 0; slot < 2; slot++) {
@@ -201,24 +182,24 @@
}
flash_area_close(fap);
- cbor_encoder_create_map(&images, &image, CborIndefiniteLength);
+ map_start_encode(&cbor_state, 20);
#if (BOOT_IMAGE_NUMBER > 1)
- cbor_encode_text_stringz(&image, "image");
- cbor_encode_int(&image, image_index);
+ tstrx_put(&cbor_state, "image");
+ uintx32_put(&cbor_state, image_index);
#endif
- cbor_encode_text_stringz(&image, "slot");
- cbor_encode_int(&image, slot);
- cbor_encode_text_stringz(&image, "version");
+ tstrx_put(&cbor_state, "slot");
+ uintx32_put(&cbor_state, slot);
+ tstrx_put(&cbor_state, "version");
bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
- cbor_encode_text_stringz(&image, (char *)tmpbuf);
- cbor_encoder_close_container(&images, &image);
+ tstrx_put_term(&cbor_state, (char *)tmpbuf);
+ map_end_encode(&cbor_state, 20);
}
}
- cbor_encoder_close_container(&bs_rsp, &images);
- cbor_encoder_close_container(&bs_root, &bs_rsp);
+ list_end_encode(&cbor_state, 5);
+ map_end_encode(&cbor_state, 1);
boot_serial_output();
}
@@ -229,10 +210,10 @@
bs_upload(char *buf, int len)
{
const uint8_t *img_data = NULL;
- long long int off = UINT_MAX;
+ long long int off = UINT64_MAX;
size_t img_blen = 0;
uint8_t rem_bytes;
- long long int data_len = UINT_MAX;
+ long long int data_len = UINT64_MAX;
int img_num;
size_t slen;
const struct flash_area *fap = NULL;
@@ -255,7 +236,7 @@
*/
struct Upload upload;
- size_t decoded_len;
+ uint32_t decoded_len;
bool result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len);
if (!result || (len != decoded_len)) {
@@ -286,7 +267,7 @@
}
}
- if (off == UINT_MAX || img_data == NULL) {
+ if (off == UINT64_MAX || img_data == NULL) {
/*
* Offset must be set in every block.
*/
@@ -403,14 +384,14 @@
out:
BOOT_LOG_INF("RX: 0x%x", rc);
- cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
- cbor_encode_text_stringz(&bs_rsp, "rc");
- cbor_encode_int(&bs_rsp, rc);
+ map_start_encode(&cbor_state, 10);
+ tstrx_put(&cbor_state, "rc");
+ uintx32_put(&cbor_state, rc);
if (rc == 0) {
- cbor_encode_text_stringz(&bs_rsp, "off");
- cbor_encode_uint(&bs_rsp, curr_off);
+ tstrx_put(&cbor_state, "off");
+ uintx32_put(&cbor_state, curr_off);
}
- cbor_encoder_close_container(&bs_root, &bs_rsp);
+ map_end_encode(&cbor_state, 10);
boot_serial_output();
flash_area_close(fap);
@@ -422,10 +403,10 @@
static void
bs_empty_rsp(char *buf, int len)
{
- cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
- cbor_encode_text_stringz(&bs_rsp, "rc");
- cbor_encode_int(&bs_rsp, 0);
- cbor_encoder_close_container(&bs_root, &bs_rsp);
+ map_start_encode(&cbor_state, 10);
+ tstrx_put(&cbor_state, "rc");
+ uintx32_put(&cbor_state, 0);
+ map_end_encode(&cbor_state, 10);
boot_serial_output();
}
@@ -472,8 +453,9 @@
buf += sizeof(*hdr);
len -= sizeof(*hdr);
- bs_writer.bytes_written = 0;
- cbor_encoder_init(&bs_root, &bs_writer, 0);
+ cbor_state.payload_mut = (uint8_t *)bs_obuf;
+ cbor_state.payload_end = (const uint8_t *)bs_obuf
+ + sizeof(bs_obuf);
/*
* Limited support for commands.
@@ -516,7 +498,7 @@
char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
data = bs_obuf;
- len = bs_writer.bytes_written;
+ len = (uint32_t)cbor_state.payload_mut - (uint32_t)bs_obuf;
bs_hdr->nh_op++;
bs_hdr->nh_flags = 0;
diff --git a/boot/boot_serial/src/cbor_encode.c b/boot/boot_serial/src/cbor_encode.c
new file mode 100644
index 0000000..c2e9191
--- /dev/null
+++ b/boot/boot_serial/src/cbor_encode.c
@@ -0,0 +1,440 @@
+/*
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 8f9358a0b4b0e9b0cd579f0988056ef0b60760e4
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include "cbor_encode.h"
+#include "cbor_common.h"
+
+_Static_assert((sizeof(size_t) == sizeof(void *)),
+ "This code needs size_t to be the same length as pointers.");
+
+uint8_t get_additional(uint32_t len, uint8_t value0)
+{
+ switch(len) {
+ case 0: return value0;
+ case 1: return 24;
+ case 2: return 25;
+ case 3: return 25;
+ case 4: return 26;
+ case 5: return 26;
+ case 6: return 26;
+ case 7: return 26;
+ case 8: return 27;
+ }
+
+ cbor_assert(false, NULL);
+ return 0;
+}
+
+static bool encode_header_byte(cbor_state_t *state,
+ cbor_major_type_t major_type, uint8_t additional)
+{
+ if ((state->payload + 1) > state->payload_end) {
+ FAIL();
+ }
+
+ cbor_assert(additional < 32, NULL);
+
+ *(state->payload_mut++) = (major_type << 5) | (additional & 0x1F);
+ return true;
+}
+
+/** Encode a single value.
+ */
+static bool value_encode_len(cbor_state_t *state, cbor_major_type_t major_type,
+ const void *const input, uint32_t result_len)
+{
+ uint8_t *u8_result = (uint8_t *)input;
+
+ if ((state->payload + 1 + result_len) > state->payload_end) {
+ FAIL();
+ }
+
+ if (!encode_header_byte(state, major_type,
+ get_additional(result_len, u8_result[0]))) {
+ FAIL();
+ }
+ state->payload_mut--;
+ cbor_trace();
+ state->payload_mut++;
+
+#ifdef CONFIG_BIG_ENDIAN
+ memcpy(state->payload_mut, u8_result, result_len);
+ state->payload_mut += result_len;
+#else
+ for (; result_len > 0; result_len--) {
+ *(state->payload_mut++) = u8_result[result_len - 1];
+ }
+#endif
+
+ state->elem_count++;
+ return true;
+}
+
+
+static uint32_t get_result_len(const void *const input, uint32_t max_result_len)
+{
+ uint8_t *u8_result = (uint8_t *)input;
+
+ for (; max_result_len > 0; max_result_len--) {
+ if (u8_result[max_result_len - 1] != 0) {
+ break;
+ }
+ }
+ if ((max_result_len == 1) && (u8_result[0] <= VALUE_IN_HEADER)) {
+ max_result_len = 0;
+ }
+
+ return max_result_len;
+}
+
+
+static bool value_encode(cbor_state_t *state, cbor_major_type_t major_type,
+ const void *const input, uint32_t max_result_len)
+{
+ cbor_assert(max_result_len != 0, "0-length result not supported.\n");
+ return value_encode_len(state, major_type, input,
+ get_result_len(input, max_result_len));
+}
+
+
+bool intx32_put(cbor_state_t *state, int32_t input)
+{
+ cbor_major_type_t major_type;
+
+ if (input < 0) {
+ major_type = CBOR_MAJOR_TYPE_NINT;
+ /* Convert from CBOR's representation. */
+ input = -1 - input;
+ } else {
+ major_type = CBOR_MAJOR_TYPE_PINT;
+ input = input;
+ }
+
+ if (!value_encode(state, major_type, &input, 4)) {
+ FAIL();
+ }
+
+ return true;
+}
+
+bool intx32_encode(cbor_state_t *state, const int32_t *input)
+{
+ return intx32_put(state, *input);
+}
+
+
+static bool uint32_encode(cbor_state_t *state, const uint32_t *input,
+ cbor_major_type_t major_type)
+{
+ if (!value_encode(state, major_type, input, 4)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+bool uintx32_encode(cbor_state_t *state, const uint32_t *input)
+{
+ if (!uint32_encode(state, input, CBOR_MAJOR_TYPE_PINT)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+bool uintx32_put(cbor_state_t *state, uint32_t input)
+{
+ if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PINT)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+static bool strx_start_encode(cbor_state_t *state,
+ const cbor_string_type_t *input, cbor_major_type_t major_type)
+{
+ if (input->value && ((get_result_len(&input->len, sizeof(input->len))
+ + 1 + input->len + (size_t)state->payload)
+ > (size_t)state->payload_end)) {
+ FAIL();
+ }
+ if (!uint32_encode(state, &input->len, major_type)) {
+ FAIL();
+ }
+
+ return true;
+}
+
+
+static bool primx_encode(cbor_state_t *state, uint32_t input)
+{
+ if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PRIM)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+static uint32_t remaining_str_len(cbor_state_t *state)
+{
+ uint32_t max_len = (size_t)state->payload_end - (size_t)state->payload;
+ uint32_t result_len = get_result_len(&max_len, sizeof(uint32_t));
+ return max_len - result_len - 1;
+}
+
+
+bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result)
+{
+ if (!new_backup(state, 0)) {
+ FAIL();
+ }
+
+ uint32_t max_len = remaining_str_len(state);
+
+ /* Encode a dummy header */
+ if (!uint32_encode(state, &max_len,
+ CBOR_MAJOR_TYPE_BSTR)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+bool bstrx_cbor_end_encode(cbor_state_t *state)
+{
+ const uint8_t *payload = state->payload;
+
+ if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
+ FAIL();
+ }
+ cbor_string_type_t value;
+
+ value.value = state->payload_end - remaining_str_len(state);
+ value.len = (size_t)payload - (size_t)value.value;
+
+ /* Reencode header of list now that we know the number of elements. */
+ if (!bstrx_encode(state, &value)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+static bool strx_encode(cbor_state_t *state,
+ const cbor_string_type_t *input, cbor_major_type_t major_type)
+{
+ if (!strx_start_encode(state, input, major_type)) {
+ FAIL();
+ }
+ if (state->payload_mut != input->value) {
+ memmove(state->payload_mut, input->value, input->len);
+ }
+ state->payload += input->len;
+ return true;
+}
+
+
+bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
+{
+ return strx_encode(state, input, CBOR_MAJOR_TYPE_BSTR);
+}
+
+
+bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
+{
+ return strx_encode(state, input, CBOR_MAJOR_TYPE_TSTR);
+}
+
+
+static bool list_map_start_encode(cbor_state_t *state, uint32_t max_num,
+ cbor_major_type_t major_type)
+{
+#ifdef CDDL_CBOR_CANONICAL
+ if (!new_backup(state, 0)) {
+ FAIL();
+ }
+
+ /* Encode dummy header with max number of elements. */
+ if (!uint32_encode(state, &max_num, major_type)) {
+ FAIL();
+ }
+ state->elem_count--; /* Because of dummy header. */
+#else
+ if (!encode_header_byte(state, major_type, 31)) {
+ FAIL();
+ }
+#endif
+ return true;
+}
+
+
+bool list_start_encode(cbor_state_t *state, uint32_t max_num)
+{
+ return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
+}
+
+
+bool map_start_encode(cbor_state_t *state, uint32_t max_num)
+{
+ return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
+}
+
+
+bool list_map_end_encode(cbor_state_t *state, uint32_t max_num,
+ cbor_major_type_t major_type)
+{
+#ifdef CDDL_CBOR_CANONICAL
+ uint32_t list_count = ((major_type == CBOR_MAJOR_TYPE_LIST) ?
+ state->elem_count
+ : (state->elem_count / 2));
+
+ const uint8_t *payload = state->payload;
+ uint32_t max_header_len = get_result_len(&max_num, 4);
+ uint32_t header_len = get_result_len(&list_count, 4);
+
+ if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
+ FAIL();
+ }
+
+ cbor_print("list_count: %d\r\n", list_count);
+
+ /* Reencode header of list now that we know the number of elements. */
+ if (!(uint32_encode(state, &list_count, major_type))) {
+ FAIL();
+ }
+
+ if (max_header_len != header_len) {
+ const uint8_t *start = state->payload + max_header_len - header_len;
+ uint32_t body_size = payload - start;
+ memmove(state->payload_mut,
+ state->payload + max_header_len - header_len,
+ body_size);
+ /* Reset payload pointer to end of list */
+ state->payload += body_size;
+ } else {
+ /* Reset payload pointer to end of list */
+ state->payload = payload;
+ }
+#else
+ if (!encode_header_byte(state, CBOR_MAJOR_TYPE_PRIM, 31)) {
+ FAIL();
+ }
+#endif
+ return true;
+}
+
+
+bool list_end_encode(cbor_state_t *state, uint32_t max_num)
+{
+ return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
+}
+
+
+bool map_end_encode(cbor_state_t *state, uint32_t max_num)
+{
+ return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
+}
+
+
+bool nilx_put(cbor_state_t *state, const void *input)
+{
+ (void)input;
+ return primx_encode(state, 22);
+}
+
+
+bool boolx_encode(cbor_state_t *state, const bool *input)
+{
+ if (!primx_encode(state, *input + BOOL_TO_PRIM)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+bool boolx_put(cbor_state_t *state, bool input)
+{
+ if (!primx_encode(state, input + BOOL_TO_PRIM)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+bool double_encode(cbor_state_t *state, double *input)
+{
+ if (!value_encode(state, CBOR_MAJOR_TYPE_PRIM, input,
+ sizeof(*input))) {
+ FAIL();
+ }
+
+ return true;
+}
+
+
+bool double_put(cbor_state_t *state, double input)
+{
+ return double_encode(state, &input);
+}
+
+
+bool any_encode(cbor_state_t *state, void *input)
+{
+ return nilx_put(state, input);
+}
+
+
+bool tag_encode(cbor_state_t *state, uint32_t tag)
+{
+ if (!value_encode(state, CBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) {
+ FAIL();
+ }
+ state->elem_count--;
+
+ return true;
+}
+
+
+bool multi_encode(uint32_t min_encode,
+ uint32_t max_encode,
+ const uint32_t *num_encode,
+ cbor_encoder_t encoder,
+ cbor_state_t *state,
+ const void *input,
+ uint32_t result_len)
+{
+ if (!PTR_VALUE_IN_RANGE(uint32_t, num_encode, NULL, &max_encode)) {
+ FAIL();
+ }
+ for (uint32_t i = 0; i < *num_encode; i++) {
+ if (!encoder(state, (const uint8_t *)input + i*result_len)) {
+ FAIL();
+ }
+ }
+ cbor_print("Found %zu elements.\n", *num_encode);
+ return true;
+}
+
+
+bool present_encode(const uint32_t *present,
+ cbor_encoder_t encoder,
+ cbor_state_t *state,
+ const void *input)
+{
+ uint32_t num_encode = *present;
+ bool retval = multi_encode(0, 1, &num_encode, encoder, state, input, 0);
+ return retval;
+}
diff --git a/boot/boot_serial/src/cbor_encode.h b/boot/boot_serial/src/cbor_encode.h
new file mode 100644
index 0000000..ca0a8f8
--- /dev/null
+++ b/boot/boot_serial/src/cbor_encode.h
@@ -0,0 +1,150 @@
+/*
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 8f9358a0b4b0e9b0cd579f0988056ef0b60760e4
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef CBOR_ENCODE_H__
+#define CBOR_ENCODE_H__
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "cbor_common.h"
+
+
+/** Encode a PINT/NINT into a int32_t.
+ *
+ * @param[inout] state The current state of the decoding.
+ * @param[out] result Where to place the encoded value.
+ *
+ * @retval true Everything is ok.
+ * @retval false If the payload is exhausted.
+ */
+bool intx32_encode(cbor_state_t *state, const int32_t *input);
+bool intx32_put(cbor_state_t *state, int32_t result);
+
+/** Encode a PINT into a uint32_t. */
+bool uintx32_encode(cbor_state_t *state, const uint32_t *result);
+bool uintx32_put(cbor_state_t *state, uint32_t result);
+
+/** Encode a BSTR header.
+ *
+ * The rest of the string can be encoded as CBOR.
+ * A state backup is created to keep track of the element count.
+ *
+ * @retval true Header encoded correctly
+ * @retval false Header encoded incorrectly, or backup failed.
+ */
+bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result);
+
+/** Finalize encoding a CBOR-encoded BSTR.
+ *
+ * Restore element count from backup.
+ */
+bool bstrx_cbor_end_encode(cbor_state_t *state);
+
+/** Encode a BSTR, */
+bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *result);
+
+/** Encode a TSTR. */
+bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *result);
+
+#define tstrx_put(state, string) \
+ tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, len = (sizeof(string) - 1)})
+
+#define tstrx_put_term(state, string) \
+ tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, len = strlen((const char *)string)})
+
+/** Encode a LIST header.
+ *
+ * The contents of the list can be decoded via subsequent function calls.
+ * A state backup is created to keep track of the element count.
+ */
+bool list_start_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode a MAP header. */
+bool map_start_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode end of a LIST. Do some checks and deallocate backup. */
+bool list_end_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode end of a MAP. Do some checks and deallocate backup. */
+bool map_end_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode a "nil" primitive value. result should be NULL. */
+bool nilx_put(cbor_state_t *state, const void *result);
+
+/** Encode a boolean primitive value. */
+bool boolx_encode(cbor_state_t *state, const bool *result);
+bool boolx_put(cbor_state_t *state, bool result);
+
+/** Encode a float */
+bool float_encode(cbor_state_t *state, double *result);
+bool float_put(cbor_state_t *state, double result);
+
+/** Dummy encode "any": Encode a "nil". input should be NULL. */
+bool any_encode(cbor_state_t *state, void *input);
+
+/** Encode a tag. */
+bool tag_encode(cbor_state_t *state, uint32_t tag);
+
+/** Encode 0 or more elements with the same type and constraints.
+ *
+ * @details This must not necessarily encode all elements in a list. E.g. if
+ * the list contains 3 INTS between 0 and 100 followed by 0 to 2 BSTRs
+ * with length 8, that could be done with:
+ *
+ * @code{c}
+ * uint32_t int_min = 0;
+ * uint32_t int_max = 100;
+ * uint32_t bstr_size = 8;
+ * uint32_t ints[3];
+ * cbor_string_type_t bstrs[2] = <initialize here>;
+ * bool res;
+ *
+ * res = list_start_encode(state, 5);
+ * // check res
+ * res = multi_encode(3, 3, &num_encode, uintx32_encode, state,
+ * ints, 4);
+ * // check res
+ * res = multi_encode(0, 2, &num_encode, strx_encode, state,
+ * bstrs, sizeof(cbor_string_type_t));
+ * // check res
+ * res = list_end_encode(state, 5);
+ * // check res
+ * @endcode
+ *
+ * @param[in] min_encode The minimum acceptable number of elements.
+ * @param[in] max_encode The maximum acceptable number of elements.
+ * @param[in] num_encode The actual number of elements.
+ * @param[in] encoder The encoder function to call under the hood. This
+ * function will be called with the provided arguments
+ * repeatedly until the function fails (returns false)
+ * or until it has been called @p max_encode times.
+ * result is moved @p result_len bytes for each call
+ * to @p encoder, i.e. @p result refers to an array
+ * of result variables.
+ * @param[in] input Source of the encoded values. Must be an array
+ * of length at least @p max_encode.
+ * @param[in] result_len The length of the result variables. Must be the
+ * length of the elements in result.
+ *
+ * @retval true If at least @p min_encode variables were correctly encoded.
+ * @retval false If @p encoder failed before having encoded @p min_encode
+ * values.
+ */
+bool multi_encode(uint32_t min_encode, uint32_t max_encode, const uint32_t *num_encode,
+ cbor_encoder_t encoder, cbor_state_t *state, const void *input,
+ uint32_t result_len);
+
+bool present_encode(const uint32_t *present,
+ cbor_encoder_t encoder,
+ cbor_state_t *state,
+ const void *input);
+
+#endif /* CBOR_ENCODE_H__ */
diff --git a/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c b/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
index 53a7199..83ba50a 100644
--- a/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
+++ b/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
@@ -18,7 +18,6 @@
*/
#include <flash_map_backend/flash_map_backend.h>
-#include <tinycbor/cborconstants_p.h>
#include "boot_test.h"
diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt
index 29cff0a..259e903 100644
--- a/boot/zephyr/CMakeLists.txt
+++ b/boot/zephyr/CMakeLists.txt
@@ -239,6 +239,7 @@
zephyr_sources(${BOOT_DIR}/boot_serial/src/boot_serial.c)
zephyr_sources(${BOOT_DIR}/boot_serial/src/serial_recovery_cbor.c)
zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_decode.c)
+ zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_encode.c)
zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_common.c)
zephyr_include_directories(${BOOT_DIR}/bootutil/include)
diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig
index 932110d..aa4ee1f 100644
--- a/boot/zephyr/Kconfig
+++ b/boot/zephyr/Kconfig
@@ -469,7 +469,6 @@
select SERIAL
select UART_INTERRUPT_DRIVEN
select BASE64
- select TINYCBOR
help
If y, enables a serial-port based update mode. This allows
MCUboot itself to load update images into flash over a UART.