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/pkg.yml b/boot/boot_serial/pkg.yml
index dd92cf4..69d90e1 100644
--- a/boot/boot_serial/pkg.yml
+++ b/boot/boot_serial/pkg.yml
@@ -32,8 +32,8 @@
     - "@apache-mynewt-core/encoding/cborattr"
     - "@apache-mynewt-core/encoding/base64"
     - "@mcuboot/boot/mynewt/flash_map_backend"
+    - "@mcuboot/boot/mynewt/boot_uart"
     - "@apache-mynewt-core/util/crc"
 
 pkg.req_apis:
-    - console
     - bootloader
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);
 
diff --git a/boot/mynewt/boot_uart/include/boot_uart/boot_uart.h b/boot/mynewt/boot_uart/include/boot_uart/boot_uart.h
new file mode 100644
index 0000000..29b6d00
--- /dev/null
+++ b/boot/mynewt/boot_uart/include/boot_uart/boot_uart.h
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _BOOT_UART_H_
+#define _BOOT_UART_H_
+
+int boot_uart_open(void);
+void boot_uart_close(void);
+int boot_uart_read(char *str, int cnt, int *newline);
+void boot_uart_write(char *ptr, int cnt);
+
+#endif /* _BOOT_UART_H_ */
diff --git a/boot/mynewt/boot_uart/pkg.yml b/boot/mynewt/boot_uart/pkg.yml
new file mode 100644
index 0000000..a100a20
--- /dev/null
+++ b/boot/mynewt/boot_uart/pkg.yml
@@ -0,0 +1,32 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: boot/mynewt/boot_uart
+pkg.description: "For interfacing with uart from boot_serial"
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - loader
+    - boot
+    - bootloader
+
+pkg.deps:
+    - "@apache-mynewt-core/hw/hal"
+
+
diff --git a/boot/mynewt/boot_uart/src/boot_uart.c b/boot/mynewt/boot_uart/src/boot_uart.c
new file mode 100644
index 0000000..5e2fbbe
--- /dev/null
+++ b/boot/mynewt/boot_uart/src/boot_uart.c
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <assert.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include "os/mynewt.h"
+#include <uart/uart.h>
+
+/*
+ * RX is a ring buffer, which gets drained constantly.
+ * TX blocks until buffer has been completely transmitted.
+ */
+#define CONSOLE_HEAD_INC(cr) (((cr)->head + 1) & (sizeof((cr)->buf) - 1))
+#define CONSOLE_TAIL_INC(cr) (((cr)->tail + 1) & (sizeof((cr)->buf) - 1))
+
+struct {
+    uint8_t head;
+    uint8_t tail;
+    uint8_t buf[16];
+} bs_uart_rx;
+
+struct {
+    uint8_t *ptr;
+    int cnt;
+} volatile bs_uart_tx;
+
+static struct uart_dev *bs_uart;
+
+static int bs_rx_char(void *arg, uint8_t byte);
+static int bs_tx_char(void *arg);
+
+int
+boot_uart_open(void)
+{
+    struct uart_conf uc = {
+        .uc_speed = MYNEWT_VAL(CONSOLE_UART_BAUD),
+        .uc_databits = 8,
+        .uc_stopbits = 1,
+        .uc_parity = UART_PARITY_NONE,
+        .uc_flow_ctl = MYNEWT_VAL(CONSOLE_UART_FLOW_CONTROL),
+        .uc_tx_char = bs_tx_char,
+        .uc_rx_char = bs_rx_char,
+    };
+
+    bs_uart = (struct uart_dev *)os_dev_open(MYNEWT_VAL(CONSOLE_UART_DEV),
+      OS_TIMEOUT_NEVER, &uc);
+    if (!bs_uart) {
+        return -1;
+    }
+    return 0;
+}
+
+void
+boot_uart_close(void)
+{
+    os_dev_close(&bs_uart->ud_dev);
+    bs_uart_rx.head = 0;
+    bs_uart_rx.tail = 0;
+    bs_uart_tx.cnt = 0;
+}
+
+static int
+bs_rx_char(void *arg, uint8_t byte)
+{
+    if (CONSOLE_HEAD_INC(&bs_uart_rx) == bs_uart_rx.tail) {
+        /*
+         * RX queue full. Reader must drain this.
+         */
+        return -1;
+    }
+    bs_uart_rx.buf[bs_uart_rx.head] = byte;
+    bs_uart_rx.head = CONSOLE_HEAD_INC(&bs_uart_rx);
+    return 0;
+}
+
+static uint8_t
+bs_pull_char(void)
+{
+    uint8_t ch;
+
+    ch = bs_uart_rx.buf[bs_uart_rx.tail];
+    bs_uart_rx.tail = CONSOLE_TAIL_INC(&bs_uart_rx);
+    return ch;
+}
+
+int
+boot_uart_read(char *str, int cnt, int *newline)
+{
+    int i;
+    int sr;
+    uint8_t ch;
+
+    *newline = 0;
+    OS_ENTER_CRITICAL(sr);
+    for (i = 0; i < cnt; i++) {
+        if (bs_uart_rx.head == bs_uart_rx.tail) {
+            break;
+        }
+
+        ch = bs_pull_char();
+        if (ch == '\n') {
+            *str = '\0';
+            *newline = 1;
+            break;
+        }
+        *str++ = ch;
+    }
+    OS_EXIT_CRITICAL(sr);
+    if (i > 0 || *newline) {
+        uart_start_rx(bs_uart);
+    }
+    return i;
+}
+
+static int
+bs_tx_char(void *arg)
+{
+    uint8_t ch;
+
+    if (!bs_uart_tx.cnt) {
+        return -1;
+    }
+
+    bs_uart_tx.cnt--;
+    ch = *bs_uart_tx.ptr;
+    bs_uart_tx.ptr++;
+    return ch;
+}
+
+#if MYNEWT_VAL(SELFTEST)
+/*
+ * OS is not running, so native uart 'driver' cannot run either.
+ * At the moment unit tests don't check the responses to messages it
+ * sends, so we can drop the outgoing data here.
+ */
+void
+boot_uart_write(char *ptr, int cnt)
+{
+}
+
+#else
+
+void
+boot_uart_write(char *ptr, int cnt)
+{
+    int sr;
+
+    OS_ENTER_CRITICAL(sr);
+    bs_uart_tx.ptr = (uint8_t *)ptr;
+    bs_uart_tx.cnt = cnt;
+    OS_EXIT_CRITICAL(sr);
+
+    uart_start_tx(bs_uart);
+    while (bs_uart_tx.cnt);
+}
+
+#endif
diff --git a/boot/mynewt/mcuboot_config/syscfg.yml b/boot/mynewt/mcuboot_config/syscfg.yml
index 467bcee..5eecf98 100644
--- a/boot/mynewt/mcuboot_config/syscfg.yml
+++ b/boot/mynewt/mcuboot_config/syscfg.yml
@@ -52,6 +52,13 @@
     BOOTUTIL_HAVE_LOGGING:
         description: 'Enable serial logging'
         value: 0
