serial_recovery: Add copied and generated CBOR decoding code files
Generated serial_recovery_cbor.c and serial_recovery_cbor.h
Copied cbor_decode.c and cbor_decode.h
This commit is the result of running
./regenerate_serial_recovery_cbor.sh "2020 Nordic Semiconductor ASA"
Signed-off-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no>
diff --git a/boot/boot_serial/src/cbor_decode.c b/boot/boot_serial/src/cbor_decode.c
new file mode 100644
index 0000000..9d27bbb
--- /dev/null
+++ b/boot/boot_serial/src/cbor_decode.c
@@ -0,0 +1,417 @@
+/*
+ * This file has been copied from the cddl_gen submodule.
+ * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ */
+
+/*
+ * 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_decode.h"
+
+/** Enumeration representing the major types available in CBOR.
+ *
+ * The major type is represented in the 3 first bits of the header byte.
+ */
+typedef enum
+{
+ CBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer
+ CBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer
+ CBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String
+ CBOR_MAJOR_TYPE_TSTR = 3, ///! Text String
+ CBOR_MAJOR_TYPE_LIST = 4, ///! List
+ CBOR_MAJOR_TYPE_MAP = 5, ///! Map
+ CBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag
+ CBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type
+} cbor_major_type_t;
+
+/** Return value length from additional value.
+ */
+static uint32_t additional_len(uint8_t additional)
+{
+ if (24 <= additional && additional <= 27) {
+ /* 24 => 1
+ * 25 => 2
+ * 26 => 4
+ * 27 => 8
+ */
+ return 1 << (additional - 24);
+ }
+ return 0;
+}
+
+/** Extract the major type, i.e. the first 3 bits of the header byte. */
+#define MAJOR_TYPE(header_byte) (((header_byte) >> 5) & 0x7)
+
+/** Extract the additional info, i.e. the last 5 bits of the header byte. */
+#define ADDITIONAL(header_byte) ((header_byte) & 0x1F)
+
+/** Shorthand macro to check if a result is within min/max constraints.
+ */
+#define PTR_VALUE_IN_RANGE(type, p_res, p_min, p_max) \
+ (((p_min == NULL) || (*(type *)p_res >= *(type *)p_min)) \
+ && ((p_max == NULL) || (*(type *)p_res <= *(type *)p_max)))
+
+#define FAIL() \
+do {\
+ cbor_decode_trace(); \
+ return false; \
+} while(0)
+
+#define FAIL_AND_DECR_IF(expr) \
+do {\
+ if (expr) { \
+ (p_state->p_payload)--; \
+ FAIL(); \
+ } \
+} while(0)
+
+#define VALUE_IN_HEADER 23 /**! For values below this, the value is encoded
+ directly in the header. */
+
+#define BOOL_TO_PRIM 20 ///! In CBOR, false/true have the values 20/21
+
+/** Get a single value.
+ *
+ * @details @p pp_payload must point to the header byte. This function will
+ * retrieve the value (either from within the additional info, or from
+ * the subsequent bytes) and return it in the result. The result can
+ * have arbitrary length.
+ *
+ * The function will also validate
+ * - Min/max constraints on the value.
+ * - That @p pp_payload doesn't overrun past @p p_payload_end.
+ * - That @p p_elem_count has not been exhausted.
+ *
+ * @p pp_payload and @p p_elem_count are updated if the function
+ * succeeds. If not, they are left unchanged.
+ *
+ * CBOR values are always big-endian, so this function converts from
+ * big to little-endian if necessary (@ref CONFIG_BIG_ENDIAN).
+ */
+static bool value_extract(cbor_decode_state_t * p_state,
+ void * const p_result, size_t result_len)
+{
+ cbor_decode_trace();
+ cbor_decode_assert(result_len != 0, "0-length result not supported.\n");
+
+ FAIL_AND_DECR_IF(p_state->elem_count == 0);
+ FAIL_AND_DECR_IF(p_state->p_payload >= p_state->p_payload_end);
+
+ uint8_t *p_u8_result = (uint8_t *)p_result;
+ uint8_t additional = ADDITIONAL(*p_state->p_payload);
+
+ (p_state->p_payload)++;
+
+ memset(p_result, 0, result_len);
+ if (additional <= VALUE_IN_HEADER) {
+#ifdef CONFIG_BIG_ENDIAN
+ p_u8_result[result_len - 1] = additional;
+#else
+ p_u8_result[0] = additional;
+#endif /* CONFIG_BIG_ENDIAN */
+ } else {
+ uint32_t len = additional_len(additional);
+
+ FAIL_AND_DECR_IF(len > result_len);
+ FAIL_AND_DECR_IF((p_state->p_payload + len)
+ > p_state->p_payload_end);
+
+#ifdef CONFIG_BIG_ENDIAN
+ memcpy(&p_u8_result[result_len - len], p_state->p_payload, len);
+#else
+ for (uint32_t i = 0; i < len; i++) {
+ p_u8_result[i] = (p_state->p_payload)[len - i - 1];
+ }
+#endif /* CONFIG_BIG_ENDIAN */
+
+ (p_state->p_payload) += len;
+ }
+
+ (p_state->elem_count)--;
+ return true;
+}
+
+
+static bool int32_decode(cbor_decode_state_t * p_state,
+ int32_t *p_result, void *p_min_value, void *p_max_value)
+{
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+
+ if (!value_extract(p_state, p_result, 4)) {
+ FAIL();
+ }
+ if (*p_result < 0) {
+ /* Value is too large to fit in a signed integer. */
+ FAIL();
+ }
+
+ if (major_type == CBOR_MAJOR_TYPE_NINT) {
+ // Convert from CBOR's representation.
+ *p_result = 1 - *p_result;
+ }
+ if (!PTR_VALUE_IN_RANGE(int32_t, p_result, p_min_value, p_max_value)) {
+ FAIL();
+ }
+ cbor_decode_print("val: %d\r\n", *p_result);
+ return true;
+}
+
+
+bool intx32_decode(cbor_decode_state_t * p_state,
+ int32_t *p_result, void *p_min_value, void *p_max_value)
+{
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+
+ if (major_type != CBOR_MAJOR_TYPE_PINT
+ && major_type != CBOR_MAJOR_TYPE_NINT) {
+ /* Value to be read doesn't have the right type. */
+ FAIL();
+ }
+
+ if (!int32_decode(p_state,
+ p_result, p_min_value,
+ p_max_value)){
+ FAIL();
+ }
+ return true;
+}
+
+
+static bool uint32_decode(cbor_decode_state_t * p_state,
+ void *p_result, void *p_min_value, void *p_max_value)
+{
+ if (!value_extract(p_state, p_result, 4)) {
+ FAIL();
+ }
+
+ if (!PTR_VALUE_IN_RANGE(uint32_t, p_result, p_min_value, p_max_value)) {
+ FAIL();
+ }
+ cbor_decode_print("val: %u\r\n", *(uint32_t *)p_result);
+ return true;
+}
+
+
+bool uintx32_decode(cbor_decode_state_t * p_state,
+ uint32_t *p_result, void *p_min_value, void *p_max_value)
+{
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+
+ if (major_type != CBOR_MAJOR_TYPE_PINT) {
+ /* Value to be read doesn't have the right type. */
+ FAIL();
+ }
+ if (!uint32_decode(p_state, p_result, p_min_value, p_max_value)){
+ FAIL();
+ }
+ return true;
+}
+
+
+static bool size_decode(cbor_decode_state_t * p_state,
+ size_t *p_result, size_t *p_min_value, size_t *p_max_value)
+{
+ _Static_assert((sizeof(size_t) == sizeof(uint32_t)),
+ "This code needs size_t to be 4 bytes long.");
+ return uint32_decode(p_state,
+ p_result, p_min_value, p_max_value);
+}
+
+
+bool strx_start_decode(cbor_decode_state_t * p_state,
+ cbor_string_type_t *p_result, void *p_min_len, void *p_max_len)
+{
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+ cbor_string_type_t *p_str_result = (cbor_string_type_t *)p_result;
+
+ if (major_type != CBOR_MAJOR_TYPE_BSTR
+ && major_type != CBOR_MAJOR_TYPE_TSTR) {
+ /* Value to be read doesn't have the right type. */
+ FAIL();
+ }
+ if (!size_decode(p_state,
+ &p_str_result->len, (size_t *)p_min_len,
+ (size_t *)p_max_len)) {
+ FAIL();
+ }
+ p_str_result->value = p_state->p_payload;
+ return true;
+}
+
+
+bool strx_decode(cbor_decode_state_t * p_state,
+ cbor_string_type_t *p_result, void *p_min_len, void *p_max_len)
+{
+ if (!strx_start_decode(p_state, p_result,
+ p_min_len, p_max_len)) {
+ return false;
+ }
+ (p_state->p_payload) += p_result->len;
+ return true;
+}
+
+
+bool list_start_decode(cbor_decode_state_t * p_state,
+ size_t *p_result, size_t min_num, size_t max_num)
+{
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+
+ *p_result = p_state->elem_count;
+
+ if (major_type != CBOR_MAJOR_TYPE_LIST
+ && major_type != CBOR_MAJOR_TYPE_MAP) {
+ FAIL();
+ }
+ if (!uint32_decode(p_state,
+ p_result, &min_num, &max_num)) {
+ FAIL();
+ }
+ size_t tmp = *p_result;
+ *p_result = p_state->elem_count;
+ p_state->elem_count = major_type == CBOR_MAJOR_TYPE_MAP ? tmp * 2 : tmp;
+ return true;
+}
+
+
+bool primx_decode(cbor_decode_state_t * p_state,
+ uint8_t *p_result, void *p_min_result, void *p_max_result)
+{
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+ uint32_t val;
+
+ if (major_type != CBOR_MAJOR_TYPE_PRIM) {
+ /* Value to be read doesn't have the right type. */
+ FAIL();
+ }
+ if (!uint32_decode(p_state,
+ &val, p_min_result, p_max_result)) {
+ FAIL();
+ }
+ if (p_result != NULL) {
+ *p_result = val;
+ }
+ return true;
+}
+
+
+bool boolx_decode(cbor_decode_state_t * p_state,
+ bool *p_result, void *p_min_result, void *p_max_result)
+{
+ uint8_t min_result = *(uint8_t *)p_min_result + BOOL_TO_PRIM;
+ uint8_t max_result = *(uint8_t *)p_max_result + BOOL_TO_PRIM;
+
+ if (!primx_decode(p_state,
+ (uint8_t *)p_result, &min_result, &max_result)) {
+ FAIL();
+ }
+ (*p_result) -= BOOL_TO_PRIM;
+ return true;
+}
+
+
+bool double_decode(cbor_decode_state_t * p_state,
+ double *p_result, void *p_min_result, void *p_max_result)
+{
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+
+ if (major_type != CBOR_MAJOR_TYPE_PRIM) {
+ /* Value to be read doesn't have the right type. */
+ FAIL();
+ }
+ if (!value_extract(p_state, p_result,
+ sizeof(*p_result))) {
+ FAIL();
+ }
+
+ if (!PTR_VALUE_IN_RANGE(double, p_result, p_min_result, p_max_result)) {
+ FAIL();
+ }
+ return true;
+}
+
+
+bool any_decode(cbor_decode_state_t * p_state,
+ void *p_result, void *p_min_result, void *p_max_result)
+{
+ cbor_decode_assert(p_result == NULL,
+ "'any' type cannot be returned, only skipped.\n");
+
+ uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+ uint32_t value;
+ size_t num_decode;
+ void *p_null_result = NULL;
+ size_t temp_elem_count;
+
+ if (!value_extract(p_state, &value, sizeof(value))) {
+ /* Can happen because of p_elem_count (or p_payload_end) */
+ FAIL();
+ }
+
+ switch (major_type) {
+ case CBOR_MAJOR_TYPE_BSTR:
+ case CBOR_MAJOR_TYPE_TSTR:
+ (p_state->p_payload) += value;
+ break;
+ case CBOR_MAJOR_TYPE_MAP:
+ value *= 2; /* Because all members have a key. */
+ /* Fallthrough */
+ case CBOR_MAJOR_TYPE_LIST:
+ temp_elem_count = p_state->elem_count;
+ p_state->elem_count = value;
+ if (!multi_decode(value, value, &num_decode, any_decode,
+ p_state,
+ &p_null_result, NULL, NULL, 0)) {
+ p_state->elem_count = temp_elem_count;
+ FAIL();
+ }
+ p_state->elem_count = temp_elem_count;
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ return true;
+}
+
+
+bool multi_decode(size_t min_decode,
+ size_t max_decode,
+ size_t *p_num_decode,
+ decoder_t decoder,
+ cbor_decode_state_t * p_state,
+ void *p_result,
+ void *p_min_result,
+ void *p_max_result,
+ size_t result_len)
+{
+ for (size_t i = 0; i < max_decode; i++) {
+ uint8_t const *p_payload_bak = p_state->p_payload;
+ size_t elem_count_bak = p_state->elem_count;
+
+ if (!decoder(p_state,
+ (uint8_t *)p_result + i*result_len,
+ p_min_result,
+ p_max_result)) {
+ *p_num_decode = i;
+ p_state->p_payload = p_payload_bak;
+ p_state->elem_count = elem_count_bak;
+ if (i < min_decode) {
+ FAIL();
+ } else {
+ cbor_decode_print("Found %zu elements.\n", i);
+ }
+ return true;
+ }
+ }
+ cbor_decode_print("Found %zu elements.\n", max_decode);
+ *p_num_decode = max_decode;
+ return true;
+}
diff --git a/boot/boot_serial/src/cbor_decode.h b/boot/boot_serial/src/cbor_decode.h
new file mode 100644
index 0000000..cd466cd
--- /dev/null
+++ b/boot/boot_serial/src/cbor_decode.h
@@ -0,0 +1,269 @@
+/*
+ * This file has been copied from the cddl_gen submodule.
+ * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef CDDL_CBOR_H__
+#define CDDL_CBOR_H__
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/** The cbor_decode library provides functions for decoding CBOR data elements.
+ *
+ * This library is primarily meant to be called from code generated by
+ * $CDDL_GEN_BASE/scripts/cddl_gen.py
+ *
+ * Some details to notice about this library:
+ * - Integers are all 32 bits (uint32_t and size_t). This means that CBOR's
+ * 64 bit values are not supported. This applies to integer types, as well as
+ * lengths for other types.
+ * - Strings are kept in the container type cbor_string_type_t, which is a
+ * pointer and a length.
+ * - When a function returns false, it only means that decoding that particular
+ * value failed. If a value is allowed to take multiple different values,
+ * another decoding function can be called if the first fails. All functions
+ * are designed to reset pp_payload and p_elem_count to their original values
+ * if they return false.
+ * - There is some type casting going on under the hood to make the code
+ * generator friendly. See especially the decoder_t type which is compatible
+ * with all functions except multi_decode, but the compiler doesn't "know"
+ * this because they are defined with different pointer types. It also means
+ * any usage of multi_decode must be made with care for function types.
+ * - This library has no function for semantic tags.
+ * - This library doesn't distinguish lists from maps.
+ *
+ *
+ * CBOR's format is described well on Wikipedia
+ * - https://en.wikipedia.org/wiki/CBOR
+ * but here's a synopsis:
+ *
+ * Encoded CBOR data elements look like this.
+ *
+ * | Header | Value | Payload |
+ * | 1 byte | 0, 1, 2, 4, or 8 bytes | 0 - 2^64-1 bytes/elements |
+ * | 3 bits | 5 bits |
+ * | Major | Additional|
+ * | Type | info |
+ *
+ * The available major types can be seen in @ref cbor_major_type_t.
+ *
+ * PINT, NINT, TAG, and PRIM elements have no payload, only Value.
+ * PINT: Interpret the Value as a positive integer.
+ * NINT: Interpret the Value as a positive integer, then multiply by -1 and
+ * subtract 1.
+ * TAG: The Value says something about the next non-tag element.
+ * See https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
+ * PRIM: Different Values mean different things:
+ * 20: "false"
+ * 21: "true"
+ * 22: "null"
+ * 23: "undefined"
+ * >256: Interpret as IEEE 754 float with given precision
+ *
+ * For BSTR, TSTR, LIST, and MAP, the Value describes the length of the payload.
+ * For BSTR and TSTR, the length is in bytes, for LIST, the length is in number
+ * of elements, and for MAP, the length is in number of key/value element pairs.
+ *
+ * For LIST and MAP, sub elements are regular CBOR elements with their own
+ * Header, Value and Payload. LISTs and MAPs can be recursively encoded.
+ *
+ * For all types, Values 0-23 are encoded directly in the "Additional info",
+ * meaning that the "Value" field is 0 bytes long. If "Additional info" is 24,
+ * 25, 26, or 27, the "Value" field is 1, 2, 4, or 8 bytes long, respectively.
+ *
+ * The additional info means slightly different things for different major
+ * types.
+ */
+
+
+/** Convenience type that allows pointing to strings directly inside the payload
+ * without the need to copy out.
+ */
+typedef struct
+{
+ const uint8_t *value;
+ size_t len;
+} cbor_string_type_t;
+
+#ifdef CDDL_CBOR_VERBOSE
+#include <sys/printk.h>
+#define cbor_decode_trace() (printk("p_state->p_payload: 0x%x, "\
+ "*p_state->p_payload: 0x%x, p_state->elem_count: 0x%zx, %s:%d\n",\
+ (uint32_t)p_state->p_payload, *p_state->p_payload, p_state->elem_count,\
+ __FILE__, __LINE__))
+#define cbor_decode_assert(expr, ...) \
+do { \
+ if (!(expr)) { \
+ printk("ASSERTION \n \"" #expr \
+ "\"\nfailed at %s:%d with message:\n ", \
+ __FILE__, __LINE__); \
+ printk(__VA_ARGS__);\
+ return false; \
+ } \
+} while(0)
+#define cbor_decode_print(...) printk(__VA_ARGS__)
+#else
+#define cbor_decode_trace()
+#define cbor_decode_assert(...)
+#define cbor_decode_print(...)
+#endif
+
+typedef struct {
+ uint8_t const *p_payload;
+ uint8_t const *p_payload_end;
+ size_t elem_count;
+} cbor_decode_state_t;
+
+/** Function pointer type used with multi_decode.
+ *
+ * This type is compatible with all decoding functions here and in the generated
+ * code, except for multi_decode.
+ */
+typedef bool(decoder_t)(cbor_decode_state_t *, void *, void *, void *);
+
+/** Decode a PINT/NINT into a int32_t.
+ *
+ * @param[inout] pp_payload The current place in the payload. Will be
+ * updated if the element is correctly decoded.
+ * @param[in] p_payload_end The end of the payload. This will be checked
+ * against pp_payload before decoding.
+ * @param[inout] p_elem_count The current element is part of a LIST or a MAP,
+ * and this keeps count of how many elements are
+ * expected. This will be checked before decoding
+ * decremented if the element is correctly decoded.
+ * @param[out] p_result Where to place the decoded value.
+ * @param[in] p_min_value The minimum acceptable value. This is checked
+ * after decoding, and if the decoded value is
+ * outside the range, the decoding will fail.
+ * A NULL value here means there is no restriction.
+ * @param[in] p_max_value The maximum acceptable value. This is checked
+ * after decoding, and if the decoded value is
+ * outside the range, the decoding will fail.
+ * A NULL value here means there is no restriction.
+ *
+ * @retval true If the value was decoded correctly.
+ * @retval false If the value has the wrong type, the payload overflowed, the
+ * element count was exhausted, the value was not within the
+ * acceptable range, or the value was larger than can fit in the
+ * result variable.
+ */
+bool intx32_decode(cbor_decode_state_t * p_state, int32_t *p_result, void *p_min_value, void *p_max_value);
+
+/** Decode a PINT into a uint32_t.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values.
+ */
+bool uintx32_decode(cbor_decode_state_t * p_state, uint32_t *p_result, void *p_min_value, void *p_max_value);
+
+/** Decode a BSTR or TSTR, but leave pp_payload pointing at the payload.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values. For strings, the value refers to the length of the string.
+ */
+bool strx_start_decode(cbor_decode_state_t * p_state, cbor_string_type_t *p_result, void *p_min_len, void *p_max_len);
+
+/** Decode a BSTR or TSTR, and move pp_payload to after the payload.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values. For strings, the value refers to the length of the string.
+ */
+bool strx_decode(cbor_decode_state_t * p_state, cbor_string_type_t *p_result, void *p_min_len, void *p_max_len);
+
+/** Decode a LIST or MAP, but leave pp_payload pointing at the payload.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values. For lists and maps, the value refers to the number of
+ * elements.
+ */
+bool list_start_decode(cbor_decode_state_t * p_state, size_t *p_result, size_t min_num, size_t max_num);
+
+/** Decode a primitive value.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values.
+ */
+bool primx_decode(cbor_decode_state_t * p_state, uint8_t *p_result, void *p_min_result, void *p_max_result);
+
+/** Decode a boolean primitive value.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values. The result is translated internally from the primitive
+ * values for true/false (20/21) to 0/1.
+ */
+bool boolx_decode(cbor_decode_state_t * p_state, bool *p_result, void *p_min_result, void *p_max_result);
+
+/** Decode a float
+ *
+ * @warning This function has not been tested, and likely doesn't work.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values.
+ */
+bool float_decode(cbor_decode_state_t * p_state, double *p_result, void *p_min_result, void *p_max_result);
+
+/** Skip a single element, regardless of type and value.
+ *
+ * @details See @ref intx32_decode for information about parameters and return
+ * values. @p p_result, @p p_min_result, and @p p_max_result must be
+ * NULL.
+ */
+bool any_decode(cbor_decode_state_t * p_state, void *p_result, void *p_min_result, void *p_max_result);
+
+/** Decode 0 or more elements with the same type and constraints.
+ *
+ * @details This must not necessarily decode 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}
+ * size_t elem_count = 5;
+ * uint32_t int_min = 0;
+ * uint32_t int_max = 100;
+ * size_t bstr_size = 8;
+ * uint32_t ints[3];
+ * cbor_string_type_t bstrs[2];
+ *
+ * list_start_decode(pp_payload, p_payload_end, &parent_elem_count,
+ * &elem_count, NULL, NULL);
+ * multi_decode(3, 3, &num_decode, uintx32_decode, pp_payload,
+ * p_payload_end, ints, &int_min, &int_max, 4);
+ * multi_decode(0, 2, &num_decode, strx_decode, pp_payload,
+ * p_payload_end, bstrs, &bstr_size, &bstr_size,
+ * sizeof(cbor_string_type_t));
+ * @endcode
+ *
+ * See @ref intx32_decode for information about the undocumented
+ * parameters.
+ *
+ * @param[in] min_decode The minimum acceptable number of elements.
+ * @param[in] max_decode The maximum acceptable number of elements.
+ * @param[out] p_num_decode The actual number of elements.
+ * @param[in] decoder The decoder 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_decode times.
+ * p_result is moved @p result_len bytes for each call
+ * to @p decoder, i.e. @p p_result refers to an array
+ * of result variables.
+ * @param[out] p_result Where to place the decoded values. Must be an array
+ * of length at least @p max_decode.
+ * @param[in] result_len The length of the result variables. Must be the
+ * length expected by the @p decoder.
+ *
+ * @retval true If at least @p min_decode variables were correctly decoded.
+ * @retval false If @p decoder failed before having decoded @p min_decode
+ * values.
+ */
+bool multi_decode(size_t min_decode, size_t max_decode, size_t *p_num_decode,
+ decoder_t decoder, cbor_decode_state_t * p_state, void *p_result, void *p_min_result, void *p_max_result,
+ size_t result_len);
+
+#endif
diff --git a/boot/boot_serial/src/serial_recovery_cbor.c b/boot/boot_serial/src/serial_recovery_cbor.c
new file mode 100644
index 0000000..d774f58
--- /dev/null
+++ b/boot/boot_serial/src/serial_recovery_cbor.c
@@ -0,0 +1,84 @@
+/*
+ * This file has been generated from the cddl_gen submodule.
+ * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/* Generated with cddl_gen.py (https://github.com/oyvindronningstad/cddl_gen)
+ * at: 2020-02-26 10:33:34
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include "cbor_decode.h"
+#include "serial_recovery_cbor.h"
+
+
+static bool decode_Member(
+ cbor_decode_state_t *p_state, void * p_result, void * p_min_value,
+ void * p_max_value)
+{
+ cbor_decode_print("decode_Member\n");
+ uint8_t const * p_payload_bak;
+ size_t elem_count_bak;
+ _Member_t* p_type_result = (_Member_t*)p_result;
+
+ bool result = (((p_payload_bak = p_state->p_payload) && ((elem_count_bak = p_state->elem_count) || 1) && ((((strx_decode(p_state, &((*p_type_result)._Member_image_key), NULL, NULL))&& !memcmp("image", (*p_type_result)._Member_image_key.value, (*p_type_result)._Member_image_key.len)
+ && (intx32_decode(p_state, &((*p_type_result)._Member_image), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_image) || 1))
+ || ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_data_key), NULL, NULL))&& !memcmp("data", (*p_type_result)._Member_data_key.value, (*p_type_result)._Member_data_key.len)
+ && (strx_decode(p_state, &((*p_type_result)._Member_data), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_data) || 1)))
+ || ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_len_key), NULL, NULL))&& !memcmp("len", (*p_type_result)._Member_len_key.value, (*p_type_result)._Member_len_key.len)
+ && (intx32_decode(p_state, &((*p_type_result)._Member_len), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_len) || 1)))
+ || ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_off_key), NULL, NULL))&& !memcmp("off", (*p_type_result)._Member_off_key.value, (*p_type_result)._Member_off_key.len)
+ && (intx32_decode(p_state, &((*p_type_result)._Member_off), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_off) || 1)))
+ || ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_sha_key), NULL, NULL))&& !memcmp("sha", (*p_type_result)._Member_sha_key.value, (*p_type_result)._Member_sha_key.len)
+ && (strx_decode(p_state, &((*p_type_result)._Member_sha), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_sha) || 1))))));
+
+ if (!result)
+ {
+ cbor_decode_trace();
+ }
+
+ return result;
+}
+
+static bool decode_Upload(
+ cbor_decode_state_t *p_state, void * p_result, void * p_min_value,
+ void * p_max_value)
+{
+ cbor_decode_print("decode_Upload\n");
+ size_t temp_elem_counts[2];
+ size_t *p_temp_elem_count = temp_elem_counts;
+ Upload_t* p_type_result = (Upload_t*)p_result;
+
+ bool result = (((list_start_decode(p_state, &(*(p_temp_elem_count++)), 3, 5))
+ && multi_decode(3, 5, &(*p_type_result)._Upload_members_count, (void*)decode_Member, p_state, &((*p_type_result)._Upload_members), NULL, NULL, sizeof(_Member_t))
+ && ((p_state->elem_count = *(--p_temp_elem_count)) || 1)));
+
+ if (!result)
+ {
+ cbor_decode_trace();
+ }
+
+ p_state->elem_count = temp_elem_counts[0];
+ return result;
+}
+
+
+bool cbor_decode_Upload(const uint8_t * p_payload, size_t payload_len, Upload_t * p_result)
+{
+ cbor_decode_state_t state = {
+ .p_payload = p_payload,
+ .p_payload_end = p_payload + payload_len,
+ .elem_count = 1
+ };
+
+ return decode_Upload(&state, p_result, NULL, NULL);
+}
diff --git a/boot/boot_serial/src/serial_recovery_cbor.h b/boot/boot_serial/src/serial_recovery_cbor.h
new file mode 100644
index 0000000..dd3978f
--- /dev/null
+++ b/boot/boot_serial/src/serial_recovery_cbor.h
@@ -0,0 +1,65 @@
+/*
+ * This file has been generated from the cddl_gen submodule.
+ * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/* Generated with cddl_gen.py (https://github.com/oyvindronningstad/cddl_gen)
+ * at: 2020-02-26 10:33:34
+ */
+
+#ifndef SERIAL_RECOVERY_CBOR_H__
+#define SERIAL_RECOVERY_CBOR_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include "cbor_decode.h"
+
+
+typedef struct {
+ union {
+ struct {
+ cbor_string_type_t _Member_image_key;
+ int32_t _Member_image;
+ };
+ struct {
+ cbor_string_type_t _Member_data_key;
+ cbor_string_type_t _Member_data;
+ };
+ struct {
+ cbor_string_type_t _Member_len_key;
+ int32_t _Member_len;
+ };
+ struct {
+ cbor_string_type_t _Member_off_key;
+ int32_t _Member_off;
+ };
+ struct {
+ cbor_string_type_t _Member_sha_key;
+ cbor_string_type_t _Member_sha;
+ };
+ };
+ enum {
+ _Member_image,
+ _Member_data,
+ _Member_len,
+ _Member_off,
+ _Member_sha,
+ } _Member_choice;
+} _Member_t;
+
+typedef struct {
+ _Member_t _Upload_members[5];
+ size_t _Upload_members_count;
+} Upload_t;
+
+bool cbor_decode_Upload(const uint8_t * p_payload, size_t payload_len, Upload_t * p_result);
+
+#endif // SERIAL_RECOVERY_CBOR_H__