boot_serial; text size reduction.
 - Remove dependency to sprintf()
 - Remove dependency to cborattr
 - mynewt: replace console with more direct interface to uart
 - mynewt: settings to reduce included os code

Signed-off-by: Marko Kiiskila <marko@runtime.io>
diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c
index 623225c..e67e68d 100644
--- a/boot/boot_serial/src/boot_serial.c
+++ b/boot/boot_serial/src/boot_serial.c
@@ -40,11 +40,15 @@
 #include <hal/hal_system.h>
 #include <os/endian.h>
 #include <os/os_cputime.h>
-#include <console/console.h>
+#include <boot_uart/boot_uart.h>
 #include <crc/crc16.h>
 #include <base64/base64.h>
 #include <tinycbor/cbor.h>
 #include <tinycbor/cbor_buf_reader.h>
+
+#define console_write boot_uart_write
+#define console_read  boot_uart_read
+
 #endif /* __ZEPHYR__ */
 
 #include <cborattr/cborattr.h>
@@ -58,7 +62,7 @@
 #include "boot_serial/boot_serial.h"
 #include "boot_serial_priv.h"
 
-#define BOOT_SERIAL_OUT_MAX	48
+#define BOOT_SERIAL_OUT_MAX	80
 
 #ifdef __ZEPHYR__
 /* base64 lib encodes data to null-terminated string */
@@ -93,6 +97,10 @@
 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;
 
@@ -100,31 +108,49 @@
 }
 
 /*
- * Looks for 'name' from NULL-terminated json data in buf.
- * Returns pointer to first character of value for that name.
- * Returns NULL if 'name' is not found.
+ * Convert version into string without use of snprintf().
  */