+        restrictions:
+            - "!BOOTUTIL_NO_LOGGING"
+    BOOTUTIL_NO_LOGGING:
+        description: 'No serial logging'
+        value: 1
+        restrictions:
+            - "!BOOTUTIL_HAVE_LOGGING"
     BOOTUTIL_LOG_LEVEL:
         description: >
             Default console log level. Valid values are:
diff --git a/boot/mynewt/pkg.yml b/boot/mynewt/pkg.yml
index 396df49..1cbd1ab 100644
--- a/boot/mynewt/pkg.yml
+++ b/boot/mynewt/pkg.yml
@@ -33,7 +33,13 @@
     - "@mcuboot/boot/bootutil"
     - "@mcuboot/boot/mynewt/flash_map_backend"
     - "@apache-mynewt-core/kernel/os"
+
+pkg.deps.BOOTUTIL_NO_LOGGING:
+    - "@apache-mynewt-core/sys/console/stub"
+
+pkg.deps.BOOTUTIL_HAVE_LOGGING:
     - "@apache-mynewt-core/sys/console/minimal"
 
 pkg.deps.BOOT_SERIAL:
     - "@mcuboot/boot/boot_serial"
+    - "@mcuboot/boot/mynewt/boot_uart"
diff --git a/boot/mynewt/src/main.c b/boot/mynewt/src/main.c
index 083d03e..b504896 100755
--- a/boot/mynewt/src/main.c
+++ b/boot/mynewt/src/main.c
@@ -23,7 +23,8 @@
 #include <stddef.h>
 #include <inttypes.h>
 #include <stdio.h>
