enable serial recovery functionality on the zephyr mcuboot

This patch introduced serial bootloader functionality ported
from mynewt targets tree.

For achieving this following changes were applied:
- Modified boot_serial module for using, zephyr-os modules
  (crc driver, mbedtls-base64 library) and the zephyr serial adapter module
  introduced recently.
- Added service of boot serial recovery mode to main.
- Adapted the input parser to using static buffers.

Default serial-boot-pin configuration was added for nrf52_pca10040
and nrf52840_pca10056 boards.

Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
diff --git a/Kconfig b/Kconfig
index bcf196b..871e1e5 100644
--- a/Kconfig
+++ b/Kconfig
@@ -18,6 +18,7 @@
 	select REBOOT
 	select UART_INTERRUPT_DRIVEN
 	select SERIAL
+	select NEWLIB_LIBC
 	help
 	  Enable serial recovery feature in mcuboot.
 
@@ -31,7 +32,7 @@
 config BOOT_SERIAL_DETECT_PORT
 	string
 	prompt "GPIO Port to trigger serial recovery mode"
-	default CONFIG_GPIO_NRF5_P0_DEV_NAME
+	default GPIO_0 if SOC_FAMILY_NRF5
 	depends on MCUBOOT_SERIAL
 	help
 	  Serial recovery detect port
@@ -39,7 +40,8 @@
 config BOOT_SERIAL_DETECT_PIN
 	int
 	prompt "Pin to trigger serial recovery mode"
-	default 0
+	default 11 if BOARD_NRF52840_PCA10056
+	default 13 if BOARD_NRF52_PCA10040
 	depends on MCUBOOT_SERIAL
 	help
 	  Serial recovery detect pin
diff --git a/boot/boot_serial/CMakeLists.txt b/boot/boot_serial/CMakeLists.txt
new file mode 100644
index 0000000..77665a7
--- /dev/null
+++ b/boot/boot_serial/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(src)
+zephyr_include_directories(include)
diff --git a/boot/boot_serial/src/CMakeLists.txt b/boot/boot_serial/src/CMakeLists.txt
new file mode 100644
index 0000000..48608e8
--- /dev/null
+++ b/boot/boot_serial/src/CMakeLists.txt
@@ -0,0 +1,6 @@
+zephyr_sources(boot_serial.c)
+
+#mbedtls-base64 library header
+zephyr_include_directories($ENV{ZEPHYR_BASE}/ext/lib/crypto/mbedtls/include)
+
+zephyr_include_directories(${BOOT_DIR}/bootutil/include)
diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c
index ac935c1..db6388e 100644
--- a/boot/boot_serial/src/boot_serial.c
+++ b/boot/boot_serial/src/boot_serial.c
@@ -24,24 +24,35 @@
 
 #include "sysflash/sysflash.h"
 
+#ifdef __ZEPHYR__
+#include <misc/reboot.h>
+#include <misc/byteorder.h>
+#include <misc/__assert.h>
+#include <flash.h>
+#include <crc16.h>
+#include <serial_adapter/serial_adapter.h>
+
+#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
+#include "bootutil/bootutil_log.h"
+#include "mbedtls/base64.h"
+#else
 #include <bsp/bsp.h>
-
-#include <flash_map/flash_map.h>
-#include <hal/hal_flash.h>
 #include <hal/hal_system.h>
-
 #include <os/endian.h>
-#include <os/os.h>
-#include <os/os_malloc.h>
 #include <os/os_cputime.h>
-
 #include <console/console.h>
+#include <crc/crc16.h>
+#include <base64/base64.h>
+#endif /* __ZEPHYR__ */
 
 #include <tinycbor/cbor.h>
 #include <tinycbor/cbor_buf_reader.h>
 #include <cborattr/cborattr.h>
-#include <base64/base64.h>
-#include <crc/crc16.h>
+
+#include <flash_map/flash_map.h>
+#include <hal/hal_flash.h>
+#include <os/os.h>
+#include <os/os_malloc.h>
 
 #include <bootutil/image.h>
 
