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__