-#include "syscfg/syscfg.h"
+
+#include <syscfg/syscfg.h>
 #include <flash_map_backend/flash_map_backend.h>
 #include <os/os.h>
 #include <bsp/bsp.h>
@@ -36,6 +37,9 @@
 #include <hal/hal_nvreg.h>
 #include <boot_serial/boot_serial.h>
 #endif
+#if defined(MCUBOOT_SERIAL) && MYNEWT_VAL(BOOT_SERIAL_DETECT_TIMEOUT) != 0
+#include <boot_uart/boot_uart.h>
+#endif
 #include <console/console.h>
 #include "bootutil/image.h"
 #include "bootutil/bootutil.h"
@@ -61,6 +65,70 @@
 }
 
 #ifdef MCUBOOT_SERIAL
+#if MYNEWT_VAL(BOOT_SERIAL_DETECT_TIMEOUT) != 0
+
+/** Don't include null-terminator in comparison. */
+#define BOOT_SERIAL_DETECT_STRING_LEN \
+    (sizeof MYNEWT_VAL(BOOT_SERIAL_DETECT_STRING) - 1)
+
+/**
+ * Listens on the UART for the management string.  Blocks for up to
+ * BOOT_SERIAL_DETECT_TIMEOUT milliseconds.
+ *
+ * @return                      true if the management string was received;
+ *                              false if the management string was not received
+ *                                  before the UART listen timeout expired.
+ */
+static bool
+serial_detect_uart_string(void)
+{
+    uint32_t start_tick;
+    char buf[BOOT_SERIAL_DETECT_STRING_LEN] = { 0 };
+    char ch;
+    int newline;
+    int rc;
+
+    /* Calculate the timeout duration in OS cputime ticks. */
+    static const uint32_t timeout_dur =
+        MYNEWT_VAL(BOOT_SERIAL_DETECT_TIMEOUT) /
+        (1000.0 / MYNEWT_VAL(OS_CPUTIME_FREQ));
+
+    rc = boot_serial_uart_open();
+    assert(rc == 0);
+
+    start_tick = os_cputime_get32();
+
+    while (1) {
+        /* Read a single character from the UART. */
+        rc = boot_serial_uart_read(&ch, 1, &newline);
+        if (rc > 0) {
+            /* Eliminate the oldest character in the buffer to make room for
+             * the new one.
+             */
+            memmove(buf, buf + 1, BOOT_SERIAL_DETECT_STRING_LEN - 1);
+            buf[BOOT_SERIAL_DETECT_STRING_LEN - 1] = ch;
+
+            /* If the full management string has been received, indicate that
+             * the serial boot loader should start.
+             */
+            rc = memcmp(buf,
+                        MYNEWT_VAL(BOOT_SERIAL_DETECT_STRING),
+                        BOOT_SERIAL_DETECT_STRING_LEN);
+            if (rc == 0) {
+                boot_serial_uart_close();
+                return true;
+            }
+        }
+
+        /* Abort the listen on timeout. */
+        if (os_cputime_get32() >= start_tick + timeout_dur) {
+            boot_serial_uart_close();
+            return false;
+        }
+    }
+}
+#endif
+
 static void
 serial_boot_detect(void)
 {
@@ -99,7 +167,7 @@
      * download commands from serial.
      */
 #if MYNEWT_VAL(BOOT_SERIAL_DETECT_TIMEOUT) != 0
-    if (boot_serial_detect_uart_string()) {
+    if (serial_detect_uart_string()) {
         boot_serial_start(BOOT_SERIAL_INPUT_MAX);
         assert(0);
     }
diff --git a/boot/mynewt/syscfg.yml b/boot/mynewt/syscfg.yml
index 778ba5f..3460954 100644
--- a/boot/mynewt/syscfg.yml
+++ b/boot/mynewt/syscfg.yml
@@ -29,5 +29,5 @@
 syscfg.vals:
     SYSINIT_CONSTRAIN_INIT: 0
     OS_SCHEDULING: 0
-    OS_CPUTIME_TIMER_NUM: -1
+    MSYS_1_BLOCK_COUNT: 0
     CONSOLE_COMPAT: 1