@@ -50,6 +61,20 @@
 
 #define BOOT_SERIAL_OUT_MAX	48
 
+#ifdef __ZEPHYR__
+/* mbedtls-base64 lib encodes data to null-terminated string */
+#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
+
+#define CRC16_INITIAL_CRC       0       /* what to seed crc16 with */
+#define CRC_CITT_POLYMINAL 0x1021
+
+#define ntohs(x) sys_be16_to_cpu(x)
+#define htons(x) sys_cpu_to_be16(x)
+
+static char in_buf[CONFIG_BOOT_MAX_LINE_INPUT_LEN + 1];
+static char dec_buf[CONFIG_BOOT_MAX_LINE_INPUT_LEN + 1];
+#endif
+
 static uint32_t curr_off;
 static uint32_t img_size;
 static struct nmgr_hdr *bs_hdr;
@@ -229,6 +254,7 @@
     curr_off += img_blen;
 
 out:
+    BOOT_LOG_INF("RX: 0x%x", rc);
     cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
     cbor_encode_text_stringz(&bs_rsp, "rc");
     cbor_encode_int(&bs_rsp, rc);
@@ -264,8 +290,13 @@
     cbor_encoder_close_container(&bs_root, &bs_rsp);
 
     boot_serial_output();
+#ifdef __ZEPHYR__
+    k_sleep(250);
+    sys_reboot(SYS_REBOOT_COLD);
+#else
     os_cputime_delay_usecs(250000);
     hal_system_reset();
+#endif
 }
 
 /*
@@ -288,10 +319,10 @@
 
     buf += sizeof(*hdr);
     len -= sizeof(*hdr);
-
     bs_writer.bytes_written = 0;
     cbor_encoder_init(&bs_root, &bs_writer, 0);
 
+
     /*
      * Limited support for commands.
      */
@@ -339,8 +370,14 @@
     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(data, len, CRC_CITT_POLYMINAL, crc, true);
+#else
     crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
     crc = crc16_ccitt(crc, data, len);
+#endif
     crc = htons(crc);
 
     console_write(pkt_start, sizeof(pkt_start));
@@ -356,9 +393,17 @@
     totlen += len;
     memcpy(&buf[totlen], &crc, sizeof(crc));
     totlen += sizeof(crc);
+#ifdef __ZEPHYR__
+    size_t enc_len;
+    mbedtls_base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf,
+                          totlen);
+    totlen = enc_len;
+#else
     totlen = base64_encode(buf, totlen, encoded_buf, 1);
+#endif
     console_write(encoded_buf, totlen);
     console_write("\n", 1);