-char *
-bs_find_val(char *buf, char *name)
+static int
+u32toa(char *tgt, uint32_t val)
 {
-    char *ptr;
+    char *dst;
+    uint32_t d = 1;
+    uint32_t dgt;
+    int n = 0;
 
-    ptr = strstr(buf, name);
-    if (!ptr) {
-        return NULL;
+    dst = tgt;
+    while (val / d >= 10) {
+        d *= 10;
     }
-    ptr += strlen(name);
-
-    while (*ptr != '\0') {
-        if (*ptr != ':' && !isspace((int)*ptr)) {
-            break;
+    while (d) {
+        dgt = val / d;
+        val %= d;
+        d /= 10;
+        if (n || dgt > 0 || d == 0) {
+            *dst++ = dgt + '0';
+            ++n;
         }
-        ++ptr;
     }
-    if (*ptr == '\0') {
-        ptr = NULL;
-    }
-    return ptr;
+    *dst = '\0';
+
+    return dst - tgt;
+}
+
+/*
+ * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
+ */
+static void
+bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
+{
+    int off;
+
+    off = u32toa(dst, ver->iv_major);
+    dst[off++] = '.';
+    off += u32toa(dst + off, ver->iv_minor);
+    dst[off++] = '.';
+    off += u32toa(dst + off, ver->iv_revision);
+    dst[off++] = '.';
+    off += u32toa(dst + off, ver->iv_build_num);
 }
 
 /*
@@ -164,9 +190,7 @@
         cbor_encode_int(&image, i);
         cbor_encode_text_stringz(&image, "version");
 
-        len = snprintf((char *)tmpbuf, sizeof(tmpbuf),
-          "%u.%u.%u.%u", hdr.ih_ver.iv_major, hdr.ih_ver.iv_minor,
-          hdr.ih_ver.iv_revision, (unsigned int)hdr.ih_ver.iv_build_num);
+        bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
         cbor_encode_text_stringz(&image, (char *)tmpbuf);
         cbor_encoder_close_container(&images, &image);
     }
@@ -183,47 +207,115 @@
 {
     CborParser parser;
     struct cbor_buf_reader reader;
+    struct CborValue root_value;
     struct CborValue value;
-    uint8_t img_data[400];
-    long long unsigned int off = UINT_MAX;
+    uint8_t img_data[512];
+    long long int off = UINT_MAX;
     size_t img_blen = 0;
     uint8_t rem_bytes;
-    long long unsigned int data_len = UINT_MAX;
-    const struct cbor_attr_t attr[4] = {
-        [0] = {
-            .attribute = "data",
-            .type = CborAttrByteStringType,
-            .addr.bytestring.data = img_data,
-            .addr.bytestring.len = &img_blen,
-            .len = sizeof(img_data)
-        },
-        [1] = {
-            .attribute = "off",
-            .type = CborAttrUnsignedIntegerType,
-            .addr.uinteger = &off,
-            .nodefault = true
-        },
-        [2] = {
-            .attribute = "len",
-            .type = CborAttrUnsignedIntegerType,
-            .addr.uinteger = &data_len,
-            .nodefault = true
-        }
-    };
+    long long int data_len = UINT_MAX;
+    size_t slen;
+    char name_str[8];
     const struct flash_area *fap = NULL;
     int rc;
 
     memset(img_data, 0, sizeof(img_data));
+
+    /*
+     * Expected data format.
+     * {
+     *   "data":<img_data>
+     *   "len":<image len>
+     *   "off":<current offset of image data>
+     * }
+     */
+
+    /*
+     * Object comes within { ... }
+     */
     cbor_buf_reader_init(&reader, (uint8_t *)buf, len);
 #ifdef __ZEPHYR__
-    cbor_parser_cust_reader_init(&reader.r, 0, &parser, &value);
+    cbor_parser_cust_reader_init(&reader.r, 0, &parser, &root_value);
 #else
-    cbor_parser_init(&reader.r, 0, &parser, &value);
+    cbor_parser_init(&reader.r, 0, &parser, &root_value);
 #endif
-    rc = cbor_read_object(&value, attr);
-    if (rc || off == UINT_MAX) {
-        rc = MGMT_ERR_EINVAL;
-        goto out;
+    if (!cbor_value_is_container(&root_value)) {
+        goto out_invalid_data;
+    }
+    if (cbor_value_enter_container(&root_value, &value)) {
+        goto out_invalid_data;
+    }
+    while (cbor_value_is_valid(&value)) {
+        /*
+         * Decode key.
+         */
+        if (cbor_value_calculate_string_length(&value, &slen)) {
+            goto out_invalid_data;
+        }
+        if (!cbor_value_is_text_string(&value) ||
+            slen >= sizeof(name_str) - 1) {
+            goto out_invalid_data;
+        }
+        if (cbor_value_copy_text_string(&value, name_str, &slen, &value)) {
+            goto out_invalid_data;
+        }
+        name_str[slen] = '\0';
+        if (!strcmp(name_str, "data")) {
+            /*
+             * Image data
+             */
+            if (value.type != CborByteStringType) {
+                goto out_invalid_data;
+            }
+            if (cbor_value_calculate_string_length(&value, &slen) ||
+                slen >= sizeof(img_data)) {
+                goto out_invalid_data;
+            }
+            if (cbor_value_copy_byte_string(&value, img_data, &slen, &value)) {
+                goto out_invalid_data;
+            }
+            img_blen = slen;
+        } else if (!strcmp(name_str, "off")) {
+            /*
+             * Offset of the data.
+             */
+            if (value.type != CborIntegerType) {
+                goto out_invalid_data;
+            }
+            if (cbor_value_get_int64(&value, &off)) {
+                goto out_invalid_data;
+            }
+            if (cbor_value_advance(&value)) {
+                goto out_invalid_data;
+            }
+        } else if (!strcmp(name_str, "len")) {
+            /*
+             * Length of the image. This should only be present in the first
+             * block of data; when offset is 0.
+             */
+            if (value.type != CborIntegerType) {
+                goto out_invalid_data;
+            }
+            if (cbor_value_get_int64(&value, &data_len)) {
+                goto out_invalid_data;
+            }
+            if (cbor_value_advance(&value)) {
+                goto out_invalid_data;
+            }
+        } else {
+            /*
+             * Unknown keys.
+             */
+            if (cbor_value_advance(&value)) {
+                goto out_invalid_data;
+            }
+        }
+    }
+    if (off == UINT_MAX) {
+        /*
+         * Offset must be set in every block.
+         */
+        goto out_invalid_data;
     }
 
     rc = flash_area_open(flash_area_id_from_image_slot(0), &fap);
@@ -235,13 +327,11 @@
     if (off == 0) {
         curr_off = 0;
         if (data_len > fap->fa_size) {
-            rc = MGMT_ERR_EINVAL;
-            goto out;
+            goto out_invalid_data;
         }
         rc = flash_area_erase(fap, 0, fap->fa_size);
         if (rc) {
-            rc = MGMT_ERR_EINVAL;
-            goto out;
+            goto out_invalid_data;
         }
         img_size = data_len;
     }
@@ -256,12 +346,12 @@
         }
     }
     rc = flash_area_write(fap, curr_off, img_data, img_blen);
-    if (rc) {
+    if (rc == 0) {
+        curr_off += img_blen;
+    } else {
+    out_invalid_data:
         rc = MGMT_ERR_EINVAL;
-        goto out;
     }
-    curr_off += img_blen;
-
 out:
     BOOT_LOG_INF("RX: 0x%x", rc);
     cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
@@ -278,11 +368,15 @@
 }
 
 /*
- * Console echo control. Send empty response, don't do anything.
+ * Console echo control/image erase. Send empty response, don't do anything.
  */
 static void
-bs_echo_ctl(char *buf, int len)
+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);
     boot_serial_output();
 }
 
@@ -293,12 +387,8 @@
 static void
 bs_reset(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);
+    bs_empty_rsp(buf, len);
 
-    boot_serial_output();
 #ifdef __ZEPHYR__
     k_sleep(250);
     sys_reboot(SYS_REBOOT_COLD);
@@ -328,6 +418,7 @@
 
     buf += sizeof(*hdr);
     len -= sizeof(*hdr);
+
     bs_writer.bytes_written = 0;
 #ifdef __ZEPHYR__
     cbor_encoder_cust_writer_init(&bs_root, &bs_writer, 0);
@@ -340,19 +431,20 @@
      */
     if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
         switch (hdr->nh_id) {
-        case IMGMGR_NMGR_OP_STATE:
+        case IMGMGR_NMGR_ID_STATE:
             bs_list(buf, len);
             break;
-        case IMGMGR_NMGR_OP_UPLOAD:
+        case IMGMGR_NMGR_ID_UPLOAD:
             bs_upload(buf, len);
             break;
         default:
+            bs_empty_rsp(buf, len);
             break;
         }
     } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
         switch (hdr->nh_id) {
         case NMGR_ID_CONS_ECHO_CTRL:
-            bs_echo_ctl(buf, len);
+            bs_empty_rsp(buf, len);
             break;
         case NMGR_ID_RESET:
             bs_reset(buf, len);
@@ -378,13 +470,13 @@
     len = bs_writer.bytes_written;
 
     bs_hdr->nh_op++;
-    bs_hdr->nh_flags = NMGR_F_CBOR_RSP_COMPLETE;
+    bs_hdr->nh_flags = 0;
     bs_hdr->nh_len = htons(len);
     bs_hdr->nh_group = htons(bs_hdr->nh_group);
 
 #ifdef __ZEPHYR__
-    crc =  crc16((u8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC,
-                 false);
+    crc =  crc16((u8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL,
+                 CRC16_INITIAL_CRC, false);
     crc =  crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
 #else
     crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
@@ -413,7 +505,7 @@
     totlen = base64_encode(buf, totlen, encoded_buf, 1);
 #endif
     console_write(encoded_buf, totlen);
-    console_write("\n", 1);
+    console_write("\n\r", 2);
     BOOT_LOG_INF("TX");
 }
 
@@ -484,13 +576,13 @@
     dec = dec_buf;
     assert(max_input <= sizeof(in_buf) && max_input <= sizeof(dec_buf));
 #else
-    rc = console_init(NULL);
+    rc = boot_uart_open();
     assert(rc == 0);
-    console_echo(0);
+
     buf = os_malloc(max_input);
     dec = os_malloc(max_input);
-#endif
     assert(buf && dec);
+#endif
 
     off = 0;
     while (1) {
@@ -500,6 +592,12 @@
         }
         off += rc;
         if (!full_line) {
+            if (off == max_input) {
+                /*
+                 * Full line, no newline yet. Reset the input buffer.
+                 */
+                off = 0;
+            }
             continue;
         }
         if (buf[0] == SHELL_NLIP_PKT_START1 &&
diff --git a/boot/boot_serial/src/boot_serial_priv.h b/boot/boot_serial/src/boot_serial_priv.h
index 146aa6a..3b4c1ec 100644
--- a/boot/boot_serial/src/boot_serial_priv.h
+++ b/boot/boot_serial/src/boot_serial_priv.h
@@ -41,8 +41,6 @@
 #define NMGR_OP_READ            0
 #define NMGR_OP_WRITE           2
 
-#define NMGR_F_CBOR_RSP_COMPLETE 0x01
-
 #define MGMT_GROUP_ID_DEFAULT   0
 #define MGMT_GROUP_ID_IMAGE     1
 
@@ -61,9 +59,8 @@
 /*
  * From imgmgr.h
  */
-#define IMGMGR_NMGR_OP_STATE            0
-#define IMGMGR_NMGR_OP_UPLOAD           1
-
+#define IMGMGR_NMGR_ID_STATE            0
+#define IMGMGR_NMGR_ID_UPLOAD           1
 
 void boot_serial_input(char *buf, int len);