+    BOOT_LOG_INF("TX");
 }
 
 /*
@@ -370,7 +415,13 @@
     int rc;
     uint16_t crc;
     uint16_t len;
-
+#ifdef __ZEPHYR__
+    int err;
+    err = mbedtls_base64_decode( &out[*out_off], maxout, &rc, in, inlen - 2);
+    if (err) {
+        return -1;
+    }
+#else
     if (*out_off + base64_decode_len(in) >= maxout) {
         return -1;
     }
@@ -378,6 +429,7 @@
     if (rc < 0) {
         return -1;
     }
+#endif
     *out_off += rc;
 
     if (*out_off > sizeof(uint16_t)) {
@@ -385,7 +437,11 @@
 
         len = min(len, *out_off - sizeof(uint16_t));
         out += sizeof(uint16_t);
+#ifdef __ZEPHYR__
+        crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
+#else
         crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
+#endif
         if (crc || len <= sizeof(crc)) {
             return 0;
         }
@@ -411,12 +467,18 @@
     int dec_off;
     int full_line;
 
+#ifdef __ZEPHYR__
+    rc = boot_console_init();
+    buf = in_buf;
+    dec = dec_buf;
+    assert(max_input <= sizeof(in_buf) && max_input <= sizeof(dec_buf));
+#else
     rc = console_init(NULL);
     assert(rc == 0);
     console_echo(0);
-
     buf = os_malloc(max_input);
     dec = os_malloc(max_input);
+#endif
     assert(buf && dec);
 
     off = 0;
diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt
index 0b9eabb..e303421 100644
--- a/boot/zephyr/CMakeLists.txt
+++ b/boot/zephyr/CMakeLists.txt
@@ -6,6 +6,9 @@
 
 cmake_minimum_required(VERSION 3.8.2)
 
+
+set(KCONFIG_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../Kconfig)
+
 ########################
 # Configuration choices.
 ########################
@@ -168,3 +171,12 @@
   target_sources(app PRIVATE "${TINYCRYPT_DIR}/source/sha256.c")
   target_sources(app PRIVATE "${TINYCRYPT_DIR}/source/utils.c")
 endif()
+
+if (CONFIG_MCUBOOT_SERIAL)
+zephyr_sources(${BOOT_DIR}/zephyr/serial_adapter.c)
+
+add_subdirectory(${BOOT_DIR}/boot_serial ./boot/boot_serial)
+add_subdirectory(${BOOT_DIR}/zephyr/tinycbor)
+add_subdirectory(${BOOT_DIR}/zephyr/cborattr)
+
+endif()
diff --git a/boot/zephyr/include/config-boot.h b/boot/zephyr/include/config-boot.h
index a81a02f..72cca68 100644
--- a/boot/zephyr/include/config-boot.h
+++ b/boot/zephyr/include/config-boot.h
@@ -29,6 +29,11 @@
 #ifndef MBEDTLS_CONFIG_BOOT_H
 #define MBEDTLS_CONFIG_BOOT_H
 
+#ifdef CONFIG_MCUBOOT_SERIAL
+/* Mcuboot uses mbedts-base64 for serial protocol encoding. */
+#define MBEDTLS_BASE64_C
+#endif
+
 /* TODO: Configure this between app and target.  Really, we want the
  * config to come from the app. */
 #define CONFIG_BOOT_VERIFY_RSA_SIGNATURE
diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c
index cdd4139..1159e34 100644
--- a/boot/zephyr/main.c
+++ b/boot/zephyr/main.c
@@ -16,6 +16,8 @@
 
 #include <assert.h>
 #include <zephyr.h>
+#include <gpio.h>
+#include <misc/__assert.h>
 #include <flash.h>
 #include <asm_inline.h>
 #include <drivers/system_timer.h>
@@ -28,6 +30,10 @@
 #include "bootutil/bootutil.h"
 #include "flash_map/flash_map.h"
 
+#ifdef CONFIG_MCUBOOT_SERIAL
+#include <boot_serial/boot_serial.h>
+#endif
+
 struct device *boot_flash_device;
 
 void os_heap_init(void);
@@ -101,6 +107,29 @@
             ;
     }
 
+#ifdef CONFIG_MCUBOOT_SERIAL
+
+    struct device *detect_port;
+    u32_t detect_value;
+
+    detect_port = device_get_binding(CONFIG_BOOT_SERIAL_DETECT_PORT);
+    __ASSERT(detect_port, "Error: Bad port for boot serial detection.\n");
+
+    rc = gpio_pin_configure(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN,
+                            GPIO_DIR_IN | GPIO_PUD_PULL_UP);
+    __ASSERT(rc, "Error of boot detect pin initialization.\n");
+
+    rc = gpio_pin_read(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN, 
+                       &detect_value);
+    __ASSERT(rc, "Error of the reading the detect pin.\n");
+
+    if (detect_value == CONFIG_BOOT_SERIAL_DETECT_PIN_VAL) {
+        BOOT_LOG_INF("Enter the serial recovery mode");
+        boot_serial_start(CONFIG_BOOT_MAX_LINE_INPUT_LEN + 1);
+        __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n");
+    }
+#endif
+
     rc = boot_go(&rsp);
     if (rc != 0) {
         BOOT_LOG_ERR("Unable to find bootable image");