You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2018/02/13 02:21:44 UTC

[mynewt-mcumgr] branch master updated (3c0c033 -> 44e3500)

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git.


 discard 3c0c033  Merge pull request #1 from miyatsu/readme-fix-2018-02-09
    omit 2df71ec  Readme.md: Fix bad links in file README.md
    omit bfd56c3  smp_svr - Update zephyr port for compatibility.
    omit a989cc9  Zephyr port: move mcumgr location in zephyr.
    omit 6629d1c  zephyr img_mgmt: Use `FLASH_DEV_NAME`
    omit 0921e38  Remove local tinycbor copy.
    omit 9dfb177  Correct "MCUboot" spelling in documentation.
    omit b15ecf9  smp_svr - Use CONFIG_BOOTLOADER_MCUBOOT setting.
    omit 3390a3a  smp_svr - Add statistics.
    omit 00bf1b8  stat_mgmt command handler group.
    omit ee62327  smp_svr - fix build error when CONFIG_MDLOG unset.
    omit 1124271  smp_svr - Allow both CONFIG_FCB and CONFIG_FS_NFFS
    omit 90c5cfd  Minor code cleanup.
    omit 89ee0f5  Add doxygen comments for log_mgmt.
    omit e93bd66  Update documentation.
    omit 2ee9695  smp_svr Mynewt sample app - Remove redundant dep.
    omit 6c0dd9f  Add log_mgmt support to smp_svr sample app.
    omit e5fcfd6  log_mgmt command handler group.
    omit 7f40df2  Reboot in system workqueue, not ISR.
    omit 1a1e227  Fix some misnamed identifiers.
    omit a4f1ba0  Add missing license text.
    omit 1ea9adb  Make MCUMGR_CMD_FS_MGMT depend on FILE_SYSTEM.
    omit 7e83bda  Remove extraneous README.rst file.
    omit 7c761c0  Sample app - smp_svr
    omit 373dcb1  Documentation.
    omit 1da5b49  Mynewt support.
    omit e5ec685  Zephyr support.
    omit b3b7c5e  cborattr library
    omit 83a7483  OS-agnostic command handlers: fs, img, os.
    omit a1a98c1  External tinycbor library.
    omit 17ecb23  External base64 library.
    omit 0f10b53  smp - The built-in transfer encoding.
    omit 9f3757c  mgmt - Code implementing the core `mgmt` layer.
    omit 6683426  Initial commit.
     new 9eee2c6  Initial commit.
     new b9e2cf8  mgmt - Code implementing the core `mgmt` layer.
     new 63d47c1  smp - The built-in transfer encoding.
     new 9417697  External base64 library.
     new 42b2816  External tinycbor library.
     new 4355617  OS-agnostic command handlers: fs, img, os.
     new 1636f65  cborattr library
     new cfe132e  Zephyr support.
     new 6974956  Mynewt support.
     new 5515138  Documentation.
     new 22bba90  Sample app - smp_svr
     new db04a30  Remove extraneous README.rst file.
     new ad113bc  Make MCUMGR_CMD_FS_MGMT depend on FILE_SYSTEM.
     new 4df50f7  Add missing license text.
     new a4d9248  Fix some misnamed identifiers.
     new 80e46f3  Reboot in system workqueue, not ISR.
     new afdb047  log_mgmt command handler group.
     new d9131d6  Add log_mgmt support to smp_svr sample app.
     new b5c74b5  smp_svr Mynewt sample app - Remove redundant dep.
     new a6898ca  Update documentation.
     new f43f1df  Add doxygen comments for log_mgmt.
     new 4b601ef  Minor code cleanup.
     new af277cf  smp_svr - Allow both CONFIG_FCB and CONFIG_FS_NFFS
     new 980c924  smp_svr - fix build error when CONFIG_MDLOG unset.
     new 7bdec14  stat_mgmt command handler group.
     new e86e83f  smp_svr - Add statistics.
     new ffdecf8  smp_svr - Use CONFIG_BOOTLOADER_MCUBOOT setting.
     new e4db21b  Correct "MCUboot" spelling in documentation.
     new d69cfa3  Remove local tinycbor copy.
     new fec5444  zephyr img_mgmt: Use `FLASH_DEV_NAME`
     new 4ab4db6  Zephyr port: move mcumgr location in zephyr.
     new e6dc5b6  smp_svr - Update zephyr port for compatibility.
     new 80fc499  Readme.md: Fix bad links in file README.md
     new 4a72306  mcumgr: Minor refactor to increase readability
     new 490f44f  Indicate units (bytes) in Kconfig help.
     new 821f578  Remove "zephyr,code_partition" from dts overlay
     new 9b45fbc  fs_mgmt - Surround macro definition with ().
     new 75c5f1a  smp_svr/CMakeLists.txt: remove set_conf_file macro
     new 6e77227  smp_svr/CMakeLists.txt: remove FROM_WHO variable
     new 1aca722  Zephyr: use <> for non-relative include paths.
     new 785fe1a  Remove base64 library.
     new 44e3500  smp_svr (zephyr) - CONFIG_NET_BUF_USER_DATA_SIZE=7

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (3c0c033)
            \
             N -- N -- N   refs/heads/master (44e3500)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 42 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CMakeLists.txt                                   |   6 +-
 cmd/fs_mgmt/Kconfig                              |  15 +-
 cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c     |   6 +-
 cmd/fs_mgmt/src/fs_mgmt.c                        |   2 +-
 cmd/img_mgmt/Kconfig                             |   5 +-
 cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c   |   6 +-
 cmd/log_mgmt/Kconfig                             |  20 +--
 cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c   |   8 +-
 cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c     |   8 +-
 cmd/stat_mgmt/Kconfig                            |   8 +-
 cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c |   8 +-
 ext/CMakeLists.txt                               |   1 -
 ext/base64/CMakeLists.txt                        |  17 ---
 ext/base64/include/base64/base64.h               |  40 -----
 ext/base64/include/base64/hex.h                  |  33 -----
 ext/base64/pkg.yml                               |  26 ----
 ext/base64/src/base64.c                          | 181 -----------------------
 ext/base64/src/hex.c                             | 101 -------------
 ext/base64/test/pkg.yml                          |  30 ----
 ext/base64/test/src/encoding_test.c              |  53 -------
 ext/base64/test/src/encoding_test_priv.h         |  38 -----
 ext/base64/test/src/testcases/hex2str.c          |  64 --------
 ext/base64/test/src/testcases/str2hex.c          |  72 ---------
 samples/smp_svr/zephyr/CMakeLists.txt            |  17 +--
 samples/smp_svr/zephyr/dts.overlay               |   3 -
 samples/smp_svr/zephyr/prj.conf                  |   3 +
 samples/smp_svr/zephyr/src/main.c                |  12 +-
 27 files changed, 58 insertions(+), 725 deletions(-)
 delete mode 100644 ext/CMakeLists.txt
 delete mode 100644 ext/base64/CMakeLists.txt
 delete mode 100644 ext/base64/include/base64/base64.h
 delete mode 100644 ext/base64/include/base64/hex.h
 delete mode 100644 ext/base64/pkg.yml
 delete mode 100644 ext/base64/src/base64.c
 delete mode 100644 ext/base64/src/hex.c
 delete mode 100644 ext/base64/test/pkg.yml
 delete mode 100644 ext/base64/test/src/encoding_test.c
 delete mode 100644 ext/base64/test/src/encoding_test_priv.h
 delete mode 100644 ext/base64/test/src/testcases/hex2str.c
 delete mode 100644 ext/base64/test/src/testcases/str2hex.c

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 31/42: Zephyr port: move mcumgr location in zephyr.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 4ab4db676ab074cd8064d59eba35c3b5da1df444
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Feb 8 15:24:24 2018 -0800

    Zephyr port: move mcumgr location in zephyr.
    
    `ext/mcumgr` --> `ext/lib/mgmt/mcumgr`
---
 Kconfig     |  4 ++--
 cmd/Kconfig | 10 +++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/Kconfig b/Kconfig
index 89de3ee..f0ce016 100644
--- a/Kconfig
+++ b/Kconfig
@@ -24,6 +24,6 @@ menuconfig MCUMGR
       This option enables the mcumgr management library.
 
 if MCUMGR
-source "ext/mcumgr/mgmt/port/zephyr/Kconfig"
-source "ext/mcumgr/cmd/Kconfig"
+source "ext/lib/mgmt/mcumgr/mgmt/port/zephyr/Kconfig"
+source "ext/lib/mgmt/mcumgr/cmd/Kconfig"
 endif
diff --git a/cmd/Kconfig b/cmd/Kconfig
index e404d2d..d26d382 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -17,10 +17,10 @@
 
 menu "Command handlers"
 
-source "ext/mcumgr/cmd/fs_mgmt/Kconfig"
-source "ext/mcumgr/cmd/img_mgmt/Kconfig"
-source "ext/mcumgr/cmd/log_mgmt/Kconfig"
-source "ext/mcumgr/cmd/os_mgmt/Kconfig"
-source "ext/mcumgr/cmd/stat_mgmt/Kconfig"
+source "ext/lib/mgmt/mcumgr/cmd/fs_mgmt/Kconfig"
+source "ext/lib/mgmt/mcumgr/cmd/img_mgmt/Kconfig"
+source "ext/lib/mgmt/mcumgr/cmd/log_mgmt/Kconfig"
+source "ext/lib/mgmt/mcumgr/cmd/os_mgmt/Kconfig"
+source "ext/lib/mgmt/mcumgr/cmd/stat_mgmt/Kconfig"
 
 endmenu

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 16/42: Reboot in system workqueue, not ISR.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 80e46f31e2a09ff5257fa66372a209cf075cbb30
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 15:47:32 2018 -0800

    Reboot in system workqueue, not ISR.
---
 cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
index 221da97..df996a8 100644
--- a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
+++ b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
@@ -26,10 +26,13 @@
 #include "os_mgmt/os_mgmt_impl.h"
 
 static void zephyr_os_mgmt_reset_cb(struct k_timer *timer);
+static void zephyr_os_mgmt_reset_work_handler(struct k_work *work);
 
 static K_TIMER_DEFINE(zephyr_os_mgmt_reset_timer,
                       zephyr_os_mgmt_reset_cb, NULL);
 
+K_WORK_DEFINE(zephyr_os_mgmt_reset_work, zephyr_os_mgmt_reset_work_handler);
+
 #ifdef CONFIG_THREAD_MONITOR
 static const struct k_thread *
 zephyr_os_mgmt_task_at(int idx)
@@ -72,11 +75,18 @@ os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info)
 #endif /* CONFIG_THREAD_MONITOR */
 
 static void
-zephyr_os_mgmt_reset_cb(struct k_timer *timer)
+zephyr_os_mgmt_reset_work_handler(struct k_work *work)
 {
     sys_reboot(SYS_REBOOT_WARM);
 }
 
+static void
+zephyr_os_mgmt_reset_cb(struct k_timer *timer)
+{
+    /* Reboot the system from the system workqueue thread. */
+    k_work_submit(&zephyr_os_mgmt_reset_work);
+}
+
 int
 os_mgmt_impl_reset(unsigned int delay_ms)
 {

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 11/42: Sample app - smp_svr

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 22bba90da5c1909663581eedd691d0bed2ed07c3
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:18:13 2018 -0800

    Sample app - smp_svr
---
 samples/smp_svr/README.md             |  64 +++++++
 samples/smp_svr/mynewt/pkg.yml        |  43 +++++
 samples/smp_svr/mynewt/src/main.c     | 320 ++++++++++++++++++++++++++++++++++
 samples/smp_svr/mynewt/syscfg.yml     |  39 +++++
 samples/smp_svr/zephyr/CMakeLists.txt |  42 +++++
 samples/smp_svr/zephyr/README.rst     |  41 +++++
 samples/smp_svr/zephyr/dts.overlay    |  13 ++
 samples/smp_svr/zephyr/prj.conf       |  30 ++++
 samples/smp_svr/zephyr/src/main.c     | 108 ++++++++++++
 9 files changed, 700 insertions(+)

diff --git a/samples/smp_svr/README.md b/samples/smp_svr/README.md
new file mode 100644
index 0000000..cb9d3e7
--- /dev/null
+++ b/samples/smp_svr/README.md
@@ -0,0 +1,64 @@
+# smp_svr
+
+This sample application implements a simple SMP server with the following
+transports:
+    * Shell
+    * Bluetooth
+
+`smp_svr` enables support for the following command groups:
+    * fs_mgmt
+    * img_mgmt
+    * os_mgmt
+
+## Mynewt
+
+The Mynewt port of `smp_svr` is a regular Mynewt app.  The below example uses the nRF52dk as the BSP, so you may need to adjust accordingly if you are using different hardware.
+
+0. Create a Mynewt project and upload the Apache mynewt boot loader to your
+board as described here: http://mynewt.apache.org/latest/os/tutorials/nRF52/
+
+1. Add the mcumgr repo to your `project.yml` file:
+
+```
+repository.mynewt-mcumgr:
+    type: git
+    vers: 0-latest
+    url: 'git@github.com:apache/mynewt-mcumgr.git'
+```
+
+2. Create a target that ties the `smp_svr` app to your BSP of choice (nRF52dk in this example):
+
+```
+$ newt target create smp_svr-nrf52dk
+$ newt target set smp_svr-nrf52dk app=@mynewt-mcumgr/samples/smp_svr/apache \
+                                  bsp=@apache-mynewt-core/hw/bsp/nrf52dk    \
+                                  build_profile=debug
+```
+
+3. Build, upload, and run the application on your board:
+
+```
+$ newt run smp_svr-nrf52dk
+```
+
+## Zephyr
+
+The Zephyr port of `smp_svr` is configured to run on an nRF52 MCU.  The
+application should build and run for other platforms without modification, but
+the file system management commands will not work.  To enable file system
+management for a different platform, adjust the `CONFIG_FS_NFFS_FLASH_DEV_NAME`
+setting in `prj.conf` accordingly.
+
+In addition, the MCUBoot boot loader (https://github.com/runtimeco/mcuboot) is
+required for img_mgmt to function properly.
+
+### Building
+
+The Zephyr port of `smp_svr` can be built using the usual procedure:
+
+```
+$ cd samples/smp_svr/zephyr
+$ mkdir build && cd build
+$ cmake -DBOARD=<board> ..
+$ make
+```
diff --git a/samples/smp_svr/mynewt/pkg.yml b/samples/smp_svr/mynewt/pkg.yml
new file mode 100644
index 0000000..83d38d5
--- /dev/null
+++ b/samples/smp_svr/mynewt/pkg.yml
@@ -0,0 +1,43 @@
+# 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: samples/smp_svr/mynewt
+pkg.type: app
+pkg.description: Simple BLE peripheral running an mcumgr SMP server.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps: 
+    - '@apache-mynewt-core/boot/bootutil'
+    - '@apache-mynewt-core/mgmt/newtmgr/transport/ble'
+    - '@apache-mynewt-core/mgmt/newtmgr/transport/nmgr_shell'
+    - '@apache-mynewt-core/net/nimble/controller'
+    - '@apache-mynewt-core/net/nimble/host'
+    - '@apache-mynewt-core/net/nimble/host/services/ans'
+    - '@apache-mynewt-core/net/nimble/host/services/gap'
+    - '@apache-mynewt-core/net/nimble/host/services/gatt'
+    - '@apache-mynewt-core/net/nimble/host/store/config'
+    - '@apache-mynewt-core/net/nimble/transport/ram'
+    - '@apache-mynewt-core/sys/console/full'
+    - '@apache-mynewt-core/sys/log/full'
+    - '@apache-mynewt-core/sys/stats/full'
+    - '@mynewt-mcumgr/cmd/fs_mgmt'
+    - '@mynewt-mcumgr/cmd/img_mgmt'
+    - '@mynewt-mcumgr/cmd/os_mgmt'
+    - '@mynewt-mcumgr/mgmt'
+    - '@mynewt-mcumgr/smp'
diff --git a/samples/smp_svr/mynewt/src/main.c b/samples/smp_svr/mynewt/src/main.c
new file mode 100755
index 0000000..19d5f91
--- /dev/null
+++ b/samples/smp_svr/mynewt/src/main.c
@@ -0,0 +1,320 @@
+/*
+ * 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 <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include "sysinit/sysinit.h"
+#include "bsp/bsp.h"
+#include "bsp/bsp.h"
+#include "config/config.h"
+#include "console/console.h"
+#include "hal/hal_gpio.h"
+#include "hal/hal_system.h"
+#include "os/os.h"
+
+/* BLE */
+#include "nimble/ble.h"
+#include "host/ble_hs.h"
+#include "services/gap/ble_svc_gap.h"
+
+/* smp_svr uses the first "peruser" log module. */
+#define SMP_SVR_LOG_MODULE  (LOG_MODULE_PERUSER + 0)
+
+/* Convenience macro for logging to the smp_svr module. */
+#define SMP_SVR_LOG(lvl, ...) \
+    LOG_ ## lvl(&smp_svr_log, SMP_SVR_LOG_MODULE, __VA_ARGS__)
+
+/** Log data. */
+struct log smp_svr_log;
+
+static int smp_svr_gap_event(struct ble_gap_event *event, void *arg);
+
+void
+print_addr(const void *addr)
+{
+    const uint8_t *u8p;
+
+    u8p = addr;
+    SMP_SVR_LOG(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
+                u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
+}
+
+/**
+ * Logs information about a connection to the console.
+ */
+static void
+smp_svr_print_conn_desc(struct ble_gap_conn_desc *desc)
+{
+    SMP_SVR_LOG(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
+                desc->conn_handle, desc->our_ota_addr.type);
+    print_addr(desc->our_ota_addr.val);
+    SMP_SVR_LOG(INFO, " our_id_addr_type=%d our_id_addr=",
+                desc->our_id_addr.type);
+    print_addr(desc->our_id_addr.val);
+    SMP_SVR_LOG(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
+                desc->peer_ota_addr.type);
+    print_addr(desc->peer_ota_addr.val);
+    SMP_SVR_LOG(INFO, " peer_id_addr_type=%d peer_id_addr=",
+                desc->peer_id_addr.type);
+    print_addr(desc->peer_id_addr.val);
+    SMP_SVR_LOG(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
+                "encrypted=%d authenticated=%d bonded=%d\n",
+                desc->conn_itvl, desc->conn_latency,
+                desc->supervision_timeout,
+                desc->sec_state.encrypted,
+                desc->sec_state.authenticated,
+                desc->sec_state.bonded);
+}
+
+/**
+ * Enables advertising with the following parameters:
+ *     o General discoverable mode.
+ *     o Undirected connectable mode.
+ */
+static void
+smp_svr_advertise(void)
+{
+    struct ble_gap_adv_params adv_params;
+    struct ble_hs_adv_fields fields;
+    const char *name;
+    int rc;
+
+    /**
+     *  Set the advertisement data included in our advertisements:
+     *     o Flags (indicates advertisement type and other general info).
+     *     o Advertising tx power.
+     *     o Device name.
+     *     o 16-bit service UUIDs (alert notifications).
+     */
+
+    memset(&fields, 0, sizeof fields);
+
+    /* Advertise two flags:
+     *     o Discoverability in forthcoming advertisement (general)
+     *     o BLE-only (BR/EDR unsupported).
+     */
+    fields.flags = BLE_HS_ADV_F_DISC_GEN |
+                   BLE_HS_ADV_F_BREDR_UNSUP;
+
+    /* Indicate that the TX power level field should be included; have the
+     * stack fill this value automatically.  This is done by assiging the
+     * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
+     */
+    fields.tx_pwr_lvl_is_present = 1;
+    fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
+
+    name = ble_svc_gap_device_name();
+    fields.name = (uint8_t *)name;
+    fields.name_len = strlen(name);
+    fields.name_is_complete = 1;
+
+    fields.uuids16 = (ble_uuid16_t[]){
+        BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
+    };
+    fields.num_uuids16 = 1;
+    fields.uuids16_is_complete = 1;
+
+    rc = ble_gap_adv_set_fields(&fields);
+    if (rc != 0) {
+        SMP_SVR_LOG(ERROR, "error setting advertisement data; rc=%d\n", rc);
+        return;
+    }
+
+    /* Begin advertising. */
+    memset(&adv_params, 0, sizeof adv_params);
+    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
+    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
+    rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
+                           &adv_params, smp_svr_gap_event, NULL);
+    if (rc != 0) {
+        SMP_SVR_LOG(ERROR, "error enabling advertisement; rc=%d\n", rc);
+        return;
+    }
+}
+
+/**
+ * The nimble host executes this callback when a GAP event occurs.  The
+ * application associates a GAP event callback with each connection that forms.
+ * smp_svr uses the same callback for all connections.
+ *
+ * @param event                 The type of event being signalled.
+ * @param ctxt                  Various information pertaining to the event.
+ * @param arg                   Application-specified argument; unuesd by
+ *                                  smp_svr.
+ *
+ * @return                      0 if the application successfully handled the
+ *                                  event; nonzero on failure.  The semantics
+ *                                  of the return code is specific to the
+ *                                  particular GAP event being signalled.
+ */
+static int
+smp_svr_gap_event(struct ble_gap_event *event, void *arg)
+{
+    struct ble_gap_conn_desc desc;
+    int rc;
+
+    switch (event->type) {
+    case BLE_GAP_EVENT_CONNECT:
+        /* A new connection was established or a connection attempt failed. */
+        SMP_SVR_LOG(INFO, "connection %s; status=%d ",
+                       event->connect.status == 0 ? "established" : "failed",
+                       event->connect.status);
+        if (event->connect.status == 0) {
+            rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+            assert(rc == 0);
+            smp_svr_print_conn_desc(&desc);
+
+#if MYNEWT_VAL(SMP_SVR_LE_PHY_SUPPORT)
+            phy_conn_changed(event->connect.conn_handle);
+#endif
+        }
+        SMP_SVR_LOG(INFO, "\n");
+
+        if (event->connect.status != 0) {
+            /* Connection failed; resume advertising. */
+            smp_svr_advertise();
+        }
+        return 0;
+
+    case BLE_GAP_EVENT_DISCONNECT:
+        SMP_SVR_LOG(INFO, "disconnect; reason=%d ", event->disconnect.reason);
+        smp_svr_print_conn_desc(&event->disconnect.conn);
+        SMP_SVR_LOG(INFO, "\n");
+
+#if MYNEWT_VAL(SMP_SVR_LE_PHY_SUPPORT)
+        phy_conn_changed(CONN_HANDLE_INVALID);
+#endif
+
+        /* Connection terminated; resume advertising. */
+        smp_svr_advertise();
+        return 0;
+
+    case BLE_GAP_EVENT_CONN_UPDATE:
+        /* The central has updated the connection parameters. */
+        SMP_SVR_LOG(INFO, "connection updated; status=%d ",
+                    event->conn_update.status);
+        rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+        assert(rc == 0);
+        smp_svr_print_conn_desc(&desc);
+        SMP_SVR_LOG(INFO, "\n");
+        return 0;
+
+    case BLE_GAP_EVENT_ADV_COMPLETE:
+        SMP_SVR_LOG(INFO, "advertise complete; reason=%d",
+                    event->adv_complete.reason);
+        smp_svr_advertise();
+        return 0;
+
+    case BLE_GAP_EVENT_ENC_CHANGE:
+        /* Encryption has been enabled or disabled for this connection. */
+        SMP_SVR_LOG(INFO, "encryption change event; status=%d ",
+                    event->enc_change.status);
+        rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+        assert(rc == 0);
+        smp_svr_print_conn_desc(&desc);
+        SMP_SVR_LOG(INFO, "\n");
+        return 0;
+
+    case BLE_GAP_EVENT_MTU:
+        SMP_SVR_LOG(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
+                    event->mtu.conn_handle,
+                    event->mtu.channel_id,
+                    event->mtu.value);
+        return 0;
+
+    case BLE_GAP_EVENT_REPEAT_PAIRING:
+        /* We already have a bond with the peer, but it is attempting to
+         * establish a new secure link.  This app sacrifices security for
+         * convenience: just throw away the old bond and accept the new link.
+         */
+
+        /* Delete the old bond. */
+        rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
+        assert(rc == 0);
+        ble_store_util_delete_peer(&desc.peer_id_addr);
+
+        /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
+         * continue with the pairing operation.
+         */
+        return BLE_GAP_REPEAT_PAIRING_RETRY;
+    }
+
+    return 0;
+}
+
+static void
+smp_svr_on_reset(int reason)
+{
+    SMP_SVR_LOG(ERROR, "Resetting state; reason=%d\n", reason);
+}
+
+static void
+smp_svr_on_sync(void)
+{
+    /* Begin advertising. */
+    smp_svr_advertise();
+}
+
+/**
+ * main
+ *
+ * The main task for the project. This function initializes the packages,
+ * then starts serving events from default event queue.
+ *
+ * @return int NOTE: this function should never return!
+ */
+int
+main(void)
+{
+    int rc;
+
+    /* Initialize OS */
+    sysinit();
+
+    /* Initialize the smp_svr log. */
+    log_register("smp_svr", &smp_svr_log, &log_console_handler, NULL,
+                 LOG_SYSLEVEL);
+
+    /* Initialize the NimBLE host configuration. */
+    log_register("ble_hs", &ble_hs_log, &log_console_handler, NULL,
+                 LOG_SYSLEVEL);
+    ble_hs_cfg.reset_cb = smp_svr_on_reset;
+    ble_hs_cfg.sync_cb = smp_svr_on_sync;
+    ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
+    ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
+
+    rc = gatt_svr_init();
+    assert(rc == 0);
+
+    /* Set the default device name. */
+    rc = ble_svc_gap_device_name_set("smp_svr");
+    assert(rc == 0);
+
+    conf_load();
+
+    /*
+     * As the last thing, process events from default event queue.
+     */
+    while (1) {
+        os_eventq_run(os_eventq_dflt_get());
+    }
+    return 0;
+}
diff --git a/samples/smp_svr/mynewt/syscfg.yml b/samples/smp_svr/mynewt/syscfg.yml
new file mode 100644
index 0000000..99b4dc4
--- /dev/null
+++ b/samples/smp_svr/mynewt/syscfg.yml
@@ -0,0 +1,39 @@
+# 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.
+#
+
+# Package: apps/bleprph
+
+syscfg.vals:
+    # Disable central and observer roles.
+    BLE_ROLE_BROADCASTER: 1
+    BLE_ROLE_CENTRAL: 0
+    BLE_ROLE_OBSERVER: 0
+    BLE_ROLE_PERIPHERAL: 1
+
+    # Log reboot messages to a flash circular buffer.
+    REBOOT_LOG_FCB: 1
+    LOG_FCB: 1
+    CONFIG_FCB: 1
+
+    # OS main/default task
+    OS_MAIN_STACK_SIZE: 468
+
+    # Lots of smaller mbufs are required for newtmgr using typical BLE ATT MTU
+    # values.
+    MSYS_1_BLOCK_COUNT: 22
+    MSYS_1_BLOCK_SIZE: 110
diff --git a/samples/smp_svr/zephyr/CMakeLists.txt b/samples/smp_svr/zephyr/CMakeLists.txt
new file mode 100644
index 0000000..30a4ebd
--- /dev/null
+++ b/samples/smp_svr/zephyr/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Top-level CMakeLists.txt for the skeleton application.
+#
+# Copyright (c) 2017 Open Source Foundries Limited
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# This provides a basic application structure suitable for communication using
+# mcumgr.  It can be used as a starting point for new applications.
+
+# The default top-level application configuration is prj.conf.  You can place
+# additional board-specific files in boards/${BOARD}.conf, and they will be
+# merged into the configuration along with prj.conf.
+macro(set_conf_file)
+  if(EXISTS ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf)
+    set(CONF_FILE "prj.conf ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf")
+  else()
+    set(CONF_FILE "prj.conf")
+  endif()
+endmacro()
+
+# Zephyr uses Device Tree (DT) to describe some board hardware configuration.
+#
+# See the Zephyr documentation for more information on DT:
+# http://docs.zephyrproject.org/devices/dts/device_tree.html
+set(DTC_OVERLAY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/dts.overlay")
+
+# Standard Zephyr application boilerplate.
+include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
+project(NONE)
+
+assert_exists(DTC_OVERLAY_FILE)
+
+# This string ends up getting printed in the device console
+if (NOT DEFINED FROM_WHO)
+  set(FROM_WHO Zephyr)
+endif()
+
+target_sources(app PRIVATE
+    src/main.c
+)
+
+zephyr_link_libraries(MCUMGR NFFS)
diff --git a/samples/smp_svr/zephyr/README.rst b/samples/smp_svr/zephyr/README.rst
new file mode 100644
index 0000000..00218b0
--- /dev/null
+++ b/samples/smp_svr/zephyr/README.rst
@@ -0,0 +1,41 @@
+.. _hello_world:
+
+Hello World
+###########
+
+Overview
+********
+A simple Hello World example that can be used with any supported board and
+prints 'Hello World' to the console. This application can be built into modes:
+
+* single thread
+* multi threading
+
+Building and Running
+********************
+
+This project outputs 'Hello World' to the console.  It can be built and executed
+on QEMU as follows:
+
+.. zephyr-app-commands::
+   :zephyr-app: samples/hello_world
+   :board: qemu_x86
+   :goals: run
+   :compact:
+
+To build the single thread version, use the supplied configuration file for
+single thread: :file:`prj_single.conf`:
+
+.. zephyr-app-commands::
+   :zephyr-app: samples/hello_world
+   :board: qemu_x86
+   :conf: prj_single.conf
+   :goals: run
+   :compact:
+
+Sample Output
+=============
+
+.. code-block:: console
+
+    Hello World! x86
diff --git a/samples/smp_svr/zephyr/dts.overlay b/samples/smp_svr/zephyr/dts.overlay
new file mode 100644
index 0000000..5a3a7f3
--- /dev/null
+++ b/samples/smp_svr/zephyr/dts.overlay
@@ -0,0 +1,13 @@
+/*
+ * Basic Device Tree overlay file.
+ */
+
+/ {
+	chosen {
+		/* Required by mcuboot. */
+		zephyr,code-partition = &slot0_partition;
+
+		/* Use uart0 for the mcumgr UART transport. */
+		zephyr,uart-mcumgr = &uart0;
+	};
+};
diff --git a/samples/smp_svr/zephyr/prj.conf b/samples/smp_svr/zephyr/prj.conf
new file mode 100644
index 0000000..50e8ff1
--- /dev/null
+++ b/samples/smp_svr/zephyr/prj.conf
@@ -0,0 +1,30 @@
+# Required by file management command handlers.
+CONFIG_FILE_SYSTEM=y
+CONFIG_FILE_SYSTEM_NFFS=y
+CONFIG_FS_NFFS_FLASH_DEV_NAME="NRF5_FLASH"
+
+# Required by tinycbor (math.h).
+CONFIG_NEWLIB_LIBC=y
+
+# Some command handlers require a large stack.
+CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
+
+# Allow room for the mcuboot image header.
+CONFIG_TEXT_SECTION_OFFSET=0x200
+
+# Increase the number of transmit buffers to avoid the Bluetooth stack buffer
+# leak.
+CONFIG_BT_L2CAP_TX_BUF_COUNT=8
+
+# Allow for large Bluetooth data packets.
+CONFIG_BT_L2CAP_TX_MTU=260
+CONFIG_BT_RX_BUF_LEN=260
+
+# Enable the Bluetooth and shell mcumgr transports.
+CONFIG_MCUMGR_SMP_BT=y
+CONFIG_MCUMGR_SMP_SHELL=y
+
+# Enable all core commands.
+CONFIG_MCUMGR_CMD_FS_MGMT=y
+CONFIG_MCUMGR_CMD_IMG_MGMT=y
+CONFIG_MCUMGR_CMD_OS_MGMT=y
diff --git a/samples/smp_svr/zephyr/src/main.c b/samples/smp_svr/zephyr/src/main.c
new file mode 100644
index 0000000..757725f
--- /dev/null
+++ b/samples/smp_svr/zephyr/src/main.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2012-2014 Wind River Systems, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <assert.h>
+#include <zephyr.h>
+#include <string.h>
+#include <stdlib.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include "fs_mgmt/fs_mgmt.h"
+#include "os_mgmt/os_mgmt.h"
+#include "img_mgmt/img_mgmt.h"
+#include "mgmt/smp_bt.h"
+#include "mgmt/buf.h"
+ 
+#define DEVICE_NAME         CONFIG_BT_DEVICE_NAME
+#define DEVICE_NAME_LEN     (sizeof(DEVICE_NAME) - 1)
+
+static const struct bt_data ad[] = {
+    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+    BT_DATA_BYTES(BT_DATA_UUID128_ALL,
+        0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86,
+        0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d),
+};
+
+static const struct bt_data sd[] = {
+    BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
+};
+
+static void advertise(void)
+{
+    int rc;
+
+    bt_le_adv_stop();
+
+    rc = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad),
+                         sd, ARRAY_SIZE(sd));
+    if (rc) {
+        printk("Advertising failed to start (rc %d)\n", rc);
+        return;
+    }
+
+    printk("Advertising successfully started\n");
+}
+
+static void connected(struct bt_conn *conn, u8_t err)
+{
+    if (err) {
+        printk("Connection failed (err %u)\n", err);
+    } else {
+        printk("Connected\n");
+    }
+}
+
+static void disconnected(struct bt_conn *conn, u8_t reason)
+{
+    printk("Disconnected (reason %u)\n", reason);
+    advertise();
+}
+
+static struct bt_conn_cb conn_callbacks = {
+    .connected = connected,
+    .disconnected = disconnected,
+};
+
+static void bt_ready(int err)
+{
+    if (err) {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    advertise();
+}
+
+void main(void)
+{
+    int rc;
+
+    /* Register the built-in mcumgr command handlers. */
+    os_mgmt_register_group();
+    img_mgmt_register_group();
+    fs_mgmt_register_group();
+
+    /* Enable Bluetooth. */
+    rc = bt_enable(bt_ready);
+    if (rc != 0) {
+        printk("Bluetooth init failed (err %d)\n", rc);
+        return;
+    }
+    bt_conn_cb_register(&conn_callbacks);
+
+    /* Initialize the Bluetooth mcumgr transport. */
+    smp_bt_register();
+
+    /* The system work queue handles all incoming mcumgr requests.  Let the
+     * main thread idle while the mcumgr server runs.
+     */
+    while (1) {
+        k_sleep(INT32_MAX);
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 03/42: smp - The built-in transfer encoding.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 63d47c1811226e19b1ca9458cf969da86d9a5112
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:11:12 2018 -0800

    smp - The built-in transfer encoding.
    
    Simple management protocol.
---
 smp/CMakeLists.txt    |   7 +
 smp/include/smp/smp.h |  91 ++++++++++++
 smp/pkg.yml           |  40 ++++++
 smp/src/smp.c         | 379 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 517 insertions(+)

diff --git a/smp/CMakeLists.txt b/smp/CMakeLists.txt
new file mode 100644
index 0000000..74072ab
--- /dev/null
+++ b/smp/CMakeLists.txt
@@ -0,0 +1,7 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    smp/src/smp.c
+)
diff --git a/smp/include/smp/smp.h b/smp/include/smp/smp.h
new file mode 100644
index 0000000..7afa7ad
--- /dev/null
+++ b/smp/include/smp/smp.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * @brief SMP - Simple Management Protocol.
+ *
+ * SMP is a basic protocol that sits on top of the mgmt layer.  SMP requests
+ * and responses have the following format:
+ *
+ *     [Offset 0]: Mgmt header
+ *     [Offset 8]: CBOR map of command-specific key-value pairs.
+ *
+ * SMP request packets may contain multiple concatenated requests.  Each
+ * request must start at an offset that is a multiple of 4, so padding should
+ * be inserted between requests as necessary.  Requests are processed
+ * sequentially from the start of the packet to the end.  Each response is sent
+ * individually in its own packet.  If a request elicits an error response,
+ * processing of the packet is aborted.
+ */
+
+#ifndef H_SMP_
+#define H_SMP_
+
+#include "mgmt/mgmt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct smp_streamer;
+struct mgmt_hdr;
+
+/** @typedef smp_tx_rsp_fn
+ * @brief Transmits an SMP response packet.
+ *
+ * @param ss                    The streamer to transmit via.
+ * @param buf                   Buffer containing the response packet.
+ * @param arg                   Optional streamer argument.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+typedef int smp_tx_rsp_fn(struct smp_streamer *ss, void *buf, void *arg);
+
+/**
+ * @brief Decodes, encodes, and transmits SMP packets.
+ */
+struct smp_streamer {
+    struct mgmt_streamer mgmt_stmr;
+    smp_tx_rsp_fn *tx_rsp_cb;
+};
+
+/**
+ * @brief Processes a single SMP request packet and sends all corresponding
+ *        responses.
+ *
+ * Processes all SMP requests in an incoming packet.  Requests are processed
+ * sequentially from the start of the packet to the end.  Each response is sent
+ * individually in its own packet.  If a request elicits an error response,
+ * processing of the packet is aborted.  This function consumes the supplied
+ * request buffer regardless of the outcome.
+ *
+ * @param streamer              The streamer providing the required SMP
+ *                                  callbacks.
+ * @param req                   The request packet to process.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int smp_process_request_packet(struct smp_streamer *streamer, void *req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_SMP_ */
diff --git a/smp/pkg.yml b/smp/pkg.yml
new file mode 100644
index 0000000..b9fcc78
--- /dev/null
+++ b/smp/pkg.yml
@@ -0,0 +1,40 @@
+#
+# 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: smp
+pkg.description: Server-side simple management protocol (SMP) functionality.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - '@apache-mynewt-core/encoding/cborattr'
+    - '@apache-mynewt-core/kernel/os'
+    - '@apache-mynewt-core/util/mem'
+    - '@mynewt-mcumgr/mgmt'
+    - '@mynewt-mcumgr/smp'
+
+pkg.deps.NEWTMGR_BLE_HOST:
+    - '@apache-mynewt-core/mgmt/newtmgr/transport/ble'
+
+pkg.apis:
+    - newtmgr
+
+pkg.init:
+    smp_pkg_init: 500
diff --git a/smp/src/smp.c b/smp/src/smp.c
new file mode 100644
index 0000000..b014be5
--- /dev/null
+++ b/smp/src/smp.c
@@ -0,0 +1,379 @@
+/*
+ * 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.
+ */
+
+/** SMP - Simple Management Protocol. */
+
+#include <assert.h>
+#include <string.h>
+
+#include "mgmt/endian.h"
+#include "mgmt/mgmt.h"
+#include "smp/smp.h"
+#include "cbor.h"
+
+static int
+smp_align4(int x)
+{
+    int rem;
+
+    rem = x % 4;
+    if (rem == 0) {
+        return x;
+    } else {
+        return x - rem + 4;
+    }
+}
+
+/**
+ * Converts a request opcode to its corresponding response opcode.
+ */
+static uint8_t
+smp_rsp_op(uint8_t req_op)
+{
+    if (req_op == MGMT_OP_READ) {
+        return MGMT_OP_READ_RSP;
+    } else {
+        return MGMT_OP_WRITE_RSP;
+    }
+}
+
+static void
+smp_init_rsp_hdr(const struct mgmt_hdr *req_hdr, struct mgmt_hdr *rsp_hdr)
+{
+    *rsp_hdr = (struct mgmt_hdr) {
+        .nh_len = 0,
+        .nh_flags = 0,
+        .nh_op = smp_rsp_op(req_hdr->nh_op),
+        .nh_group = req_hdr->nh_group,
+        .nh_seq = req_hdr->nh_seq,
+        .nh_id = req_hdr->nh_id,
+    };
+}
+
+static int
+smp_read_hdr(struct smp_streamer *streamer, struct mgmt_hdr *dst_hdr)
+{
+    struct cbor_decoder_reader *reader;
+
+    reader = streamer->mgmt_stmr.reader;
+
+    if (reader->message_size < sizeof *dst_hdr) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    reader->cpy(reader, (char *)dst_hdr, 0, sizeof *dst_hdr);
+    return 0;
+}
+
+static int
+smp_write_hdr(struct smp_streamer *streamer, const struct mgmt_hdr *src_hdr)
+{
+    int rc;
+
+    rc = mgmt_streamer_write_at(&streamer->mgmt_stmr, 0, src_hdr,
+                                sizeof *src_hdr);
+    return mgmt_err_from_cbor(rc);
+}
+
+static int
+smp_build_err_rsp(struct smp_streamer *streamer,
+                  const struct mgmt_hdr *req_hdr,
+                  int status)
+{
+    struct CborEncoder map;
+    struct mgmt_ctxt cbuf;
+    struct mgmt_hdr rsp_hdr;
+    int rc;
+
+    rc = mgmt_ctxt_init(&cbuf, &streamer->mgmt_stmr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    smp_init_rsp_hdr(req_hdr, &rsp_hdr);
+    rc = smp_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encoder_create_map(&cbuf.encoder, &map, CborIndefiniteLength);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = mgmt_write_rsp_status(&cbuf, status);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encoder_close_container(&cbuf.encoder, &map);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rsp_hdr.nh_len = cbor_encode_bytes_written(&cbuf.encoder) - MGMT_HDR_SIZE;
+    mgmt_hton_hdr(&rsp_hdr);
+    rc = smp_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+/**
+ * Processes a single SMP request and generates a response payload (i.e.,
+ * everything after the management header).  On success, the response payload
+ * is written to the supplied cbuf but not transmitted.  On failure, no error
+ * response gets written; the caller is expected to build an error response
+ * from the return code.
+ *
+ * @param cbuf                  A cbuf containing the request and response
+ *                                  buffer.
+ * @param req_hdr               The management header belonging to the incoming
+ *                                  request (host-byte order).
+ *
+ * @return                      A MGMT_ERR_[...] error code.
+ */
+static int
+smp_handle_single_payload(struct mgmt_ctxt *cbuf,
+                          const struct mgmt_hdr *req_hdr)
+{
+    const struct mgmt_handler *handler;
+    struct CborEncoder payload_encoder;
+    int rc;
+
+    handler = mgmt_find_handler(req_hdr->nh_group, req_hdr->nh_id);
+    if (handler == NULL) {
+        return MGMT_ERR_ENOTSUP;
+    }
+
+    /* Begin response payload.  Response fields are inserted into the root
+     * map as key value pairs.
+     */
+    rc = cbor_encoder_create_map(&cbuf->encoder, &payload_encoder,
+                                 CborIndefiniteLength);
+    rc = mgmt_err_from_cbor(rc);
+    if (rc != 0) {
+        return rc;
+    }
+
+    switch (req_hdr->nh_op) {
+    case MGMT_OP_READ:
+        if (handler->mh_read != NULL) {
+            rc = handler->mh_read(cbuf);
+        } else {
+            rc = MGMT_ERR_ENOTSUP;
+        }
+        break;
+
+    case MGMT_OP_WRITE:
+        if (handler->mh_write != NULL) {
+            rc = handler->mh_write(cbuf);
+        } else {
+            rc = MGMT_ERR_ENOTSUP;
+        }
+        break;
+
+    default:
+        rc = MGMT_ERR_EINVAL;
+        break;
+    }
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* End response payload. */
+    rc = cbor_encoder_close_container(&cbuf->encoder, &payload_encoder);
+    return mgmt_err_from_cbor(rc);
+}
+
+/**
+ * Processes a single SMP request and generates a complete response (i.e.,
+ * header and payload).  On success, the response is written using the supplied
+ * streamer but not transmitted.  On failure, no error response gets written;
+ * the caller is expected to build an error response from the return code.
+ *
+ * @param streamer              The SMP streamer to use for reading the request
+ *                                  and writing the response.
+ * @param req_hdr               The management header belonging to the incoming
+ *                                  request (host-byte order).
+ *
+ * @return                      A MGMT_ERR_[...] error code.
+ */
+static int
+smp_handle_single_req(struct smp_streamer *streamer,
+                      const struct mgmt_hdr *req_hdr)
+{
+    struct mgmt_ctxt cbuf;
+    struct mgmt_hdr rsp_hdr;
+    int rc;
+
+    rc = mgmt_ctxt_init(&cbuf, &streamer->mgmt_stmr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Write a dummy header to the beginning of the response buffer.  Some
+     * fields will need to be fixed up later.
+     */
+    smp_init_rsp_hdr(req_hdr, &rsp_hdr);
+    rc = smp_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Process the request and write the response payload. */
+    rc = smp_handle_single_payload(&cbuf, req_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Fix up the response header with the correct length. */
+    rsp_hdr.nh_len = cbor_encode_bytes_written(&cbuf.encoder) - MGMT_HDR_SIZE;
+    mgmt_hton_hdr(&rsp_hdr);
+    rc = smp_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+/**
+ * Attempts to transmit an SMP error response.  This function consumes both
+ * supplied buffers.
+ *
+ * @param streamer              The SMP streamer for building and transmitting
+ *                                  the response.
+ * @param req_hdr               The header of the request which elicited the
+ *                                  error.
+ * @param req                   The buffer holding the request.
+ * @param rsp                   The buffer holding the response, or NULL if
+ *                                  none was allocated.
+ * @param status                The status to indicate in the error response.
+ */
+static void
+smp_on_err(struct smp_streamer *streamer, const struct mgmt_hdr *req_hdr,
+           void *req, void *rsp, int status)
+{
+    int rc;
+
+    /* Prefer the response buffer for holding the error response.  If no
+     * response buffer was allocated, use the request buffer instead.
+     */
+    if (rsp == NULL) {
+        rsp = req;
+        req = NULL;
+    }
+
+    /* Clear the partial response from the buffer, if any. */
+    mgmt_streamer_reset_buf(&streamer->mgmt_stmr, rsp);
+    mgmt_streamer_init_writer(&streamer->mgmt_stmr, rsp);
+
+    /* Build and transmit the error response. */
+    rc = smp_build_err_rsp(streamer, req_hdr, status);
+    if (rc == 0) {
+        streamer->tx_rsp_cb(streamer, rsp, streamer->mgmt_stmr.cb_arg);
+        rsp = NULL;
+    }
+
+    /* Free any extra buffers. */
+    mgmt_streamer_free_buf(&streamer->mgmt_stmr, req);
+    mgmt_streamer_free_buf(&streamer->mgmt_stmr, rsp);
+}
+
+/**
+ * Processes all SMP requests in an incoming packet.  Requests are processed
+ * sequentially from the start of the packet to the end.  Each response is sent
+ * individually in its own packet.  If a request elicits an error response,
+ * processing of the packet is aborted.  This function consumes the supplied
+ * request buffer regardless of the outcome.
+ *
+ * @param streamer              The streamer to use for reading, writing, and
+ *                                  transmitting.
+ * @param req                   A buffer containing the request packet.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int
+smp_process_request_packet(struct smp_streamer *streamer, void *req)
+{
+    struct mgmt_hdr req_hdr;
+    void *rsp;
+    bool valid_hdr;
+    int rc;
+
+    rsp = NULL;
+    valid_hdr = true;
+
+    while (1) {
+        rc = mgmt_streamer_init_reader(&streamer->mgmt_stmr, req);
+        if (rc != 0) {
+            valid_hdr = false;
+            break;
+        }
+
+        /* Read the management header and strip it from the request. */
+        rc = smp_read_hdr(streamer, &req_hdr);
+        if (rc != 0) {
+            valid_hdr = false;
+            break;
+        }
+        mgmt_ntoh_hdr(&req_hdr);
+        mgmt_streamer_trim_front(&streamer->mgmt_stmr, req, MGMT_HDR_SIZE);
+
+        rsp = mgmt_streamer_alloc_rsp(&streamer->mgmt_stmr, req);
+        if (rsp == NULL) {
+            rc = MGMT_ERR_ENOMEM;
+            break;
+        }
+
+        rc = mgmt_streamer_init_writer(&streamer->mgmt_stmr, rsp);
+        if (rc != 0) {
+            break;
+        }
+
+        /* Process the request payload and build the response. */
+        rc = smp_handle_single_req(streamer, &req_hdr);
+        if (rc != 0) {
+            break;
+        }
+
+        /* Send the response. */
+        rc = streamer->tx_rsp_cb(streamer, rsp, streamer->mgmt_stmr.cb_arg);
+        rsp = NULL;
+        if (rc != 0) {
+            break;
+        }
+
+        /* Trim processed request to free up space for subsequent responses. */
+        mgmt_streamer_trim_front(&streamer->mgmt_stmr, req,
+                                 smp_align4(req_hdr.nh_len));
+    }
+
+    if (rc != 0 && valid_hdr) {
+        smp_on_err(streamer, &req_hdr, req, rsp, rc);
+        return rc;
+    }
+
+    mgmt_streamer_free_buf(&streamer->mgmt_stmr, req);
+    mgmt_streamer_free_buf(&streamer->mgmt_stmr, rsp);
+    return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 09/42: Mynewt support.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 6974956f30578a763f8aac394d0c52fcc5e31b1b
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:15:59 2018 -0800

    Mynewt support.
---
 cmd/fs_mgmt/pkg.yml                            |  27 ++++
 cmd/fs_mgmt/port/mynewt/src/mynewt_fs_mgmt.c   | 106 ++++++++++++
 cmd/fs_mgmt/syscfg.yml                         |  40 +++++
 cmd/img_mgmt/pkg.yml                           |  30 ++++
 cmd/img_mgmt/port/mynewt/src/mynewt_img_mgmt.c | 214 +++++++++++++++++++++++++
 cmd/img_mgmt/syscfg.yml                        |  26 +++
 cmd/os_mgmt/pkg.yml                            |  27 ++++
 cmd/os_mgmt/port/mynewt/src/mynewt_os_mgmt.c   | 116 ++++++++++++++
 cmd/os_mgmt/syscfg.yml                         |  26 +++
 repository.yml                                 |  25 +++
 10 files changed, 637 insertions(+)

diff --git a/cmd/fs_mgmt/pkg.yml b/cmd/fs_mgmt/pkg.yml
new file mode 100644
index 0000000..9452cc6
--- /dev/null
+++ b/cmd/fs_mgmt/pkg.yml
@@ -0,0 +1,27 @@
+#
+# 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: cmd/fs_mgmt
+pkg.description: 'File system command handlers for mcumgr.'
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - '@apache-mynewt-core/fs/fs'
diff --git a/cmd/fs_mgmt/port/mynewt/src/mynewt_fs_mgmt.c b/cmd/fs_mgmt/port/mynewt/src/mynewt_fs_mgmt.c
new file mode 100644
index 0000000..632bd1e
--- /dev/null
+++ b/cmd/fs_mgmt/port/mynewt/src/mynewt_fs_mgmt.c
@@ -0,0 +1,106 @@
+/*
+ * 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 "mgmt/mgmt.h"
+#include "fs_mgmt/fs_mgmt_impl.h"
+#include "fs/fs.h"
+
+int
+fs_mgmt_impl_filelen(const char *path, size_t *out_len)
+{
+    struct fs_file *file;
+    int rc;
+
+    rc = fs_open(path, FS_ACCESS_READ, &file);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = fs_filelen(file, &out_len);
+    fs_close(file);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+int
+fs_mgmt_impl_read(const char *path, size_t offset, size_t len,
+                  void *out_data, size_t *out_len)
+{
+    struct fs_file *file;
+    uint32_t bytes_read;
+    int rc;
+
+    rc = fs_open(path, FS_ACCESS_READ, &file);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = fs_seek(file, offset);
+    if (rc != 0) {
+        goto done;
+    }
+
+    rc = fs_read(file, len, file_data, &bytes_read);
+    if (rc != 0) {
+        goto done;
+    }
+
+    *out_len = bytes_read;
+
+done:
+    fs_close(file);
+
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+int
+fs_mgmt_impl_write(const char *path, size_t offset, const void *data,
+                   size_t len)
+{
+    struct fs_file *file;
+    uint8_t access;
+    int rc;
+ 
+    access = FS_ACCESS_WRITE;
+    if (offset == 0) {
+        access |= FS_ACCESS_TRUNCATE;
+    } else {
+        access |= FS_ACCESS_APPEND;
+    }
+
+    rc = fs_open(path, access, &file);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = fs_write(file, data, len);
+    fs_close(file);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
diff --git a/cmd/fs_mgmt/syscfg.yml b/cmd/fs_mgmt/syscfg.yml
new file mode 100644
index 0000000..888c84a
--- /dev/null
+++ b/cmd/fs_mgmt/syscfg.yml
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+syscfg.defs:
+    FS_MGMT_UL_CHUNK_SIZE:
+        description: >
+            Limits the maximum chunk size in file uploads.  A buffer of this
+            size gets allocated on the stack during handling of a file upload
+            command.
+        value: 512
+
+    FS_MGMT_DL_CHUNK_SIZE:
+        description: >
+            Limits the maximum chunk size in file downloads.  A buffer of this
+            size gets allocated on the stack during handling of a file download
+            command.
+        value: 512
+
+    FS_MGMT_PATH_SIZE:
+        description: >
+            Limits the maximum path length in file operations.  A buffer of
+            this size gets allocated on the stack during handling of file
+            upload and download commands.
+        value: 64
diff --git a/cmd/img_mgmt/pkg.yml b/cmd/img_mgmt/pkg.yml
new file mode 100644
index 0000000..fd27c07
--- /dev/null
+++ b/cmd/img_mgmt/pkg.yml
@@ -0,0 +1,30 @@
+#
+# 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: cmd/img_mgmt
+pkg.description: 'Image management command handlers for mcumgr.'
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - '@apache-mynewt-core/boot/split'
+    - '@apache-mynewt-core/encoding/base64'
+    - '@apache-mynewt-core/sys/flash_map'
+    - '@mynewt-mcumgr/mgmt'
diff --git a/cmd/img_mgmt/port/mynewt/src/mynewt_img_mgmt.c b/cmd/img_mgmt/port/mynewt/src/mynewt_img_mgmt.c
new file mode 100644
index 0000000..c645d1b
--- /dev/null
+++ b/cmd/img_mgmt/port/mynewt/src/mynewt_img_mgmt.c
@@ -0,0 +1,214 @@
+/*
+ * 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 "sysinit/sysinit.h"
+#include "mgmt/mgmt.h"
+#include "img_mgmt/img_mgmt_impl.h"
+#include "img_mgmt/img_mgmt.h"
+#include "img_mgmt_priv.h"
+
+int
+img_mgmt_impl_erase_slot(void)
+{
+    const struct flash_area *fa;
+    bool empty;
+    int rc;
+
+    rc = flash_area_open(FLASH_AREA_IMAGE_1, &fa);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = flash_area_is_empty(fa, &empty);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (!empty) {
+        rc = flash_area_erase(fa, 0, fa->fa_size);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_write_pending(int slot, bool permanent)
+{
+    uint32_t image_flags;
+    uint8_t state_flags;
+    int split_app_active;
+    int rc;
+
+    state_flags = imgmgr_state_flags(slot);
+    split_app_active = split_app_active_get();
+
+    /* Unconfirmed slots are always runable.  A confirmed slot can only be
+     * run if it is a loader in a split image setup.
+     */
+    if (state_flags & IMGMGR_STATE_F_CONFIRMED &&
+        (slot != 0 || !split_app_active)) {
+
+        return MGMT_ERR_EBADSTATE;
+    }
+
+    rc = imgr_read_info(slot, NULL, NULL, &image_flags);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (!(image_flags & IMAGE_F_NON_BOOTABLE)) {
+        /* Unified image or loader. */
+        if (!split_app_active) {
+            /* No change in split status. */
+            rc = boot_set_pending(permanent);
+            if (rc != 0) {
+                return MGMT_ERR_EUNKNOWN;
+            }
+        } else {
+            /* Currently loader + app; testing loader-only. */
+            if (permanent) {
+                rc = split_write_split(SPLIT_MODE_LOADER);
+            } else {
+                rc = split_write_split(SPLIT_MODE_TEST_LOADER);
+            }
+            if (rc != 0) {
+                return MGMT_ERR_EUNKNOWN;
+            }
+        }
+    } else {
+        /* Testing split app. */
+        if (permanent) {
+            rc = split_write_split(SPLIT_MODE_APP);
+        } else {
+            rc = split_write_split(SPLIT_MODE_TEST_APP);
+        }
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_write_confirmed(void)
+{
+    /* Confirm the unified image or loader in slot 0. */
+    rc = boot_set_confirmed();
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    /* If a split app in slot 1 is active, confirm it as well. */
+    if (split_app_active_get()) {
+        rc = split_write_split(SPLIT_MODE_APP);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+    } else {
+        rc = split_write_split(SPLIT_MODE_LOADER);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_read(int slot, unsigned int offset, void *dst,
+                   unsigned int num_bytes)
+{
+    const struct flash_area *fa;
+    int area_id;
+    int rc;
+
+    area_id = flash_area_id_from_image_slot(image_slot);
+    rc = flash_area_open(area_id, &fa);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = flash_area_read(fa, offset, dst, num_bytes);
+    flash_area_close(fa);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_write_image_data(unsigned int offset, const void *data,
+                               unsigned int num_bytes, bool last)
+{
+    const struct flash_area *fa;
+    int rc;
+
+    rc = flash_area_open(FLASH_AREA_IMAGE_1, &fa);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = flash_area_write(fa, offset, data, num_bytes);
+    flash_area_close(fa);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_swap_type(void)
+{
+    switch (boot_swap_type()) {
+    case BOOT_SWAP_TYPE_NONE:
+        return IMG_MGMT_SWAP_TYPE_NONE;
+    case BOOT_SWAP_TYPE_TEST:
+        return IMG_MGMT_SWAP_TYPE_TEST;
+    case BOOT_SWAP_TYPE_PERM:
+        return IMG_MGMT_SWAP_TYPE_PERM;
+    case BOOT_SWAP_TYPE_REVERT:
+        return IMG_MGMT_SWAP_TYPE_REVERT;
+    default:
+        assert(0);
+        return IMG_MGMT_SWAP_TYPE_NONE;
+    }
+}
+
+void
+img_mgmt_module_init(void)
+{
+    int rc;
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+    rc = img_mgmt_register_group();
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+#if MYNEWT_VAL(IMGMGR_CLI)
+    rc = imgr_cli_register();
+    SYSINIT_PANIC_ASSERT(rc == 0);
+#endif
+}
diff --git a/cmd/img_mgmt/syscfg.yml b/cmd/img_mgmt/syscfg.yml
new file mode 100644
index 0000000..ac4095f
--- /dev/null
+++ b/cmd/img_mgmt/syscfg.yml
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+syscfg.defs:
+    IMG_MGMT_UL_CHUNK_SIZE:
+        description: >
+            Limits the maximum chunk size in image uploads.  A buffer of this
+            size gets allocated on the stack during handling of a image upload
+            command.
+        value: 512
diff --git a/cmd/os_mgmt/pkg.yml b/cmd/os_mgmt/pkg.yml
new file mode 100644
index 0000000..c1389c4
--- /dev/null
+++ b/cmd/os_mgmt/pkg.yml
@@ -0,0 +1,27 @@
+#
+# 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: cmd/os_mgmt
+pkg.description: 'OS management command handlers for mcumgr.'
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - '@apache-mynewt-core/kernel/os'
diff --git a/cmd/os_mgmt/port/mynewt/src/mynewt_os_mgmt.c b/cmd/os_mgmt/port/mynewt/src/mynewt_os_mgmt.c
new file mode 100644
index 0000000..ccb94f0
--- /dev/null
+++ b/cmd/os_mgmt/port/mynewt/src/mynewt_os_mgmt.c
@@ -0,0 +1,116 @@
+/*
+ * 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 "hal/hal_system.h"
+#include "hal/hal_watchdog.h"
+#include "os/os.h"
+#if MYNEWT_VAL(LOG_SOFT_RESET)
+#include "reboot/log_reboot.h"
+#endif
+#include "os_mgmt/os_mgmt_impl.h"
+
+static struct os_callout mynewt_os_mgmt_reset_callout;
+
+static void
+mynewt_os_mgmt_reset_tmo(struct os_event *ev)
+{
+    /* Tickle watchdog just before re-entering bootloader.  Depending on what
+     * the system has been doing lately, the watchdog timer might be close to
+     * firing.
+     */
+    hal_watchdog_tickle();
+    hal_system_reset();
+}
+
+static uint16_t
+mynewt_os_mgmt_stack_usage(const struct os_task *task)
+{
+    const os_stack_t *bottom;
+    const os_stack_t *top;
+
+    top = task->t_stacktop;
+    bottom = task->t_stacktop - task->t_stacksize;
+    while (bottom < top) {
+        if (*bottom != OS_STACK_PATTERN) {
+            break;
+        }
+        ++bottom;
+    }
+
+    return task->t_stacktop - bottom;
+}
+
+static const struct os_task *
+mynewt_os_mgmt_task_at(int idx)
+{
+    const struct os_task *task;
+    int i;
+
+    task = STAILQ_FIRST(&g_os_task_list);
+    for (i = 0; i < idx; i++) {
+        if (task == NULL) {
+            break;
+        }
+
+        task = STAILQ_NEXT(task, t_os_task_list);
+    }
+
+    return task;
+}
+
+int
+os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info)
+{
+    const struct os_task *task;
+
+    task = mynewt_os_mgmt_task_at(idx);
+    if (task == NULL) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    out_info->oti_prio = task->t_prio;
+    out_info->oti_taskid = task->t_taskid;
+    out_info->oti_state = task->t_state;
+    out_info->oti_stkusage = mynewt_os_mgmt_stack_usage(task);
+    out_info->oti_stksize = task->t_stacksize;
+    out_info->oti_cswcnt = task->t_ctx_sw_cnt;
+    out_info->oti_runtime = task->t_run_time;
+    out_info->oti_last_checkin = task->t_sanity_check.sc_checkin_last;
+    out_info->oti_next_checkin = task->t_sanity_check.sc_checkin_last +
+                                 task->t_sanity_check.sc_checkin_itvl;
+    strncpy(out_info->oti_name, task->t_name, sizeof out_info->oti_name);
+
+    return 0;
+}
+
+int
+os_mgmt_impl_reset(unsigned int delay_ms)
+{
+    int rc;
+
+    os_callout_init(&mynewt_os_mgmt_reset_callout, mgmt_evq_get(),
+                    nmgr_reset_tmo, NULL);
+
+#if MYNEWT_VAL(LOG_SOFT_RESET)
+    log_reboot(HAL_RESET_REQUESTED);
+#endif
+    os_callout_reset(&nmgr_reset_callout, delay_ms * OS_TICKS_PER_SEC / 1000);
+
+    return 0;
+}
diff --git a/cmd/os_mgmt/syscfg.yml b/cmd/os_mgmt/syscfg.yml
new file mode 100644
index 0000000..7ecb7c0
--- /dev/null
+++ b/cmd/os_mgmt/syscfg.yml
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+syscfg.defs:
+    OS_MGMT_RESET_MS:
+        description: >
+            When a reset command is received, the system waits this many
+            milliseconds before performing the reset.  This delay allows time
+            for the mcumgr response to be delivered.
+        value: 250
diff --git a/repository.yml b/repository.yml
new file mode 100644
index 0000000..c2495ce
--- /dev/null
+++ b/repository.yml
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+repo.name: mynewt-mcumgr
+repo.versions:
+    "0.0.0": "master"
+
+    "0-latest": "0.0.0"
+    "0-dev": "0.0.0"

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 36/42: Remove "zephyr, code_partition" from dts overlay

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 821f578be1bf5a75db6a95b611dd2d50608fb19f
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Feb 12 13:03:34 2018 -0800

    Remove "zephyr,code_partition" from dts overlay
    
    This is no longer needed now that MCUboot has been integrated more fully
    into Zephyr.
---
 samples/smp_svr/zephyr/dts.overlay | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/samples/smp_svr/zephyr/dts.overlay b/samples/smp_svr/zephyr/dts.overlay
index 5a3a7f3..7e73db7 100644
--- a/samples/smp_svr/zephyr/dts.overlay
+++ b/samples/smp_svr/zephyr/dts.overlay
@@ -4,9 +4,6 @@
 
 / {
 	chosen {
-		/* Required by mcuboot. */
-		zephyr,code-partition = &slot0_partition;
-
 		/* Use uart0 for the mcumgr UART transport. */
 		zephyr,uart-mcumgr = &uart0;
 	};

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 12/42: Remove extraneous README.rst file.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit db04a3084835b6593d7784ba6c0964904d2a66c8
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 15:44:11 2018 -0800

    Remove extraneous README.rst file.
    
    This file belongs to the "Hello World" sample app in the Zephyr
    repository.
---
 samples/smp_svr/zephyr/README.rst | 41 ---------------------------------------
 1 file changed, 41 deletions(-)

diff --git a/samples/smp_svr/zephyr/README.rst b/samples/smp_svr/zephyr/README.rst
deleted file mode 100644
index 00218b0..0000000
--- a/samples/smp_svr/zephyr/README.rst
+++ /dev/null
@@ -1,41 +0,0 @@
-.. _hello_world:
-
-Hello World
-###########
-
-Overview
-********
-A simple Hello World example that can be used with any supported board and
-prints 'Hello World' to the console. This application can be built into modes:
-
-* single thread
-* multi threading
-
-Building and Running
-********************
-
-This project outputs 'Hello World' to the console.  It can be built and executed
-on QEMU as follows:
-
-.. zephyr-app-commands::
-   :zephyr-app: samples/hello_world
-   :board: qemu_x86
-   :goals: run
-   :compact:
-
-To build the single thread version, use the supplied configuration file for
-single thread: :file:`prj_single.conf`:
-
-.. zephyr-app-commands::
-   :zephyr-app: samples/hello_world
-   :board: qemu_x86
-   :conf: prj_single.conf
-   :goals: run
-   :compact:
-
-Sample Output
-=============
-
-.. code-block:: console
-
-    Hello World! x86

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 01/42: Initial commit.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 9eee2c690d7605e3ede0618be1710b08e90961c1
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Dec 7 16:55:48 2017 -0800

    Initial commit.
---
 .gitignore | 37 +++++++++++++++++++++++++++++++++++++
 README.md  |  1 +
 2 files changed, 38 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..91be3d8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+.app.db
+.app
+bin
+obj
+tags
+.gdb_history
+.gdb_out
+.gdb_cmds
+.gdbinit
+*~
+.DS_Store
+*.swp
+*.swo
+*.bak
+docs/html
+docs/latex
+cscope.*
+*.tags
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3a9710e
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# mynewt-mcumgr

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 28/42: Correct "MCUboot" spelling in documentation.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit e4db21b4ea2042cb9929fa22b9e85dd5c4138cf5
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 31 16:31:39 2018 -0800

    Correct "MCUboot" spelling in documentation.
    
    MCUBoot --> MCUboot.
---
 README.md                 | 2 +-
 samples/smp_svr/README.md | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index bbe0016..4726883 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ the list below:
 ## Dependencies
 
 To use mcumgr's image management support, your device must be running the
-MCUBoot boot loader (https://github.com/runtimeco/mcuboot).  The other mcumgr
+MCUboot boot loader (https://github.com/runtimeco/mcuboot).  The other mcumgr
 features do not require MCUboot.
 
 ## Command line tool
diff --git a/samples/smp_svr/README.md b/samples/smp_svr/README.md
index 6ff9dcd..5e99d83 100644
--- a/samples/smp_svr/README.md
+++ b/samples/smp_svr/README.md
@@ -50,7 +50,7 @@ the file system management commands will not work.  To enable file system
 management for a different platform, adjust the `CONFIG_FS_NFFS_FLASH_DEV_NAME`
 setting in `prj.conf` accordingly.
 
-In addition, the MCUBoot boot loader (https://github.com/runtimeco/mcuboot) is
+In addition, the MCUboot boot loader (https://github.com/runtimeco/mcuboot) is
 required for img_mgmt to function properly.
 
 The smp_svr app logs reboots to a flash circular buffer (FCB) backed log.  The

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 14/42: Add missing license text.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 4df50f799f7b4fb9b9ef953ab64bdd8e6d5cc0c6
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 15:45:20 2018 -0800

    Add missing license text.
---
 cmd/fs_mgmt/src/fs_mgmt_config.h   | 19 +++++++++++++++++++
 cmd/img_mgmt/src/img_mgmt_config.h | 19 +++++++++++++++++++
 cmd/os_mgmt/src/os_mgmt_config.h   | 19 +++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/cmd/fs_mgmt/src/fs_mgmt_config.h b/cmd/fs_mgmt/src/fs_mgmt_config.h
index 81fb7dd..deaec8a 100644
--- a/cmd/fs_mgmt/src/fs_mgmt_config.h
+++ b/cmd/fs_mgmt/src/fs_mgmt_config.h
@@ -1,3 +1,22 @@
+/*
+ * 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 H_FS_MGMT_CONFIG_
 #define H_FS_MGMT_CONFIG_
 
diff --git a/cmd/img_mgmt/src/img_mgmt_config.h b/cmd/img_mgmt/src/img_mgmt_config.h
index 4ec8295..a520372 100644
--- a/cmd/img_mgmt/src/img_mgmt_config.h
+++ b/cmd/img_mgmt/src/img_mgmt_config.h
@@ -1,3 +1,22 @@
+/*
+ * 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 H_IMG_MGMT_CONFIG_
 #define H_IMG_MGMT_CONFIG_
 
diff --git a/cmd/os_mgmt/src/os_mgmt_config.h b/cmd/os_mgmt/src/os_mgmt_config.h
index d388dec..fee386b 100644
--- a/cmd/os_mgmt/src/os_mgmt_config.h
+++ b/cmd/os_mgmt/src/os_mgmt_config.h
@@ -1,3 +1,22 @@
+/*
+ * 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 H_OS_MGMT_CONFIG_
 #define H_OS_MGMT_CONFIG_
 

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 02/42: mgmt - Code implementing the core `mgmt` layer.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit b9e2cf860399324c848692f8ef5cd8d61407213f
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:11:06 2018 -0800

    mgmt - Code implementing the core `mgmt` layer.
    
    The core of mcumgr; facilitates the passing of requests and responses
    between the generic command handlers and the concrete transports and
    transfer encodings.
---
 mgmt/CMakeLists.txt        |   8 +
 mgmt/include/mgmt/endian.h |  58 +++++++
 mgmt/include/mgmt/mgmt.h   | 388 +++++++++++++++++++++++++++++++++++++++++++++
 mgmt/pkg.yml               |  29 ++++
 mgmt/src/mgmt.c            | 170 ++++++++++++++++++++
 mgmt/syscfg.yml            |  18 +++
 6 files changed, 671 insertions(+)

diff --git a/mgmt/CMakeLists.txt b/mgmt/CMakeLists.txt
new file mode 100644
index 0000000..ffce8a5
--- /dev/null
+++ b/mgmt/CMakeLists.txt
@@ -0,0 +1,8 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+    port/zephyr/include
+)
+
+zephyr_library_sources(
+    mgmt/src/mgmt.c
+)
diff --git a/mgmt/include/mgmt/endian.h b/mgmt/include/mgmt/endian.h
new file mode 100644
index 0000000..ad9bd34
--- /dev/null
+++ b/mgmt/include/mgmt/endian.h
@@ -0,0 +1,58 @@
+/*
+ * 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 H_MGMT_ENDIAN_
+#define H_MGMT_ENDIAN_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+
+#ifndef ntohs
+#define ntohs(x) (x)
+#endif
+
+#ifndef htons
+#define htons(x) (x)
+#endif
+
+#else
+/* Little endian. */
+
+#ifndef ntohs
+#define ntohs(x)   ((uint16_t)  \
+    ((((x) & 0xff00) >> 8) |    \
+     (((x) & 0x00ff) << 8)))
+#endif
+
+#ifndef htons
+#define htons(x) (ntohs(x))
+#endif
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mgmt/include/mgmt/mgmt.h b/mgmt/include/mgmt/mgmt.h
new file mode 100644
index 0000000..549fcdc
--- /dev/null
+++ b/mgmt/include/mgmt/mgmt.h
@@ -0,0 +1,388 @@
+/*
+ * 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 H_MGMT_MGMT_
+#define H_MGMT_MGMT_
+
+#include <inttypes.h>
+#include "cbor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Opcodes; encoded in first byte of header. */
+#define MGMT_OP_READ            0
+#define MGMT_OP_READ_RSP        1
+#define MGMT_OP_WRITE           2
+#define MGMT_OP_WRITE_RSP       3
+
+/**
+ * The first 64 groups are reserved for system level mcumgr commands.
+ * Per-user commands are then defined after group 64.
+ */
+#define MGMT_GROUP_ID_OS        0
+#define MGMT_GROUP_ID_IMAGE     1
+#define MGMT_GROUP_ID_STATS     2
+#define MGMT_GROUP_ID_CONFIG    3
+#define MGMT_GROUP_ID_LOGS      4
+#define MGMT_GROUP_ID_CRASH     5
+#define MGMT_GROUP_ID_SPLIT     6
+#define MGMT_GROUP_ID_RUN       7
+#define MGMT_GROUP_ID_FS        8
+#define MGMT_GROUP_ID_PERUSER   64
+
+/**
+ * mcumgr error codes.
+ */
+#define MGMT_ERR_EOK            0
+#define MGMT_ERR_EUNKNOWN       1
+#define MGMT_ERR_ENOMEM         2
+#define MGMT_ERR_EINVAL         3
+#define MGMT_ERR_ETIMEOUT       4
+#define MGMT_ERR_ENOENT         5
+#define MGMT_ERR_EBADSTATE      6       /* Current state disallows command. */
+#define MGMT_ERR_EMSGSIZE       7       /* Response too large. */
+#define MGMT_ERR_ENOTSUP        8       /* Command not supported. */
+#define MGMT_ERR_EPERUSER       256
+
+#define MGMT_HDR_SIZE           8
+
+struct mgmt_hdr {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    uint8_t  nh_op:3;           /* MGMT_OP_[...] */
+    uint8_t  _res1:5;
+#endif
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    uint8_t  _res1:5;
+    uint8_t  nh_op:3;           /* MGMT_OP_[...] */
+#endif
+    uint8_t  nh_flags;          /* Reserved for future flags */
+    uint16_t nh_len;            /* Length of the payload */
+    uint16_t nh_group;          /* MGMT_GROUP_ID_[...] */
+    uint8_t  nh_seq;            /* Sequence number */
+    uint8_t  nh_id;             /* Message ID within group */
+};
+
+/** @typedef mgmt_alloc_rsp_fn
+ * @brief Allocates a buffer suitable for holding a response.
+ *
+ * If a source buf is provided, its user data is copied into the new buffer.
+ *
+ * @param src_buf               An optional source buffer to copy user data
+ *                                  from.
+ * @param arg                   Optional streamer argument.
+ *
+ * @return                      Newly-allocated buffer on success
+ *                              NULL on failure.
+ */
+typedef void *mgmt_alloc_rsp_fn(const void *src_buf, void *arg);
+
+/** @typedef mgmt_trim_front_fn
+ * @brief Trims data from the front of a buffer.
+ *
+ * If the amount to trim exceeds the size of the buffer, the buffer is
+ * truncated to a length of 0.
+ *
+ * @param buf                   The buffer to trim.
+ * @param len                   The number of bytes to remove.
+ * @param arg                   Optional streamer argument.
+ */
+typedef void mgmt_trim_front_fn(void *buf, size_t len, void *arg);
+
+/** @typedef mgmt_reset_buf_fn
+ * @brief Resets a buffer to a length of 0.
+ *
+ * The buffer's user data remains, but its payload is cleared.
+ *
+ * @param buf                   The buffer to reset.
+ * @param arg                   Optional streamer argument.
+ */
+typedef void mgmt_reset_buf_fn(void *buf, void *arg);
+
+/** @typedef mgmt_write_at_fn
+ * @brief Writes data to a CBOR encoder.
+ *
+ * Any existing data at the specified offset is overwritten by the new data.
+ * Any new data that extends past the buffer's current length is appended.
+ *
+ * @param writer                The encoder to write to.
+ * @param offset                The byte offset to write to,
+ * @param data                  The data to write.
+ * @param len                   The number of bytes to write.
+ * @param arg                   Optional streamer argument.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+typedef int mgmt_write_at_fn(struct cbor_encoder_writer *writer, size_t offset,
+                             const void *data, size_t len, void *arg);
+
+/** @typedef mgmt_init_reader_fn
+ * @brief Initializes a CBOR reader with the specified buffer.
+ *
+ * @param reader                The reader to initialize.
+ * @param buf                   The buffer to configure the reader with.
+ * @param arg                   Optional streamer argument.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+typedef int mgmt_init_reader_fn(struct cbor_decoder_reader *reader, void *buf,
+                                void *arg);
+
+/** @typedef mgmt_init_writer_fn
+ * @brief Initializes a CBOR writer with the specified buffer.
+ *
+ * @param writer                The writer to initialize.
+ * @param buf                   The buffer to configure the writer with.
+ * @param arg                   Optional streamer argument.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+typedef int mgmt_init_writer_fn(struct cbor_encoder_writer *writer, void *buf,
+                                void *arg);
+
+/** @typedef mgmt_init_writer_fn
+ * @brief Frees the specified buffer.
+ *
+ * @param buf                   The buffer to free.
+ * @param arg                   Optional streamer argument.
+ */
+typedef void mgmt_free_buf_fn(void *buf, void *arg);
+
+/**
+ * @brief Configuration for constructing a mgmt_streamer object.
+ */
+struct mgmt_streamer_cfg {
+    mgmt_alloc_rsp_fn *alloc_rsp;
+    mgmt_trim_front_fn *trim_front;
+    mgmt_reset_buf_fn *reset_buf;
+    mgmt_write_at_fn *write_at;
+    mgmt_init_reader_fn *init_reader;
+    mgmt_init_writer_fn *init_writer;
+    mgmt_free_buf_fn *free_buf;
+};
+
+/**
+ * @brief Decodes requests and encodes responses for any mcumgr protocol.
+ */
+struct mgmt_streamer {
+    const struct mgmt_streamer_cfg *cfg;
+    void *cb_arg;
+    struct cbor_decoder_reader *reader;
+    struct cbor_encoder_writer *writer;
+};
+
+/**
+ * @brief Context required by command handlers for parsing requests and writing
+ *        responses.
+ */
+struct mgmt_ctxt {
+    struct CborEncoder encoder;
+    struct CborParser parser;
+    struct CborValue it;
+};
+
+/** @typedef mgmt_handler_fn
+ * @brief Processes a request and writes the corresponding response.
+ *
+ * A separate handler is required for each supported op-ID pair.
+ *
+ * @param cbuf                  The mcumgr context to use.
+ *
+ * @return                      0 if a response was successfully encoded,
+ *                                 MGMT_ERR_[...] code on failure.
+ */
+typedef int mgmt_handler_fn(struct mgmt_ctxt *cbuf);
+
+/**
+ * @brief Read handler and write handler for a single command ID.
+ */
+struct mgmt_handler {
+    mgmt_handler_fn *mh_read;
+    mgmt_handler_fn *mh_write;
+};
+
+/**
+ * @brief A collection of handlers for an entire command group.
+ */
+struct mgmt_group {
+    /** Points to the next group in the list. */
+    struct mgmt_group *mg_next;
+
+    /** Array of handlers; one entry per command ID. */
+    const struct mgmt_handler *mg_handlers;
+    uint16_t mg_handlers_count;
+
+    /* The numeric ID of this group. */
+    uint16_t mg_group_id;
+};
+
+/**
+ * @brief Uses the specified streamer to allocates a response buffer.
+ *
+ * If a source buf is provided, its user data is copied into the new buffer.
+ *
+ * @param streamer              The streamer providing the callback.
+ * @param src_buf               An optional source buffer to copy user data
+ *                                  from.
+ *
+ * @return                      Newly-allocated buffer on success
+ *                              NULL on failure.
+ */
+void *mgmt_streamer_alloc_rsp(struct mgmt_streamer *streamer,
+                              const void *src_buf);
+
+/**
+ * @brief Uses the specified streamer to trim data from the front of a buffer.
+ *
+ * If the amount to trim exceeds the size of the buffer, the buffer is
+ * truncated to a length of 0.
+ *
+ * @param streamer              The streamer providing the callback.
+ * @param buf                   The buffer to trim.
+ * @param len                   The number of bytes to remove.
+ */
+void mgmt_streamer_trim_front(struct mgmt_streamer *streamer, void *buf,
+                              size_t len);
+
+/**
+ * @brief Uses the specified streamer to reset a buffer to a length of 0.
+ *
+ * The buffer's user data remains, but its payload is cleared.
+ *
+ * @param streamer              The streamer providing the callback.
+ * @param buf                   The buffer to reset.
+ */
+void mgmt_streamer_reset_buf(struct mgmt_streamer *streamer, void *buf);
+
+/**
+ * @brief Uses the specified streamer to write data to a CBOR encoder.
+ *
+ * Any existing data at the specified offset is overwritten by the new data.
+ * Any new data that extends past the buffer's current length is appended.
+ *
+ * @param streamer              The streamer providing the callback.
+ * @param writer                The encoder to write to.
+ * @param offset                The byte offset to write to,
+ * @param data                  The data to write.
+ * @param len                   The number of bytes to write.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int mgmt_streamer_write_at(struct mgmt_streamer *streamer, size_t offset,
+                           const void *data, int len);
+
+/**
+ * @brief Uses the specified streamer to initialize a CBOR reader.
+ *
+ * @param streamer              The streamer providing the callback.
+ * @param reader                The reader to initialize.
+ * @param buf                   The buffer to configure the reader with.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int mgmt_streamer_init_reader(struct mgmt_streamer *streamer, void *buf);
+
+/**
+ * @brief Uses the specified streamer to initializes a CBOR writer.
+ *
+ * @param streamer              The streamer providing the callback.
+ * @param writer                The writer to initialize.
+ * @param buf                   The buffer to configure the writer with.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int mgmt_streamer_init_writer(struct mgmt_streamer *streamer, void *buf);
+
+/**
+ * @brief Uses the specified streamer to free a buffer.
+ *
+ * @param streamer              The streamer providing the callback.
+ * @param buf                   The buffer to free.
+ */
+void mgmt_streamer_free_buf(struct mgmt_streamer *streamer, void *buf);
+
+/**
+ * @brief Registers a full command group.
+ *
+ * @param group                 The group to register.
+ */
+void mgmt_register_group(struct mgmt_group *group);
+
+/**
+ * @brief Finds a registered command handler.
+ *
+ * @param group_id              The group of the command to find.
+ * @param command_id            The ID of the command to find.
+ *
+ * @return                      The requested command handler on success;
+ *                              NULL on failure.
+ */
+const struct mgmt_handler *mgmt_find_handler(uint16_t group_id,
+                                             uint16_t command_id);
+
+/**
+ * @brief Encodes a response status into the specified management context.
+ *
+ * @param cbuf                  The management context to encode into.
+ * @param status                The response status to write.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int mgmt_write_rsp_status(struct mgmt_ctxt *cbuf, int status);
+
+/**
+ * @brief Initializes a management context object with the specified streamer.
+ *
+ * @param cbuf                  The context object to initialize.
+ * @param streamer              The streamer that will be used with the
+ *                                  context.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int mgmt_ctxt_init(struct mgmt_ctxt *cbuf, struct mgmt_streamer *streamer);
+
+/**
+ * @brief Converts a CBOR status code to a MGMT_ERR_[...] code.
+ *
+ * @param cbor_status           The CBOR status code to convert.
+ *
+ * @return                      The corresponding MGMT_ERR_[,,,] code.
+ */
+int mgmt_err_from_cbor(int cbor_status);
+
+/**
+ * @brief Byte-swaps an mcumgr header from network to host byte order.
+ *
+ * @param hdr                   The mcumgr header to byte-swap.
+ */
+void mgmt_ntoh_hdr(struct mgmt_hdr *hdr);
+
+/**
+ * @brief Byte-swaps an mcumgr header from host to network byte order.
+ *
+ * @param hdr                   The mcumgr header to byte-swap.
+ */
+void mgmt_hton_hdr(struct mgmt_hdr *hdr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MGMT_MGMT_H_ */
diff --git a/mgmt/pkg.yml b/mgmt/pkg.yml
new file mode 100644
index 0000000..94839bd
--- /dev/null
+++ b/mgmt/pkg.yml
@@ -0,0 +1,29 @@
+#
+# 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: mgmt
+pkg.description: 'System-wide mcumgr management interfaces.'
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - '@apache-mynewt-core/encoding/tinycbor'
+    - '@apache-mynewt-core/kernel/os'
+    - '@mynewt-mcumgr/mgmt'
diff --git a/mgmt/src/mgmt.c b/mgmt/src/mgmt.c
new file mode 100644
index 0000000..ccea65a
--- /dev/null
+++ b/mgmt/src/mgmt.c
@@ -0,0 +1,170 @@
+/*
+ * 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 <string.h>
+#include "cbor.h"
+#include "mgmt/endian.h"
+#include "mgmt/mgmt.h"
+
+static struct mgmt_group *mgmt_group_list;
+static struct mgmt_group *mgmt_group_list_end;
+
+void *
+mgmt_streamer_alloc_rsp(struct mgmt_streamer *streamer, const void *req)
+{
+    return streamer->cfg->alloc_rsp(req, streamer->cb_arg);
+}
+
+void
+mgmt_streamer_trim_front(struct mgmt_streamer *streamer, void *buf, size_t len)
+{
+    streamer->cfg->trim_front(buf, len, streamer->cb_arg);
+}
+
+void
+mgmt_streamer_reset_buf(struct mgmt_streamer *streamer, void *buf)
+{
+    streamer->cfg->reset_buf(buf, streamer->cb_arg);
+}
+
+int
+mgmt_streamer_write_at(struct mgmt_streamer *streamer, size_t offset,
+                       const void *data, int len)
+{
+    return streamer->cfg->write_at(streamer->writer, offset, data, len,
+                                   streamer->cb_arg);
+}
+
+int
+mgmt_streamer_init_reader(struct mgmt_streamer *streamer, void *buf)
+{
+    return streamer->cfg->init_reader(streamer->reader, buf, streamer->cb_arg);
+}
+
+int
+mgmt_streamer_init_writer(struct mgmt_streamer *streamer, void *buf)
+{
+    return streamer->cfg->init_writer(streamer->writer, buf, streamer->cb_arg);
+}
+
+void
+mgmt_streamer_free_buf(struct mgmt_streamer *streamer, void *buf)
+{
+    streamer->cfg->free_buf(buf, streamer->cb_arg);
+}
+
+void
+mgmt_register_group(struct mgmt_group *group)
+{
+    if (mgmt_group_list_end == NULL) {
+        mgmt_group_list = group;
+    } else {
+        mgmt_group_list_end->mg_next = group;
+    }
+    mgmt_group_list_end = group;
+}
+
+static struct mgmt_group *
+mgmt_find_group(uint16_t group_id)
+{
+    struct mgmt_group *group;
+
+    for (group = mgmt_group_list; group != NULL; group = group->mg_next) {
+        if (group->mg_group_id == group_id) {
+            return group;
+        }
+    }
+
+    return NULL;
+}
+
+const struct mgmt_handler *
+mgmt_find_handler(uint16_t group_id, uint16_t command_id)
+{
+    const struct mgmt_group *group;
+
+    group = mgmt_find_group(group_id);
+    if (group == NULL) {
+        return NULL;
+    }
+
+    if (command_id >= group->mg_handlers_count) {
+        return NULL;
+    }
+
+    return &group->mg_handlers[command_id];
+}
+
+int
+mgmt_write_rsp_status(struct mgmt_ctxt *cbuf, int errcode)
+{
+    int rc;
+
+    rc = cbor_encode_text_stringz(&cbuf->encoder, "rc");
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encode_int(&cbuf->encoder, errcode);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+mgmt_err_from_cbor(int cbor_status)
+{
+    switch (cbor_status) {
+        case CborNoError:           return MGMT_ERR_EOK;
+        case CborErrorOutOfMemory:  return MGMT_ERR_ENOMEM;
+        default:                    return MGMT_ERR_EUNKNOWN;
+    }
+}
+
+int
+mgmt_ctxt_init(struct mgmt_ctxt *cbuf, struct mgmt_streamer *streamer)
+{
+    int rc;
+
+    rc = cbor_parser_cust_reader_init(streamer->reader, 0, &cbuf->parser,
+                                      &cbuf->it);
+    if (rc != CborNoError) {
+        return mgmt_err_from_cbor(rc);
+    }
+
+    cbor_encoder_cust_writer_init(&cbuf->encoder, streamer->writer, 0);
+
+    return 0;
+}
+
+void
+mgmt_ntoh_hdr(struct mgmt_hdr *hdr)
+{
+    hdr->nh_len = ntohs(hdr->nh_len);
+    hdr->nh_group = ntohs(hdr->nh_group);
+}
+
+void
+mgmt_hton_hdr(struct mgmt_hdr *hdr)
+{
+    hdr->nh_len = htons(hdr->nh_len);
+    hdr->nh_group = htons(hdr->nh_group);
+}
diff --git a/mgmt/syscfg.yml b/mgmt/syscfg.yml
new file mode 100644
index 0000000..30ccc02
--- /dev/null
+++ b/mgmt/syscfg.yml
@@ -0,0 +1,18 @@
+#
+# 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.
+#

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 39/42: smp_svr/CMakeLists.txt: remove FROM_WHO variable

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 6e7722722ed385c113f669e3435e91efbd581fdc
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Feb 12 13:17:48 2018 -0800

    smp_svr/CMakeLists.txt: remove FROM_WHO variable
    
    This variable is unnecessary.  It was a leftover from the original
    CMakeLists.txt file used as a template.
---
 samples/smp_svr/zephyr/CMakeLists.txt | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/samples/smp_svr/zephyr/CMakeLists.txt b/samples/smp_svr/zephyr/CMakeLists.txt
index 7765cb4..612b436 100644
--- a/samples/smp_svr/zephyr/CMakeLists.txt
+++ b/samples/smp_svr/zephyr/CMakeLists.txt
@@ -19,11 +19,6 @@ project(NONE)
 
 assert_exists(DTC_OVERLAY_FILE)
 
-# This string ends up getting printed in the device console
-if (NOT DEFINED FROM_WHO)
-  set(FROM_WHO Zephyr)
-endif()
-
 target_sources(app PRIVATE
     src/main.c
 )

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 06/42: OS-agnostic command handlers: fs, img, os.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 4355617a16c1a4c6974d6b4527c7a6d80ef0e9cd
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:12:52 2018 -0800

    OS-agnostic command handlers: fs, img, os.
---
 cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h         |  41 +++
 cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h    |  77 +++++
 cmd/fs_mgmt/src/fs_mgmt.c                     | 250 ++++++++++++++++
 cmd/fs_mgmt/src/fs_mgmt_config.h              |  26 ++
 cmd/fs_mgmt/src/stubs.c                       |  46 +++
 cmd/img_mgmt/include/img_mgmt/image.h         |  82 ++++++
 cmd/img_mgmt/include/img_mgmt/img_mgmt.h      |  49 ++++
 cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h | 107 +++++++
 cmd/img_mgmt/src/img_mgmt.c                   | 400 ++++++++++++++++++++++++++
 cmd/img_mgmt/src/img_mgmt_config.h            |  22 ++
 cmd/img_mgmt/src/img_mgmt_priv.h              |  96 +++++++
 cmd/img_mgmt/src/img_mgmt_state.c             | 315 ++++++++++++++++++++
 cmd/img_mgmt/src/img_mgmt_util.c              |  39 +++
 cmd/img_mgmt/src/stubs.c                      |  64 +++++
 cmd/os_mgmt/include/os_mgmt/os_mgmt.h         |  64 +++++
 cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h    |  62 ++++
 cmd/os_mgmt/src/os_mgmt.c                     | 190 ++++++++++++
 cmd/os_mgmt/src/os_mgmt_config.h              |  22 ++
 cmd/os_mgmt/src/stubs.c                       |  38 +++
 19 files changed, 1990 insertions(+)

diff --git a/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h
new file mode 100644
index 0000000..38173fd
--- /dev/null
+++ b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h
@@ -0,0 +1,41 @@
+/*
+ * 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 H_FS_MGMT_
+#define H_FS_MGMT_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Command IDs for file system management group.
+ */
+#define FS_MGMT_ID_FILE     0
+
+/**
+ * @brief Registers the file system management command handler group.
+ */ 
+void fs_mgmt_register_group(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h
new file mode 100644
index 0000000..3cb30b8
--- /dev/null
+++ b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * @brief Declares implementation-specific functions required by file system
+ *        management.  The default stubs can be overridden with functions that
+ *        are compatible with the host OS.
+ */
+
+#ifndef H_FS_MGMT_IMPL_
+#define H_FS_MGMT_IMPL_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Retrieves the length of the file at the specified path.
+ *
+ * @param path                  The path of the file to query.
+ * @param out_len               On success, the file length gets written here.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int fs_mgmt_impl_filelen(const char *path, size_t *out_len);
+
+/**
+ * @brief Reads the specified chunk of file data.
+ *
+ * @param path                  The path of the file to read from.
+ * @param offset                The byte offset to read from.
+ * @param len                   The number of bytes to read.
+ * @param out_data              On success, the file data gets written here.
+ * @param out_len               On success, the number of bytes actually read
+ *                                  gets written here.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int fs_mgmt_impl_read(const char *path, size_t offset, size_t len,
+                      void *out_data, size_t *out_len);
+
+/**
+ * @brief Writes the specified chunk of file data.  A write to offset 0 must
+ * truncate the file; other offsets must append.
+ *
+ * @param path                  The path of the file to write to.
+ * @param offset                The byte offset to write to.
+ * @param data                  The data to write to the file.
+ * @param len                   The number of bytes to write.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int fs_mgmt_impl_write(const char *path, size_t offset, const void *data,
+                       size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/fs_mgmt/src/fs_mgmt.c b/cmd/fs_mgmt/src/fs_mgmt.c
new file mode 100644
index 0000000..2ce7fc2
--- /dev/null
+++ b/cmd/fs_mgmt/src/fs_mgmt.c
@@ -0,0 +1,250 @@
+/*
+ * 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 <limits.h>
+#include <string.h>
+#include "cborattr/cborattr.h"
+#include "mgmt/mgmt.h"
+#include "fs_mgmt/fs_mgmt.h"
+#include "fs_mgmt/fs_mgmt_impl.h"
+#include "fs_mgmt_config.h"
+
+static mgmt_handler_fn fs_mgmt_file_download;
+static mgmt_handler_fn fs_mgmt_file_upload;
+
+static struct {
+    /** Whether an upload is currently in progress. */
+    bool uploading;
+
+    /** Expected offset of next upload request. */
+    size_t off;
+
+    /** Total length of file currently being uploaded. */
+    size_t len;
+} fs_mgmt_ctxt;
+
+static const struct mgmt_handler fs_mgmt_handlers[] = {
+    [FS_MGMT_ID_FILE] = {
+        .mh_read = fs_mgmt_file_download,
+        .mh_write = fs_mgmt_file_upload,
+    },
+};
+
+#define FS_MGMT_HANDLER_CNT \
+    sizeof fs_mgmt_handlers / sizeof fs_mgmt_handlers[0]
+
+static struct mgmt_group fs_mgmt_group = {
+    .mg_handlers = fs_mgmt_handlers,
+    .mg_handlers_count = FS_MGMT_HANDLER_CNT,
+    .mg_group_id = MGMT_GROUP_ID_FS,
+};
+
+/**
+ * Command handler: fs file (read)
+ */
+static int
+fs_mgmt_file_download(struct mgmt_ctxt *ctxt)
+{
+    uint8_t file_data[FS_MGMT_DL_CHUNK_SIZE];
+    char path[FS_MGMT_PATH_SIZE + 1];
+    unsigned long long off;
+    CborError err;
+    size_t bytes_read;
+    size_t file_len;
+    int rc;
+
+    const struct cbor_attr_t dload_attr[] = {
+        {
+            .attribute = "off",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &off,
+        },
+        {
+            .attribute = "name",
+            .type = CborAttrTextStringType,
+            .addr.string = path,
+            .len = sizeof path,
+        },
+        { 0 },
+    };
+
+    off = ULLONG_MAX;
+    rc = cbor_read_object(&ctxt->it, dload_attr);
+    if (rc != 0 || off == ULLONG_MAX) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    /* Only the response to the first download request contains the total file
+     * length.
+     */
+    if (off == 0) {
+        rc = fs_mgmt_impl_filelen(path, &file_len);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    /* Read the requested chunk from the file. */
+    rc = fs_mgmt_impl_read(path, off, FS_MGMT_DL_CHUNK_SIZE,
+                           file_data, &bytes_read);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Encode the response. */
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "off");
+    err |= cbor_encode_uint(&ctxt->encoder, off);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "data");
+    err |= cbor_encode_byte_string(&ctxt->encoder, file_data, bytes_read);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK);
+    if (off == 0) {
+        err |= cbor_encode_text_stringz(&ctxt->encoder, "len");
+        err |= cbor_encode_uint(&ctxt->encoder, file_len);
+    }
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Encodes a file upload response.
+ */
+static int
+fs_mgmt_file_upload_rsp(struct mgmt_ctxt *ctxt, int rc, unsigned long long off)
+{
+    CborError err;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, rc);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "off");
+    err |= cbor_encode_uint(&ctxt->encoder, off);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: fs file (write)
+ */
+static int
+fs_mgmt_file_upload(struct mgmt_ctxt *ctxt)
+{
+    uint8_t file_data[FS_MGMT_UL_CHUNK_SIZE];
+    char file_name[FS_MGMT_PATH_SIZE + 1];
+    unsigned long long len;
+    unsigned long long off;
+    size_t data_len;
+    size_t new_off;
+    int rc;
+
+    const struct cbor_attr_t uload_attr[5] = {
+        [0] = {
+            .attribute = "off",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &off,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "data",
+            .type = CborAttrByteStringType,
+            .addr.bytestring.data = file_data,
+            .addr.bytestring.len = &data_len,
+            .len = sizeof(file_data)
+        },
+        [2] = {
+            .attribute = "len",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &len,
+            .nodefault = true
+        },
+        [3] = {
+            .attribute = "name",
+            .type = CborAttrTextStringType,
+            .addr.string = file_name,
+            .len = sizeof(file_name)
+        },
+        [4] = { 0 },
+    };
+
+    len = ULLONG_MAX;
+    off = ULLONG_MAX;
+    rc = cbor_read_object(&ctxt->it, uload_attr);
+    if (rc != 0 || off == ULLONG_MAX || file_name[0] == '\0') {
+        return MGMT_ERR_EINVAL;
+    }
+
+    if (off == 0) {
+        /* Total file length is a required field in the first chunk request. */
+        if (len == ULLONG_MAX) {
+            return MGMT_ERR_EINVAL;
+        }
+
+        fs_mgmt_ctxt.uploading = true;
+        fs_mgmt_ctxt.off = 0;
+        fs_mgmt_ctxt.len = len;
+    } else {
+        if (!fs_mgmt_ctxt.uploading) {
+            return MGMT_ERR_EINVAL;
+        }
+        
+        if (off != fs_mgmt_ctxt.off) {
+            /* Invalid offset.  Drop the data and send the expected offset. */
+            return fs_mgmt_file_upload_rsp(ctxt, MGMT_ERR_EINVAL,
+                                           fs_mgmt_ctxt.off);
+        }
+    }
+
+    new_off = fs_mgmt_ctxt.off + data_len;
+    if (new_off > fs_mgmt_ctxt.len) {
+        /* Data exceeds image length. */
+        return MGMT_ERR_EINVAL;
+    }
+
+    if (data_len > 0) {
+        /* Write the data chunk to the file. */
+        rc = fs_mgmt_impl_write(file_name, off, file_data, data_len);
+        if (rc != 0) {
+            return rc;
+        }
+        fs_mgmt_ctxt.off = new_off;
+    }
+
+    if (fs_mgmt_ctxt.off == fs_mgmt_ctxt.len) {
+        /* Upload complete. */
+        fs_mgmt_ctxt.uploading = false;
+    }
+
+    /* Send the response. */
+    return fs_mgmt_file_upload_rsp(ctxt, 0, fs_mgmt_ctxt.off);
+}
+
+void
+fs_mgmt_register_group(void)
+{
+    mgmt_register_group(&fs_mgmt_group);
+}
diff --git a/cmd/fs_mgmt/src/fs_mgmt_config.h b/cmd/fs_mgmt/src/fs_mgmt_config.h
new file mode 100644
index 0000000..81fb7dd
--- /dev/null
+++ b/cmd/fs_mgmt/src/fs_mgmt_config.h
@@ -0,0 +1,26 @@
+#ifndef H_FS_MGMT_CONFIG_
+#define H_FS_MGMT_CONFIG_
+
+#if defined MYNEWT
+
+#include "syscfg/syscfg.h"
+
+#define FS_MGMT_DL_CHUNK_SIZE   MYNEWT_VAL(FS_MGMT_DL_CHUNK_SIZE)
+#define FS_MGMT_PATH_SIZE       MYNEWT_VAL(FS_MGMT_PATH_SIZE)
+#define FS_MGMT_UL_CHUNK_SIZE   MYNEWT_VAL(FS_MGMT_UL_CHUNK_SIZE)
+
+#elif defined __ZEPHYR__
+
+#define FS_MGMT_DL_CHUNK_SIZE   CONFIG_FS_MGMT_DL_CHUNK_SIZE
+#define FS_MGMT_PATH_SIZE       CONFIG_FS_MGMT_PATH_SIZE
+#define FS_MGMT_UL_CHUNK_SIZE   CONFIG_FS_MGMT_UL_CHUNK_SIZE
+
+#else
+
+/* No direct support for this OS.  The application needs to define the above
+ * settings itself.
+ */
+
+#endif
+
+#endif
diff --git a/cmd/fs_mgmt/src/stubs.c b/cmd/fs_mgmt/src/stubs.c
new file mode 100644
index 0000000..8b6ab83
--- /dev/null
+++ b/cmd/fs_mgmt/src/stubs.c
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/**
+ * These stubs get linked in when there is no equivalent OS-specific
+ * implementation.
+ */
+
+#include "mgmt/mgmt.h"
+#include "fs_mgmt/fs_mgmt_impl.h"
+
+int  __attribute__((weak))
+fs_mgmt_impl_filelen(const char *path, size_t *out_len)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+fs_mgmt_impl_read(const char *path, size_t offset, size_t len,
+                  void *out_data, size_t *out_len)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+fs_mgmt_impl_write(const char *path, size_t offset, const void *data,
+                   size_t len)
+{
+    return MGMT_ERR_ENOTSUP;
+}
diff --git a/cmd/img_mgmt/include/img_mgmt/image.h b/cmd/img_mgmt/include/img_mgmt/image.h
new file mode 100644
index 0000000..d390783
--- /dev/null
+++ b/cmd/img_mgmt/include/img_mgmt/image.h
@@ -0,0 +1,82 @@
+/*
+ * 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 H_IMAGE_
+#define H_IMAGE_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IMAGE_MAGIC                 0x96f3b83d
+#define IMAGE_TLV_INFO_MAGIC        0x6907
+
+#define IMAGE_HEADER_SIZE           32
+
+/** Image header flags. */
+#define IMAGE_F_NON_BOOTABLE        0x00000010 /* Split image app. */
+
+/** Image trailer TLV types. */
+#define IMAGE_TLV_SHA256            0x10   /* SHA256 of image hdr and body */
+
+/** Image TLV-specific definitions. */
+#define IMAGE_HASH_LEN              32
+
+struct image_version {
+    uint8_t iv_major;
+    uint8_t iv_minor;
+    uint16_t iv_revision;
+    uint32_t iv_build_num;
+};
+
+/** Image header.  All fields are in little endian byte order. */
+struct image_header {
+    uint32_t ih_magic;
+    uint32_t ih_load_addr;
+    uint16_t ih_hdr_size; /* Size of image header (bytes). */
+    uint16_t _pad2;
+    uint32_t ih_img_size; /* Does not include header. */
+    uint32_t ih_flags;    /* IMAGE_F_[...]. */
+    struct image_version ih_ver;
+    uint32_t _pad3;
+};
+
+/** Image TLV header.  All fields in little endian. */
+struct image_tlv_info {
+    uint16_t it_magic;
+    uint16_t it_tlv_tot;  /* size of TLV area (including tlv_info header) */
+};
+
+/** Image trailer TLV format. All fields in little endian. */
+struct image_tlv {
+    uint8_t  it_type;   /* IMAGE_TLV_[...]. */
+    uint8_t  _pad;
+    uint16_t it_len;    /* Data length (not including TLV header). */
+};
+
+_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE,
+               "struct image_header not required size");
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/img_mgmt/include/img_mgmt/img_mgmt.h b/cmd/img_mgmt/include/img_mgmt/img_mgmt.h
new file mode 100644
index 0000000..865964d
--- /dev/null
+++ b/cmd/img_mgmt/include/img_mgmt/img_mgmt.h
@@ -0,0 +1,49 @@
+/*
+ * 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 H_IMG_MGMT_
+#define H_IMG_MGMT_
+
+#include <inttypes.h>
+struct image_version;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Command IDs for image management group.
+ */
+#define IMG_MGMT_ID_STATE           0
+#define IMG_MGMT_ID_UPLOAD          1
+#define IMG_MGMT_ID_FILE            2
+#define IMG_MGMT_ID_CORELIST        3
+#define IMG_MGMT_ID_CORELOAD        4
+#define IMG_MGMT_ID_ERASE           5
+
+/**
+ * @brief Registers the image management command handler group.
+ */ 
+void img_mgmt_register_group(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_IMG_MGMT_ */
diff --git a/cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h b/cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h
new file mode 100644
index 0000000..d0898ef
--- /dev/null
+++ b/cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * @brief Declares implementation-specific functions required by image
+ *        management.  The default stubs can be overridden with functions that
+ *        are compatible with the host OS.
+ */
+
+#ifndef H_IMG_MGMT_IMPL_
+#define H_IMG_MGMT_IMPL_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Ensures the spare slot (slot 1) is fully erased.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int img_mgmt_impl_erase_slot(void);
+
+/**
+ * @brief Marks the image in the specified slot as pending. On the next reboot,
+ * the system will perform a boot of the specified image.
+ *
+ * @param slot                  The slot to mark as pending.  In the typical
+ *                                  use case, this is 1.
+ * @param permanent             Whether the image should be used permanently or
+ *                                  only tested once:
+ *                                      0=run image once, then confirm or
+ *                                        revert.
+ *                                      1=run image forever.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int img_mgmt_impl_write_pending(int slot, bool permanent);
+
+/**
+ * @brief Marks the image in slot 0 as confirmed. The system will continue
+ * booting into the image in slot 0 until told to boot from a different slot.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int img_mgmt_impl_write_confirmed(void);
+
+/**
+ * @brief Reads the specified chunk of data from an image slot.
+ *
+ * @param slot                  The index of the slot to read from.
+ * @param offset                The offset within the slot to read from.
+ * @param dst                   On success, the read data gets written here.
+ * @param num_bytes             The number of byets to read.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int img_mgmt_impl_read(int slot, unsigned int offset, void *dst,
+                       unsigned int num_bytes);
+
+/**
+ * @brief Writes the specified chunk of image data to slot 1.
+ *
+ * @param offset                The offset within slot 1 to write to.
+ * @param data                  The image data to write.
+ * @param num_bytes             The number of bytes to read.
+ * @param last                  Whether this chunk is the end of the image:
+ *                                  false=additional image chunks are
+ *                                        forthcoming.
+ *                                  true=last image chunk; flush unwritten data
+ *                                       to disk.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int img_mgmt_impl_write_image_data(unsigned int offset, const void *data,
+                                   unsigned int num_bytes, bool last);
+
+/**
+ * @brief Indicates the type of swap operation that will occur on the next
+ * reboot, if any.
+ *
+ * @return                      An IMG_MGMT_SWAP_TYPE_[...] code.
+ */
+int img_mgmt_impl_swap_type(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/img_mgmt/src/img_mgmt.c b/cmd/img_mgmt/src/img_mgmt.c
new file mode 100644
index 0000000..fe91397
--- /dev/null
+++ b/cmd/img_mgmt/src/img_mgmt.c
@@ -0,0 +1,400 @@
+/*
+ * 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 <limits.h>
+#include <assert.h>
+#include <string.h>
+
+#include "cborattr/cborattr.h"
+#include "mgmt/mgmt.h"
+
+#include "img_mgmt/image.h"
+#include "img_mgmt/img_mgmt.h"
+#include "img_mgmt/img_mgmt_impl.h"
+#include "img_mgmt_priv.h"
+#include "img_mgmt_config.h"
+
+static mgmt_handler_fn img_mgmt_upload;
+static mgmt_handler_fn img_mgmt_erase;
+
+static const struct mgmt_handler img_mgmt_handlers[] = {
+    [IMG_MGMT_ID_STATE] = {
+        .mh_read = img_mgmt_state_read,
+        .mh_write = img_mgmt_state_write,
+    },
+    [IMG_MGMT_ID_UPLOAD] = {
+        .mh_read = NULL,
+        .mh_write = img_mgmt_upload
+    },
+    [IMG_MGMT_ID_ERASE] = {
+        .mh_read = NULL,
+        .mh_write = img_mgmt_erase
+    },
+};
+
+#define IMG_MGMT_HANDLER_CNT \
+    sizeof(img_mgmt_handlers) / sizeof(img_mgmt_handlers[0])
+
+static struct mgmt_group img_mgmt_group = {
+    .mg_handlers = (struct mgmt_handler *)img_mgmt_handlers,
+    .mg_handlers_count = IMG_MGMT_HANDLER_CNT,
+    .mg_group_id = MGMT_GROUP_ID_IMAGE,
+};
+
+static struct {
+    /* Whether an upload is currently in progress. */
+    bool uploading;
+
+    /** Expected offset of next upload request. */
+    size_t off;
+
+    /** Total length of image currently being uploaded. */
+    size_t len;
+} img_mgmt_ctxt;
+
+/**
+ * Finds the TLVs in the specified image slot, if any.
+ */
+static int
+img_mgmt_find_tlvs(const struct image_header *hdr,
+                   int slot, size_t *start_off, size_t *end_off)
+{
+    struct image_tlv_info tlv_info;
+    int rc;
+
+    rc = img_mgmt_impl_read(slot, *start_off, &tlv_info, sizeof tlv_info);
+    if (rc != 0) {
+        /* Read error. */
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (tlv_info.it_magic != IMAGE_TLV_INFO_MAGIC) {
+        /* No TLVs. */
+        return MGMT_ERR_ENOENT;
+    }
+
+    *start_off += sizeof tlv_info;
+    *end_off = *start_off + tlv_info.it_tlv_tot;
+
+    return 0;
+}
+
+/*
+ * Reads the version and build hash from the specified image slot.
+ */
+int
+img_mgmt_read_info(int image_slot, struct image_version *ver, uint8_t *hash,
+                   uint32_t *flags)
+{
+    struct image_header hdr;
+    struct image_tlv tlv;
+    size_t data_off;
+    size_t data_end;
+    bool hash_found;
+    int rc;
+
+    rc = img_mgmt_impl_read(image_slot, 0, &hdr, sizeof hdr);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (ver != NULL) {
+        memset(ver, 0xff, sizeof(*ver));
+    }
+    if (hdr.ih_magic == IMAGE_MAGIC) {
+        if (ver != NULL) {
+            memcpy(ver, &hdr.ih_ver, sizeof(*ver));
+        }
+    } else if (hdr.ih_magic == 0xffffffff) {
+        return MGMT_ERR_ENOENT;
+    } else {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (flags != NULL) {
+        *flags = hdr.ih_flags;
+    }
+
+    /* Read the image's TLVs.  All images are required to have a hash TLV.  If
+     * the hash is missing, the image is considered invalid.
+     */
+    data_off = hdr.ih_hdr_size + hdr.ih_img_size;
+    rc = img_mgmt_find_tlvs(&hdr, image_slot, &data_off, &data_end);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    hash_found = false;
+    while (data_off + sizeof tlv <= data_end) {
+        rc = img_mgmt_impl_read(image_slot, data_off, &tlv, sizeof tlv);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+        if (tlv.it_type == 0xff && tlv.it_len == 0xffff) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+        if (tlv.it_type != IMAGE_TLV_SHA256 || tlv.it_len != IMAGE_HASH_LEN) {
+            /* Non-hash TLV.  Skip it. */
+            data_off += sizeof tlv + tlv.it_len;
+            continue;
+        }
+
+        if (hash_found) {
+            /* More than one hash. */
+            return MGMT_ERR_EUNKNOWN;
+        }
+        hash_found = true;
+
+        data_off += sizeof tlv;
+        if (hash != NULL) {
+            if (data_off + IMAGE_HASH_LEN > data_end) {
+                return MGMT_ERR_EUNKNOWN;
+            }
+            rc = img_mgmt_impl_read(image_slot, data_off, hash,
+                                    IMAGE_HASH_LEN);
+            if (rc != 0) {
+                return MGMT_ERR_EUNKNOWN;
+            }
+        }
+    }
+
+    if (!hash_found) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+/*
+ * Finds image given version number. Returns the slot number image is in,
+ * or -1 if not found.
+ */
+int
+img_mgmt_find_by_ver(struct image_version *find, uint8_t *hash)
+{
+    int i;
+    struct image_version ver;
+
+    for (i = 0; i < 2; i++) {
+        if (img_mgmt_read_info(i, &ver, hash, NULL) != 0) {
+            continue;
+        }
+        if (!memcmp(find, &ver, sizeof(ver))) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+/*
+ * Finds image given hash of the image. Returns the slot number image is in,
+ * or -1 if not found.
+ */
+int
+img_mgmt_find_by_hash(uint8_t *find, struct image_version *ver)
+{
+    int i;
+    uint8_t hash[IMAGE_HASH_LEN];
+
+    for (i = 0; i < 2; i++) {
+        if (img_mgmt_read_info(i, ver, hash, NULL) != 0) {
+            continue;
+        }
+        if (!memcmp(hash, find, IMAGE_HASH_LEN)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+/**
+ * Command handler: image erase
+ */
+static int
+img_mgmt_erase(struct mgmt_ctxt *ctxt)
+{
+    CborError err;
+    int rc;
+
+    rc = img_mgmt_impl_erase_slot();
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, rc);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Encodes an image upload response.
+ */
+static int
+img_mgmt_encode_upload_rsp(struct mgmt_ctxt *ctxt, int status)
+{
+    CborError err;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, status);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "off");
+    err |= cbor_encode_int(&ctxt->encoder, img_mgmt_ctxt.off);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+    return 0;
+}
+
+/**
+ * Processes an upload request specifying an offset of 0 (i.e., the first image
+ * chunk).  The caller is responsible for encoding the response.
+ */
+static int
+img_mgmt_upload_first_chunk(struct mgmt_ctxt *ctxt, const uint8_t *req_data,
+                            size_t len)
+{
+    struct image_header hdr;
+    int rc;
+
+    if (len < sizeof hdr) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    memcpy(&hdr, req_data, sizeof hdr);
+    if (hdr.ih_magic != IMAGE_MAGIC) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    if (img_mgmt_slot_in_use(1)) {
+        /* No free slot. */
+        return MGMT_ERR_ENOMEM;
+    }
+
+    rc = img_mgmt_impl_erase_slot();
+    if (rc != 0) {
+        return rc;
+    }
+
+    img_mgmt_ctxt.uploading = true;
+    img_mgmt_ctxt.off = 0;
+    img_mgmt_ctxt.len = 0;
+
+    return 0;
+}
+
+/**
+ * Command handler: image upload
+ */
+static int
+img_mgmt_upload(struct mgmt_ctxt *ctxt)
+{
+    uint8_t img_mgmt_data[IMG_MGMT_UL_CHUNK_SIZE];
+    unsigned long long len;
+    unsigned long long off;
+    size_t data_len;
+    size_t new_off;
+    bool last;
+    int rc;
+
+    const struct cbor_attr_t off_attr[4] = {
+        [0] = {
+            .attribute = "data",
+            .type = CborAttrByteStringType,
+            .addr.bytestring.data = img_mgmt_data,
+            .addr.bytestring.len = &data_len,
+            .len = sizeof(img_mgmt_data)
+        },
+        [1] = {
+            .attribute = "len",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &len,
+            .nodefault = true
+        },
+        [2] = {
+            .attribute = "off",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &off,
+            .nodefault = true
+        },
+        [3] = { 0 },
+    };
+
+    len = ULLONG_MAX;
+    off = ULLONG_MAX;
+    data_len = 0;
+    rc = cbor_read_object(&ctxt->it, off_attr);
+    if (rc || off == ULLONG_MAX) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    if (off == 0) {
+        /* Total image length is a required field in the first request. */
+        if (len == ULLONG_MAX) {
+            return MGMT_ERR_EINVAL;
+        }
+
+        rc = img_mgmt_upload_first_chunk(ctxt, img_mgmt_data, data_len);
+        if (rc != 0) {
+            return rc;
+        }
+        img_mgmt_ctxt.len = len;
+    } else {
+        if (!img_mgmt_ctxt.uploading) {
+            return MGMT_ERR_EINVAL;
+        }
+
+        if (off != img_mgmt_ctxt.off) {
+            /* Invalid offset.  Drop the data and send the expected offset. */
+            return img_mgmt_encode_upload_rsp(ctxt, 0);
+        }
+    }
+
+    new_off = img_mgmt_ctxt.off + data_len;
+    if (new_off > img_mgmt_ctxt.len) {
+        /* Data exceeds image length. */
+        return MGMT_ERR_EINVAL;
+    }
+    last = new_off == img_mgmt_ctxt.len;
+
+    if (data_len > 0) {
+        rc = img_mgmt_impl_write_image_data(off, img_mgmt_data, data_len,
+                                            last);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    img_mgmt_ctxt.off = new_off;
+    if (last) {
+        /* Upload complete. */
+        img_mgmt_ctxt.uploading = false;
+    }
+
+    return img_mgmt_encode_upload_rsp(ctxt, 0);
+}
+
+void
+img_mgmt_register_group(void)
+{
+    mgmt_register_group(&img_mgmt_group);
+}
diff --git a/cmd/img_mgmt/src/img_mgmt_config.h b/cmd/img_mgmt/src/img_mgmt_config.h
new file mode 100644
index 0000000..4ec8295
--- /dev/null
+++ b/cmd/img_mgmt/src/img_mgmt_config.h
@@ -0,0 +1,22 @@
+#ifndef H_IMG_MGMT_CONFIG_
+#define H_IMG_MGMT_CONFIG_
+
+#if defined MYNEWT
+
+#include "syscfg/syscfg.h"
+
+#define IMG_MGMT_UL_CHUNK_SIZE  MYNEWT_VAL(IMG_MGMT_UL_CHUNK_SIZE)
+
+#elif defined __ZEPHYR__
+
+#define IMG_MGMT_UL_CHUNK_SIZE  CONFIG_IMG_MGMT_UL_CHUNK_SIZE
+
+#else
+
+/* No direct support for this OS.  The application needs to define the above
+ * settings itself.
+ */
+
+#endif
+
+#endif
diff --git a/cmd/img_mgmt/src/img_mgmt_priv.h b/cmd/img_mgmt/src/img_mgmt_priv.h
new file mode 100644
index 0000000..a8a3a28
--- /dev/null
+++ b/cmd/img_mgmt/src/img_mgmt_priv.h
@@ -0,0 +1,96 @@
+/*
+ * 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 H_IMG_PRIV_
+#define H_IMG_PRIV_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IMG_MGMT_SWAP_TYPE_NONE     0
+#define IMG_MGMT_SWAP_TYPE_TEST     1
+#define IMG_MGMT_SWAP_TYPE_PERM     2
+#define IMG_MGMT_SWAP_TYPE_REVERT   3
+
+/*
+ * Response to list:
+ * {
+ *      "images":[ <version1>, <version2>]
+ * }
+ *
+ *
+ * Request to boot to version:
+ * {
+ *      "test":<version>
+ * }
+ *
+ *
+ * Response to boot read:
+ * {
+ *	"test":<version>,
+ *	"main":<version>,
+ *      "active":<version>
+ * }
+ *
+ *
+ * Request to image upload:
+ * {
+ *      "off":<offset>,
+ *      "len":<img_size>		inspected when off = 0
+ *      "data":<base64encoded binary>
+ * }
+ *
+ *
+ * Response to upload:
+ * {
+ *      "off":<offset>
+ * }
+ *
+ *
+ * Request to image upload:
+ * {
+ *      "off":<offset>
+ *	    "name":<filename>		inspected when off = 0
+ *      "len":<file_size>		inspected when off = 0
+ *      "data":<base64encoded binary>
+ * }
+ */
+
+struct mgmt_ctxt;
+
+int img_mgmt_core_erase(struct mgmt_ctxt *);
+int img_mgmt_core_list(struct mgmt_ctxt *);
+int img_mgmt_core_load(struct mgmt_ctxt *);
+int img_mgmt_find_by_hash(uint8_t *find, struct image_version *ver);
+int img_mgmt_find_by_ver(struct image_version *find, uint8_t *hash);
+int img_mgmt_read_info(int image_slot, struct image_version *ver,
+                       uint8_t *hash, uint32_t *flags);
+int img_mgmt_slot_in_use(int slot);
+int img_mgmt_state_read(struct mgmt_ctxt *ctxt);
+int img_mgmt_state_write(struct mgmt_ctxt *njb);
+int img_mgmt_ver_str(const struct image_version *ver, char *dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __IMG_PRIV_H */
diff --git a/cmd/img_mgmt/src/img_mgmt_state.c b/cmd/img_mgmt/src/img_mgmt_state.c
new file mode 100644
index 0000000..bca3aed
--- /dev/null
+++ b/cmd/img_mgmt/src/img_mgmt_state.c
@@ -0,0 +1,315 @@
+/*
+ * 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 "cbor.h"
+#include "cborattr/cborattr.h"
+#include "mgmt/mgmt.h"
+#include "img_mgmt/img_mgmt.h"
+#include "img_mgmt/image.h"
+#include "img_mgmt_priv.h"
+#include "img_mgmt/img_mgmt_impl.h"
+
+#define IMG_MGMT_STATE_F_PENDING    0x01
+#define IMG_MGMT_STATE_F_CONFIRMED  0x02
+#define IMG_MGMT_STATE_F_ACTIVE     0x04
+#define IMG_MGMT_STATE_F_PERMANENT  0x08
+
+#define IMG_MGMT_VER_MAX_STR_LEN    25  /* 255.255.65535.4294967295\0 */
+
+/**
+ * Collects information about the specified image slot.
+ */
+static uint8_t
+img_mgmt_state_flags(int query_slot)
+{
+    uint8_t flags;
+    int swap_type;
+
+    assert(query_slot == 0 || query_slot == 1);
+
+    flags = 0;
+
+    /* Determine if this is is pending or confirmed (only applicable for
+     * unified images and loaders.
+     */
+    swap_type = img_mgmt_impl_swap_type();
+    switch (swap_type) {
+    case IMG_MGMT_SWAP_TYPE_NONE:
+        if (query_slot == 0) {
+            flags |= IMG_MGMT_STATE_F_CONFIRMED;
+            flags |= IMG_MGMT_STATE_F_ACTIVE;
+        }
+        break;
+
+    case IMG_MGMT_SWAP_TYPE_TEST:
+        if (query_slot == 0) {
+            flags |= IMG_MGMT_STATE_F_CONFIRMED;
+        } else if (query_slot == 1) {
+            flags |= IMG_MGMT_STATE_F_PENDING;
+        }
+        break;
+
+    case IMG_MGMT_SWAP_TYPE_PERM:
+        if (query_slot == 0) {
+            flags |= IMG_MGMT_STATE_F_CONFIRMED;
+        } else if (query_slot == 1) {
+            flags |= IMG_MGMT_STATE_F_PENDING | IMG_MGMT_STATE_F_PERMANENT;
+        }
+        break;
+
+    case IMG_MGMT_SWAP_TYPE_REVERT:
+        if (query_slot == 0) {
+            flags |= IMG_MGMT_STATE_F_ACTIVE;
+        } else if (query_slot == 1) {
+            flags |= IMG_MGMT_STATE_F_CONFIRMED;
+        }
+        break;
+    }
+
+    /* Slot 0 is always active. */
+    /* XXX: The slot 0 assumption only holds when running from flash. */
+    if (query_slot == 0) {
+        flags |= IMG_MGMT_STATE_F_ACTIVE;
+    }
+
+    return flags;
+}
+
+/**
+ * Indicates whether any image slot is pending (i.e., whether a test swap will
+ * happen on the next reboot.
+ */
+static int
+img_mgmt_state_any_pending(void)
+{
+    return img_mgmt_state_flags(0) & IMG_MGMT_STATE_F_PENDING ||
+           img_mgmt_state_flags(1) & IMG_MGMT_STATE_F_PENDING;
+}
+
+/**
+ * Indicates whether the specified slot has any flags.  If no flags are set,
+ * the slot can be freely erased.
+ */
+int
+img_mgmt_slot_in_use(int slot)
+{
+    uint8_t state_flags;
+
+    state_flags = img_mgmt_state_flags(slot);
+    return state_flags & IMG_MGMT_STATE_F_ACTIVE       ||
+           state_flags & IMG_MGMT_STATE_F_CONFIRMED    ||
+           state_flags & IMG_MGMT_STATE_F_PENDING;
+}
+
+/**
+ * Sets the pending flag for the specified image slot.  That is, the system
+ * will swap to the specified image on the next reboot.  If the permanent
+ * argument is specified, the system doesn't require a confirm after the swap
+ * occurs.
+ */
+int
+img_mgmt_state_set_pending(int slot, int permanent)
+{
+    uint8_t state_flags;
+    int rc;
+
+    state_flags = img_mgmt_state_flags(slot);
+
+    /* Unconfirmed slots are always runable.  A confirmed slot can only be
+     * run if it is a loader in a split image setup.
+     */
+    if (state_flags & IMG_MGMT_STATE_F_CONFIRMED && slot != 0) {
+        return MGMT_ERR_EBADSTATE;
+    }
+
+    rc = img_mgmt_impl_write_pending(slot, permanent);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+/**
+ * Confirms the current image state.  Prevents a fallback from occurring on the
+ * next reboot if the active image is currently being tested.
+ */
+int
+img_mgmt_state_confirm(void)
+{
+    int rc;
+
+    /* Confirm disallowed if a test is pending. */
+    if (img_mgmt_state_any_pending()) {
+        return MGMT_ERR_EBADSTATE;
+    }
+
+    rc = img_mgmt_impl_write_confirmed();
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: image state read
+ */
+int
+img_mgmt_state_read(struct mgmt_ctxt *ctxt)
+{
+    char vers_str[IMG_MGMT_VER_MAX_STR_LEN];
+    uint8_t hash[IMAGE_HASH_LEN]; /* SHA256 hash */
+    struct image_version ver;
+    CborEncoder images;
+    CborEncoder image;
+    CborError err;
+    uint32_t flags;
+    uint8_t state_flags;
+    int rc;
+    int i;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "images");
+
+    err |= cbor_encoder_create_array(&ctxt->encoder, &images,
+                                       CborIndefiniteLength);
+    for (i = 0; i < 2; i++) {
+        rc = img_mgmt_read_info(i, &ver, hash, &flags);
+        if (rc != 0) {
+            continue;
+        }
+
+        state_flags = img_mgmt_state_flags(i);
+
+        err |= cbor_encoder_create_map(&images, &image,
+                                         CborIndefiniteLength);
+        err |= cbor_encode_text_stringz(&image, "slot");
+        err |= cbor_encode_int(&image, i);
+
+        err |= cbor_encode_text_stringz(&image, "version");
+        img_mgmt_ver_str(&ver, vers_str);
+        err |= cbor_encode_text_stringz(&image, vers_str);
+
+        err |= cbor_encode_text_stringz(&image, "hash");
+        err |= cbor_encode_byte_string(&image, hash, IMAGE_HASH_LEN);
+
+        err |= cbor_encode_text_stringz(&image, "bootable");
+        err |= cbor_encode_boolean(&image, !(flags & IMAGE_F_NON_BOOTABLE));
+
+        err |= cbor_encode_text_stringz(&image, "pending");
+        err |= cbor_encode_boolean(&image,
+                                     state_flags & IMG_MGMT_STATE_F_PENDING);
+
+        err |= cbor_encode_text_stringz(&image, "confirmed");
+        err |= cbor_encode_boolean(&image,
+                                     state_flags & IMG_MGMT_STATE_F_CONFIRMED);
+
+        err |= cbor_encode_text_stringz(&image, "active");
+        err |= cbor_encode_boolean(&image,
+                                     state_flags & IMG_MGMT_STATE_F_ACTIVE);
+
+        err |= cbor_encode_text_stringz(&image, "permanent");
+        err |= cbor_encode_boolean(&image,
+                                     state_flags & IMG_MGMT_STATE_F_PERMANENT);
+
+        err |= cbor_encoder_close_container(&images, &image);
+    }
+
+    err |= cbor_encoder_close_container(&ctxt->encoder, &images);
+
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "splitStatus");
+    err |= cbor_encode_int(&ctxt->encoder, 0);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: image state write
+ */
+int
+img_mgmt_state_write(struct mgmt_ctxt *ctxt)
+{
+    uint8_t hash[IMAGE_HASH_LEN];
+    size_t hash_len;
+    bool confirm;
+    int slot;
+    int rc;
+
+    const struct cbor_attr_t write_attr[] = {
+        [0] = {
+            .attribute = "hash",
+            .type = CborAttrByteStringType,
+            .addr.bytestring.data = hash,
+            .addr.bytestring.len = &hash_len,
+            .len = sizeof(hash),
+        },
+        [1] = {
+            .attribute = "confirm",
+            .type = CborAttrBooleanType,
+            .addr.boolean = &confirm,
+            .dflt.boolean = false,
+        },
+        [2] = { 0 },
+    };
+
+    hash_len = 0;
+    rc = cbor_read_object(&ctxt->it, write_attr);
+    if (rc != 0) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    /* Determine which slot is being operated on. */
+    if (hash_len == 0) {
+        if (confirm) {
+            slot = 0;
+        } else {
+            /* A 'test' without a hash is invalid. */
+            return MGMT_ERR_EINVAL;
+        }
+    } else {
+        slot = img_mgmt_find_by_hash(hash, NULL);
+        if (slot < 0) {
+            return MGMT_ERR_EINVAL;
+        }
+    }
+
+    if (slot == 0 && confirm) {
+        /* Confirm current setup. */
+        rc = img_mgmt_state_confirm();
+    } else {
+        rc = img_mgmt_state_set_pending(slot, confirm);
+    }
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Send the current image state in the response. */
+    rc = img_mgmt_state_read(ctxt);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
diff --git a/cmd/img_mgmt/src/img_mgmt_util.c b/cmd/img_mgmt/src/img_mgmt_util.c
new file mode 100644
index 0000000..5889f61
--- /dev/null
+++ b/cmd/img_mgmt/src/img_mgmt_util.c
@@ -0,0 +1,39 @@
+/*
+ * 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 <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "img_mgmt/image.h"
+#include "img_mgmt/img_mgmt.h"
+
+int
+img_mgmt_ver_str(const struct image_version *ver, char *dst)
+{
+    if (ver->iv_build_num != 0) {
+        return sprintf(dst, "%u.%u.%u.%lu",
+          ver->iv_major, ver->iv_minor, ver->iv_revision,
+          (unsigned long)ver->iv_build_num);
+    } else {
+        return sprintf(dst, "%u.%u.%u",
+          ver->iv_major, ver->iv_minor, ver->iv_revision);
+    }
+}
diff --git a/cmd/img_mgmt/src/stubs.c b/cmd/img_mgmt/src/stubs.c
new file mode 100644
index 0000000..fa440dc
--- /dev/null
+++ b/cmd/img_mgmt/src/stubs.c
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/**
+ * These stubs get linked in when there is no equivalent OS-specific
+ * implementation.
+ */
+
+#include "mgmt/mgmt.h"
+#include "img_mgmt/img_mgmt_impl.h"
+
+int __attribute__((weak))
+img_mgmt_impl_erase_slot(void)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+img_mgmt_impl_write_pending(int slot, bool permanent)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+img_mgmt_impl_write_confirmed(void)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+img_mgmt_impl_read(int slot, unsigned int offset, void *dst,
+                   unsigned int num_bytes)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+img_mgmt_impl_write_image_data(unsigned int offset, const void *data,
+                               unsigned int num_bytes, bool last)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+img_mgmt_impl_swap_type(void)
+{
+    return MGMT_ERR_ENOTSUP;
+}
diff --git a/cmd/os_mgmt/include/os_mgmt/os_mgmt.h b/cmd/os_mgmt/include/os_mgmt/os_mgmt.h
new file mode 100644
index 0000000..493d227
--- /dev/null
+++ b/cmd/os_mgmt/include/os_mgmt/os_mgmt.h
@@ -0,0 +1,64 @@
+/*
+ * 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 H_OS_MGMT_
+#define H_OS_MGMT_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mgmt_ctxt;
+
+/**
+ * Command IDs for OS management group.
+ */
+#define OS_MGMT_ID_ECHO             0
+#define OS_MGMT_ID_CONS_ECHO_CTRL   1
+#define OS_MGMT_ID_TASKSTAT         2
+#define OS_MGMT_ID_MPSTAT           3
+#define OS_MGMT_ID_DATETIME_STR     4
+#define OS_MGMT_ID_RESET            5
+
+#define OS_MGMT_TASK_NAME_LEN       32
+
+struct os_mgmt_task_info {
+    uint8_t oti_prio;
+    uint8_t oti_taskid;
+    uint8_t oti_state;
+    uint16_t oti_stkusage;
+    uint16_t oti_stksize;
+    uint32_t oti_cswcnt;
+    uint32_t oti_runtime;
+    uint32_t oti_last_checkin;
+    uint32_t oti_next_checkin;
+
+    char oti_name[OS_MGMT_TASK_NAME_LEN];
+};
+
+/**
+ * @brief Registers the OS management command handler group.
+ */ 
+void os_mgmt_register_group(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_OS_MGMT_ */
diff --git a/cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h b/cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h
new file mode 100644
index 0000000..252ba75
--- /dev/null
+++ b/cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * @brief Declares implementation-specific functions required by OS management.
+ *        The default stubs can be overridden with functions that are
+ *        compatible with the host OS.
+ */
+
+#ifndef H_OS_MGMT_IMPL_
+#define H_OS_MGMT_IMPL_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_mgmt_task_info;
+
+/**
+ * @brief Retrieves information about the specified task.  
+ *
+ * @param idx                   The index of the task to query.
+ * @param out_info              On success, the requested information gets
+ *                                  written here.
+ *
+ * @return                      0 on success;
+ *                              MGMT_ERR_ENOENT if no such task exists;
+ *                              Other MGMT_ERR_[...] code on failure.
+ */
+int os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info);
+
+/**
+ * @brief Schedules a near-immediate system reset.  There must be a slight
+ * delay before the reset occurs to allow time for the mgmt response to be
+ * delivered.
+ *
+ * @return                      0 on success, MGMT_ERR_[...] code on failure.
+ */
+int os_mgmt_impl_reset(unsigned int delay_ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/os_mgmt/src/os_mgmt.c b/cmd/os_mgmt/src/os_mgmt.c
new file mode 100644
index 0000000..ed359d8
--- /dev/null
+++ b/cmd/os_mgmt/src/os_mgmt.c
@@ -0,0 +1,190 @@
+/*
+ * 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 <string.h>
+#include "cbor.h"
+#include "cborattr/cborattr.h"
+#include "mgmt/mgmt.h"
+#include "os_mgmt/os_mgmt.h"
+#include "os_mgmt/os_mgmt_impl.h"
+#include "os_mgmt_config.h"
+
+static mgmt_handler_fn os_mgmt_echo;
+static mgmt_handler_fn os_mgmt_reset;
+static mgmt_handler_fn os_mgmt_taskstat_read;
+
+static const struct mgmt_handler os_mgmt_group_handlers[] = {
+    [OS_MGMT_ID_ECHO] = {
+        os_mgmt_echo, os_mgmt_echo
+    },
+    [OS_MGMT_ID_TASKSTAT] = {
+        os_mgmt_taskstat_read, NULL
+    },
+    [OS_MGMT_ID_RESET] = {
+        NULL, os_mgmt_reset
+    },
+};
+
+#define OS_MGMT_GROUP_SZ    \
+    (sizeof os_mgmt_group_handlers / sizeof os_mgmt_group_handlers[0])
+
+static struct mgmt_group os_mgmt_group = {
+    .mg_handlers = os_mgmt_group_handlers,
+    .mg_handlers_count = OS_MGMT_GROUP_SZ,
+    .mg_group_id = MGMT_GROUP_ID_OS,
+};
+
+/**
+ * Command handler: os echo
+ */
+static int
+os_mgmt_echo(struct mgmt_ctxt *ctxt)
+{
+    char echo_buf[128];
+    CborError err;
+
+    const struct cbor_attr_t attrs[2] = {
+        [0] = {
+            .attribute = "d",
+            .type = CborAttrTextStringType,
+            .addr.string = echo_buf,
+            .nodefault = 1,
+            .len = sizeof echo_buf,
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    echo_buf[0] = '\0';
+
+    err = cbor_read_object(&ctxt->it, attrs);
+    if (err != 0) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "r");
+    err |= cbor_encode_text_string(&ctxt->encoder, echo_buf, strlen(echo_buf));
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Encodes a single taskstat entry.
+ */
+static int
+os_mgmt_taskstat_encode_one(struct CborEncoder *encoder,
+                            const struct os_mgmt_task_info *task_info)
+{
+    CborEncoder task_map;
+    CborError err;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(encoder, task_info->oti_name);
+    err |= cbor_encoder_create_map(encoder, &task_map, CborIndefiniteLength);
+    err |= cbor_encode_text_stringz(&task_map, "prio");
+    err |= cbor_encode_uint(&task_map, task_info->oti_prio);
+    err |= cbor_encode_text_stringz(&task_map, "tid");
+    err |= cbor_encode_uint(&task_map, task_info->oti_taskid);
+    err |= cbor_encode_text_stringz(&task_map, "state");
+    err |= cbor_encode_uint(&task_map, task_info->oti_state);
+    err |= cbor_encode_text_stringz(&task_map, "stkuse");
+    err |= cbor_encode_uint(&task_map, task_info->oti_stkusage);
+    err |= cbor_encode_text_stringz(&task_map, "stksiz");
+    err |= cbor_encode_uint(&task_map, task_info->oti_stksize);
+    err |= cbor_encode_text_stringz(&task_map, "cswcnt");
+    err |= cbor_encode_uint(&task_map, task_info->oti_cswcnt);
+    err |= cbor_encode_text_stringz(&task_map, "runtime");
+    err |= cbor_encode_uint(&task_map, task_info->oti_runtime);
+    err |= cbor_encode_text_stringz(&task_map, "last_checkin");
+    err |= cbor_encode_uint(&task_map, task_info->oti_last_checkin);
+    err |= cbor_encode_text_stringz(&task_map, "next_checkin");
+    err |= cbor_encode_uint(&task_map, task_info->oti_next_checkin);
+    err |= cbor_encoder_close_container(encoder, &task_map);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: os taskstat
+ */
+static int
+os_mgmt_taskstat_read(struct mgmt_ctxt *ctxt)
+{
+    struct os_mgmt_task_info task_info;
+    struct CborEncoder tasks_map;
+    CborError err;
+    int task_idx;
+    int rc;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "tasks");
+    err |= cbor_encoder_create_map(&ctxt->encoder, &tasks_map,
+                                   CborIndefiniteLength);
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    /* Iterate the list of tasks, encoding each. */
+    for (task_idx = 0; ; task_idx++) {
+        rc = os_mgmt_impl_task_info(task_idx, &task_info);
+        if (rc == MGMT_ERR_ENOENT) {
+            /* No more tasks to encode. */
+            break;
+        } else if (rc != 0) {
+            return rc;
+        }
+
+        rc = os_mgmt_taskstat_encode_one(&tasks_map, &task_info);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    err = cbor_encoder_close_container(&ctxt->encoder, &tasks_map);
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: os reset
+ */
+static int
+os_mgmt_reset(struct mgmt_ctxt *ctxt)
+{
+    return os_mgmt_impl_reset(OS_MGMT_RESET_MS);
+}
+
+void
+os_mgmt_register_group(void)
+{
+    mgmt_register_group(&os_mgmt_group);
+}
diff --git a/cmd/os_mgmt/src/os_mgmt_config.h b/cmd/os_mgmt/src/os_mgmt_config.h
new file mode 100644
index 0000000..d388dec
--- /dev/null
+++ b/cmd/os_mgmt/src/os_mgmt_config.h
@@ -0,0 +1,22 @@
+#ifndef H_OS_MGMT_CONFIG_
+#define H_OS_MGMT_CONFIG_
+
+#if defined MYNEWT
+
+#include "syscfg/syscfg.h"
+
+#define OS_MGMT_RESET_MS    MYNEWT_VAL(OS_MGMT_RESET_MS)
+
+#elif defined __ZEPHYR__
+
+#define OS_MGMT_RESET_MS    CONFIG_OS_MGMT_RESET_MS
+
+#else
+
+/* No direct support for this OS.  The application needs to define the above
+ * settings itself.
+ */
+
+#endif
+
+#endif
diff --git a/cmd/os_mgmt/src/stubs.c b/cmd/os_mgmt/src/stubs.c
new file mode 100644
index 0000000..c17532b
--- /dev/null
+++ b/cmd/os_mgmt/src/stubs.c
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+/**
+ * These stubs get linked in when there is no equivalent OS-specific
+ * implementation.
+ */
+
+#include "mgmt/mgmt.h"
+#include "os_mgmt/os_mgmt_impl.h"
+
+int __attribute__((weak))
+os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+os_mgmt_impl_reset(unsigned int delay_ms)
+{
+    return MGMT_ERR_ENOTSUP;
+}

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 37/42: fs_mgmt - Surround macro definition with ().

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 9b45fbc5d2cb59e3de14dc88077b6e4713892103
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Feb 12 13:16:56 2018 -0800

    fs_mgmt - Surround macro definition with ().
---
 cmd/fs_mgmt/src/fs_mgmt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cmd/fs_mgmt/src/fs_mgmt.c b/cmd/fs_mgmt/src/fs_mgmt.c
index 2ce7fc2..2d43ac1 100644
--- a/cmd/fs_mgmt/src/fs_mgmt.c
+++ b/cmd/fs_mgmt/src/fs_mgmt.c
@@ -47,7 +47,7 @@ static const struct mgmt_handler fs_mgmt_handlers[] = {
 };
 
 #define FS_MGMT_HANDLER_CNT \
-    sizeof fs_mgmt_handlers / sizeof fs_mgmt_handlers[0]
+    (sizeof fs_mgmt_handlers / sizeof fs_mgmt_handlers[0])
 
 static struct mgmt_group fs_mgmt_group = {
     .mg_handlers = fs_mgmt_handlers,

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 23/42: smp_svr - Allow both CONFIG_FCB and CONFIG_FS_NFFS

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit af277cfcd04711f50c38114fb07ce2b5fac13889
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Jan 30 12:05:44 2018 -0800

    smp_svr - Allow both CONFIG_FCB and CONFIG_FS_NFFS
    
    Prior to this commit, the smp_svr sample app raised a build-time error
    if both FCB and NFFS were enabled.  The thinking was that a user only
    has enough flash space for one or the other.  However, this does not
    justify an error for two reasons:
    
    1. The user's platform may have sufficient flash for both storage types.
    
    2. Even if only one storage type is enabled, it is still OK to enable
    both.  One storage type will silently fail to initialize, but the other
    will work.  Enabling both makes it easier to switch configurations in
    the sample app.
---
 samples/smp_svr/zephyr/CMakeLists.txt | 4 +---
 samples/smp_svr/zephyr/prj.conf       | 4 ++--
 samples/smp_svr/zephyr/src/main.c     | 5 -----
 3 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/samples/smp_svr/zephyr/CMakeLists.txt b/samples/smp_svr/zephyr/CMakeLists.txt
index ec1fced..b61b8ea 100644
--- a/samples/smp_svr/zephyr/CMakeLists.txt
+++ b/samples/smp_svr/zephyr/CMakeLists.txt
@@ -41,7 +41,5 @@ target_sources(app PRIVATE
 
 zephyr_link_libraries(
     MCUMGR
-
-    ### Uncomment this line to use the NFFS file system.
-    # NFFS
+    NFFS
 )
diff --git a/samples/smp_svr/zephyr/prj.conf b/samples/smp_svr/zephyr/prj.conf
index 60ccd65..88ad795 100644
--- a/samples/smp_svr/zephyr/prj.conf
+++ b/samples/smp_svr/zephyr/prj.conf
@@ -17,8 +17,8 @@ CONFIG_MCUMGR_SMP_BT=y
 CONFIG_MCUMGR_SMP_SHELL=y
 
 # Enable the NFFS file system.
-#CONFIG_FILE_SYSTEM=y
-#CONFIG_FILE_SYSTEM_NFFS=y
+CONFIG_FILE_SYSTEM=y
+CONFIG_FILE_SYSTEM_NFFS=y
 
 # Enable the flash circular buffer (FCB) for the reboot log.
 CONFIG_FLASH_PAGE_LAYOUT=y
diff --git a/samples/smp_svr/zephyr/src/main.c b/samples/smp_svr/zephyr/src/main.c
index fad6fbc..7f5e9e6 100644
--- a/samples/smp_svr/zephyr/src/main.c
+++ b/samples/smp_svr/zephyr/src/main.c
@@ -17,11 +17,6 @@
 #include "mgmt/smp_bt.h"
 #include "mgmt/buf.h"
 
-#if defined CONFIG_FCB && defined CONFIG_FILE_SYSTEM_NFFS
-#error Both CONFIG_FCB and CONFIG_FILE_SYSTEM_NFFS are defined; smp_svr \
-       application only supports one at a time.
-#endif
-
 #ifdef CONFIG_MCUMGR_CMD_FS_MGMT
 #include "fs_mgmt/fs_mgmt.h"
 #endif

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 22/42: Minor code cleanup.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 4b601efa12a3fee73a4afe7326bbd64cb09de557
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Jan 30 11:47:12 2018 -0800

    Minor code cleanup.
---
 cmd/log_mgmt/Kconfig                  | 1 +
 cmd/log_mgmt/src/log_mgmt.c           | 4 ++--
 cmd/os_mgmt/include/os_mgmt/os_mgmt.h | 2 --
 3 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/cmd/log_mgmt/Kconfig b/cmd/log_mgmt/Kconfig
index e949aa6..8b43166 100644
--- a/cmd/log_mgmt/Kconfig
+++ b/cmd/log_mgmt/Kconfig
@@ -18,6 +18,7 @@
 menuconfig MCUMGR_CMD_LOG_MGMT
     bool
     prompt "Enable mcumgr handlers for log management"
+    depends on MDLOG
     default n
     help
       Enables mcumgr handlers for log management
diff --git a/cmd/log_mgmt/src/log_mgmt.c b/cmd/log_mgmt/src/log_mgmt.c
index 430f35a..a3c0cac 100644
--- a/cmd/log_mgmt/src/log_mgmt.c
+++ b/cmd/log_mgmt/src/log_mgmt.c
@@ -92,7 +92,7 @@ log_mgmt_encode_entry(CborEncoder *enc, const struct log_mgmt_entry *entry,
 }
 
 static int
-log_mgmt_walk_cb_encode(const struct log_mgmt_entry *entry, void *arg)
+log_mgmt_cb_encode(const struct log_mgmt_entry *entry, void *arg)
 {
     struct CborCntWriter cnt_writer;
     struct log_walk_ctxt *ctxt;
@@ -151,7 +151,7 @@ log_encode_entries(const struct log_mgmt_log *log, CborEncoder *enc,
     };
 
     rc = log_mgmt_impl_foreach_entry(log->name, &filter,
-                                     log_mgmt_walk_cb_encode, &ctxt);
+                                     log_mgmt_cb_encode, &ctxt);
     if (rc != 0 && rc != MGMT_ERR_EMSGSIZE) {
         return rc;
     }
diff --git a/cmd/os_mgmt/include/os_mgmt/os_mgmt.h b/cmd/os_mgmt/include/os_mgmt/os_mgmt.h
index 493d227..0c85cbe 100644
--- a/cmd/os_mgmt/include/os_mgmt/os_mgmt.h
+++ b/cmd/os_mgmt/include/os_mgmt/os_mgmt.h
@@ -24,8 +24,6 @@
 extern "C" {
 #endif
 
-struct mgmt_ctxt;
-
 /**
  * Command IDs for OS management group.
  */

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 18/42: Add log_mgmt support to smp_svr sample app.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit d9131d612861611bd33d6b344b887c77c606fdfe
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 15:52:34 2018 -0800

    Add log_mgmt support to smp_svr sample app.
---
 samples/smp_svr/README.md             | 30 +++++++++++
 samples/smp_svr/zephyr/CMakeLists.txt |  7 ++-
 samples/smp_svr/zephyr/prj.conf       | 41 ++++++++++++---
 samples/smp_svr/zephyr/src/main.c     | 97 +++++++++++++++++++++++++++++++++--
 4 files changed, 162 insertions(+), 13 deletions(-)

diff --git a/samples/smp_svr/README.md b/samples/smp_svr/README.md
index cb9d3e7..6ff9dcd 100644
--- a/samples/smp_svr/README.md
+++ b/samples/smp_svr/README.md
@@ -8,6 +8,7 @@ transports:
 `smp_svr` enables support for the following command groups:
     * fs_mgmt
     * img_mgmt
+    * log_mgmt
     * os_mgmt
 
 ## Mynewt
@@ -52,6 +53,35 @@ setting in `prj.conf` accordingly.
 In addition, the MCUBoot boot loader (https://github.com/runtimeco/mcuboot) is
 required for img_mgmt to function properly.
 
+The smp_svr app logs reboots to a flash circular buffer (FCB) backed log.  The
+flash map for the nRF52 only allocates flash for either the NFFS file system or
+the FCB, but not both.  By default, this application uses the FCB log, not the
+file system.  You can enable the NFFS file system and disable the FCB as follows-
+
+1. In `zephyr/prj.conf`, uncomment the `FILE_SYSTEM` settings and comment out
+the `FLASH` and `FCB` settings:
+
+```
+    # Enable the NFFS file system.
+    CONFIG_FILE_SYSTEM=y
+    CONFIG_FILE_SYSTEM_NFFS=y
+
+     # Enable the flash circular buffer (FCB) for the reboot log.
+    #CONFIG_FLASH_PAGE_LAYOUT=y
+    #CONFIG_FLASH_MAP=y
+    #CONFIG_FCB=y
+```
+
+2. Link in the NFFS library by uncommenting the `NFFS` line in
+`zephyr/CMakeLists.txt`:
+
+```
+    zephyr_link_libraries(
+        MCUMGR
+        NFFS
+    )
+```
+
 ### Building
 
 The Zephyr port of `smp_svr` can be built using the usual procedure:
diff --git a/samples/smp_svr/zephyr/CMakeLists.txt b/samples/smp_svr/zephyr/CMakeLists.txt
index 30a4ebd..ec1fced 100644
--- a/samples/smp_svr/zephyr/CMakeLists.txt
+++ b/samples/smp_svr/zephyr/CMakeLists.txt
@@ -39,4 +39,9 @@ target_sources(app PRIVATE
     src/main.c
 )
 
-zephyr_link_libraries(MCUMGR NFFS)
+zephyr_link_libraries(
+    MCUMGR
+
+    ### Uncomment this line to use the NFFS file system.
+    # NFFS
+)
diff --git a/samples/smp_svr/zephyr/prj.conf b/samples/smp_svr/zephyr/prj.conf
index 50e8ff1..60ccd65 100644
--- a/samples/smp_svr/zephyr/prj.conf
+++ b/samples/smp_svr/zephyr/prj.conf
@@ -1,11 +1,3 @@
-# Required by file management command handlers.
-CONFIG_FILE_SYSTEM=y
-CONFIG_FILE_SYSTEM_NFFS=y
-CONFIG_FS_NFFS_FLASH_DEV_NAME="NRF5_FLASH"
-
-# Required by tinycbor (math.h).
-CONFIG_NEWLIB_LIBC=y
-
 # Some command handlers require a large stack.
 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
 
@@ -24,7 +16,40 @@ CONFIG_BT_RX_BUF_LEN=260
 CONFIG_MCUMGR_SMP_BT=y
 CONFIG_MCUMGR_SMP_SHELL=y
 
+# Enable the NFFS file system.
+#CONFIG_FILE_SYSTEM=y
+#CONFIG_FILE_SYSTEM_NFFS=y
+
+# Enable the flash circular buffer (FCB) for the reboot log.
+CONFIG_FLASH_PAGE_LAYOUT=y
+CONFIG_FLASH_MAP=y
+CONFIG_FCB=y
+
+# Enable the managed log (mdlog).
+CONFIG_MDLOG=y
+CONFIG_MDLOG_CONSOLE=y
+CONFIG_MDLOG_FCB=y
+
+# Required by the `taskstat` command.
+CONFIG_THREAD_MONITOR=y
+
+# Enable the reboot log.
+CONFIG_REBOOT_LOG=y
+
+# Enable assertions.  Required for crash logging.
+CONFIG_ASSERT=y
+
 # Enable all core commands.
 CONFIG_MCUMGR_CMD_FS_MGMT=y
 CONFIG_MCUMGR_CMD_IMG_MGMT=y
+CONFIG_MCUMGR_CMD_LOG_MGMT=y
 CONFIG_MCUMGR_CMD_OS_MGMT=y
+
+### nRF5 specific settings
+
+# Disable flash-radio sync.  This is necessary for writing to the reboot log
+# with an interrupt handler.
+CONFIG_SOC_FLASH_NRF5_RADIO_SYNC=n
+
+# Specify the location of the NFFS file system.
+CONFIG_FS_NFFS_FLASH_DEV_NAME="NRF5_FLASH"
diff --git a/samples/smp_svr/zephyr/src/main.c b/samples/smp_svr/zephyr/src/main.c
index 757725f..fad6fbc 100644
--- a/samples/smp_svr/zephyr/src/main.c
+++ b/samples/smp_svr/zephyr/src/main.c
@@ -11,15 +11,44 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/conn.h>
 #include <bluetooth/gatt.h>
+#include "logging/mdlog.h"
+#include "logging/reboot_log.h"
+#include "fcb.h"
+#include "mgmt/smp_bt.h"
+#include "mgmt/buf.h"
+
+#if defined CONFIG_FCB && defined CONFIG_FILE_SYSTEM_NFFS
+#error Both CONFIG_FCB and CONFIG_FILE_SYSTEM_NFFS are defined; smp_svr \
+       application only supports one at a time.
+#endif
+
+#ifdef CONFIG_MCUMGR_CMD_FS_MGMT
 #include "fs_mgmt/fs_mgmt.h"
+#endif
+#ifdef CONFIG_MCUMGR_CMD_OS_MGMT
 #include "os_mgmt/os_mgmt.h"
+#endif
+#ifdef CONFIG_MCUMGR_CMD_IMG_MGMT
 #include "img_mgmt/img_mgmt.h"
-#include "mgmt/smp_bt.h"
-#include "mgmt/buf.h"
- 
+#endif
+#ifdef CONFIG_MCUMGR_CMD_LOG_MGMT
+#include "log_mgmt/log_mgmt.h"
+#endif
+
 #define DEVICE_NAME         CONFIG_BT_DEVICE_NAME
 #define DEVICE_NAME_LEN     (sizeof(DEVICE_NAME) - 1)
 
+struct fcb smp_svr_fcb;
+struct mdlog smp_svr_log;
+
+/* smp_svr uses the first "peruser" log module. */
+#define SMP_SVR_MDLOG_MODULE  (MDLOG_MODULE_PERUSER + 0)
+
+/* Convenience macro for logging to the smp_svr module. */
+#define SMP_SVR_MDLOG(lvl, ...) \
+    MDLOG_ ## lvl(&smp_svr_log, SMP_SVR_MDLOG_MODULE, __VA_ARGS__)
+
+
 static const struct bt_data ad[] = {
     BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
     BT_DATA_BYTES(BT_DATA_UUID128_ALL,
@@ -79,14 +108,71 @@ static void bt_ready(int err)
     advertise();
 }
 
+static int init_fcb(void)
+{
+    /* If the user has enabled FCB support, assume there is an FCB in the NFFS
+     * area.
+     */
+#ifndef CONFIG_FCB
+    return 0;
+#endif
+
+    static struct flash_sector sectors[128];
+
+    uint32_t sector_cnt;
+    int rc;
+
+    sector_cnt = sizeof sectors / sizeof sectors[0];
+    rc = flash_area_get_sectors(4, &sector_cnt, sectors);
+    if (rc != 0) {
+        return rc;
+    }
+
+    if (sector_cnt <= 1) {
+        return -EINVAL;
+    }
+
+    /* Initialize the FCB in the NFFS flash area (area 4) with one scratch
+     * sector.
+     */
+    smp_svr_fcb = (struct fcb) {
+        .f_magic = 0x12345678,
+        .f_version = MDLOG_VERSION,
+        .f_sector_cnt = sector_cnt - 1,
+        .f_scratch_cnt = 1,
+        .f_area_id = 4,
+        .f_sectors = sectors,
+    };
+
+    rc = fcb_init(&smp_svr_fcb);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
 void main(void)
 {
     int rc;
 
+    rc = init_fcb();
+    assert(rc == 0);
+    reboot_log_configure(&smp_svr_log);
+
     /* Register the built-in mcumgr command handlers. */
+#ifdef CONFIG_MCUMGR_CMD_FS_MGMT
+    fs_mgmt_register_group();
+#endif
+#ifdef CONFIG_MCUMGR_CMD_OS_MGMT
     os_mgmt_register_group();
+#endif
+#ifdef CONFIG_MCUMGR_CMD_IMG_MGMT
     img_mgmt_register_group();
-    fs_mgmt_register_group();
+#endif
+#ifdef CONFIG_MCUMGR_CMD_LOG_MGMT
+    log_mgmt_register_group();
+#endif
 
     /* Enable Bluetooth. */
     rc = bt_enable(bt_ready);
@@ -99,6 +185,9 @@ void main(void)
     /* Initialize the Bluetooth mcumgr transport. */
     smp_bt_register();
 
+    mdlog_register("smp_svr", &smp_svr_log, &mdlog_fcb_handler, &smp_svr_fcb,
+                   MDLOG_LEVEL_DEBUG);
+
     /* The system work queue handles all incoming mcumgr requests.  Let the
      * main thread idle while the mcumgr server runs.
      */

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 38/42: smp_svr/CMakeLists.txt: remove set_conf_file macro

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 75c5f1a7c3842f75c130a41a837157cfad2854e0
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Feb 12 13:17:22 2018 -0800

    smp_svr/CMakeLists.txt: remove set_conf_file macro
    
    This macro is unnecessary.  It was a leftover from the original
    CMakeLists.txt file used as a template.
---
 samples/smp_svr/zephyr/CMakeLists.txt | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/samples/smp_svr/zephyr/CMakeLists.txt b/samples/smp_svr/zephyr/CMakeLists.txt
index b61b8ea..7765cb4 100644
--- a/samples/smp_svr/zephyr/CMakeLists.txt
+++ b/samples/smp_svr/zephyr/CMakeLists.txt
@@ -7,17 +7,6 @@
 # This provides a basic application structure suitable for communication using
 # mcumgr.  It can be used as a starting point for new applications.
 
-# The default top-level application configuration is prj.conf.  You can place
-# additional board-specific files in boards/${BOARD}.conf, and they will be
-# merged into the configuration along with prj.conf.
-macro(set_conf_file)
-  if(EXISTS ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf)
-    set(CONF_FILE "prj.conf ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf")
-  else()
-    set(CONF_FILE "prj.conf")
-  endif()
-endmacro()
-
 # Zephyr uses Device Tree (DT) to describe some board hardware configuration.
 #
 # See the Zephyr documentation for more information on DT:

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 17/42: log_mgmt command handler group.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit afdb0474da89b2cb8b59ddff6be404ba3484745b
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 15:52:28 2018 -0800

    log_mgmt command handler group.
---
 cmd/CMakeLists.txt                             |   1 +
 cmd/Kconfig                                    |   1 +
 cmd/log_mgmt/CMakeLists.txt                    |   9 +
 cmd/log_mgmt/Kconfig                           |  53 +++
 cmd/log_mgmt/include/log_mgmt/log_mgmt.h       |  83 +++++
 cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h  |  48 +++
 cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c | 206 +++++++++++
 cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c | 189 ++++++++++
 cmd/log_mgmt/src/log_mgmt.c                    | 494 +++++++++++++++++++++++++
 cmd/log_mgmt/src/log_mgmt_config.h             |  45 +++
 cmd/log_mgmt/src/stubs.c                       |  65 ++++
 cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c   |   2 +
 12 files changed, 1196 insertions(+)

diff --git a/cmd/CMakeLists.txt b/cmd/CMakeLists.txt
index bc91e2f..be26ded 100644
--- a/cmd/CMakeLists.txt
+++ b/cmd/CMakeLists.txt
@@ -1,3 +1,4 @@
 add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_FS_MGMT   fs_mgmt)
 add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_IMG_MGMT  img_mgmt)
+add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_LOG_MGMT  log_mgmt)
 add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_OS_MGMT   os_mgmt)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index a0e2031..ea51804 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -19,6 +19,7 @@ menu "Command handlers"
 
 source "ext/mcumgr/cmd/fs_mgmt/Kconfig"
 source "ext/mcumgr/cmd/img_mgmt/Kconfig"
+source "ext/mcumgr/cmd/log_mgmt/Kconfig"
 source "ext/mcumgr/cmd/os_mgmt/Kconfig"
 
 endmenu
diff --git a/cmd/log_mgmt/CMakeLists.txt b/cmd/log_mgmt/CMakeLists.txt
new file mode 100644
index 0000000..7d72dcd
--- /dev/null
+++ b/cmd/log_mgmt/CMakeLists.txt
@@ -0,0 +1,9 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c
+    cmd/log_mgmt/src/log_mgmt.c
+    cmd/log_mgmt/src/stubs.c
+)
diff --git a/cmd/log_mgmt/Kconfig b/cmd/log_mgmt/Kconfig
new file mode 100644
index 0000000..e949aa6
--- /dev/null
+++ b/cmd/log_mgmt/Kconfig
@@ -0,0 +1,53 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE log
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this log
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this log 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.
+
+menuconfig MCUMGR_CMD_LOG_MGMT
+    bool
+    prompt "Enable mcumgr handlers for log management"
+    default n
+    help
+      Enables mcumgr handlers for log management
+
+if MCUMGR_CMD_LOG_MGMT
+config LOG_MGMT_CHUNK_SIZE
+    int
+    prompt "Maximum chunk size for log downloads"
+    default 512
+    help
+      Limits the maximum chunk size in log downloads.  A buffer of this size
+      gets allocated on the stack during handling of the log show command.
+
+config LOG_MGMT_NAME_LEN
+    int
+    prompt "Maximum log name length"
+    default 64
+    help
+      Limits the maximum length of log names.  If a log's name length exceeds
+      this number, it gets truncated in management responses.  A buffer of this
+      size gets allocated on the stack during handling of all log management
+      commands.
+
+config LOG_MGMT_BODY_LEN
+    int
+    prompt "Maximum log body length"
+    default 128
+    help
+      Limits the maximum length of log entry bodies.  If a log entry's body
+      length exceeds this number, it gets truncated in management responses.  A
+      buffer of this size gets allocated on the stack during handling of the
+      log show command.
+endif
diff --git a/cmd/log_mgmt/include/log_mgmt/log_mgmt.h b/cmd/log_mgmt/include/log_mgmt/log_mgmt.h
new file mode 100644
index 0000000..01df2e5
--- /dev/null
+++ b/cmd/log_mgmt/include/log_mgmt/log_mgmt.h
@@ -0,0 +1,83 @@
+/*
+ * 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 H_LOG_MGMT_
+#define H_LOG_MGMT_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Command IDs for log management group.
+ */
+#define LOG_MGMT_ID_SHOW        0
+#define LOG_MGMT_ID_CLEAR       1
+#define LOG_MGMT_ID_APPEND      2
+#define LOG_MGMT_ID_MODULE_LIST 3
+#define LOG_MGMT_ID_LEVEL_LIST  4
+#define LOG_MGMT_ID_LOGS_LIST   5
+
+/** @brief Log output is streamed without retention (e.g., console). */
+#define LOG_MGMT_TYPE_STREAM     0
+
+/** @brief Log entries are stored in RAM. */
+#define LOG_MGMT_TYPE_MEMORY     1
+
+/** @brief Log entries are persisted across reboots. */
+#define LOG_MGMT_TYPE_STORAGE    2
+
+/** @brief Generic descriptor for an OS-specific log. */
+struct log_mgmt_log {
+    const char *name;
+    int type;
+};
+
+/** @brief Generic descriptor for an OS-specific log entry. */
+struct log_mgmt_entry {
+    int64_t ts;
+    uint32_t index;
+    const void *data;
+    size_t len;
+    uint8_t module;
+    uint8_t level;
+};
+
+/** @brief Indicates which log entries to operate on. */
+struct log_mgmt_filter {
+    /* If   min_timestamp == -1: Only access last log entry;
+     * Elif min_timestamp == 0:  Don't filter by timestamp;
+     * Else:                     Only access entries whose ts >= min_timestamp.
+     */
+    int64_t min_timestamp;
+
+    /* Only access entries whose index >= min_index. */
+    uint32_t min_index;
+};
+
+/**
+ * @brief Registers the log management command handler group.
+ */ 
+void log_mgmt_register_group(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h b/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h
new file mode 100644
index 0000000..1890643
--- /dev/null
+++ b/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h
@@ -0,0 +1,48 @@
+/*
+ * 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 H_LOG_MGMT_IMPL_
+#define H_LOG_MGMT_IMPL_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct log_mgmt_filter;
+struct log_mgmt_entry;
+struct log_mgmt_log;
+
+typedef int log_mgmt_foreach_entry_fn(const struct log_mgmt_entry *entry,
+                                      void *arg);
+
+int log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log);
+int log_mgmt_impl_get_module(int idx, const char **out_module_name);
+int log_mgmt_impl_get_level(int idx, const char **out_level_name);
+int log_mgmt_impl_get_next_idx(uint32_t *out_idx);
+int log_mgmt_impl_foreach_entry(const char *log_name,
+                                const struct log_mgmt_filter *filter,
+                                log_mgmt_foreach_entry_fn *cb,
+                                void *arg);
+int log_mgmt_impl_clear(const char *log_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c b/cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c
new file mode 100644
index 0000000..f81e591
--- /dev/null
+++ b/cmd/log_mgmt/port/mynewt/src/mynewt_log_mgmt.c
@@ -0,0 +1,206 @@
+/*
+ * 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 "log/log.h"
+#include "mgmt/mgmt.h"
+#include "log_mgmt/log_mgmt.h"
+#include "log_mgmt/log_mgmt_impl.h"
+#include "../../../src/log_mgmt_config.h"
+
+struct mynewt_log_mgmt_walk_arg {
+    log_mgmt_foreach_entry_fn *cb;
+    uint8_t body[LOG_MGMT_BODY_LEN];
+    void *arg;
+};
+
+static struct log *
+mynewt_log_mgmt_find_log(const char *log_name)
+{
+    struct log *log;
+
+    log = NULL;
+    while (1) {
+        log = log_list_get_next(log);
+        if (log == NULL) {
+            return NULL;
+        }
+
+        if (strcmp(log->l_name, log_name) == 0) {
+            return log;
+        }
+    }
+}
+
+int
+log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log)
+{
+    struct log *log;
+    int i;
+
+    log = NULL;
+    for (i = 0; i <= idx; i++) {
+        log = log_list_get_next(log);
+        if (log == NULL) {
+            return MGMT_ERR_ENOENT;
+        }
+    }
+
+    out_log->name = log->l_name;
+    out_log->type = log->l_handler->type;
+    return 0;
+}
+
+int
+log_mgmt_impl_get_module(int idx, const char **out_module_name)
+{
+    const char *name;
+
+    name = LOG_MODULE_STR(idx);
+    if (name == NULL) {
+        return MGMT_ERR_ENOENT;
+    } else {
+        *out_module_name = name;
+        return 0;
+    }
+}
+
+int
+log_mgmt_impl_get_level(int idx, const char **out_level_name)
+{
+    const char *name;
+
+    name = LOG_LEVEL_STR(idx);
+    if (name == NULL) {
+        return MGMT_ERR_ENOENT;
+    } else {
+        *out_level_name = name;
+        return 0;
+    }
+}
+
+int
+log_mgmt_impl_get_next_idx(uint32_t *out_idx)
+{
+    *out_idx = g_log_info.li_next_index;
+    return 0;
+}
+
+static int
+mynewt_log_mgmt_walk_cb(struct log *log, struct log_offset *log_offset,
+                        const void *desciptor, uint16_t len)
+{
+    struct mynewt_log_mgmt_walk_arg *mynewt_log_mgmt_walk_arg;
+    struct log_mgmt_entry entry;
+    struct log_entry_hdr ueh;
+    int read_len;
+    int rc;
+
+    mynewt_log_mgmt_walk_arg = log_offset->lo_arg;
+
+    rc = log_read(log, desciptor, &ueh, 0, sizeof ueh);
+    if (rc != sizeof ueh) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    /* If specified timestamp is nonzero, it is the primary criterion, and the
+     * specified index is the secondary criterion.  If specified timetsamp is
+     * zero, specified index is the only criterion.
+     *
+     * If specified timestamp == 0: encode entries whose index >=
+     *     specified index.
+     * Else: encode entries whose timestamp >= specified timestamp and whose
+     *      index >= specified index
+     */
+
+    if (log_offset->lo_ts == 0) {
+        if (log_offset->lo_index > ueh.ue_index) {
+            return 0;
+        }
+    } else if (ueh.ue_ts < log_offset->lo_ts   ||
+               (ueh.ue_ts == log_offset->lo_ts &&
+                ueh.ue_index < log_offset->lo_index)) {
+        return 0;
+    }
+
+    read_len = min(len - sizeof ueh, LOG_MGMT_BODY_LEN - sizeof ueh);
+    rc = log_read(log, desciptor, mynewt_log_mgmt_walk_arg->body, sizeof ueh,
+                  read_len);
+    if (rc < 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    entry.ts = ueh.ue_ts;
+    entry.index = ueh.ue_index;
+    entry.module = ueh.ue_module;
+    entry.level = ueh.ue_level;
+    entry.len = rc;
+    entry.data = mynewt_log_mgmt_walk_arg->body;
+
+    return mynewt_log_mgmt_walk_arg->cb(&entry, mynewt_log_mgmt_walk_arg->arg);
+}
+
+int
+log_mgmt_impl_foreach_entry(const char *log_name,
+                            const struct log_mgmt_filter *filter,
+                            log_mgmt_foreach_entry_fn *cb, void *arg)
+{
+    struct mynewt_log_mgmt_walk_arg walk_arg;
+    struct log_offset offset;
+    struct log *log;
+
+    walk_arg = (struct mynewt_log_mgmt_walk_arg) {
+        .cb = cb,
+        .arg = arg,
+    };
+
+    log = mynewt_log_mgmt_find_log(log_name);
+    if (log == NULL) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    if (strcmp(log->l_name, log_name) == 0) {
+        offset.lo_arg = &walk_arg;
+        offset.lo_ts = filter->min_timestamp;
+        offset.lo_index = filter->min_index;
+        offset.lo_data_len = 0;
+
+        return log_walk(log, mynewt_log_mgmt_walk_cb, &offset);
+    }
+
+    return MGMT_ERR_ENOENT;
+}
+
+int
+log_mgmt_impl_clear(const char *log_name)
+{
+    struct log *log;
+    int rc;
+
+    log = mynewt_log_mgmt_find_log(log_name);
+    if (log == NULL) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    rc = log_flush(log);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
diff --git a/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c b/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c
new file mode 100644
index 0000000..41cf51e
--- /dev/null
+++ b/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c
@@ -0,0 +1,189 @@
+/*
+ * 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 <misc/util.h>
+#include "logging/mdlog.h"
+#include "mgmt/mgmt.h"
+#include "log_mgmt/log_mgmt.h"
+#include "log_mgmt/log_mgmt_impl.h"
+#include "../../../src/log_mgmt_config.h"
+
+struct zephyr_log_mgmt_walk_arg {
+    log_mgmt_foreach_entry_fn *cb;
+    uint8_t body[LOG_MGMT_BODY_LEN];
+    void *arg;
+};
+
+int
+log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log)
+{
+    struct mdlog *mdlog;
+    int i;
+
+    mdlog = NULL;
+    for (i = 0; i <= idx; i++) {
+        mdlog = mdlog_get_next(mdlog);
+        if (mdlog == NULL) {
+            return MGMT_ERR_ENOENT;
+        }
+    }
+
+    out_log->name = mdlog->l_name;
+    out_log->type = mdlog->l_handler->type;
+    return 0;
+}
+
+int
+log_mgmt_impl_get_module(int idx, const char **out_module_name)
+{
+    const char *name;
+
+    name = mdlog_module_name(idx);
+    if (name == NULL) {
+        return MGMT_ERR_ENOENT;
+    } else {
+        *out_module_name = name;
+        return 0;
+    }
+}
+
+int
+log_mgmt_impl_get_level(int idx, const char **out_level_name)
+{
+    const char *name;
+
+    name = mdlog_level_name(idx);
+    if (name == NULL) {
+        return MGMT_ERR_ENOENT;
+    } else {
+        *out_level_name = name;
+        return 0;
+    }
+}
+
+int
+log_mgmt_impl_get_next_idx(uint32_t *out_idx)
+{
+    *out_idx = mdlog_get_next_index();
+    return 0;
+}
+
+static int
+zephyr_log_mgmt_walk_cb(struct mdlog *log, struct mdlog_offset *log_offset,
+                        const void *desciptor, uint16_t len)
+{
+    struct zephyr_log_mgmt_walk_arg *zephyr_log_mgmt_walk_arg;
+    struct log_mgmt_entry entry;
+    struct mdlog_entry_hdr ueh;
+    int read_len;
+    int rc;
+
+    zephyr_log_mgmt_walk_arg = log_offset->lo_arg;
+
+    rc = mdlog_read(log, desciptor, &ueh, 0, sizeof ueh);
+    if (rc != sizeof ueh) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    /* If specified timestamp is nonzero, it is the primary criterion, and the
+     * specified index is the secondary criterion.  If specified timetsamp is
+     * zero, specified index is the only criterion.
+     *
+     * If specified timestamp == 0: encode entries whose index >=
+     *     specified index.
+     * Else: encode entries whose timestamp >= specified timestamp and whose
+     *      index >= specified index
+     */
+
+    if (log_offset->lo_ts == 0) {
+        if (log_offset->lo_index > ueh.ue_index) {
+            return 0;
+        }
+    } else if (ueh.ue_ts < log_offset->lo_ts   ||
+               (ueh.ue_ts == log_offset->lo_ts &&
+                ueh.ue_index < log_offset->lo_index)) {
+        return 0;
+    }
+
+    read_len = min(len - sizeof ueh, LOG_MGMT_BODY_LEN - sizeof ueh);
+    rc = mdlog_read(log, desciptor, zephyr_log_mgmt_walk_arg->body, sizeof ueh,
+                    read_len);
+    if (rc < 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    entry.ts = ueh.ue_ts;
+    entry.index = ueh.ue_index;
+    entry.module = ueh.ue_module;
+    entry.level = ueh.ue_level;
+    entry.len = rc;
+    entry.data = zephyr_log_mgmt_walk_arg->body;
+
+    return zephyr_log_mgmt_walk_arg->cb(&entry, zephyr_log_mgmt_walk_arg->arg);
+}
+
+int
+log_mgmt_impl_foreach_entry(const char *log_name,
+                            const struct log_mgmt_filter *filter,
+                            log_mgmt_foreach_entry_fn *cb, void *arg)
+{
+    struct zephyr_log_mgmt_walk_arg walk_arg;
+    struct mdlog_offset offset;
+    struct mdlog *mdlog;
+
+    walk_arg = (struct zephyr_log_mgmt_walk_arg) {
+        .cb = cb,
+        .arg = arg,
+    };
+
+    mdlog = mdlog_find(log_name);
+    if (mdlog == NULL) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    if (strcmp(mdlog->l_name, log_name) == 0) {
+        offset.lo_arg = &walk_arg;
+        offset.lo_ts = filter->min_timestamp;
+        offset.lo_index = filter->min_index;
+        offset.lo_data_len = 0;
+
+        return mdlog_walk(mdlog, zephyr_log_mgmt_walk_cb, &offset);
+    }
+
+    return MGMT_ERR_ENOENT;
+}
+
+int
+log_mgmt_impl_clear(const char *log_name)
+{
+    struct mdlog *mdlog;
+    int rc;
+
+    mdlog = mdlog_find(log_name);
+    if (mdlog == NULL) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    rc = mdlog_flush(mdlog);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
diff --git a/cmd/log_mgmt/src/log_mgmt.c b/cmd/log_mgmt/src/log_mgmt.c
new file mode 100644
index 0000000..430f35a
--- /dev/null
+++ b/cmd/log_mgmt/src/log_mgmt.c
@@ -0,0 +1,494 @@
+/*
+ * 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 <string.h>
+#include <stdio.h>
+
+#include "mgmt/mgmt.h"
+#include "cborattr/cborattr.h"
+#include "cbor_cnt_writer.h"
+#include "log_mgmt/log_mgmt.h"
+#include "log_mgmt/log_mgmt_impl.h"
+#include "log_mgmt_config.h"
+
+/** Context used during walks. */
+struct log_walk_ctxt {
+    /* The number of bytes encoded to the response so far. */
+    size_t rsp_len;
+
+    /* The encoder to use to write the current log entry. */
+    struct CborEncoder *enc;
+};
+
+static mgmt_handler_fn log_mgmt_show;
+static mgmt_handler_fn log_mgmt_clear;
+static mgmt_handler_fn log_mgmt_module_list;
+static mgmt_handler_fn log_mgmt_level_list;
+static mgmt_handler_fn log_mgmt_logs_list;
+
+static struct mgmt_handler log_mgmt_handlers[] = {
+    [LOG_MGMT_ID_SHOW] =        { log_mgmt_show, NULL },
+    [LOG_MGMT_ID_CLEAR] =       { NULL, log_mgmt_clear },
+    [LOG_MGMT_ID_MODULE_LIST] = { log_mgmt_module_list, NULL },
+    [LOG_MGMT_ID_LEVEL_LIST] =  { log_mgmt_level_list, NULL },
+    [LOG_MGMT_ID_LOGS_LIST] =   { log_mgmt_logs_list, NULL },
+};
+
+#define LOG_MGMT_HANDLER_CNT \
+    sizeof log_mgmt_handlers / sizeof log_mgmt_handlers[0]
+
+static struct mgmt_group log_mgmt_group = {
+    .mg_handlers = log_mgmt_handlers,
+    .mg_handlers_count = LOG_MGMT_HANDLER_CNT,
+    .mg_group_id = MGMT_GROUP_ID_LOG,
+};
+
+static int
+log_mgmt_encode_entry(CborEncoder *enc, const struct log_mgmt_entry *entry,
+                      size_t *out_len)
+{
+    CborEncoder entry_enc;
+    CborError err;
+
+    err = 0;
+    err |= cbor_encoder_create_map(enc, &entry_enc, 5);
+    err |= cbor_encode_text_stringz(&entry_enc, "msg");
+    err |= cbor_encode_byte_string(&entry_enc, entry->data, entry->len);
+    err |= cbor_encode_text_stringz(&entry_enc, "ts");
+    err |= cbor_encode_int(&entry_enc, entry->ts);
+    err |= cbor_encode_text_stringz(&entry_enc, "level");
+    err |= cbor_encode_uint(&entry_enc, entry->level);
+    err |= cbor_encode_text_stringz(&entry_enc, "index");
+    err |= cbor_encode_uint(&entry_enc, entry->index);
+    err |= cbor_encode_text_stringz(&entry_enc, "module");
+    err |= cbor_encode_uint(&entry_enc, entry->module);
+    err |= cbor_encoder_close_container(enc, &entry_enc);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    if (out_len != NULL) {
+        *out_len = cbor_encode_bytes_written(enc);
+    }
+
+    return 0;
+}
+
+static int
+log_mgmt_walk_cb_encode(const struct log_mgmt_entry *entry, void *arg)
+{
+    struct CborCntWriter cnt_writer;
+    struct log_walk_ctxt *ctxt;
+    CborEncoder cnt_encoder;
+    size_t entry_len;
+    int rc;
+
+    ctxt = arg;
+
+    /*** First, determine if this entry would fit. */
+
+    cbor_cnt_writer_init(&cnt_writer);
+    cbor_encoder_cust_writer_init(&cnt_encoder, &cnt_writer.enc, 0);
+    rc = log_mgmt_encode_entry(&cnt_encoder, entry, &entry_len);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* `+ 1` to account for the CBOR array terminator. */
+    if (ctxt->rsp_len + entry_len + 1 > LOG_MGMT_CHUNK_SIZE) {
+        return MGMT_ERR_EMSGSIZE;
+    }
+    ctxt->rsp_len += entry_len;
+
+    /*** The entry fits.  Now encode it. */
+
+    rc = log_mgmt_encode_entry(ctxt->enc, entry, NULL);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static int
+log_encode_entries(const struct log_mgmt_log *log, CborEncoder *enc,
+                   int64_t timestamp, uint32_t index)
+{
+    struct log_mgmt_filter filter;
+    struct log_walk_ctxt ctxt;
+    CborEncoder entries;
+    CborError err;
+    int rc;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(enc, "entries");
+    err |= cbor_encoder_create_array(enc, &entries, CborIndefiniteLength);
+
+    filter = (struct log_mgmt_filter) {
+        .min_timestamp = timestamp,
+        .min_index = index,
+    };
+    ctxt = (struct log_walk_ctxt) {
+        .enc = &entries,
+        .rsp_len = cbor_encode_bytes_written(enc),
+    };
+
+    rc = log_mgmt_impl_foreach_entry(log->name, &filter,
+                                     log_mgmt_walk_cb_encode, &ctxt);
+    if (rc != 0 && rc != MGMT_ERR_EMSGSIZE) {
+        return rc;
+    }
+
+    err |= cbor_encoder_close_container(enc, &entries);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+static int
+log_encode(const struct log_mgmt_log *log, CborEncoder *ctxt,
+           int64_t timestamp, uint32_t index)
+{
+    CborEncoder logs;
+    CborError err;
+    int rc;
+
+    err = 0;
+    err |= cbor_encoder_create_map(ctxt, &logs, CborIndefiniteLength);
+    err |= cbor_encode_text_stringz(&logs, "name");
+    err |= cbor_encode_text_stringz(&logs, log->name);
+    err |= cbor_encode_text_stringz(&logs, "type");
+    err |= cbor_encode_uint(&logs, log->type);
+
+    rc = log_encode_entries(log, &logs, timestamp, index);
+    if (rc != 0) {
+        return rc;
+    }
+
+    err |= cbor_encoder_close_container(ctxt, &logs);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: log show
+ */
+static int
+log_mgmt_show(struct mgmt_ctxt *ctxt)
+{
+    char name[LOG_MGMT_NAME_LEN];
+    struct log_mgmt_log log;
+    CborEncoder logs;
+    CborError err;
+    uint64_t index;
+    int64_t timestamp;
+    uint32_t next_idx;
+    int name_len;
+    int log_idx;
+    int rc;
+
+    const struct cbor_attr_t attr[] = {
+        {
+            .attribute = "log_name",
+            .type = CborAttrTextStringType,
+            .addr.string = name,
+            .len = sizeof(name),
+        },
+        {
+            .attribute = "ts",
+            .type = CborAttrIntegerType,
+            .addr.integer = &timestamp,
+        },
+        {
+            .attribute = "index",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &index,
+        },
+        {
+            .attribute = NULL,
+        },
+    };
+
+    name[0] = '\0';
+    rc = cbor_read_object(&ctxt->it, attr);
+    if (rc != 0) {
+        return MGMT_ERR_EINVAL;
+    }
+    name_len = strlen(name);
+
+    /* Determine the index that the next log entry would use. */
+    rc = log_mgmt_impl_get_next_idx(&next_idx);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "next_index");
+    err |= cbor_encode_uint(&ctxt->encoder, next_idx);
+
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "logs");
+    err |= cbor_encoder_create_array(&ctxt->encoder, &logs,
+                                     CborIndefiniteLength);
+
+    /* Iterate list of logs, encoding each that matches the client request. */
+    for (log_idx = 0; ; log_idx++) {
+        rc = log_mgmt_impl_get_log(log_idx, &log);
+        if (rc == MGMT_ERR_ENOENT) {
+            /* Log list fully iterated. */
+            if (name_len != 0) {
+                /* Client specified log name, but the log wasn't found. */
+                return MGMT_ERR_ENOENT;
+            } else {
+                break;
+            }
+        } else if (rc != 0) {
+            return rc;
+        }
+
+        /* Stream logs cannot be read. */
+        if (log.type != LOG_MGMT_TYPE_STREAM) {
+            if (name_len == 0 || strcmp(name, log.name) == 0) {
+                rc = log_encode(&log, &logs, timestamp, index);
+                if (rc != 0) {
+                    return rc;
+                }
+
+                /* If the client specified this log, he isn't interested in the
+                 * remaining ones.
+                 */
+                if (name_len != 0) {
+                    break;
+                }
+            }
+        }
+    }
+
+    err |= cbor_encoder_close_container(&ctxt->encoder, &logs);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, rc);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: log module_list
+ */
+static int
+log_mgmt_module_list(struct mgmt_ctxt *ctxt)
+{
+    const char *module_name;
+    CborEncoder modules;
+    CborError err;
+    int module;
+    int rc;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "module_map");
+    err |= cbor_encoder_create_map(&ctxt->encoder, &modules,
+                                   CborIndefiniteLength);
+
+    for (module = 0; ; module++) {
+        rc = log_mgmt_impl_get_module(module, &module_name);
+        if (rc == MGMT_ERR_ENOENT) {
+            break;
+        }
+        if (rc != 0) {
+            return rc;
+        }
+
+        if (module_name != NULL) {
+            err |= cbor_encode_text_stringz(&modules, module_name);
+            err |= cbor_encode_uint(&modules, module);
+        }
+    }
+
+    err |= cbor_encoder_close_container(&ctxt->encoder, &modules);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: log list
+ */
+static int
+log_mgmt_logs_list(struct mgmt_ctxt *ctxt)
+{
+    struct log_mgmt_log log;
+    CborEncoder log_list;
+    CborError err;
+    int log_idx;
+    int rc;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "log_list");
+    err |= cbor_encoder_create_array(&ctxt->encoder, &log_list,
+                                     CborIndefiniteLength);
+
+    for (log_idx = 0; ; log_idx++) {
+        rc = log_mgmt_impl_get_log(log_idx, &log);
+        if (rc == MGMT_ERR_ENOENT) {
+            break;
+        }
+        if (rc != 0) {
+            return rc;
+        }
+
+        if (log.type != LOG_MGMT_TYPE_STREAM) {
+            err |= cbor_encode_text_stringz(&log_list, log.name);
+        }
+    }
+
+    err |= cbor_encoder_close_container(&ctxt->encoder, &log_list);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: log level_list
+ */
+static int
+log_mgmt_level_list(struct mgmt_ctxt *ctxt)
+{
+    const char *level_name;
+    CborEncoder level_map;
+    CborError err;
+    int level;
+    int rc;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK);
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "level_map");
+    err |= cbor_encoder_create_map(&ctxt->encoder, &level_map,
+                                   CborIndefiniteLength);
+
+    for (level = 0; ; level++) {
+        rc = log_mgmt_impl_get_level(level, &level_name);
+        if (rc == MGMT_ERR_ENOENT) {
+            break;
+        }
+        if (rc != 0) {
+            return rc;
+        }
+
+        if (level_name != NULL) {
+            err |= cbor_encode_text_stringz(&level_map, level_name);
+            err |= cbor_encode_uint(&level_map, level);
+        }
+    }
+
+    err |= cbor_encoder_close_container(&ctxt->encoder, &level_map);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: log clear
+ */
+static int
+log_mgmt_clear(struct mgmt_ctxt *ctxt)
+{
+    struct log_mgmt_log log;
+    char name[LOG_MGMT_NAME_LEN] = {0};
+    int name_len;
+    int log_idx;
+    int rc;
+
+    const struct cbor_attr_t attr[] = {
+        {
+            .attribute = "log_name",
+            .type = CborAttrTextStringType,
+            .addr.string = name,
+            .len = sizeof(name)
+        },
+        {
+            .attribute = NULL
+        },
+    };
+
+    name[0] = '\0';
+    rc = cbor_read_object(&ctxt->it, attr);
+    if (rc != 0) {
+        return MGMT_ERR_EINVAL;
+    }
+    name_len = strlen(name);
+
+    for (log_idx = 0; ; log_idx++) {
+        rc = log_mgmt_impl_get_log(log_idx, &log);
+        if (rc == MGMT_ERR_ENOENT) {
+            return 0;
+        }
+        if (rc != 0) {
+            return rc;
+        }
+
+        if (log.type != LOG_MGMT_TYPE_STREAM) {
+            if (name_len == 0 || strcmp(log.name, name) == 0) {
+                rc = log_mgmt_impl_clear(log.name);
+                if (rc != 0) {
+                    return rc;
+                }
+
+                if (name_len != 0) {
+                    return 0;
+                }
+            }
+        }
+    }
+
+    if (name_len != 0) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    return 0;
+}
+
+void
+log_mgmt_register_group(void)
+{
+    mgmt_register_group(&log_mgmt_group);
+}
diff --git a/cmd/log_mgmt/src/log_mgmt_config.h b/cmd/log_mgmt/src/log_mgmt_config.h
new file mode 100644
index 0000000..572fb00
--- /dev/null
+++ b/cmd/log_mgmt/src/log_mgmt_config.h
@@ -0,0 +1,45 @@
+/*
+ * 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 H_LOG_MGMT_CONFIG_
+#define H_LOG_MGMT_CONFIG_
+
+#if defined MYNEWT
+
+#include "syscfg/syscfg.h"
+
+#define LOG_MGMT_CHUNK_SIZE MYNEWT_VAL(LOG_MGMT_CHUNK_SIZE)
+#define LOG_MGMT_NAME_LEN   MYNEWT_VAL(LOG_MGMT_NAME_LEN)
+#define LOG_MGMT_BODY_LEN   MYNEWT_VAL(LOG_MGMT_BODY_LEN)
+
+#elif defined __ZEPHYR__
+
+#define LOG_MGMT_CHUNK_SIZE CONFIG_LOG_MGMT_CHUNK_SIZE
+#define LOG_MGMT_NAME_LEN   CONFIG_LOG_MGMT_NAME_LEN
+#define LOG_MGMT_BODY_LEN   CONFIG_LOG_MGMT_BODY_LEN
+
+#else
+
+/* No direct support for this OS.  The application needs to define the above
+ * settings itself.
+ */
+
+#endif
+
+#endif
diff --git a/cmd/log_mgmt/src/stubs.c b/cmd/log_mgmt/src/stubs.c
new file mode 100644
index 0000000..7ce61cf
--- /dev/null
+++ b/cmd/log_mgmt/src/stubs.c
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/**
+ * These stubs get linked in when there is no equivalent OS-specific
+ * implementation.
+ */
+
+#include "mgmt/mgmt.h"
+#include "log_mgmt/log_mgmt_impl.h"
+
+int __attribute__((weak))
+log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+log_mgmt_impl_get_module(int idx, const char **out_module_name)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+log_mgmt_impl_get_level(int idx, const char **out_level_name)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+log_mgmt_impl_get_next_idx(uint32_t *out_idx)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+log_mgmt_impl_foreach_entry(const char *log_name,
+                            const struct log_mgmt_filter *filter,
+                            log_mgmt_foreach_entry_fn *cb,
+                            void *arg)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+log_mgmt_impl_clear(const char *log_name)
+{
+    return MGMT_ERR_ENOTSUP;
+}
diff --git a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
index df996a8..20ee5a6 100644
--- a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
+++ b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
@@ -21,6 +21,7 @@
 #include <misc/reboot.h>
 #include <debug/object_tracing.h>
 #include <kernel_structs.h>
+#include "logging/reboot_log.h"
 #include "mgmt/mgmt.h"
 #include "os_mgmt/os_mgmt.h"
 #include "os_mgmt/os_mgmt_impl.h"
@@ -77,6 +78,7 @@ os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info)
 static void
 zephyr_os_mgmt_reset_work_handler(struct k_work *work)
 {
+    reboot_log_write("mcumgr");
     sys_reboot(SYS_REBOOT_WARM);
 }
 

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 10/42: Documentation.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 5515138c01a910eaeaf67aff89d0ca2f3c1dbcac
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:16:10 2018 -0800

    Documentation.
---
 README.md                  | 126 ++++++++++++++++++++++++++++++++++++++++++++-
 transport/smp-bluetooth.md |  50 ++++++++++++++++++
 transport/smp-console.md   |  56 ++++++++++++++++++++
 3 files changed, 231 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 3a9710e..12141dc 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,125 @@
-# mynewt-mcumgr
+# mcumgr
+
+This is mcumgr, version 0.0.1
+
+mcumgr is a management library for 32-bit MCUs.   The goal of mcumgr is to
+define a common management infrastructure with pluggable transport and encoding
+components.  In addition, mcumgr provides definitions and handlers for some
+core commands: image management, file system management, and OS managment.
+
+mcumgr is operating system and hardware independent.  It relies on hardware
+porting layers from the operating system it runs on.  Currently, mcumgr runs on
+both the Apache Mynewt and Zephyr operating systems.
+
+## Command line tool
+
+The `mcumgr` command line tool is available at:
+https://github.com/apache/mynewt-mcumgr-cli.  The tool is written in Go, and it
+is installed with the `go get` command:
+
+```
+$ go get github.com/apache/mynewt-mcumgr-cli/mcumgr
+```
+
+The `mcumgr` tool allows you to manage devices running an mcumgr server.
+
+## Architecture
+
+The mcumgr stack has the following layout:
+
+```
++---------------------+---------------------+
+|             <command handlers>            |
++---------------------+---------------------+
+|                   mgmt                    |
++---------------------+---------------------+
+|           <transfer encoding(s)>          |
++---------------------+---------------------+
+|               <transport(s)>              |
++---------------------+---------------------+
+```
+
+Items enclosed in angled brackets represent generic components that can be plugged into mcumgr.  The items in this stack diagram are defined below:
+* *Command handler*: Processes incoming mcumgr requests and generates corresponding responses.  A command handler is associated with a single command type, defined by a (group ID, command ID) pair.
+* *mgmt*: The core of mcumgr; facilitates the passing of requests and responses between the generic command handlers and the concrete transports and transfer encodings.
+* *Transfer encoding*: Defines how mcumgr requests and responses are encoded on the wire.
+* *Transport*: Sends and receives mcumgr packets over a particular medium.
+
+Each transport is configured with a single transfer encoding.
+
+As an example, the sample application `smp_svr` uses the following components:
+
+* Command handlers:
+    * Image management (`img_mgmt`)
+    * File system management (`fs_mgmt`)
+    * OS management (`os_mgmt`)
+* Transfer/Transports protocols:
+    * SMP/Bluetooth
+    * SMP/Shell
+
+yielding the following stack diagram:
+
+```
++--------------+--------------+-------------+
+|   img_mgmt   |   fs_mgmt    |   os_mgmt   |
++--------------+--------------+-------------+
+|                   mgmt                    |
++---------------------+---------------------+
+|         SMP         |         SMP         |
++---------------------+---------------------+
+|      Bluetooth      |        Shell        |
++---------------------+---------------------+
+```
+
+## Command definition
+
+An mcumgr request or response consists of the following two components:
+* mcumgr header
+* CBOR key-value map 
+
+How these two components are encoded and parsed depends on the transfer
+encoding used.
+
+The mcumgr header structure is defined in `mgmt/include/mgmt/mgmt.h` as
+`struct mgmt_hdr`.
+
+The contents of the CBOR key-value map are specified per command type.
+
+## Supported transfer encodings
+
+Mcumgr comes with one built-in transfer encoding: Simple Management Protocol (SMP).  SMP requests and responses have a very basic structure.  For details, see the comments at the top of `smp/include/smp/smp.h`.
+
+## Supported transports
+
+The mcumgr project defines two transports:
+    * SMP/Console
+    * SMP/Bluetooth
+
+Particulars of these transports are specified in the following documents:
+    * SMP/Console: `transports/smp-console.md`
+    * SMP/Bluetooth: `transports/smp-bluetooth.md`
+
+Implementations, being hardware- and OS-specified, are not included.
+
+## Browsing
+
+Information and documentation for mcumgr is stored within the source.
+
+For more information in the source, here are some pointers:
+
+- [cborattr](https://github.com/apache/mcumgr/tree/master/cborattr): Used for parsing incoming mcumgr requests.  Destructures mcumgr packets and populates corresponding field variables.
+- [cmd](https://github.com/apache/mcumgr/tree/master/cmd): Built-in command handlers for the core mcumgr commands.
+- [ext](https://github.com/apache/mcumgr/tree/master/ext): Third-party libraries that mcumgr depends on.
+- [mgmt](https://github.com/apache/mcumgr/tree/master/mgmt): Code implementing the `mgmt` layer of mcumgr.
+- [samples](https://github.com/apache/mcumgr/tree/master/samples): Sample applications utilizing mcumgr.
+- [smp](https://github.com/apache/mcumgr/tree/master/smp): The built-in transfer encoding: Simple management protocol.
+
+## Known issues
+
+- (Zephyr) If the Bluetooth stack runs out of ACL transmit buffers while a large mcumgr response is being sent, the buffers never get freed.  This appears to trigger a net_buf leak in the stack.
+
+## Joining
+
+Developers welcome!
+
+* Our Slack channel: https://mynewt.slack.com/messages/C7Y3K0C2J
diff --git a/transport/smp-bluetooth.md b/transport/smp-bluetooth.md
new file mode 100644
index 0000000..029d995
--- /dev/null
+++ b/transport/smp-bluetooth.md
@@ -0,0 +1,50 @@
+# SMP over Bluetooth
+
+This document specifies how the mcumgr Simple Management Procotol (SMP) is
+transmitted over Bluetooth.
+
+## Overview
+
+All SMP communication utilizes a single GATT characteristic.  An SMP request is
+sent in the form of either 1) a GATT Write Command, or 2) a GATT Write Without
+Response command.  An SMP response is sent in the form of a GATT Notification
+specifying the same characteristic that was written.
+
+If an SMP request or response is too large to fit in a single GATT command, the
+sender fragments it across several commands.  No additional framing is
+introduced when a request or response is fragmented; the payload is simply
+split among several commands.  Since Bluetooth guarantees ordered delivery of
+packets, the SMP header in the first fragment contains sufficient information
+for reassembly.
+
+## Services
+
+### SMP service
+
+UUID: `8D53DC1D-1DB7-4CD3-868B-8A527460AA84`
+
+### Characteristics
+
+#### SMP Characteristic
+
+| Field | Value                                                             |
+| ----- | ----------------------------------------------------------------- |
+| Name                  | SMP                                               |
+| Description           | Used for both SMP requests and responses.         |
+| Read                  | Excluded                                          |
+| Write                 | Mandatory                                         |
+| WriteWithoutResponse  | Mandatory                                         |
+| SignedWrite           | Excluded                                          |
+| Notify                | Mandatory                                         |
+| Indicate              | Excluded                                          |
+| WritableAuxiliaries   | Excluded                                          |
+| Broadcast             | Excluded                                          |
+| ExtendedProperties    |                                                   |
+
+As indicated, SMP requests can be sent in the form of either a Write or a Write
+Without Response.  The Write Without Response form is generally preferred, as
+an application-layer response is always sent in the form of a Notification.
+The regular Write form is accepted in case the client requires a GATT response
+to initiate pairing.
+
+Security for this characteristic is optional.
diff --git a/transport/smp-console.md b/transport/smp-console.md
new file mode 100644
index 0000000..cbf9b47
--- /dev/null
+++ b/transport/smp-console.md
@@ -0,0 +1,56 @@
+# SMP over console
+
+This document specifies how the mcumgr Simple Management Procotol (SMP) is
+transmitted over text consoles.
+
+## Overview
+
+Mcumgr packets sent over serial are fragmented into frames of 128 bytes or
+fewer.
+
+The initial frame in a packet has the following format:
+
+```
+    offset 0:    0x06 0x09
+    === Begin base64 encoding ===
+    offset 2:    <16-bit packet-length>
+    offset ?:    <body>
+    offset ?:    <crc16> (if final frame)
+    === End base64 encoding ===
+    offset ?:    0x0a (newline)
+```
+
+All subsequent frames have the following format:
+
+```
+    offset 0:    0x04 0x14
+    === Begin base64 encoding ===
+    offset 2:    <body>
+    offset ?:    <crc16> (if final frame)
+    === End base64 encoding ===
+    offset ?:    0x0a (newline)
+```
+
+All integers are represented in big-endian.  The packet fields are described
+below:
+
+| Field | Description |
+| ----- | ----------- |
+| 0x06 0x09 | Byte pair indicating the start of a packet. |
+| 0x04 0x14 | Byte pair indicating the start of a continuation frame. |
+| Packet length | The combined total length of the *unencoded* body. |
+| Body | The actual SMP data (i.e., 8-byte header and CBOR key-value map). |
+| CRC16 | A CRC16 of the *unencoded* body of the entire packet.  This field is only present in the final frame of a packet. |
+| Newline | A 0x0a byte; terminates a frame. |
+
+The packet is fully received when <packet-length> bytes of body has been
+received.
+
+## CRC details
+
+The CRC16 should be calculated with the following parameters:
+
+| Field         | Value         |
+| ------------- | ------------- |
+| Polynomial    | 0x1021        |
+| Initial Value | 0             |

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 42/42: smp_svr (zephyr) - CONFIG_NET_BUF_USER_DATA_SIZE=7

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 44e350044d1d7f417942dd653519525349af42e3
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Feb 12 17:40:40 2018 -0800

    smp_svr (zephyr) - CONFIG_NET_BUF_USER_DATA_SIZE=7
    
    This setting is required by the updated net_buf API.  Failing to
    configure this setting to a value >= 7 causes a static assert failure.
---
 samples/smp_svr/zephyr/prj.conf | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/samples/smp_svr/zephyr/prj.conf b/samples/smp_svr/zephyr/prj.conf
index 9e04c3c..42abc04 100644
--- a/samples/smp_svr/zephyr/prj.conf
+++ b/samples/smp_svr/zephyr/prj.conf
@@ -19,6 +19,9 @@ CONFIG_BT_RX_BUF_LEN=260
 CONFIG_MCUMGR_SMP_BT=y
 CONFIG_MCUMGR_SMP_SHELL=y
 
+# Bluetooth support requires a net_buf user_data size >= 7.
+CONFIG_NET_BUF_USER_DATA_SIZE=7
+
 # Enable flash operations.
 CONFIG_FLASH=y
 

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 26/42: smp_svr - Add statistics.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit e86e83f27293ec7eaef751c8d5acc62f411248d3
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Jan 30 12:17:43 2018 -0800

    smp_svr - Add statistics.
---
 samples/smp_svr/zephyr/prj.conf   |  5 +++++
 samples/smp_svr/zephyr/src/main.c | 31 +++++++++++++++++++++++++++----
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/samples/smp_svr/zephyr/prj.conf b/samples/smp_svr/zephyr/prj.conf
index 88ad795..5179c2c 100644
--- a/samples/smp_svr/zephyr/prj.conf
+++ b/samples/smp_svr/zephyr/prj.conf
@@ -39,11 +39,16 @@ CONFIG_REBOOT_LOG=y
 # Enable assertions.  Required for crash logging.
 CONFIG_ASSERT=y
 
+# Enable statistics and statistic names.
+CONFIG_STATS=y
+CONFIG_STATS_NAMES=y
+
 # Enable all core commands.
 CONFIG_MCUMGR_CMD_FS_MGMT=y
 CONFIG_MCUMGR_CMD_IMG_MGMT=y
 CONFIG_MCUMGR_CMD_LOG_MGMT=y
 CONFIG_MCUMGR_CMD_OS_MGMT=y
+CONFIG_MCUMGR_CMD_STAT_MGMT=y
 
 ### nRF5 specific settings
 
diff --git a/samples/smp_svr/zephyr/src/main.c b/samples/smp_svr/zephyr/src/main.c
index 2906711..47e5de2 100644
--- a/samples/smp_svr/zephyr/src/main.c
+++ b/samples/smp_svr/zephyr/src/main.c
@@ -14,6 +14,7 @@
 #include "logging/mdlog.h"
 #include "logging/reboot_log.h"
 #include "fcb.h"
+#include "stats.h"
 #include "mgmt/smp_bt.h"
 #include "mgmt/buf.h"
 
@@ -29,13 +30,13 @@
 #ifdef CONFIG_MCUMGR_CMD_LOG_MGMT
 #include "log_mgmt/log_mgmt.h"
 #endif
+#ifdef CONFIG_MCUMGR_CMD_STAT_MGMT
+#include "stat_mgmt/stat_mgmt.h"
+#endif
 
 #define DEVICE_NAME         CONFIG_BT_DEVICE_NAME
 #define DEVICE_NAME_LEN     (sizeof(DEVICE_NAME) - 1)
 
-struct fcb smp_svr_fcb;
-struct mdlog smp_svr_log;
-
 /* smp_svr uses the first "peruser" log module. */
 #define SMP_SVR_MDLOG_MODULE  (MDLOG_MODULE_PERUSER + 0)
 
@@ -43,6 +44,21 @@ struct mdlog smp_svr_log;
 #define SMP_SVR_MDLOG(lvl, ...) \
     MDLOG_ ## lvl(&smp_svr_log, SMP_SVR_MDLOG_MODULE, __VA_ARGS__)
 
+/* Define an example stats group; tracks seconds of uptime. */
+STATS_SECT_START(smp_svr_stats)
+    STATS_SECT_ENTRY(ticks)
+STATS_SECT_END
+
+/* Assign a name to the `ticks` stat. */
+STATS_NAME_START(smp_svr_stats)
+    STATS_NAME(smp_svr_stats, ticks)
+STATS_NAME_END(smp_svr_stats)
+
+/* Define an instance of the stats group. */
+STATS_SECT_DECL(smp_svr_stats) smp_svr_stats;
+
+struct fcb smp_svr_fcb;
+struct mdlog smp_svr_log;
 
 static const struct bt_data ad[] = {
     BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
@@ -158,6 +174,9 @@ void main(void)
     reboot_log_configure(&smp_svr_log);
 #endif
 
+    rc = STATS_INIT_AND_REG(smp_svr_stats, STATS_SIZE_32, "smp_svr_stats");
+    assert(rc == 0);
+
     /* Register the built-in mcumgr command handlers. */
 #ifdef CONFIG_MCUMGR_CMD_FS_MGMT
     fs_mgmt_register_group();
@@ -171,6 +190,9 @@ void main(void)
 #ifdef CONFIG_MCUMGR_CMD_LOG_MGMT
     log_mgmt_register_group();
 #endif
+#ifdef CONFIG_MCUMGR_CMD_STAT_MGMT
+    stat_mgmt_register_group();
+#endif
 
     /* Enable Bluetooth. */
     rc = bt_enable(bt_ready);
@@ -192,6 +214,7 @@ void main(void)
      * main thread idle while the mcumgr server runs.
      */
     while (1) {
-        k_sleep(INT32_MAX);
+        k_sleep(1000);
+        STATS_INC(smp_svr_stats, ticks);
     }
 }

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 34/42: mcumgr: Minor refactor to increase readability

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 4a723061331dedaac52a42d3f5475b14d1a7c32e
Author: Sebastian Bøe <se...@nordicsemi.no>
AuthorDate: Mon Feb 12 12:32:37 2018 +0100

    mcumgr: Minor refactor to increase readability
    
    horizontal alignment improves readability and diff-ability.
    
    Signed-off-by: Sebastian Bøe <se...@nordicsemi.no>
---
 CMakeLists.txt | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a88725a..4225f3e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,4 +9,8 @@ add_subdirectory(smp)
 
 zephyr_library_link_libraries(MCUMGR)
 
-target_link_libraries(MCUMGR INTERFACE zephyr_interface BASE64 TINYCBOR)
+target_link_libraries(MCUMGR INTERFACE
+  zephyr_interface
+  BASE64
+  TINYCBOR
+  )

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 35/42: Indicate units (bytes) in Kconfig help.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 490f44f3715373051c16b02238da2c8fab52a4c5
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Feb 12 13:01:59 2018 -0800

    Indicate units (bytes) in Kconfig help.
---
 cmd/fs_mgmt/Kconfig   | 15 ++++++++-------
 cmd/img_mgmt/Kconfig  |  5 +++--
 cmd/log_mgmt/Kconfig  | 20 ++++++++++----------
 cmd/stat_mgmt/Kconfig |  8 ++++----
 4 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/cmd/fs_mgmt/Kconfig b/cmd/fs_mgmt/Kconfig
index 03157b0..ccbcf17 100644
--- a/cmd/fs_mgmt/Kconfig
+++ b/cmd/fs_mgmt/Kconfig
@@ -29,23 +29,24 @@ config FS_MGMT_UL_CHUNK_SIZE
     prompt "Maximum chunk size for file uploads"
     default 512
     help
-      Limits the maximum chunk size in file uploads.  A buffer of this size
-      gets allocated on the stack during handling of a file upload command.
+      Limits the maximum chunk size for file uploads, in bytes.  A buffer of
+      this size gets allocated on the stack during handling of a file upload command.
 
 config FS_MGMT_DL_CHUNK_SIZE
     int
     prompt "Maximum chunk size for file downloads"
     default 512
     help
-      Limits the maximum chunk size in file downloads.  A buffer of this size
-      gets allocated on the stack during handling of a file download command.
+      Limits the maximum chunk size for file downloads, in bytes.  A buffer of
+      this size gets allocated on the stack during handling of a file download
+      command.
 
 config FS_MGMT_PATH_SIZE
     int
     prompt "Maximum file path length"
     default 64
     help
-      Limits the maximum path length in file operations.  A buffer of this size
-      gets allocated on the stack during handling of file upload and download
-      commands.
+      Limits the maximum path length for file operations, in bytes.  A buffer
+      of this size gets allocated on the stack during handling of file upload
+      and download commands.
 endif
diff --git a/cmd/img_mgmt/Kconfig b/cmd/img_mgmt/Kconfig
index 2ac6c61..f8072b8 100644
--- a/cmd/img_mgmt/Kconfig
+++ b/cmd/img_mgmt/Kconfig
@@ -33,6 +33,7 @@ config IMG_MGMT_UL_CHUNK_SIZE
     prompt "Maximum chunk size for image uploads"
     default 512
     help
-      Limits the maximum chunk size in image uploads.  A buffer of this size
-      gets allocated on the stack during handling of a image upload command.
+      Limits the maximum chunk size for image uploads, in bytes.  A buffer of
+      this size gets allocated on the stack during handling of a image upload
+      command.
 endif
diff --git a/cmd/log_mgmt/Kconfig b/cmd/log_mgmt/Kconfig
index 8b43166..9373571 100644
--- a/cmd/log_mgmt/Kconfig
+++ b/cmd/log_mgmt/Kconfig
@@ -29,26 +29,26 @@ config LOG_MGMT_CHUNK_SIZE
     prompt "Maximum chunk size for log downloads"
     default 512
     help
-      Limits the maximum chunk size in log downloads.  A buffer of this size
-      gets allocated on the stack during handling of the log show command.
+      Limits the maximum chunk size for log downloads, in bytes.  A buffer of
+      this size gets allocated on the stack during handling of the log show command.
 
 config LOG_MGMT_NAME_LEN
     int
     prompt "Maximum log name length"
     default 64
     help
-      Limits the maximum length of log names.  If a log's name length exceeds
-      this number, it gets truncated in management responses.  A buffer of this
-      size gets allocated on the stack during handling of all log management
-      commands.
+      Limits the maximum length of log names, in bytes.  If a log's name length
+      exceeds this number, it gets truncated in management responses.  A buffer
+      of this size gets allocated on the stack during handling of all log
+      management commands.
 
 config LOG_MGMT_BODY_LEN
     int
     prompt "Maximum log body length"
     default 128
     help
-      Limits the maximum length of log entry bodies.  If a log entry's body
-      length exceeds this number, it gets truncated in management responses.  A
-      buffer of this size gets allocated on the stack during handling of the
-      log show command.
+      Limits the maximum length of log entry bodies, in bytes.  If a log
+      entry's body length exceeds this number, it gets truncated in management
+      responses.  A buffer of this size gets allocated on the stack during
+      handling of the log show command.
 endif
diff --git a/cmd/stat_mgmt/Kconfig b/cmd/stat_mgmt/Kconfig
index ffda20f..3688ed1 100644
--- a/cmd/stat_mgmt/Kconfig
+++ b/cmd/stat_mgmt/Kconfig
@@ -29,8 +29,8 @@ config STAT_MGMT_MAX_NAME_LEN
     prompt "Maximum stat group name length"
     default 32
     help
-      Limits the maximum stat group name length in mcumgr requests.  A buffer
-      of this size gets allocated on the stack during handling of all stat read
-      commands.  If a stat group's name exceeds this limit, it will be
-      impossible to retrieve its values with a stat show command.
+      Limits the maximum stat group name length in mcumgr requests, in bytes.
+      A buffer of this size gets allocated on the stack during handling of all
+      stat read commands.  If a stat group's name exceeds this limit, it will
+      be impossible to retrieve its values with a stat show command.
 endif

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 08/42: Zephyr support.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit cfe132ea4f00ba519ed7f313d974ecbb3aa84987
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:15:18 2018 -0800

    Zephyr support.
---
 CMakeLists.txt                                 |  12 ++
 Kconfig                                        |  29 ++++
 cmd/CMakeLists.txt                             |   3 +
 cmd/Kconfig                                    |  24 +++
 cmd/fs_mgmt/CMakeLists.txt                     |   9 +
 cmd/fs_mgmt/Kconfig                            |  50 ++++++
 cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c   | 151 ++++++++++++++++
 cmd/img_mgmt/CMakeLists.txt                    |  11 ++
 cmd/img_mgmt/Kconfig                           |  38 +++++
 cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c | 227 +++++++++++++++++++++++++
 cmd/os_mgmt/CMakeLists.txt                     |   9 +
 cmd/os_mgmt/Kconfig                            |  35 ++++
 cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c   |  85 +++++++++
 ext/CMakeLists.txt                             |   2 +
 14 files changed, 685 insertions(+)

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..a88725a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_library(MCUMGR INTERFACE)
+
+zephyr_library()
+add_subdirectory(cborattr)
+add_subdirectory(cmd)
+add_subdirectory(ext)
+add_subdirectory(mgmt)
+add_subdirectory(smp)
+
+zephyr_library_link_libraries(MCUMGR)
+
+target_link_libraries(MCUMGR INTERFACE zephyr_interface BASE64 TINYCBOR)
diff --git a/Kconfig b/Kconfig
new file mode 100644
index 0000000..89de3ee
--- /dev/null
+++ b/Kconfig
@@ -0,0 +1,29 @@
+# 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.
+
+menuconfig MCUMGR
+    bool
+    prompt "mcumgr Support"
+    select TINYCBOR
+    default n
+    help
+      This option enables the mcumgr management library.
+
+if MCUMGR
+source "ext/mcumgr/mgmt/port/zephyr/Kconfig"
+source "ext/mcumgr/cmd/Kconfig"
+endif
diff --git a/cmd/CMakeLists.txt b/cmd/CMakeLists.txt
new file mode 100644
index 0000000..bc91e2f
--- /dev/null
+++ b/cmd/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_FS_MGMT   fs_mgmt)
+add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_IMG_MGMT  img_mgmt)
+add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_OS_MGMT   os_mgmt)
diff --git a/cmd/Kconfig b/cmd/Kconfig
new file mode 100644
index 0000000..a0e2031
--- /dev/null
+++ b/cmd/Kconfig
@@ -0,0 +1,24 @@
+# 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.
+
+menu "Command handlers"
+
+source "ext/mcumgr/cmd/fs_mgmt/Kconfig"
+source "ext/mcumgr/cmd/img_mgmt/Kconfig"
+source "ext/mcumgr/cmd/os_mgmt/Kconfig"
+
+endmenu
diff --git a/cmd/fs_mgmt/CMakeLists.txt b/cmd/fs_mgmt/CMakeLists.txt
new file mode 100644
index 0000000..974d0a9
--- /dev/null
+++ b/cmd/fs_mgmt/CMakeLists.txt
@@ -0,0 +1,9 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c
+    cmd/fs_mgmt/src/fs_mgmt.c
+    cmd/fs_mgmt/src/stubs.c
+)
diff --git a/cmd/fs_mgmt/Kconfig b/cmd/fs_mgmt/Kconfig
new file mode 100644
index 0000000..62602d6
--- /dev/null
+++ b/cmd/fs_mgmt/Kconfig
@@ -0,0 +1,50 @@
+# 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.
+
+menuconfig MCUMGR_CMD_FS_MGMT
+    bool
+    prompt "Enable mcumgr handlers for file management"
+    default n
+    help
+      Enables mcumgr handlers for file management
+
+if MCUMGR_CMD_FS_MGMT
+config FS_MGMT_UL_CHUNK_SIZE
+    int
+    prompt "Maximum chunk size for file uploads"
+    default 512
+    help
+      Limits the maximum chunk size in file uploads.  A buffer of this size
+      gets allocated on the stack during handling of a file upload command.
+
+config FS_MGMT_DL_CHUNK_SIZE
+    int
+    prompt "Maximum chunk size for file downloads"
+    default 512
+    help
+      Limits the maximum chunk size in file downloads.  A buffer of this size
+      gets allocated on the stack during handling of a file download command.
+
+config FS_MGMT_PATH_SIZE
+    int
+    prompt "Maximum file path length"
+    default 64
+    help
+      Limits the maximum path length in file operations.  A buffer of this size
+      gets allocated on the stack during handling of file upload and download
+      commands.
+endif
diff --git a/cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c b/cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c
new file mode 100644
index 0000000..42b7d80
--- /dev/null
+++ b/cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c
@@ -0,0 +1,151 @@
+/*
+ * 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 "mgmt/mgmt.h"
+#include "fs_mgmt/fs_mgmt_impl.h"
+#include "fs.h"
+
+int
+fs_mgmt_impl_filelen(const char *path, size_t *out_len)
+{
+    struct fs_dirent dirent;
+    int rc;
+
+    rc = fs_stat(path, &dirent);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (dirent.type != FS_DIR_ENTRY_FILE) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    *out_len = dirent.size;
+
+    return 0;
+}
+
+int
+fs_mgmt_impl_read(const char *path, size_t offset, size_t len,
+                  void *out_data, size_t *out_len)
+{
+    fs_file_t file;
+    ssize_t bytes_read;
+    int rc;
+
+    rc = fs_open(&file, path);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = fs_seek(&file, offset, FS_SEEK_SET);
+    if (rc != 0) {
+        goto done;
+    }
+
+    bytes_read = fs_read(&file, out_data, len);
+    if (bytes_read < 0) {
+        goto done;
+    }
+
+    *out_len = bytes_read;
+
+done:
+    fs_close(&file);
+
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    } else {
+        return 0;
+    }
+}
+
+static int
+zephyr_fs_mgmt_truncate(const char *path)
+{
+    size_t len;
+    int rc;
+
+    /* Attempt to get the length of the file at the specified path.  This is a
+     * quick way to determine if there is already a file there.
+     */
+    rc = fs_mgmt_impl_filelen(path, &len);
+    if (rc == 0) {
+        /* There is already a file with the specified path.  Unlink it to
+         * simulate a truncate operation.
+         *
+         * XXX: This isn't perfect - if the file is currently open, the unlink
+         * operation won't actually delete the file.  Consequently, the file
+         * will get partially overwritten rather than truncated.  The NFFS port
+         * doesn't support the truncate operation, so this is an imperfect
+         * workaround.
+         */
+        rc = fs_unlink(path);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return 0;
+}
+
+int
+fs_mgmt_impl_write(const char *path, size_t offset, const void *data,
+                   size_t len)
+{
+    fs_file_t file;
+    int rc;
+ 
+    /* Truncate the file before writing the first chunk.  This is done to
+     * properly handle an overwrite of an existing file.
+     *
+     */
+    if (offset == 0) {
+        rc = zephyr_fs_mgmt_truncate(path);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    rc = fs_open(&file, path);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    rc = fs_seek(&file, offset, FS_SEEK_SET);
+    if (rc != 0) {
+        goto done;
+    }
+
+    rc = fs_write(&file, data, len);
+    if (rc < 0) {
+        goto done;
+    }
+
+    rc = 0;
+
+done:
+    fs_close(&file);
+
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    } else {
+        return 0;
+    }
+}
diff --git a/cmd/img_mgmt/CMakeLists.txt b/cmd/img_mgmt/CMakeLists.txt
new file mode 100644
index 0000000..9b52e71
--- /dev/null
+++ b/cmd/img_mgmt/CMakeLists.txt
@@ -0,0 +1,11 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
+    cmd/img_mgmt/src/img_mgmt.c
+    cmd/img_mgmt/src/img_mgmt_state.c
+    cmd/img_mgmt/src/img_mgmt_util.c
+    cmd/img_mgmt/src/stubs.c
+)
diff --git a/cmd/img_mgmt/Kconfig b/cmd/img_mgmt/Kconfig
new file mode 100644
index 0000000..2ac6c61
--- /dev/null
+++ b/cmd/img_mgmt/Kconfig
@@ -0,0 +1,38 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE image
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this image
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this image 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.
+
+menuconfig MCUMGR_CMD_IMG_MGMT
+    bool
+    prompt "Enable mcumgr handlers for image management"
+    select FLASH
+    select MPU_ALLOW_FLASH_WRITE
+    select IMG_MANAGER
+    select MCUBOOT_IMG_MANAGER
+
+    default n
+    help
+      Enables mcumgr handlers for image management
+
+if MCUMGR_CMD_IMG_MGMT
+config IMG_MGMT_UL_CHUNK_SIZE
+    int
+    prompt "Maximum chunk size for image uploads"
+    default 512
+    help
+      Limits the maximum chunk size in image uploads.  A buffer of this size
+      gets allocated on the stack during handling of a image upload command.
+endif
diff --git a/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
new file mode 100644
index 0000000..dc71d8f
--- /dev/null
+++ b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
@@ -0,0 +1,227 @@
+/*
+ * 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 <flash.h>
+#include <zephyr.h>
+#include <soc.h>
+#include <init.h>
+#include <dfu/mcuboot.h>
+#include <dfu/flash_img.h>
+#include "mgmt/mgmt.h"
+#include "img_mgmt/img_mgmt_impl.h"
+#include "img_mgmt/img_mgmt.h"
+#include "../../../src/img_mgmt_priv.h"
+
+static struct device *zephyr_img_flash_dev;
+static struct flash_img_context zephyr_img_flash_ctxt;
+
+/**
+ * Determines if the specified area of flash is completely unwritten.
+ */
+static int
+img_mgmt_impl_flash_check_empty(off_t offset, size_t size, bool *out_empty)
+{
+    uint32_t data[16];
+    off_t addr;
+    off_t end;
+    int bytes_to_read;
+    int rc;
+    int i;
+
+    assert(size % 4 == 0);
+
+    end = offset + size;
+    for (addr = offset; addr < end; addr += sizeof data) {
+        if (end - addr < sizeof data) {
+            bytes_to_read = end - addr;
+        } else {
+            bytes_to_read = sizeof data;
+        }
+
+        rc = flash_read(zephyr_img_flash_dev, addr, data, bytes_to_read);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+
+        for (i = 0; i < bytes_to_read / 4; i++) {
+            if (data[i] != 0xffffffff) {
+                *out_empty = false;
+                return 0;
+            }
+        }
+    }
+
+    *out_empty = true;
+    return 0;
+}
+
+/**
+ * Converts an offset within an image slot to an absolute address.
+ */
+static off_t
+img_mgmt_impl_abs_offset(int slot, off_t sub_offset)
+{
+    off_t slot_start;
+
+    switch (slot) {
+    case 0:
+        slot_start = FLASH_AREA_IMAGE_0_OFFSET;
+        break;
+
+    case 1:
+        slot_start = FLASH_AREA_IMAGE_1_OFFSET;
+        break;
+
+    default:
+        assert(0);
+        slot_start = FLASH_AREA_IMAGE_1_OFFSET;
+        break;
+    }
+
+    return slot_start + sub_offset;
+}
+
+int
+img_mgmt_impl_erase_slot(void)
+{
+    bool empty;
+    int rc;
+
+    rc = img_mgmt_impl_flash_check_empty(FLASH_AREA_IMAGE_1_OFFSET,
+                                         FLASH_AREA_IMAGE_1_SIZE,
+                                         &empty);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (!empty) {
+        rc = boot_erase_img_bank(FLASH_AREA_IMAGE_1_OFFSET);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_write_pending(int slot, bool permanent)
+{
+    int rc;
+
+    if (slot != 1) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    rc = boot_request_upgrade(permanent);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_write_confirmed(void)
+{
+    int rc;
+
+    rc = boot_write_img_confirmed();
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_read(int slot, unsigned int offset, void *dst,
+                   unsigned int num_bytes)
+{
+    off_t abs_offset;
+    int rc;
+
+    abs_offset = img_mgmt_impl_abs_offset(slot, offset);
+    rc = flash_read(zephyr_img_flash_dev, abs_offset, dst, num_bytes);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_write_image_data(unsigned int offset, const void *data,
+                               unsigned int num_bytes, bool last)
+{
+    int rc;
+
+    if (offset == 0) {
+        flash_img_init(&zephyr_img_flash_ctxt, zephyr_img_flash_dev);
+    }
+
+    /* Cast away const. */
+    rc = flash_img_buffered_write(&zephyr_img_flash_ctxt, (void *)data,
+                                  num_bytes, false);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    if (last) {
+        rc = flash_img_buffered_write(&zephyr_img_flash_ctxt, NULL, 0, true);
+        if (rc != 0) {
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return 0;
+}
+
+int
+img_mgmt_impl_swap_type(void)
+{
+    switch (boot_swap_type()) {
+    case BOOT_SWAP_TYPE_NONE:
+        return IMG_MGMT_SWAP_TYPE_NONE;
+    case BOOT_SWAP_TYPE_TEST:
+        return IMG_MGMT_SWAP_TYPE_TEST;
+    case BOOT_SWAP_TYPE_PERM:
+        return IMG_MGMT_SWAP_TYPE_PERM;
+    case BOOT_SWAP_TYPE_REVERT:
+        return IMG_MGMT_SWAP_TYPE_REVERT;
+    default:
+        assert(0);
+        return IMG_MGMT_SWAP_TYPE_NONE;
+    }
+}
+
+static int
+img_mgmt_impl_init(struct device *dev)
+{
+    ARG_UNUSED(dev);
+
+    zephyr_img_flash_dev = device_get_binding(FLASH_DRIVER_NAME);
+    if (zephyr_img_flash_dev == NULL) {
+        return -ENODEV;
+    }
+    return 0;
+}
+
+SYS_INIT(img_mgmt_impl_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
diff --git a/cmd/os_mgmt/CMakeLists.txt b/cmd/os_mgmt/CMakeLists.txt
new file mode 100644
index 0000000..0a9176a
--- /dev/null
+++ b/cmd/os_mgmt/CMakeLists.txt
@@ -0,0 +1,9 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
+    cmd/os_mgmt/src/os_mgmt.c
+    cmd/os_mgmt/src/stubs.c
+)
diff --git a/cmd/os_mgmt/Kconfig b/cmd/os_mgmt/Kconfig
new file mode 100644
index 0000000..10f0abc
--- /dev/null
+++ b/cmd/os_mgmt/Kconfig
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE image
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this image
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this image 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.
+
+menuconfig MCUMGR_CMD_OS_MGMT
+    bool
+    prompt "Enable mcumgr handlers for OS management"
+    select REBOOT
+    default n
+    help
+      Enables mcumgr handlers for OS management
+
+if MCUMGR_CMD_OS_MGMT
+config OS_MGMT_RESET_MS
+    int
+    prompt "Delay before executing reset command (ms)"
+    default 250
+    help
+      When a reset command is received, the system waits this many milliseconds
+      before performing the reset.  This delay allows time for the mcumgr
+      response to be delivered.
+endif
diff --git a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
new file mode 100644
index 0000000..221da97
--- /dev/null
+++ b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
@@ -0,0 +1,85 @@
+/*
+ * 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 <zephyr.h>
+#include <misc/reboot.h>
+#include <debug/object_tracing.h>
+#include <kernel_structs.h>
+#include "mgmt/mgmt.h"
+#include "os_mgmt/os_mgmt.h"
+#include "os_mgmt/os_mgmt_impl.h"
+
+static void zephyr_os_mgmt_reset_cb(struct k_timer *timer);
+
+static K_TIMER_DEFINE(zephyr_os_mgmt_reset_timer,
+                      zephyr_os_mgmt_reset_cb, NULL);
+
+#ifdef CONFIG_THREAD_MONITOR
+static const struct k_thread *
+zephyr_os_mgmt_task_at(int idx)
+{
+    const struct k_thread *thread;
+    int i;
+
+    thread = SYS_THREAD_MONITOR_HEAD;
+    for (i = 0; i < idx; i++) {
+        if (thread == NULL) {
+            break;
+        }
+        thread = SYS_THREAD_MONITOR_NEXT(thread);
+    }
+
+    return thread;
+}
+
+int
+os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info)
+{
+    const struct k_thread *thread;
+
+    thread = zephyr_os_mgmt_task_at(idx);
+    if (thread == NULL) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    *out_info = (struct os_mgmt_task_info){ 0 };
+
+    snprintf(out_info->oti_name, sizeof out_info->oti_name, "%d",
+             thread->base.prio);
+    out_info->oti_prio = thread->base.prio;
+    out_info->oti_taskid = idx;
+    out_info->oti_state = thread->base.thread_state;
+    out_info->oti_stksize = thread->stack_info.size / 4;
+
+    return 0;
+}
+#endif /* CONFIG_THREAD_MONITOR */
+
+static void
+zephyr_os_mgmt_reset_cb(struct k_timer *timer)
+{
+    sys_reboot(SYS_REBOOT_WARM);
+}
+
+int
+os_mgmt_impl_reset(unsigned int delay_ms)
+{
+    k_timer_start(&zephyr_os_mgmt_reset_timer, K_MSEC(delay_ms), 0);
+    return 0;
+}
diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
new file mode 100644
index 0000000..f32ffb5
--- /dev/null
+++ b/ext/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(base64)
+add_subdirectory(tinycbor)

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 40/42: Zephyr: use <> for non-relative include paths.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 1aca72268fb6c21977bd45752bb7ca509262e7b0
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Feb 12 13:18:22 2018 -0800

    Zephyr: use <> for non-relative include paths.
    
    For `#include` directives, Zephyr uses "" for paths relative to the
    source file; <> for headers in an include path.
---
 cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c     |  6 +++---
 cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c   |  6 +++---
 cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c   |  8 ++++----
 cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c     |  8 ++++----
 cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c |  8 ++++----
 samples/smp_svr/zephyr/src/main.c                | 12 ++++++------
 6 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c b/cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c
index 42b7d80..754d3c3 100644
--- a/cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c
+++ b/cmd/fs_mgmt/port/zephyr/src/zephyr_fs_mgmt.c
@@ -17,9 +17,9 @@
  * under the License.
  */
 
-#include "mgmt/mgmt.h"
-#include "fs_mgmt/fs_mgmt_impl.h"
-#include "fs.h"
+#include <fs.h>
+#include <mgmt/mgmt.h>
+#include <fs_mgmt/fs_mgmt_impl.h>
 
 int
 fs_mgmt_impl_filelen(const char *path, size_t *out_len)
diff --git a/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
index 143b1e0..8693451 100644
--- a/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
+++ b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
@@ -24,9 +24,9 @@
 #include <init.h>
 #include <dfu/mcuboot.h>
 #include <dfu/flash_img.h>
-#include "mgmt/mgmt.h"
-#include "img_mgmt/img_mgmt_impl.h"
-#include "img_mgmt/img_mgmt.h"
+#include <mgmt/mgmt.h>
+#include <img_mgmt/img_mgmt_impl.h>
+#include <img_mgmt/img_mgmt.h>
 #include "../../../src/img_mgmt_priv.h"
 
 static struct device *zephyr_img_mgmt_flash_dev;
diff --git a/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c b/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c
index 41cf51e..378c3ea 100644
--- a/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c
+++ b/cmd/log_mgmt/port/zephyr/src/zephyr_log_mgmt.c
@@ -18,10 +18,10 @@
  */
 
 #include <misc/util.h>
-#include "logging/mdlog.h"
-#include "mgmt/mgmt.h"
-#include "log_mgmt/log_mgmt.h"
-#include "log_mgmt/log_mgmt_impl.h"
+#include <logging/mdlog.h>
+#include <mgmt/mgmt.h>
+#include <log_mgmt/log_mgmt.h>
+#include <log_mgmt/log_mgmt_impl.h>
 #include "../../../src/log_mgmt_config.h"
 
 struct zephyr_log_mgmt_walk_arg {
diff --git a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
index 20ee5a6..e127bdb 100644
--- a/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
+++ b/cmd/os_mgmt/port/zephyr/src/zephyr_os_mgmt.c
@@ -21,10 +21,10 @@
 #include <misc/reboot.h>
 #include <debug/object_tracing.h>
 #include <kernel_structs.h>
-#include "logging/reboot_log.h"
-#include "mgmt/mgmt.h"
-#include "os_mgmt/os_mgmt.h"
-#include "os_mgmt/os_mgmt_impl.h"
+#include <logging/reboot_log.h>
+#include <mgmt/mgmt.h>
+#include <os_mgmt/os_mgmt.h>
+#include <os_mgmt/os_mgmt_impl.h>
 
 static void zephyr_os_mgmt_reset_cb(struct k_timer *timer);
 static void zephyr_os_mgmt_reset_work_handler(struct k_work *work);
diff --git a/cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c b/cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c
index dd0ba0b..22654f8 100644
--- a/cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c
+++ b/cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c
@@ -18,10 +18,10 @@
  */
 
 #include <misc/util.h>
-#include "stats.h"
-#include "mgmt/mgmt.h"
-#include "stat_mgmt/stat_mgmt.h"
-#include "stat_mgmt/stat_mgmt_impl.h"
+#include <stats.h>
+#include <mgmt/mgmt.h>
+#include <stat_mgmt/stat_mgmt.h>
+#include <stat_mgmt/stat_mgmt_impl.h>
 
 struct zephyr_stat_mgmt_walk_arg {
     stat_mgmt_foreach_entry_fn *cb;
diff --git a/samples/smp_svr/zephyr/src/main.c b/samples/smp_svr/zephyr/src/main.c
index 3e06e40..fde3f4e 100644
--- a/samples/smp_svr/zephyr/src/main.c
+++ b/samples/smp_svr/zephyr/src/main.c
@@ -11,12 +11,12 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/conn.h>
 #include <bluetooth/gatt.h>
-#include "logging/mdlog.h"
-#include "logging/reboot_log.h"
-#include "fcb.h"
-#include "stats.h"
-#include "mgmt/smp_bt.h"
-#include "mgmt/buf.h"
+#include <logging/mdlog.h>
+#include <logging/reboot_log.h>
+#include <fcb.h>
+#include <stats.h>
+#include <mgmt/smp_bt.h>
+#include <mgmt/buf.h>
 
 #ifdef CONFIG_MCUMGR_CMD_FS_MGMT
 #include "fs_mgmt/fs_mgmt.h"

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 30/42: zephyr img_mgmt: Use `FLASH_DEV_NAME`

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit fec54445ad34a682eea741d6ff45555d231f7d07
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Feb 8 14:33:40 2018 -0800

    zephyr img_mgmt: Use `FLASH_DEV_NAME`
    
    This used to be `FLASH_DRIVER_NAME`, but it changed in zephyr.
---
 cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
index e17952b..143b1e0 100644
--- a/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
+++ b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
@@ -218,7 +218,7 @@ zephyr_img_mgmt_init(struct device *dev)
 {
     ARG_UNUSED(dev);
 
-    zephyr_img_mgmt_flash_dev = device_get_binding(FLASH_DRIVER_NAME);
+    zephyr_img_mgmt_flash_dev = device_get_binding(FLASH_DEV_NAME);
     if (zephyr_img_mgmt_flash_dev == NULL) {
         return -ENODEV;
     }

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 27/42: smp_svr - Use CONFIG_BOOTLOADER_MCUBOOT setting.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit ffdecf8ece47c9e30cc5c934173ddd74e108d974
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 31 16:30:37 2018 -0800

    smp_svr - Use CONFIG_BOOTLOADER_MCUBOOT setting.
---
 samples/smp_svr/zephyr/prj.conf | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/samples/smp_svr/zephyr/prj.conf b/samples/smp_svr/zephyr/prj.conf
index 5179c2c..fc2f99c 100644
--- a/samples/smp_svr/zephyr/prj.conf
+++ b/samples/smp_svr/zephyr/prj.conf
@@ -1,8 +1,8 @@
 # Some command handlers require a large stack.
 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
 
-# Allow room for the mcuboot image header.
-CONFIG_TEXT_SECTION_OFFSET=0x200
+# Ensure an MCUboot-compatible binary is generated.
+CONFIG_BOOTLOADER_MCUBOOT=y
 
 # Increase the number of transmit buffers to avoid the Bluetooth stack buffer
 # leak.

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 13/42: Make MCUMGR_CMD_FS_MGMT depend on FILE_SYSTEM.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit ad113bc56f9431c276b863ef7c489837a2aed34f
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 15:45:00 2018 -0800

    Make MCUMGR_CMD_FS_MGMT depend on FILE_SYSTEM.
---
 cmd/fs_mgmt/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/cmd/fs_mgmt/Kconfig b/cmd/fs_mgmt/Kconfig
index 62602d6..03157b0 100644
--- a/cmd/fs_mgmt/Kconfig
+++ b/cmd/fs_mgmt/Kconfig
@@ -18,6 +18,7 @@
 menuconfig MCUMGR_CMD_FS_MGMT
     bool
     prompt "Enable mcumgr handlers for file management"
+    depends on FILE_SYSTEM
     default n
     help
       Enables mcumgr handlers for file management

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 33/42: Readme.md: Fix bad links in file README.md

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 80fc49927636f6c66179c553277bebe609563053
Author: Ding Tao <mi...@qq.com>
AuthorDate: Fri Feb 9 17:39:54 2018 +0800

    Readme.md: Fix bad links in file README.md
    
    Replace "mcumgr" with "mynewt-mcumgr".
    
    Signed-off-by: Ding Tao <mi...@qq.com>
---
 README.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index 4726883..cad3514 100644
--- a/README.md
+++ b/README.md
@@ -124,12 +124,12 @@ Information and documentation for mcumgr is stored within the source.
 
 For more information in the source, here are some pointers:
 
-- [cborattr](https://github.com/apache/mcumgr/tree/master/cborattr): Used for parsing incoming mcumgr requests.  Destructures mcumgr packets and populates corresponding field variables.
-- [cmd](https://github.com/apache/mcumgr/tree/master/cmd): Built-in command handlers for the core mcumgr commands.
-- [ext](https://github.com/apache/mcumgr/tree/master/ext): Third-party libraries that mcumgr depends on.
-- [mgmt](https://github.com/apache/mcumgr/tree/master/mgmt): Code implementing the `mgmt` layer of mcumgr.
-- [samples](https://github.com/apache/mcumgr/tree/master/samples): Sample applications utilizing mcumgr.
-- [smp](https://github.com/apache/mcumgr/tree/master/smp): The built-in transfer encoding: Simple management protocol.
+- [cborattr](https://github.com/apache/mynewt-mcumgr/tree/master/cborattr): Used for parsing incoming mcumgr requests.  Destructures mcumgr packets and populates corresponding field variables.
+- [cmd](https://github.com/apache/mynewt-mcumgr/tree/master/cmd): Built-in command handlers for the core mcumgr commands.
+- [ext](https://github.com/apache/mynewt-mcumgr/tree/master/ext): Third-party libraries that mcumgr depends on.
+- [mgmt](https://github.com/apache/mynewt-mcumgr/tree/master/mgmt): Code implementing the `mgmt` layer of mcumgr.
+- [samples](https://github.com/apache/mynewt-mcumgr/tree/master/samples): Sample applications utilizing mcumgr.
+- [smp](https://github.com/apache/mynewt-mcumgr/tree/master/smp): The built-in transfer encoding: Simple management protocol.
 
 ## Joining
 

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 41/42: Remove base64 library.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 785fe1a7680605755753f9cc97405d345c6ded0e
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Feb 9 13:59:49 2018 -0800

    Remove base64 library.
    
    The application code is expected to provide its own base64 library.
---
 CMakeLists.txt                           |   2 -
 ext/CMakeLists.txt                       |   1 -
 ext/base64/CMakeLists.txt                |  17 ---
 ext/base64/include/base64/base64.h       |  40 -------
 ext/base64/include/base64/hex.h          |  33 ------
 ext/base64/pkg.yml                       |  26 -----
 ext/base64/src/base64.c                  | 181 -------------------------------
 ext/base64/src/hex.c                     | 101 -----------------
 ext/base64/test/pkg.yml                  |  30 -----
 ext/base64/test/src/encoding_test.c      |  53 ---------
 ext/base64/test/src/encoding_test_priv.h |  38 -------
 ext/base64/test/src/testcases/hex2str.c  |  64 -----------
 ext/base64/test/src/testcases/str2hex.c  |  72 ------------
 samples/smp_svr/zephyr/CMakeLists.txt    |   1 +
 14 files changed, 1 insertion(+), 658 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4225f3e..b88b4ac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,6 @@ add_library(MCUMGR INTERFACE)
 zephyr_library()
 add_subdirectory(cborattr)
 add_subdirectory(cmd)
-add_subdirectory(ext)
 add_subdirectory(mgmt)
 add_subdirectory(smp)
 
@@ -11,6 +10,5 @@ zephyr_library_link_libraries(MCUMGR)
 
 target_link_libraries(MCUMGR INTERFACE
   zephyr_interface
-  BASE64
   TINYCBOR
   )
diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
deleted file mode 100644
index f453a03..0000000
--- a/ext/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_subdirectory(base64)
diff --git a/ext/base64/CMakeLists.txt b/ext/base64/CMakeLists.txt
deleted file mode 100644
index 101985e..0000000
--- a/ext/base64/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-add_library(BASE64 INTERFACE)
-
-target_include_directories(BASE64 INTERFACE src)
-
-zephyr_library()
-target_include_directories(BASE64 INTERFACE
-    include
-    port/zephyr/include
-)
-
-zephyr_library_sources(
-    src/base64.c
-    src/hex.c
-)
-
-zephyr_library_link_libraries(BASE64)
-target_link_libraries(BASE64 INTERFACE zephyr_interface)
diff --git a/ext/base64/include/base64/base64.h b/ext/base64/include/base64/base64.h
deleted file mode 100644
index 53c4853..0000000
--- a/ext/base64/include/base64/base64.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 __UTIL_BASE64_H
-#define __UTIL_BASE64_H
-
-#include <stdint.h>
-#include <string.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int base64_encode(const void *, int, char *, uint8_t);
-int base64_decode(const char *, void *buf);
-int base64_pad(char *, int);
-int base64_decode_len(const char *str);
-
-#define BASE64_ENCODE_SIZE(__size) (((((__size) - 1) / 3) * 4) + 4)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __UTIL_BASE64_H__ */
diff --git a/ext/base64/include/base64/hex.h b/ext/base64/include/base64/hex.h
deleted file mode 100644
index 8ebae77..0000000
--- a/ext/base64/include/base64/hex.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 _UTIL_HEX_H_
-#define _UTIL_HEX_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-char *hex_format(void *src_v, int src_len, char *dst, int dst_len);
-int hex_parse(const char *src, int src_len, void *dst_v, int dst_len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _UTIL_HEX_H_ */
diff --git a/ext/base64/pkg.yml b/ext/base64/pkg.yml
deleted file mode 100644
index 5ebb1b3..0000000
--- a/ext/base64/pkg.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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: ext/base64
-pkg.description: Libary for base64 encoding and decoding.
-pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
-pkg.homepage: "http://mynewt.apache.org/"
-pkg.keywords:
-    - base64
-    - hex
diff --git a/ext/base64/src/base64.c b/ext/base64/src/base64.c
deleted file mode 100644
index 0587835..0000000
--- a/ext/base64/src/base64.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * This file is based on roken from the FreeBSD source.  It has been modified
- * to not use malloc() and instead expect static buffers, and tabs have been
- * replaced with spaces.  Also, instead of strlen() on the resulting string,
- * pointer arithmitic is done, as p represents the end of the buffer.
- */
-
-/*
- * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <stdio.h>
-
-#include <base64/base64.h>
-
-static const char base64_chars[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-static int
-pos(char c)
-{
-    const char *p;
-    for (p = base64_chars; *p; p++)
-        if (*p == c)
-            return p - base64_chars;
-    return -1;
-}
-
-int
-base64_encode(const void *data, int size, char *s, uint8_t should_pad)
-{
-    char *p;
-    int i;
-    int c;
-    const unsigned char *q;
-    char *last;
-    int diff;
-
-    p = s;
-
-    q = (const unsigned char *) data;
-    last = NULL;
-    i = 0;
-    while (i < size) {
-        c = q[i++];
-        c *= 256;
-        if (i < size)
-            c += q[i];
-        i++;
-        c *= 256;
-        if (i < size)
-            c += q[i];
-        i++;
-        p[0] = base64_chars[(c & 0x00fc0000) >> 18];
-        p[1] = base64_chars[(c & 0x0003f000) >> 12];
-        p[2] = base64_chars[(c & 0x00000fc0) >> 6];
-        p[3] = base64_chars[(c & 0x0000003f) >> 0];
-        last = p;
-        p += 4;
-    }
-
-    if (last) {
-        diff = i - size;
-        if (diff > 0) {
-            if (should_pad) {
-                memset(last + (4 - diff), '=', diff);
-            } else {
-                p = last + (4 - diff);
-            }
-        }
-    }
-
-    *p = 0;
-
-    return (p - s);
-}
-
-int
-base64_pad(char *buf, int len)
-{
-    int remainder;
-
-    remainder = len % 4;
-    if (remainder == 0) {
-        return (0);
-    }
-
-    memset(buf, '=', 4 - remainder);
-
-    return (4 - remainder);
-}
-
-#define DECODE_ERROR -1
-
-static unsigned int
-token_decode(const char *token)
-{
-    int i;
-    unsigned int val = 0;
-    int marker = 0;
-    if (strlen(token) < 4)
-        return DECODE_ERROR;
-    for (i = 0; i < 4; i++) {
-        val *= 64;
-        if (token[i] == '=')
-            marker++;
-        else if (marker > 0)
-            return DECODE_ERROR;
-        else
-            val += pos(token[i]);
-    }
-    if (marker > 2)
-        return DECODE_ERROR;
-    return (marker << 24) | val;
-}
-
-int
-base64_decode(const char *str, void *data)
-{
-    const char *p;
-    unsigned char *q;
-
-    q = data;
-    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
-        unsigned int val = token_decode(p);
-        unsigned int marker = (val >> 24) & 0xff;
-        if (val == DECODE_ERROR)
-            return -1;
-        *q++ = (val >> 16) & 0xff;
-        if (marker < 2)
-            *q++ = (val >> 8) & 0xff;
-        if (marker < 1)
-            *q++ = val & 0xff;
-    }
-    return q - (unsigned char *) data;
-}
-
-
-int
-base64_decode_len(const char *str)
-{
-    int len;
-
-    len = strlen(str);
-    while (len && str[len - 1] == '=') {
-        len--;
-    }
-    return len * 3 / 4;
-}
diff --git a/ext/base64/src/hex.c b/ext/base64/src/hex.c
deleted file mode 100644
index 0ff3209..0000000
--- a/ext/base64/src/hex.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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 <inttypes.h>
-#include <ctype.h>
-#include <stddef.h>
-
-#include "base64/hex.h"
-
-static const char hex_bytes[] = "0123456789abcdef";
-
-/*
- * Turn byte array into a printable array. I.e. "\x01" -> "01"
- *
- * @param src_v		Data to convert
- * @param src_len	Number of bytes of input
- * @param dst		String where to place the results
- * @param dst_len	Size of the target string
- *
- * @return		Pointer to 'dst' if successful; NULL on failure
- */
-char *
-hex_format(void *src_v, int src_len, char *dst, int dst_len)
-{
-    int i;
-    uint8_t *src = (uint8_t *)src_v;
-    char *tgt = dst;
-
-    if (dst_len <= src_len * 2) {
-        return NULL;
-    }
-    for (i = 0; i < src_len; i++) {
-        tgt[0] = hex_bytes[(src[i] >> 4) & 0xf];
-        tgt[1] = hex_bytes[src[i] & 0xf];
-        tgt += 2;
-        dst_len -= 2;
-    }
-    *tgt = '\0';
-    return dst;
-}
-
-/*
- * Turn string of hex decimals into a byte array. I.e. "01" -> "\x01
- *
- * @param src		String to convert
- * @param src_len	Number of bytes in input string
- * @param dst_v		Memory location to place the result
- * @param dst_len	Amount of space for the result
- *
- * @return		-1 on failure; number of bytes of input
- */
-int
-hex_parse(const char *src, int src_len, void *dst_v, int dst_len)
-{
-    int i;
-    uint8_t *dst = (uint8_t *)dst_v;
-    char c;
-
-    if (src_len & 0x1) {
-        return -1;
-    }
-    if (dst_len * 2 < src_len) {
-        return -1;
-    }
-    for (i = 0; i < src_len; i++, src++) {
-        c = *src;
-        if (isdigit((int) c)) {
-            c -= '0';
-        } else if (c >= 'a' && c <= 'f') {
-            c -= ('a' - 10);
-        } else if (c >= 'A' && c <= 'F') {
-            c -= ('A' - 10);
-        } else {
-            return -1;
-        }
-        if (i & 1) {
-            *dst |= c;
-            dst++;
-            dst_len--;
-        } else {
-            *dst = c << 4;
-        }
-    }
-    return src_len >> 1;
-}
diff --git a/ext/base64/test/pkg.yml b/ext/base64/test/pkg.yml
deleted file mode 100644
index 2c85ee7..0000000
--- a/ext/base64/test/pkg.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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: ext/base64/test
-pkg.type: unittest
-pkg.description: "base64 encoding unit tests."
-pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
-pkg.homepage: "http://mynewt.apache.org/"
-pkg.keywords:
-
-pkg.deps: 
-    - "@apache-mynewt-core/test/testutil"
-    - "@apache-mynewt-core/encoding/base64"
-
-pkg.deps.SELFTEST:
-    - "@apache-mynewt-core/sys/console/stub"
diff --git a/ext/base64/test/src/encoding_test.c b/ext/base64/test/src/encoding_test.c
deleted file mode 100644
index e8af540..0000000
--- a/ext/base64/test/src/encoding_test.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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 "sysinit/sysinit.h"
-#include "syscfg/syscfg.h"
-#include "testutil/testutil.h"
-#include "encoding_test_priv.h"
-
-TEST_CASE_DECL(hex2str)
-TEST_CASE_DECL(str2hex)
-
-int
-hex_fmt_test_all(void)
-{
-    hex_fmt_test_suite();
-    return tu_case_failed;
-}
-
-TEST_SUITE(hex_fmt_test_suite)
-{
-    hex2str();
-    str2hex();
-}
-
-#if MYNEWT_VAL(SELFTEST)
-
-int
-main(int argc, char **argv)
-{
-    sysinit();
-
-    hex_fmt_test_all();
-    return tu_any_failed;
-}
-
-#endif
diff --git a/ext/base64/test/src/encoding_test_priv.h b/ext/base64/test/src/encoding_test_priv.h
deleted file mode 100644
index 2630e5c..0000000
--- a/ext/base64/test/src/encoding_test_priv.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 __ENCODING_TEST_PRIV_
-#define __ENCODING_TEST_PRIV_
-
-#include <assert.h>
-#include <stddef.h>
-#include "syscfg/syscfg.h"
-#include "base64/hex.h"
-#include "testutil/testutil.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int hex_fmt_test_suite(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/ext/base64/test/src/testcases/hex2str.c b/ext/base64/test/src/testcases/hex2str.c
deleted file mode 100644
index b1f1adc..0000000
--- a/ext/base64/test/src/testcases/hex2str.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 <string.h>
-#include "encoding_test_priv.h"
-
-TEST_CASE(hex2str)
-{
-    int i;
-    char *ret;
-    char cmp_data[8];
-
-    struct {
-        char *in;
-        int inlen;
-        char *out;
-        int outlen;
-    } test_data[] = {
-        [0] = {
-            .in = "\x01",
-            .inlen = 1,
-            .out = "01",
-            .outlen = 2,
-        },
-        [1] = {
-            .in = "\xaf\xf2",
-            .inlen = 2,
-            .out = "aff2",
-            .outlen = 4,
-        }
-    };
-
-    for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++) {
-        ret = hex_format(test_data[i].in, test_data[i].inlen,
-          cmp_data, sizeof(cmp_data));
-        TEST_ASSERT(ret == cmp_data);
-        TEST_ASSERT(strlen(cmp_data) == test_data[i].outlen);
-        TEST_ASSERT(!strcmp(test_data[i].out, cmp_data));
-    }
-
-    /*
-     * Test not enough space. Must have space for '\0' at the end.
-     */
-    ret = hex_format("\x01\x02", 2, cmp_data, 1);
-    TEST_ASSERT(ret == NULL);
-
-    ret = hex_format("\x01\x02", 2, cmp_data, 2);
-    TEST_ASSERT(ret == NULL);
-}
diff --git a/ext/base64/test/src/testcases/str2hex.c b/ext/base64/test/src/testcases/str2hex.c
deleted file mode 100644
index c17066c..0000000
--- a/ext/base64/test/src/testcases/str2hex.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 <string.h>
-#include "encoding_test_priv.h"
-
-TEST_CASE(str2hex)
-{
-    int i;
-    char cmp_data[8];
-    int rc;
-
-    struct {
-        char *in;
-        int inlen;
-        char *out;
-        int outlen;
-    } test_data[] = {
-        [0] = {
-            .in = "01",
-            .inlen = 2,
-            .out = "\x01",
-            .outlen = 1,
-        },
-        [1] = {
-            .in = "AfF2",
-            .inlen = 4,
-            .out = "\xaf\xf2",
-            .outlen = 2,
-        }
-    };
-
-    for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++) {
-        rc = hex_parse(test_data[i].in, test_data[i].inlen,
-          cmp_data, sizeof(cmp_data));
-        TEST_ASSERT(rc == test_data[i].outlen);
-        TEST_ASSERT(!memcmp(test_data[i].out, cmp_data, rc));
-    }
-
-    /*
-     * Test invalid input
-     */
-    rc = hex_parse("HJ", 2, cmp_data, sizeof(cmp_data));
-    TEST_ASSERT(rc < 0);
-
-    rc = hex_parse("a", 1, cmp_data, sizeof(cmp_data));
-    TEST_ASSERT(rc < 0);
-
-    rc = hex_parse("0102", 4, cmp_data, 1);
-    TEST_ASSERT(rc < 0);
-
-    /*
-     * This should be valid.
-     */
-    rc = hex_parse("0102", 4, cmp_data, 2);
-    TEST_ASSERT(rc == 2);
-}
diff --git a/samples/smp_svr/zephyr/CMakeLists.txt b/samples/smp_svr/zephyr/CMakeLists.txt
index 612b436..0d5a485 100644
--- a/samples/smp_svr/zephyr/CMakeLists.txt
+++ b/samples/smp_svr/zephyr/CMakeLists.txt
@@ -26,4 +26,5 @@ target_sources(app PRIVATE
 zephyr_link_libraries(
     MCUMGR
     NFFS
+    mbedTLS
 )

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 04/42: External base64 library.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 9417697c3e1c259a02edd98cf60a1c5bc38760c6
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:11:46 2018 -0800

    External base64 library.
---
 ext/base64/CMakeLists.txt                |  17 +++
 ext/base64/include/base64/base64.h       |  40 +++++++
 ext/base64/include/base64/hex.h          |  33 ++++++
 ext/base64/pkg.yml                       |  26 +++++
 ext/base64/src/base64.c                  | 181 +++++++++++++++++++++++++++++++
 ext/base64/src/hex.c                     | 101 +++++++++++++++++
 ext/base64/test/pkg.yml                  |  30 +++++
 ext/base64/test/src/encoding_test.c      |  53 +++++++++
 ext/base64/test/src/encoding_test_priv.h |  38 +++++++
 ext/base64/test/src/testcases/hex2str.c  |  64 +++++++++++
 ext/base64/test/src/testcases/str2hex.c  |  72 ++++++++++++
 11 files changed, 655 insertions(+)

diff --git a/ext/base64/CMakeLists.txt b/ext/base64/CMakeLists.txt
new file mode 100644
index 0000000..101985e
--- /dev/null
+++ b/ext/base64/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_library(BASE64 INTERFACE)
+
+target_include_directories(BASE64 INTERFACE src)
+
+zephyr_library()
+target_include_directories(BASE64 INTERFACE
+    include
+    port/zephyr/include
+)
+
+zephyr_library_sources(
+    src/base64.c
+    src/hex.c
+)
+
+zephyr_library_link_libraries(BASE64)
+target_link_libraries(BASE64 INTERFACE zephyr_interface)
diff --git a/ext/base64/include/base64/base64.h b/ext/base64/include/base64/base64.h
new file mode 100644
index 0000000..53c4853
--- /dev/null
+++ b/ext/base64/include/base64/base64.h
@@ -0,0 +1,40 @@
+/*
+ * 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 __UTIL_BASE64_H
+#define __UTIL_BASE64_H
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int base64_encode(const void *, int, char *, uint8_t);
+int base64_decode(const char *, void *buf);
+int base64_pad(char *, int);
+int base64_decode_len(const char *str);
+
+#define BASE64_ENCODE_SIZE(__size) (((((__size) - 1) / 3) * 4) + 4)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTIL_BASE64_H__ */
diff --git a/ext/base64/include/base64/hex.h b/ext/base64/include/base64/hex.h
new file mode 100644
index 0000000..8ebae77
--- /dev/null
+++ b/ext/base64/include/base64/hex.h
@@ -0,0 +1,33 @@
+/*
+ * 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 _UTIL_HEX_H_
+#define _UTIL_HEX_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char *hex_format(void *src_v, int src_len, char *dst, int dst_len);
+int hex_parse(const char *src, int src_len, void *dst_v, int dst_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_HEX_H_ */
diff --git a/ext/base64/pkg.yml b/ext/base64/pkg.yml
new file mode 100644
index 0000000..5ebb1b3
--- /dev/null
+++ b/ext/base64/pkg.yml
@@ -0,0 +1,26 @@
+#
+# 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: ext/base64
+pkg.description: Libary for base64 encoding and decoding.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - base64
+    - hex
diff --git a/ext/base64/src/base64.c b/ext/base64/src/base64.c
new file mode 100644
index 0000000..0587835
--- /dev/null
+++ b/ext/base64/src/base64.c
@@ -0,0 +1,181 @@
+/*
+ * This file is based on roken from the FreeBSD source.  It has been modified
+ * to not use malloc() and instead expect static buffers, and tabs have been
+ * replaced with spaces.  Also, instead of strlen() on the resulting string,
+ * pointer arithmitic is done, as p represents the end of the buffer.
+ */
+
+/*
+ * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdio.h>
+
+#include <base64/base64.h>
+
+static const char base64_chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int
+pos(char c)
+{
+    const char *p;
+    for (p = base64_chars; *p; p++)
+        if (*p == c)
+            return p - base64_chars;
+    return -1;
+}
+
+int
+base64_encode(const void *data, int size, char *s, uint8_t should_pad)
+{
+    char *p;
+    int i;
+    int c;
+    const unsigned char *q;
+    char *last;
+    int diff;
+
+    p = s;
+
+    q = (const unsigned char *) data;
+    last = NULL;
+    i = 0;
+    while (i < size) {
+        c = q[i++];
+        c *= 256;
+        if (i < size)
+            c += q[i];
+        i++;
+        c *= 256;
+        if (i < size)
+            c += q[i];
+        i++;
+        p[0] = base64_chars[(c & 0x00fc0000) >> 18];
+        p[1] = base64_chars[(c & 0x0003f000) >> 12];
+        p[2] = base64_chars[(c & 0x00000fc0) >> 6];
+        p[3] = base64_chars[(c & 0x0000003f) >> 0];
+        last = p;
+        p += 4;
+    }
+
+    if (last) {
+        diff = i - size;
+        if (diff > 0) {
+            if (should_pad) {
+                memset(last + (4 - diff), '=', diff);
+            } else {
+                p = last + (4 - diff);
+            }
+        }
+    }
+
+    *p = 0;
+
+    return (p - s);
+}
+
+int
+base64_pad(char *buf, int len)
+{
+    int remainder;
+
+    remainder = len % 4;
+    if (remainder == 0) {
+        return (0);
+    }
+
+    memset(buf, '=', 4 - remainder);
+
+    return (4 - remainder);
+}
+
+#define DECODE_ERROR -1
+
+static unsigned int
+token_decode(const char *token)
+{
+    int i;
+    unsigned int val = 0;
+    int marker = 0;
+    if (strlen(token) < 4)
+        return DECODE_ERROR;
+    for (i = 0; i < 4; i++) {
+        val *= 64;
+        if (token[i] == '=')
+            marker++;
+        else if (marker > 0)
+            return DECODE_ERROR;
+        else
+            val += pos(token[i]);
+    }
+    if (marker > 2)
+        return DECODE_ERROR;
+    return (marker << 24) | val;
+}
+
+int
+base64_decode(const char *str, void *data)
+{
+    const char *p;
+    unsigned char *q;
+
+    q = data;
+    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
+        unsigned int val = token_decode(p);
+        unsigned int marker = (val >> 24) & 0xff;
+        if (val == DECODE_ERROR)
+            return -1;
+        *q++ = (val >> 16) & 0xff;
+        if (marker < 2)
+            *q++ = (val >> 8) & 0xff;
+        if (marker < 1)
+            *q++ = val & 0xff;
+    }
+    return q - (unsigned char *) data;
+}
+
+
+int
+base64_decode_len(const char *str)
+{
+    int len;
+
+    len = strlen(str);
+    while (len && str[len - 1] == '=') {
+        len--;
+    }
+    return len * 3 / 4;
+}
diff --git a/ext/base64/src/hex.c b/ext/base64/src/hex.c
new file mode 100644
index 0000000..0ff3209
--- /dev/null
+++ b/ext/base64/src/hex.c
@@ -0,0 +1,101 @@
+/*
+ * 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 <inttypes.h>
+#include <ctype.h>
+#include <stddef.h>
+
+#include "base64/hex.h"
+
+static const char hex_bytes[] = "0123456789abcdef";
+
+/*
+ * Turn byte array into a printable array. I.e. "\x01" -> "01"
+ *
+ * @param src_v		Data to convert
+ * @param src_len	Number of bytes of input
+ * @param dst		String where to place the results
+ * @param dst_len	Size of the target string
+ *
+ * @return		Pointer to 'dst' if successful; NULL on failure
+ */
+char *
+hex_format(void *src_v, int src_len, char *dst, int dst_len)
+{
+    int i;
+    uint8_t *src = (uint8_t *)src_v;
+    char *tgt = dst;
+
+    if (dst_len <= src_len * 2) {
+        return NULL;
+    }
+    for (i = 0; i < src_len; i++) {
+        tgt[0] = hex_bytes[(src[i] >> 4) & 0xf];
+        tgt[1] = hex_bytes[src[i] & 0xf];
+        tgt += 2;
+        dst_len -= 2;
+    }
+    *tgt = '\0';
+    return dst;
+}
+
+/*
+ * Turn string of hex decimals into a byte array. I.e. "01" -> "\x01
+ *
+ * @param src		String to convert
+ * @param src_len	Number of bytes in input string
+ * @param dst_v		Memory location to place the result
+ * @param dst_len	Amount of space for the result
+ *
+ * @return		-1 on failure; number of bytes of input
+ */
+int
+hex_parse(const char *src, int src_len, void *dst_v, int dst_len)
+{
+    int i;
+    uint8_t *dst = (uint8_t *)dst_v;
+    char c;
+
+    if (src_len & 0x1) {
+        return -1;
+    }
+    if (dst_len * 2 < src_len) {
+        return -1;
+    }
+    for (i = 0; i < src_len; i++, src++) {
+        c = *src;
+        if (isdigit((int) c)) {
+            c -= '0';
+        } else if (c >= 'a' && c <= 'f') {
+            c -= ('a' - 10);
+        } else if (c >= 'A' && c <= 'F') {
+            c -= ('A' - 10);
+        } else {
+            return -1;
+        }
+        if (i & 1) {
+            *dst |= c;
+            dst++;
+            dst_len--;
+        } else {
+            *dst = c << 4;
+        }
+    }
+    return src_len >> 1;
+}
diff --git a/ext/base64/test/pkg.yml b/ext/base64/test/pkg.yml
new file mode 100644
index 0000000..2c85ee7
--- /dev/null
+++ b/ext/base64/test/pkg.yml
@@ -0,0 +1,30 @@
+# 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: ext/base64/test
+pkg.type: unittest
+pkg.description: "base64 encoding unit tests."
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps: 
+    - "@apache-mynewt-core/test/testutil"
+    - "@apache-mynewt-core/encoding/base64"
+
+pkg.deps.SELFTEST:
+    - "@apache-mynewt-core/sys/console/stub"
diff --git a/ext/base64/test/src/encoding_test.c b/ext/base64/test/src/encoding_test.c
new file mode 100644
index 0000000..e8af540
--- /dev/null
+++ b/ext/base64/test/src/encoding_test.c
@@ -0,0 +1,53 @@
+/*
+ * 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 "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "testutil/testutil.h"
+#include "encoding_test_priv.h"
+
+TEST_CASE_DECL(hex2str)
+TEST_CASE_DECL(str2hex)
+
+int
+hex_fmt_test_all(void)
+{
+    hex_fmt_test_suite();
+    return tu_case_failed;
+}
+
+TEST_SUITE(hex_fmt_test_suite)
+{
+    hex2str();
+    str2hex();
+}
+
+#if MYNEWT_VAL(SELFTEST)
+
+int
+main(int argc, char **argv)
+{
+    sysinit();
+
+    hex_fmt_test_all();
+    return tu_any_failed;
+}
+
+#endif
diff --git a/ext/base64/test/src/encoding_test_priv.h b/ext/base64/test/src/encoding_test_priv.h
new file mode 100644
index 0000000..2630e5c
--- /dev/null
+++ b/ext/base64/test/src/encoding_test_priv.h
@@ -0,0 +1,38 @@
+/*
+ * 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 __ENCODING_TEST_PRIV_
+#define __ENCODING_TEST_PRIV_
+
+#include <assert.h>
+#include <stddef.h>
+#include "syscfg/syscfg.h"
+#include "base64/hex.h"
+#include "testutil/testutil.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int hex_fmt_test_suite(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ext/base64/test/src/testcases/hex2str.c b/ext/base64/test/src/testcases/hex2str.c
new file mode 100644
index 0000000..b1f1adc
--- /dev/null
+++ b/ext/base64/test/src/testcases/hex2str.c
@@ -0,0 +1,64 @@
+/*
+ * 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 <string.h>
+#include "encoding_test_priv.h"
+
+TEST_CASE(hex2str)
+{
+    int i;
+    char *ret;
+    char cmp_data[8];
+
+    struct {
+        char *in;
+        int inlen;
+        char *out;
+        int outlen;
+    } test_data[] = {
+        [0] = {
+            .in = "\x01",
+            .inlen = 1,
+            .out = "01",
+            .outlen = 2,
+        },
+        [1] = {
+            .in = "\xaf\xf2",
+            .inlen = 2,
+            .out = "aff2",
+            .outlen = 4,
+        }
+    };
+
+    for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++) {
+        ret = hex_format(test_data[i].in, test_data[i].inlen,
+          cmp_data, sizeof(cmp_data));
+        TEST_ASSERT(ret == cmp_data);
+        TEST_ASSERT(strlen(cmp_data) == test_data[i].outlen);
+        TEST_ASSERT(!strcmp(test_data[i].out, cmp_data));
+    }
+
+    /*
+     * Test not enough space. Must have space for '\0' at the end.
+     */
+    ret = hex_format("\x01\x02", 2, cmp_data, 1);
+    TEST_ASSERT(ret == NULL);
+
+    ret = hex_format("\x01\x02", 2, cmp_data, 2);
+    TEST_ASSERT(ret == NULL);
+}
diff --git a/ext/base64/test/src/testcases/str2hex.c b/ext/base64/test/src/testcases/str2hex.c
new file mode 100644
index 0000000..c17066c
--- /dev/null
+++ b/ext/base64/test/src/testcases/str2hex.c
@@ -0,0 +1,72 @@
+/*
+ * 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 <string.h>
+#include "encoding_test_priv.h"
+
+TEST_CASE(str2hex)
+{
+    int i;
+    char cmp_data[8];
+    int rc;
+
+    struct {
+        char *in;
+        int inlen;
+        char *out;
+        int outlen;
+    } test_data[] = {
+        [0] = {
+            .in = "01",
+            .inlen = 2,
+            .out = "\x01",
+            .outlen = 1,
+        },
+        [1] = {
+            .in = "AfF2",
+            .inlen = 4,
+            .out = "\xaf\xf2",
+            .outlen = 2,
+        }
+    };
+
+    for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++) {
+        rc = hex_parse(test_data[i].in, test_data[i].inlen,
+          cmp_data, sizeof(cmp_data));
+        TEST_ASSERT(rc == test_data[i].outlen);
+        TEST_ASSERT(!memcmp(test_data[i].out, cmp_data, rc));
+    }
+
+    /*
+     * Test invalid input
+     */
+    rc = hex_parse("HJ", 2, cmp_data, sizeof(cmp_data));
+    TEST_ASSERT(rc < 0);
+
+    rc = hex_parse("a", 1, cmp_data, sizeof(cmp_data));
+    TEST_ASSERT(rc < 0);
+
+    rc = hex_parse("0102", 4, cmp_data, 1);
+    TEST_ASSERT(rc < 0);
+
+    /*
+     * This should be valid.
+     */
+    rc = hex_parse("0102", 4, cmp_data, 2);
+    TEST_ASSERT(rc == 2);
+}

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 07/42: cborattr library

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 1636f65725542693ed1d2941b58c6d6485ff055b
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:13:14 2018 -0800

    cborattr library
    
    This is used for parsing incoming mcumgr requests.  Destructures mcumgr
    packets and populates corresponding field variables.
    
    This comes from Apache Mynewt.
---
 cborattr/CMakeLists.txt                            |   7 +
 cborattr/include/cborattr/cborattr.h               | 153 ++++++++
 cborattr/pkg.yml                                   |  29 ++
 cborattr/src/cborattr.c                            | 423 +++++++++++++++++++++
 cborattr/syscfg.yml                                |  24 ++
 cborattr/test/pkg.yml                              |  30 ++
 cborattr/test/src/test_cborattr.c                  |  49 +++
 cborattr/test/src/test_cborattr.h                  |  57 +++
 cborattr/test/src/test_cborattr_utils.c            |  35 ++
 cborattr/test/src/testcases/cborattr_decode1.c     |  83 ++++
 .../src/testcases/cborattr_decode_bool_array.c     | 101 +++++
 .../test/src/testcases/cborattr_decode_int_array.c | 143 +++++++
 .../test/src/testcases/cborattr_decode_obj_array.c | 109 ++++++
 .../test/src/testcases/cborattr_decode_object.c    | 198 ++++++++++
 .../src/testcases/cborattr_decode_object_array.c   | 126 ++++++
 .../test/src/testcases/cborattr_decode_partial.c   |  47 +++
 .../test/src/testcases/cborattr_decode_simple.c    | 123 ++++++
 .../src/testcases/cborattr_decode_string_array.c   | 135 +++++++
 .../src/testcases/cborattr_decode_substring_key.c  | 111 ++++++
 .../src/testcases/cborattr_decode_unnamed_array.c  |  99 +++++
 20 files changed, 2082 insertions(+)

diff --git a/cborattr/CMakeLists.txt b/cborattr/CMakeLists.txt
new file mode 100644
index 0000000..2f22bd0
--- /dev/null
+++ b/cborattr/CMakeLists.txt
@@ -0,0 +1,7 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    cborattr/src/cborattr.c
+)
diff --git a/cborattr/include/cborattr/cborattr.h b/cborattr/include/cborattr/cborattr.h
new file mode 100644
index 0000000..1cc14b3
--- /dev/null
+++ b/cborattr/include/cborattr/cborattr.h
@@ -0,0 +1,153 @@
+/*
+ * 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 CBORATTR_H
+#define CBORATTR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include "cbor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This library wraps the tinycbor decoder with a attribute based decoder
+ * suitable for decoding a binary version of json.  Specifically, the
+ * contents of the cbor contains pairs of attributes.  where the attribute
+ * is a key/value pair.  keys are always text strings, but values can be
+ * many different things (enumerated below) */
+
+typedef enum CborAttrType {
+    CborAttrIntegerType = 1,
+    CborAttrUnsignedIntegerType,
+    CborAttrByteStringType,
+    CborAttrTextStringType,
+    CborAttrBooleanType,
+    CborAttrFloatType,
+    CborAttrDoubleType,
+    CborAttrArrayType,
+    CborAttrObjectType,
+    CborAttrStructObjectType,
+    CborAttrNullType,
+} CborAttrType;
+
+struct cbor_attr_t;
+
+struct cbor_enum_t {
+    char *name;
+    long long int value;
+};
+
+struct cbor_array_t {
+    CborAttrType element_type;
+    union {
+        struct {
+            const struct cbor_attr_t *subtype;
+            char *base;
+            size_t stride;
+        } objects;
+        struct {
+            char **ptrs;
+            char *store;
+            int storelen;
+        } strings;
+        struct {
+            long long int *store;
+        } integers;
+        struct {
+            long long unsigned int *store;
+        } uintegers;
+        struct {
+            double *store;
+        } reals;
+        struct {
+            bool *store;
+        } booleans;
+    } arr;
+    int *count;
+    int maxlen;
+};
+
+struct cbor_attr_t {
+    char *attribute;
+    CborAttrType type;
+    union {
+        long long int *integer;
+        long long unsigned int *uinteger;
+        double *real;
+        float *fval;
+        char *string;
+        bool *boolean;
+        struct byte_string {
+            uint8_t *data;
+            size_t *len;
+        } bytestring;
+        struct cbor_array_t array;
+        size_t offset;
+        struct cbor_attr_t *obj;
+    } addr;
+    union {
+        long long int integer;
+        double real;
+        bool boolean;
+        float fval;
+    } dflt;
+    size_t len;
+    bool nodefault;
+};
+
+/*
+ * Use the following macros to declare template initializers for
+ * CborAttrStructObjectType arrays. Writing the equivalents out by hand is
+ * error-prone.
+ *
+ * CBOR_STRUCT_OBJECT takes a structure name s, and a fieldname f in s.
+ *
+ * CBOR_STRUCT_ARRAY takes the name of a structure array, a pointer to a an
+ * initializer defining the subobject type, and the address of an integer to
+ * store the length in.
+ */
+#define CBORATTR_STRUCT_OBJECT(s, f)        .addr.offset = offsetof(s, f)
+#define CBORATTR_STRUCT_ARRAY(a, e, n)                                  \
+    .addr.array.element_type = CborAttrStructObjectType,                \
+    .addr.array.arr.objects.subtype = e,                                \
+    .addr.array.arr.objects.base = (char*)a,                            \
+    .addr.array.arr.objects.stride = sizeof(a[0]),                      \
+    .addr.array.count = n,                                              \
+    .addr.array.maxlen = (int)(sizeof(a)/sizeof(a[0]))
+
+#define CBORATTR_ATTR_UNNAMED (char *)(-1)
+
+int cbor_read_object(struct CborValue *, const struct cbor_attr_t *);
+int cbor_read_array(struct CborValue *, const struct cbor_array_t *);
+
+int cbor_read_flat_attrs(const uint8_t *data, int len,
+                         const struct cbor_attr_t *attrs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBORATTR_H */
+
diff --git a/cborattr/pkg.yml b/cborattr/pkg.yml
new file mode 100644
index 0000000..8495f95
--- /dev/null
+++ b/cborattr/pkg.yml
@@ -0,0 +1,29 @@
+#
+# 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: cborattr 
+pkg.description: CBOR encoding/decoding library 
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - "encoding/tinycbor"
+
+pkg.cflags.FLOAT_USER: -DFLOAT_SUPPORT
diff --git a/cborattr/src/cborattr.c b/cborattr/src/cborattr.c
new file mode 100644
index 0000000..46cdc23
--- /dev/null
+++ b/cborattr/src/cborattr.c
@@ -0,0 +1,423 @@
+/*
+ * 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 <syscfg/syscfg.h>
+#include "cborattr/cborattr.h"
+#include "cbor.h"
+#include "cbor_buf_reader.h"
+
+#define CBORATTR_MAX_SIZE 512
+
+/* this maps a CborType to a matching CborAtter Type. The mapping is not
+ * one-to-one because of signedness of integers
+ * and therefore we need a function to do this trickery */
+static int
+valid_attr_type(CborType ct, CborAttrType at)
+{
+    switch (at) {
+    case CborAttrIntegerType:
+    case CborAttrUnsignedIntegerType:
+        if (ct == CborIntegerType) {
+            return 1;
+        }
+        break;
+    case CborAttrByteStringType:
+        if (ct == CborByteStringType) {
+            return 1;
+        }
+        break;
+    case CborAttrTextStringType:
+        if (ct == CborTextStringType) {
+            return 1;
+        }
+        break;
+    case CborAttrBooleanType:
+        if (ct == CborBooleanType) {
+            return 1;
+        }
+#if FLOAT_SUPPORT
+    case CborAttrFloatType:
+        if (ct == CborFloatType) {
+            return 1;
+        }
+        break;
+    case CborAttrDoubleType:
+        if (ct == CborDoubleType) {
+            return 1;
+        }
+        break;
+#endif
+    case CborAttrArrayType:
+        if (ct == CborArrayType) {
+            return 1;
+        }
+        break;
+    case CborAttrObjectType:
+        if (ct == CborMapType) {
+            return 1;
+        }
+        break;
+    case CborAttrNullType:
+        if (ct == CborNullType) {
+            return 1;
+        }
+        break;
+    default:
+        break;
+    }
+    return 0;
+}
+
+/* this function find the pointer to the memory location to
+  * write or read and attribute from the cbor_attr_r structure */
+static char *
+cbor_target_address(const struct cbor_attr_t *cursor,
+                    const struct cbor_array_t *parent, int offset)
+{
+    char *targetaddr = NULL;
+
+    if (parent == NULL || parent->element_type != CborAttrStructObjectType) {
+        /* ordinary case - use the address in the cursor structure */
+        switch (cursor->type) {
+        case CborAttrNullType:
+            targetaddr = NULL;
+            break;
+        case CborAttrIntegerType:
+            targetaddr = (char *)&cursor->addr.integer[offset];
+            break;
+        case CborAttrUnsignedIntegerType:
+            targetaddr = (char *)&cursor->addr.uinteger[offset];
+            break;
+#if FLOAT_SUPPORT
+        case CborAttrFloatType:
+            targetaddr = (char *)&cursor->addr.fval[offset];
+            break;
+        case CborAttrDoubleType:
+            targetaddr = (char *)&cursor->addr.real[offset];
+            break;
+#endif
+        case CborAttrByteStringType:
+            targetaddr = (char *) cursor->addr.bytestring.data;
+            break;
+        case CborAttrTextStringType:
+            targetaddr = cursor->addr.string;
+            break;
+        case CborAttrBooleanType:
+            targetaddr = (char *)&cursor->addr.boolean[offset];
+            break;
+        default:
+            targetaddr = NULL;
+            break;
+        }
+    } else {
+        /* tricky case - hacking a member in an array of structures */
+        targetaddr =
+            parent->arr.objects.base + (offset * parent->arr.objects.stride) +
+            cursor->addr.offset;
+    }
+    return targetaddr;
+}
+
+static int
+cbor_internal_read_object(CborValue *root_value,
+                          const struct cbor_attr_t *attrs,
+                          const struct cbor_array_t *parent,
+                          int offset)
+{
+    const struct cbor_attr_t *cursor, *best_match;
+    char attrbuf[CBORATTR_MAX_SIZE + 1];
+    void *lptr;
+    CborValue cur_value;
+    CborError err = 0;
+    size_t len;
+    CborType type = CborInvalidType;
+
+    /* stuff fields with defaults in case they're omitted in the JSON input */
+    for (cursor = attrs; cursor->attribute != NULL; cursor++) {
+        if (!cursor->nodefault) {
+            lptr = cbor_target_address(cursor, parent, offset);
+            if (lptr != NULL) {
+                switch (cursor->type) {
+                case CborAttrIntegerType:
+                    memcpy(lptr, &cursor->dflt.integer, sizeof(long long int));
+                    break;
+                case CborAttrUnsignedIntegerType:
+                    memcpy(lptr, &cursor->dflt.integer,
+                           sizeof(long long unsigned int));
+                    break;
+                case CborAttrBooleanType:
+                    memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
+                    break;
+#if FLOAT_SUPPORT
+                case CborAttrFloatType:
+                    memcpy(lptr, &cursor->dflt.fval, sizeof(float));
+                    break;
+                case CborAttrDoubleType:
+                    memcpy(lptr, &cursor->dflt.real, sizeof(double));
+                    break;
+#endif
+                default:
+                    break;
+                }
+            }
+        }
+    }
+
+    if (cbor_value_is_map(root_value)) {
+        err |= cbor_value_enter_container(root_value, &cur_value);
+    } else {
+        err |= CborErrorIllegalType;
+        return err;
+    }
+
+    /* contains key value pairs */
+    while (cbor_value_is_valid(&cur_value) && !err) {
+        /* get the attribute */
+        if (cbor_value_is_text_string(&cur_value)) {
+            if (cbor_value_calculate_string_length(&cur_value, &len) == 0) {
+                if (len > CBORATTR_MAX_SIZE) {
+                    err |= CborErrorDataTooLarge;
+                    break;
+                }
+                err |= cbor_value_copy_text_string(&cur_value, attrbuf, &len,
+                                                     NULL);
+            }
+
+            /* at least get the type of the next value so we can match the
+             * attribute name and type for a perfect match */
+            err |= cbor_value_advance(&cur_value);
+            if (cbor_value_is_valid(&cur_value)) {
+                type = cbor_value_get_type(&cur_value);
+            } else {
+                err |= CborErrorIllegalType;
+                break;
+            }
+        } else {
+            attrbuf[0] = '\0';
+            type = cbor_value_get_type(&cur_value);
+        }
+
+        /* find this attribute in our list */
+        best_match = NULL;
+        for (cursor = attrs; cursor->attribute != NULL; cursor++) {
+            if (valid_attr_type(type, cursor->type)) {
+                if (cursor->attribute == CBORATTR_ATTR_UNNAMED &&
+                    attrbuf[0] == '\0') {
+                    best_match = cursor;
+                } else if (strlen(cursor->attribute) == len &&
+                    !memcmp(cursor->attribute, attrbuf, len)) {
+                    break;
+                }
+            }
+        }
+        if (!cursor->attribute && best_match) {
+            cursor = best_match;
+        }
+        /* we found a match */
+        if (cursor->attribute != NULL) {
+            lptr = cbor_target_address(cursor, parent, offset);
+            switch (cursor->type) {
+            case CborAttrNullType:
+                /* nothing to do */
+                break;
+            case CborAttrBooleanType:
+                err |= cbor_value_get_boolean(&cur_value, lptr);
+                break;
+            case CborAttrIntegerType:
+                err |= cbor_value_get_int64(&cur_value, lptr);
+                break;
+            case CborAttrUnsignedIntegerType:
+                err |= cbor_value_get_uint64(&cur_value, lptr);
+                break;
+#if FLOAT_SUPPORT
+            case CborAttrFloatType:
+                err |= cbor_value_get_float(&cur_value, lptr);
+                break;
+            case CborAttrDoubleType:
+                err |= cbor_value_get_double(&cur_value, lptr);
+                break;
+#endif
+            case CborAttrByteStringType: {
+                size_t len = cursor->len;
+                err |= cbor_value_copy_byte_string(&cur_value, lptr,
+                                                   &len, NULL);
+                *cursor->addr.bytestring.len = len;
+                break;
+            }
+            case CborAttrTextStringType: {
+                size_t len = cursor->len;
+                err |= cbor_value_copy_text_string(&cur_value, lptr,
+                                                   &len, NULL);
+                break;
+            }
+            case CborAttrArrayType:
+                err |= cbor_read_array(&cur_value, &cursor->addr.array);
+                continue;
+            case CborAttrObjectType:
+                err |= cbor_internal_read_object(&cur_value, cursor->addr.obj,
+                                                 NULL, 0);
+                continue;
+            default:
+                err |= CborErrorIllegalType;
+            }
+        }
+        cbor_value_advance(&cur_value);
+    }
+    if (!err) {
+        /* that should be it for this container */
+        err |= cbor_value_leave_container(root_value, &cur_value);
+    }
+    return err;
+}
+
+int
+cbor_read_array(struct CborValue *value, const struct cbor_array_t *arr)
+{
+    CborError err = 0;
+    struct CborValue elem;
+    int off, arrcount;
+    size_t len;
+    void *lptr;
+    char *tp;
+
+    err = cbor_value_enter_container(value, &elem);
+    if (err) {
+        return err;
+    }
+    arrcount = 0;
+    tp = arr->arr.strings.store;
+    for (off = 0; off < arr->maxlen; off++) {
+        switch (arr->element_type) {
+        case CborAttrBooleanType:
+            lptr = &arr->arr.booleans.store[off];
+            err |= cbor_value_get_boolean(&elem, lptr);
+            break;
+        case CborAttrIntegerType:
+            lptr = &arr->arr.integers.store[off];
+            err |= cbor_value_get_int64(&elem, lptr);
+            break;
+        case CborAttrUnsignedIntegerType:
+            lptr = &arr->arr.uintegers.store[off];
+            err |= cbor_value_get_uint64(&elem, lptr);
+            break;
+#if FLOAT_SUPPORT
+        case CborAttrFloatType:
+        case CborAttrDoubleType:
+            lptr = &arr->arr.reals.store[off];
+            err |= cbor_value_get_double(&elem, lptr);
+            break;
+#endif
+        case CborAttrTextStringType:
+            len = arr->arr.strings.storelen - (tp - arr->arr.strings.store);
+            err |= cbor_value_copy_text_string(&elem, tp, &len, NULL);
+            arr->arr.strings.ptrs[off] = tp;
+            tp += len + 1;
+            break;
+        case CborAttrStructObjectType:
+            err |= cbor_internal_read_object(&elem, arr->arr.objects.subtype,
+                                             arr, off);
+            break;
+        default:
+            err |= CborErrorIllegalType;
+            break;
+        }
+        arrcount++;
+        if (arr->element_type != CborAttrStructObjectType) {
+            err |= cbor_value_advance(&elem);
+        }
+        if (!cbor_value_is_valid(&elem)) {
+            break;
+        }
+    }
+    if (arr->count) {
+        *arr->count = arrcount;
+    }
+    while (!cbor_value_at_end(&elem)) {
+        err |= CborErrorDataTooLarge;
+        cbor_value_advance(&elem);
+    }
+    err |= cbor_value_leave_container(value, &elem);
+    return err;
+}
+
+int
+cbor_read_object(struct CborValue *value, const struct cbor_attr_t *attrs)
+{
+    int st;
+
+    st = cbor_internal_read_object(value, attrs, NULL, 0);
+    return st;
+}
+
+/*
+ * Read in cbor key/values from flat buffer pointed by data, and fill them
+ * into attrs.
+ *
+ * @param data		Pointer to beginning of cbor encoded data
+ * @param len		Number of bytes in the buffer
+ * @param attrs		Array of cbor objects to look for.
+ *
+ * @return		0 on success; non-zero on failure.
+ */
+int
+cbor_read_flat_attrs(const uint8_t *data, int len,
+                     const struct cbor_attr_t *attrs)
+{
+    struct cbor_buf_reader reader;
+    struct CborParser parser;
+    struct CborValue value;
+    CborError err;
+
+    cbor_buf_reader_init(&reader, data, len);
+    err = cbor_parser_cust_reader_init(&reader.r, 0, &parser, &value);
+    if (err != CborNoError) {
+        return -1;
+    }
+    return cbor_read_object(&value, attrs);
+}
+
+#if 0
+/*
+ * Read in cbor key/values from os_mbuf pointed by m, and fill them
+ * into attrs.
+ *
+ * @param m		Pointer to os_mbuf containing cbor encoded data
+ * @param off		Offset into mbuf where cbor data begins
+ * @param len		Number of bytes to decode
+ * @param attrs		Array of cbor objects to look for.
+ *
+ * @return		0 on success; non-zero on failure.
+ */
+int
+cbor_read_mbuf_attrs(struct os_mbuf *m, uint16_t off, uint16_t len,
+                     const struct cbor_attr_t *attrs)
+{
+    struct cbor_mbuf_reader cmr;
+    struct CborParser parser;
+    struct CborValue value;
+    CborError err;
+
+    cbor_mbuf_reader_init(&cmr, m, off);
+    err = cbor_parser_init(&cmr.r, 0, &parser, &value);
+    if (err != CborNoError) {
+        return -1;
+    }
+    return cbor_read_object(&value, attrs);
+}
+#endif
diff --git a/cborattr/syscfg.yml b/cborattr/syscfg.yml
new file mode 100644
index 0000000..cc93c26
--- /dev/null
+++ b/cborattr/syscfg.yml
@@ -0,0 +1,24 @@
+# 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.
+#
+
+# Package: mgmt/imgmgr
+
+syscfg.defs:
+    CBORATTR_MAX_SIZE:
+        description: 'The maximum size of a CBOR attribute during decoding'
+        value: 512
diff --git a/cborattr/test/pkg.yml b/cborattr/test/pkg.yml
new file mode 100644
index 0000000..071ca5f
--- /dev/null
+++ b/cborattr/test/pkg.yml
@@ -0,0 +1,30 @@
+# 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: cborattr/test
+pkg.type: unittest
+pkg.description: "CBOR attr unit tests."
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - '@mynewt-mcumgr/ext/tinycbor'
+    - '@mynewt-mcumgr/cborattr'
+
+pkg.deps.SELFTEST:
+    - sys/console/stub
diff --git a/cborattr/test/src/test_cborattr.c b/cborattr/test/src/test_cborattr.c
new file mode 100644
index 0000000..0a64039
--- /dev/null
+++ b/cborattr/test/src/test_cborattr.c
@@ -0,0 +1,49 @@
+/*
+ * 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 "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "testutil/testutil.h"
+#include "test_cborattr.h"
+
+TEST_SUITE(test_cborattr_suite)
+{
+    test_cborattr_decode1();
+    test_cborattr_decode_partial();
+    test_cborattr_decode_simple();
+    test_cborattr_decode_object();
+    test_cborattr_decode_int_array();
+    test_cborattr_decode_bool_array();
+    test_cborattr_decode_string_array();
+    test_cborattr_decode_object_array();
+    test_cborattr_decode_unnamed_array();
+    test_cborattr_decode_substring_key();
+}
+
+#if MYNEWT_VAL(SELFTEST)
+int
+main(int argc, char **argv)
+{
+    sysinit();
+
+    test_cborattr_suite();
+
+    return tu_any_failed;
+}
+#endif
diff --git a/cborattr/test/src/test_cborattr.h b/cborattr/test/src/test_cborattr.h
new file mode 100644
index 0000000..815048f
--- /dev/null
+++ b/cborattr/test/src/test_cborattr.h
@@ -0,0 +1,57 @@
+/*
+ * 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 TEST_CBORATTR_H
+#define TEST_CBORATTR_H
+
+#include <assert.h>
+#include <string.h>
+#include "testutil/testutil.h"
+#include "test_cborattr.h"
+#include "tinycbor/cbor.h"
+#include "cborattr/cborattr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Returns test data.
+ */
+const uint8_t *test_str1(int *len);
+
+/*
+ * Testcases
+ */
+TEST_CASE_DECL(test_cborattr_decode1);
+TEST_CASE_DECL(test_cborattr_decode_partial);
+TEST_CASE_DECL(test_cborattr_decode_simple);
+TEST_CASE_DECL(test_cborattr_decode_object);
+TEST_CASE_DECL(test_cborattr_decode_int_array);
+TEST_CASE_DECL(test_cborattr_decode_bool_array);
+TEST_CASE_DECL(test_cborattr_decode_string_array);
+TEST_CASE_DECL(test_cborattr_decode_object_array);
+TEST_CASE_DECL(test_cborattr_decode_unnamed_array);
+TEST_CASE_DECL(test_cborattr_decode_substring_key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_CBORATTR_H */
+
diff --git a/cborattr/test/src/test_cborattr_utils.c b/cborattr/test/src/test_cborattr_utils.c
new file mode 100644
index 0000000..0a43766
--- /dev/null
+++ b/cborattr/test/src/test_cborattr_utils.c
@@ -0,0 +1,35 @@
+/*
+ * 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 "test_cborattr.h"
+/*
+ * {"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
+ */
+static const uint8_t test_data1[] = {
+    0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61,
+    0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61,
+    0x44, 0x61, 0x65, 0x61, 0x45
+};
+
+const uint8_t *
+test_str1(int *len)
+{
+    *len = sizeof(test_data1);
+    return (test_data1);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode1.c b/cborattr/test/src/testcases/cborattr_decode1.c
new file mode 100644
index 0000000..1b6cddf
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode1.c
@@ -0,0 +1,83 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode1)
+{
+    const uint8_t *data;
+    int len;
+    int rc;
+    char test_str_a[4] = { '\0' };
+    char test_str_b[4] = { '\0' };
+    char test_str_c[4] = { '\0' };
+    char test_str_d[4] = { '\0' };
+    char test_str_e[4] = { '\0' };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_a,
+            .len = sizeof(test_str_a),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_b,
+            .len = sizeof(test_str_b),
+            .nodefault = true
+            },
+        [2] = {
+            .attribute = "c",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_c,
+            .len = sizeof(test_str_c),
+            .nodefault = true
+            },
+        [3] = {
+            .attribute = "d",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_d,
+            .len = sizeof(test_str_d),
+            .nodefault = true,
+            },
+        [4] = {
+            .attribute = "e",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_e,
+            .len = sizeof(test_str_e),
+            .nodefault = true,
+        },
+        [5] = {
+            .attribute = NULL
+        }
+    };
+
+    data = test_str1(&len);
+    rc = cbor_read_flat_attrs(data, len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!strcmp(test_str_a, "A"));
+    TEST_ASSERT(!strcmp(test_str_b, "B"));
+    TEST_ASSERT(!strcmp(test_str_c, "C"));
+    TEST_ASSERT(!strcmp(test_str_d, "D"));
+    TEST_ASSERT(!strcmp(test_str_e, "E"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_bool_array.c b/cborattr/test/src/testcases/cborattr_decode_bool_array.c
new file mode 100644
index 0000000..71520c4
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_bool_array.c
@@ -0,0 +1,101 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_bool_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [true,true,false]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_boolean(&array, true);
+    cbor_encode_boolean(&array, true);
+    cbor_encode_boolean(&array, false);
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * array of booleans
+ */
+TEST_CASE(test_cborattr_decode_bool_array)
+{
+    int rc;
+    bool arr_data[5];
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrBooleanType,
+            .addr.array.arr.booleans.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_bool_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(arr_data[0] == true);
+    TEST_ASSERT(arr_data[1] == true);
+    TEST_ASSERT(arr_data[2] == false);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_int_array.c b/cborattr/test/src/testcases/cborattr_decode_int_array.c
new file mode 100644
index 0000000..96bc8cc
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_int_array.c
@@ -0,0 +1,143 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_int_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [1,2,33,15,-4]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_int(&array, 1);
+    cbor_encode_int(&array, 2);
+    cbor_encode_int(&array, 33);
+    cbor_encode_int(&array, 15);
+    cbor_encode_int(&array, -4);
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * integer array
+ */
+TEST_CASE(test_cborattr_decode_int_array)
+{
+    int rc;
+    int64_t arr_data[5];
+    int64_t b_int;
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrIntegerType,
+            .addr.array.arr.integers.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrIntegerType,
+            .addr.integer = &b_int,
+            .dflt.integer = 1
+        },
+        [2] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attrs_small[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrIntegerType,
+            .addr.array.arr.integers.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = 1,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrIntegerType,
+            .addr.integer = &b_int,
+            .dflt.integer = 1
+        },
+        [2] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_int_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 5);
+    TEST_ASSERT(arr_data[0] == 1);
+    TEST_ASSERT(arr_data[1] == 2);
+    TEST_ASSERT(arr_data[2] == 33);
+    TEST_ASSERT(arr_data[3] == 15);
+    TEST_ASSERT(arr_data[4] == -4);
+    TEST_ASSERT(b_int == 1);
+
+    memset(arr_data, 0, sizeof(arr_data));
+    b_int = 0;
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs_small);
+    TEST_ASSERT(rc == CborErrorDataTooLarge);
+    TEST_ASSERT(arr_cnt == 1);
+    TEST_ASSERT(arr_data[0] == 1);
+    TEST_ASSERT(arr_data[1] == 0);
+    TEST_ASSERT(b_int == 1);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_obj_array.c b/cborattr/test/src/testcases/cborattr_decode_obj_array.c
new file mode 100644
index 0000000..57c46cd
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_obj_array.c
@@ -0,0 +1,109 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_obj_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+    CborEncoder obj;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [{ n:"a", v:1}, {n:"b", v:2} ]
+     */
+    cbor_encode_text_stringz(&data, "a");
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+
+    cbor_encoder_create_map(&array, &obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&obj, "n");
+    cbor_encode_text_stringz(&obj, "a");
+    cbor_encode_text_stringz(&obj, "v");
+    cbor_encode_int(&obj, 1);
+    cbor_encoder_close_container(&array, &obj);
+
+    cbor_encoder_create_map(&array, &obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&obj, "n");
+    cbor_encode_text_stringz(&obj, "b");
+    cbor_encode_text_stringz(&obj, "v");
+    cbor_encode_int(&obj, 2);
+    cbor_encoder_close_container(&array, &obj);
+
+    cbor_encoder_close_container(&data, &array);
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * object array
+ */
+TEST_CASE(test_cborattr_decode_obj_array)
+{
+    int rc;
+    char arr_data[4];
+    int arr_cnt;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrNullType,
+            .addr.array.arr.objects.base = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = 4,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_obj_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 2);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_object.c b/cborattr/test/src/testcases/cborattr_decode_object.c
new file mode 100644
index 0000000..25a32d2
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_object.c
@@ -0,0 +1,198 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_data(void)
+{
+    CborEncoder test_data;
+    CborEncoder sub_obj;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+    cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+
+    /*
+     * p: { bm : 7 }
+     */
+    cbor_encode_text_stringz(&test_data, "p");
+
+    cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&test_data, "bm");
+    cbor_encode_int(&test_data, 7);
+    cbor_encoder_close_container(&test_data, &sub_obj);
+
+    cbor_encoder_close_container(&test_encoder, &test_data);
+}
+
+static void
+test_encode_data_complex(void)
+{
+    CborEncoder test_data;
+    CborEncoder sub_obj;
+    CborEncoder sub_sub_obj;
+
+    test_cbor_len = 0;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+    cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+
+    /*
+     * p: { bm : 7 }, c: { d : { i : 1 } }, a: 3
+     */
+    cbor_encode_text_stringz(&test_data, "p");
+
+    cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&test_data, "bm");
+    cbor_encode_int(&test_data, 7);
+    cbor_encoder_close_container(&test_data, &sub_obj);
+
+    cbor_encode_text_stringz(&test_data, "c");
+    cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "d");
+
+    cbor_encoder_create_map(&sub_obj, &sub_sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_sub_obj, "i");
+    cbor_encode_int(&sub_sub_obj, 1);
+    cbor_encoder_close_container(&sub_obj, &sub_sub_obj);
+    cbor_encoder_close_container(&test_data, &sub_obj);
+
+    cbor_encode_text_stringz(&test_data, "a");
+    cbor_encode_int(&test_data, 3);
+
+    cbor_encoder_close_container(&test_encoder, &test_data);
+}
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode_object)
+{
+    int rc;
+    int64_t bm_val = 0;
+    struct cbor_attr_t test_sub_attr_bm[] = {
+        [0] = {
+            .attribute = "bm",
+            .type = CborAttrIntegerType,
+            .addr.integer = &bm_val,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "p",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_attr_bm,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    int64_t a_val = 0;
+    int64_t i_val = 0;
+    struct cbor_attr_t test_sub_sub_attr[] = {
+        [0] = {
+            .attribute = "i",
+            .type = CborAttrIntegerType,
+            .addr.integer = &i_val,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_sub_attr_d[] = {
+        [0] = {
+            .attribute = "d",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_sub_attr,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attr_complex[] = {
+        [0] = {
+            .attribute = "c",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_attr_d,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "a",
+            .type = CborAttrIntegerType,
+            .addr.integer = &a_val,
+            .nodefault = true
+        },
+        [2] = {
+            .attribute = "p",
+            .type = CborAttrObjectType,
+            .addr.obj = test_sub_attr_bm,
+            .nodefault = true
+        },
+        [3] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_data();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(bm_val == 7);
+
+    test_encode_data_complex();
+
+    bm_val = 0;
+    i_val = 0;
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attr_complex);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(bm_val == 7);
+    TEST_ASSERT(i_val == 1);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_object_array.c b/cborattr/test/src/testcases/cborattr_decode_object_array.c
new file mode 100644
index 0000000..82cc34f
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_object_array.c
@@ -0,0 +1,126 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_object_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+    CborEncoder sub_obj;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: [ { h:"str1"}, {h:"2str"}, {h:"str3"}]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+
+    cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "h");
+    cbor_encode_text_stringz(&sub_obj, "str1");
+    cbor_encoder_close_container(&array, &sub_obj);
+
+    cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "h");
+    cbor_encode_text_stringz(&sub_obj, "2str");
+    cbor_encoder_close_container(&array, &sub_obj);
+
+    cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+    cbor_encode_text_stringz(&sub_obj, "h");
+    cbor_encode_text_stringz(&sub_obj, "str3");
+    cbor_encoder_close_container(&array, &sub_obj);
+
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * object array
+ */
+TEST_CASE(test_cborattr_decode_object_array)
+{
+    int rc;
+    struct h_obj {
+        char h_data[32];
+    } arr_objs[5];
+    int arr_cnt = 0;
+    struct cbor_attr_t sub_attr[] = {
+        [0] = {
+            .attribute = "h",
+            .type = CborAttrTextStringType,
+            CBORATTR_STRUCT_OBJECT(struct h_obj, h_data),
+            .len = sizeof(arr_objs[0].h_data)
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            CBORATTR_STRUCT_ARRAY(arr_objs, sub_attr, &arr_cnt),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_object_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(!strcmp(arr_objs[0].h_data, "str1"));
+    TEST_ASSERT(!strcmp(arr_objs[1].h_data, "2str"));
+    TEST_ASSERT(!strcmp(arr_objs[2].h_data, "str3"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_partial.c b/cborattr/test/src/testcases/cborattr_decode_partial.c
new file mode 100644
index 0000000..df0b8d4
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_partial.c
@@ -0,0 +1,47 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Simple decoding. Only have key for one of the key/value pairs.
+ */
+TEST_CASE(test_cborattr_decode_partial)
+{
+    const uint8_t *data;
+    int len;
+    int rc;
+    char test_str_b[4] = { '\0' };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "b",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_b,
+            .len = sizeof(test_str_b),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    data = test_str1(&len);
+    rc = cbor_read_flat_attrs(data, len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!strcmp(test_str_b, "B"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_simple.c b/cborattr/test/src/testcases/cborattr_decode_simple.c
new file mode 100644
index 0000000..9e206e1
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_simple.c
@@ -0,0 +1,123 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_data(void)
+{
+    CborEncoder test_data;
+    uint8_t data[4] = { 0, 1, 2 };
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+    /*
+     * a:22
+     */
+    cbor_encode_text_stringz(&test_data, "a");
+    cbor_encode_uint(&test_data, 22);
+
+    /*
+     * b:-13
+     */
+    cbor_encode_text_stringz(&test_data, "b");
+    cbor_encode_int(&test_data, -13);
+
+    /*
+     * c:0x000102
+     */
+    cbor_encode_text_stringz(&test_data, "c");
+    cbor_encode_byte_string(&test_data, data, 3);
+    cbor_encoder_close_container(&test_encoder, &test_data);
+
+    /*
+     * XXX add other data types to encode here.
+     */
+
+}
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode_simple)
+{
+    int rc;
+    uint64_t a_val = 0;
+    int64_t b_val = 0;
+    uint8_t c_data[4];
+    size_t c_len;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrIntegerType,
+            .addr.uinteger = &a_val,
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "b",
+            .type = CborAttrIntegerType,
+            .addr.integer = &b_val,
+            .nodefault = true
+        },
+        [2] = {
+            .attribute = "c",
+            .type = CborAttrByteStringType,
+            .addr.bytestring.data = c_data,
+            .addr.bytestring.len = &c_len,
+            .len = sizeof(c_data)
+        },
+        [3] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_data();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(a_val == 22);
+    TEST_ASSERT(b_val == -13);
+    TEST_ASSERT(c_len == 3);
+    TEST_ASSERT(c_data[0] == 0 && c_data[1] == 1 && c_data[2] == 2);
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_string_array.c b/cborattr/test/src/testcases/cborattr_decode_string_array.c
new file mode 100644
index 0000000..d68e8df
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_string_array.c
@@ -0,0 +1,135 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_string_array_one(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: ["asdf"]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_text_stringz(&array, "asdf");
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+static void
+test_encode_string_array_three(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    test_cbor_len = 0;
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * a: ["asdf", "k", "blurb"]
+     */
+    cbor_encode_text_stringz(&data, "a");
+
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_text_stringz(&array, "asdf");
+    cbor_encode_text_stringz(&array, "k");
+    cbor_encode_text_stringz(&array, "blurb");
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * string array
+ */
+TEST_CASE(test_cborattr_decode_string_array)
+{
+    int rc;
+    char *str_ptrs[5];
+    char arr_data[256];
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "a",
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrTextStringType,
+            .addr.array.arr.strings.ptrs = str_ptrs,
+            .addr.array.arr.strings.store = arr_data,
+            .addr.array.arr.strings.storelen = sizeof(arr_data),
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_string_array_one();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 1);
+    TEST_ASSERT(!strcmp(str_ptrs[0], "asdf"));
+
+    test_encode_string_array_three();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(!strcmp(str_ptrs[0], "asdf"));
+    TEST_ASSERT(!strcmp(str_ptrs[1], "k"));
+    TEST_ASSERT(!strcmp(str_ptrs[2], "blurb"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_substring_key.c b/cborattr/test/src/testcases/cborattr_decode_substring_key.c
new file mode 100644
index 0000000..6eee774
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_substring_key.c
@@ -0,0 +1,111 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_substring_key(void)
+{
+    CborEncoder data;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    /*
+     * { "a": "A", "aa": "AA", "aaa" : "AAA" }
+     */
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    cbor_encode_text_stringz(&data, "a");
+    cbor_encode_text_stringz(&data, "A");
+    cbor_encode_text_stringz(&data, "aa");
+    cbor_encode_text_stringz(&data, "AA");
+    cbor_encode_text_stringz(&data, "aaa");
+    cbor_encode_text_stringz(&data, "AAA");
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * substring key
+ */
+TEST_CASE(test_cborattr_decode_substring_key)
+{
+    int rc;
+    char test_str_1a[4] = { '\0' };
+    char test_str_2a[4] = { '\0' };
+    char test_str_3a[4] = { '\0' };
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = "aaa",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_3a,
+            .len = sizeof(test_str_3a),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = "aa",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_2a,
+            .len = sizeof(test_str_2a),
+            .nodefault = true
+            },
+        [2] = {
+            .attribute = "a",
+            .type = CborAttrTextStringType,
+            .addr.string = test_str_1a,
+            .len = sizeof(test_str_1a),
+            .nodefault = true
+            },
+        [3] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_substring_key();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!strcmp(test_str_1a, "A"));
+    TEST_ASSERT(!strcmp(test_str_2a, "AA"));
+    TEST_ASSERT(!strcmp(test_str_3a, "AAA"));
+}
diff --git a/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c b/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c
new file mode 100644
index 0000000..c4446b8
--- /dev/null
+++ b/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c
@@ -0,0 +1,99 @@
+/*
+ * 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+    .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(test_cbor_buf + test_cbor_len, data, len);
+    test_cbor_len += len;
+
+    assert(test_cbor_len < sizeof(test_cbor_buf));
+    return 0;
+}
+
+static void
+test_encode_unnamed_array(void)
+{
+    CborEncoder data;
+    CborEncoder array;
+
+    cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+    cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+    /*
+     * [1,2,33]
+     */
+    cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+    cbor_encode_int(&array, 1);
+    cbor_encode_int(&array, 2);
+    cbor_encode_int(&array, 33);
+    cbor_encoder_close_container(&data, &array);
+
+    cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * integer array
+ */
+TEST_CASE(test_cborattr_decode_unnamed_array)
+{
+    int rc;
+    int64_t arr_data[5];
+    int arr_cnt = 0;
+    struct cbor_attr_t test_attrs[] = {
+        [0] = {
+            .attribute = CBORATTR_ATTR_UNNAMED,
+            .type = CborAttrArrayType,
+            .addr.array.element_type = CborAttrIntegerType,
+            .addr.array.arr.integers.store = arr_data,
+            .addr.array.count = &arr_cnt,
+            .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+            .nodefault = true
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    test_encode_unnamed_array();
+
+    rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(arr_cnt == 3);
+    TEST_ASSERT(arr_data[0] == 1);
+    TEST_ASSERT(arr_data[1] == 2);
+    TEST_ASSERT(arr_data[2] == 33);
+}

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 29/42: Remove local tinycbor copy.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit d69cfa39a240bb58a257c3db936f87094124e667
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Feb 8 13:23:30 2018 -0800

    Remove local tinycbor copy.
    
    Now mcumgr requires the application to supply the tinycbor library.
---
 ext/CMakeLists.txt                         |    1 -
 ext/tinycbor/.appveyor.yml                 |   35 -
 ext/tinycbor/.gitattributes                |    4 -
 ext/tinycbor/.gitignore                    |   81 -
 ext/tinycbor/.tag                          |    1 -
 ext/tinycbor/.travis.yml                   |   24 -
 ext/tinycbor/CMakeLists.txt                |   15 -
 ext/tinycbor/Doxyfile                      | 2318 ----------------------------
 ext/tinycbor/LICENSE                       |   21 -
 ext/tinycbor/Makefile                      |  234 ---
 ext/tinycbor/README                        |   13 -
 ext/tinycbor/TODO                          |   25 -
 ext/tinycbor/VERSION                       |    1 -
 ext/tinycbor/examples/examples.pro         |    2 -
 ext/tinycbor/examples/simplereader.c       |  181 ---
 ext/tinycbor/examples/simplereader.pro     |    3 -
 ext/tinycbor/maketag.pl                    |   91 --
 ext/tinycbor/pkg.yml                       |   29 -
 ext/tinycbor/src/cbor.dox                  |  123 --
 ext/tinycbor/src/cbor.h                    |  392 -----
 ext/tinycbor/src/cbor_buf_reader.c         |  125 --
 ext/tinycbor/src/cbor_buf_reader.h         |   47 -
 ext/tinycbor/src/cbor_buf_writer.c         |   99 --
 ext/tinycbor/src/cbor_buf_writer.h         |   55 -
 ext/tinycbor/src/cbor_cnt_writer.h         |   63 -
 ext/tinycbor/src/cbor_decoder_reader.h     |   60 -
 ext/tinycbor/src/cbor_defs.h               |  253 ---
 ext/tinycbor/src/cbor_encoder_writer.h     |   45 -
 ext/tinycbor/src/cborencoder.c             |  627 --------
 ext/tinycbor/src/cborerrorstrings.c        |  183 ---
 ext/tinycbor/src/cborinternal_p.h          |   89 --
 ext/tinycbor/src/cborjson.h                |   62 -
 ext/tinycbor/src/cborparser.c              | 1554 -------------------
 ext/tinycbor/src/cborparser_dup_string.c   |  118 --
 ext/tinycbor/src/cborpretty.c              |  535 -------
 ext/tinycbor/src/cborpretty_stdio.c        |   85 -
 ext/tinycbor/src/cbortojson.c              |  688 ---------
 ext/tinycbor/src/cborvalidation.c          |  675 --------
 ext/tinycbor/src/compilersupport_p.h       |  263 ----
 ext/tinycbor/src/open_memstream.c          |  117 --
 ext/tinycbor/src/parsetags.pl              |  116 --
 ext/tinycbor/src/src.pri                   |   17 -
 ext/tinycbor/src/tags.txt                  |   23 -
 ext/tinycbor/src/tinycbor-version.h        |    3 -
 ext/tinycbor/src/tinycbor.pro              |    6 -
 ext/tinycbor/src/utf8_p.h                  |  104 --
 ext/tinycbor/tests/.gitignore              |   15 -
 ext/tinycbor/tests/cpp/cpp.pro             |    5 -
 ext/tinycbor/tests/cpp/tst_cpp.cpp         |   44 -
 ext/tinycbor/tests/encoder/encoder.pro     |    9 -
 ext/tinycbor/tests/encoder/tst_encoder.cpp |  729 ---------
 ext/tinycbor/tests/parser/parser.pro       |   10 -
 ext/tinycbor/tests/parser/tst_parser.cpp   | 2031 ------------------------
 ext/tinycbor/tests/tests.pro               |    3 -
 ext/tinycbor/tests/tojson/tojson.pro       |    8 -
 ext/tinycbor/tests/tojson/tst_tojson.cpp   |  724 ---------
 ext/tinycbor/tinycbor.pc.in                |   11 -
 ext/tinycbor/tools/cbordump/cbordump.c     |  167 --
 ext/tinycbor/tools/cbordump/cbordump.pro   |   10 -
 ext/tinycbor/tools/json2cbor/json2cbor.c   |  492 ------
 ext/tinycbor/tools/json2cbor/json2cbor.pro |   20 -
 61 files changed, 13884 deletions(-)

diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
index f32ffb5..f453a03 100644
--- a/ext/CMakeLists.txt
+++ b/ext/CMakeLists.txt
@@ -1,2 +1 @@
 add_subdirectory(base64)
-add_subdirectory(tinycbor)
diff --git a/ext/tinycbor/.appveyor.yml b/ext/tinycbor/.appveyor.yml
deleted file mode 100644
index a64cb3f..0000000
--- a/ext/tinycbor/.appveyor.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-version: 0.5-build-{build}
-pull_requests:
-  do_not_increment_build_number: true
-image:
-- Visual Studio 2015
-- Visual Studio 2013
-- Visual Studio 2017
-install:
-- cmd: >-
-    set tests=1
-
-    if /i "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" (call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64) & (set tests=0)
-
-    if /i "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64) & (set QTDIR=C:\Qt\5.9\msvc2015_64)
-
-    if /i "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64) & (set QTDIR=C:\Qt\5.9\msvc2017_64)
-
-    set path=%PATH%;%QTDIR%\bin
-build_script:
-- cmd: >-
-    nmake -f Makefile.nmake -nologo CFLAGS="-W3 -Os -MDd"
-
-    cd tests
-
-    if /i "%tests%"=="1" qmake CONFIG-=release CONFIG+=debug
-
-    if /i "%tests%"=="1" nmake -nologo -s
-test_script:
-- cmd: >-
-    if /i "%tests%"=="1" nmake -s -nologo check
-
-    if /i "%tests%"=="0" echo Tests skipped.
-artifacts:
-- path: lib\tinycbor.lib
-deploy: off
diff --git a/ext/tinycbor/.gitattributes b/ext/tinycbor/.gitattributes
deleted file mode 100644
index 76ed256..0000000
--- a/ext/tinycbor/.gitattributes
+++ /dev/null
@@ -1,4 +0,0 @@
-.tag                    export-subst
-.gitignore              export-ignore
-.gitattributes          export-ignore
-.appveyor.yml           text
diff --git a/ext/tinycbor/.gitignore b/ext/tinycbor/.gitignore
deleted file mode 100644
index 3272de3..0000000
--- a/ext/tinycbor/.gitignore
+++ /dev/null
@@ -1,81 +0,0 @@
-# Frequent generated files
-callgrind.out.*
-pcviewer.cfg
-*~
-*.a
-*.la
-*.core
-*.d
-*.dylib
-*.moc
-*.o
-*.obj
-*.orig
-*.swp
-*.rej
-*.so
-*.so.*
-*.pbxuser
-*.mode1
-*.mode1v3
-*_pch.h.cpp
-*_resource.rc
-.#*
-*.*#
-core
-.qmake.cache
-.qmake.stash
-.qmake.vars
-.device.vars
-tags
-.DS_Store
-*.debug
-Makefile*
-*.prl
-*.app
-*.pro.user*
-*.qmlproject.user*
-*.gcov
-*.gcda
-*.gcno
-*.flc
-.*.swp
-tinycbor.pc
-
-# Visual Studio generated files
-*.ib_pdb_index
-*.idb
-*.ilk
-*.pdb
-*.sln
-*.suo
-*.vcproj
-*vcproj.*.*.user
-*.ncb
-*.vcxproj
-*.vcxproj.filters
-*.vcxproj.user
-*.exe.embed.manifest
-*.exe_manifest.rc
-*.exe_manifest.res
-
-# MinGW generated files
-*.Debug
-*.Release
-
-# INTEGRITY generated files
-*.gpj
-*.int
-*.ael
-*.dla
-*.dnm
-*.dep
-*.map
-
-bin
-doc
-lib
-src/cjson
-src/doxygen.log
-!/Makefile
-.config
diff --git a/ext/tinycbor/.tag b/ext/tinycbor/.tag
deleted file mode 100644
index 6828f88..0000000
--- a/ext/tinycbor/.tag
+++ /dev/null
@@ -1 +0,0 @@
-$Format:%H$
diff --git a/ext/tinycbor/.travis.yml b/ext/tinycbor/.travis.yml
deleted file mode 100644
index 0615bc4..0000000
--- a/ext/tinycbor/.travis.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-language: cpp
-os:
-  - linux
-  - osx
-env:
-  - CFLAGS="-O0 -g" QMAKEFLAGS="-config debug" PATH=/opt/qt59/bin:/usr/local/opt/qt5/bin:$PATH
-addons:
-  apt:
-    sources:
-      - sourceline: 'ppa:beineri/opt-qt593-trusty'
-    packages:
-      - qt59base valgrind
-install:
-  - if [ "${TRAVIS_OS_NAME}" != "linux" ]; then
-        brew update;
-        brew install qt5;
-    fi
-script:
-  - make -s -f Makefile.configure configure | tee .config
-  - make
-        CFLAGS="$CFLAGS"
-        all tests/Makefile
-  - cd tests && make check -k
-        TESTRUNNER=`which valgrind 2>/dev/null`
diff --git a/ext/tinycbor/CMakeLists.txt b/ext/tinycbor/CMakeLists.txt
deleted file mode 100644
index c9e11ee..0000000
--- a/ext/tinycbor/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-add_library(TINYCBOR INTERFACE)
-
-target_include_directories(TINYCBOR INTERFACE src)
-
-zephyr_library()
-zephyr_library_sources(
-    src/cbor_buf_reader.c
-    src/cbor_buf_writer.c
-    src/cborencoder.c
-    src/cborerrorstrings.c
-    src/cborparser.c
-    src/cborparser_dup_string.c
-)
-zephyr_library_link_libraries(TINYCBOR)
-target_link_libraries(TINYCBOR INTERFACE zephyr_interface)
diff --git a/ext/tinycbor/Doxyfile b/ext/tinycbor/Doxyfile
deleted file mode 100644
index 2cfaa33..0000000
--- a/ext/tinycbor/Doxyfile
+++ /dev/null
@@ -1,2318 +0,0 @@
-# Doxyfile 1.8.8
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME           = "TinyCBOR $(VERSION) API"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER         =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF          =
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
-
-PROJECT_LOGO           =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = ../doc
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS         = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES    = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF       =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES        = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH        = $(docroot)
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH    = $(docroot)
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES            = YES
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF      = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF           = YES
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE               = 8
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES                = "value=\arg \c"
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST              =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING      =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT       = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT       = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING            = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS  = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT   = NO
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL            = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC         = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES  = NO
-
-# This flag is only useful for Objective-C code. When set to YES local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS     = YES
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES     = YES
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES       = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC  = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING  = NO
-
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST      = NO
-
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST      = NO
-
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST       = NO
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= NO
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS       =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES        = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER    =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE            =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES         =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS               = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED   = NO
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE           = doxygen.log
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
-# Note: If this tag is empty the current directory is searched.
-
-INPUT                  = .
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
-
-FILE_PATTERNS          = *.h \
-                         *.c \
-                         *.dox
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE              = NO
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE                =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       = *_p.h
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS        =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH           = . \
-                         ../examples/rime \
-                         ../examples/multi-threading
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS       =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH             = pics
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-
-INPUT_FILTER           =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS        =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES    = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS    = NO
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS        = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS       = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX     = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX          = cbor_ Cbor
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER            =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER            =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET        =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra stylesheet files is of importance (e.g. the last
-# stylesheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET  =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES       =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE    = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA  = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP         = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET        = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP      = YES
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE               =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION           =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI           = YES
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING     =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC             = YES
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND             = YES
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE               =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE          = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME   =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS  =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS  =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION           =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID         = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX          = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW      = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH         = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT    = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX            = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT         = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS     =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE       =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE           = NO
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH    = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH        = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL       =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE        = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID     =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS  =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX          = YES
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE             = a4wide
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES         =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
-# for the replacement values of the other commands the user is refered to
-# HTML_HEADER.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER           =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER           =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES      =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE        = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES     = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE      = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE        = plain
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE    =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE    =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION          = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR             =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT             = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK       = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT         = docbook
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION        = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH           =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS  =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED             = DOXYGEN \
-                         CBOR_INLINE_API=
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED      =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES               =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE       =
-
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
-# The default value is: NO.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS        = YES
-
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES         = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS         = NO
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            =
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH               =
-
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT               = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS        = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME           = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH           =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH            = NO
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH    = NO
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS           = NO
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK               = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS   = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH          = NO
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH      = NO
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY    = NO
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH        = NO
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif and svg.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT       = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG        = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH               =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS           =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS           =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS           =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP            = YES
diff --git a/ext/tinycbor/LICENSE b/ext/tinycbor/LICENSE
deleted file mode 100644
index 4aad977..0000000
--- a/ext/tinycbor/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2017 Intel Corporation
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/ext/tinycbor/Makefile b/ext/tinycbor/Makefile
deleted file mode 100644
index 98c9a59..0000000
--- a/ext/tinycbor/Makefile
+++ /dev/null
@@ -1,234 +0,0 @@
-# Variables:
-prefix = /usr/local
-exec_prefix = $(prefix)
-bindir = $(exec_prefix)/bin
-libdir = $(exec_prefix)/lib
-includedir = $(prefix)/src
-pkgconfigdir = $(libdir)/pkgconfig
-
-CFLAGS = -Wall -Wextra
-LDFLAGS_GCSECTIONS = -Wl,--gc-sections
-LDFLAGS = $(if $(gc_sections-pass),$(LDFLAGS_GCSECTIONS))
-
-GIT_ARCHIVE = git archive --prefix="$(PACKAGE)/" -9
-INSTALL = install
-INSTALL_DATA = $(INSTALL) -m 644
-INSTALL_PROGRAM = $(INSTALL) -m 755
-QMAKE = qmake
-MKDIR = mkdir -p
-RMDIR = rmdir
-SED = sed
-
-# Our sources
-TINYCBOR_HEADERS = \
-	src/cbor.h \
- 	src/cborjson.h \
-	src/cbor_enocoder_writer.h \
-	src/cbor_decoder_reader.h \
-	src/cbor_defs.h
-TINYCBOR_SOURCES = \
-	src/cborerrorstrings.c \
-	src/cborencoder.c \
-	src/cborparser.c \
-	src/cborparser_dup_string.c \
-	src/cborpretty.c \
-	src/cborpretty_stdio.c \
-	src/cbortojson.c \
-	src/cborvalidation.c \
-	src/cbor_buf_reader.c \
-	src/cbor_buf_writer.c
-#
-CBORDUMP_SOURCES = tools/cbordump/cbordump.c
-
-BUILD_SHARED = $(shell file -L /bin/sh 2>/dev/null | grep -q ELF && echo 1)
-BUILD_STATIC = 1
-
-ifneq ($(BUILD_STATIC),1)
-ifneq ($(BUILD_SHARED),1)
-  $(error error: BUILD_STATIC and BUILD_SHARED can not be both disabled)
-endif
-endif
-
-INSTALL_TARGETS += $(bindir)/cbordump
-ifeq ($(BUILD_SHARED),1)
-BINLIBRARY=lib/libtinycbor.so
-INSTALL_TARGETS += $(libdir)/libtinycbor.so
-INSTALL_TARGETS += $(libdir)/libtinycbor.so.0
-INSTALL_TARGETS += $(libdir)/libtinycbor.so.$(VERSION)
-endif
-ifeq ($(BUILD_STATIC),1)
-BINLIBRARY=lib/libtinycbor.a
-INSTALL_TARGETS += $(libdir)/libtinycbor.a
-endif
-INSTALL_TARGETS += $(pkgconfigdir)/tinycbor.pc
-INSTALL_TARGETS += $(TINYCBOR_HEADERS:./%=$(includedir)/%)
-
-# setup VPATH
-MAKEFILE := $(lastword $(MAKEFILE_LIST))
-SRCDIR := $(dir $(MAKEFILE))
-VPATH = $(SRCDIR):$(SRCDIR)/src
-
-# Our version
-GIT_DIR := $(strip $(shell git -C $(SRCDIR). rev-parse --git-dir 2> /dev/null))
-ifeq ($(GIT_DIR),)
-  VERSION = $(shell cat $(SRCDIR)VERSION)
-  DIRTYSRC :=
-else
-  VERSION := $(shell git -C $(SRCDIR). describe --tags | cut -c2-)
-  DIRTYSRC := $(shell \
-	test -n "`git -C $(SRCDIR). diff --name-only HEAD`" && \
-	echo +)
-endif
-PACKAGE = tinycbor-$(VERSION)
-
-# Check that QMAKE is Qt 5
-ifeq ($(origin QMAKE),file)
-  check_qmake = $(strip $(shell $(1) -query QT_VERSION 2>/dev/null | cut -b1))
-  ifneq ($(call check_qmake,$(QMAKE)),5)
-    QMAKE := qmake -qt5
-    ifneq ($(call check_qmake,$(QMAKE)),5)
-      QMAKE := qmake-qt5
-      ifneq ($(call check_qmake,$(QMAKE)),5)
-        QMAKE := @echo >&2 $(MAKEFILE): Cannot find a Qt 5 qmake; false
-      endif
-    endif
-  endif
-endif
-
--include .config
-
-# if open_memstream is unavailable on the system, try to implement our own
-# version using funopen or fopencookie
-ifeq ($(open_memstream-pass),)
-  ifeq ($(funopen-pass)$(fopencookie-pass),)
-    CFLAGS += -DWITHOUT_OPEN_MEMSTREAM
-    $(warning warning: funopen and fopencookie unavailable, open_memstream can not be implemented and conversion to JSON will not work properly!)
-  else
-    TINYCBOR_SOURCES += src/open_memstream.c
-  endif
-endif
-
-# json2cbor depends on an external library (cjson)
-ifneq ($(cjson-pass)$(system-cjson-pass),)
-  JSON2CBOR_SOURCES = tools/json2cbor/json2cbor.c
-  INSTALL_TARGETS += $(bindir)/json2cbor
-  ifeq ($(system-cjson-pass),1)
-    LDFLAGS_CJSON = -lcjson
-  else
-    JSON2CBOR_SOURCES += src/cjson/cJSON.c
-    json2cbor_CCFLAGS = -I$(SRCDIR)src/cjson
-  endif
-endif
-
-# Rules
-all: .config \
-	$(if $(subst 0,,$(BUILD_STATIC)),lib/libtinycbor.a) \
-	$(if $(subst 0,,$(BUILD_SHARED)),lib/libtinycbor.so) \
-	bin/cbordump tinycbor.pc
-all: $(if $(JSON2CBOR_SOURCES),bin/json2cbor)
-check: tests/Makefile | $(BINLIBRARY)
-	$(MAKE) -C tests check
-silentcheck: | $(BINLIBRARY)
-	TESTARGS=-silent $(MAKE) -f $(MAKEFILE) -s check
-configure: .config
-.config: Makefile.configure
-	$(MAKE) -f $(SRCDIR)Makefile.configure OUT='>&9' configure 9> $@
-
-lib/libtinycbor.a: $(TINYCBOR_SOURCES:.c=.o)
-	@$(MKDIR) -p lib
-	$(AR) cqs $@ $^
-
-lib/libtinycbor.so: $(TINYCBOR_SOURCES:.c=.pic.o)
-	@$(MKDIR) -p lib
-	$(CC) -shared -Wl,-soname,libtinycbor.so.0 -o lib/libtinycbor.so.$(VERSION) $(LDFLAGS) $^
-	cd lib ; ln -sf libtinycbor.so.$(VERSION) libtinycbor.so ; ln -sf libtinycbor.so.$(VERSION) libtinycbor.so.0
-
-bin/cbordump: $(CBORDUMP_SOURCES:.c=.o) $(BINLIBRARY)
-	@$(MKDIR) -p bin
-	$(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS) -lm
-
-bin/json2cbor: $(JSON2CBOR_SOURCES:.c=.o) $(BINLIBRARY)
-	@$(MKDIR) -p bin
-	$(CC) -o $@ $(LDFLAGS) $^ $(LDFLAGS_CJSON) $(LDLIBS) -lm
-
-tinycbor.pc: tinycbor.pc.in
-	$(SED) > $@ < $< \
-		-e 's,@prefix@,$(prefix),' \
-		-e 's,@exec_prefix@,$(exec_prefix),' \
-		-e 's,@libdir@,$(libdir),' \
-		-e 's,@includedir@,$(includedir),' \
-		-e 's,@version@,$(VERSION),'
-
-tests/Makefile: tests/tests.pro
-	$(QMAKE) $(QMAKEFLAGS) -o $@ $<
-
-$(PACKAGE).tar.gz: | .git
-	GIT_DIR=$(SRCDIR).git $(GIT_ARCHIVE) --format=tar.gz -o "$(PACKAGE).tar.gz" HEAD
-$(PACKAGE).zip: | .git
-	GIT_DIR=$(SRCDIR).git $(GIT_ARCHIVE) --format=zip -o "$(PACKAGE).zip" HEAD
-
-$(DESTDIR)$(libdir)/%: lib/%
-	$(INSTALL) -d $(@D)
-	$(INSTALL_DATA) $< $@
-$(DESTDIR)$(bindir)/%: bin/%
-	$(INSTALL) -d $(@D)
-	$(INSTALL_PROGRAM) $< $@
-$(DESTDIR)$(pkgconfigdir)/%: %
-	$(INSTALL) -d $(@D)
-	$(INSTALL_DATA) $< $@
-$(DESTDIR)$(includedir)/%: src/%
-	$(INSTALL) -d $(@D)
-	$(INSTALL_DATA) $< $@
-
-install-strip:
-	$(MAKE) -f $(MAKEFILE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
-
-install: $(INSTALL_TARGETS:%=$(DESTDIR)%)
-uninstall:
-	$(RM) $(INSTALL_TARGETS:%=$(DESTDIR)%)
-
-mostlyclean:
-	$(RM) $(TINYCBOR_SOURCES:.c=.o)
-	$(RM) $(TINYCBOR_SOURCES:.c=.pic.o)
-	$(RM) $(CBORDUMP_SOURCES:.c=.o)
-
-clean: mostlyclean
-	$(RM) bin/cbordump
-	$(RM) bin/json2cbor
-	$(RM) lib/libtinycbor.a
-	$(RM) tinycbor.pc
-	$(RM) lib/libtinycbor.so*
-	test -e tests/Makefile && $(MAKE) -C tests clean || :
-
-distclean: clean
-	test -e tests/Makefile && $(MAKE) -C tests distclean || :
-
-docs:
-	cd $(SRCDIR)src && VERSION=$(VERSION) doxygen $(SRCDIR)/../Doxyfile
-
-dist: $(PACKAGE).tar.gz $(PACKAGE).zip
-distcheck: .git
-	-$(RM) -r $${TMPDIR-/tmp}/tinycbor-distcheck
-	GIT_DIR=$(SRCDIR).git git archive --prefix=tinycbor-distcheck/ --format=tar HEAD | tar -xf - -C $${TMPDIR-/tmp}
-	cd $${TMPDIR-/tmp}/tinycbor-distcheck && $(MAKE) silentcheck
-	$(RM) -r $${TMPDIR-/tmp}/tinycbor-distcheck
-
-tag: distcheck
-	@cd $(SRCDIR). && perl maketag.pl
-
-.PHONY: all check silentcheck configure install uninstall
-.PHONY: mostlyclean clean distclean
-.PHONY: docs dist distcheck release
-.SECONDARY:
-
-cflags := $(CPPFLAGS) -I$(SRCDIR)/src
-cflags += -DTINYCBOR_VERSION_SUFFIX=\"$(DIRTYSRC)\"
-cflags += -std=c99 $(CFLAGS)
-%.o: %.c
-	@test -d $(@D) || $(MKDIR) $(@D)
-	$(CC) $(cflags) $($(basename $(notdir $@))_CCFLAGS) -c -o $@ $<
-%.pic.o: %.c
-	@test -d $(@D) || $(MKDIR) $(@D)
-	$(CC) $(cflags) -fPIC $($(basename $(notdir $@))_CCFLAGS) -c -o $@ $<
-
--include src/*.d
diff --git a/ext/tinycbor/README b/ext/tinycbor/README
deleted file mode 100644
index 167efa0..0000000
--- a/ext/tinycbor/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Concise Binary Object Representation (CBOR) Library
----------------------------------------------------
-
-To build TinyCBOR:
-
-  make
-
-If you want to change the compiler or pass extra compiler flags:
-
-  make CC=clang CFLAGS="-m32 -Oz" LDFLAGS="-m32"
-
-Documentation: https://intel.github.io/tinycbor/current/
-
diff --git a/ext/tinycbor/TODO b/ext/tinycbor/TODO
deleted file mode 100644
index e9103ee..0000000
--- a/ext/tinycbor/TODO
+++ /dev/null
@@ -1,25 +0,0 @@
-==== To Do list for libcbor ====
-=== General ===
-* API review
-* Benchmark
-* Write examples
-** Simple decoder
-** Decoder to JSON
-** Windowed encoding/decoding (limited memory)
-
-=== Encoder ===
-* Write API docs
-* Add API for creating indeterminate-length arrays and maps
-* Add API for creating indeterminate-length strings
-* Add API for relaxing doubles to floats and to integers
-* Add length-checking of the sub-containers (#ifndef CBOR_ENCODER_NO_USER_CHECK)
-* Decide how to indicate number of bytes needed
-** Suggestion: return negative number from the functions
-
-=== Decoder ===
-* Write functions not yet implemented
-* Add API for stream-decoding strings
-* Add API for checking known tags and simple types
-* (unlikely) Add API for checking the pairing of a tag and the tagged type
-* Write tests for error conditions
-* Fuzzy-test the decoder
diff --git a/ext/tinycbor/VERSION b/ext/tinycbor/VERSION
deleted file mode 100644
index 2eb3c4f..0000000
--- a/ext/tinycbor/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-0.5
diff --git a/ext/tinycbor/examples/examples.pro b/ext/tinycbor/examples/examples.pro
deleted file mode 100644
index 22071ac..0000000
--- a/ext/tinycbor/examples/examples.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-TEMPLATE = subdirs
-SUBDIRS = simplereader.pro
diff --git a/ext/tinycbor/examples/simplereader.c b/ext/tinycbor/examples/simplereader.c
deleted file mode 100644
index 256191f..0000000
--- a/ext/tinycbor/examples/simplereader.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include "../src/cbor.h"
-
-#include <sys/stat.h>
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-static uint8_t *readfile(const char *fname, size_t *size)
-{
-    struct stat st;
-    FILE *f = fopen(fname, "rb");
-    if (!f)
-        return NULL;
-    if (fstat(fileno(f), &st) == -1)
-        return NULL;
-    uint8_t *buf = malloc(st.st_size);
-    *size = fread(buf, st.st_size, 1, f);
-    fclose(f);
-    return buf;
-}
-
-static void indent(int nestingLevel)
-{
-    while (nestingLevel--)
-        puts("  ");
-}
-
-static void dumpbytes(const uint8_t *buf, size_t len)
-{
-    while (len--)
-        printf("%02X ", *buf++);
-}
-
-static bool dumprecursive(CborValue *it, int nestingLevel)
-{
-    while (!cbor_value_at_end(it)) {
-        CborError err;
-        CborType type = cbor_value_get_type(it);
-
-        indent(nestingLevel);
-        switch (type) {
-        case CborArrayType:
-        case CborMapType: {
-            // recursive type
-            CborValue recursed;
-            assert(cbor_value_is_container(it));
-            puts(type == CborArrayType ? "Array[" : "Map[");
-            err = cbor_value_enter_container(it, &recursed);
-            if (err)
-                return err;       // parse error
-            err = dumprecursive(&recursed, nestingLevel + 1);
-            if (err)
-                return err;       // parse error
-            err = cbor_value_leave_container(it, &recursed);
-            if (err)
-                return err;       // parse error
-            indent(nestingLevel);
-            puts("]");
-            continue;
-        }
-
-        case CborIntegerType: {
-            int64_t val;
-            cbor_value_get_int64(it, &val);     // can't fail
-            printf("%lld\n", (long long)val);
-            break;
-        }
-
-        case CborByteStringType: {
-            uint8_t *buf;
-            size_t n;
-            err = cbor_value_dup_byte_string(it, &buf, &n, it);
-            if (err)
-                return err;     // parse error
-            dumpbytes(buf, n);
-            puts("");
-            free(buf);
-            continue;
-        }
-
-        case CborTextStringType: {
-            char *buf;
-            size_t n;
-            err = cbor_value_dup_text_string(it, &buf, &n, it);
-            if (err)
-                return err;     // parse error
-            puts(buf);
-            free(buf);
-            continue;
-        }
-
-        case CborTagType: {
-            CborTag tag;
-            cbor_value_get_tag(it, &tag);       // can't fail
-            printf("Tag(%lld)\n", (long long)tag);
-            break;
-        }
-
-        case CborSimpleType: {
-            uint8_t type;
-            cbor_value_get_simple_type(it, &type);  // can't fail
-            printf("simple(%u)\n", type);
-            break;
-        }
-
-        case CborNullType:
-            puts("null");
-            break;
-
-        case CborUndefinedType:
-            puts("undefined");
-            break;
-
-        case CborBooleanType: {
-            bool val;
-            cbor_value_get_boolean(it, &val);       // can't fail
-            puts(val ? "true" : "false");
-            break;
-        }
-
-        case CborDoubleType: {
-            double val;
-            if (false) {
-                float f;
-        case CborFloatType:
-                cbor_value_get_float(it, &f);
-                val = f;
-            } else {
-                cbor_value_get_double(it, &val);
-            }
-            printf("%g\n", val);
-            break;
-        }
-        case CborHalfFloatType: {
-            uint16_t val;
-            cbor_value_get_half_float(it, &val);
-            printf("__f16(%04x)\n", val);
-            break;
-        }
-
-        case CborInvalidType:
-            assert(false);      // can't happen
-            break;
-        }
-
-        err = cbor_value_advance_fixed(it);
-        if (err)
-            return err;
-    }
-    return CborNoError;
-}
-
-int main(int argc, char **argv)
-{
-    if (argc == 1) {
-        puts("simplereader <filename>");
-        return 0;
-    }
-
-    size_t length;
-    uint8_t *buf = readfile(argv[1], &length);
-    if (!buf) {
-        perror("readfile");
-        return 1;
-    }
-
-    CborParser parser;
-    CborValue it;
-    CborError err = cbor_parser_init(buf, length, 0, &parser, &it);
-    if (!err)
-        err = dumprecursive(&it, 0);
-    free(buf);
-
-    if (err) {
-        fprintf(stderr, "CBOR parsing failure at offset %ld: %s\n",
-                it.ptr - buf, cbor_error_string(err));
-        return 1;
-    }
-    return 0;
-}
diff --git a/ext/tinycbor/examples/simplereader.pro b/ext/tinycbor/examples/simplereader.pro
deleted file mode 100644
index 07fdc6a..0000000
--- a/ext/tinycbor/examples/simplereader.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-CONFIG -= qt
-SOURCES = simplereader.c
-include(../src/src.pri)
diff --git a/ext/tinycbor/maketag.pl b/ext/tinycbor/maketag.pl
deleted file mode 100644
index 5b1a8b7..0000000
--- a/ext/tinycbor/maketag.pl
+++ /dev/null
@@ -1,91 +0,0 @@
-#!perl
-use strict;
-sub run(@) {
-    open PROC, "-|", @_ or die("Cannot run $_[0]: $!");
-    my @out;
-    while (<PROC>) {
-        chomp;
-        push @out, $_;
-    }
-    close PROC;
-    return @out;
-}
-
-my @tags = run("git", "tag");
-my @v = run("git", "show", "HEAD:VERSION");
-my $v = $v[0];
-
-my $tagfile = ".git/TAG_EDITMSG";
-open TAGFILE, ">", $tagfile
-    or die("Cannot create file for editing tag message: $!");
-select TAGFILE;
-print "TinyCBOR release $v\n";
-print "\n";
-print "# Write something nice about this release here\n";
-
-# Do we have a commit template?
-my @result = run("git", "config", "--get", "commit.template");
-if (scalar @result) {
-    open TEMPLATE, "<", $result[0];
-    map { print $_; } <TEMPLATE>;
-    close TEMPLATE;
-}
-
-print "\n";
-print "# Commit log\n";
-open LOG, "-|", "git", "shortlog", "-e", "--no-merges", "--not", @tags;
-map { print "#  $_"; } <LOG>;
-close LOG;
-
-print "# Header diff:\n";
-open DIFF, "-|", "git", "diff", "HEAD", "--not", @tags, "--", 'src/*.h', ':!*_p.h';
-map { print "# $_"; } <DIFF>;
-close DIFF;
-
-select STDOUT;
-close TAGFILE;
-
-# Run the editor.
-# We use system so that stdin, stdout and stderr are forwarded.
-@result = run("git", "var", "GIT_EDITOR");
-@result = ($result[0], $tagfile);
-system @result;
-exit ($? >> 8) if $?;
-
-# Create the tag
-# Also using system so that hte user can see the output.
-system("git", "tag", "-a", "-F", $tagfile, split(' ', $ENV{GITTAGFLAGS}), "v$v");
-exit ($? >> 8) if $?;
-
-# Update the version files for the next patch release
-@v = split(/\./, $v);
-if (scalar @v < 3) {
-    push @v, '1';
-} else {
-    ++$v[-1];
-}
-$v = join('.', @v);
-open VERSION, ">", "VERSION" or die("Cannot open VERSION file: $!");
-print VERSION "$v\n";
-close VERSION;
-
-open VERSION, ">", "src/tinycbor-version.h" or die("Cannot open src/tinycbor-version.h: $!");
-print VERSION "#define TINYCBOR_VERSION_MAJOR      ", $v[0], "\n";
-print VERSION "#define TINYCBOR_VERSION_MINOR      ", $v[1], "\n";
-print VERSION "#define TINYCBOR_VERSION_PATCH      ", $v[2], "\n";
-close VERSION;
-
-if (open APPVEYORYML, "<", ".appveyor.yml") {
-    my @contents = map {
-        s/^version:.*/version: $v[0].$v[1].$v[2]-build-{build}/;
-        $_;
-    } <APPVEYORYML>;
-    close APPVEYORYML;
-    open APPVEYORYML, ">", ".appveyor.yml";
-    print APPVEYORYML join('', @contents);
-    close APPVEYORYML;
-}
-
-# Print summary
-print "Tag created and next versions updated.\n";
-print "Don't forget to create the docs.\n" if $v[2] == 1;
diff --git a/ext/tinycbor/pkg.yml b/ext/tinycbor/pkg.yml
deleted file mode 100644
index c0e2133..0000000
--- a/ext/tinycbor/pkg.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# 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: ext/tinycbor 
-pkg.description: CBOR encoding/decoding library 
-pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
-pkg.homepage: "http://mynewt.apache.org/"
-pkg.keywords:
-
-pkg.cflags:
-    - -DWITHOUT_OPEN_MEMSTREAM
-    - "-I@mynewt-mcumgr/ext/tinycbor/src"
-pkg.cflags.FLOAT_USER: -DFLOAT_SUPPORT
diff --git a/ext/tinycbor/src/cbor.dox b/ext/tinycbor/src/cbor.dox
deleted file mode 100644
index cc7a79d..0000000
--- a/ext/tinycbor/src/cbor.dox
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-/**
- * \mainpage
- * The TinyCBOR $(VERSION) library is a small CBOR encoder and decoder library,
- * optimized for very fast operation with very small footprint. The main encoder
- * and decoder functions do not allocate memory.
- *
- * TinyCBOR is divided into the following groups of functions and structures:
- *  - \ref CborGlobals
- *  - \ref CborEncoding
- *  - \ref CborParsing
- *  - \ref CborPretty
- *  - \ref CborToJson
- */
-
-/**
- * \file <cbor.h>
- * The <cbor.h> is the main header in TinyCBOR and defines the constants used by most functions
- * as well as the structures for encoding (CborEncoder) and decoding (CborValue).
- *
- * \sa <cborjson.h>
- */
-
-/**
- * \file <cborjson.h>
- * The <cborjson.h> file contains the routines that are used to convert a CBOR
- * data stream into JSON.
- *
- * \sa <cbor.h>
- */
-
-/**
- * \defgroup CborGlobals Global constants
- * \brief Constants used by all TinyCBOR function groups.
- */
-
-/**
- * \addtogroup CborGlobals
- * @{
- */
-
-/**
- * \var size_t CborIndefiniteLength
- *
- * This variable is a constant used to indicate that the length of the map or
- * array is not yet determined. It is used in functions
- * cbor_encoder_create_map() and cbor_encoder_create_array()
- */
-
-/**
- * \enum CborType
- * The CborType enum contains the types known to TinyCBOR.
- *
- * \value CborIntegerType           Type is an integer value, positive, negative or zero
- * \value CborByteStringType        Type is a string of arbitrary raw bytes
- * \value CborTextStringType        Type is a text string encoded in UTF-8
- * \value CborArrayType             Type is a CBOR array
- * \value CborMapType               Type is a CBOR map (an associative container with key and value pairs)
- * \value CborTagType               Type is a CBOR tag (a 64-bit integer describing the item that follows, see CborKnownTags)
- * \value CborSimpleType            Type is one of CBOR Simple Types
- * \value CborBooleanType           Type is a boolean (true or false)
- * \value CborNullType              Type encodes a null
- * \value CborUndefinedType         Type encodes an undefined value
- * \value CborHalfFloatType         Type is an IEEE 754 half precision (16-bit) floating point type
- * \value CborFloatType             Type is an IEEE 754 single precision (32-bit) floating point type
- * \value CborDoubleType            Type is an IEEE 754 double precision (64-bit) floating point type
- * \value CborInvalidType           Type is not valid (this value is used to indicate error conditions)
- */
-
-/**
- * \enum CborKnownTags
- * The CborKnownTags enum contains known tags specified in RFC 7049, for use by the application.
- * TinyCBOR does not usually interpret the meaning of these tags and does not add them to the
- * output stream, unless specifically instructed to do so in functions for that effect.
- *
- * \value CborDateTimeStringTag     Text string contains a date-time encoded in RFC 3339 format, "YYYY-MM-DD hh:mm:ss+zzzz"
- * \value CborUnixTime_tTag         Number is a Unix time_t quantity, the number of seconds since 1970-01-01 midnight UTC
- * \value CborPositiveBignumTag     Item is a CBOR byte string encoding a positive integer of arbitrary precision
- * \value CborNegativeBignumTag     Item is a CBOR byte string encoding a negative integer of arbitrary precision
- * \value CborDecimalTag            Item is a CBOR array of two integers encoding a fixed-point decimal
- * \value CborBigfloatTag           Item is a bigfloat
- * \value CborExpectedBase64urlTag  Item is a CBOR byte string that is expected to be encoded as Base64Url
- * \value CborExpectedBase64Tag     Item is a CBOR byte string that is expected to be encoded as Base64
- * \value CborExpectedBase16Tag     Item is a CBOR byte string that is expected to be encoded as Base16 (also known as "hexdump")
- * \value CborUriTag                Item is a CBOR text string containing an URI (RFC 3986) or IRI (RFC 3987)
- * \value CborBase64urlTag          Item is a CBOR text string that was encoded as Base64Url
- * \value CborBase64Tag             Item is a CBOR text string that was encoded as Base64
- * \value CborRegularExpressionTag  Item is a CBOR text string containing a regular expression
- * \value CborMimeMessageTag        Item is a CBOR text string containing a MIME message (RFC 2045, 2046, 2047, 2822)
- * \value CborSignatureTag          Item contains CBOR-encoded data.
- *                                  This tag is also used as "file magic," marking a file as containing CBOR
- */
-
-/**
- * \typedef CborTag
- * This typedef is an unsigned 64-bit integer. Known CBOR tags can be used from the CborKnownTags enum
- * but the user application may use other tag values than the ones specified in RFC 7049.
- */
-
-/** @} */
diff --git a/ext/tinycbor/src/cbor.h b/ext/tinycbor/src/cbor.h
deleted file mode 100644
index ae87ed6..0000000
--- a/ext/tinycbor/src/cbor.h
+++ /dev/null
@@ -1,392 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_H
-#define CBOR_H
-
-#ifndef assert
-#include <assert.h>
-#endif
-#include <limits.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "cbor_buf_writer.h"
-#include "cbor_buf_reader.h"
-#include "cbor_defs.h"
-#include "tinycbor-version.h"
-
-#define TINYCBOR_VERSION            ((TINYCBOR_VERSION_MAJOR << 16) | (TINYCBOR_VERSION_MINOR << 8) | TINYCBOR_VERSION_PATCH)
-
-#ifdef __cplusplus
-extern "C" {
-#else
-#include <stdbool.h>
-#endif
-
-CBOR_API const char *cbor_error_string(CborError error);
-
-/* Encoder API */
-struct CborEncoder
-{
-    cbor_encoder_writer *writer;
-    void *writer_arg;
-#ifndef NO_DFLT_WRITER
-    struct cbor_buf_writer wr;
-#endif
-    size_t added;
-    size_t container_size;
-    int flags;
-};
-
-typedef struct CborEncoder CborEncoder;
-
-#ifndef NO_DFLT_WRITER
-CBOR_API void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags);
-#endif
-CBOR_API void cbor_encoder_cust_writer_init(CborEncoder *encoder, struct cbor_encoder_writer *w, int flags);
-CBOR_API CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value);
-CBOR_API CborError cbor_encode_int(CborEncoder *encoder, int64_t value);
-CBOR_API CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value);
-CBOR_API CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value);
-CBOR_API CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag);
-CBOR_API CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length);
-CBOR_INLINE_API CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string)
-{ return cbor_encode_text_string(encoder, string, strlen(string)); }
-CBOR_API CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length);
-CBOR_API CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value);
-CBOR_INLINE_API int cbor_encode_bytes_written(CborEncoder *encoder)
-{   return encoder->writer->bytes_written; }
-CBOR_INLINE_API CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
-{ return cbor_encode_simple_value(encoder, (int)value - 1 + (CborBooleanType & 0x1f)); }
-CBOR_INLINE_API CborError cbor_encode_null(CborEncoder *encoder)
-{ return cbor_encode_simple_value(encoder, CborNullType & 0x1f); }
-CBOR_INLINE_API CborError cbor_encode_undefined(CborEncoder *encoder)
-{ return cbor_encode_simple_value(encoder, CborUndefinedType & 0x1f); }
-
-CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
-{ return cbor_encode_floating_point(encoder, CborHalfFloatType, value); }
-CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value)
-{ return cbor_encode_floating_point(encoder, CborFloatType, &value); }
-CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double value)
-{ return cbor_encode_floating_point(encoder, CborDoubleType, &value); }
-
-CBOR_API CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length);
-CBOR_API CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length);
-CBOR_API CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder);
-CBOR_API CborError cbor_encoder_close_container_checked(CborEncoder *encoder, const CborEncoder *containerEncoder);
-
-/* Parser API */
-struct CborParser
-{
-#ifndef NO_DFLT_READER
-    struct cbor_buf_reader br;
-#endif
-    struct cbor_decoder_reader *d;
-    int end;
-    int flags;
-};
-typedef struct CborParser CborParser;
-
-struct CborValue
-{
-    const CborParser *parser;
-    int offset;
-    uint32_t remaining;
-    uint32_t remainingclen;
-    uint16_t extra;
-    uint8_t type;
-    uint8_t flags;
-};
-typedef struct CborValue CborValue;
-
-#ifndef NO_DFLT_READER
-CBOR_API CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it);
-#endif
-CBOR_API CborError cbor_parser_cust_reader_init(struct cbor_decoder_reader *r, int flags, CborParser *parser, CborValue *it);
-
-CBOR_API CborError cbor_value_validate_basic(const CborValue *it);
-
-CBOR_INLINE_API bool cbor_value_at_end(const CborValue *it)
-{ return it->remaining == 0; }
-CBOR_API CborError cbor_value_advance_fixed(CborValue *it);
-CBOR_API CborError cbor_value_advance(CborValue *it);
-CBOR_INLINE_API bool cbor_value_is_container(const CborValue *it)
-{ return it->type == CborArrayType || it->type == CborMapType; }
-CBOR_API CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed);
-CBOR_API CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed);
-
-CBOR_PRIVATE_API uint64_t _cbor_value_decode_int64_internal(const CborValue *value);
-CBOR_INLINE_API uint64_t _cbor_value_extract_int64_helper(const CborValue *value)
-{
-    return value->flags & CborIteratorFlag_IntegerValueTooLarge ?
-                _cbor_value_decode_int64_internal(value) : value->extra;
-}
-
-CBOR_INLINE_API bool cbor_value_is_valid(const CborValue *value)
-{ return value && value->type != CborInvalidType; }
-CBOR_INLINE_API CborType cbor_value_get_type(const CborValue *value)
-{ return (CborType)value->type; }
-
-/* Null & undefined type */
-CBOR_INLINE_API bool cbor_value_is_null(const CborValue *value)
-{ return value->type == CborNullType; }
-CBOR_INLINE_API bool cbor_value_is_undefined(const CborValue *value)
-{ return value->type == CborUndefinedType; }
-
-/* Booleans */
-CBOR_INLINE_API bool cbor_value_is_boolean(const CborValue *value)
-{ return value->type == CborBooleanType; }
-CBOR_INLINE_API CborError cbor_value_get_boolean(const CborValue *value, bool *result)
-{
-    assert(cbor_value_is_boolean(value));
-    *result = !!value->extra;
-    return CborNoError;
-}
-
-/* Simple types */
-CBOR_INLINE_API bool cbor_value_is_simple_type(const CborValue *value)
-{ return value->type == CborSimpleType; }
-CBOR_INLINE_API CborError cbor_value_get_simple_type(const CborValue *value, uint8_t *result)
-{
-    assert(cbor_value_is_simple_type(value));
-    *result = (uint8_t)value->extra;
-    return CborNoError;
-}
-
-/* Integers */
-CBOR_INLINE_API bool cbor_value_is_integer(const CborValue *value)
-{ return value->type == CborIntegerType; }
-CBOR_INLINE_API bool cbor_value_is_unsigned_integer(const CborValue *value)
-{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger) == 0; }
-CBOR_INLINE_API bool cbor_value_is_negative_integer(const CborValue *value)
-{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger); }
-
-CBOR_INLINE_API CborError cbor_value_get_raw_integer(const CborValue *value, uint64_t *result)
-{
-    assert(cbor_value_is_integer(value));
-    *result = _cbor_value_extract_int64_helper(value);
-    return CborNoError;
-}
-
-CBOR_INLINE_API CborError cbor_value_get_uint64(const CborValue *value, uint64_t *result)
-{
-    assert(cbor_value_is_unsigned_integer(value));
-    *result = _cbor_value_extract_int64_helper(value);
-    return CborNoError;
-}
-
-CBOR_INLINE_API CborError cbor_value_get_int64(const CborValue *value, int64_t *result)
-{
-    assert(cbor_value_is_integer(value));
-    *result = (int64_t) _cbor_value_extract_int64_helper(value);
-    if (value->flags & CborIteratorFlag_NegativeInteger)
-        *result = -*result - 1;
-    return CborNoError;
-}
-
-CBOR_INLINE_API CborError cbor_value_get_int(const CborValue *value, int *result)
-{
-    assert(cbor_value_is_integer(value));
-    *result = (int) _cbor_value_extract_int64_helper(value);
-    if (value->flags & CborIteratorFlag_NegativeInteger)
-        *result = -*result - 1;
-    return CborNoError;
-}
-
-CBOR_API CborError cbor_value_get_int64_checked(const CborValue *value, int64_t *result);
-CBOR_API CborError cbor_value_get_int_checked(const CborValue *value, int *result);
-
-CBOR_INLINE_API bool cbor_value_is_length_known(const CborValue *value)
-{ return (value->flags & CborIteratorFlag_UnknownLength) == 0; }
-
-/* Tags */
-CBOR_INLINE_API bool cbor_value_is_tag(const CborValue *value)
-{ return value->type == CborTagType; }
-CBOR_INLINE_API CborError cbor_value_get_tag(const CborValue *value, CborTag *result)
-{
-    assert(cbor_value_is_tag(value));
-    *result = _cbor_value_extract_int64_helper(value);
-    return CborNoError;
-}
-CBOR_API CborError cbor_value_skip_tag(CborValue *it);
-
-/* Strings */
-CBOR_INLINE_API bool cbor_value_is_byte_string(const CborValue *value)
-{ return value->type == CborByteStringType; }
-CBOR_INLINE_API bool cbor_value_is_text_string(const CborValue *value)
-{ return value->type == CborTextStringType; }
-
-CBOR_INLINE_API CborError cbor_value_get_string_length(const CborValue *value, size_t *length)
-{
-    assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
-    if (!cbor_value_is_length_known(value))
-        return CborErrorUnknownLength;
-    uint64_t v = _cbor_value_extract_int64_helper(value);
-    *length = (size_t)v;
-    if (*length != v)
-        return CborErrorDataTooLarge;
-    return CborNoError;
-}
-
-CBOR_PRIVATE_API CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
-                                                   size_t *buflen, CborValue *next);
-CBOR_PRIVATE_API CborError _cbor_value_dup_string(const CborValue *value, void **buffer,
-                                                  size_t *buflen, CborValue *next);
-
-CBOR_API CborError cbor_value_calculate_string_length(const CborValue *value, size_t *length);
-
-CBOR_INLINE_API CborError cbor_value_copy_text_string(const CborValue *value, char *buffer,
-                                                      size_t *buflen, CborValue *next)
-{
-    assert(cbor_value_is_text_string(value));
-    return _cbor_value_copy_string(value, buffer, buflen, next);
-}
-CBOR_INLINE_API CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer,
-                                                      size_t *buflen, CborValue *next)
-{
-    assert(cbor_value_is_byte_string(value));
-    return _cbor_value_copy_string(value, buffer, buflen, next);
-}
-
-CBOR_INLINE_API CborError cbor_value_dup_text_string(const CborValue *value, char **buffer,
-                                                     size_t *buflen, CborValue *next)
-{
-    assert(cbor_value_is_text_string(value));
-    return _cbor_value_dup_string(value, (void **)buffer, buflen, next);
-}
-CBOR_INLINE_API CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer,
-                                                     size_t *buflen, CborValue *next)
-{
-    assert(cbor_value_is_byte_string(value));
-    return _cbor_value_dup_string(value, (void **)buffer, buflen, next);
-}
-
-CBOR_PRIVATE_API CborError _cbor_value_get_string_chunk(const CborValue *value, const void **bufferptr,
-                                                        size_t *len, CborValue *next);
-CBOR_INLINE_API CborError cbor_value_get_text_string_chunk(const CborValue *value, const char **bufferptr,
-                                                           size_t *len, CborValue *next)
-{
-    assert(cbor_value_is_text_string(value));
-    return _cbor_value_get_string_chunk(value, (const void **)bufferptr, len, next);
-}
-CBOR_INLINE_API CborError cbor_value_get_byte_string_chunk(const CborValue *value, const uint8_t **bufferptr,
-                                                           size_t *len, CborValue *next)
-{
-    assert(cbor_value_is_byte_string(value));
-    return _cbor_value_get_string_chunk(value, (const void **)bufferptr, len, next);
-}
-
-CBOR_API CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result);
-
-/* Maps and arrays */
-CBOR_INLINE_API bool cbor_value_is_array(const CborValue *value)
-{ return value->type == CborArrayType; }
-CBOR_INLINE_API bool cbor_value_is_map(const CborValue *value)
-{ return value->type == CborMapType; }
-
-CBOR_INLINE_API CborError cbor_value_get_array_length(const CborValue *value, size_t *length)
-{
-    assert(cbor_value_is_array(value));
-    if (!cbor_value_is_length_known(value))
-        return CborErrorUnknownLength;
-    uint64_t v = _cbor_value_extract_int64_helper(value);
-    *length = (size_t)v;
-    if (*length != v)
-        return CborErrorDataTooLarge;
-    return CborNoError;
-}
-
-CBOR_INLINE_API CborError cbor_value_get_map_length(const CborValue *value, size_t *length)
-{
-    assert(cbor_value_is_map(value));
-    if (!cbor_value_is_length_known(value))
-        return CborErrorUnknownLength;
-    uint64_t v = _cbor_value_extract_int64_helper(value);
-    *length = (size_t)v;
-    if (*length != v)
-        return CborErrorDataTooLarge;
-    return CborNoError;
-}
-
-CBOR_API CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element);
-
-/* Floating point */
-CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value)
-{ return value->type == CborHalfFloatType; }
-CBOR_API CborError cbor_value_get_half_float(const CborValue *value, void *result);
-
-CBOR_INLINE_API bool cbor_value_is_float(const CborValue *value)
-{ return value->type == CborFloatType; }
-CBOR_INLINE_API CborError cbor_value_get_float(const CborValue *value, float *result)
-{
-    assert(cbor_value_is_float(value));
-    assert(value->flags & CborIteratorFlag_IntegerValueTooLarge);
-    uint32_t data = (uint32_t)_cbor_value_decode_int64_internal(value);
-    memcpy(result, &data, sizeof(*result));
-    return CborNoError;
-}
-
-CBOR_INLINE_API bool cbor_value_is_double(const CborValue *value)
-{ return value->type == CborDoubleType; }
-CBOR_INLINE_API CborError cbor_value_get_double(const CborValue *value, double *result)
-{
-    assert(cbor_value_is_double(value));
-    assert(value->flags & CborIteratorFlag_IntegerValueTooLarge);
-    uint64_t data = _cbor_value_decode_int64_internal(value);
-    memcpy(result, &data, sizeof(*result));
-    return CborNoError;
-}
-
-/* Validation API */
-CBOR_API CborError cbor_value_validate(const CborValue *it, int flags);
-
-/* Human-readable (dump) API */
-
-typedef CborError (*CborStreamFunction)(void *token, const char *fmt, ...)
-#ifdef __GNUC__
-    __attribute__((__format__(printf, 2, 3)))
-#endif
-;
-
-CBOR_API CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags);
-
-/* The following API requires a hosted C implementation (uses FILE*) */
-#if !defined(__STDC_HOSTED__) || __STDC_HOSTED__-0 == 1
-CBOR_API CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags);
-CBOR_API CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value);
-CBOR_INLINE_API CborError cbor_value_to_pretty(FILE *out, const CborValue *value)
-{
-    CborValue copy = *value;
-    return cbor_value_to_pretty_advance_flags(out, &copy, CborPrettyDefaultFlags);
-}
-#endif /* __STDC_HOSTED__ check */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CBOR_H */
diff --git a/ext/tinycbor/src/cbor_buf_reader.c b/ext/tinycbor/src/cbor_buf_reader.c
deleted file mode 100644
index 54ec067..0000000
--- a/ext/tinycbor/src/cbor_buf_reader.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#include "cbor_buf_reader.h"
-#include "compilersupport_p.h"
-
-CBOR_INLINE_API uint16_t get16(const uint8_t *ptr)
-{
-    uint16_t result;
-    memcpy(&result, ptr, sizeof(result));
-    return cbor_ntohs(result);
-}
-
-CBOR_INLINE_API uint32_t get32(const uint8_t *ptr)
-{
-    uint32_t result;
-    memcpy(&result, ptr, sizeof(result));
-    return cbor_ntohl(result);
-}
-
-CBOR_INLINE_API uint64_t get64(const uint8_t *ptr)
-{
-    uint64_t result;
-    memcpy(&result, ptr, sizeof(result));
-    return cbor_ntohll(result);
-}
-
-CBOR_INLINE_API uintptr_t get_string_chunk(const uint8_t *ptr)
-{
-    return (uintptr_t)ptr;
-}
-
-static uint8_t
-cbuf_buf_reader_get8(struct cbor_decoder_reader *d, int offset)
-{
-    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
-    return cb->buffer[offset];
-}
-
-static uint16_t
-cbuf_buf_reader_get16(struct cbor_decoder_reader *d, int offset)
-{
-    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
-    return get16(cb->buffer + offset);
-}
-
-static uint32_t
-cbuf_buf_reader_get32(struct cbor_decoder_reader *d, int offset)
-{
-    uint32_t val;
-    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
-    val = get32(cb->buffer + offset);
-    return val;
-}
-
-static uint64_t
-cbuf_buf_reader_get64(struct cbor_decoder_reader *d, int offset)
-{
-    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
-    return get64(cb->buffer + offset);
-}
-
-static uintptr_t
-cbor_buf_reader_get_string_chunk(struct cbor_decoder_reader *d,
-                                 int offset, size_t *len)
-{
-    struct cbor_buf_reader *cb = (struct cbor_buf_reader *)d;
-
-    (void)*len;
-
-    return get_string_chunk(cb->buffer + offset);
-}
-
-static uintptr_t
-cbor_buf_reader_cmp(struct cbor_decoder_reader *d, char *dst, int src_offset,
-                    size_t len)
-{
-    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
-
-    return !memcmp(dst, cb->buffer + src_offset, len);
-}
-
-static uintptr_t
-cbor_buf_reader_cpy(struct cbor_decoder_reader *d, char *dst, int src_offset,
-                    size_t len)
-{
-    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
-    return (uintptr_t) memcpy(dst, cb->buffer + src_offset, len);
-}
-
-void
-cbor_buf_reader_init(struct cbor_buf_reader *cb, const uint8_t *buffer,
-                     size_t data)
-{
-    cb->buffer = buffer;
-    cb->r.get8 = &cbuf_buf_reader_get8;
-    cb->r.get16 = &cbuf_buf_reader_get16;
-    cb->r.get32 = &cbuf_buf_reader_get32;
-    cb->r.get64 = &cbuf_buf_reader_get64;
-    cb->r.cmp = &cbor_buf_reader_cmp;
-    cb->r.cpy = &cbor_buf_reader_cpy;
-    cb->r.get_string_chunk = &cbor_buf_reader_get_string_chunk;
-    cb->r.message_size = data;
-}
diff --git a/ext/tinycbor/src/cbor_buf_reader.h b/ext/tinycbor/src/cbor_buf_reader.h
deleted file mode 100644
index 70408fd..0000000
--- a/ext/tinycbor/src/cbor_buf_reader.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_BUF_READER_H
-#define CBOR_BUF_READER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "cbor_decoder_reader.h"
-
-struct cbor_buf_reader {
-    struct cbor_decoder_reader r;
-    const uint8_t *buffer;
-};
-
-void cbor_buf_reader_init(struct cbor_buf_reader *cb, const uint8_t *buffer,
-                          size_t data);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CBOR_BUF_READER_H */
-
diff --git a/ext/tinycbor/src/cbor_buf_writer.c b/ext/tinycbor/src/cbor_buf_writer.c
deleted file mode 100644
index fb401bc..0000000
--- a/ext/tinycbor/src/cbor_buf_writer.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#include "cbor.h"
-#include "cbor_buf_writer.h"
-
-CBOR_INLINE_API int
-would_overflow(struct cbor_buf_writer *cb, size_t len)
-{
-    ptrdiff_t remaining = (ptrdiff_t)cb->end;
-
-    if (!remaining)
-        return 1;
-    remaining -= (ptrdiff_t)cb->ptr;
-    remaining -= (ptrdiff_t)len;
-    return (remaining < 0);
-}
-
-int
-cbor_buf_writer(struct cbor_encoder_writer *arg, const char *data, int len)
-{
-    struct cbor_buf_writer *cb = (struct cbor_buf_writer *) arg;
-
-    if (would_overflow(cb, len)) {
-        if (cb->end != NULL) {
-            len -= cb->end - cb->ptr;
-            cb->end = NULL;
-            cb->bytes_needed = 0;
-        }
-
-        cb->bytes_needed += len;
-
-        return CborErrorOutOfMemory;
-    }
-
-    memcpy(cb->ptr, data, len);
-    cb->ptr += len;
-    cb->enc.bytes_written += len;
-    return CborNoError;
-}
-
-void
-cbor_buf_writer_init(struct cbor_buf_writer *cb, uint8_t *buffer, size_t size)
-{
-    cb->ptr = buffer;
-    cb->end = buffer + size;
-    cb->enc.bytes_written = 0;
-    cb->bytes_needed = 0;
-    cb->enc.write = cbor_buf_writer;
-}
-
-size_t
-cbor_buf_writer_buffer_size(struct cbor_buf_writer *cb, const uint8_t *buffer)
-{
-    return (size_t)(cb->ptr - buffer);
-}
-
-size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder)
-{
-    struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer;
-
-    return wr->end ? 0 : (size_t)wr->bytes_needed;
-}
-
-size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer)
-{
-    struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer;
-
-    return (size_t)(wr->ptr - buffer);
-}
-
-uint8_t *_cbor_encoder_get_buffer_pointer(const CborEncoder *encoder)
-{
-    struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer;
-
-    return wr->ptr;
-}
-
diff --git a/ext/tinycbor/src/cbor_buf_writer.h b/ext/tinycbor/src/cbor_buf_writer.h
deleted file mode 100644
index f9f714f..0000000
--- a/ext/tinycbor/src/cbor_buf_writer.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_BUF_WRITER_H
-#define CBOR_BUF_WRITER_H
-
-#include "cbor_encoder_writer.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct cbor_buf_writer {
-    struct cbor_encoder_writer enc;
-    uint8_t *ptr;
-    const uint8_t *end;
-    int bytes_needed;
-};
-
-struct CborEncoder;
-
-void cbor_buf_writer_init(struct cbor_buf_writer *cb, uint8_t *buffer,
-                          size_t data);
-size_t cbor_buf_writer_buffer_size(struct cbor_buf_writer *cb,
-                                   const uint8_t *buffer);
-size_t cbor_encoder_get_extra_bytes_needed(const struct CborEncoder *encoder);
-size_t cbor_encoder_get_buffer_size(const struct CborEncoder *encoder,
-                                    const uint8_t *buffer);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CBOR_BUF_WRITER_H */
diff --git a/ext/tinycbor/src/cbor_cnt_writer.h b/ext/tinycbor/src/cbor_cnt_writer.h
deleted file mode 100644
index 7cf3464..0000000
--- a/ext/tinycbor/src/cbor_cnt_writer.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_CNT_WRITER_H
-#define CBOR_CNT_WRITER_H
-
-#include "cbor.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-    /* use this count writer if you want to try out a cbor encoding to see
-     * how long it would be (before allocating memory). This replaced the
-     * code in tinycbor.h that would try to do this once the encoding failed
-     * in a buffer.  Its much easier to understand this way (for me)
-     */
-
-struct CborCntWriter {
-    struct cbor_encoder_writer enc;
-};
-
-static inline int
-cbor_cnt_writer(struct cbor_encoder_writer *arg, const char *data, int len) {
-    struct CborCntWriter *cb = (struct CborCntWriter *) arg;
-    cb->enc.bytes_written += len;
-    return CborNoError;
-}
-
-static inline void
-cbor_cnt_writer_init(struct CborCntWriter *cb) {
-    cb->enc.bytes_written = 0;
-    cb->enc.write = &cbor_cnt_writer;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CBOR_CNT_WRITER_H */
-
diff --git a/ext/tinycbor/src/cbor_decoder_reader.h b/ext/tinycbor/src/cbor_decoder_reader.h
deleted file mode 100644
index c3ecaba..0000000
--- a/ext/tinycbor/src/cbor_decoder_reader.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_DECODER_WRITER_H
-#define CBOR_DECODER_WRITER_H
-
-#include <stdint.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct cbor_decoder_reader;
-
-typedef uint8_t (cbor_reader_get8)(struct cbor_decoder_reader *d, int offset);
-typedef uint16_t (cbor_reader_get16)(struct cbor_decoder_reader *d, int offset);
-typedef uint32_t (cbor_reader_get32)(struct cbor_decoder_reader *d, int offset);
-typedef uint64_t (cbor_reader_get64)(struct cbor_decoder_reader *d, int offset);
-typedef uintptr_t (cbor_memcmp)(struct cbor_decoder_reader *d, char *buf, int offset, size_t len);
-typedef uintptr_t (cbor_memcpy)(struct cbor_decoder_reader *d, char *buf, int offset, size_t len);
-typedef uintptr_t (cbor_get_string_chunk)(struct cbor_decoder_reader *d, int offset, size_t *len);
-
-struct cbor_decoder_reader {
-    cbor_reader_get8  *get8;
-    cbor_reader_get16 *get16;
-    cbor_reader_get32 *get32;
-    cbor_reader_get64 *get64;
-    cbor_memcmp       *cmp;
-    cbor_memcpy       *cpy;
-    cbor_get_string_chunk *get_string_chunk;
-    size_t             message_size;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/ext/tinycbor/src/cbor_defs.h b/ext/tinycbor/src/cbor_defs.h
deleted file mode 100644
index a4975c6..0000000
--- a/ext/tinycbor/src/cbor_defs.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_DEFS_H
-#define CBOR_DEFS_H
-
-#include <limits.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#ifndef SIZE_MAX
-/* Some systems fail to define SIZE_MAX in <stdint.h>, even though C99 requires it...
- * Conversion from signed to unsigned is defined in 6.3.1.3 (Signed and unsigned integers) p2,
- * which says: "the value is converted by repeatedly adding or subtracting one more than the
- * maximum value that can be represented in the new type until the value is in the range of the
- * new type."
- * So -1 gets converted to size_t by adding SIZE_MAX + 1, which results in SIZE_MAX.
- */
-#  define SIZE_MAX ((size_t)-1)
-#endif
-
-#ifndef CBOR_API
-#  define CBOR_API
-#endif
-#ifndef CBOR_PRIVATE_API
-#  define CBOR_PRIVATE_API
-#endif
-#ifndef CBOR_INLINE_API
-#  if defined(__cplusplus)
-#    define CBOR_INLINE inline
-#    define CBOR_INLINE_API inline
-#  else
-#    define CBOR_INLINE_API static CBOR_INLINE
-#    if defined(_MSC_VER)
-#      define CBOR_INLINE __inline
-#    elif defined(__GNUC__)
-#      define CBOR_INLINE __inline__
-#    elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-#      define CBOR_INLINE inline
-#    else
-#      define CBOR_INLINE
-#    endif
-#  endif
-#endif
-
-typedef enum CborType {
-    CborIntegerType     = 0x00,
-    CborByteStringType  = 0x40,
-    CborTextStringType  = 0x60,
-    CborArrayType       = 0x80,
-    CborMapType         = 0xa0,
-    CborTagType         = 0xc0,
-    CborSimpleType      = 0xe0,
-    CborBooleanType     = 0xf5,
-    CborNullType        = 0xf6,
-    CborUndefinedType   = 0xf7,
-    CborHalfFloatType   = 0xf9,
-    CborFloatType       = 0xfa,
-    CborDoubleType      = 0xfb,
-
-    CborInvalidType     = 0xff              /* equivalent to the break byte, so it will never be used */
-} CborType;
-
-typedef uint64_t CborTag;
-
-typedef enum CborKnownTags {
-    CborDateTimeStringTag          = 0,        /* RFC 3339 format: YYYY-MM-DD hh:mm:ss+zzzz */
-    CborUnixTime_tTag              = 1,
-    CborPositiveBignumTag          = 2,
-    CborNegativeBignumTag          = 3,
-    CborDecimalTag                 = 4,
-    CborBigfloatTag                = 5,
-    CborExpectedBase64urlTag       = 21,
-    CborExpectedBase64Tag          = 22,
-    CborExpectedBase16Tag          = 23,
-    CborUriTag                     = 32,
-    CborBase64urlTag               = 33,
-    CborBase64Tag                  = 34,
-    CborRegularExpressionTag       = 35,
-    CborMimeMessageTag             = 36,       /* RFC 2045-2047 */
-    CborSignatureTag               = 55799
-} CborKnownTags;
-
-/* #define the constants so we can check with #ifdef */
-#define CborDateTimeStringTag CborDateTimeStringTag
-#define CborUnixTime_tTag CborUnixTime_tTag
-#define CborPositiveBignumTag CborPositiveBignumTag
-#define CborNegativeBignumTag CborNegativeBignumTag
-#define CborDecimalTag CborDecimalTag
-#define CborBigfloatTag CborBigfloatTag
-#define CborCOSE_Encrypt0Tag CborCOSE_Encrypt0Tag
-#define CborCOSE_Mac0Tag CborCOSE_Mac0Tag
-#define CborCOSE_Sign1Tag CborCOSE_Sign1Tag
-#define CborExpectedBase64urlTag CborExpectedBase64urlTag
-#define CborExpectedBase64Tag CborExpectedBase64Tag
-#define CborExpectedBase16Tag CborExpectedBase16Tag
-#define CborEncodedCborTag CborEncodedCborTag
-#define CborUrlTag CborUrlTag
-#define CborBase64urlTag CborBase64urlTag
-#define CborBase64Tag CborBase64Tag
-#define CborRegularExpressionTag CborRegularExpressionTag
-#define CborMimeMessageTag CborMimeMessageTag
-#define CborCOSE_EncryptTag CborCOSE_EncryptTag
-#define CborCOSE_MacTag CborCOSE_MacTag
-#define CborCOSE_SignTag CborCOSE_SignTag
-#define CborSignatureTag CborSignatureTag
-
-/* Error API */
-
-typedef enum CborError {
-    CborNoError = 0,
-
-    /* errors in all modes */
-    CborUnknownError,
-    CborErrorUnknownLength,         /* request for length in array, map, or string with indeterminate length */
-    CborErrorAdvancePastEOF,
-    CborErrorIO,
-
-    /* parser errors streaming errors */
-    CborErrorGarbageAtEnd = 256,
-    CborErrorUnexpectedEOF,
-    CborErrorUnexpectedBreak,
-    CborErrorUnknownType,           /* can only heppen in major type 7 */
-    CborErrorIllegalType,           /* type not allowed here */
-    CborErrorIllegalNumber,
-    CborErrorIllegalSimpleType,     /* types of value less than 32 encoded in two bytes */
-
-    /* parser errors in strict mode parsing only */
-    CborErrorUnknownSimpleType = 512,
-    CborErrorUnknownTag,
-    CborErrorInappropriateTagForType,
-    CborErrorDuplicateObjectKeys,
-    CborErrorInvalidUtf8TextString,
-    CborErrorExcludedType,
-    CborErrorExcludedValue,
-    CborErrorImproperValue,
-    CborErrorOverlongEncoding,
-    CborErrorMapKeyNotString,
-    CborErrorMapNotSorted,
-    CborErrorMapKeysNotUnique,
-
-    /* encoder errors */
-    CborErrorTooManyItems = 768,
-    CborErrorTooFewItems,
-
-    /* internal implementation errors */
-    CborErrorDataTooLarge = 1024,
-    CborErrorNestingTooDeep,
-    CborErrorUnsupportedType,
-
-    /* errors in converting to JSON */
-    CborErrorJsonObjectKeyIsAggregate,
-    CborErrorJsonObjectKeyNotString,
-    CborErrorJsonNotImplemented,
-
-    CborErrorOutOfMemory = (int) (~0U / 2 + 1),
-    CborErrorInternalError = (int) (~0U / 2)    /* INT_MAX on two's complement machines */
-} CborError;
-
-/* Parser Flags */
-
-enum CborParserIteratorFlags
-{
-    CborIteratorFlag_IntegerValueTooLarge   = 0x01,
-    CborIteratorFlag_NegativeInteger        = 0x02,
-    CborIteratorFlag_IteratingStringChunks  = 0x02,
-    CborIteratorFlag_UnknownLength          = 0x04,
-    CborIteratorFlag_ContainerIsMap         = 0x20
-};
-
-enum CborValidationFlags {
-    /* Bit mapping:
-     *  bits 0-7 (8 bits):      canonical format
-     *  bits 8-11 (4 bits):     canonical format & strict mode
-     *  bits 12-20 (8 bits):    strict mode
-     *  bits 21-31 (10 bits):   other
-     */
-
-    CborValidateShortestIntegrals           = 0x0001,
-    CborValidateShortestFloatingPoint       = 0x0002,
-    CborValidateShortestNumbers             = CborValidateShortestIntegrals | CborValidateShortestFloatingPoint,
-    CborValidateNoIndeterminateLength       = 0x0100,
-    CborValidateMapIsSorted                 = 0x0200 | CborValidateNoIndeterminateLength,
-
-    CborValidateCanonicalFormat             = 0x0fff,
-
-    CborValidateMapKeysAreUnique            = 0x1000 | CborValidateMapIsSorted,
-    CborValidateTagUse                      = 0x2000,
-    CborValidateUtf8                        = 0x4000,
-
-    CborValidateStrictMode                  = 0xfff00,
-
-    CborValidateMapKeysAreString            = 0x100000,
-    CborValidateNoUndefined                 = 0x200000,
-    CborValidateNoTags                      = 0x400000,
-    CborValidateFiniteFloatingPoint         = 0x800000,
-    /* unused                               = 0x1000000, */
-    /* unused                               = 0x2000000, */
-
-    CborValidateNoUnknownSimpleTypesSA      = 0x4000000,
-    CborValidateNoUnknownSimpleTypes        = 0x8000000 | CborValidateNoUnknownSimpleTypesSA,
-    CborValidateNoUnknownTagsSA             = 0x10000000,
-    CborValidateNoUnknownTagsSR             = 0x20000000 | CborValidateNoUnknownTagsSA,
-    CborValidateNoUnknownTags               = 0x40000000 | CborValidateNoUnknownTagsSR,
-
-    CborValidateCompleteData                = (int)0x80000000,
-
-    CborValidateStrictest                   = (int)~0U,
-    CborValidateBasic                       = 0
-};
-
-static const size_t CborIndefiniteLength = SIZE_MAX;
-
-/* The following API requires a hosted C implementation (uses FILE*) */
-#if !defined(__STDC_HOSTED__) || __STDC_HOSTED__-0 == 1
-
-enum CborPrettyFlags {
-    CborPrettyNumericEncodingIndicators     = 0x01,
-    CborPrettyTextualEncodingIndicators     = 0,
-
-    CborPrettyIndicateIndetermineLength     = 0x02,
-    CborPrettyIndicateOverlongNumbers       = 0x04,
-
-    CborPrettyShowStringFragments           = 0x100,
-    CborPrettyMergeStringFragments          = 0,
-
-    CborPrettyDefaultFlags          = CborPrettyIndicateIndetermineLength
-};
-
-#endif /* __STDC_HOSTED__ check */
-
-#endif
diff --git a/ext/tinycbor/src/cbor_encoder_writer.h b/ext/tinycbor/src/cbor_encoder_writer.h
deleted file mode 100644
index 37fd399..0000000
--- a/ext/tinycbor/src/cbor_encoder_writer.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_ENCODER_H
-#define CBOR_ENCODER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct cbor_encoder_writer;
-
-typedef int (cbor_encoder_write)(struct cbor_encoder_writer *, const char *data, int len);
-
-typedef struct cbor_encoder_writer {
-    cbor_encoder_write *write;
-    int                 bytes_written;
-} cbor_encoder_writer;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CBOR_ENCODER_WRITER_H */
diff --git a/ext/tinycbor/src/cborencoder.c b/ext/tinycbor/src/cborencoder.c
deleted file mode 100644
index de66cad..0000000
--- a/ext/tinycbor/src/cborencoder.c
+++ /dev/null
@@ -1,627 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE 1
-#endif
-#ifndef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE 1
-#endif
-#ifndef __STDC_LIMIT_MACROS
-#  define __STDC_LIMIT_MACROS 1
-#endif
-
-#include "cbor.h"
-#include "cborinternal_p.h"
-#include "compilersupport_p.h"
-#include "cbor_buf_writer.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-/**
- * \defgroup CborEncoding Encoding to CBOR
- * \brief Group of functions used to encode data to CBOR.
- *
- * CborEncoder is used to encode data into a CBOR stream. The outermost
- * CborEncoder is initialized by calling cbor_encoder_init(), with the buffer
- * where the CBOR stream will be stored. The outermost CborEncoder is usually
- * used to encode exactly one item, most often an array or map. It is possible
- * to encode more than one item, but care must then be taken on the decoder
- * side to ensure the state is reset after each item was decoded.
- *
- * Nested CborEncoder objects are created using cbor_encoder_create_array() and
- * cbor_encoder_create_map(), later closed with cbor_encoder_close_container()
- * or cbor_encoder_close_container_checked(). The pairs of creation and closing
- * must be exactly matched and their parameters are always the same.
- *
- * CborEncoder writes directly to the user-supplied buffer, without extra
- * buffering. CborEncoder does not allocate memory and CborEncoder objects are
- * usually created on the stack of the encoding functions.
- *
- * The example below initializes a CborEncoder object with a buffer and encodes
- * a single integer.
- *
- * \code
- *      uint8_t buf[16];
- *      CborEncoder encoder;
- *      cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
- *      cbor_encode_int(&encoder, some_value);
- * \endcode
- *
- * As explained before, usually the outermost CborEncoder object is used to add
- * one array or map, which in turn contains multiple elements. The example
- * below creates a CBOR map with one element: a key "foo" and a boolean value.
- *
- * \code
- *      uint8_t buf[16];
- *      CborEncoder encoder, mapEncoder;
- *      cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
- *      cbor_encoder_create_map(&encoder, &mapEncoder, 1);
- *      cbor_encode_text_stringz(&mapEncoder, "foo");
- *      cbor_encode_boolean(&mapEncoder, some_value);
- *      cbor_encoder_close_container(&encoder, &mapEncoder);
- * \endcode
- *
- * <h3 class="groupheader">Error checking and buffer size</h2>
- *
- * All functions operating on CborEncoder return a condition of type CborError.
- * If the encoding was successful, they return CborNoError. Some functions do
- * extra checking on the input provided and may return some other error
- * conditions (for example, cbor_encode_simple_value() checks that the type is
- * of the correct type).
- *
- * In addition, all functions check whether the buffer has enough bytes to
- * encode the item being appended. If that is not possible, they return
- * CborErrorOutOfMemory.
- *
- * It is possible to continue with the encoding of data past the first function
- * that returns CborErrorOutOfMemory. CborEncoder functions will not overrun
- * the buffer, but will instead count how many more bytes are needed to
- * complete the encoding. At the end, you can obtain that count by calling
- * cbor_encoder_get_extra_bytes_needed().
- *
- * \section1 Finalizing the encoding
- *
- * Once all items have been appended and the containers have all been properly
- * closed, the user-supplied buffer will contain the CBOR stream and may be
- * immediately used. To obtain the size of the buffer, call
- * cbor_encoder_get_buffer_size() with the original buffer pointer.
- *
- * The example below illustrates how one can encode an item with error checking
- * and then pass on the buffer for network sending.
- *
- * \code
- *      uint8_t buf[16];
- *      CborError err;
- *      CborEncoder encoder, mapEncoder;
- *      cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
- *      err = cbor_encoder_create_map(&encoder, &mapEncoder, 1);
- *      if (!err)
- *          return err;
- *      err = cbor_encode_text_stringz(&mapEncoder, "foo");
- *      if (!err)
- *          return err;
- *      err = cbor_encode_boolean(&mapEncoder, some_value);
- *      if (!err)
- *          return err;
- *      err = cbor_encoder_close_container_checked(&encoder, &mapEncoder);
- *      if (!err)
- *          return err;
- *
- *      size_t len = cbor_encoder_get_buffer_size(&encoder, buf);
- *      send_payload(buf, len);
- *      return CborNoError;
- * \endcode
- *
- * Finally, the example below illustrates expands on the one above and also
- * deals with dynamically growing the buffer if the initial allocation wasn't
- * big enough. Note the two places where the error checking was replaced with
- * an cbor_assertion, showing where the author assumes no error can occur.
- *
- * \code
- * uint8_t *encode_string_array(const char **strings, int n, size_t *bufsize)
- * {
- *     CborError err;
- *     CborEncoder encoder, arrayEncoder;
- *     size_t size = 256;
- *     uint8_t *buf = NULL;
- *
- *     while (1) {
- *         int i;
- *         size_t more_bytes;
- *         uint8_t *nbuf = realloc(buf, size);
- *         if (nbuf == NULL)
- *             goto error;
- *         buf = nbuf;
- *
- *         cbor_encoder_init(&encoder, &buf, size, 0);
- *         err = cbor_encoder_create_array(&encoder, &arrayEncoder, n);
- *         cbor_assert(err);         // can't fail, the buffer is always big enough
- *
- *         for (i = 0; i < n; ++i) {
- *             err = cbor_encode_text_stringz(&arrayEncoder, strings[i]);
- *             if (err && err != CborErrorOutOfMemory)
- *                 goto error;
- *         }
- *
- *         err = cbor_encoder_close_container_checked(&encoder, &arrayEncoder);
- *         cbor_assert(err);         // shouldn't fail!
- *
- *         more_bytes = cbor_encoder_get_extra_bytes_needed(encoder);
- *         if (more_size) {
- *             // buffer wasn't big enough, try again
- *             size += more_bytes;
- *             continue;
- *         }
- *
- *         *bufsize = cbor_encoder_get_buffer_size(encoder, buf);
- *         return buf;
- *     }
- *  error:
- *     free(buf);
- *     return NULL;
- *  }
- * \endcode
- */
-
-/**
- * \addtogroup CborEncoding
- * @{
- */
-
-/**
- * \struct CborEncoder
- * Structure used to encode to CBOR.
- */
-
-#ifndef NO_DFLT_WRITER
-/**
- * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a
- * buffer of size \a size. The \a flags field is currently unused and must be
- * zero.
- */
-void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags)
-{
-    cbor_buf_writer_init(&encoder->wr, buffer, size);
-
-    cbor_encoder_cust_writer_init(encoder, &encoder->wr.enc, flags);
-}
-#endif
-
-/**
- * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a
- * buffer of size \a size. The \a flags field is currently unused and must be
- * zero.
- */
-void cbor_encoder_cust_writer_init(CborEncoder *encoder, struct cbor_encoder_writer *w, int flags)
-{
-    encoder->writer = w;
-    encoder->added = 0;
-    encoder->flags = flags;
-    encoder->container_size = 0;
-}
-
-
-#ifndef NO_FLOAT_SUPPORT
-static inline void put16(void *where, uint16_t v)
-{
-    v = cbor_htons(v);
-    memcpy(where, &v, sizeof(v));
-}
-#endif
-
-/* Note: Since this is currently only used in situations where OOM is the only
- * valid error, we KNOW this to be true.  Thus, this function now returns just 'true',
- * but if in the future, any function starts returning a non-OOM error, this will need
- * to be changed to the test.  At the moment, this is done to prevent more branches
- * being created in the tinycbor output */
-static inline bool isOomError(CborError err)
-{
-    (void) err;
-    return true;
-}
-
-#ifndef NO_FLOAT_SUPPORT
-static inline void put32(void *where, uint32_t v)
-{
-    v = cbor_htonl(v);
-    memcpy(where, &v, sizeof(v));
-}
-#endif
-
-static inline void put64(void *where, uint64_t v)
-{
-    v = cbor_htonll(v);
-    memcpy(where, &v, sizeof(v));
-}
-
-static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len)
-{
-    return (CborError)encoder->writer->write(encoder->writer, (const char *)data, len);
-}
-
-static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte)
-{
-    return append_to_buffer(encoder, &byte, 1);
-}
-
-static inline CborError encode_number_no_update(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
-{
-    /* Little-endian would have been so much more convenient here:
-     * We could just write at the beginning of buf but append_to_buffer
-     * only the necessary bytes.
-     * Since it has to be big endian, do it the other way around:
-     * write from the end. */
-    uint64_t buf[2];
-    uint8_t *const bufend = (uint8_t *)buf + sizeof(buf);
-    uint8_t *bufstart = bufend - 1;
-    put64(buf + 1, ui);     /* we probably have a bunch of zeros in the beginning */
-
-    if (ui < Value8Bit) {
-        *bufstart += shiftedMajorType;
-    } else {
-        uint8_t more = 0;
-        if (ui > 0xffU)
-            ++more;
-        if (ui > 0xffffU)
-            ++more;
-        if (ui > 0xffffffffU)
-            ++more;
-        bufstart -= (size_t)1 << more;
-        *bufstart = shiftedMajorType + Value8Bit + more;
-    }
-
-    return append_to_buffer(encoder, bufstart, bufend - bufstart);
-}
-
-static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
-{
-    ++encoder->added;
-    return encode_number_no_update(encoder, ui, shiftedMajorType);
-}
-
-/**
- * Appends the unsigned 64-bit integer \a value to the CBOR stream provided by
- * \a encoder.
- *
- * \sa cbor_encode_negative_int, cbor_encode_int
- */
-CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
-{
-    return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
-}
-
-/**
- * Appends the negative 64-bit integer whose absolute value is \a
- * absolute_value to the CBOR stream provided by \a encoder.
- *
- * \sa cbor_encode_uint, cbor_encode_int
- */
-CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value)
-{
-    return encode_number(encoder, absolute_value, NegativeIntegerType << MajorTypeShift);
-}
-
-/**
- * Appends the signed 64-bit integer \a value to the CBOR stream provided by
- * \a encoder.
- *
- * \sa cbor_encode_negative_int, cbor_encode_uint
- */
-CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
-{
-    /* adapted from code in RFC 7049 appendix C (pseudocode) */
-    uint64_t ui = value >> 63;              /* extend sign to whole length */
-    uint8_t majorType = ui & 0x20;          /* extract major type */
-    ui ^= value;                            /* complement negatives */
-    return encode_number(encoder, ui, majorType);
-}
-
-/**
- * Appends the CBOR Simple Type of value \a value to the CBOR stream provided by
- * \a encoder.
- *
- * This function may return error CborErrorIllegalSimpleType if the \a value
- * variable contains a number that is not a valid simple type.
- */
-CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
-{
-#ifndef CBOR_ENCODER_NO_CHECK_USER
-    /* check if this is a valid simple type */
-    if (value >= HalfPrecisionFloat && value <= Break)
-        return CborErrorIllegalSimpleType;
-#endif
-    return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
-}
-
-#ifndef NO_FLOAT_SUPPORT
-/**
- * Appends the floating-point value of type \a fpType and pointed to by \a
- * value to the CBOR stream provided by \a encoder. The value of \a fpType must
- * be one of CborHalfFloatType, CborFloatType or CborDoubleType, otherwise the
- * behavior of this function is undefined.
- *
- * This function is useful for code that needs to pass through floating point
- * values but does not wish to have the actual floating-point code.
- *
- * \sa cbor_encode_half_float, cbor_encode_float, cbor_encode_double
- */
-CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value)
-{
-    uint8_t buf[1 + sizeof(uint64_t)];
-    cbor_assert(fpType == CborHalfFloatType || fpType == CborFloatType || fpType == CborDoubleType);
-    buf[0] = fpType;
-
-    unsigned size = 2U << (fpType - CborHalfFloatType);
-    if (size == 8)
-        put64(buf + 1, *(const uint64_t*)value);
-    else if (size == 4)
-        put32(buf + 1, *(const uint32_t*)value);
-    else
-        put16(buf + 1, *(const uint16_t*)value);
-    ++encoder->added;
-    return append_to_buffer(encoder, buf, size + 1);
-}
-#endif
-
-/**
- * Appends the CBOR tag \a tag to the CBOR stream provided by \a encoder.
- *
- * \sa CborTag
- */
-CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
-{
-    /* tags don't count towards the number of elements in an array or map */
-    return encode_number_no_update(encoder, tag, TagType << MajorTypeShift);
-}
-
-static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string)
-{
-    CborError err = encode_number(encoder, length, shiftedMajorType);
-    if (err && !isOomError(err))
-        return err;
-    return append_to_buffer(encoder, string, length);
-}
-
-/**
- * \fn CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string)
- *
- * Appends the null-terminated text string \a string to the CBOR stream
- * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
- * TinyCBOR makes no verification of correctness. The terminating null is not
- * included in the stream.
- *
- * \sa cbor_encode_text_string, cbor_encode_byte_string
- */
-
-/**
- * Appends the text string \a string of length \a length to the CBOR stream
- * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
- * TinyCBOR makes no verification of correctness.
- *
- * \sa CborError cbor_encode_text_stringz, cbor_encode_byte_string
- */
-CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length)
-{
-    return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
-}
-
-/**
- * Appends the byte string \a string of length \a length to the CBOR stream
- * provided by \a encoder. CBOR byte strings are arbitrary raw data.
- *
- * \sa cbor_encode_text_stringz, cbor_encode_text_string
- */
-CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
-{
-    return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
-}
-
-#ifdef __GNUC__
-__attribute__((noinline))
-#endif
-static CborError create_container(CborEncoder *encoder, CborEncoder *container, size_t length, uint8_t shiftedMajorType)
-{
-    CborError err;
-    container->writer = encoder->writer;
-    ++encoder->added;
-    container->added = 0;
-    container->container_size = length;
-
-    cbor_static_assert(((MapType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == CborIteratorFlag_ContainerIsMap);
-    cbor_static_assert(((ArrayType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == 0);
-    container->flags = shiftedMajorType & CborIteratorFlag_ContainerIsMap;
-
-    if (length == CborIndefiniteLength) {
-        container->flags |= CborIteratorFlag_UnknownLength;
-        err = append_byte_to_buffer(container, shiftedMajorType + IndefiniteLength);
-    } else {
-        err = encode_number_no_update(container, length, shiftedMajorType);
-    }
-    return err;
-}
-
-/**
- * Creates a CBOR array in the CBOR stream provided by \a encoder and
- * initializes \a arrayEncoder so that items can be added to the array using
- * the CborEncoder functions. The array must be terminated by calling either
- * cbor_encoder_close_container() or cbor_encoder_close_container_checked()
- * with the same \a encoder and \a arrayEncoder parameters.
- *
- * The number of items inserted into the array must be exactly \a length items,
- * otherwise the stream is invalid. If the number of items is not known when
- * creating the array, the constant \ref CborIndefiniteLength may be passed as
- * length instead.
- *
- * \sa cbor_encoder_create_map
- */
-CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length)
-{
-    return create_container(encoder, arrayEncoder, length, ArrayType << MajorTypeShift);
-}
-
-/**
- * Creates a CBOR map in the CBOR stream provided by \a encoder and
- * initializes \a mapEncoder so that items can be added to the map using
- * the CborEncoder functions. The map must be terminated by calling either
- * cbor_encoder_close_container() or cbor_encoder_close_container_checked()
- * with the same \a encoder and \a mapEncoder parameters.
- *
- * The number of pair of items inserted into the map must be exactly \a length
- * items, otherwise the stream is invalid. If the number of items is not known
- * when creating the map, the constant \ref CborIndefiniteLength may be passed as
- * length instead.
- *
- * \b{Implementation limitation:} TinyCBOR cannot encode more than SIZE_MAX/2
- * key-value pairs in the stream. If the length \a length is larger than this
- * value, this function returns error CborErrorDataTooLarge.
- *
- * \sa cbor_encoder_create_array
- */
-CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length)
-{
-    if (length != CborIndefiniteLength && length > SIZE_MAX / 2)
-        return CborErrorDataTooLarge;
-    return create_container(encoder, mapEncoder, length, MapType << MajorTypeShift);
-}
-
-/**
- * Closes the CBOR container (array or map) provided by \a containerEncoder and
- * updates the CBOR stream provided by \a encoder. Both parameters must be the
- * same as were passed to cbor_encoder_create_array() or
- * cbor_encoder_create_map().
- *
- * This function does not verify that the number of items (or pair of items, in
- * the case of a map) was correct. To execute that verification, call
- * cbor_encoder_close_container_checked() instead.
- *
- * \sa cbor_encoder_create_array(), cbor_encoder_create_map()
- */
-CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder)
-{
-    size_t container_size;
-
-    encoder->writer = containerEncoder->writer;
-
-    if (containerEncoder->flags & CborIteratorFlag_UnknownLength) {
-        return append_byte_to_buffer(encoder, BreakByte);
-    } else {
-        container_size = containerEncoder->container_size;
-        if (containerEncoder->flags & CborIteratorFlag_ContainerIsMap) {
-            container_size = containerEncoder->container_size * 2;
-        }
-
-        return container_size == containerEncoder->added ? CborNoError :
-            container_size < containerEncoder->added ? CborErrorTooManyItems : CborErrorTooFewItems;
-    }
-}
-
-/**
- * \fn CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
- *
- * Appends the boolean value \a value to the CBOR stream provided by \a encoder.
- */
-
-/**
- * \fn CborError cbor_encode_null(CborEncoder *encoder)
- *
- * Appends the CBOR type representing a null value to the CBOR stream provided
- * by \a encoder.
- *
- * \sa cbor_encode_undefined()
- */
-
-/**
- * \fn CborError cbor_encode_undefined(CborEncoder *encoder)
- *
- * Appends the CBOR type representing an undefined value to the CBOR stream
- * provided by \a encoder.
- *
- * \sa cbor_encode_null()
- */
-
-/**
- * \fn CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
- *
- * Appends the IEEE 754 half-precision (16-bit) floating point value pointed to
- * by \a value to the CBOR stream provided by \a encoder.
- *
- * \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double()
- */
-
-/**
- * \fn CborError cbor_encode_float(CborEncoder *encoder, float value)
- *
- * Appends the IEEE 754 single-precision (32-bit) floating point value \a value
- * to the CBOR stream provided by \a encoder.
- *
- * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_double()
- */
-
-/**
- * \fn CborError cbor_encode_double(CborEncoder *encoder, double value)
- *
- * Appends the IEEE 754 double-precision (64-bit) floating point value \a value
- * to the CBOR stream provided by \a encoder.
- *
- * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float()
- */
-
-/**
- * \fn size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer)
- *
- * Returns the total size of the buffer starting at \a buffer after the
- * encoding finished without errors. The \a encoder and \a buffer arguments
- * must be the same as supplied to cbor_encoder_init().
- *
- * If the encoding process had errors, the return value of this function is
- * meaningless. If the only errors were CborErrorOutOfMemory, instead use
- * cbor_encoder_get_extra_bytes_needed() to find out by how much to grow the
- * buffer before encoding again.
- *
- * See \ref CborEncoding for an example of using this function.
- *
- * \sa cbor_encoder_init(), cbor_encoder_get_extra_bytes_needed(), CborEncoding
- */
-
-/**
- * \fn size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder)
- *
- * Returns how many more bytes the original buffer supplied to
- * cbor_encoder_init() needs to be extended by so that no CborErrorOutOfMemory
- * condition will happen for the encoding. If the buffer was big enough, this
- * function returns 0. The \a encoder must be the original argument as passed
- * to cbor_encoder_init().
- *
- * This function is usually called after an encoding sequence ended with one or
- * more CborErrorOutOfMemory errors, but no other error. If any other error
- * happened, the return value of this function is meaningless.
- *
- * See \ref CborEncoding for an example of using this function.
- *
- * \sa cbor_encoder_init(), cbor_encoder_get_buffer_size(), CborEncoding
- */
-
-/** @} */
diff --git a/ext/tinycbor/src/cborerrorstrings.c b/ext/tinycbor/src/cborerrorstrings.c
deleted file mode 100644
index 41319e4..0000000
--- a/ext/tinycbor/src/cborerrorstrings.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#include "cbor_defs.h"
-#include "cbor.h"
-
-#ifndef _
-#  define _(msg)    msg
-#endif
-
-/**
- * \enum CborError
- * \ingroup CborGlobals
- * The CborError enum contains the possible error values used by the CBOR encoder and decoder.
- *
- * TinyCBOR functions report success by returning CborNoError, or one error
- * condition by returning one of the values below. One exception is the
- * out-of-memory condition (CborErrorOutOfMemory), which the functions for \ref
- * CborEncoding may report in bit-wise OR with other conditions.
- *
- * This technique allows code to determine whether the only error condition was
- * a lack of buffer space, which may not be a fatal condition if the buffer can
- * be resized. Additionally, the functions for \ref CborEncoding may continue
- * to be used even after CborErrorOutOfMemory is returned, and instead they
- * will simply calculate the extra space needed.
- *
- * \value CborNoError                   No error occurred
- * \omitvalue CborUnknownError
- * \value CborErrorUnknownLength        Request for the length of an array, map or string whose length is not provided in the CBOR stream
- * \value CborErrorAdvancePastEOF       Not enough data in the stream to decode item (decoding would advance past end of stream)
- * \value CborErrorIO                   An I/O error occurred, probably due to an out-of-memory situation
- * \value CborErrorGarbageAtEnd         Bytes exist past the end of the CBOR stream
- * \value CborErrorUnexpectedEOF        End of stream reached unexpectedly
- * \value CborErrorUnexpectedBreak      A CBOR break byte was found where not expected
- * \value CborErrorUnknownType          An unknown type (future extension to CBOR) was found in the stream
- * \value CborErrorIllegalType          An invalid type was found while parsing a chunked CBOR string
- * \value CborErrorIllegalNumber        An illegal initial byte (encoding unspecified additional information) was found
- * \value CborErrorIllegalSimpleType    An illegal encoding of a CBOR Simple Type of value less than 32 was found
- * \omitvalue CborErrorUnknownSimpleType
- * \omitvalue CborErrorUnknownTag
- * \omitvalue CborErrorInappropriateTagForType
- * \omitvalue CborErrorDuplicateObjectKeys
- * \value CborErrorInvalidUtf8TextString Illegal UTF-8 encoding found while parsing CBOR Text String
- * \value CborErrorTooManyItems         Too many items were added to CBOR map or array of pre-determined length
- * \value CborErrorTooFewItems          Too few items were added to CBOR map or array of pre-determeined length
- * \value CborErrorDataTooLarge         Data item size exceeds TinyCBOR's implementation limits
- * \value CborErrorNestingTooDeep       Data item nesting exceeds TinyCBOR's implementation limits
- * \omitvalue CborErrorUnsupportedType
- * \value CborErrorJsonObjectKeyIsAggregate Conversion to JSON failed because the key in a map is a CBOR map or array
- * \value CborErrorJsonObjectKeyNotString Conversion to JSON failed because the key in a map is not a text string
- * \value CborErrorOutOfMemory          During CBOR encoding, the buffer provided is insufficient for encoding the data item;
- *                                      in other situations, TinyCBOR failed to allocate memory
- * \value CborErrorInternalError        An internal error occurred in TinyCBOR
- */
-
-/**
- * \ingroup CborGlobals
- * Returns the error string corresponding to the CBOR error condition \a error.
- */
-const char *cbor_error_string(CborError error)
-{
-    switch (error) {
-    case CborNoError:
-        return "";
-
-    case CborUnknownError:
-        return _("unknown error");
-
-    case CborErrorOutOfMemory:
-        return _("out of memory/need more memory");
-
-    case CborErrorUnknownLength:
-        return _("unknown length (attempted to get the length of a map/array/string of indeterminate length");
-
-    case CborErrorAdvancePastEOF:
-        return _("attempted to advance past EOF");
-
-    case CborErrorIO:
-        return _("I/O error");
-
-    case CborErrorGarbageAtEnd:
-        return _("garbage after the end of the content");
-
-    case CborErrorUnexpectedEOF:
-        return _("unexpected end of data");
-
-    case CborErrorUnexpectedBreak:
-        return _("unexpected 'break' byte");
-
-    case CborErrorUnknownType:
-        return _("illegal byte (encodes future extension type)");
-
-    case CborErrorIllegalType:
-        return _("mismatched string type in chunked string");
-
-    case CborErrorIllegalNumber:
-        return _("illegal initial byte (encodes unspecified additional information)");
-
-    case CborErrorIllegalSimpleType:
-        return _("illegal encoding of simple type smaller than 32");
-
-    case CborErrorUnknownSimpleType:
-        return _("unknown simple type");
-
-    case CborErrorUnknownTag:
-        return _("unknown tag");
-
-    case CborErrorInappropriateTagForType:
-        return _("inappropriate tag for type");
-
-    case CborErrorDuplicateObjectKeys:
-        return _("duplicate keys in object");
-
-    case CborErrorInvalidUtf8TextString:
-        return _("invalid UTF-8 content in string");
-
-    case CborErrorExcludedType:
-        return _("excluded type found");
-
-    case CborErrorExcludedValue:
-        return _("excluded value found");
-
-    case CborErrorImproperValue:
-    case CborErrorOverlongEncoding:
-        return _("value encoded in non-canonical form");
-
-    case CborErrorMapKeyNotString:
-    case CborErrorJsonObjectKeyNotString:
-        return _("key in map is not a string");
-
-    case CborErrorMapNotSorted:
-        return _("map is not sorted");
-
-    case CborErrorMapKeysNotUnique:
-        return _("map keys are not unique");
-
-    case CborErrorTooManyItems:
-        return _("too many items added to encoder");
-
-    case CborErrorTooFewItems:
-        return _("too few items added to encoder");
-
-    case CborErrorDataTooLarge:
-        return _("internal error: data too large");
-
-    case CborErrorNestingTooDeep:
-        return _("internal error: too many nested containers found in recursive function");
-
-    case CborErrorUnsupportedType:
-        return _("unsupported type");
-
-    case CborErrorJsonObjectKeyIsAggregate:
-        return _("conversion to JSON failed: key in object is an array or map");
-
-    case CborErrorJsonNotImplemented:
-        return _("conversion to JSON failed: open_memstream unavailable");
-
-    case CborErrorInternalError:
-        return _("internal error");
-    }
-    return cbor_error_string(CborUnknownError);
-}
diff --git a/ext/tinycbor/src/cborinternal_p.h b/ext/tinycbor/src/cborinternal_p.h
deleted file mode 100644
index ddeb2c2..0000000
--- a/ext/tinycbor/src/cborinternal_p.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBORINTERNAL_P_H
-#define CBORINTERNAL_P_H
-
-#include "compilersupport_p.h"
-
-#ifndef CBOR_INTERNAL_API
-#  define CBOR_INTERNAL_API
-#endif
-
-#ifndef CBOR_PARSER_MAX_RECURSIONS
-#  define CBOR_PARSER_MAX_RECURSIONS 1024
-#endif
-
-/*
- * CBOR Major types
- * Encoded in the high 3 bits of the descriptor byte
- * See http://tools.ietf.org/html/rfc7049#section-2.1
- */
-typedef enum CborMajorTypes {
-    UnsignedIntegerType = 0U,
-    NegativeIntegerType = 1U,
-    ByteStringType = 2U,
-    TextStringType = 3U,
-    ArrayType = 4U,
-    MapType = 5U,           /* a.k.a. object */
-    TagType = 6U,
-    SimpleTypesType = 7U
-} CborMajorTypes;
-
-/*
- * CBOR simple and floating point types
- * Encoded in the low 8 bits of the descriptor byte when the
- * Major Type is 7.
- */
-typedef enum CborSimpleTypes {
-    FalseValue              = 20,
-    TrueValue               = 21,
-    NullValue               = 22,
-    UndefinedValue          = 23,
-    SimpleTypeInNextByte    = 24,   /* not really a simple type */
-    HalfPrecisionFloat      = 25,   /* ditto */
-    SinglePrecisionFloat    = 26,   /* ditto */
-    DoublePrecisionFloat    = 27,   /* ditto */
-    Break                   = 31
-} CborSimpleTypes;
-
-enum {
-    SmallValueBitLength     = 5U,
-    SmallValueMask          = (1U << SmallValueBitLength) - 1,      /* 31 */
-    Value8Bit               = 24U,
-    Value16Bit              = 25U,
-    Value32Bit              = 26U,
-    Value64Bit              = 27U,
-    IndefiniteLength        = 31U,
-
-    MajorTypeShift          = SmallValueBitLength,
-    MajorTypeMask           = (int) (~0U << MajorTypeShift),
-
-    BreakByte               = (unsigned)Break | (SimpleTypesType << MajorTypeShift)
-};
-
-CBOR_INTERNAL_API CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const CborParser *p, int *offset, uint64_t *len);
-CBOR_INTERNAL_API CBOR_INTERNAL_API_CC CborError _cbor_value_prepare_string_iteration(CborValue *it);
-
-#endif /* CBORINTERNAL_P_H */
diff --git a/ext/tinycbor/src/cborjson.h b/ext/tinycbor/src/cborjson.h
deleted file mode 100644
index 8ff27b9..0000000
--- a/ext/tinycbor/src/cborjson.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBORJSON_H
-#define CBORJSON_H
-
-#include "cbor.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Conversion to JSON */
-enum CborToJsonFlags
-{
-    CborConvertAddMetadata = 1,
-    CborConvertTagsToObjects = 2,
-    CborConvertIgnoreTags = 0,
-
-    CborConvertObeyByteStringTags = 0,
-    CborConvertByteStringsToBase64Url = 4,
-
-    CborConvertRequireMapStringKeys = 0,
-    CborConvertStringifyMapKeys = 8,
-
-    CborConvertDefaultFlags = 0
-};
-
-CBOR_API CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags);
-CBOR_INLINE_API CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags)
-{
-    CborValue copy = *value;
-    return cbor_value_to_json_advance(out, &copy, flags);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CBORJSON_H */
-
diff --git a/ext/tinycbor/src/cborparser.c b/ext/tinycbor/src/cborparser.c
deleted file mode 100644
index a796f67..0000000
--- a/ext/tinycbor/src/cborparser.c
+++ /dev/null
@@ -1,1554 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE 1
-#endif
-#ifndef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE 1
-#endif
-#ifndef __STDC_LIMIT_MACROS
-#  define __STDC_LIMIT_MACROS 1
-#endif
-
-#include "cbor.h"
-#include "cborinternal_p.h"
-#include "compilersupport_p.h"
-
-#include <string.h>
-
-#include "cbor_buf_reader.h"
-
-#ifndef CBOR_PARSER_MAX_RECURSIONS
-#  define CBOR_PARSER_MAX_RECURSIONS 1024
-#endif
-
-/**
- * \defgroup CborParsing Parsing CBOR streams
- * \brief Group of functions used to parse CBOR streams.
- *
- * TinyCBOR provides functions for pull-based stream parsing of a CBOR-encoded
- * payload. The main data type for the parsing is a CborValue, which behaves
- * like an iterator and can be used to extract the encoded data. It is first
- * initialized with a call to cbor_parser_init() and is usually used to extract
- * exactly one item, most often an array or map.
- *
- * Nested CborValue objects can be parsed using cbor_value_enter_container().
- * Each call to cbor_value_enter_container() must be matched by a call to
- * cbor_value_leave_container(), with the exact same parameters.
- *
- * The example below initializes a CborParser object, begins the parsing with a
- * CborValue and decodes a single integer:
- *
- * \code
- * int extract_int(const uint8_t *buffer, size_t len)
- * {
- *     CborParser parser;
- *     CborValue value;
- *     int result;
- *     cbor_parser_init(buffer, len, 0, &buffer, &value);
- *     cbor_value_get_int(&value, &result);
- *     return result;
- * }
- * \endcode
- *
- * The code above does no error checking, which means it assumes the data comes
- * from a source trusted to send one properly-encoded integer. The following
- * example does the exact same operation, but includes error parsing and
- * returns 0 on parsing failure:
- *
- * \code
- * int extract_int(const uint8_t *buffer, size_t len)
- * {
- *     CborParser parser;
- *     CborValue value;
- *     int result;
- *     if (cbor_parser_init(buffer, len, 0, &buffer, &value) != CborNoError)
- *         return 0;
- *     if (!cbor_value_is_integer(&value) ||
- *             cbor_value_get_int(&value, &result) != CborNoError)
- *         return 0;
- *     return result;
- * }
- * \endcode
- *
- * Note, in the example above, that one can't distinguish a parsing failure
- * from an encoded value of zero. Reporting a parsing error is left as an
- * exercise to the reader.
- *
- * The code above does not execute a range-check either: it is possible that
- * the value decoded from the CBOR stream encodes a number larger than what can
- * be represented in a variable of type \c{int}. If detecting that case is
- * important, the code should call cbor_value_get_int_checked() instead.
- *
- * <h3 class="groupheader">Memory and parsing constraints</h3>
- *
- * TinyCBOR is designed to run with little memory and with minimal overhead.
- * Except where otherwise noted, the parser functions always run on constant
- * time (O(1)), do not recurse and never allocate memory (thus, stack usage is
- * bounded and is O(1)).
- *
- * <h3 class="groupheader">Error handling and preconditions</h3>
- *
- * All functions operating on a CborValue return a CborError condition, with
- * CborNoError standing for the normal situation in which no parsing error
- * occurred. All functions may return parsing errors in case the stream cannot
- * be decoded properly, be it due to corrupted data or due to reaching the end
- * of the input buffer.
- *
- * Error conditions must not be ignored. All decoder functions have undefined
- * behavior if called after an error has been reported, and may crash.
- *
- * Some functions are also documented to have preconditions, like
- * cbor_value_get_int() requiring that the input be an integral value.
- * Violation of preconditions also results in undefined behavior and the
- * program may crash.
- */
-
-/**
- * \addtogroup CborParsing
- * @{
- */
-
-/**
- * \struct CborValue
- *
- * This type contains one value parsed from the CBOR stream. Each CborValue
- * behaves as an iterator in a StAX-style parser.
- *
- * \if privatedocs
- * Implementation details: the CborValue contains these fields:
- * \list
- *   \li ptr: pointer to the actual data
- *   \li flags: flags from the decoder
- *   \li extra: partially decoded integer value (0, 1 or 2 bytes)
- *   \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
- * \endlist
- * \endif
- */
-
-CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const CborParser *p, int *offset, uint64_t *len)
-{
-    uint8_t additional_information = p->d->get8(p->d, *offset) & SmallValueMask;
-    ++*offset;
-    if (additional_information < Value8Bit) {
-        *len = additional_information;
-        return CborNoError;
-    }
-    if (unlikely(additional_information > Value64Bit))
-        return CborErrorIllegalNumber;
-
-    size_t bytesNeeded = (size_t)(1 << (additional_information - Value8Bit));
-    if (unlikely(bytesNeeded > (size_t)(p->end - *offset))) {
-        return CborErrorUnexpectedEOF;
-    } else if (bytesNeeded == 1) {
-        *len = p->d->get8(p->d, *offset);
-    } else if (bytesNeeded == 2) {
-        *len =  p->d->get16(p->d, *offset);
-    } else if (bytesNeeded == 4) {
-        *len =  p->d->get32(p->d, *offset);
-    } else {
-        *len =  p->d->get64(p->d, *offset);
-    }
-    *offset += bytesNeeded;
-    return CborNoError;
-}
-
-static CborError extract_length(const CborParser *parser,
-                                    int *offset, size_t *len)
-{
-    uint64_t v;
-    CborError err = _cbor_value_extract_number(parser, offset, &v);
-    if (err) {
-        *len = 0;
-        return err;
-    }
-
-    *len = (size_t)v;
-    if (v != *len)
-        return CborErrorDataTooLarge;
-    return CborNoError;
-}
-
-static bool is_fixed_type(uint8_t type)
-{
-    return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
-           type != CborMapType;
-}
-
-static CborError preparse_value(CborValue *it)
-{
-    const CborParser *parser = it->parser;
-    it->type = CborInvalidType;
-    /* are we at the end? */
-    if (it->offset == parser->end)
-        return CborErrorUnexpectedEOF;
-
-    uint8_t descriptor = parser->d->get8(parser->d, it->offset);
-    uint8_t type = descriptor & MajorTypeMask;
-    it->type = type;
-    it->flags = 0;
-    it->remainingclen = 0;
-    it->extra = (descriptor &= SmallValueMask);
-
-    size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
-
-    if (descriptor > Value64Bit) {
-        if (unlikely(descriptor != IndefiniteLength))
-            return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
-        if (likely(!is_fixed_type(type))) {
-            /* special case */
-            it->flags |= CborIteratorFlag_UnknownLength;
-            it->type = type;
-            return CborNoError;
-        }
-        return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
-    }
-
-    if (bytesNeeded + 1 > (size_t)(parser->end - it->offset))
-        return CborErrorUnexpectedEOF;
-
-    uint8_t majortype = type >> MajorTypeShift;
-    if (majortype == NegativeIntegerType) {
-        it->flags |= CborIteratorFlag_NegativeInteger;
-        it->type = CborIntegerType;
-    } else if (majortype == SimpleTypesType) {
-        switch (descriptor) {
-        case FalseValue:
-            it->extra = false;
-            it->type = CborBooleanType;
-            break;
-
-        case SinglePrecisionFloat:
-        case DoublePrecisionFloat:
-            it->flags |= CborIteratorFlag_IntegerValueTooLarge;
-            /* fall through */
-        case TrueValue:
-        case NullValue:
-        case UndefinedValue:
-        case HalfPrecisionFloat:
-            it->type = parser->d->get8(parser->d, it->offset);
-            break;
-
-        case SimpleTypeInNextByte:
-            it->extra = parser->d->get8(parser->d, it->offset + 1);
-#ifndef CBOR_PARSER_NO_STRICT_CHECKS
-            if (unlikely(it->extra < 32)) {
-                it->type = CborInvalidType;
-                return CborErrorIllegalSimpleType;
-            }
-#endif
-            break;
-
-        case 28:
-        case 29:
-        case 30:
-        case Break:
-            cbor_assert(false);  /* these conditions can't be reached */
-            return CborErrorUnexpectedBreak;
-        }
-        return CborNoError;
-    }
-
-    /* try to decode up to 16 bits */
-    if (descriptor < Value8Bit)
-        return CborNoError;
-
-    if (descriptor == Value8Bit)
-        it->extra = parser->d->get8(parser->d, it->offset + 1);
-    else if (descriptor == Value16Bit)
-        it->extra = parser->d->get16(parser->d, it->offset + 1);
-    else
-        it->flags |= CborIteratorFlag_IntegerValueTooLarge;     /* Value32Bit or Value64Bit */
-    return CborNoError;
-}
-
-static CborError preparse_next_value(CborValue *it)
-{
-    if (it->remaining != UINT32_MAX) {
-        /* don't decrement the item count if the current item is tag: they don't count */
-        if (it->type != CborTagType && !--it->remaining) {
-            it->type = CborInvalidType;
-            return CborNoError;
-        }
-    } else if (it->remaining == UINT32_MAX && it->offset != it->parser->end &&
-        it->parser->d->get8(it->parser->d, it->offset) == (uint8_t)BreakByte) {
-        /* end of map or array */
-        ++it->offset;
-        it->type = CborInvalidType;
-        it->remaining = 0;
-        return CborNoError;
-    }
-
-    return preparse_value(it);
-}
-
-static CborError advance_internal(CborValue *it)
-{
-    uint64_t length;
-    CborError err = _cbor_value_extract_number(it->parser, &it->offset,  &length);
-    cbor_assert(err == CborNoError);
-
-    if (it->type == CborByteStringType || it->type == CborTextStringType) {
-        cbor_assert(length == (size_t)length);
-        cbor_assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
-        it->offset += length;
-    }
-
-    return preparse_next_value(it);
-}
-
-/** \internal
- *
- * Decodes the CBOR integer value when it is larger than the 16 bits available
- * in value->extra. This function requires that value->flags have the
- * CborIteratorFlag_IntegerValueTooLarge flag set.
- *
- * This function is also used to extract single- and double-precision floating
- * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
- * Value64Bit).
- */
-uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
-{
-    uint8_t val = value->parser->d->get8(value->parser->d, value->offset);
-
-    cbor_assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
-           value->type == CborFloatType || value->type == CborDoubleType);
-
-    /* since the additional information can only be Value32Bit or Value64Bit,
-     * we just need to test for the one bit those two options differ */
-    cbor_assert((val & SmallValueMask) == Value32Bit || (val & SmallValueMask) == Value64Bit);
-    if ((val & 1) == (Value32Bit & 1))
-        return value->parser->d->get32(value->parser->d, value->offset + 1);
-
-    cbor_assert((val & SmallValueMask) == Value64Bit);
-        return value->parser->d->get64(value->parser->d, value->offset + 1);
-}
-
-#ifndef NO_DFLT_READER
-/**
- * Initializes the CBOR parser for parsing \a size bytes beginning at \a
- * buffer. Parsing will use flags set in \a flags. The iterator to the first
- * element is returned in \a it.
- *
- * The \a parser structure needs to remain valid throughout the decoding
- * process. It is not thread-safe to share one CborParser among multiple
- * threads iterating at the same time, but the object can be copied so multiple
- * threads can iterate.
- */
-CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
-{
-    memset(parser, 0, sizeof(*parser));
-
-    cbor_buf_reader_init(&parser->br, buffer, size);
-
-    return cbor_parser_cust_reader_init(&parser->br.r, flags, parser, it);
-}
-#endif
-
-/**
- * Initializes the CBOR parser for parsing. It uses the \a decoder reader. Parsing will
- * use flags set in \a flags. The iterator to the first element is returned in \a it.
- *
- * The \a parser structure needs to remain valid throughout the decoding
- * process. It is not thread-safe to share one CborParser among multiple
- * threads iterating at the same time, but the object can be copied so multiple
- * threads can iterate.
- */
-CborError cbor_parser_cust_reader_init(struct cbor_decoder_reader *r, int flags, CborParser *parser, CborValue *it)
-{
-    parser->d = r;
-    parser->end = r->message_size;
-    parser->flags = flags;
-    it->parser = parser;
-    it->offset = 0;
-    it->remaining = 1;/* there's one type altogether, usually an array or map */
-    return preparse_value(it);
-}
-
-/**
- * \fn bool cbor_value_at_end(const CborValue *it)
- *
- * Returns true if \a it has reached the end of the iteration, usually when
- * advancing after the last item in an array or map.
- *
- * In the case of the outermost CborValue object, this function returns true
- * after decoding a single element. A pointer to the first byte of the
- * remaining data (if any) can be obtained with cbor_value_get_next_byte().
- *
- * \sa cbor_value_advance(), cbor_value_is_valid(), cbor_value_get_next_byte()
- */
-
-/**
- * \fn const uint8_t *cbor_value_get_next_byte(const CborValue *it)
- *
- * Returns a pointer to the next byte that would be decoded if this CborValue
- * object were advanced.
- *
- * This function is useful if cbor_value_at_end() returns true for the
- * outermost CborValue: the pointer returned is the first byte of the data
- * remaining in the buffer, if any. Code can decide whether to begin decoding a
- * new CBOR data stream from this point, or parse some other data appended to
- * the same buffer.
- *
- * This function may be used even after a parsing error. If that occurred,
- * then this function returns a pointer to where the parsing error occurred.
- * Note that the error recovery is not precise and the pointer may not indicate
- * the exact byte containing bad data.
- *
- * \sa cbor_value_at_end()
- */
-
-/**
- * \fn bool cbor_value_is_valid(const CborValue *it)
- *
- * Returns true if the iterator \a it contains a valid value. Invalid iterators
- * happen when iteration reaches the end of a container (see \ref
- * cbor_value_at_end()) or when a search function resulted in no matches.
- *
- * \sa cbor_value_advance(), cbor_valie_at_end(), cbor_value_get_type()
- */
-
-/**
- * Performs a basic validation of the CBOR stream pointed by \a it and returns
- * the error it found. If no error was found, it returns CborNoError and the
- * application can iterate over the items with certainty that no other errors
- * will appear during parsing.
- *
- * A basic validation checks for:
- * \list
- *   \li absence of undefined additional information bytes;
- *   \li well-formedness of all numbers, lengths, and simple values;
- *   \li string contents match reported sizes;
- *   \li arrays and maps contain the number of elements they are reported to have;
- * \endlist
- *
- * For further checks, see cbor_value_validate().
- *
- * This function has the same timing and memory requirements as
- * cbor_value_advance().
- *
- * \sa cbor_value_validate(), cbor_value_advance()
- */
-CborError cbor_value_validate_basic(const CborValue *it)
-{
-    CborValue value = *it;
-    return cbor_value_advance(&value);
-}
-
-/**
- * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
- * are: integers, tags, simple types (including boolean, null and undefined
- * values) and floating point types.
- *
- * If the type is not of fixed size, this function has undefined behavior. Code
- * must be sure that the current type is one of the fixed-size types before
- * calling this function. This function is provided because it can guarantee
- * that runs in constant time (O(1)).
- *
- * If the caller is not able to determine whether the type is fixed or not, code
- * can use the cbor_value_advance() function instead.
- *
- * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_enter_container(), cbor_value_leave_container()
- */
-CborError cbor_value_advance_fixed(CborValue *it)
-{
-    cbor_assert(it->type != CborInvalidType);
-    cbor_assert(is_fixed_type(it->type));
-    if (!it->remaining)
-        return CborErrorAdvancePastEOF;
-    return advance_internal(it);
-}
-
-static CborError advance_recursive(CborValue *it, int nestingLevel)
-{
-    if (is_fixed_type(it->type))
-        return advance_internal(it);
-
-    if (!cbor_value_is_container(it)) {
-        size_t len = SIZE_MAX;
-        return _cbor_value_copy_string(it, NULL, &len, it);
-    }
-
-    /* map or array */
-    if (nestingLevel == 0)
-        return CborErrorNestingTooDeep;
-
-    CborError err;
-    CborValue recursed;
-    err = cbor_value_enter_container(it, &recursed);
-    if (err)
-        return err;
-    while (!cbor_value_at_end(&recursed)) {
-        err = advance_recursive(&recursed, nestingLevel - 1);
-        if (err)
-            return err;
-    }
-    return cbor_value_leave_container(it, &recursed);
-}
-
-
-/**
- * Advances the CBOR value \a it by one element, skipping over containers.
- * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
- * value of any type. However, if the type is a container (map or array) or a
- * string with a chunked payload, this function will not run in constant time
- * and will recurse into itself (it will run on O(n) time for the number of
- * elements or chunks and will use O(n) memory for the number of nested
- * containers).
- *
- * The number of recursions can be limited at compile time to avoid stack
- * exhaustion in constrained systems.
- *
- * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_enter_container(), cbor_value_leave_container()
- */
-CborError cbor_value_advance(CborValue *it)
-{
-    cbor_assert(it->type != CborInvalidType);
-    if (!it->remaining)
-        return CborErrorAdvancePastEOF;
-    return advance_recursive(it, CBOR_PARSER_MAX_RECURSIONS);
-}
-
-/**
- * \fn bool cbor_value_is_tag(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR tag.
- *
- * \sa cbor_value_get_tag(), cbor_value_skip_tag()
- */
-
-/**
- * \fn CborError cbor_value_get_tag(const CborValue *value, CborTag *result)
- *
- * Retrieves the CBOR tag value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to a CBOR tag value, the
- * behavior is undefined, so checking with \ref cbor_value_get_type or with
- * \ref cbor_value_is_tag is recommended.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_tag()
- */
-
-/**
- * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
- * already not pointing to a tag, then this function returns it unchanged.
- *
- * This function does not run in constant time: it will run on O(n) for n being
- * the number of tags. It does use constant memory (O(1) memory requirements).
- *
- * \sa cbor_value_advance_fixed(), cbor_value_advance()
- */
-CborError cbor_value_skip_tag(CborValue *it)
-{
-    while (cbor_value_is_tag(it)) {
-        CborError err = cbor_value_advance_fixed(it);
-        if (err)
-            return err;
-    }
-    return CborNoError;
-}
-
-/**
- * \fn bool cbor_value_is_container(const CborValue *it)
- *
- * Returns true if the \a it value is a container and requires recursion in
- * order to decode (maps and arrays), false otherwise.
- */
-
-/**
- * Creates a CborValue iterator pointing to the first element of the container
- * represented by \a it and saves it in \a recursed. The \a it container object
- * needs to be kept and passed again to cbor_value_leave_container() in order
- * to continue iterating past this container.
- *
- * The \a it CborValue iterator must point to a container.
- *
- * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
- */
-CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
-{
-    CborError err;
-    cbor_assert(cbor_value_is_container(it));
-    *recursed = *it;
-
-    if (it->flags & CborIteratorFlag_UnknownLength) {
-        recursed->remaining = UINT32_MAX;
-        ++recursed->offset;
-        err = preparse_value(recursed);
-        if (err != CborErrorUnexpectedBreak)
-            return err;
-        /* actually, break was expected here
-         * it's just an empty container */
-        ++recursed->offset;
-    } else {
-        uint64_t len;
-        err = _cbor_value_extract_number(recursed->parser, &recursed->offset, &len);
-        cbor_assert(err == CborNoError);
-
-        recursed->remaining = (uint32_t)len;
-        if (recursed->remaining != len || len == UINT32_MAX) {
-            /* back track the pointer to indicate where the error occurred */
-            recursed->offset = it->offset;
-            return CborErrorDataTooLarge;
-        }
-        if (recursed->type == CborMapType) {
-            /* maps have keys and values, so we need to multiply by 2 */
-            if (recursed->remaining > UINT32_MAX / 2) {
-                /* back track the pointer to indicate where the error occurred */
-                recursed->offset = it->offset;
-                return CborErrorDataTooLarge;
-            }
-            recursed->remaining *= 2;
-        }
-        if (len != 0)
-            return preparse_value(recursed);
-    }
-
-    /* the case of the empty container */
-    recursed->type = CborInvalidType;
-    recursed->remaining = 0;
-    return CborNoError;
-}
-
-/**
- * Updates \a it to point to the next element after the container. The \a
- * recursed object needs to point to the element obtained either by advancing
- * the last element of the container (via cbor_value_advance(),
- * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
- * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
- *
- * The \a it and \a recursed parameters must be the exact same as passed to
- * cbor_value_enter_container().
- *
- * \sa cbor_value_enter_container(), cbor_value_at_end()
- */
-CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
-{
-    cbor_assert(cbor_value_is_container(it));
-    cbor_assert(recursed->type == CborInvalidType);
-    it->offset = recursed->offset;
-
-    return preparse_next_value(it);
-}
-
-
-/**
- * \fn CborType cbor_value_get_type(const CborValue *value)
- *
- * Returns the type of the CBOR value that the iterator \a value points to. If
- * \a value does not point to a valid value, this function returns \ref
- * CborInvalidType.
- *
- * TinyCBOR also provides functions to test directly if a given CborValue object
- * is of a given type, like cbor_value_is_text_string() and cbor_value_is_null().
- *
- * \sa cbor_value_is_valid()
- */
-
-/**
- * \fn bool cbor_value_is_null(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR null type.
- *
- * \sa cbor_value_is_valid(), cbor_value_is_undefined()
- */
-
-/**
- * \fn bool cbor_value_is_undefined(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR undefined type.
- *
- * \sa cbor_value_is_valid(), cbor_value_is_null()
- */
-
-/**
- * \fn bool cbor_value_is_boolean(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR boolean
- * type (true or false).
- *
- * \sa cbor_value_is_valid(), cbor_value_get_boolean()
- */
-
-/**
- * \fn CborError cbor_value_get_boolean(const CborValue *value, bool *result)
- *
- * Retrieves the boolean value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to a boolean value, the
- * behavior is undefined, so checking with \ref cbor_value_get_type or with
- * \ref cbor_value_is_boolean is recommended.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_boolean()
- */
-
-/**
- * \fn bool cbor_value_is_simple_type(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR Simple Type
- * type (other than true, false, null and undefined).
- *
- * \sa cbor_value_is_valid(), cbor_value_get_simple_type()
- */
-
-/**
- * \fn CborError cbor_value_get_simple_type(const CborValue *value, uint8_t *result)
- *
- * Retrieves the CBOR Simple Type value that \a value points to and stores it
- * in \a result. If the iterator \a value does not point to a simple_type
- * value, the behavior is undefined, so checking with \ref cbor_value_get_type
- * or with \ref cbor_value_is_simple_type is recommended.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_simple_type()
- */
-
-/**
- * \fn bool cbor_value_is_integer(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR integer
- * type.
- *
- * \sa cbor_value_is_valid(), cbor_value_get_int, cbor_value_get_int64, cbor_value_get_uint64, cbor_value_get_raw_integer
- */
-
-/**
- * \fn bool cbor_value_is_unsigned_integer(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR unsigned
- * integer type (positive values or zero).
- *
- * \sa cbor_value_is_valid(), cbor_value_get_uint64()
- */
-
-/**
- * \fn bool cbor_value_is_negative_integer(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR negative
- * integer type.
- *
- * \sa cbor_value_is_valid(), cbor_value_get_int, cbor_value_get_int64, cbor_value_get_raw_integer
- */
-
-/**
- * \fn CborError cbor_value_get_int(const CborValue *value, int *result)
- *
- * Retrieves the CBOR integer value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to an integer value, the
- * behavior is undefined, so checking with \ref cbor_value_get_type or with
- * \ref cbor_value_is_integer is recommended.
- *
- * Note that this function does not do range-checking: integral values that do
- * not fit in a variable of type \c{int} are silently truncated to fit. Use
- * cbor_value_get_int_checked() that is not acceptable.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer()
- */
-
-/**
- * \fn CborError cbor_value_get_int64(const CborValue *value, int64_t *result)
- *
- * Retrieves the CBOR integer value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to an integer value, the
- * behavior is undefined, so checking with \ref cbor_value_get_type or with
- * \ref cbor_value_is_integer is recommended.
- *
- * Note that this function does not do range-checking: integral values that do
- * not fit in a variable of type \c{int64_t} are silently truncated to fit. Use
- * cbor_value_get_int64_checked() that is not acceptable.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer()
- */
-
-/**
- * \fn CborError cbor_value_get_uint64(const CborValue *value, uint64_t *result)
- *
- * Retrieves the CBOR integer value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to an unsigned integer
- * value, the behavior is undefined, so checking with \ref cbor_value_get_type
- * or with \ref cbor_value_is_unsigned_integer is recommended.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_unsigned_integer()
- */
-
-/**
- * \fn CborError cbor_value_get_raw_integer(const CborValue *value, uint64_t *result)
- *
- * Retrieves the CBOR integer value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to an integer value, the
- * behavior is undefined, so checking with \ref cbor_value_get_type or with
- * \ref cbor_value_is_integer is recommended.
- *
- * This function is provided because CBOR negative integers can assume values
- * that cannot be represented with normal 64-bit integer variables.
- *
- * If the integer is unsigned (that is, if cbor_value_is_unsigned_integer()
- * returns true), then \a result will contain the actual value. If the integer
- * is negative, then \a result will contain the absolute value of that integer,
- * minus one. That is, \c {actual = -result - 1}. On architectures using two's
- * complement for representation of negative integers, it is equivalent to say
- * that \a result will contain the bitwise negation of the actual value.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer()
- */
-
-/**
- * Retrieves the CBOR integer value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to an integer value, the
- * behavior is undefined, so checking with \ref cbor_value_get_type or with
- * \ref cbor_value_is_integer is recommended.
- *
- * Unlike cbor_value_get_int64(), this function performs a check to see if the
- * stored integer fits in \a result without data loss. If the number is outside
- * the valid range for the data type, this function returns the recoverable
- * error CborErrorDataTooLarge. In that case, use either
- * cbor_value_get_uint64() (if the number is positive) or
- * cbor_value_get_raw_integer().
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer(), cbor_value_get_int64()
- */
-CborError cbor_value_get_int64_checked(const CborValue *value, int64_t *result)
-{
-    cbor_assert(cbor_value_is_integer(value));
-    uint64_t v = _cbor_value_extract_int64_helper(value);
-
-    /* Check before converting, as the standard says (C11 6.3.1.3 paragraph 3):
-     * "[if] the new type is signed and the value cannot be represented in it; either the
-     *  result is implementation-defined or an implementation-defined signal is raised."
-     *
-     * The range for int64_t is -2^63 to 2^63-1 (int64_t is required to be
-     * two's complement, C11 7.20.1.1 paragraph 3), which in CBOR is
-     * represented the same way, differing only on the "sign bit" (the major
-     * type).
-     */
-
-    if (unlikely(v > (uint64_t)INT64_MAX))
-        return CborErrorDataTooLarge;
-
-    *result = v;
-    if (value->flags & CborIteratorFlag_NegativeInteger)
-        *result = -*result - 1;
-    return CborNoError;
-}
-
-/**
- * Retrieves the CBOR integer value that \a value points to and stores it in \a
- * result. If the iterator \a value does not point to an integer value, the
- * behavior is undefined, so checking with \ref cbor_value_get_type or with
- * \ref cbor_value_is_integer is recommended.
- *
- * Unlike cbor_value_get_int(), this function performs a check to see if the
- * stored integer fits in \a result without data loss. If the number is outside
- * the valid range for the data type, this function returns the recoverable
- * error CborErrorDataTooLarge. In that case, use one of the other integer
- * functions to obtain the value.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer(), cbor_value_get_int64(),
- *     cbor_value_get_uint64(), cbor_value_get_int64_checked(), cbor_value_get_raw_integer()
- */
-CborError cbor_value_get_int_checked(const CborValue *value, int *result)
-{
-    cbor_assert(cbor_value_is_integer(value));
-    uint64_t v = _cbor_value_extract_int64_helper(value);
-
-    /* Check before converting, as the standard says (C11 6.3.1.3 paragraph 3):
-     * "[if] the new type is signed and the value cannot be represented in it; either the
-     *  result is implementation-defined or an implementation-defined signal is raised."
-     *
-     * But we can convert from signed to unsigned without fault (paragraph 2).
-     *
-     * The range for int is implementation-defined and int is not guaranteed use
-     * two's complement representation (int32_t is).
-     */
-
-    if (value->flags & CborIteratorFlag_NegativeInteger) {
-        if (unlikely(v > (unsigned) -(INT_MIN + 1)))
-            return CborErrorDataTooLarge;
-
-        *result = (int)v;
-        *result = -*result - 1;
-    } else {
-        if (unlikely(v > (uint64_t)INT_MAX))
-            return CborErrorDataTooLarge;
-
-        *result = (int)v;
-    }
-    return CborNoError;
-
-}
-
-/**
- * \fn bool cbor_value_is_length_known(const CborValue *value)
- *
- * Returns true if the length of this type is known without calculation. That
- * is, if the length of this CBOR string, map or array is encoded in the data
- * stream, this function returns true. If the length is not encoded, it returns
- * false.
- *
- * If the length is known, code can call cbor_value_get_string_length(),
- * cbor_value_get_array_length() or cbor_value_get_map_length() to obtain the
- * length. If the length is not known but is necessary, code can use the
- * cbor_value_calculate_string_length() function (no equivalent function is
- * provided for maps and arrays).
- */
-
-/**
- * \fn bool cbor_value_is_text_string(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR text
- * string. CBOR text strings are UTF-8 encoded and usually contain
- * human-readable text.
- *
- * \sa cbor_value_is_valid(), cbor_value_get_string_length(), cbor_value_calculate_string_length(),
- *     cbor_value_copy_text_string(), cbor_value_dup_text_string()
- */
-
-/**
- * \fn bool cbor_value_is_byte_string(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR text
- * string. CBOR byte strings are binary data with no specified encoding or
- * format.
- *
- * \sa cbor_value_is_valid(), cbor_value_get_string_length(), cbor_value_calculate_string_length(),
- *     cbor_value_copy_byte_string(), cbor_value_dup_byte_string()
- */
-
-/**
- * \fn CborError cbor_value_get_string_length(const CborValue *value, size_t *length)
- *
- * Extracts the length of the byte or text string that \a value points to and
- * stores it in \a result. If the iterator \a value does not point to a text
- * string or a byte string, the behaviour is undefined, so checking with \ref
- * cbor_value_get_type, with \ref cbor_value_is_text_string or \ref
- * cbor_value_is_byte_string is recommended.
- *
- * If the length of this string is not encoded in the CBOR data stream, this
- * function will return the recoverable error CborErrorUnknownLength. You may
- * also check whether that is the case by using cbor_value_is_length_known().
- *
- * If the length of the string is required but the length was not encoded, use
- * cbor_value_calculate_string_length(), but note that that function does not
- * run in constant time.
- *
- * \note On 32-bit platforms, this function will return error condition of \ref
- * CborErrorDataTooLarge if the stream indicates a length that is too big to
- * fit in 32-bit.
- *
- * \sa cbor_value_is_valid(), cbor_value_is_length_known(), cbor_value_calculate_string_length()
- */
-
-/**
- * Calculates the length of the byte or text string that \a value points to and
- * stores it in \a len. If the iterator \a value does not point to a text
- * string or a byte string, the behaviour is undefined, so checking with \ref
- * cbor_value_get_type, with \ref cbor_value_is_text_string or \ref
- * cbor_value_is_byte_string is recommended.
- *
- * This function is different from cbor_value_get_string_length() in that it
- * calculates the length even for strings sent in chunks. For that reason, this
- * function may not run in constant time (it will run in O(n) time on the
- * number of chunks). It does use constant memory (O(1)).
- *
- * \note On 32-bit platforms, this function will return error condition of \ref
- * CborErrorDataTooLarge if the stream indicates a length that is too big to
- * fit in 32-bit.
- *
- * \sa cbor_value_get_string_length(), cbor_value_copy_text_string(), cbor_value_copy_byte_string(), cbor_value_is_length_known()
- */
-CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
-{
-    *len = SIZE_MAX;
-    return _cbor_value_copy_string(value, NULL, len, NULL);
-}
-
-static inline void prepare_string_iteration(CborValue *it)
-{
-    if (!cbor_value_is_length_known(it)) {
-        /* chunked string: we're before the first chunk;
-         * advance to the first chunk */
-        ++it->offset;
-        it->flags |= CborIteratorFlag_IteratingStringChunks;
-    }
-}
-
-CBOR_INTERNAL_API_CC CborError _cbor_value_prepare_string_iteration(CborValue *it)
-{
-    cbor_assert((it->flags & CborIteratorFlag_IteratingStringChunks) == 0);
-    prepare_string_iteration(it);
-
-    /* are we at the end? */
-    if (it->offset == it->parser->end)
-        return CborErrorUnexpectedEOF;
-
-    return CborNoError;
-}
-
-static const void *
-get_string_chunk_update(CborValue *it, const void **bufferptr, size_t *len)
-{
-    *bufferptr = (const void *)it->parser->d->get_string_chunk(it->parser->d,
-                 it->offset, len);
-    it->offset += *len;
-    it->remainingclen -= *len;
-
-    return *bufferptr;
-}
-
-static CborError get_string_chunk(CborValue *it, const void **bufferptr, size_t *len)
-{
-    CborError err;
-
-
-    if (it->remainingclen) {
-        *len = it->remainingclen;
-
-        *bufferptr = get_string_chunk_update(it, bufferptr, len);
-
-        return CborNoError;
-    }
-
-    /* Possible states:
-     * length known | iterating | meaning
-     *     no       |    no     | before the first chunk of a chunked string
-     *     yes      |    no     | at a non-chunked string
-     *     no       |    yes    | second or later chunk
-     *     yes      |    yes    | after a non-chunked string
-     */
-    if (it->flags & CborIteratorFlag_IteratingStringChunks) {
-        /* already iterating */
-        if (cbor_value_is_length_known(it)) {
-            /* if the length was known, it wasn't chunked, so finish iteration */
-            goto last_chunk;
-        }
-    } else {
-        prepare_string_iteration(it);
-    }
-
-    uint8_t val;
-
-    val = it->parser->d->get8(it->parser->d, it->offset);
-
-    /* are we at the end? */
-    if (it->offset == it->parser->end)
-        return CborErrorUnexpectedEOF;
-
-    if (val == (uint8_t)BreakByte) {
-        /* last chunk */
-        ++it->offset;
-last_chunk:
-        *bufferptr = NULL;
-        *len = 0;
-        it->remainingclen = 0;
-        return preparse_next_value(it);
-    } else if ((val & MajorTypeMask) == it->type) {
-        err = extract_length(it->parser, &it->offset, len);
-        if (err)
-            return err;
-
-        if (*len > (size_t)(it->parser->end - it->offset))
-            return CborErrorUnexpectedEOF;
-
-        it->remainingclen = *len;
-
-        *bufferptr = get_string_chunk_update(it, bufferptr, len);
-
-    } else {
-        return CborErrorIllegalType;
-    }
-
-    it->flags |= CborIteratorFlag_IteratingStringChunks;
-    return CborNoError;
-}
-
-/**
- * \fn CborError cbor_value_get_text_string_chunk(const CborValue *value, const char **bufferptr, size_t *len, CborValue *next)
- *
- * Extracts one text string chunk pointed to by \a value and stores a pointer
- * to the data in \a buffer and the size in \a len, which must not be null. If
- * no more chunks are available, then \a bufferptr will be set to null. This
- * function may be used to iterate over any string without causing its contents
- * to be copied to a separate buffer, like the convenience function
- * cbor_value_copy_text_string() does.
- *
- * It is designed to be used in code like:
- *
- * \code
- *   if (cbor_value_is_text_string(value)) {
- *       char *ptr;
- *       size_t len;
- *       while (1) {
- *           err = cbor_value_get_text_string_chunk(value, &ptr, &len, &value));
- *           if (err) return err;
- *           if (ptr == NULL) return CborNoError;
- *           consume(ptr, len);
- *       }
- *   }
- * \endcode
- *
- * If the iterator \a value does not point to a text string, the behaviour is
- * undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_text_string is recommended.
- *
- * The \a next pointer, if not null, will be updated to point to the next item
- * after this string. During iteration, the pointer must only be passed back
- * again to this function; passing it to any other function in this library
- * results in undefined behavior. If there are no more chunks to be read from
- * \a value, then \a next will be set to the next item after this string; if \a
- * value points to the last item, then \a next will be invalid.
- *
- * \note This function does not perform UTF-8 validation on the incoming text
- * string.
- *
- * \sa cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_caculate_string_length(), cbor_value_get_byte_string_chunk()
- */
-
-/**
- * \fn CborError cbor_value_get_byte_string_chunk(const CborValue *value, const char **bufferptr, size_t *len, CborValue *next)
- *
- * Extracts one byte string chunk pointed to by \a value and stores a pointer
- * to the data in \a buffer and the size in \a len, which must not be null. If
- * no more chunks are available, then \a bufferptr will be set to null. This
- * function may be used to iterate over any string without causing its contents
- * to be copied to a separate buffer, like the convenience function
- * cbor_value_copy_byte_string() does.
- *
- * It is designed to be used in code like:
- *
- * \code
- *   if (cbor_value_is_byte_string(value)) {
- *       char *ptr;
- *       size_t len;
- *       while (1) {
- *           err = cbor_value_get_byte_string_chunk(value, &ptr, &len, &value));
- *           if (err) return err;
- *           if (ptr == NULL) return CborNoError;
- *           consume(ptr, len);
- *       }
- *   }
- * \endcode
- *
- * If the iterator \a value does not point to a byte string, the behaviour is
- * undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_byte_string is recommended.
- *
- * The \a next pointer, if not null, will be updated to point to the next item
- * after this string. During iteration, the pointer must only be passed back
- * again to this function; passing it to any other function in this library
- * results in undefined behavior. If there are no more chunks to be read from
- * \a value, then \a next will be set to the next item after this string; if \a
- * value points to the last item, then \a next will be invalid.
- *
- * \sa cbor_value_dup_byte_string(), cbor_value_copy_byte_string(), cbor_value_caculate_string_length(), cbor_value_get_text_string_chunk()
- */
-
-CborError _cbor_value_get_string_chunk(const CborValue *value, const void **bufferptr,
-                                                        size_t *len, CborValue *next)
-{
-    CborValue tmp;
-    if (!next)
-        next = &tmp;
-    *next = *value;
-
-    return get_string_chunk(next, bufferptr, len);
-}
-
-/* We return uintptr_t so that we can pass memcpy directly as the iteration
- * function. The choice is to optimize for memcpy, which is used in the base
- * parser API (cbor_value_copy_string), while memcmp is used in convenience API
- * only. */
-typedef uintptr_t (*IterateFunction)(struct cbor_decoder_reader *d, char *dst, int src_offset, size_t len);
-
-static uintptr_t iterate_noop(struct cbor_decoder_reader *d, char *dst, int src_offset,  size_t len)
-{
-    (void)d;
-    (void)dst;
-    (void)src_offset;
-    (void)len;
-    return true;
-}
-
-static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
-                                       bool *result, CborValue *next, IterateFunction func)
-{
-    cbor_assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
-
-    CborError err;
-    CborValue tmp;
-    size_t total = 0;
-    const void *ptr;
-
-    if (!next)
-        next = &tmp;
-    *next = *value;
-    *result = true;
-
-    while (1) {
-        size_t newTotal;
-        size_t chunkLen = 0;
-        err = get_string_chunk(next, &ptr, &chunkLen);
-        if (err)
-            return err;
-        if (!ptr)
-            break;
-
-        if (unlikely(add_check_overflow(total, chunkLen, &newTotal)))
-            return CborErrorDataTooLarge;
-
-        if (*result && *buflen >= newTotal)
-            *result = !!func(value->parser->d, buffer + total, next->offset - chunkLen, chunkLen);
-        else
-            *result = false;
-
-        total = newTotal;
-    }
-
-    *buflen = total;
-
-    return CborNoError;
-}
-
-/**
- * \fn CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, size_t *buflen, CborValue *next)
- *
- * Copies the string pointed by \a value into the buffer provided at \a buffer
- * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
- * copy anything and will only update the \a next value.
- *
- * If the iterator \a value does not point to a text string, the behaviour is
- * undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_text_string is recommended.
- *
- * If the provided buffer length was too small, this function returns an error
- * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
- * of the string in order to preallocate a buffer, use
- * cbor_value_calculate_string_length().
- *
- * On success, this function sets the number of bytes copied to \c{*buflen}. If
- * the buffer is large enough, this function will insert a null byte after the
- * last copied byte, to facilitate manipulation of text strings. That byte is
- * not included in the returned value of \c{*buflen}.
- *
- * The \a next pointer, if not null, will be updated to point to the next item
- * after this string. If \a value points to the last item, then \a next will be
- * invalid.
- *
- * This function may not run in constant time (it will run in O(n) time on the
- * number of chunks). It requires constant memory (O(1)).
- *
- * \note This function does not perform UTF-8 validation on the incoming text
- * string.
- *
- * \sa cbor_value_get_text_string_chunk() cbor_value_dup_text_string(), cbor_value_copy_byte_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
- */
-
-/**
- * \fn CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, size_t *buflen, CborValue *next)
- *
- * Copies the string pointed by \a value into the buffer provided at \a buffer
- * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
- * copy anything and will only update the \a next value.
- *
- * If the iterator \a value does not point to a byte string, the behaviour is
- * undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_byte_string is recommended.
- *
- * If the provided buffer length was too small, this function returns an error
- * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
- * of the string in order to preallocate a buffer, use
- * cbor_value_calculate_string_length().
- *
- * On success, this function sets the number of bytes copied to \c{*buflen}. If
- * the buffer is large enough, this function will insert a null byte after the
- * last copied byte, to facilitate manipulation of null-terminated strings.
- * That byte is not included in the returned value of \c{*buflen}.
- *
- * The \a next pointer, if not null, will be updated to point to the next item
- * after this string. If \a value points to the last item, then \a next will be
- * invalid.
- *
- * This function may not run in constant time (it will run in O(n) time on the
- * number of chunks). It requires constant memory (O(1)).
- *
- * \sa cbor_value_get_byte_string_chunk(), cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
- */
-
-CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
-                                 size_t *buflen, CborValue *next)
-{
-    bool copied_all;
-    CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next,
-                                          buffer ? (IterateFunction) value->parser->d->cpy : iterate_noop);
-    if (err) {
-        return err;
-    }
-
-    if (!copied_all) {
-        return CborErrorOutOfMemory;
-    }
-
-    if (buffer) {
-        *((uint8_t *)buffer + *buflen) = '\0';
-    }
-
-    return CborNoError;
-}
-
-/**
- * Compares the entry \a value with the string \a string and store the result
- * in \a result. If the value is different from \a string \a result will
- * contain \c false.
- *
- * The entry at \a value may be a tagged string. If \a is not a string or a
- * tagged string, the comparison result will be false.
- *
- * CBOR requires text strings to be encoded in UTF-8, but this function does
- * not validate either the strings in the stream or the string \a string to be
- * matched. Moreover, comparison is done on strict codepoint comparison,
- * without any Unicode normalization.
- *
- * This function may not run in constant time (it will run in O(n) time on the
- * number of chunks). It requires constant memory (O(1)).
- *
- * \sa cbor_value_skip_tag(), cbor_value_copy_text_string()
- */
-CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
-{
-    CborValue copy = *value;
-    CborError err = cbor_value_skip_tag(&copy);
-
-    if (err)
-        return err;
-    if (!cbor_value_is_text_string(&copy)) {
-        *result = false;
-        return CborNoError;
-    }
-
-    size_t len = strlen(string);
-    err = iterate_string_chunks(&copy, CONST_CAST(char *, string), &len,
-                                result, NULL, value->parser->d->cmp);
-    if (err) {
-        return err;
-    }
-
-    if (*result && string[len] != '\0') {
-        *result = false;
-    }
-
-    return CborNoError;
-}
-
-/**
- * \fn bool cbor_value_is_array(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR array.
- *
- * \sa cbor_value_is_valid(), cbor_value_is_map()
- */
-
-/**
- * \fn CborError cbor_value_get_array_length(const CborValue *value, size_t *length)
- *
- * Extracts the length of the CBOR array that \a value points to and stores it
- * in \a result. If the iterator \a value does not point to a CBOR array, the
- * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_array is recommended.
- *
- * If the length of this array is not encoded in the CBOR data stream, this
- * function will return the recoverable error CborErrorUnknownLength. You may
- * also check whether that is the case by using cbor_value_is_length_known().
- *
- * \note On 32-bit platforms, this function will return error condition of \ref
- * CborErrorDataTooLarge if the stream indicates a length that is too big to
- * fit in 32-bit.
- *
- * \sa cbor_value_is_valid(), cbor_value_is_length_known()
- */
-
-/**
- * \fn bool cbor_value_is_map(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR map.
- *
- * \sa cbor_value_is_valid(), cbor_value_is_array()
- */
-
-/**
- * \fn CborError cbor_value_get_map_length(const CborValue *value, size_t *length)
- *
- * Extracts the length of the CBOR map that \a value points to and stores it in
- * \a result. If the iterator \a value does not point to a CBOR map, the
- * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_map is recommended.
- *
- * If the length of this map is not encoded in the CBOR data stream, this
- * function will return the recoverable error CborErrorUnknownLength. You may
- * also check whether that is the case by using cbor_value_is_length_known().
- *
- * \note On 32-bit platforms, this function will return error condition of \ref
- * CborErrorDataTooLarge if the stream indicates a length that is too big to
- * fit in 32-bit.
- *
- * \sa cbor_value_is_valid(), cbor_value_is_length_known()
- */
-
-/**
- * Attempts to find the value in map \a map that corresponds to the text string
- * entry \a string. If the iterator \a value does not point to a CBOR map, the
- * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_map is recommended.
- *
- * If the item is found, it is stored in \a result. If no item is found
- * matching the key, then \a result will contain an element of type \ref
- * CborInvalidType. Matching is performed using
- * cbor_value_text_string_equals(), so tagged strings will also match.
- *
- * This function has a time complexity of O(n) where n is the number of
- * elements in the map to be searched. In addition, this function is has O(n)
- * memory requirement based on the number of nested containers (maps or arrays)
- * found as elements of this map.
- *
- * \sa cbor_value_is_valid(), cbor_value_text_string_equals(), cbor_value_advance()
- */
-CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
-{
-    cbor_assert(cbor_value_is_map(map));
-    size_t len = strlen(string);
-    CborError err = cbor_value_enter_container(map, element);
-    if (err)
-        goto error;
-
-    while (!cbor_value_at_end(element)) {
-        /* find the non-tag so we can compare */
-        err = cbor_value_skip_tag(element);
-        if (err)
-            goto error;
-        if (cbor_value_is_text_string(element)) {
-            bool equals;
-            size_t dummyLen = len;
-            err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
-                                        &equals, element, map->parser->d->cmp);
-            if (err)
-                goto error;
-            if (equals && string[dummyLen] == '\0')
-                return preparse_value(element);
-        } else {
-            /* skip this key */
-            err = cbor_value_advance(element);
-            if (err)
-                goto error;
-        }
-
-        /* skip this value */
-        err = cbor_value_skip_tag(element);
-        if (err)
-            goto error;
-        err = cbor_value_advance(element);
-        if (err)
-            goto error;
-    }
-
-    /* not found */
-    element->type = CborInvalidType;
-    return CborNoError;
-
-error:
-    element->type = CborInvalidType;
-    return err;
-}
-
-/**
- * \fn bool cbor_value_is_float(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR
- * single-precision floating point (32-bit).
- *
- * \sa cbor_value_is_valid(), cbor_value_is_double(), cbor_value_is_half_float()
- */
-
-/**
- * \fn CborError cbor_value_get_float(const CborValue *value, float *result)
- *
- * Retrieves the CBOR single-precision floating point (32-bit) value that \a
- * value points to and stores it in \a result. If the iterator \a value does
- * not point to a single-precision floating point value, the behavior is
- * undefined, so checking with \ref cbor_value_get_type or with \ref
- * cbor_value_is_float is recommended.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_float(), cbor_value_get_double()
- */
-
-/**
- * \fn bool cbor_value_is_double(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR
- * double-precision floating point (64-bit).
- *
- * \sa cbor_value_is_valid(), cbor_value_is_float(), cbor_value_is_half_float()
- */
-
-/**
- * \fn CborError cbor_value_get_double(const CborValue *value, float *result)
- *
- * Retrieves the CBOR double-precision floating point (64-bit) value that \a
- * value points to and stores it in \a result. If the iterator \a value does
- * not point to a double-precision floating point value, the behavior is
- * undefined, so checking with \ref cbor_value_get_type or with \ref
- * cbor_value_is_double is recommended.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_double(), cbor_value_get_float()
- */
-
-/**
- * \fn bool cbor_value_is_half_float(const CborValue *value)
- *
- * Returns true if the iterator \a value is valid and points to a CBOR
- * single-precision floating point (16-bit).
- *
- * \sa cbor_value_is_valid(), cbor_value_is_double(), cbor_value_is_float()
- */
-
-/**
- * Retrieves the CBOR half-precision floating point (16-bit) value that \a
- * value points to and stores it in \a result. If the iterator \a value does
- * not point to a half-precision floating point value, the behavior is
- * undefined, so checking with \ref cbor_value_get_type or with \ref
- * cbor_value_is_half_float is recommended.
- *
- * Note: since the C language does not have a standard type for half-precision
- * floating point, this function takes a \c{void *} as a parameter for the
- * storage area, which must be at least 16 bits wide.
- *
- * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_float()
- */
-CborError cbor_value_get_half_float(const CborValue *value, void *result)
-{
-    cbor_assert(cbor_value_is_half_float(value));
-
-    /* size has been computed already */
-    uint16_t v = value->parser->d->get16(value->parser->d, value->offset + 1);
-    memcpy(result, &v, sizeof(v));
-    return CborNoError;
-}
-
-
-/** @} */
diff --git a/ext/tinycbor/src/cborparser_dup_string.c b/ext/tinycbor/src/cborparser_dup_string.c
deleted file mode 100644
index 1fda05e..0000000
--- a/ext/tinycbor/src/cborparser_dup_string.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE 1
-#endif
-#ifndef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE 1
-#endif
-#ifndef __STDC_LIMIT_MACROS
-#  define __STDC_LIMIT_MACROS 1
-#endif
-
-#include "cbor.h"
-#include <stdlib.h>
-#include "compilersupport_p.h"
-
-/**
- * \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
- *
- * Allocates memory for the string pointed by \a value and copies it into this
- * buffer. The pointer to the buffer is stored in \a buffer and the number of
- * bytes copied is stored in \a len (those variables must not be NULL).
- *
- * If the iterator \a value does not point to a text string, the behaviour is
- * undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_text_string is recommended.
- *
- * If \c malloc returns a NULL pointer, this function will return error
- * condition \ref CborErrorOutOfMemory.
- *
- * On success, \c{*buffer} will contain a valid pointer that must be freed by
- * calling \c{free()}. This is the case even for zero-length strings.
- *
- * The \a next pointer, if not null, will be updated to point to the next item
- * after this string. If \a value points to the last item, then \a next will be
- * invalid.
- *
- * This function may not run in constant time (it will run in O(n) time on the
- * number of chunks). It requires constant memory (O(1)) in addition to the
- * malloc'ed block.
- *
- * \note This function does not perform UTF-8 validation on the incoming text
- * string.
- *
- * \sa cbor_value_get_text_string_chunk(), cbor_value_copy_text_string(), cbor_value_dup_byte_string()
- */
-
-/**
- * \fn CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, size_t *buflen, CborValue *next)
- *
- * Allocates memory for the string pointed by \a value and copies it into this
- * buffer. The pointer to the buffer is stored in \a buffer and the number of
- * bytes copied is stored in \a len (those variables must not be NULL).
- *
- * If the iterator \a value does not point to a byte string, the behaviour is
- * undefined, so checking with \ref cbor_value_get_type or \ref
- * cbor_value_is_byte_string is recommended.
- *
- * If \c malloc returns a NULL pointer, this function will return error
- * condition \ref CborErrorOutOfMemory.
- *
- * On success, \c{*buffer} will contain a valid pointer that must be freed by
- * calling \c{free()}. This is the case even for zero-length strings.
- *
- * The \a next pointer, if not null, will be updated to point to the next item
- * after this string. If \a value points to the last item, then \a next will be
- * invalid.
- *
- * This function may not run in constant time (it will run in O(n) time on the
- * number of chunks). It requires constant memory (O(1)) in addition to the
- * malloc'ed block.
- *
- * \sa cbor_value_get_text_string_chunk(), cbor_value_copy_byte_string(), cbor_value_dup_text_string()
- */
-CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next)
-{
-    cbor_assert(buffer);
-    cbor_assert(buflen);
-    *buflen = SIZE_MAX;
-    CborError err = _cbor_value_copy_string(value, NULL, buflen, NULL);
-    if (err)
-        return err;
-
-    ++*buflen;
-    *buffer = malloc(*buflen);
-    if (!*buffer) {
-        /* out of memory */
-        return CborErrorOutOfMemory;
-    }
-    err = _cbor_value_copy_string(value, *buffer, buflen, next);
-    if (err) {
-        free(*buffer);
-        return err;
-    }
-    return CborNoError;
-}
diff --git a/ext/tinycbor/src/cborpretty.c b/ext/tinycbor/src/cborpretty.c
deleted file mode 100644
index 800d68c..0000000
--- a/ext/tinycbor/src/cborpretty.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#define _BSD_SOURCE 1
-#define _DEFAULT_SOURCE 1
-#ifndef __STDC_LIMIT_MACROS
-#  define __STDC_LIMIT_MACROS 1
-#endif
-
-#include "cbor.h"
-#include "compilersupport_p.h"
-#include "cborinternal_p.h"
-#include "utf8_p.h"
-
-#include <float.h>
-#include <inttypes.h>
-#include <math.h>
-#include <string.h>
-
-/**
- * \defgroup CborPretty Converting CBOR to text
- * \brief Group of functions used to convert CBOR to text form.
- *
- * This group contains two functions that are can be used to convert one
- * CborValue object to a text representation. This module attempts to follow
- * the recommendations from RFC 7049 section 6 "Diagnostic Notation", though it
- * has a few differences. They are noted below.
- *
- * TinyCBOR does not provide a way to convert from the text representation back
- * to encoded form. To produce a text form meant to be parsed, CborToJson is
- * recommended instead.
- *
- * Either of the functions in this section will attempt to convert exactly one
- * CborValue object to text. Those functions may return any error documented
- * for the functions for CborParsing. In addition, if the C standard library
- * stream functions return with error, the text conversion will return with
- * error CborErrorIO.
- *
- * These functions also perform UTF-8 validation in CBOR text strings. If they
- * encounter a sequence of bytes that not permitted in UTF-8, they will return
- * CborErrorInvalidUtf8TextString. That includes encoding of surrogate points
- * in UTF-8.
- *
- * \warning The output type produced by these functions is not guaranteed to
- * remain stable. A future update of TinyCBOR may produce different output for
- * the same input and parsers may be unable to handle them.
- *
- * \sa CborParsing, CborToJson, cbor_parser_init()
- */
-
-/**
- * \addtogroup CborPretty
- * @{
- * <h2 class="groupheader">Text format</h2>
- *
- * As described in RFC 7049 section 6 "Diagnostic Notation", the format is
- * largely borrowed from JSON, but modified to suit CBOR's different data
- * types. TinyCBOR makes further modifications to distinguish different, but
- * similar values.
- *
- * CBOR values are currently encoded as follows:
- * \par Integrals (unsigned and negative)
- *      Base-10 (decimal) text representation of the value
- * \par Byte strings:
- *      <tt>"h'"</tt> followed by the Base16 (hex) representation of the binary data, followed by an ending quote (')
- * \par Text strings:
- *      C-style escaped string in quotes, with C11/C++11 escaping of Unicode codepoints above U+007F.
- * \par Tags:
- *      Tag value, with the tagged value in parentheses. No special encoding of the tagged value is performed.
- * \par Simple types:
- *      <tt>"simple(nn)"</tt> where \c nn is the simple value
- * \par Null:
- *      \c null
- * \par Undefined:
- *      \c undefined
- * \par Booleans:
- *      \c true or \c false
- * \par Floating point:
- *      If NaN or infinite, the actual words \c NaN or \c infinite.
- *      Otherwise, the decimal representation with as many digits as necessary to ensure no loss of information.
- *      By default, float values are suffixed by "f" and half-float values suffixed by "f16" (doubles have no suffix).
- *      If the CborPrettyNumericEncodingIndicators flag is active, the values instead are encoded following the
- *      Section 6 recommended encoding indicators: float values are suffixed with "_2" and half-float with "_1".
- *      A dot is always present.
- * \par Arrays:
- *      Comma-separated list of elements, enclosed in square brackets ("[" and "]").
- * \par Maps:
- *      Comma-separated list of key-value pairs, with the key and value separated
- *      by a colon (":"), enclosed in curly braces ("{" and "}").
- *
- * The CborPrettyFlags enumerator contains flags to control some aspects of the
- * encoding:
- * \par String fragmentation
- *      When the CborPrettyShowStringFragments option is active, text and byte
- *      strings that are transmitted in fragments are shown instead inside
- *      parentheses ("(" and ")") with no preceding number and each fragment is
- *      displayed individually. If a tag precedes the string, then the output
- *      will contain a double set of parentheses. If the option is not active,
- *      the fragments are merged together and the display will not show any
- *      difference from a string transmitted with determinate length.
- * \par Encoding indicators
- *      Numbers and lengths in CBOR can be encoded in multiple representations.
- *      If the CborPrettyIndicateOverlongNumbers option is active, numbers
- *      and lengths that are transmitted in a longer encoding than necessary
- *      will be indicated, by appending an underscore ("_") to either the
- *      number or the opening bracket or brace, followed by a number
- *      indicating the CBOR additional information: 0 for 1 byte, 1 for 2
- *      bytes, 2 for 4 bytes and 3 for 8 bytes.
- *      If the CborPrettyIndicateIndetermineLength option is active, maps,
- *      arrays and strings encoded with indeterminate length will be marked by
- *      an underscore after the opening bracket or brace or the string (if not
- *      showing fragments), without a number after it.
- */
-
-/**
- * \enum CborPrettyFlags
- * The CborPrettyFlags enum contains flags that control the conversion of CBOR to text format.
- *
- * \value CborPrettyNumericEncodingIndicators   Use numeric encoding indicators instead of textual for float and half-float.
- * \value CborPrettyTextualEncodingIndicators   Use textual encoding indicators for float ("f") and half-float ("f16").
- * \value CborPrettyIndicateIndetermineLength   Indicate when a map or array has indeterminate length.
- * \value CborPrettyIndicateOverlongNumbers     Indicate when a number or length was encoded with more bytes than needed.
- * \value CborPrettyShowStringFragments         If the byte or text string is transmitted in chunks, show each individually.
- * \value CborPrettyMergeStringFragment         Merge all chunked byte or text strings and display them in a single entry.
- * \value CborPrettyDefaultFlags       Default conversion flags.
- */
-
-static void printRecursionLimit(CborStreamFunction stream, void *out)
-{
-    stream(out, "<nesting too deep, recursion stopped>");
-}
-
-static CborError hexDump(CborStreamFunction stream, void *out, const void *ptr, size_t n)
-{
-    const uint8_t *buffer = (const uint8_t *)ptr;
-    CborError err = CborNoError;
-    while (n-- && !err)
-        err = stream(out, "%02" PRIx8, *buffer++);
-
-    return err;
-}
-
-/* This function decodes buffer as UTF-8 and prints as escaped UTF-16.
- * On UTF-8 decoding error, it returns CborErrorInvalidUtf8TextString */
-static CborError utf8EscapedDump(CborStreamFunction stream, void *out, const void *ptr, size_t n)
-{
-    const uint8_t *buffer = (const uint8_t *)ptr;
-    const uint8_t * const end = buffer + n;
-    CborError err = CborNoError;
-
-    while (buffer < end && !err) {
-        uint32_t uc = get_utf8(&buffer, end);
-        if (uc == ~0U)
-            return CborErrorInvalidUtf8TextString;
-
-        if (uc < 0x80) {
-            /* single-byte UTF-8 */
-            if (uc < 0x7f && uc >= 0x20 && uc != '\\' && uc != '"') {
-                err = stream(out, "%c", (char)uc);
-                continue;
-            }
-
-            /* print as an escape sequence */
-            char escaped = (char)uc;
-            switch (uc) {
-            case '"':
-            case '\\':
-                break;
-            case '\b':
-                escaped = 'b';
-                break;
-            case '\f':
-                escaped = 'f';
-                break;
-            case '\n':
-                escaped = 'n';
-                break;
-            case '\r':
-                escaped = 'r';
-                break;
-            case '\t':
-                escaped = 't';
-                break;
-            default:
-                goto print_utf16;
-            }
-            err = stream(out, "\\%c", escaped);
-            continue;
-        }
-
-        /* now print the sequence */
-        if (uc > 0xffffU) {
-            /* needs surrogate pairs */
-            err = stream(out, "\\u%04" PRIX32 "\\u%04" PRIX32,
-                         (uc >> 10) + 0xd7c0,    /* high surrogate */
-                         (uc % 0x0400) + 0xdc00);
-        } else {
-print_utf16:
-            /* no surrogate pair needed */
-            err = stream(out, "\\u%04" PRIX32, uc);
-        }
-    }
-    return err;
-}
-
-static const char *resolve_indicator(const CborValue *it, int flags)
-{
-    static const char indicators[8][3] = {
-        "_0", "_1", "_2", "_3",
-        "", "", "",             /* these are not possible */
-        "_"
-    };
-    const char *no_indicator = indicators[5];   /* empty string */
-    uint8_t additional_information;
-    uint8_t expected_information;
-    uint64_t value;
-    CborError err;
-    int offset;
-    uint8_t val;
-
-    if (it->offset == it->parser->end)
-        return NULL;    /* CborErrorUnexpectedEOF */
-
-    val = it->parser->d->get8(it->parser->d, it->offset);
-
-    additional_information = (val & SmallValueMask);
-    if (additional_information < Value8Bit)
-        return no_indicator;
-
-    /* determine whether to show anything */
-    if ((flags & CborPrettyIndicateIndetermineLength) &&
-            additional_information == IndefiniteLength)
-        return indicators[IndefiniteLength - Value8Bit];
-    if ((flags & CborPrettyIndicateOverlongNumbers) == 0)
-        return no_indicator;
-
-    offset = it->offset;
-
-    err = _cbor_value_extract_number(it->parser, &offset, &value);
-    if (err)
-        return NULL;    /* CborErrorUnexpectedEOF */
-
-    expected_information = Value8Bit - 1;
-    if (value >= Value8Bit)
-        ++expected_information;
-    if (value > 0xffU)
-        ++expected_information;
-    if (value > 0xffffU)
-        ++expected_information;
-    if (value > 0xffffffffU)
-        ++expected_information;
-    return expected_information == additional_information ?
-                no_indicator :
-                indicators[additional_information - Value8Bit];
-}
-
-static const char *get_indicator(const CborValue *it, int flags)
-{
-    return resolve_indicator(it, flags);
-}
-
-static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft);
-static CborError container_to_pretty(CborStreamFunction stream, void *out, CborValue *it, CborType containerType,
-                                     int flags, int recursionsLeft)
-{
-    if (!recursionsLeft) {
-        printRecursionLimit(stream, out);
-        return CborNoError; /* do allow the dumping to continue */
-    }
-
-    const char *comma = "";
-    CborError err = CborNoError;
-    while (!cbor_value_at_end(it) && !err) {
-        err = stream(out, "%s", comma);
-        comma = ", ";
-
-        if (!err)
-            err = value_to_pretty(stream, out, it, flags, recursionsLeft);
-
-        if (containerType == CborArrayType)
-            continue;
-
-        /* map: that was the key, so get the value */
-        if (!err)
-            err = stream(out, ": ");
-        if (!err)
-            err = value_to_pretty(stream, out, it, flags, recursionsLeft);
-    }
-    return err;
-}
-
-static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft)
-{
-    CborError err = CborNoError;
-    CborType type = cbor_value_get_type(it);
-    switch (type) {
-    case CborArrayType:
-    case CborMapType: {
-        /* recursive type */
-        CborValue recursed;
-        const char *indicator = get_indicator(it, flags);
-        const char *space = *indicator ? " " : indicator;
-
-        err = stream(out, "%c%s%s", type == CborArrayType ? '[' : '{', indicator, space);
-        if (err)
-            return err;
-
-        err = cbor_value_enter_container(it, &recursed);
-        if (err) {
-            it->offset = recursed.offset;
-            return err;       /* parse error */
-        }
-        err = container_to_pretty(stream, out, &recursed, type, flags, recursionsLeft - 1);
-        if (err) {
-            it->offset = recursed.offset;
-            return err;       /* parse error */
-        }
-        err = cbor_value_leave_container(it, &recursed);
-        if (err)
-            return err;       /* parse error */
-
-        return stream(out, type == CborArrayType ? "]" : "}");
-    }
-
-    case CborIntegerType: {
-        uint64_t val;
-        cbor_value_get_raw_integer(it, &val);    /* can't fail */
-
-        if (cbor_value_is_unsigned_integer(it)) {
-            err = stream(out, "%" PRIu64, val);
-        } else {
-            /* CBOR stores the negative number X as -1 - X
-             * (that is, -1 is stored as 0, -2 as 1 and so forth) */
-            if (++val) {                /* unsigned overflow may happen */
-                err = stream(out, "-%" PRIu64, val);
-            } else {
-                /* overflown
-                 *   0xffff`ffff`ffff`ffff + 1 =
-                 * 0x1`0000`0000`0000`0000 = 18446744073709551616 (2^64) */
-                err = stream(out, "-18446744073709551616");
-            }
-        }
-        if (!err)
-            err = stream(out, "%s", get_indicator(it, flags));
-        break;
-    }
-
-    case CborByteStringType:
-    case CborTextStringType: {
-        size_t n = 0;
-        const void *ptr;
-        bool showingFragments = (flags & CborPrettyShowStringFragments) && !cbor_value_is_length_known(it);
-        const char *separator = "";
-        char close = '\'';
-        char open[3] = "h'";
-        const char *indicator = NULL;
-
-        if (type == CborTextStringType) {
-            close = open[0] = '"';
-            open[1] = '\0';
-        }
-
-        if (showingFragments) {
-            err = stream(out, "(_ ");
-            if (!err)
-                err = _cbor_value_prepare_string_iteration(it);
-        } else {
-            err = stream(out, "%s", open);
-        }
-
-        while (!err) {
-            if (showingFragments || indicator == NULL) {
-                /* any iteration, except the second for a non-chunked string */
-                indicator = resolve_indicator(it, flags);
-            }
-
-            err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
-            if (!ptr)
-                break;
-
-            if (!err && showingFragments)
-                err = stream(out, "%s%s", separator, open);
-            if (!err)
-                err = (type == CborByteStringType ?
-                           hexDump(stream, out, ptr, n) :
-                           utf8EscapedDump(stream, out, ptr, n));
-            if (!err && showingFragments) {
-                err = stream(out, "%c%s", close, indicator);
-                separator = ", ";
-            }
-        }
-
-        if (!err) {
-            if (showingFragments)
-                err = stream(out, ")");
-            else
-                err = stream(out, "%c%s", close, indicator);
-        }
-        return err;
-    }
-
-    case CborTagType: {
-        CborTag tag;
-        cbor_value_get_tag(it, &tag);       /* can't fail */
-        err = stream(out, "%" PRIu64 "%s(", tag, get_indicator(it, flags));
-        if (!err)
-            err = cbor_value_advance_fixed(it);
-        if (!err && recursionsLeft)
-            err = value_to_pretty(stream, out, it, flags, recursionsLeft - 1);
-        else if (!err)
-            printRecursionLimit(stream, out);
-        if (!err)
-            err = stream(out, ")");
-        return err;
-    }
-
-    case CborSimpleType: {
-        /* simple types can't fail and can't have overlong encoding */
-        uint8_t simple_type;
-        cbor_value_get_simple_type(it, &simple_type);
-        err = stream(out, "simple(%" PRIu8 ")", simple_type);
-        break;
-    }
-
-    case CborNullType:
-        err = stream(out, "null");
-        break;
-
-    case CborUndefinedType:
-        err = stream(out, "undefined");
-        break;
-
-    case CborBooleanType: {
-        bool val;
-        cbor_value_get_boolean(it, &val);       /* can't fail */
-        err = stream(out, val ? "true" : "false");
-        break;
-    }
-#ifndef NO_FLOAT_SUPPORT
-    case CborDoubleType: {
-        const char *suffix;
-        double val;
-        int r;
-        if (false) {
-            float f;
-    case CborFloatType:
-            cbor_value_get_float(it, &f);
-            val = f;
-            suffix = flags & CborPrettyNumericEncodingIndicators ? "_2" : "f";
-        } else if (false) {
-            uint16_t f16;
-    case CborHalfFloatType:
-            cbor_value_get_half_float(it, &f16);
-            val = decode_half(f16);
-            suffix = flags & CborPrettyNumericEncodingIndicators ? "_1" : "f16";
-        } else {
-            cbor_value_get_double(it, &val);
-            suffix = "";
-        }
-
-        if ((flags & CborPrettyNumericEncodingIndicators) == 0) {
-            r = fpclassify(val);
-            if (r == FP_NAN || r == FP_INFINITE)
-                suffix = "";
-        }
-
-        uint64_t ival = (uint64_t)fabs(val);
-        if (ival == fabs(val)) {
-            /* this double value fits in a 64-bit integer, so show it as such
-             * (followed by a floating point suffix, to disambiguate) */
-            err = stream(out, "%s%" PRIu64 ".%s", val < 0 ? "-" : "", ival, suffix);
-        } else {
-            /* this number is definitely not a 64-bit integer */
-            err = stream(out, "%." DBL_DECIMAL_DIG_STR "g%s", val, suffix);
-        }
-        break;
-    }
-#endif
-    case CborInvalidType:
-        err = stream(out, "invalid");
-        if (err)
-            return err;
-    }
-
-    if (!err)
-        err = cbor_value_advance_fixed(it);
-    return err;
-}
-
-/**
- * Converts the current CBOR type pointed by \a value to its textual
- * representation and writes it to the stream by calling the \a streamFunction.
- * If an error occurs, this function returns an error code similar to
- * CborParsing.
- *
- * The textual representation can be controlled by the \a flags parameter (see
- * CborPrettyFlags for more information).
- *
- * If no error ocurred, this function advances \a value to the next element.
- * Often, concatenating the text representation of multiple elements can be
- * done by appending a comma to the output stream.
- *
- * The \a streamFunction function will be called with the \a token value as the
- * first parameter and a printf-style format string as the second, with a variable
- * number of further parameters.
- *
- * \sa cbor_value_to_pretty(), cbor_value_to_json_advance()
- */
-CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags)
-{
-    return value_to_pretty(streamFunction, token, value, flags, CBOR_PARSER_MAX_RECURSIONS);
-}
-
-/** @} */
diff --git a/ext/tinycbor/src/cborpretty_stdio.c b/ext/tinycbor/src/cborpretty_stdio.c
deleted file mode 100644
index f905e86..0000000
--- a/ext/tinycbor/src/cborpretty_stdio.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#include "cbor.h"
-#include <stdarg.h>
-#include <stdio.h>
-
-static CborError cbor_fprintf(void *out, const char *fmt, ...)
-{
-    int n;
-
-    va_list list;
-    va_start(list, fmt);
-    n = vfprintf((FILE *)out, fmt, list);
-    va_end(list);
-
-    return n < 0 ? CborErrorIO : CborNoError;
-}
-
-/**
- * \fn CborError cbor_value_to_pretty(FILE *out, const CborValue *value)
- *
- * Converts the current CBOR type pointed by \a value to its textual
- * representation and writes it to the \a out stream. If an error occurs, this
- * function returns an error code similar to CborParsing.
- *
- * \sa cbor_value_to_pretty_advance(), cbor_value_to_json_advance()
- */
-
-/**
- * Converts the current CBOR type pointed by \a value to its textual
- * representation and writes it to the \a out stream. If an error occurs, this
- * function returns an error code similar to CborParsing.
- *
- * If no error ocurred, this function advances \a value to the next element.
- * Often, concatenating the text representation of multiple elements can be
- * done by appending a comma to the output stream.
- *
- * \sa cbor_value_to_pretty(), cbor_value_to_pretty_stream(), cbor_value_to_json_advance()
- */
-CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value)
-{
-    return cbor_value_to_pretty_stream(cbor_fprintf, out, value, CborPrettyDefaultFlags);
-}
-
-/**
- * Converts the current CBOR type pointed by \a value to its textual
- * representation and writes it to the \a out stream. If an error occurs, this
- * function returns an error code similar to CborParsing.
- *
- * The textual representation can be controlled by the \a flags parameter (see
- * CborPrettyFlags for more information).
- *
- * If no error ocurred, this function advances \a value to the next element.
- * Often, concatenating the text representation of multiple elements can be
- * done by appending a comma to the output stream.
- *
- * \sa cbor_value_to_pretty_stream(), cbor_value_to_pretty(), cbor_value_to_json_advance()
- */
-CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags)
-{
-    return cbor_value_to_pretty_stream(cbor_fprintf, out, value, flags);
-}
-
diff --git a/ext/tinycbor/src/cbortojson.c b/ext/tinycbor/src/cbortojson.c
deleted file mode 100644
index babb23d..0000000
--- a/ext/tinycbor/src/cbortojson.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#define _BSD_SOURCE 1
-#define _DEFAULT_SOURCE 1
-#define _GNU_SOURCE 1
-#define _POSIX_C_SOURCE 200809L
-#ifndef __STDC_LIMIT_MACROS
-#  define __STDC_LIMIT_MACROS 1
-#endif
-
-#include "cbor.h"
-#include "cborjson.h"
-#include "compilersupport_p.h"
-
-#include <float.h>
-#include <inttypes.h>
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-/**
- * \defgroup CborToJson Converting CBOR to JSON
- * \brief Group of functions used to convert CBOR to JSON.
- *
- * This group contains two functions that are can be used to convert one
- * CborValue object to an equivalent JSON representation. This module attempts
- * to follow the recommendations from RFC 7049 section 4.1 "Converting from
- * CBOR to JSON", though it has a few differences. They are noted below.
- *
- * These functions produce a "minified" JSON output, with no spacing,
- * indentation or line breaks. If those are necessary, they need to be applied
- * in a post-processing phase.
- *
- * Note that JSON cannot support all CBOR types with fidelity, so the
- * conversion is usually lossy. For that reason, TinyCBOR supports adding a set
- * of metadata JSON values that can be used by a JSON-to-CBOR converter to
- * restore the original data types.
- *
- * The TinyCBOR library does not provide a way to convert from JSON
- * representation back to encoded form. However, it provides a tool called
- * \c json2cbor which can be used for that purpose. That tool supports the
- * metadata format that these functions may produce.
- *
- * Either of the functions in this section will attempt to convert exactly one
- * CborValue object to JSON. Those functions may return any error documented
- * for the functions for CborParsing. In addition, if the C standard library
- * stream functions return with error, the text conversion will return with
- * error CborErrorIO.
- *
- * These functions also perform UTF-8 validation in CBOR text strings. If they
- * encounter a sequence of bytes that not permitted in UTF-8, they will return
- * CborErrorInvalidUtf8TextString. That includes encoding of surrogate points
- * in UTF-8.
- *
- * \warning The metadata produced by these functions is not guaranteed to
- * remain stable. A future update of TinyCBOR may produce different output for
- * the same input and parsers may be unable to handle them.
- *
- * \sa CborParsing, CborPretty, cbor_parser_init()
- */
-
-/**
- * \addtogroup CborToJson
- * @{
- * <h2 class="groupheader">Conversion limitations</h2>
- *
- * When converting from CBOR to JSON, there may be information loss. This
- * section lists the possible scenarios.
- *
- * \par Number precision:
- * ALL JSON numbers, due to its JavaScript heritage, are IEEE 754
- * double-precision floating point. This means JSON is not capable of
- * representing integers numbers outside the range [-(2<sup>53</sup>)+1,
- * 2<sup>53</sup>-1] and is not capable of representing NaN or infinite. If the
- * CBOR data contains a number outside the valid range, the conversion will
- * lose precision. If the input was NaN or infinite, the result of the
- * conversion will be "null". In addition, the distinction between half-,
- * single- and double-precision is lost.
- *
- * \par
- * If enabled, the original value and original type are stored in the metadata.
- *
- * \par Non-native types:
- * CBOR's type system is richer than JSON's, which means some data values
- * cannot be represented when converted to JSON. The conversion silently turns
- * them into strings: CBOR simple types become "simple(nn)" where \c nn is the
- * simple type's value, with the exception of CBOR undefined, which becomes
- * "undefined", while CBOR byte strings are converted to an Base16, Base64, or
- * Base64url encoding
- *
- * \par
- * If enabled, the original type is stored in the metadata.
- *
- * \par Presence of tags:
- * JSON has no support for tagged values, so by default tags are dropped when
- * converting to JSON. However, if the CborConvertObeyByteStringTags option is
- * active (default), then certain known tags are honored and are used to format
- * the conversion of the tagged byte string to JSON.
- *
- * \par
- * If the CborConvertTagsToObjects option is active, then the tag and the
- * tagged value are converted to to a JSON object. Otherwise, if enabled, the
- * last (innermost) tag is stored in the metadata.
- *
- * \par Non-string keys in maps:
- * JSON requires all Object keys to be strings, while CBOR does not. By
- * default, if a non-string key is found, the conversion fails with error
- * CborErrorJsonObjectKeyNotString. If the CborConvertStringifyMapKeys option
- * is active, then the conversion attempts to create a string representation
- * using CborPretty. Note that the \c json2cbor tool is not able to parse this
- * back to the original form.
- *
- * \par Duplicate keys in maps:
- * Neither JSON nor CBOR allow duplicated keys, but current TinyCBOR does not
- * validate that this is the case. If there are duplicated keys in the input,
- * they will be repeated in the output, which may JSON tools may flag as
- * invalid. In addition to that, if the CborConvertStringifyMapKeys option is
- * active, it is possible that a non-string key in a CBOR map will be converted
- * to a string form that is identical to another key.
- *
- * \par
- * When metadata support is active, the conversion will add extra key-value
- * pairs to the JSON output so it can store the metadata. It is possible that
- * the keys for the metadata clash with existing keys in the JSON map.
- */
-
-extern FILE *open_memstream(char **bufptr, size_t *sizeptr);
-
-enum ConversionStatusFlags {
-    TypeWasNotNative            = 0x100,    /* anything but strings, boolean, null, arrays and maps */
-    TypeWasTagged               = 0x200,
-    NumberPrecisionWasLost      = 0x400,
-    NumberWasNaN                = 0x800,
-    NumberWasInfinite           = 0x1000,
-    NumberWasNegative           = 0x2000,   /* always used with NumberWasInifite or NumberWasTooBig */
-
-    FinalTypeMask               = 0xff
-};
-
-typedef struct ConversionStatus {
-    CborTag lastTag;
-    uint64_t originalNumber;
-    int flags;
-} ConversionStatus;
-
-static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status);
-
-static CborError dump_bytestring_base16(char **result, CborValue *it)
-{
-    static const char characters[] = "0123456789abcdef";
-    size_t i;
-    size_t n = 0;
-    uint8_t *buffer;
-    CborError err = cbor_value_calculate_string_length(it, &n);
-    if (err)
-        return err;
-
-    /* a Base16 (hex) output is twice as big as our buffer */
-    buffer = (uint8_t *)malloc(n * 2 + 1);
-    *result = (char *)buffer;
-
-    /* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */
-    ++n;
-    err = cbor_value_copy_byte_string(it, buffer + n - 1, &n, it);
-    cbor_assert(err == CborNoError);
-
-    for (i = 0; i < n; ++i) {
-        uint8_t byte = buffer[n + i];
-        buffer[2*i]     = characters[byte >> 4];
-        buffer[2*i + 1] = characters[byte & 0xf];
-    }
-    return CborNoError;
-}
-
-static CborError generic_dump_base64(char **result, CborValue *it, const char alphabet[65])
-{
-    size_t n = 0, i;
-    uint8_t *buffer, *out, *in;
-    CborError err = cbor_value_calculate_string_length(it, &n);
-    if (err)
-        return err;
-
-    /* a Base64 output (untruncated) has 4 bytes for every 3 in the input */
-    size_t len = (n + 5) / 3 * 4;
-    out = buffer = (uint8_t *)malloc(len + 1);
-    *result = (char *)buffer;
-
-    /* we read our byte string at the tail end of the buffer
-     * so we can do an in-place conversion while iterating forwards */
-    in = buffer + len - n;
-
-    /* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */
-    ++n;
-    err = cbor_value_copy_byte_string(it, in, &n, it);
-    cbor_assert(err == CborNoError);
-
-    uint_least32_t val = 0;
-    for (i = 0; n - i >= 3; i += 3) {
-        /* read 3 bytes x 8 bits = 24 bits */
-        if (false) {
-#ifdef __GNUC__
-        } else if (i) {
-            __builtin_memcpy(&val, in + i - 1, sizeof(val));
-            val = cbor_ntohl(val);
-#endif
-        } else {
-            val = (in[i] << 16) | (in[i + 1] << 8) | in[i + 2];
-        }
-
-        /* write 4 chars x 6 bits = 24 bits */
-        *out++ = alphabet[(val >> 18) & 0x3f];
-        *out++ = alphabet[(val >> 12) & 0x3f];
-        *out++ = alphabet[(val >> 6) & 0x3f];
-        *out++ = alphabet[val & 0x3f];
-    }
-
-    /* maybe 1 or 2 bytes left */
-    if (n - i) {
-        /* we can read in[i + 1] even if it's past the end of the string because
-         * we know (by construction) that it's a NUL byte */
-#ifdef __GNUC__
-        uint16_t val16;
-        __builtin_memcpy(&val16, in + i, sizeof(val16));
-        val = cbor_ntohs(val16);
-#else
-        val = (in[i] << 8) | in[i + 1];
-#endif
-        val <<= 8;
-
-        /* the 65th character in the alphabet is our filler: either '=' or '\0' */
-        out[4] = '\0';
-        out[3] = alphabet[64];
-        if (n - i == 2) {
-            /* write the third char in 3 chars x 6 bits = 18 bits */
-            out[2] = alphabet[(val >> 6) & 0x3f];
-        } else {
-            out[2] = alphabet[64];  /* filler */
-        }
-        out[1] = alphabet[(val >> 12) & 0x3f];
-        out[0] = alphabet[(val >> 18) & 0x3f];
-    } else {
-        out[0] = '\0';
-    }
-
-    return CborNoError;
-}
-
-static CborError dump_bytestring_base64(char **result, CborValue *it)
-{
-    static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
-                                   "ghijklmn" "opqrstuv" "wxyz0123" "456789+/" "=";
-    return generic_dump_base64(result, it, alphabet);
-}
-
-static CborError dump_bytestring_base64url(char **result, CborValue *it)
-{
-    static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
-                                   "ghijklmn" "opqrstuv" "wxyz0123" "456789-_";
-    return generic_dump_base64(result, it, alphabet);
-}
-
-static CborError add_value_metadata(FILE *out, CborType type, const ConversionStatus *status)
-{
-    int flags = status->flags;
-    if (flags & TypeWasTagged) {
-        /* extract the tagged type, which may be JSON native */
-        type = flags & FinalTypeMask;
-        flags &= ~(FinalTypeMask | TypeWasTagged);
-
-        if (fprintf(out, "\"tag\":\"%" PRIu64 "\"%s", status->lastTag,
-                    flags & ~TypeWasTagged ? "," : "") < 0)
-            return CborErrorIO;
-    }
-
-    if (!flags)
-        return CborNoError;
-
-    /* print at least the type */
-    if (fprintf(out, "\"t\":%d", type) < 0)
-        return CborErrorIO;
-
-    if (flags & NumberWasNaN)
-        if (fprintf(out, ",\"v\":\"nan\"") < 0)
-            return CborErrorIO;
-    if (flags & NumberWasInfinite)
-        if (fprintf(out, ",\"v\":\"%sinf\"", flags & NumberWasNegative ? "-" : "") < 0)
-            return CborErrorIO;
-    if (flags & NumberPrecisionWasLost)
-        if (fprintf(out, ",\"v\":\"%c%" PRIx64 "\"", flags & NumberWasNegative ? '-' : '+',
-                    status->originalNumber) < 0)
-            return CborErrorIO;
-    if (type == CborSimpleType)
-        if (fprintf(out, ",\"v\":%d", (int)status->originalNumber) < 0)
-            return CborErrorIO;
-    return CborNoError;
-}
-
-static CborError find_tagged_type(CborValue *it, CborTag *tag, CborType *type)
-{
-    CborError err = CborNoError;
-    *type = cbor_value_get_type(it);
-    while (*type == CborTagType) {
-        cbor_value_get_tag(it, tag);    /* can't fail */
-        err = cbor_value_advance_fixed(it);
-        if (err)
-            return err;
-
-        *type = cbor_value_get_type(it);
-    }
-    return err;
-}
-
-static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
-{
-    CborTag tag;
-    CborError err;
-
-    if (flags & CborConvertTagsToObjects) {
-        cbor_value_get_tag(it, &tag);       /* can't fail */
-        err = cbor_value_advance_fixed(it);
-        if (err)
-            return err;
-
-        if (fprintf(out, "{\"tag%" PRIu64 "\":", tag) < 0)
-            return CborErrorIO;
-
-        CborType type = cbor_value_get_type(it);
-        err = value_to_json(out, it, flags, type, status);
-        if (err)
-            return err;
-        if (flags & CborConvertAddMetadata && status->flags) {
-            if (fprintf(out, ",\"tag%" PRIu64 "$cbor\":{", tag) < 0 ||
-                    add_value_metadata(out, type, status) != CborNoError ||
-                    fputc('}', out) < 0)
-                return CborErrorIO;
-        }
-        if (fputc('}', out) < 0)
-            return CborErrorIO;
-        status->flags = TypeWasNotNative | CborTagType;
-        return CborNoError;
-    }
-
-    CborType type;
-    err = find_tagged_type(it, &status->lastTag, &type);
-    if (err)
-        return err;
-    tag = status->lastTag;
-
-    /* special handling of byte strings? */
-    if (type == CborByteStringType && (flags & CborConvertByteStringsToBase64Url) == 0 &&
-            (tag == CborNegativeBignumTag || tag == CborExpectedBase16Tag || tag == CborExpectedBase64Tag)) {
-        char *str;
-        char *pre = "";
-
-        if (tag == CborNegativeBignumTag) {
-            pre = "~";
-            err = dump_bytestring_base64url(&str, it);
-        } else if (tag == CborExpectedBase64Tag) {
-            err = dump_bytestring_base64(&str, it);
-        } else { /* tag == CborExpectedBase16Tag */
-            err = dump_bytestring_base16(&str, it);
-        }
-        if (err)
-            return err;
-        err = fprintf(out, "\"%s%s\"", pre, str) < 0 ? CborErrorIO : CborNoError;
-        free(str);
-        status->flags = TypeWasNotNative | TypeWasTagged | CborByteStringType;
-        return err;
-    }
-
-    /* no special handling */
-    err = value_to_json(out, it, flags, type, status);
-    status->flags |= TypeWasTagged | type;
-    return err;
-}
-
-static CborError stringify_map_key(char **key, CborValue *it, int flags, CborType type)
-{
-    (void)flags;    /* unused */
-    (void)type;     /* unused */
-#ifdef WITHOUT_OPEN_MEMSTREAM
-    (void)key;      /* unused */
-    (void)it;       /* unused */
-    return CborErrorJsonNotImplemented;
-#else
-    size_t size;
-
-    FILE *memstream = open_memstream(key, &size);
-    if (memstream == NULL)
-        return CborErrorOutOfMemory;        /* could also be EMFILE, but it's unlikely */
-    CborError err = cbor_value_to_pretty_advance(memstream, it);
-
-    if (unlikely(fclose(memstream) < 0 || *key == NULL))
-        return CborErrorInternalError;
-    return err;
-#endif
-}
-
-static CborError array_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
-{
-    const char *comma = "";
-    while (!cbor_value_at_end(it)) {
-        if (fprintf(out, "%s", comma) < 0)
-            return CborErrorIO;
-        comma = ",";
-
-        CborError err = value_to_json(out, it, flags, cbor_value_get_type(it), status);
-        if (err)
-            return err;
-    }
-    return CborNoError;
-}
-
-static CborError map_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
-{
-    const char *comma = "";
-    CborError err;
-    while (!cbor_value_at_end(it)) {
-        char *key;
-        if (fprintf(out, "%s", comma) < 0)
-            return CborErrorIO;
-        comma = ",";
-
-        CborType keyType = cbor_value_get_type(it);
-        if (likely(keyType == CborTextStringType)) {
-            size_t n = 0;
-            err = cbor_value_dup_text_string(it, &key, &n, it);
-        } else if (flags & CborConvertStringifyMapKeys) {
-            err = stringify_map_key(&key, it, flags, keyType);
-        } else {
-            return CborErrorJsonObjectKeyNotString;
-        }
-        if (err)
-            return err;
-
-        /* first, print the key */
-        if (fprintf(out, "\"%s\":", key) < 0)
-            return CborErrorIO;
-
-        /* then, print the value */
-        CborType valueType = cbor_value_get_type(it);
-        err = value_to_json(out, it, flags, valueType, status);
-
-        /* finally, print any metadata we may have */
-        if (flags & CborConvertAddMetadata) {
-            if (!err && keyType != CborTextStringType) {
-                if (fprintf(out, ",\"%s$keycbordump\":true", key) < 0)
-                    err = CborErrorIO;
-            }
-            if (!err && status->flags) {
-                if (fprintf(out, ",\"%s$cbor\":{", key) < 0 ||
-                        add_value_metadata(out, valueType, status) != CborNoError ||
-                        fputc('}', out) < 0)
-                    err = CborErrorIO;
-            }
-        }
-
-        free(key);
-        if (err)
-            return err;
-    }
-    return CborNoError;
-}
-
-static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status)
-{
-    CborError err;
-    status->flags = 0;
-
-    switch (type) {
-    case CborArrayType:
-    case CborMapType: {
-        /* recursive type */
-        CborValue recursed;
-        err = cbor_value_enter_container(it, &recursed);
-        if (err) {
-            it->offset = recursed.offset;
-            return err;       /* parse error */
-        }
-        if (fputc(type == CborArrayType ? '[' : '{', out) < 0)
-            return CborErrorIO;
-
-        err = (type == CborArrayType) ?
-                  array_to_json(out, &recursed, flags, status) :
-                  map_to_json(out, &recursed, flags, status);
-        if (err) {
-            it->offset = recursed.offset;
-            return err;       /* parse error */
-        }
-
-        if (fputc(type == CborArrayType ? ']' : '}', out) < 0)
-            return CborErrorIO;
-        err = cbor_value_leave_container(it, &recursed);
-        if (err)
-            return err;       /* parse error */
-
-        status->flags = 0;    /* reset, there are never conversion errors for us */
-        return CborNoError;
-    }
-
-    case CborIntegerType: {
-        double num;     /* JS numbers are IEEE double precision */
-        uint64_t val;
-        cbor_value_get_raw_integer(it, &val);    /* can't fail */
-        num = (double)val;
-
-        if (cbor_value_is_negative_integer(it)) {
-            num = -num - 1;                     /* convert to negative */
-            if ((uint64_t)(-num - 1) != val) {
-                status->flags = NumberPrecisionWasLost | NumberWasNegative;
-                status->originalNumber = val;
-            }
-        } else {
-            if ((uint64_t)num != val) {
-                status->flags = NumberPrecisionWasLost;
-                status->originalNumber = val;
-            }
-        }
-        if (fprintf(out, "%.0f", num) < 0)  /* this number has no fraction, so no decimal points please */
-            return CborErrorIO;
-        break;
-    }
-
-    case CborByteStringType:
-    case CborTextStringType: {
-        char *str;
-        if (type == CborByteStringType) {
-            err = dump_bytestring_base64url(&str, it);
-            status->flags = TypeWasNotNative;
-        } else {
-            size_t n = 0;
-            err = cbor_value_dup_text_string(it, &str, &n, it);
-        }
-        if (err)
-            return err;
-        err = (fprintf(out, "\"%s\"", str) < 0) ? CborErrorIO : CborNoError;
-        free(str);
-        return err;
-    }
-
-    case CborTagType:
-        return tagged_value_to_json(out, it, flags, status);
-
-    case CborSimpleType: {
-        uint8_t simple_type;
-        cbor_value_get_simple_type(it, &simple_type);  /* can't fail */
-        status->flags = TypeWasNotNative;
-        status->originalNumber = simple_type;
-        if (fprintf(out, "\"simple(%" PRIu8 ")\"", simple_type) < 0)
-            return CborErrorIO;
-        break;
-    }
-
-    case CborNullType:
-        if (fprintf(out, "null") < 0)
-            return CborErrorIO;
-        break;
-
-    case CborUndefinedType:
-        status->flags = TypeWasNotNative;
-        if (fprintf(out, "\"undefined\"") < 0)
-            return CborErrorIO;
-        break;
-
-    case CborBooleanType: {
-        bool val;
-        cbor_value_get_boolean(it, &val);       /* can't fail */
-        if (fprintf(out, val ? "true" : "false") < 0)
-            return CborErrorIO;
-        break;
-    }
-#ifndef NO_FLOAT_SUPPORT
-    case CborDoubleType: {
-        double val;
-        if (false) {
-            float f;
-    case CborFloatType:
-            status->flags = TypeWasNotNative;
-            cbor_value_get_float(it, &f);
-            val = f;
-        } else if (false) {
-            uint16_t f16;
-    case CborHalfFloatType:
-            status->flags = TypeWasNotNative;
-            cbor_value_get_half_float(it, &f16);
-            val = decode_half(f16);
-        } else {
-            cbor_value_get_double(it, &val);
-        }
-
-        int r = fpclassify(val);
-        if (r == FP_NAN || r == FP_INFINITE) {
-            if (fprintf(out, "null") < 0)
-                return CborErrorIO;
-            status->flags |= r == FP_NAN ? NumberWasNaN :
-                                           NumberWasInfinite | (val < 0 ? NumberWasNegative : 0);
-        } else {
-            uint64_t ival = (uint64_t)fabs(val);
-            if ((double)ival == fabs(val)) {
-                /* print as integer so we get the full precision */
-                r = fprintf(out, "%s%" PRIu64, val < 0 ? "-" : "", ival);
-                status->flags |= TypeWasNotNative;   /* mark this integer number as a double */
-            } else {
-                /* this number is definitely not a 64-bit integer */
-                r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g", val);
-            }
-            if (r < 0)
-                return CborErrorIO;
-        }
-        break;
-    }
-#endif
-
-    case CborInvalidType:
-    default:
-        return CborErrorUnknownType;
-    }
-
-    return cbor_value_advance_fixed(it);
-}
-
-/**
-
- * \enum CborToJsonFlags
- * The CborToJsonFlags enum contains flags that control the conversion of CBOR to JSON.
- *
- * \value CborConvertAddMetadata        Adds metadata to facilitate restoration of the original CBOR data.
- * \value CborConvertTagsToObjects      Converts CBOR tags to JSON objects
- * \value CborConvertIgnoreTags         (default) Ignore CBOR tags, except for byte strings
- * \value CborConvertObeyByteStringTags (default) Honor formatting of CBOR byte strings if so tagged
- * \value CborConvertByteStringsToBase64Url Force the conversion of all CBOR byte strings to Base64url encoding, despite any tags
- * \value CborConvertRequireMapStringKeys (default) Require CBOR map keys to be strings, failing the conversion if they are not
- * \value CborConvertStringifyMapKeys   Convert non-string keys in CBOR maps to a string form
- * \value CborConvertDefaultFlags       Default conversion flags.
- */
-
-/**
- * \fn CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags)
- *
- * Converts the current CBOR type pointed by \a value to JSON and writes that
- * to the \a out stream. If an error occurs, this function returns an error
- * code similar to CborParsing. The \a flags parameter indicates one of the
- * flags from CborToJsonFlags that control the conversion.
- *
- * \sa cbor_value_to_json_advance(), cbor_value_to_pretty()
- */
-
-/**
- * Converts the current CBOR type pointed by \a value to JSON and writes that
- * to the \a out stream. If an error occurs, this function returns an error
- * code similar to CborParsing. The \a flags parameter indicates one of the
- * flags from CborToJsonFlags that control the conversion.
- *
- * If no error ocurred, this function advances \a value to the next element.
- *
- * \sa cbor_value_to_json(), cbor_value_to_pretty_advance()
- */
-CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags)
-{
-    ConversionStatus status;
-    return value_to_json(out, value, flags, cbor_value_get_type(value), &status);
-}
-
-/** @} */
diff --git a/ext/tinycbor/src/cborvalidation.c b/ext/tinycbor/src/cborvalidation.c
deleted file mode 100644
index 4d093e4..0000000
--- a/ext/tinycbor/src/cborvalidation.c
+++ /dev/null
@@ -1,675 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE 1
-#endif
-#ifndef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE 1
-#endif
-#ifndef __STDC_LIMIT_MACROS
-#  define __STDC_LIMIT_MACROS 1
-#endif
-
-#include "cbor.h"
-#include "cborinternal_p.h"
-#include "compilersupport_p.h"
-#include "utf8_p.h"
-
-#include <string.h>
-
-#ifndef CBOR_NO_FLOATING_POINT
-#  include <float.h>
-#  include <math.h>
-#endif
-
-
-#ifndef CBOR_PARSER_MAX_RECURSIONS
-#  define CBOR_PARSER_MAX_RECURSIONS 1024
-#endif
-
-/**
- * \addtogroup CborParsing
- * @{
- */
-
-/**
- * \enum CborValidationFlags
- * The CborValidationFlags enum contains flags that control the validation of a
- * CBOR stream.
- *
- * \value CborValidateBasic         Validates only the syntax correctedness of the stream.
- * \value CborValidateCanonical     Validates that the stream is in canonical format, according to
- *                                  RFC 7049 section 3.9.
- * \value CborValidateStrictMode    Performs strict validation, according to RFC 7049 section 3.10.
- * \value CborValidateStrictest     Attempt to perform the strictest validation we know of.
- *
- * \value CborValidateShortestIntegrals     (Canonical) Validate that integral numbers and lengths are
- *                                          enconded in their shortest form possible.
- * \value CborValidateShortestFloatingPoint (Canonical) Validate that floating-point numbers are encoded
- *                                          in their shortest form possible.
- * \value CborValidateShortestNumbers       (Canonical) Validate both integrals and floating-point numbers
- *                                          are in their shortest form possible.
- * \value CborValidateNoIndeterminateLength (Canonical) Validate that no string, array or map uses
- *                                          indeterminate length encoding.
- * \value CborValidateMapIsSorted           (Canonical & Strict mode) Validate that map keys appear in
- *                                          sorted order.
- * \value CborValidateMapKeysAreUnique      (Strict mode) Validate that map keys are unique.
- * \value CborValidateTagUse                (Strict mode) Validate that known tags are used with the
- *                                          correct types. This does not validate that the content of
- *                                          those types is syntactically correct.
- * \value CborValidateUtf8                  (Strict mode) Validate that text strings are appropriately
- *                                          encoded in UTF-8.
- * \value CborValidateMapKeysAreString      Validate that all map keys are text strings.
- * \value CborValidateNoUndefined           Validate that no elements of type "undefined" are present.
- * \value CborValidateNoTags                Validate that no tags are used.
- * \value CborValidateFiniteFloatingPoint   Validate that all floating point numbers are finite (no NaN or
- *                                          infinities are allowed).
- * \value CborValidateCompleteData          Validate that the stream is complete and there is no more data
- *                                          in the buffer.
- * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
- *                                          with IANA.
- * \value CborValidateNoUnknownSimpleTypes  Validate that all simple types used are registered with IANA.
- * \value CborValidateNoUnknownTagsSA       Validate that all Standard Actions tags are registered with IANA.
- * \value CborValidateNoUnknownTagsSR       Validate that all Standard Actions and Specification Required tags
- *                                          are registered with IANA (see below for limitations).
- * \value CborValidateNoUnkonwnTags         Validate that all tags are registered with IANA
- *                                          (see below for limitations).
- *
- * \par Simple type registry
- * The CBOR specification requires that registration for use of the first 19
- * simple types must be done by way of Standards Action. The rest of the simple
- * types only require a specification. The official list can be obtained from
- *  https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml.
- *
- * \par
- * There are no registered simple types recognized by this release of TinyCBOR
- * (beyond those defined by RFC 7049).
- *
- * \par Tag registry
- * The CBOR specification requires that registration for use of the first 23
- * tags must be done by way of Standards Action. The next up to tag 255 only
- * require a specification. Finally, all other tags can be registered on a
- * first-come-first-serve basis. The official list can be ontained from
- *  https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml.
- *
- * \par
- * Given the variability of this list, TinyCBOR cannot recognize all tags
- * registered with IANA. Instead, the implementation only recognizes tags
- * that are backed by an RFC.
- *
- * \par
- * These are the tags known to the current TinyCBOR release:
-<table>
-  <tr>
-    <th>Tag</th>
-    <th>Data Item</th>
-    <th>Semantics</th>
-  </tr>
-  <tr>
-    <td>0</td>
-    <td>UTF-8 text string</td>
-    <td>Standard date/time string</td>
-  </td>
-  <tr>
-    <td>1</td>
-    <td>integer</td>
-    <td>Epoch-based date/time</td>
-  </td>
-  <tr>
-    <td>2</td>
-    <td>byte string</td>
-    <td>Positive bignum</td>
-  </td>
-  <tr>
-    <td>3</td>
-    <td>byte string</td>
-    <td>Negative bignum</td>
-  </td>
-  <tr>
-    <td>4</td>
-    <td>array</td>
-    <td>Decimal fraction</td>
-  </td>
-  <tr>
-    <td>5</td>
-    <td>array</td>
-    <td>Bigfloat</td>
-  </td>
-  <tr>
-    <td>16</td>
-    <td>array</td>
-    <td>COSE Single Recipient Encrypted Data Object (RFC 8152)</td>
-  </td>
-  <tr>
-    <td>17</td>
-    <td>array</td>
-    <td>COSE Mac w/o Recipients Object (RFC 8152)</td>
-  </td>
-  <tr>
-    <td>18</td>
-    <td>array</td>
-    <td>COSE Single Signer Data Object (RFC 8162)</td>
-  </td>
-  <tr>
-    <td>21</td>
-    <td>byte string, array, map</td>
-    <td>Expected conversion to base64url encoding</td>
-  </td>
-  <tr>
-    <td>22</td>
-    <td>byte string, array, map</td>
-    <td>Expected conversion to base64 encoding</td>
-  </td>
-  <tr>
-    <td>23</td>
-    <td>byte string, array, map</td>
-    <td>Expected conversion to base16 encoding</td>
-  </td>
-  <tr>
-    <td>24</td>
-    <td>byte string</td>
-    <td>Encoded CBOR data item</td>
-  </td>
-  <tr>
-    <td>32</td>
-    <td>UTF-8 text string</td>
-    <td>URI</td>
-  </td>
-  <tr>
-    <td>33</td>
-    <td>UTF-8 text string</td>
-    <td>base64url</td>
-  </td>
-  <tr>
-    <td>34</td>
-    <td>UTF-8 text string</td>
-    <td>base64</td>
-  </td>
-  <tr>
-    <td>35</td>
-    <td>UTF-8 text string</td>
-    <td>Regular expression</td>
-  </td>
-  <tr>
-    <td>36</td>
-    <td>UTF-8 text string</td>
-    <td>MIME message</td>
-  </td>
-  <tr>
-    <td>96</td>
-    <td>array</td>
-    <td>COSE Encrypted Data Object (RFC 8152)</td>
-  </td>
-  <tr>
-    <td>97</td>
-    <td>array</td>
-    <td>COSE MACed Data Object (RFC 8152)</td>
-  </td>
-  <tr>
-    <td>98</td>
-    <td>array</td>
-    <td>COSE Signed Data Object (RFC 8152)</td>
-  </td>
-  <tr>
-    <td>55799</td>
-    <td>any</td>
-    <td>Self-describe CBOR</td>
-  </td>
-</table>
- */
-
-struct KnownTagData { uint32_t tag; uint32_t types; };
-static const struct KnownTagData knownTagData[] = {
-    { 0, (uint8_t)CborTextStringType },
-    { 1, (uint8_t)(CborIntegerType+1) },
-    { 2, (uint8_t)CborByteStringType },
-    { 3, (uint8_t)CborByteStringType },
-    { 4, (uint8_t)CborArrayType },
-    { 5, (uint8_t)CborArrayType },
-    { 16, (uint8_t)CborArrayType },
-    { 17, (uint8_t)CborArrayType },
-    { 18, (uint8_t)CborArrayType },
-    { 21, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
-    { 22, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
-    { 23, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
-    { 24, (uint8_t)CborByteStringType },
-    { 32, (uint8_t)CborTextStringType },
-    { 33, (uint8_t)CborTextStringType },
-    { 34, (uint8_t)CborTextStringType },
-    { 35, (uint8_t)CborTextStringType },
-    { 36, (uint8_t)CborTextStringType },
-    { 96, (uint8_t)CborArrayType },
-    { 97, (uint8_t)CborArrayType },
-    { 98, (uint8_t)CborArrayType },
-    { 55799, 0U }
-};
-
-static CborError validate_value(CborValue *it, int flags, int recursionLeft);
-
-static inline CborError validate_utf8_string(const void *ptr, size_t n)
-{
-    const uint8_t *buffer = (const uint8_t *)ptr;
-    const uint8_t * const end = buffer + n;
-    while (buffer < end) {
-        uint32_t uc = get_utf8(&buffer, end);
-        if (uc == ~0U)
-            return CborErrorInvalidUtf8TextString;
-    }
-    return CborNoError;
-}
-
-static inline CborError validate_simple_type(uint8_t simple_type, int flags)
-{
-    /* At current time, all known simple types are those from RFC 7049,
-     * which are parsed by the parser into different CBOR types.
-     * That means that if we've got here, the type is unknown */
-    if (simple_type < 32)
-        return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError;
-    return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ?
-                CborErrorUnknownSimpleType : CborNoError;
-}
-
-static inline CborError validate_number(const CborValue *it, CborType type, int flags)
-{
-    CborError err = CborNoError;
-    uint64_t value;
-    int offset;
-
-    if ((flags & CborValidateShortestIntegrals) == 0)
-        return err;
-    if (type >= CborHalfFloatType && type <= CborDoubleType)
-        return err;     /* checked elsewhere */
-
-    offset = it->offset;
-    err = _cbor_value_extract_number(it->parser, &offset, &value);
-    if (err)
-        return err;
-
-    size_t bytesUsed = (size_t)(offset - it->offset - 1);
-    size_t bytesNeeded = 0;
-    if (value >= Value8Bit)
-        ++bytesNeeded;
-    if (value > 0xffU)
-        ++bytesNeeded;
-    if (value > 0xffffU)
-        bytesNeeded += 2;
-    if (value > 0xffffffffU)
-        bytesNeeded += 4;
-    if (bytesNeeded < bytesUsed)
-        return CborErrorOverlongEncoding;
-    return CborNoError;
-}
-
-static inline CborError validate_tag(CborValue *it, CborTag tag, int flags, int recursionLeft)
-{
-    CborType type = cbor_value_get_type(it);
-    const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
-    const struct KnownTagData *tagData = knownTagData;
-    const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
-
-    if (!recursionLeft)
-        return CborErrorNestingTooDeep;
-    if (flags & CborValidateNoTags)
-        return CborErrorExcludedType;
-
-    /* find the tag data, if any */
-    for ( ; tagData != knownTagDataEnd; ++tagData) {
-        if (tagData->tag < tag)
-            continue;
-        if (tagData->tag > tag)
-            tagData = NULL;
-        break;
-    }
-    if (tagData == knownTagDataEnd)
-        tagData = NULL;
-
-    if (flags & CborValidateNoUnknownTags && !tagData) {
-        /* tag not found */
-        if (flags & CborValidateNoUnknownTagsSA && tag < 24)
-            return CborErrorUnknownTag;
-        if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
-            return CborErrorUnknownTag;
-        if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
-            return CborErrorUnknownTag;
-    }
-
-    if (flags & CborValidateTagUse && tagData && tagData->types) {
-        uint32_t allowedTypes = tagData->types;
-
-        /* correct Integer so it's not zero */
-        if (type == CborIntegerType)
-            type = (CborType)(type + 1);
-
-        while (allowedTypes) {
-            if ((uint8_t)(allowedTypes & 0xff) == type)
-                break;
-            allowedTypes >>= 8;
-        }
-        if (!allowedTypes)
-            return CborErrorInappropriateTagForType;
-    }
-
-    return validate_value(it, flags, recursionLeft);
-}
-
-#ifndef CBOR_NO_FLOATING_POINT
-static inline CborError validate_floating_point(CborValue *it, CborType type, int flags)
-{
-    CborError err;
-    double val;
-    float valf;
-    uint16_t valf16;
-
-    if (type != CborDoubleType) {
-        if (type == CborFloatType) {
-            err = cbor_value_get_float(it, &valf);
-            val = valf;
-        } else {
-#  ifdef CBOR_NO_HALF_FLOAT_TYPE
-            (void)val16;
-            return CborErrorUnsupportedType;
-#  else
-            err = cbor_value_get_half_float(it, &valf16);
-            val = decode_half(valf16);
-#  endif
-        }
-    } else {
-        err = cbor_value_get_double(it, &val);
-    }
-    cbor_assert(err == CborNoError);     /* can't fail */
-
-    int r = fpclassify(val);
-    if (r == FP_NAN || r == FP_INFINITE) {
-        if (flags & CborValidateFiniteFloatingPoint)
-            return CborErrorExcludedValue;
-        if (flags & CborValidateShortestFloatingPoint) {
-            if (type == CborDoubleType)
-                return CborErrorOverlongEncoding;
-#  ifndef CBOR_NO_HALF_FLOAT_TYPE
-            if (type == CborFloatType)
-                return CborErrorOverlongEncoding;
-            if (r == FP_NAN && valf16 != 0x7e00)
-                return CborErrorImproperValue;
-            if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
-                return CborErrorImproperValue;
-#  endif
-        }
-    }
-
-    if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
-        if (type == CborDoubleType) {
-            valf = (float)val;
-            if ((double)valf == val)
-                return CborErrorOverlongEncoding;
-        }
-#  ifndef CBOR_NO_HALF_FLOAT_TYPE
-        if (type == CborFloatType) {
-            valf16 = encode_half(valf);
-            if (valf == decode_half(valf16))
-                return CborErrorOverlongEncoding;
-        }
-#  endif
-    }
-
-    return CborNoError;
-}
-#endif
-
-static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft)
-{
-    CborError err;
-    int previous = -1;
-    int previous_end;
-
-    if (!recursionLeft)
-        return CborErrorNestingTooDeep;
-
-    while (!cbor_value_at_end(it)) {
-        int current;
-
-        if (containerType == CborMapType) {
-            current = it->offset;
-            if (flags & CborValidateMapKeysAreString) {
-                CborType type = cbor_value_get_type(it);
-                if (type == CborTagType) {
-                    /* skip the tags */
-                    CborValue copy = *it;
-                    err = cbor_value_skip_tag(&copy);
-                    if (err)
-                        return err;
-                    type = cbor_value_get_type(&copy);
-                }
-                if (type != CborTextStringType)
-                    return CborErrorMapKeyNotString;
-            }
-        }
-
-        err = validate_value(it, flags, recursionLeft);
-        if (err)
-            return err;
-
-        if (containerType != CborMapType)
-            continue;
-
-        if (flags & CborValidateMapIsSorted) {
-            if (previous != -1) {
-                uint64_t len1, len2;
-                int offset;
-
-                /* extract the two lengths */
-                offset = previous;
-                _cbor_value_extract_number(it->parser, &offset, &len1);
-                offset = current;
-                _cbor_value_extract_number(it->parser, &offset, &len2);
-
-                if (len1 > len2)
-                    return CborErrorMapNotSorted;
-                if (len1 == len2) {
-                    int bytelen1 = (previous_end - previous);
-                    int bytelen2 = (it->offset - current);
-                    int i;
-
-                    for (i = 0; i < (bytelen1 <= bytelen2 ? bytelen1 : bytelen2); i++) {
-                        int r = it->parser->d->get8(it->parser->d, previous + i) -
-                            it->parser->d->get8(it->parser->d, current + i);
-
-                        if (r < 0) {
-                            break;
-                        }
-                        if (r == 0 && bytelen1 != bytelen2)
-                            r = bytelen1 < bytelen2 ? -1 : +1;
-                        if (r > 0)
-                            return CborErrorMapNotSorted;
-                        if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique)
-                            return CborErrorMapKeysNotUnique;
-                    }
-                }
-            }
-
-            previous = current;
-            previous_end = it->offset;
-        }
-
-        /* map: that was the key, so get the value */
-        err = validate_value(it, flags, recursionLeft);
-        if (err)
-            return err;
-    }
-    return CborNoError;
-}
-
-static CborError validate_value(CborValue *it, int flags, int recursionLeft)
-{
-    CborError err;
-    CborType type = cbor_value_get_type(it);
-
-    if (cbor_value_is_length_known(it)) {
-        err = validate_number(it, type, flags);
-        if (err)
-            return err;
-    } else {
-        if (flags & CborValidateNoIndeterminateLength)
-            return CborErrorUnknownLength;
-    }
-
-    switch (type) {
-    case CborArrayType:
-    case CborMapType: {
-        /* recursive type */
-        CborValue recursed;
-        err = cbor_value_enter_container(it, &recursed);
-        if (!err)
-            err = validate_container(&recursed, type, flags, recursionLeft - 1);
-        if (err) {
-            it->offset = recursed.offset;
-            return err;
-        }
-        err = cbor_value_leave_container(it, &recursed);
-        if (err)
-            return err;
-        return CborNoError;
-    }
-
-    case CborIntegerType: {
-        uint64_t val;
-        err = cbor_value_get_raw_integer(it, &val);
-        cbor_assert(err == CborNoError);         /* can't fail */
-
-        break;
-    }
-
-    case CborByteStringType:
-    case CborTextStringType: {
-        size_t n = 0;
-        const void *ptr;
-
-        err = _cbor_value_prepare_string_iteration(it);
-        if (err)
-            return err;
-
-        while (1) {
-            err = validate_number(it, type, flags);
-            if (err)
-                return err;
-
-            err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
-            if (err)
-                return err;
-            if (!ptr)
-                break;
-
-            if (type == CborTextStringType && flags & CborValidateUtf8) {
-                err = validate_utf8_string(ptr, n);
-                if (err)
-                    return err;
-            }
-        }
-
-        return CborNoError;
-    }
-
-    case CborTagType: {
-        CborTag tag;
-        err = cbor_value_get_tag(it, &tag);
-        cbor_assert(err == CborNoError);     /* can't fail */
-
-        err = cbor_value_advance_fixed(it);
-        if (err)
-            return err;
-        err = validate_tag(it, tag, flags, recursionLeft - 1);
-        if (err)
-            return err;
-
-        return CborNoError;
-    }
-
-    case CborSimpleType: {
-        uint8_t simple_type;
-        err = cbor_value_get_simple_type(it, &simple_type);
-        cbor_assert(err == CborNoError);     /* can't fail */
-        err = validate_simple_type(simple_type, flags);
-        if (err)
-            return err;
-        break;
-    }
-
-    case CborNullType:
-    case CborBooleanType:
-        break;
-
-    case CborUndefinedType:
-        if (flags & CborValidateNoUndefined)
-            return CborErrorExcludedType;
-        break;
-
-    case CborHalfFloatType:
-    case CborFloatType:
-    case CborDoubleType: {
-#ifdef CBOR_NO_FLOATING_POINT
-        return CborErrorUnsupportedType;
-#else
-        err = validate_floating_point(it, type, flags);
-        if (err)
-            return err;
-        break;
-    }
-#endif /* !CBOR_NO_FLOATING_POINT */
-
-    case CborInvalidType:
-        return CborErrorUnknownType;
-    }
-
-    err = cbor_value_advance_fixed(it);
-    return err;
-}
-
-/**
- * Performs a full validation controlled by the \a flags options of the CBOR
- * stream pointed by \a it and returns the error it found. If no error was
- * found, it returns CborNoError and the application can iterate over the items
- * with certainty that no other errors will appear during parsing.
- *
- * If \a flags is CborValidateBasic, the result should be the same as
- * cbor_value_validate_basic().
- *
- * This function has the same timing and memory requirements as
- * cbor_value_advance() and cbor_value_validate_basic().
- *
- * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
- */
-CborError cbor_value_validate(const CborValue *it, int flags)
-{
-    CborValue value = *it;
-    CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
-    if (err)
-        return err;
-    if (flags & CborValidateCompleteData && it->offset != it->parser->end)
-        return CborErrorGarbageAtEnd;
-    return CborNoError;
-}
-
-/**
- * @}
- */
diff --git a/ext/tinycbor/src/compilersupport_p.h b/ext/tinycbor/src/compilersupport_p.h
deleted file mode 100644
index b7831f9..0000000
--- a/ext/tinycbor/src/compilersupport_p.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef COMPILERSUPPORT_H
-#define COMPILERSUPPORT_H
-
-#include "cbor.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _BSD_SOURCE
-#  define _BSD_SOURCE
-#endif
-#ifndef _DEFAULT_SOURCE
-#  define _DEFAULT_SOURCE
-#endif
-#ifndef assert
-#  include <assert.h>
-#endif
-#include <float.h>
-#include <math.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#ifndef __cplusplus
-#  include <stdbool.h>
-#endif
-
-#ifdef __F16C__
-#  include <immintrin.h>
-#endif
-
-#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L || __cpp_static_assert >= 200410
-#  define cbor_static_assert(x)         static_assert(x, #x)
-#elif !defined(__cplusplus) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && (__STDC_VERSION__ > 199901L)
-#  define cbor_static_assert(x)         static_assert(x, #x)
-#else
-#  define cbor_static_assert(x)         ((void)sizeof(char[2*!!(x) - 1]))
-#endif
-#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
-/* inline is a keyword */
-#else
-/* use the definition from cbor.h */
-#  define inline    CBOR_INLINE
-#endif
-
-#ifdef NDEBUG
-#  define cbor_assert(cond)     do { if (!(cond)) unreachable(); } while (0)
-#else
-#  define cbor_assert(cond)     assert(cond)
-#endif
-
-#ifndef STRINGIFY
-#define STRINGIFY(x)            STRINGIFY2(x)
-#endif
-#define STRINGIFY2(x)           #x
-
-#if !defined(UINT32_MAX) || !defined(INT64_MAX)
-/* C89? We can define UINT32_MAX portably, but not INT64_MAX */
-#  error "Your system has stdint.h but that doesn't define UINT32_MAX or INT64_MAX"
-#endif
-
-#ifndef DBL_DECIMAL_DIG
-/* DBL_DECIMAL_DIG is C11 */
-#  define DBL_DECIMAL_DIG       17
-#endif
-#define DBL_DECIMAL_DIG_STR     STRINGIFY(DBL_DECIMAL_DIG)
-
-#if defined(__GNUC__) && defined(__i386__) && !defined(__iamcu__)
-#  define CBOR_INTERNAL_API_CC          __attribute__((regparm(3)))
-#elif defined(_MSC_VER) && defined(_M_IX86)
-#  define CBOR_INTERNAL_API_CC          __fastcall
-#else
-#  define CBOR_INTERNAL_API_CC
-#endif
-
-#ifndef __has_builtin
-#  define __has_builtin(x)  0
-#endif
-
-#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) || \
-    (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32))
-#  if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-#    define cbor_ntohll     __builtin_bswap64
-#    define cbor_htonll     __builtin_bswap64
-#    define cbor_ntohl      __builtin_bswap32
-#    define cbor_htonl      __builtin_bswap32
-#    ifdef __INTEL_COMPILER
-#      define cbor_ntohs    _bswap16
-#      define cbor_htons    _bswap16
-#    elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16)
-#      define cbor_ntohs    __builtin_bswap16
-#      define cbor_htons    __builtin_bswap16
-#    else
-#      define cbor_ntohs(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8))
-#      define cbor_htons    cbor_ntohs
-#    endif
-#  else
-#    define cbor_ntohll
-#    define cbor_htonll
-#    define cbor_ntohl
-#    define cbor_htonl
-#    define cbor_ntohs
-#    define cbor_htons
-#  endif
-#elif defined(__sun)
-#  include <sys/byteorder.h>
-#elif defined(_MSC_VER)
-/* MSVC, which implies Windows, which implies little-endian and sizeof(long) == 4 */
-#  include <stdlib.h>
-#  define cbor_ntohll       _byteswap_uint64
-#  define cbor_htonll       _byteswap_uint64
-#  define cbor_ntohl        _byteswap_ulong
-#  define cbor_htonl        _byteswap_ulong
-#  define cbor_ntohs        _byteswap_ushort
-#  define cbor_htons        _byteswap_ushort
-#endif
-#ifndef cbor_ntohs
-#  include <arpa/inet.h>
-#  define cbor_ntohs        ntohs
-#  define cbor_htons        htons
-#endif
-#ifndef cbor_ntohl
-#  include <arpa/inet.h>
-#  define cbor_ntohl        ntohl
-#  define cbor_htonl        htonl
-#endif
-#ifndef cbor_ntohll
-#  define cbor_ntohll       ntohll
-#  define cbor_htonll       htonll
-/* ntohll isn't usually defined */
-#  ifndef ntohll
-#    if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#      define ntohll
-#      define htonll
-#    elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-#      define ntohll(x)       ((ntohl((uint32_t)(x)) * UINT64_C(0x100000000)) + (ntohl((x) >> 32)))
-#      define htonll          ntohll
-#    else
-#      error "Unable to determine byte order!"
-#    endif
-#  endif
-#endif
-
-
-#ifdef __cplusplus
-#  define CONST_CAST(t, v)  const_cast<t>(v)
-#else
-/* C-style const_cast without triggering a warning with -Wcast-qual */
-#  define CONST_CAST(t, v)  (t)(uintptr_t)(v)
-#endif
-
-#ifdef __GNUC__
-#ifndef likely
-#  define likely(x)     __builtin_expect(!!(x), 1)
-#endif
-#ifndef unlikely
-#  define unlikely(x)   __builtin_expect(!!(x), 0)
-#endif
-#  define unreachable() __builtin_unreachable()
-#elif defined(_MSC_VER)
-#  define likely(x)     (x)
-#  define unlikely(x)   (x)
-#  define unreachable() __assume(0)
-#else
-#  define likely(x)     (x)
-#  define unlikely(x)   (x)
-#  define unreachable() do {} while (0)
-#endif
-
-static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r)
-{
-#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow)
-    return __builtin_add_overflow(v1, v2, r);
-#else
-    /* unsigned additions are well-defined */
-    *r = v1 + v2;
-    return v1 > v1 + v2;
-#endif
-}
-
-static inline unsigned short encode_half(double val)
-{
-#ifdef __F16C__
-    return _cvtss_sh((float)val, 3);
-#else
-    uint64_t v;
-    memcpy(&v, &val, sizeof(v));
-    int sign = v >> 63 << 15;
-    int exp = (v >> 52) & 0x7ff;
-    int mant = v << 12 >> 12 >> (53-11);    /* keep only the 11 most significant bits of the mantissa */
-    exp -= 1023;
-    if (exp == 1024) {
-        /* infinity or NaN */
-        exp = 16;
-        mant >>= 1;
-    } else if (exp >= 16) {
-        /* overflow, as largest number */
-        exp = 15;
-        mant = 1023;
-    } else if (exp >= -14) {
-        /* regular normal */
-    } else if (exp >= -24) {
-        /* subnormal */
-        mant |= 1024;
-        mant >>= -(exp + 14);
-        exp = -15;
-    } else {
-        /* underflow, make zero */
-        return 0;
-    }
-
-    /* safe cast here as bit operations above guarantee not to overflow */
-    return (unsigned short)(sign | ((exp + 15) << 10) | mant);
-#endif
-}
-
-/* this function was copied & adapted from RFC 7049 Appendix D */
-static inline double decode_half(unsigned short half)
-{
-#ifdef __F16C__
-    return _cvtsh_ss(half);
-#else
-    int exp = (half >> 10) & 0x1f;
-    int mant = half & 0x3ff;
-    double val;
-    if (exp == 0) val = ldexp(mant, -24);
-    else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
-    else val = mant == 0 ? INFINITY : NAN;
-    return half & 0x8000 ? -val : val;
-#endif
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* COMPILERSUPPORT_H */
-
diff --git a/ext/tinycbor/src/open_memstream.c b/ext/tinycbor/src/open_memstream.c
deleted file mode 100644
index eaa53e5..0000000
--- a/ext/tinycbor/src/open_memstream.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#define _BSD_SOURCE 1
-#define _DEFAULT_SOURCE 1
-#define _GNU_SOURCE 1
-
-#ifndef WITHOUT_OPEN_MEMSTREAM
-
-#include <sys/types.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if defined(__unix__) || defined(__APPLE__)
-#  include <unistd.h>
-#endif
-#ifdef __APPLE__
-typedef int RetType;
-typedef int LenType;
-#elif __GLIBC__
-typedef ssize_t RetType;
-typedef size_t LenType;
-#else
-#  error "Cannot implement open_memstream!"
-#endif
-
-#include "compilersupport_p.h"
-
-struct Buffer
-{
-    char **ptr;
-    size_t *len;
-    size_t alloc;
-};
-
-static RetType write_to_buffer(void *cookie, const char *data, LenType len)
-{
-    struct Buffer *b = (struct Buffer *)cookie;
-    char *ptr = *b->ptr;
-    size_t newsize;
-
-    errno = EFBIG;
-    if (unlikely(add_check_overflow(*b->len, len, &newsize)))
-        return -1;
-
-    if (newsize > b->alloc) {
-        // make room
-        size_t newalloc = newsize + newsize / 2 + 1;    // give 50% more room
-        ptr = realloc(ptr, newalloc);
-        if (ptr == NULL)
-            return -1;
-        b->alloc = newalloc;
-        *b->ptr = ptr;
-    }
-
-    memcpy(ptr + *b->len, data, len);
-    *b->len = newsize;
-    return len;
-}
-
-static int close_buffer(void *cookie)
-{
-    struct Buffer *b = (struct Buffer *)cookie;
-    if (*b->ptr)
-        (*b->ptr)[*b->len] = '\0';
-    free(b);
-    return 0;
-}
-
-FILE *open_memstream(char **bufptr, size_t *lenptr)
-{
-    struct Buffer *b = (struct Buffer *)malloc(sizeof(struct Buffer));
-    if (b == NULL)
-        return NULL;
-    b->alloc = 0;
-    b->len = lenptr;
-    b->ptr = bufptr;
-    *bufptr = NULL;
-    *lenptr = 0;
-
-#ifdef __APPLE__
-    return funopen(b, NULL, write_to_buffer, NULL, close_buffer);
-#elif __GLIBC__
-    static const cookie_io_functions_t vtable = {
-        NULL,
-        write_to_buffer,
-        NULL,
-        close_buffer
-    };
-    return fopencookie(b, "w", vtable);
-#endif
-}
-
-#endif
diff --git a/ext/tinycbor/src/parsetags.pl b/ext/tinycbor/src/parsetags.pl
deleted file mode 100755
index 18be146..0000000
--- a/ext/tinycbor/src/parsetags.pl
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/perl -l
-## Copyright (C) 2017 Intel Corporation
-##
-## Permission is hereby granted, free of charge, to any person obtaining a copy
-## of this software and associated documentation files (the "Software"), to deal
-## in the Software without restriction, including without limitation the rights
-## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-## copies of the Software, and to permit persons to whom the Software is
-## furnished to do so, subject to the following conditions:
-##
-## The above copyright notice and this permission notice shall be included in
-## all copies or substantial portions of the Software.
-##
-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-## THE SOFTWARE.
-##
-use strict;
-my $fname = shift @ARGV
-    or die("Usage: parsetags.pl tags.txt");
-open TAGS, "<", $fname
-    or die("Cannot open $fname: $!");
-
-my %typedescriptions = (
-    "Integer" => "integer",
-    "ByteString" => "byte string",
-    "TextString" => "UTF-8 text string",
-    "Array" => "array",
-    "Map" => "map",
-    "Tag" => "tag",     # shouldn't happen
-    "Simple" => "any simple type",
-    "Boolean" => "boolean",
-    "Null" => "null",
-    "Undefined" => "undefined",
-    "HalfFloat" => "IEEE 754 half-precision floating point",
-    "Float" => "IEEE 754 single-precision floating point",
-    "Double" => "IEEE 754 double-precision floating point"
-);
-
-my %tags;
-while (<TAGS>) {
-    s/\s*#.*$//;
-    next if /^$/;
-    chomp;
-
-    die("Could not parse line \"$_\"")
-        unless /^(\d+);(\w+);([\w,]*);(.*)$/;
-    $tags{$1}{id} = $2;
-    $tags{$1}{semantic} = $4;
-    my @types = split(',', $3);
-    $tags{$1}{types} = \@types;
-}
-close TAGS or die;
-
-my @tagnumbers = sort { $a <=> $b } keys %tags;
-
-print "==== HTML listing ====";
-print "<table>\n  <tr>\n    <th>Tag</th>\n    <th>Data Item</th>\n    <th>Semantics</th>\n  </tr>";
-for my $n (@tagnumbers) {
-    print "  <tr>";
-    print "    <td>$n</td>";
-
-    my @types = @{$tags{$n}{types}};
-    @types = map { $typedescriptions{$_}; } @types;
-    unshift @types, "any"
-        if (scalar @types == 0);
-    printf "    <td>%s</td>\n", join(', ', @types);
-    printf "    <td>%s</td>\n", $tags{$n}{semantic};
-    print "  </td>";
-}
-print "</table>";
-
-print "\n==== enum listing for cbor.h ====\n";
-printf "typedef enum CborKnownTags {";
-my $comma = "";
-for my $n (@tagnumbers) {
-    printf "%s\n    Cbor%sTag%s = %d", $comma,
-        $tags{$n}{id},
-        ' ' x (23 - length($tags{$n}{id})),
-        $n;
-    $comma = ",";
-}
-print "\n} CborKnownTags;";
-print "\n/* #define the constants so we can check with #ifdef */";
-for my $n (@tagnumbers) {
-    printf "#define Cbor%sTag Cbor%sTag\n", $tags{$n}{id}, $tags{$n}{id};
-}
-
-print "\n==== search table ====\n";
-print "struct KnownTagData { uint32_t tag; uint32_t types; };";
-printf "static const struct KnownTagData knownTagData[] = {";
-$comma = "";
-for my $n (@tagnumbers) {
-    my @types = @{$tags{$n}{types}};
-
-    my $typemask;
-    my $shift = 0;
-    for my $type (@types) {
-        die("Too many match types for tag $n") if $shift == 32;
-        my $actualtype = "Cbor${type}Type";
-        $actualtype = "($actualtype+1)" if $type eq "Integer";
-        $typemask .= " | " if $typemask ne "";
-        $typemask .= "((uint8_t)$actualtype << $shift)" if $shift;
-        $typemask .= "(uint8_t)$actualtype" unless $shift;
-        $shift += 8;
-    }
-    $typemask = "0U" if $typemask eq "";
-
-    printf "%s\n    { %d, %s }", $comma, $n, $typemask;
-    $comma = ",";
-}
-print "\n};";
diff --git a/ext/tinycbor/src/src.pri b/ext/tinycbor/src/src.pri
deleted file mode 100644
index 1624598..0000000
--- a/ext/tinycbor/src/src.pri
+++ /dev/null
@@ -1,17 +0,0 @@
-SOURCES += \
-    $$PWD/cborencoder.c \
-    $$PWD/cborerrorstrings.c \
-    $$PWD/cborparser.c \
-    $$PWD/cborparser_dup_string.c \
-    $$PWD/cborpretty.c \
-    $$PWD/cbortojson.c \
-    $$PWD/cborvalidation.c \
-    $$PWD/cbor_buf_reader.c \
-    $$PWD/cbor_buf_writer.c
-
-
-HEADERS += $$PWD/cbor.h $$PWD/tinycbor-version.h
-QMAKE_CFLAGS *= $$QMAKE_CFLAGS_SPLIT_SECTIONS
-QMAKE_LFLAGS *= $$QMAKE_LFLAGS_GCSECTIONS
-INCLUDEPATH += $$PWD/
-CONFIG(release, debug|release): DEFINES += NDEBUG
diff --git a/ext/tinycbor/src/tags.txt b/ext/tinycbor/src/tags.txt
deleted file mode 100644
index ef78cfb..0000000
--- a/ext/tinycbor/src/tags.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-# Tag number; Tag ID; Applicable types (comma-separated); Semantics
-0;DateTimeString;TextString;Standard date/time string
-1;UnixTime_t;Integer;Epoch-based date/time
-2;PositiveBignum;ByteString;Positive bignum
-3;NegativeBignum;ByteString;Negative bignum
-4;Decimal;Array;Decimal fraction
-5;Bigfloat;Array;Bigfloat
-16;COSE_Encrypt0;Array;COSE Single Recipient Encrypted Data Object (RFC 8152)
-17;COSE_Mac0;Array;COSE Mac w/o Recipients Object (RFC 8152)
-18;COSE_Sign1;Array;COSE Single Signer Data Object (RFC 8162)
-21;ExpectedBase64url;ByteString,Array,Map;Expected conversion to base64url encoding
-22;ExpectedBase64;ByteString,Array,Map;Expected conversion to base64 encoding
-23;ExpectedBase16;ByteString,Array,Map;Expected conversion to base16 encoding
-24;EncodedCbor;ByteString;Encoded CBOR data item
-32;Url;TextString;URI
-33;Base64url;TextString;base64url
-34;Base64;TextString;base64
-35;RegularExpression;TextString;Regular expression
-36;MimeMessage;TextString;MIME message
-96;COSE_Encrypt;Array;COSE Encrypted Data Object (RFC 8152)
-97;COSE_Mac;Array;COSE MACed Data Object (RFC 8152)
-98;COSE_Sign;Array;COSE Signed Data Object (RFC 8152)
-55799;Signature;;Self-describe CBOR
diff --git a/ext/tinycbor/src/tinycbor-version.h b/ext/tinycbor/src/tinycbor-version.h
deleted file mode 100644
index 19936e5..0000000
--- a/ext/tinycbor/src/tinycbor-version.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#define TINYCBOR_VERSION_MAJOR      0
-#define TINYCBOR_VERSION_MINOR      5
-#define TINYCBOR_VERSION_PATCH      0
diff --git a/ext/tinycbor/src/tinycbor.pro b/ext/tinycbor/src/tinycbor.pro
deleted file mode 100644
index 980dfd1..0000000
--- a/ext/tinycbor/src/tinycbor.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-TEMPLATE = lib
-CONFIG += static
-CONFIG -= qt
-DESTDIR = ../lib
-
-include(src.pri)
diff --git a/ext/tinycbor/src/utf8_p.h b/ext/tinycbor/src/utf8_p.h
deleted file mode 100644
index 661c428..0000000
--- a/ext/tinycbor/src/utf8_p.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#ifndef CBOR_UTF8_H
-#define CBOR_UTF8_H
-
-#include "compilersupport_p.h"
-
-#include <stdint.h>
-
-static inline uint32_t get_utf8(const uint8_t **buffer, const uint8_t *end)
-{
-    uint32_t uc;
-    ptrdiff_t n = end - *buffer;
-    if (n == 0)
-        return ~0U;
-
-    uc = *(*buffer)++;
-    if (uc < 0x80) {
-        /* single-byte UTF-8 */
-        return uc;
-    }
-
-    /* multi-byte UTF-8, decode it */
-    int charsNeeded;
-    uint32_t min_uc;
-    if (unlikely(uc <= 0xC1))
-        return ~0U;
-    if (uc < 0xE0) {
-        /* two-byte UTF-8 */
-        charsNeeded = 2;
-        min_uc = 0x80;
-        uc &= 0x1f;
-    } else if (uc < 0xF0) {
-        /* three-byte UTF-8 */
-        charsNeeded = 3;
-        min_uc = 0x800;
-        uc &= 0x0f;
-    } else if (uc < 0xF5) {
-        /* four-byte UTF-8 */
-        charsNeeded = 4;
-        min_uc = 0x10000;
-        uc &= 0x07;
-    } else {
-        return ~0U;
-    }
-
-    if (n < charsNeeded - 1)
-        return ~0U;
-
-    /* first continuation character */
-    uint8_t b = *(*buffer)++;
-    if ((b & 0xc0) != 0x80)
-        return ~0U;
-    uc <<= 6;
-    uc |= b & 0x3f;
-
-    if (charsNeeded > 2) {
-        /* second continuation character */
-        b = *(*buffer)++;
-        if ((b & 0xc0) != 0x80)
-            return ~0U;
-        uc <<= 6;
-        uc |= b & 0x3f;
-
-        if (charsNeeded > 3) {
-            /* third continuation character */
-            b = *(*buffer)++;
-            if ((b & 0xc0) != 0x80)
-                return ~0U;
-            uc <<= 6;
-            uc |= b & 0x3f;
-        }
-    }
-
-    /* overlong sequence? surrogate pair? out or range? */
-    if (uc < min_uc || uc - 0xd800U < 2048U || uc > 0x10ffff)
-        return ~0U;
-
-    return uc;
-}
-
-#endif // CBOR_UTF8_H
diff --git a/ext/tinycbor/tests/.gitignore b/ext/tinycbor/tests/.gitignore
deleted file mode 100644
index e65577d..0000000
--- a/ext/tinycbor/tests/.gitignore
+++ /dev/null
@@ -1,15 +0,0 @@
-Makefile
-debug
-moc_predefs.h
-release
-target_wrapper.*
-
-# The executables
-cpp/cpp
-cpp/cpp.exe
-encoder/encoder
-encoder/encoder.exe
-parser/parser
-parser/parser.exe
-tojson/tojson
-tojson/tojson.exe
diff --git a/ext/tinycbor/tests/cpp/cpp.pro b/ext/tinycbor/tests/cpp/cpp.pro
deleted file mode 100644
index 5e9e608..0000000
--- a/ext/tinycbor/tests/cpp/cpp.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG += testcase parallel_test c++11
-QT = core testlib
-
-SOURCES = tst_cpp.cpp
-INCLUDEPATH += ../../src
diff --git a/ext/tinycbor/tests/cpp/tst_cpp.cpp b/ext/tinycbor/tests/cpp/tst_cpp.cpp
deleted file mode 100644
index e221906..0000000
--- a/ext/tinycbor/tests/cpp/tst_cpp.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
... 4321 lines suppressed ...

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 21/42: Add doxygen comments for log_mgmt.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit f43f1dfd613dba87a8bfbe0b12374958964a434d
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Jan 30 11:40:38 2018 -0800

    Add doxygen comments for log_mgmt.
---
 cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h | 72 +++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h b/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h
index 1890643..b3f6b12 100644
--- a/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h
+++ b/cmd/log_mgmt/include/log_mgmt/log_mgmt_impl.h
@@ -17,6 +17,13 @@
  * under the License.
  */
 
+/**
+ * @file
+ * @brief Declares implementation-specific functions required by log
+ *        management.  The default stubs can be overridden with functions that
+ *        are compatible with the host OS.
+ */
+
 #ifndef H_LOG_MGMT_IMPL_
 #define H_LOG_MGMT_IMPL_
 
@@ -31,14 +38,79 @@ struct log_mgmt_log;
 typedef int log_mgmt_foreach_entry_fn(const struct log_mgmt_entry *entry,
                                       void *arg);
 
+/**
+ * @brief Retrieves the log at the specified index.
+ *
+ * @param idx                   The index of the log to retrieve.
+ * @param out_name              On success, the requested log gets written
+ *                                   here.
+ *
+ * @return                      0 on success;
+ *                              MGMT_ERR_ENOENT if no log with the specified
+ *                                  index exists;
+ *                              Other MGMT_ERR_[...] code on failure.
+ */
 int log_mgmt_impl_get_log(int idx, struct log_mgmt_log *out_log);
+
+/**
+ * @brief Retrieves the name of log module at the specified index.
+ *
+ * @param idx                   The index of the log module to retrieve.
+ * @param out_name              On success, the requested module's name gets
+ *                                  written here.
+ *
+ * @return                      0 on success;
+ *                              MGMT_ERR_ENOENT if no log module with the
+ *                                  specified index exists;
+ *                              Other MGMT_ERR_[...] code on failure.
+ */
 int log_mgmt_impl_get_module(int idx, const char **out_module_name);
+
+/**
+ * @brief Retrieves the name of log level at the specified index.
+ *
+ * @param idx                   The index of the log level to retrieve.
+ * @param out_name              On success, the requested level's name gets
+ *                                  written here.
+ *
+ * @return                      0 on success;
+ *                              MGMT_ERR_ENOENT if no log level with the
+ *                                  specified index exists;
+ *                              Other MGMT_ERR_[...] code on failure.
+ */
 int log_mgmt_impl_get_level(int idx, const char **out_level_name);
+
+/**
+ * @brief Retrieves the index that the next log entry will use.
+ *
+ * @param out_idx               On success, the next index gets written here.
+ *
+ * @return                      0 on success; MGMT_ERR_[...] code on failure.
+ */
 int log_mgmt_impl_get_next_idx(uint32_t *out_idx);
+
+/**
+ * @brief Applies a function to every matching entry in the specified log.
+ *
+ * @param log_name              The name of the log to operate on.
+ * @param filter                Specifies which log entries to operate on.
+ * @param cb                    The callback to apply to each log entry.
+ * @param arg                   An optional argument to pass to the callback.
+ *
+ * @return                      0 on success; MGMT_ERR_[...] code on failure.
+ */
 int log_mgmt_impl_foreach_entry(const char *log_name,
                                 const struct log_mgmt_filter *filter,
                                 log_mgmt_foreach_entry_fn *cb,
                                 void *arg);
+
+/**
+ * @brief Clear the log with the specified name.
+ *
+ * @param log_name              The name of the log to clear.
+ *
+ * @return                      0 on success; MGMT_ERR_[...] code on failure.
+ */
 int log_mgmt_impl_clear(const char *log_name);
 
 #ifdef __cplusplus

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 15/42: Fix some misnamed identifiers.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit a4d9248ffd41331d2966cd75762ae0b57c3447fc
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 15:46:06 2018 -0800

    Fix some misnamed identifiers.
---
 cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c | 35 +++++++++++++-------------
 mgmt/include/mgmt/mgmt.h                       | 16 ++++++------
 mgmt/src/mgmt.c                                | 14 +++++------
 3 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
index dc71d8f..e17952b 100644
--- a/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
+++ b/cmd/img_mgmt/port/zephyr/src/zephyr_img_mgmt.c
@@ -29,14 +29,14 @@
 #include "img_mgmt/img_mgmt.h"
 #include "../../../src/img_mgmt_priv.h"
 
-static struct device *zephyr_img_flash_dev;
-static struct flash_img_context zephyr_img_flash_ctxt;
+static struct device *zephyr_img_mgmt_flash_dev;
+static struct flash_img_context zephyr_img_mgmt_flash_ctxt;
 
 /**
  * Determines if the specified area of flash is completely unwritten.
  */
 static int
-img_mgmt_impl_flash_check_empty(off_t offset, size_t size, bool *out_empty)
+zephyr_img_mgmt_flash_check_empty(off_t offset, size_t size, bool *out_empty)
 {
     uint32_t data[16];
     off_t addr;
@@ -55,7 +55,7 @@ img_mgmt_impl_flash_check_empty(off_t offset, size_t size, bool *out_empty)
             bytes_to_read = sizeof data;
         }
 
-        rc = flash_read(zephyr_img_flash_dev, addr, data, bytes_to_read);
+        rc = flash_read(zephyr_img_mgmt_flash_dev, addr, data, bytes_to_read);
         if (rc != 0) {
             return MGMT_ERR_EUNKNOWN;
         }
@@ -76,7 +76,7 @@ img_mgmt_impl_flash_check_empty(off_t offset, size_t size, bool *out_empty)
  * Converts an offset within an image slot to an absolute address.
  */
 static off_t
-img_mgmt_impl_abs_offset(int slot, off_t sub_offset)
+zephyr_img_mgmt_abs_offset(int slot, off_t sub_offset)
 {
     off_t slot_start;
 
@@ -104,9 +104,9 @@ img_mgmt_impl_erase_slot(void)
     bool empty;
     int rc;
 
-    rc = img_mgmt_impl_flash_check_empty(FLASH_AREA_IMAGE_1_OFFSET,
-                                         FLASH_AREA_IMAGE_1_SIZE,
-                                         &empty);
+    rc = zephyr_img_mgmt_flash_check_empty(FLASH_AREA_IMAGE_1_OFFSET,
+                                           FLASH_AREA_IMAGE_1_SIZE,
+                                           &empty);
     if (rc != 0) {
         return MGMT_ERR_EUNKNOWN;
     }
@@ -158,8 +158,8 @@ img_mgmt_impl_read(int slot, unsigned int offset, void *dst,
     off_t abs_offset;
     int rc;
 
-    abs_offset = img_mgmt_impl_abs_offset(slot, offset);
-    rc = flash_read(zephyr_img_flash_dev, abs_offset, dst, num_bytes);
+    abs_offset = zephyr_img_mgmt_abs_offset(slot, offset);
+    rc = flash_read(zephyr_img_mgmt_flash_dev, abs_offset, dst, num_bytes);
     if (rc != 0) {
         return MGMT_ERR_EUNKNOWN;
     }
@@ -174,18 +174,19 @@ img_mgmt_impl_write_image_data(unsigned int offset, const void *data,
     int rc;
 
     if (offset == 0) {
-        flash_img_init(&zephyr_img_flash_ctxt, zephyr_img_flash_dev);
+        flash_img_init(&zephyr_img_mgmt_flash_ctxt, zephyr_img_mgmt_flash_dev);
     }
 
     /* Cast away const. */
-    rc = flash_img_buffered_write(&zephyr_img_flash_ctxt, (void *)data,
+    rc = flash_img_buffered_write(&zephyr_img_mgmt_flash_ctxt, (void *)data,
                                   num_bytes, false);
     if (rc != 0) {
         return MGMT_ERR_EUNKNOWN;
     }
 
     if (last) {
-        rc = flash_img_buffered_write(&zephyr_img_flash_ctxt, NULL, 0, true);
+        rc = flash_img_buffered_write(&zephyr_img_mgmt_flash_ctxt,
+                                      NULL, 0, true);
         if (rc != 0) {
             return MGMT_ERR_EUNKNOWN;
         }
@@ -213,15 +214,15 @@ img_mgmt_impl_swap_type(void)
 }
 
 static int
-img_mgmt_impl_init(struct device *dev)
+zephyr_img_mgmt_init(struct device *dev)
 {
     ARG_UNUSED(dev);
 
-    zephyr_img_flash_dev = device_get_binding(FLASH_DRIVER_NAME);
-    if (zephyr_img_flash_dev == NULL) {
+    zephyr_img_mgmt_flash_dev = device_get_binding(FLASH_DRIVER_NAME);
+    if (zephyr_img_mgmt_flash_dev == NULL) {
         return -ENODEV;
     }
     return 0;
 }
 
-SYS_INIT(img_mgmt_impl_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
+SYS_INIT(zephyr_img_mgmt_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
diff --git a/mgmt/include/mgmt/mgmt.h b/mgmt/include/mgmt/mgmt.h
index 549fcdc..2762aa8 100644
--- a/mgmt/include/mgmt/mgmt.h
+++ b/mgmt/include/mgmt/mgmt.h
@@ -41,7 +41,7 @@ extern "C" {
 #define MGMT_GROUP_ID_IMAGE     1
 #define MGMT_GROUP_ID_STATS     2
 #define MGMT_GROUP_ID_CONFIG    3
-#define MGMT_GROUP_ID_LOGS      4
+#define MGMT_GROUP_ID_LOG       4
 #define MGMT_GROUP_ID_CRASH     5
 #define MGMT_GROUP_ID_SPLIT     6
 #define MGMT_GROUP_ID_RUN       7
@@ -203,12 +203,12 @@ struct mgmt_ctxt {
  *
  * A separate handler is required for each supported op-ID pair.
  *
- * @param cbuf                  The mcumgr context to use.
+ * @param ctxt                  The mcumgr context to use.
  *
  * @return                      0 if a response was successfully encoded,
- *                                 MGMT_ERR_[...] code on failure.
+ *                                  MGMT_ERR_[...] code on failure.
  */
-typedef int mgmt_handler_fn(struct mgmt_ctxt *cbuf);
+typedef int mgmt_handler_fn(struct mgmt_ctxt *ctxt);
 
 /**
  * @brief Read handler and write handler for a single command ID.
@@ -340,23 +340,23 @@ const struct mgmt_handler *mgmt_find_handler(uint16_t group_id,
 /**
  * @brief Encodes a response status into the specified management context.
  *
- * @param cbuf                  The management context to encode into.
+ * @param ctxt                  The management context to encode into.
  * @param status                The response status to write.
  *
  * @return                      0 on success, MGMT_ERR_[...] code on failure.
  */
-int mgmt_write_rsp_status(struct mgmt_ctxt *cbuf, int status);
+int mgmt_write_rsp_status(struct mgmt_ctxt *ctxt, int status);
 
 /**
  * @brief Initializes a management context object with the specified streamer.
  *
- * @param cbuf                  The context object to initialize.
+ * @param ctxt                  The context object to initialize.
  * @param streamer              The streamer that will be used with the
  *                                  context.
  *
  * @return                      0 on success, MGMT_ERR_[...] code on failure.
  */
-int mgmt_ctxt_init(struct mgmt_ctxt *cbuf, struct mgmt_streamer *streamer);
+int mgmt_ctxt_init(struct mgmt_ctxt *ctxt, struct mgmt_streamer *streamer);
 
 /**
  * @brief Converts a CBOR status code to a MGMT_ERR_[...] code.
diff --git a/mgmt/src/mgmt.c b/mgmt/src/mgmt.c
index ccea65a..c6318ce 100644
--- a/mgmt/src/mgmt.c
+++ b/mgmt/src/mgmt.c
@@ -112,16 +112,16 @@ mgmt_find_handler(uint16_t group_id, uint16_t command_id)
 }
 
 int
-mgmt_write_rsp_status(struct mgmt_ctxt *cbuf, int errcode)
+mgmt_write_rsp_status(struct mgmt_ctxt *ctxt, int errcode)
 {
     int rc;
 
-    rc = cbor_encode_text_stringz(&cbuf->encoder, "rc");
+    rc = cbor_encode_text_stringz(&ctxt->encoder, "rc");
     if (rc != 0) {
         return rc;
     }
 
-    rc = cbor_encode_int(&cbuf->encoder, errcode);
+    rc = cbor_encode_int(&ctxt->encoder, errcode);
     if (rc != 0) {
         return rc;
     }
@@ -140,17 +140,17 @@ mgmt_err_from_cbor(int cbor_status)
 }
 
 int
-mgmt_ctxt_init(struct mgmt_ctxt *cbuf, struct mgmt_streamer *streamer)
+mgmt_ctxt_init(struct mgmt_ctxt *ctxt, struct mgmt_streamer *streamer)
 {
     int rc;
 
-    rc = cbor_parser_cust_reader_init(streamer->reader, 0, &cbuf->parser,
-                                      &cbuf->it);
+    rc = cbor_parser_cust_reader_init(streamer->reader, 0, &ctxt->parser,
+                                      &ctxt->it);
     if (rc != CborNoError) {
         return mgmt_err_from_cbor(rc);
     }
 
-    cbor_encoder_cust_writer_init(&cbuf->encoder, streamer->writer, 0);
+    cbor_encoder_cust_writer_init(&ctxt->encoder, streamer->writer, 0);
 
     return 0;
 }

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 32/42: smp_svr - Update zephyr port for compatibility.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit e6dc5b64af391c1db2282b00e48a9325cab8339c
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Feb 8 15:05:09 2018 -0800

    smp_svr - Update zephyr port for compatibility.
---
 samples/smp_svr/zephyr/prj.conf   | 6 ++++++
 samples/smp_svr/zephyr/src/main.c | 9 +++++----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/samples/smp_svr/zephyr/prj.conf b/samples/smp_svr/zephyr/prj.conf
index fc2f99c..9e04c3c 100644
--- a/samples/smp_svr/zephyr/prj.conf
+++ b/samples/smp_svr/zephyr/prj.conf
@@ -1,3 +1,6 @@
+# Enable mcumgr.
+CONFIG_MCUMGR=y
+
 # Some command handlers require a large stack.
 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
 
@@ -16,6 +19,9 @@ CONFIG_BT_RX_BUF_LEN=260
 CONFIG_MCUMGR_SMP_BT=y
 CONFIG_MCUMGR_SMP_SHELL=y
 
+# Enable flash operations.
+CONFIG_FLASH=y
+
 # Enable the NFFS file system.
 CONFIG_FILE_SYSTEM=y
 CONFIG_FILE_SYSTEM_NFFS=y
diff --git a/samples/smp_svr/zephyr/src/main.c b/samples/smp_svr/zephyr/src/main.c
index 47e5de2..3e06e40 100644
--- a/samples/smp_svr/zephyr/src/main.c
+++ b/samples/smp_svr/zephyr/src/main.c
@@ -151,11 +151,10 @@ static int init_fcb(void)
         .f_version = MDLOG_VERSION,
         .f_sector_cnt = sector_cnt - 1,
         .f_scratch_cnt = 1,
-        .f_area_id = 4,
         .f_sectors = sectors,
     };
 
-    rc = fcb_init(&smp_svr_fcb);
+    rc = fcb_init(4, &smp_svr_fcb);
     if (rc != 0) {
         return rc;
     }
@@ -168,7 +167,9 @@ void main(void)
     int rc;
 
     rc = init_fcb();
-    assert(rc == 0);
+    if (rc != 0) {
+        printk("Failed to initialize FCB; rc=%d\n", rc);
+    }
 
 #ifdef CONFIG_REBOOT_LOG
     reboot_log_configure(&smp_svr_log);
@@ -205,7 +206,7 @@ void main(void)
     /* Initialize the Bluetooth mcumgr transport. */
     smp_bt_register();
 
-#ifdef CONFIG_MDLOG
+#if defined(CONFIG_MDLOG) && defined(CONFIG_FCB)
     mdlog_register("smp_svr", &smp_svr_log, &mdlog_fcb_handler, &smp_svr_fcb,
                    MDLOG_LEVEL_DEBUG);
 #endif

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 20/42: Update documentation.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit a6898ca6cb274fbb0e05f85b8d65e1cd415e0ed8
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 17:58:38 2018 -0800

    Update documentation.
---
 README-mynewt.md | 31 +++++++++++++++++++++++++++++++
 README-zephyr.md | 30 ++++++++++++++++++++++++++++++
 README.md        | 29 +++++++++++++++++++++--------
 3 files changed, 82 insertions(+), 8 deletions(-)

diff --git a/README-mynewt.md b/README-mynewt.md
new file mode 100644
index 0000000..9e65ea8
--- /dev/null
+++ b/README-mynewt.md
@@ -0,0 +1,31 @@
+## Building and using mcumgr with Apache Mynewt
+
+NOTE: The *mcumgr* library consists of functionality that is already present in
+the `apache-mynewt-core` repo.  There is currently no need to use the external
+*mcumgr* library with Mynewt, as the functionality is already built in to the
+OS.  To use this library with a Mynewt application, you will need to remove the
+duplicate functionality from your copy of the `apache-mynewt-core` repo.
+
+### Configuration
+
+To use *mcumgr*, your Mynewt app needs to be configured to use:
+1. An mcumgr transfer encoding
+2. An mcumgr transport
+3. (optional) Command handlers.
+
+This is done by adding the necessary dependencies to your app or target.  The following list of dependencies adds support for the SMP transfer encoding, the Bluetooth and shell transports, and all the built-in command handlers:
+
+```
+    - '@apache-mynewt-core/mgmt/newtmgr/transport/ble'
+    - '@apache-mynewt-core/mgmt/newtmgr/transport/nmgr_shell'
+    - '@mynewt-mcumgr/cmd/fs_mgmt'
+    - '@mynewt-mcumgr/cmd/img_mgmt'
+    - '@mynewt-mcumgr/cmd/os_mgmt'
+    - '@mynewt-mcumgr/smp'
+```
+
+For an example of an app that uses mcumgr, see the `smp_svr` sample app in `samples/smp_svr/mynewt`.
+
+### Building
+
+With the necessary dependencies in place, your project can be built using the usual `newt build <target-name>` or `newt run <target-name>`
diff --git a/README-zephyr.md b/README-zephyr.md
new file mode 100644
index 0000000..b808a2f
--- /dev/null
+++ b/README-zephyr.md
@@ -0,0 +1,30 @@
+## Building and using mcumgr with Zephyr
+
+### Configuration
+
+The `samples/smp_svr/zephyr/prj.conf` file provides a good starting point for
+configuring an application to use *mcumgr*.  The major configuration settings
+are described below:
+
+| Setting       | Description   | Default |
+| ------------- | ------------- | ------- |
+| `CONFIG_MCUMGR` | Enable the mcumgr management library. | n |
+| `CONFIG_MCUMGR_CMD_FS_MGMT` | Enable mcumgr handlers for file management | n |
+| `CONFIG_MCUMGR_CMD_IMG_MGMT` | Enable mcumgr handlers for image management | n |
+| `CONFIG_MCUMGR_CMD_LOG_MGMT` | Enable mcumgr handlers for log management | n |
+| `CONFIG_MCUMGR_CMD_OS_MGMT` | Enable mcumgr handlers for OS management | n |
+
+### Building
+
+Your application must specify mcumgr as a link-time dependency.  This is done
+by adding the following to your application's `CMakeLists.txt` file:
+
+```
+zephyr_link_libraries(
+    MCUMGR
+)
+```
+
+### Known issues
+
+If the Bluetooth stack runs out of ACL transmit buffers while a large mcumgr response is being sent, the buffers never get freed.  This appears to trigger a net_buf leak in the stack.
diff --git a/README.md b/README.md
index 12141dc..bbe0016 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,20 @@ mcumgr is operating system and hardware independent.  It relies on hardware
 porting layers from the operating system it runs on.  Currently, mcumgr runs on
 both the Apache Mynewt and Zephyr operating systems.
 
+## Getting started
+
+For tips on using mcumgr with your particular OS, see the appropriate file from
+the list below:
+
+* README-mynewt.md
+* README-zephyr.md
+
+## Dependencies
+
+To use mcumgr's image management support, your device must be running the
+MCUBoot boot loader (https://github.com/runtimeco/mcuboot).  The other mcumgr
+features do not require MCUboot.
+
 ## Command line tool
 
 The `mcumgr` command line tool is available at:
@@ -52,6 +66,7 @@ As an example, the sample application `smp_svr` uses the following components:
 * Command handlers:
     * Image management (`img_mgmt`)
     * File system management (`fs_mgmt`)
+    * Log management (`log_mgmt`)
     * OS management (`os_mgmt`)
 * Transfer/Transports protocols:
     * SMP/Bluetooth
@@ -60,9 +75,9 @@ As an example, the sample application `smp_svr` uses the following components:
 yielding the following stack diagram:
 
 ```
-+--------------+--------------+-------------+
-|   img_mgmt   |   fs_mgmt    |   os_mgmt   |
-+--------------+--------------+-------------+
++----------+----------+----------+----------+
+| img_mgmt |  fs_mgmt | log_mgmt |  os_mgmt |
++----------+----------+----------+----------+
 |                   mgmt                    |
 +---------------------+---------------------+
 |         SMP         |         SMP         |
@@ -87,7 +102,9 @@ The contents of the CBOR key-value map are specified per command type.
 
 ## Supported transfer encodings
 
-Mcumgr comes with one built-in transfer encoding: Simple Management Protocol (SMP).  SMP requests and responses have a very basic structure.  For details, see the comments at the top of `smp/include/smp/smp.h`.
+Mcumgr comes with one built-in transfer encoding: Simple Management Protocol
+(SMP).  SMP requests and responses have a very basic structure.  For details,
+see the comments at the top of `smp/include/smp/smp.h`.
 
 ## Supported transports
 
@@ -114,10 +131,6 @@ For more information in the source, here are some pointers:
 - [samples](https://github.com/apache/mcumgr/tree/master/samples): Sample applications utilizing mcumgr.
 - [smp](https://github.com/apache/mcumgr/tree/master/smp): The built-in transfer encoding: Simple management protocol.
 
-## Known issues
-
-- (Zephyr) If the Bluetooth stack runs out of ACL transmit buffers while a large mcumgr response is being sent, the buffers never get freed.  This appears to trigger a net_buf leak in the stack.
-
 ## Joining
 
 Developers welcome!

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 24/42: smp_svr - fix build error when CONFIG_MDLOG unset.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 980c92484528ecba531961218f2453e19741b174
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Jan 30 12:07:25 2018 -0800

    smp_svr - fix build error when CONFIG_MDLOG unset.
---
 samples/smp_svr/zephyr/src/main.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/samples/smp_svr/zephyr/src/main.c b/samples/smp_svr/zephyr/src/main.c
index 7f5e9e6..2906711 100644
--- a/samples/smp_svr/zephyr/src/main.c
+++ b/samples/smp_svr/zephyr/src/main.c
@@ -153,7 +153,10 @@ void main(void)
 
     rc = init_fcb();
     assert(rc == 0);
+
+#ifdef CONFIG_REBOOT_LOG
     reboot_log_configure(&smp_svr_log);
+#endif
 
     /* Register the built-in mcumgr command handlers. */
 #ifdef CONFIG_MCUMGR_CMD_FS_MGMT
@@ -180,8 +183,10 @@ void main(void)
     /* Initialize the Bluetooth mcumgr transport. */
     smp_bt_register();
 
+#ifdef CONFIG_MDLOG
     mdlog_register("smp_svr", &smp_svr_log, &mdlog_fcb_handler, &smp_svr_fcb,
                    MDLOG_LEVEL_DEBUG);
+#endif
 
     /* The system work queue handles all incoming mcumgr requests.  Let the
      * main thread idle while the mcumgr server runs.

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 25/42: stat_mgmt command handler group.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 7bdec147ddcfd211858ec8ca8fcb1327e6c3a24b
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Jan 29 16:05:27 2018 -0800

    stat_mgmt command handler group.
---
 cmd/CMakeLists.txt                               |   1 +
 cmd/Kconfig                                      |   1 +
 cmd/stat_mgmt/CMakeLists.txt                     |   9 ++
 cmd/stat_mgmt/Kconfig                            |  36 +++++
 cmd/stat_mgmt/include/stat_mgmt/stat_mgmt.h      |  50 +++++++
 cmd/stat_mgmt/include/stat_mgmt/stat_mgmt_impl.h |  70 ++++++++++
 cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c |  97 ++++++++++++++
 cmd/stat_mgmt/src/stat_mgmt.c                    | 160 +++++++++++++++++++++++
 cmd/stat_mgmt/src/stat_mgmt_config.h             |  41 ++++++
 cmd/stat_mgmt/src/stubs.c                        |  40 ++++++
 mgmt/include/mgmt/mgmt.h                         |   2 +-
 11 files changed, 506 insertions(+), 1 deletion(-)

diff --git a/cmd/CMakeLists.txt b/cmd/CMakeLists.txt
index be26ded..a9d5968 100644
--- a/cmd/CMakeLists.txt
+++ b/cmd/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_FS_MGMT   fs_mgmt)
 add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_IMG_MGMT  img_mgmt)
 add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_LOG_MGMT  log_mgmt)
 add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_OS_MGMT   os_mgmt)
+add_subdirectory_ifdef(CONFIG_MCUMGR_CMD_STAT_MGMT stat_mgmt)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index ea51804..e404d2d 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -21,5 +21,6 @@ source "ext/mcumgr/cmd/fs_mgmt/Kconfig"
 source "ext/mcumgr/cmd/img_mgmt/Kconfig"
 source "ext/mcumgr/cmd/log_mgmt/Kconfig"
 source "ext/mcumgr/cmd/os_mgmt/Kconfig"
+source "ext/mcumgr/cmd/stat_mgmt/Kconfig"
 
 endmenu
diff --git a/cmd/stat_mgmt/CMakeLists.txt b/cmd/stat_mgmt/CMakeLists.txt
new file mode 100644
index 0000000..6dc954a
--- /dev/null
+++ b/cmd/stat_mgmt/CMakeLists.txt
@@ -0,0 +1,9 @@
+target_include_directories(MCUMGR INTERFACE 
+    include
+)
+
+zephyr_library_sources(
+    cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c
+    cmd/stat_mgmt/src/stat_mgmt.c
+    cmd/stat_mgmt/src/stubs.c
+)
diff --git a/cmd/stat_mgmt/Kconfig b/cmd/stat_mgmt/Kconfig
new file mode 100644
index 0000000..ffda20f
--- /dev/null
+++ b/cmd/stat_mgmt/Kconfig
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE log
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this log
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this log 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.
+
+menuconfig MCUMGR_CMD_STAT_MGMT
+    bool
+    prompt "Enable mcumgr handlers for statistics management"
+    depends on STATS
+    default n
+    help
+      Enables mcumgr handlers for statistics management.
+
+if MCUMGR_CMD_STAT_MGMT
+config STAT_MGMT_MAX_NAME_LEN
+    int
+    prompt "Maximum stat group name length"
+    default 32
+    help
+      Limits the maximum stat group name length in mcumgr requests.  A buffer
+      of this size gets allocated on the stack during handling of all stat read
+      commands.  If a stat group's name exceeds this limit, it will be
+      impossible to retrieve its values with a stat show command.
+endif
diff --git a/cmd/stat_mgmt/include/stat_mgmt/stat_mgmt.h b/cmd/stat_mgmt/include/stat_mgmt/stat_mgmt.h
new file mode 100644
index 0000000..f0f76fb
--- /dev/null
+++ b/cmd/stat_mgmt/include/stat_mgmt/stat_mgmt.h
@@ -0,0 +1,50 @@
+/*
+ * 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 H_STAT_MGMT_
+#define H_STAT_MGMT_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Command IDs for statistics management group.
+ */
+#define STAT_MGMT_ID_SHOW   0
+#define STAT_MGMT_ID_LIST   1
+
+/**
+ * @brief Represents a single value in a statistics group.
+ */
+struct stat_mgmt_entry {
+    const char *name;
+    uint64_t value;
+};
+
+/**
+ * @brief Registers the statistics management command handler group.
+ */ 
+void stat_mgmt_register_group(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_STAT_MGMT_ */
diff --git a/cmd/stat_mgmt/include/stat_mgmt/stat_mgmt_impl.h b/cmd/stat_mgmt/include/stat_mgmt/stat_mgmt_impl.h
new file mode 100644
index 0000000..d60707a
--- /dev/null
+++ b/cmd/stat_mgmt/include/stat_mgmt/stat_mgmt_impl.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * @brief Declares implementation-specific functions required by statistics
+ *        management.  The default stubs can be overridden with functions that
+ *        are compatible with the host OS.
+ */
+
+#ifndef H_STAT_MGMT_IMPL_
+#define H_STAT_MGMT_IMPL_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct stat_mgmt_entry;
+
+typedef int stat_mgmt_foreach_entry_fn(struct stat_mgmt_entry *entry,
+                                       void *arg);
+
+/**
+ * @brief Retrieves the name of the stat group at the specified index.
+ *
+ * @param idx                   The index of the stat group to retrieve.
+ * @param out_name              On success, the name of the requested stat
+ *                                  group gets written here.
+ *
+ * @return                      0 on success;
+ *                              MGMT_ERR_ENOENT if no group with the specified
+ *                                  index exists;
+ *                              Other MGMT_ERR_[...] code on failure.
+ */
+int stat_mgmt_impl_get_group(int idx, const char **out_name);
+
+/**
+ * @brief Applies a function to every entry in the specified stat group.
+ *
+ * @param group_name            The name of the stat group to operate on.
+ * @param cb                    The callback to apply to each stat entry.
+ * @param arg                   An optional argument to pass to the callback.
+ *
+ * @return                      0 on success; MGMT_ERR_[...] code on failure.
+ */
+int stat_mgmt_impl_foreach_entry(const char *group_name,
+                                 stat_mgmt_foreach_entry_fn *cb,
+                                 void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c b/cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c
new file mode 100644
index 0000000..dd0ba0b
--- /dev/null
+++ b/cmd/stat_mgmt/port/zephyr/src/zephyr_stat_mgmt.c
@@ -0,0 +1,97 @@
+/*
+ * 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 <misc/util.h>
+#include "stats.h"
+#include "mgmt/mgmt.h"
+#include "stat_mgmt/stat_mgmt.h"
+#include "stat_mgmt/stat_mgmt_impl.h"
+
+struct zephyr_stat_mgmt_walk_arg {
+    stat_mgmt_foreach_entry_fn *cb;
+    void *arg;
+};
+
+int
+stat_mgmt_impl_get_group(int idx, const char **out_name)
+{
+    const struct stats_hdr *cur;
+    int i;
+
+    cur = NULL;
+    for (i = 0; i <= idx; i++) {
+        cur = stats_group_get_next(cur);
+        if (cur == NULL) {
+            return MGMT_ERR_ENOENT;
+        }
+    }
+
+    *out_name = cur->s_name;
+    return 0;
+}
+
+static int
+zephyr_stat_mgmt_walk_cb(struct stats_hdr *hdr, void *arg,
+                         const char *name, uint16_t off)
+{
+    struct zephyr_stat_mgmt_walk_arg *walk_arg;
+    struct stat_mgmt_entry entry;
+    void *stat_val;
+
+    walk_arg = arg;
+
+    stat_val = (uint8_t *)hdr + off;
+    switch (hdr->s_size) {
+    case sizeof (uint16_t):
+        entry.value = *(uint16_t *) stat_val;
+        break;
+    case sizeof (uint32_t):
+        entry.value = *(uint32_t *) stat_val;
+        break;
+    case sizeof (uint64_t):
+        entry.value = *(uint64_t *) stat_val;
+        break;
+    default:
+        return MGMT_ERR_EUNKNOWN;
+    }
+    entry.name = name;
+
+    return walk_arg->cb(&entry, walk_arg->arg);
+}
+
+int
+stat_mgmt_impl_foreach_entry(const char *group_name,
+                             stat_mgmt_foreach_entry_fn *cb,
+                             void *arg)
+{
+    struct zephyr_stat_mgmt_walk_arg walk_arg;
+    struct stats_hdr *hdr;
+
+    hdr = stats_group_find(group_name);
+    if (hdr == NULL) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    walk_arg = (struct zephyr_stat_mgmt_walk_arg) {
+        .cb = cb,
+        .arg = arg,
+    };
+
+    return stats_walk(hdr, zephyr_stat_mgmt_walk_cb, &walk_arg);
+}
diff --git a/cmd/stat_mgmt/src/stat_mgmt.c b/cmd/stat_mgmt/src/stat_mgmt.c
new file mode 100644
index 0000000..7eac3f9
--- /dev/null
+++ b/cmd/stat_mgmt/src/stat_mgmt.c
@@ -0,0 +1,160 @@
+/*
+ * 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 <string.h>
+#include <stdio.h>
+
+#include "mgmt/mgmt.h"
+#include "cborattr/cborattr.h"
+#include "stat_mgmt/stat_mgmt.h"
+#include "stat_mgmt/stat_mgmt_impl.h"
+#include "stat_mgmt_config.h"
+
+static mgmt_handler_fn stat_mgmt_show;
+static mgmt_handler_fn stat_mgmt_list;
+
+static struct mgmt_handler stat_mgmt_handlers[] = {
+    [STAT_MGMT_ID_SHOW] = { stat_mgmt_show, NULL },
+    [STAT_MGMT_ID_LIST] = { stat_mgmt_list, NULL },
+};
+
+#define STAT_MGMT_HANDLER_CNT \
+    sizeof stat_mgmt_handlers / sizeof stat_mgmt_handlers[0]
+
+static struct mgmt_group stat_mgmt_group = {
+    .mg_handlers = stat_mgmt_handlers,
+    .mg_handlers_count = STAT_MGMT_HANDLER_CNT,
+    .mg_group_id = MGMT_GROUP_ID_STAT,
+};
+
+static int
+stat_mgmt_cb_encode(struct stat_mgmt_entry *entry, void *arg)
+{
+    CborEncoder *enc;
+    CborError err;
+
+    enc = arg;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(enc, entry->name);
+    err |= cbor_encode_uint(enc, entry->value);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: stat show
+ */
+static int
+stat_mgmt_show(struct mgmt_ctxt *ctxt)
+{
+    char stat_name[CONFIG_STAT_MGMT_MAX_NAME_LEN];
+    CborEncoder map_enc;
+    CborError err;
+    int rc;
+
+    struct cbor_attr_t attrs[] = {
+        {
+            .attribute = "name",
+            .type = CborAttrTextStringType,
+            .addr.string = stat_name,
+            .len = sizeof(stat_name)
+        },
+        { NULL },
+    };
+
+    err = cbor_read_object(&ctxt->it, attrs);
+    if (err != 0) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "rc");
+    err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK);
+
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "name");
+    err |= cbor_encode_text_stringz(&ctxt->encoder, stat_name);
+
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "fields");
+    err |= cbor_encoder_create_map(&ctxt->encoder, &map_enc,
+                                   CborIndefiniteLength);
+
+    rc = stat_mgmt_impl_foreach_entry(stat_name, stat_mgmt_cb_encode,
+                                      &map_enc);
+    if (rc != 0) {
+        return rc;
+    }
+
+    err |= cbor_encoder_close_container(&ctxt->encoder, &map_enc);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+
+    return 0;
+}
+
+/**
+ * Command handler: stat list
+ */
+static int
+stat_mgmt_list(struct mgmt_ctxt *ctxt)
+{
+    const char *group_name;
+    CborEncoder arr_enc;
+    CborError err;
+    int rc;
+    int i;
+
+    err = 0;
+    err |= cbor_encode_text_stringz(&ctxt->encoder, "stat_list");
+    err |= cbor_encoder_create_array(&ctxt->encoder, &arr_enc,
+                                     CborIndefiniteLength);
+
+    /* Iterate the list of stat groups, encoding each group's name in the CBOR
+     * array.
+     */
+    for (i = 0; ; i++) {
+        rc = stat_mgmt_impl_get_group(i, &group_name);
+        if (rc == MGMT_ERR_ENOENT) {
+            /* No more stat groups. */
+            break;
+        } else if (rc != 0) {
+            /* Error. */
+            return rc;
+        }
+
+        err |= cbor_encode_text_stringz(&ctxt->encoder, group_name);
+    }
+    err |= cbor_encoder_close_container(&ctxt->encoder, &arr_enc);
+
+    if (err != 0) {
+        return MGMT_ERR_ENOMEM;
+    }
+    return 0;
+}
+
+void
+stat_mgmt_register_group(void)
+{
+    mgmt_register_group(&stat_mgmt_group);
+}
diff --git a/cmd/stat_mgmt/src/stat_mgmt_config.h b/cmd/stat_mgmt/src/stat_mgmt_config.h
new file mode 100644
index 0000000..6c7cbca
--- /dev/null
+++ b/cmd/stat_mgmt/src/stat_mgmt_config.h
@@ -0,0 +1,41 @@
+/*
+ * 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 H_STAT_MGMT_CONFIG_
+#define H_STAT_MGMT_CONFIG_
+
+#if defined MYNEWT
+
+#include "syscfg/syscfg.h"
+
+#define STAT_MGMT_MAX_NAME_LEN  MYNEWT_VAL(STAT_MGMT_MAX_NAME_LEN)
+
+#elif defined __ZEPHYR__
+
+#define STAT_MGMT_MAX_NAME_LEN  CONFIG_STAT_MGMT_MAX_NAME_LEN
+
+#else
+
+/* No direct support for this OS.  The application needs to define the above
+ * settings itself.
+ */
+
+#endif
+
+#endif
diff --git a/cmd/stat_mgmt/src/stubs.c b/cmd/stat_mgmt/src/stubs.c
new file mode 100644
index 0000000..906056f
--- /dev/null
+++ b/cmd/stat_mgmt/src/stubs.c
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/**
+ * These stubs get linked in when there is no equivalent OS-specific
+ * implementation.
+ */
+
+#include "mgmt/mgmt.h"
+#include "stat_mgmt/stat_mgmt_impl.h"
+
+int __attribute__((weak))
+stat_mgmt_impl_get_group(int idx, const char **out_name)
+{
+    return MGMT_ERR_ENOTSUP;
+}
+
+int __attribute__((weak))
+stat_mgmt_impl_foreach_entry(const char *stat_name,
+                             stat_mgmt_foreach_entry_fn *cb,
+                             void *arg)
+{
+    return MGMT_ERR_ENOTSUP;
+}
diff --git a/mgmt/include/mgmt/mgmt.h b/mgmt/include/mgmt/mgmt.h
index 2762aa8..8303d04 100644
--- a/mgmt/include/mgmt/mgmt.h
+++ b/mgmt/include/mgmt/mgmt.h
@@ -39,7 +39,7 @@ extern "C" {
  */
 #define MGMT_GROUP_ID_OS        0
 #define MGMT_GROUP_ID_IMAGE     1
-#define MGMT_GROUP_ID_STATS     2
+#define MGMT_GROUP_ID_STAT      2
 #define MGMT_GROUP_ID_CONFIG    3
 #define MGMT_GROUP_ID_LOG       4
 #define MGMT_GROUP_ID_CRASH     5

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 19/42: smp_svr Mynewt sample app - Remove redundant dep.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit b5c74b58afa8e8ae117d78b15566e77648c9edb1
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Jan 26 17:58:09 2018 -0800

    smp_svr Mynewt sample app - Remove redundant dep.
---
 samples/smp_svr/mynewt/pkg.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/samples/smp_svr/mynewt/pkg.yml b/samples/smp_svr/mynewt/pkg.yml
index 83d38d5..5ab44e3 100644
--- a/samples/smp_svr/mynewt/pkg.yml
+++ b/samples/smp_svr/mynewt/pkg.yml
@@ -39,5 +39,4 @@ pkg.deps:
     - '@mynewt-mcumgr/cmd/fs_mgmt'
     - '@mynewt-mcumgr/cmd/img_mgmt'
     - '@mynewt-mcumgr/cmd/os_mgmt'
-    - '@mynewt-mcumgr/mgmt'
     - '@mynewt-mcumgr/smp'

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.

[mynewt-mcumgr] 05/42: External tinycbor library.

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 42b28162f8aed0e7fe8c2f084db37d70f464b7b5
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jan 17 17:11:54 2018 -0800

    External tinycbor library.
    
    Note: This is commit 3ef6799f633df19a84b99ccd0f21fb8c02201690 of a PR
    against the tinycbor library:
    https://github.com/intel/tinycbor/pull/83
---
 ext/tinycbor/.appveyor.yml                 |   35 +
 ext/tinycbor/.gitattributes                |    4 +
 ext/tinycbor/.gitignore                    |   81 +
 ext/tinycbor/.tag                          |    1 +
 ext/tinycbor/.travis.yml                   |   24 +
 ext/tinycbor/CMakeLists.txt                |   15 +
 ext/tinycbor/Doxyfile                      | 2318 ++++++++++++++++++++++++++++
 ext/tinycbor/LICENSE                       |   21 +
 ext/tinycbor/Makefile                      |  234 +++
 ext/tinycbor/README                        |   13 +
 ext/tinycbor/TODO                          |   25 +
 ext/tinycbor/VERSION                       |    1 +
 ext/tinycbor/examples/examples.pro         |    2 +
 ext/tinycbor/examples/simplereader.c       |  181 +++
 ext/tinycbor/examples/simplereader.pro     |    3 +
 ext/tinycbor/maketag.pl                    |   91 ++
 ext/tinycbor/pkg.yml                       |   29 +
 ext/tinycbor/src/cbor.dox                  |  123 ++
 ext/tinycbor/src/cbor.h                    |  392 +++++
 ext/tinycbor/src/cbor_buf_reader.c         |  125 ++
 ext/tinycbor/src/cbor_buf_reader.h         |   47 +
 ext/tinycbor/src/cbor_buf_writer.c         |   99 ++
 ext/tinycbor/src/cbor_buf_writer.h         |   55 +
 ext/tinycbor/src/cbor_cnt_writer.h         |   63 +
 ext/tinycbor/src/cbor_decoder_reader.h     |   60 +
 ext/tinycbor/src/cbor_defs.h               |  253 +++
 ext/tinycbor/src/cbor_encoder_writer.h     |   45 +
 ext/tinycbor/src/cborencoder.c             |  627 ++++++++
 ext/tinycbor/src/cborerrorstrings.c        |  183 +++
 ext/tinycbor/src/cborinternal_p.h          |   89 ++
 ext/tinycbor/src/cborjson.h                |   62 +
 ext/tinycbor/src/cborparser.c              | 1554 +++++++++++++++++++
 ext/tinycbor/src/cborparser_dup_string.c   |  118 ++
 ext/tinycbor/src/cborpretty.c              |  535 +++++++
 ext/tinycbor/src/cborpretty_stdio.c        |   85 +
 ext/tinycbor/src/cbortojson.c              |  688 +++++++++
 ext/tinycbor/src/cborvalidation.c          |  675 ++++++++
 ext/tinycbor/src/compilersupport_p.h       |  263 ++++
 ext/tinycbor/src/open_memstream.c          |  117 ++
 ext/tinycbor/src/parsetags.pl              |  116 ++
 ext/tinycbor/src/src.pri                   |   17 +
 ext/tinycbor/src/tags.txt                  |   23 +
 ext/tinycbor/src/tinycbor-version.h        |    3 +
 ext/tinycbor/src/tinycbor.pro              |    6 +
 ext/tinycbor/src/utf8_p.h                  |  104 ++
 ext/tinycbor/tests/.gitignore              |   15 +
 ext/tinycbor/tests/cpp/cpp.pro             |    5 +
 ext/tinycbor/tests/cpp/tst_cpp.cpp         |   44 +
 ext/tinycbor/tests/encoder/encoder.pro     |    9 +
 ext/tinycbor/tests/encoder/tst_encoder.cpp |  729 +++++++++
 ext/tinycbor/tests/parser/parser.pro       |   10 +
 ext/tinycbor/tests/parser/tst_parser.cpp   | 2031 ++++++++++++++++++++++++
 ext/tinycbor/tests/tests.pro               |    3 +
 ext/tinycbor/tests/tojson/tojson.pro       |    8 +
 ext/tinycbor/tests/tojson/tst_tojson.cpp   |  724 +++++++++
 ext/tinycbor/tinycbor.pc.in                |   11 +
 ext/tinycbor/tools/cbordump/cbordump.c     |  167 ++
 ext/tinycbor/tools/cbordump/cbordump.pro   |   10 +
 ext/tinycbor/tools/json2cbor/json2cbor.c   |  492 ++++++
 ext/tinycbor/tools/json2cbor/json2cbor.pro |   20 +
 60 files changed, 13883 insertions(+)

diff --git a/ext/tinycbor/.appveyor.yml b/ext/tinycbor/.appveyor.yml
new file mode 100644
index 0000000..a64cb3f
--- /dev/null
+++ b/ext/tinycbor/.appveyor.yml
@@ -0,0 +1,35 @@
+version: 0.5-build-{build}
+pull_requests:
+  do_not_increment_build_number: true
+image:
+- Visual Studio 2015
+- Visual Studio 2013
+- Visual Studio 2017
+install:
+- cmd: >-
+    set tests=1
+
+    if /i "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" (call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64) & (set tests=0)
+
+    if /i "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64) & (set QTDIR=C:\Qt\5.9\msvc2015_64)
+
+    if /i "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64) & (set QTDIR=C:\Qt\5.9\msvc2017_64)
+
+    set path=%PATH%;%QTDIR%\bin
+build_script:
+- cmd: >-
+    nmake -f Makefile.nmake -nologo CFLAGS="-W3 -Os -MDd"
+
+    cd tests
+
+    if /i "%tests%"=="1" qmake CONFIG-=release CONFIG+=debug
+
+    if /i "%tests%"=="1" nmake -nologo -s
+test_script:
+- cmd: >-
+    if /i "%tests%"=="1" nmake -s -nologo check
+
+    if /i "%tests%"=="0" echo Tests skipped.
+artifacts:
+- path: lib\tinycbor.lib
+deploy: off
diff --git a/ext/tinycbor/.gitattributes b/ext/tinycbor/.gitattributes
new file mode 100644
index 0000000..76ed256
--- /dev/null
+++ b/ext/tinycbor/.gitattributes
@@ -0,0 +1,4 @@
+.tag                    export-subst
+.gitignore              export-ignore
+.gitattributes          export-ignore
+.appveyor.yml           text
diff --git a/ext/tinycbor/.gitignore b/ext/tinycbor/.gitignore
new file mode 100644
index 0000000..3272de3
--- /dev/null
+++ b/ext/tinycbor/.gitignore
@@ -0,0 +1,81 @@
+# Frequent generated files
+callgrind.out.*
+pcviewer.cfg
+*~
+*.a
+*.la
+*.core
+*.d
+*.dylib
+*.moc
+*.o
+*.obj
+*.orig
+*.swp
+*.rej
+*.so
+*.so.*
+*.pbxuser
+*.mode1
+*.mode1v3
+*_pch.h.cpp
+*_resource.rc
+.#*
+*.*#
+core
+.qmake.cache
+.qmake.stash
+.qmake.vars
+.device.vars
+tags
+.DS_Store
+*.debug
+Makefile*
+*.prl
+*.app
+*.pro.user*
+*.qmlproject.user*
+*.gcov
+*.gcda
+*.gcno
+*.flc
+.*.swp
+tinycbor.pc
+
+# Visual Studio generated files
+*.ib_pdb_index
+*.idb
+*.ilk
+*.pdb
+*.sln
+*.suo
+*.vcproj
+*vcproj.*.*.user
+*.ncb
+*.vcxproj
+*.vcxproj.filters
+*.vcxproj.user
+*.exe.embed.manifest
+*.exe_manifest.rc
+*.exe_manifest.res
+
+# MinGW generated files
+*.Debug
+*.Release
+
+# INTEGRITY generated files
+*.gpj
+*.int
+*.ael
+*.dla
+*.dnm
+*.dep
+*.map
+
+bin
+doc
+lib
+src/cjson
+src/doxygen.log
+!/Makefile
+.config
diff --git a/ext/tinycbor/.tag b/ext/tinycbor/.tag
new file mode 100644
index 0000000..6828f88
--- /dev/null
+++ b/ext/tinycbor/.tag
@@ -0,0 +1 @@
+$Format:%H$
diff --git a/ext/tinycbor/.travis.yml b/ext/tinycbor/.travis.yml
new file mode 100644
index 0000000..0615bc4
--- /dev/null
+++ b/ext/tinycbor/.travis.yml
@@ -0,0 +1,24 @@
+language: cpp
+os:
+  - linux
+  - osx
+env:
+  - CFLAGS="-O0 -g" QMAKEFLAGS="-config debug" PATH=/opt/qt59/bin:/usr/local/opt/qt5/bin:$PATH
+addons:
+  apt:
+    sources:
+      - sourceline: 'ppa:beineri/opt-qt593-trusty'
+    packages:
+      - qt59base valgrind
+install:
+  - if [ "${TRAVIS_OS_NAME}" != "linux" ]; then
+        brew update;
+        brew install qt5;
+    fi
+script:
+  - make -s -f Makefile.configure configure | tee .config
+  - make
+        CFLAGS="$CFLAGS"
+        all tests/Makefile
+  - cd tests && make check -k
+        TESTRUNNER=`which valgrind 2>/dev/null`
diff --git a/ext/tinycbor/CMakeLists.txt b/ext/tinycbor/CMakeLists.txt
new file mode 100644
index 0000000..c9e11ee
--- /dev/null
+++ b/ext/tinycbor/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_library(TINYCBOR INTERFACE)
+
+target_include_directories(TINYCBOR INTERFACE src)
+
+zephyr_library()
+zephyr_library_sources(
+    src/cbor_buf_reader.c
+    src/cbor_buf_writer.c
+    src/cborencoder.c
+    src/cborerrorstrings.c
+    src/cborparser.c
+    src/cborparser_dup_string.c
+)
+zephyr_library_link_libraries(TINYCBOR)
+target_link_libraries(TINYCBOR INTERFACE zephyr_interface)
diff --git a/ext/tinycbor/Doxyfile b/ext/tinycbor/Doxyfile
new file mode 100644
index 0000000..2cfaa33
--- /dev/null
+++ b/ext/tinycbor/Doxyfile
@@ -0,0 +1,2318 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "TinyCBOR $(VERSION) API"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = $(docroot)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(docroot)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                = "value=\arg \c"
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = NO
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = NO
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           = doxygen.log
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = .
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.h \
+                         *.c \
+                         *.dox
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = *_p.h
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           = . \
+                         ../examples/rime \
+                         ../examples/multi-threading
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = pics
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          = cbor_ Cbor
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = YES
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = YES
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = YES
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = YES
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = YES
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = DOXYGEN \
+                         CBOR_INLINE_API=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = NO
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = NO
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = NO
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = NO
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = NO
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = NO
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/ext/tinycbor/LICENSE b/ext/tinycbor/LICENSE
new file mode 100644
index 0000000..4aad977
--- /dev/null
+++ b/ext/tinycbor/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Intel Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ext/tinycbor/Makefile b/ext/tinycbor/Makefile
new file mode 100644
index 0000000..98c9a59
--- /dev/null
+++ b/ext/tinycbor/Makefile
@@ -0,0 +1,234 @@
+# Variables:
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/src
+pkgconfigdir = $(libdir)/pkgconfig
+
+CFLAGS = -Wall -Wextra
+LDFLAGS_GCSECTIONS = -Wl,--gc-sections
+LDFLAGS = $(if $(gc_sections-pass),$(LDFLAGS_GCSECTIONS))
+
+GIT_ARCHIVE = git archive --prefix="$(PACKAGE)/" -9
+INSTALL = install
+INSTALL_DATA = $(INSTALL) -m 644
+INSTALL_PROGRAM = $(INSTALL) -m 755
+QMAKE = qmake
+MKDIR = mkdir -p
+RMDIR = rmdir
+SED = sed
+
+# Our sources
+TINYCBOR_HEADERS = \
+	src/cbor.h \
+ 	src/cborjson.h \
+	src/cbor_enocoder_writer.h \
+	src/cbor_decoder_reader.h \
+	src/cbor_defs.h
+TINYCBOR_SOURCES = \
+	src/cborerrorstrings.c \
+	src/cborencoder.c \
+	src/cborparser.c \
+	src/cborparser_dup_string.c \
+	src/cborpretty.c \
+	src/cborpretty_stdio.c \
+	src/cbortojson.c \
+	src/cborvalidation.c \
+	src/cbor_buf_reader.c \
+	src/cbor_buf_writer.c
+#
+CBORDUMP_SOURCES = tools/cbordump/cbordump.c
+
+BUILD_SHARED = $(shell file -L /bin/sh 2>/dev/null | grep -q ELF && echo 1)
+BUILD_STATIC = 1
+
+ifneq ($(BUILD_STATIC),1)
+ifneq ($(BUILD_SHARED),1)
+  $(error error: BUILD_STATIC and BUILD_SHARED can not be both disabled)
+endif
+endif
+
+INSTALL_TARGETS += $(bindir)/cbordump
+ifeq ($(BUILD_SHARED),1)
+BINLIBRARY=lib/libtinycbor.so
+INSTALL_TARGETS += $(libdir)/libtinycbor.so
+INSTALL_TARGETS += $(libdir)/libtinycbor.so.0
+INSTALL_TARGETS += $(libdir)/libtinycbor.so.$(VERSION)
+endif
+ifeq ($(BUILD_STATIC),1)
+BINLIBRARY=lib/libtinycbor.a
+INSTALL_TARGETS += $(libdir)/libtinycbor.a
+endif
+INSTALL_TARGETS += $(pkgconfigdir)/tinycbor.pc
+INSTALL_TARGETS += $(TINYCBOR_HEADERS:./%=$(includedir)/%)
+
+# setup VPATH
+MAKEFILE := $(lastword $(MAKEFILE_LIST))
+SRCDIR := $(dir $(MAKEFILE))
+VPATH = $(SRCDIR):$(SRCDIR)/src
+
+# Our version
+GIT_DIR := $(strip $(shell git -C $(SRCDIR). rev-parse --git-dir 2> /dev/null))
+ifeq ($(GIT_DIR),)
+  VERSION = $(shell cat $(SRCDIR)VERSION)
+  DIRTYSRC :=
+else
+  VERSION := $(shell git -C $(SRCDIR). describe --tags | cut -c2-)
+  DIRTYSRC := $(shell \
+	test -n "`git -C $(SRCDIR). diff --name-only HEAD`" && \
+	echo +)
+endif
+PACKAGE = tinycbor-$(VERSION)
+
+# Check that QMAKE is Qt 5
+ifeq ($(origin QMAKE),file)
+  check_qmake = $(strip $(shell $(1) -query QT_VERSION 2>/dev/null | cut -b1))
+  ifneq ($(call check_qmake,$(QMAKE)),5)
+    QMAKE := qmake -qt5
+    ifneq ($(call check_qmake,$(QMAKE)),5)
+      QMAKE := qmake-qt5
+      ifneq ($(call check_qmake,$(QMAKE)),5)
+        QMAKE := @echo >&2 $(MAKEFILE): Cannot find a Qt 5 qmake; false
+      endif
+    endif
+  endif
+endif
+
+-include .config
+
+# if open_memstream is unavailable on the system, try to implement our own
+# version using funopen or fopencookie
+ifeq ($(open_memstream-pass),)
+  ifeq ($(funopen-pass)$(fopencookie-pass),)
+    CFLAGS += -DWITHOUT_OPEN_MEMSTREAM
+    $(warning warning: funopen and fopencookie unavailable, open_memstream can not be implemented and conversion to JSON will not work properly!)
+  else
+    TINYCBOR_SOURCES += src/open_memstream.c
+  endif
+endif
+
+# json2cbor depends on an external library (cjson)
+ifneq ($(cjson-pass)$(system-cjson-pass),)
+  JSON2CBOR_SOURCES = tools/json2cbor/json2cbor.c
+  INSTALL_TARGETS += $(bindir)/json2cbor
+  ifeq ($(system-cjson-pass),1)
+    LDFLAGS_CJSON = -lcjson
+  else
+    JSON2CBOR_SOURCES += src/cjson/cJSON.c
+    json2cbor_CCFLAGS = -I$(SRCDIR)src/cjson
+  endif
+endif
+
+# Rules
+all: .config \
+	$(if $(subst 0,,$(BUILD_STATIC)),lib/libtinycbor.a) \
+	$(if $(subst 0,,$(BUILD_SHARED)),lib/libtinycbor.so) \
+	bin/cbordump tinycbor.pc
+all: $(if $(JSON2CBOR_SOURCES),bin/json2cbor)
+check: tests/Makefile | $(BINLIBRARY)
+	$(MAKE) -C tests check
+silentcheck: | $(BINLIBRARY)
+	TESTARGS=-silent $(MAKE) -f $(MAKEFILE) -s check
+configure: .config
+.config: Makefile.configure
+	$(MAKE) -f $(SRCDIR)Makefile.configure OUT='>&9' configure 9> $@
+
+lib/libtinycbor.a: $(TINYCBOR_SOURCES:.c=.o)
+	@$(MKDIR) -p lib
+	$(AR) cqs $@ $^
+
+lib/libtinycbor.so: $(TINYCBOR_SOURCES:.c=.pic.o)
+	@$(MKDIR) -p lib
+	$(CC) -shared -Wl,-soname,libtinycbor.so.0 -o lib/libtinycbor.so.$(VERSION) $(LDFLAGS) $^
+	cd lib ; ln -sf libtinycbor.so.$(VERSION) libtinycbor.so ; ln -sf libtinycbor.so.$(VERSION) libtinycbor.so.0
+
+bin/cbordump: $(CBORDUMP_SOURCES:.c=.o) $(BINLIBRARY)
+	@$(MKDIR) -p bin
+	$(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS) -lm
+
+bin/json2cbor: $(JSON2CBOR_SOURCES:.c=.o) $(BINLIBRARY)
+	@$(MKDIR) -p bin
+	$(CC) -o $@ $(LDFLAGS) $^ $(LDFLAGS_CJSON) $(LDLIBS) -lm
+
+tinycbor.pc: tinycbor.pc.in
+	$(SED) > $@ < $< \
+		-e 's,@prefix@,$(prefix),' \
+		-e 's,@exec_prefix@,$(exec_prefix),' \
+		-e 's,@libdir@,$(libdir),' \
+		-e 's,@includedir@,$(includedir),' \
+		-e 's,@version@,$(VERSION),'
+
+tests/Makefile: tests/tests.pro
+	$(QMAKE) $(QMAKEFLAGS) -o $@ $<
+
+$(PACKAGE).tar.gz: | .git
+	GIT_DIR=$(SRCDIR).git $(GIT_ARCHIVE) --format=tar.gz -o "$(PACKAGE).tar.gz" HEAD
+$(PACKAGE).zip: | .git
+	GIT_DIR=$(SRCDIR).git $(GIT_ARCHIVE) --format=zip -o "$(PACKAGE).zip" HEAD
+
+$(DESTDIR)$(libdir)/%: lib/%
+	$(INSTALL) -d $(@D)
+	$(INSTALL_DATA) $< $@
+$(DESTDIR)$(bindir)/%: bin/%
+	$(INSTALL) -d $(@D)
+	$(INSTALL_PROGRAM) $< $@
+$(DESTDIR)$(pkgconfigdir)/%: %
+	$(INSTALL) -d $(@D)
+	$(INSTALL_DATA) $< $@
+$(DESTDIR)$(includedir)/%: src/%
+	$(INSTALL) -d $(@D)
+	$(INSTALL_DATA) $< $@
+
+install-strip:
+	$(MAKE) -f $(MAKEFILE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+
+install: $(INSTALL_TARGETS:%=$(DESTDIR)%)
+uninstall:
+	$(RM) $(INSTALL_TARGETS:%=$(DESTDIR)%)
+
+mostlyclean:
+	$(RM) $(TINYCBOR_SOURCES:.c=.o)
+	$(RM) $(TINYCBOR_SOURCES:.c=.pic.o)
+	$(RM) $(CBORDUMP_SOURCES:.c=.o)
+
+clean: mostlyclean
+	$(RM) bin/cbordump
+	$(RM) bin/json2cbor
+	$(RM) lib/libtinycbor.a
+	$(RM) tinycbor.pc
+	$(RM) lib/libtinycbor.so*
+	test -e tests/Makefile && $(MAKE) -C tests clean || :
+
+distclean: clean
+	test -e tests/Makefile && $(MAKE) -C tests distclean || :
+
+docs:
+	cd $(SRCDIR)src && VERSION=$(VERSION) doxygen $(SRCDIR)/../Doxyfile
+
+dist: $(PACKAGE).tar.gz $(PACKAGE).zip
+distcheck: .git
+	-$(RM) -r $${TMPDIR-/tmp}/tinycbor-distcheck
+	GIT_DIR=$(SRCDIR).git git archive --prefix=tinycbor-distcheck/ --format=tar HEAD | tar -xf - -C $${TMPDIR-/tmp}
+	cd $${TMPDIR-/tmp}/tinycbor-distcheck && $(MAKE) silentcheck
+	$(RM) -r $${TMPDIR-/tmp}/tinycbor-distcheck
+
+tag: distcheck
+	@cd $(SRCDIR). && perl maketag.pl
+
+.PHONY: all check silentcheck configure install uninstall
+.PHONY: mostlyclean clean distclean
+.PHONY: docs dist distcheck release
+.SECONDARY:
+
+cflags := $(CPPFLAGS) -I$(SRCDIR)/src
+cflags += -DTINYCBOR_VERSION_SUFFIX=\"$(DIRTYSRC)\"
+cflags += -std=c99 $(CFLAGS)
+%.o: %.c
+	@test -d $(@D) || $(MKDIR) $(@D)
+	$(CC) $(cflags) $($(basename $(notdir $@))_CCFLAGS) -c -o $@ $<
+%.pic.o: %.c
+	@test -d $(@D) || $(MKDIR) $(@D)
+	$(CC) $(cflags) -fPIC $($(basename $(notdir $@))_CCFLAGS) -c -o $@ $<
+
+-include src/*.d
diff --git a/ext/tinycbor/README b/ext/tinycbor/README
new file mode 100644
index 0000000..167efa0
--- /dev/null
+++ b/ext/tinycbor/README
@@ -0,0 +1,13 @@
+Concise Binary Object Representation (CBOR) Library
+---------------------------------------------------
+
+To build TinyCBOR:
+
+  make
+
+If you want to change the compiler or pass extra compiler flags:
+
+  make CC=clang CFLAGS="-m32 -Oz" LDFLAGS="-m32"
+
+Documentation: https://intel.github.io/tinycbor/current/
+
diff --git a/ext/tinycbor/TODO b/ext/tinycbor/TODO
new file mode 100644
index 0000000..e9103ee
--- /dev/null
+++ b/ext/tinycbor/TODO
@@ -0,0 +1,25 @@
+==== To Do list for libcbor ====
+=== General ===
+* API review
+* Benchmark
+* Write examples
+** Simple decoder
+** Decoder to JSON
+** Windowed encoding/decoding (limited memory)
+
+=== Encoder ===
+* Write API docs
+* Add API for creating indeterminate-length arrays and maps
+* Add API for creating indeterminate-length strings
+* Add API for relaxing doubles to floats and to integers
+* Add length-checking of the sub-containers (#ifndef CBOR_ENCODER_NO_USER_CHECK)
+* Decide how to indicate number of bytes needed
+** Suggestion: return negative number from the functions
+
+=== Decoder ===
+* Write functions not yet implemented
+* Add API for stream-decoding strings
+* Add API for checking known tags and simple types
+* (unlikely) Add API for checking the pairing of a tag and the tagged type
+* Write tests for error conditions
+* Fuzzy-test the decoder
diff --git a/ext/tinycbor/VERSION b/ext/tinycbor/VERSION
new file mode 100644
index 0000000..2eb3c4f
--- /dev/null
+++ b/ext/tinycbor/VERSION
@@ -0,0 +1 @@
+0.5
diff --git a/ext/tinycbor/examples/examples.pro b/ext/tinycbor/examples/examples.pro
new file mode 100644
index 0000000..22071ac
--- /dev/null
+++ b/ext/tinycbor/examples/examples.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = simplereader.pro
diff --git a/ext/tinycbor/examples/simplereader.c b/ext/tinycbor/examples/simplereader.c
new file mode 100644
index 0000000..256191f
--- /dev/null
+++ b/ext/tinycbor/examples/simplereader.c
@@ -0,0 +1,181 @@
+#include "../src/cbor.h"
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static uint8_t *readfile(const char *fname, size_t *size)
+{
+    struct stat st;
+    FILE *f = fopen(fname, "rb");
+    if (!f)
+        return NULL;
+    if (fstat(fileno(f), &st) == -1)
+        return NULL;
+    uint8_t *buf = malloc(st.st_size);
+    *size = fread(buf, st.st_size, 1, f);
+    fclose(f);
+    return buf;
+}
+
+static void indent(int nestingLevel)
+{
+    while (nestingLevel--)
+        puts("  ");
+}
+
+static void dumpbytes(const uint8_t *buf, size_t len)
+{
+    while (len--)
+        printf("%02X ", *buf++);
+}
+
+static bool dumprecursive(CborValue *it, int nestingLevel)
+{
+    while (!cbor_value_at_end(it)) {
+        CborError err;
+        CborType type = cbor_value_get_type(it);
+
+        indent(nestingLevel);
+        switch (type) {
+        case CborArrayType:
+        case CborMapType: {
+            // recursive type
+            CborValue recursed;
+            assert(cbor_value_is_container(it));
+            puts(type == CborArrayType ? "Array[" : "Map[");
+            err = cbor_value_enter_container(it, &recursed);
+            if (err)
+                return err;       // parse error
+            err = dumprecursive(&recursed, nestingLevel + 1);
+            if (err)
+                return err;       // parse error
+            err = cbor_value_leave_container(it, &recursed);
+            if (err)
+                return err;       // parse error
+            indent(nestingLevel);
+            puts("]");
+            continue;
+        }
+
+        case CborIntegerType: {
+            int64_t val;
+            cbor_value_get_int64(it, &val);     // can't fail
+            printf("%lld\n", (long long)val);
+            break;
+        }
+
+        case CborByteStringType: {
+            uint8_t *buf;
+            size_t n;
+            err = cbor_value_dup_byte_string(it, &buf, &n, it);
+            if (err)
+                return err;     // parse error
+            dumpbytes(buf, n);
+            puts("");
+            free(buf);
+            continue;
+        }
+
+        case CborTextStringType: {
+            char *buf;
+            size_t n;
+            err = cbor_value_dup_text_string(it, &buf, &n, it);
+            if (err)
+                return err;     // parse error
+            puts(buf);
+            free(buf);
+            continue;
+        }
+
+        case CborTagType: {
+            CborTag tag;
+            cbor_value_get_tag(it, &tag);       // can't fail
+            printf("Tag(%lld)\n", (long long)tag);
+            break;
+        }
+
+        case CborSimpleType: {
+            uint8_t type;
+            cbor_value_get_simple_type(it, &type);  // can't fail
+            printf("simple(%u)\n", type);
+            break;
+        }
+
+        case CborNullType:
+            puts("null");
+            break;
+
+        case CborUndefinedType:
+            puts("undefined");
+            break;
+
+        case CborBooleanType: {
+            bool val;
+            cbor_value_get_boolean(it, &val);       // can't fail
+            puts(val ? "true" : "false");
+            break;
+        }
+
+        case CborDoubleType: {
+            double val;
+            if (false) {
+                float f;
+        case CborFloatType:
+                cbor_value_get_float(it, &f);
+                val = f;
+            } else {
+                cbor_value_get_double(it, &val);
+            }
+            printf("%g\n", val);
+            break;
+        }
+        case CborHalfFloatType: {
+            uint16_t val;
+            cbor_value_get_half_float(it, &val);
+            printf("__f16(%04x)\n", val);
+            break;
+        }
+
+        case CborInvalidType:
+            assert(false);      // can't happen
+            break;
+        }
+
+        err = cbor_value_advance_fixed(it);
+        if (err)
+            return err;
+    }
+    return CborNoError;
+}
+
+int main(int argc, char **argv)
+{
+    if (argc == 1) {
+        puts("simplereader <filename>");
+        return 0;
+    }
+
+    size_t length;
+    uint8_t *buf = readfile(argv[1], &length);
+    if (!buf) {
+        perror("readfile");
+        return 1;
+    }
+
+    CborParser parser;
+    CborValue it;
+    CborError err = cbor_parser_init(buf, length, 0, &parser, &it);
+    if (!err)
+        err = dumprecursive(&it, 0);
+    free(buf);
+
+    if (err) {
+        fprintf(stderr, "CBOR parsing failure at offset %ld: %s\n",
+                it.ptr - buf, cbor_error_string(err));
+        return 1;
+    }
+    return 0;
+}
diff --git a/ext/tinycbor/examples/simplereader.pro b/ext/tinycbor/examples/simplereader.pro
new file mode 100644
index 0000000..07fdc6a
--- /dev/null
+++ b/ext/tinycbor/examples/simplereader.pro
@@ -0,0 +1,3 @@
+CONFIG -= qt
+SOURCES = simplereader.c
+include(../src/src.pri)
diff --git a/ext/tinycbor/maketag.pl b/ext/tinycbor/maketag.pl
new file mode 100644
index 0000000..5b1a8b7
--- /dev/null
+++ b/ext/tinycbor/maketag.pl
@@ -0,0 +1,91 @@
+#!perl
+use strict;
+sub run(@) {
+    open PROC, "-|", @_ or die("Cannot run $_[0]: $!");
+    my @out;
+    while (<PROC>) {
+        chomp;
+        push @out, $_;
+    }
+    close PROC;
+    return @out;
+}
+
+my @tags = run("git", "tag");
+my @v = run("git", "show", "HEAD:VERSION");
+my $v = $v[0];
+
+my $tagfile = ".git/TAG_EDITMSG";
+open TAGFILE, ">", $tagfile
+    or die("Cannot create file for editing tag message: $!");
+select TAGFILE;
+print "TinyCBOR release $v\n";
+print "\n";
+print "# Write something nice about this release here\n";
+
+# Do we have a commit template?
+my @result = run("git", "config", "--get", "commit.template");
+if (scalar @result) {
+    open TEMPLATE, "<", $result[0];
+    map { print $_; } <TEMPLATE>;
+    close TEMPLATE;
+}
+
+print "\n";
+print "# Commit log\n";
+open LOG, "-|", "git", "shortlog", "-e", "--no-merges", "--not", @tags;
+map { print "#  $_"; } <LOG>;
+close LOG;
+
+print "# Header diff:\n";
+open DIFF, "-|", "git", "diff", "HEAD", "--not", @tags, "--", 'src/*.h', ':!*_p.h';
+map { print "# $_"; } <DIFF>;
+close DIFF;
+
+select STDOUT;
+close TAGFILE;
+
+# Run the editor.
+# We use system so that stdin, stdout and stderr are forwarded.
+@result = run("git", "var", "GIT_EDITOR");
+@result = ($result[0], $tagfile);
+system @result;
+exit ($? >> 8) if $?;
+
+# Create the tag
+# Also using system so that hte user can see the output.
+system("git", "tag", "-a", "-F", $tagfile, split(' ', $ENV{GITTAGFLAGS}), "v$v");
+exit ($? >> 8) if $?;
+
+# Update the version files for the next patch release
+@v = split(/\./, $v);
+if (scalar @v < 3) {
+    push @v, '1';
+} else {
+    ++$v[-1];
+}
+$v = join('.', @v);
+open VERSION, ">", "VERSION" or die("Cannot open VERSION file: $!");
+print VERSION "$v\n";
+close VERSION;
+
+open VERSION, ">", "src/tinycbor-version.h" or die("Cannot open src/tinycbor-version.h: $!");
+print VERSION "#define TINYCBOR_VERSION_MAJOR      ", $v[0], "\n";
+print VERSION "#define TINYCBOR_VERSION_MINOR      ", $v[1], "\n";
+print VERSION "#define TINYCBOR_VERSION_PATCH      ", $v[2], "\n";
+close VERSION;
+
+if (open APPVEYORYML, "<", ".appveyor.yml") {
+    my @contents = map {
+        s/^version:.*/version: $v[0].$v[1].$v[2]-build-{build}/;
+        $_;
+    } <APPVEYORYML>;
+    close APPVEYORYML;
+    open APPVEYORYML, ">", ".appveyor.yml";
+    print APPVEYORYML join('', @contents);
+    close APPVEYORYML;
+}
+
+# Print summary
+print "Tag created and next versions updated.\n";
+print "Don't forget to create the docs.\n" if $v[2] == 1;
diff --git a/ext/tinycbor/pkg.yml b/ext/tinycbor/pkg.yml
new file mode 100644
index 0000000..c0e2133
--- /dev/null
+++ b/ext/tinycbor/pkg.yml
@@ -0,0 +1,29 @@
+#
+# 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: ext/tinycbor 
+pkg.description: CBOR encoding/decoding library 
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.cflags:
+    - -DWITHOUT_OPEN_MEMSTREAM
+    - "-I@mynewt-mcumgr/ext/tinycbor/src"
+pkg.cflags.FLOAT_USER: -DFLOAT_SUPPORT
diff --git a/ext/tinycbor/src/cbor.dox b/ext/tinycbor/src/cbor.dox
new file mode 100644
index 0000000..cc7a79d
--- /dev/null
+++ b/ext/tinycbor/src/cbor.dox
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+/**
+ * \mainpage
+ * The TinyCBOR $(VERSION) library is a small CBOR encoder and decoder library,
+ * optimized for very fast operation with very small footprint. The main encoder
+ * and decoder functions do not allocate memory.
+ *
+ * TinyCBOR is divided into the following groups of functions and structures:
+ *  - \ref CborGlobals
+ *  - \ref CborEncoding
+ *  - \ref CborParsing
+ *  - \ref CborPretty
+ *  - \ref CborToJson
+ */
+
+/**
+ * \file <cbor.h>
+ * The <cbor.h> is the main header in TinyCBOR and defines the constants used by most functions
+ * as well as the structures for encoding (CborEncoder) and decoding (CborValue).
+ *
+ * \sa <cborjson.h>
+ */
+
+/**
+ * \file <cborjson.h>
+ * The <cborjson.h> file contains the routines that are used to convert a CBOR
+ * data stream into JSON.
+ *
+ * \sa <cbor.h>
+ */
+
+/**
+ * \defgroup CborGlobals Global constants
+ * \brief Constants used by all TinyCBOR function groups.
+ */
+
+/**
+ * \addtogroup CborGlobals
+ * @{
+ */
+
+/**
+ * \var size_t CborIndefiniteLength
+ *
+ * This variable is a constant used to indicate that the length of the map or
+ * array is not yet determined. It is used in functions
+ * cbor_encoder_create_map() and cbor_encoder_create_array()
+ */
+
+/**
+ * \enum CborType
+ * The CborType enum contains the types known to TinyCBOR.
+ *
+ * \value CborIntegerType           Type is an integer value, positive, negative or zero
+ * \value CborByteStringType        Type is a string of arbitrary raw bytes
+ * \value CborTextStringType        Type is a text string encoded in UTF-8
+ * \value CborArrayType             Type is a CBOR array
+ * \value CborMapType               Type is a CBOR map (an associative container with key and value pairs)
+ * \value CborTagType               Type is a CBOR tag (a 64-bit integer describing the item that follows, see CborKnownTags)
+ * \value CborSimpleType            Type is one of CBOR Simple Types
+ * \value CborBooleanType           Type is a boolean (true or false)
+ * \value CborNullType              Type encodes a null
+ * \value CborUndefinedType         Type encodes an undefined value
+ * \value CborHalfFloatType         Type is an IEEE 754 half precision (16-bit) floating point type
+ * \value CborFloatType             Type is an IEEE 754 single precision (32-bit) floating point type
+ * \value CborDoubleType            Type is an IEEE 754 double precision (64-bit) floating point type
+ * \value CborInvalidType           Type is not valid (this value is used to indicate error conditions)
+ */
+
+/**
+ * \enum CborKnownTags
+ * The CborKnownTags enum contains known tags specified in RFC 7049, for use by the application.
+ * TinyCBOR does not usually interpret the meaning of these tags and does not add them to the
+ * output stream, unless specifically instructed to do so in functions for that effect.
+ *
+ * \value CborDateTimeStringTag     Text string contains a date-time encoded in RFC 3339 format, "YYYY-MM-DD hh:mm:ss+zzzz"
+ * \value CborUnixTime_tTag         Number is a Unix time_t quantity, the number of seconds since 1970-01-01 midnight UTC
+ * \value CborPositiveBignumTag     Item is a CBOR byte string encoding a positive integer of arbitrary precision
+ * \value CborNegativeBignumTag     Item is a CBOR byte string encoding a negative integer of arbitrary precision
+ * \value CborDecimalTag            Item is a CBOR array of two integers encoding a fixed-point decimal
+ * \value CborBigfloatTag           Item is a bigfloat
+ * \value CborExpectedBase64urlTag  Item is a CBOR byte string that is expected to be encoded as Base64Url
+ * \value CborExpectedBase64Tag     Item is a CBOR byte string that is expected to be encoded as Base64
+ * \value CborExpectedBase16Tag     Item is a CBOR byte string that is expected to be encoded as Base16 (also known as "hexdump")
+ * \value CborUriTag                Item is a CBOR text string containing an URI (RFC 3986) or IRI (RFC 3987)
+ * \value CborBase64urlTag          Item is a CBOR text string that was encoded as Base64Url
+ * \value CborBase64Tag             Item is a CBOR text string that was encoded as Base64
+ * \value CborRegularExpressionTag  Item is a CBOR text string containing a regular expression
+ * \value CborMimeMessageTag        Item is a CBOR text string containing a MIME message (RFC 2045, 2046, 2047, 2822)
+ * \value CborSignatureTag          Item contains CBOR-encoded data.
+ *                                  This tag is also used as "file magic," marking a file as containing CBOR
+ */
+
+/**
+ * \typedef CborTag
+ * This typedef is an unsigned 64-bit integer. Known CBOR tags can be used from the CborKnownTags enum
+ * but the user application may use other tag values than the ones specified in RFC 7049.
+ */
+
+/** @} */
diff --git a/ext/tinycbor/src/cbor.h b/ext/tinycbor/src/cbor.h
new file mode 100644
index 0000000..ae87ed6
--- /dev/null
+++ b/ext/tinycbor/src/cbor.h
@@ -0,0 +1,392 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_H
+#define CBOR_H
+
+#ifndef assert
+#include <assert.h>
+#endif
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "cbor_buf_writer.h"
+#include "cbor_buf_reader.h"
+#include "cbor_defs.h"
+#include "tinycbor-version.h"
+
+#define TINYCBOR_VERSION            ((TINYCBOR_VERSION_MAJOR << 16) | (TINYCBOR_VERSION_MINOR << 8) | TINYCBOR_VERSION_PATCH)
+
+#ifdef __cplusplus
+extern "C" {
+#else
+#include <stdbool.h>
+#endif
+
+CBOR_API const char *cbor_error_string(CborError error);
+
+/* Encoder API */
+struct CborEncoder
+{
+    cbor_encoder_writer *writer;
+    void *writer_arg;
+#ifndef NO_DFLT_WRITER
+    struct cbor_buf_writer wr;
+#endif
+    size_t added;
+    size_t container_size;
+    int flags;
+};
+
+typedef struct CborEncoder CborEncoder;
+
+#ifndef NO_DFLT_WRITER
+CBOR_API void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags);
+#endif
+CBOR_API void cbor_encoder_cust_writer_init(CborEncoder *encoder, struct cbor_encoder_writer *w, int flags);
+CBOR_API CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value);
+CBOR_API CborError cbor_encode_int(CborEncoder *encoder, int64_t value);
+CBOR_API CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value);
+CBOR_API CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value);
+CBOR_API CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag);
+CBOR_API CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length);
+CBOR_INLINE_API CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string)
+{ return cbor_encode_text_string(encoder, string, strlen(string)); }
+CBOR_API CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length);
+CBOR_API CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value);
+CBOR_INLINE_API int cbor_encode_bytes_written(CborEncoder *encoder)
+{   return encoder->writer->bytes_written; }
+CBOR_INLINE_API CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
+{ return cbor_encode_simple_value(encoder, (int)value - 1 + (CborBooleanType & 0x1f)); }
+CBOR_INLINE_API CborError cbor_encode_null(CborEncoder *encoder)
+{ return cbor_encode_simple_value(encoder, CborNullType & 0x1f); }
+CBOR_INLINE_API CborError cbor_encode_undefined(CborEncoder *encoder)
+{ return cbor_encode_simple_value(encoder, CborUndefinedType & 0x1f); }
+
+CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
+{ return cbor_encode_floating_point(encoder, CborHalfFloatType, value); }
+CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value)
+{ return cbor_encode_floating_point(encoder, CborFloatType, &value); }
+CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double value)
+{ return cbor_encode_floating_point(encoder, CborDoubleType, &value); }
+
+CBOR_API CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length);
+CBOR_API CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length);
+CBOR_API CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder);
+CBOR_API CborError cbor_encoder_close_container_checked(CborEncoder *encoder, const CborEncoder *containerEncoder);
+
+/* Parser API */
+struct CborParser
+{
+#ifndef NO_DFLT_READER
+    struct cbor_buf_reader br;
+#endif
+    struct cbor_decoder_reader *d;
+    int end;
+    int flags;
+};
+typedef struct CborParser CborParser;
+
+struct CborValue
+{
+    const CborParser *parser;
+    int offset;
+    uint32_t remaining;
+    uint32_t remainingclen;
+    uint16_t extra;
+    uint8_t type;
+    uint8_t flags;
+};
+typedef struct CborValue CborValue;
+
+#ifndef NO_DFLT_READER
+CBOR_API CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it);
+#endif
+CBOR_API CborError cbor_parser_cust_reader_init(struct cbor_decoder_reader *r, int flags, CborParser *parser, CborValue *it);
+
+CBOR_API CborError cbor_value_validate_basic(const CborValue *it);
+
+CBOR_INLINE_API bool cbor_value_at_end(const CborValue *it)
+{ return it->remaining == 0; }
+CBOR_API CborError cbor_value_advance_fixed(CborValue *it);
+CBOR_API CborError cbor_value_advance(CborValue *it);
+CBOR_INLINE_API bool cbor_value_is_container(const CborValue *it)
+{ return it->type == CborArrayType || it->type == CborMapType; }
+CBOR_API CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed);
+CBOR_API CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed);
+
+CBOR_PRIVATE_API uint64_t _cbor_value_decode_int64_internal(const CborValue *value);
+CBOR_INLINE_API uint64_t _cbor_value_extract_int64_helper(const CborValue *value)
+{
+    return value->flags & CborIteratorFlag_IntegerValueTooLarge ?
+                _cbor_value_decode_int64_internal(value) : value->extra;
+}
+
+CBOR_INLINE_API bool cbor_value_is_valid(const CborValue *value)
+{ return value && value->type != CborInvalidType; }
+CBOR_INLINE_API CborType cbor_value_get_type(const CborValue *value)
+{ return (CborType)value->type; }
+
+/* Null & undefined type */
+CBOR_INLINE_API bool cbor_value_is_null(const CborValue *value)
+{ return value->type == CborNullType; }
+CBOR_INLINE_API bool cbor_value_is_undefined(const CborValue *value)
+{ return value->type == CborUndefinedType; }
+
+/* Booleans */
+CBOR_INLINE_API bool cbor_value_is_boolean(const CborValue *value)
+{ return value->type == CborBooleanType; }
+CBOR_INLINE_API CborError cbor_value_get_boolean(const CborValue *value, bool *result)
+{
+    assert(cbor_value_is_boolean(value));
+    *result = !!value->extra;
+    return CborNoError;
+}
+
+/* Simple types */
+CBOR_INLINE_API bool cbor_value_is_simple_type(const CborValue *value)
+{ return value->type == CborSimpleType; }
+CBOR_INLINE_API CborError cbor_value_get_simple_type(const CborValue *value, uint8_t *result)
+{
+    assert(cbor_value_is_simple_type(value));
+    *result = (uint8_t)value->extra;
+    return CborNoError;
+}
+
+/* Integers */
+CBOR_INLINE_API bool cbor_value_is_integer(const CborValue *value)
+{ return value->type == CborIntegerType; }
+CBOR_INLINE_API bool cbor_value_is_unsigned_integer(const CborValue *value)
+{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger) == 0; }
+CBOR_INLINE_API bool cbor_value_is_negative_integer(const CborValue *value)
+{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger); }
+
+CBOR_INLINE_API CborError cbor_value_get_raw_integer(const CborValue *value, uint64_t *result)
+{
+    assert(cbor_value_is_integer(value));
+    *result = _cbor_value_extract_int64_helper(value);
+    return CborNoError;
+}
+
+CBOR_INLINE_API CborError cbor_value_get_uint64(const CborValue *value, uint64_t *result)
+{
+    assert(cbor_value_is_unsigned_integer(value));
+    *result = _cbor_value_extract_int64_helper(value);
+    return CborNoError;
+}
+
+CBOR_INLINE_API CborError cbor_value_get_int64(const CborValue *value, int64_t *result)
+{
+    assert(cbor_value_is_integer(value));
+    *result = (int64_t) _cbor_value_extract_int64_helper(value);
+    if (value->flags & CborIteratorFlag_NegativeInteger)
+        *result = -*result - 1;
+    return CborNoError;
+}
+
+CBOR_INLINE_API CborError cbor_value_get_int(const CborValue *value, int *result)
+{
+    assert(cbor_value_is_integer(value));
+    *result = (int) _cbor_value_extract_int64_helper(value);
+    if (value->flags & CborIteratorFlag_NegativeInteger)
+        *result = -*result - 1;
+    return CborNoError;
+}
+
+CBOR_API CborError cbor_value_get_int64_checked(const CborValue *value, int64_t *result);
+CBOR_API CborError cbor_value_get_int_checked(const CborValue *value, int *result);
+
+CBOR_INLINE_API bool cbor_value_is_length_known(const CborValue *value)
+{ return (value->flags & CborIteratorFlag_UnknownLength) == 0; }
+
+/* Tags */
+CBOR_INLINE_API bool cbor_value_is_tag(const CborValue *value)
+{ return value->type == CborTagType; }
+CBOR_INLINE_API CborError cbor_value_get_tag(const CborValue *value, CborTag *result)
+{
+    assert(cbor_value_is_tag(value));
+    *result = _cbor_value_extract_int64_helper(value);
+    return CborNoError;
+}
+CBOR_API CborError cbor_value_skip_tag(CborValue *it);
+
+/* Strings */
+CBOR_INLINE_API bool cbor_value_is_byte_string(const CborValue *value)
+{ return value->type == CborByteStringType; }
+CBOR_INLINE_API bool cbor_value_is_text_string(const CborValue *value)
+{ return value->type == CborTextStringType; }
+
+CBOR_INLINE_API CborError cbor_value_get_string_length(const CborValue *value, size_t *length)
+{
+    assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
+    if (!cbor_value_is_length_known(value))
+        return CborErrorUnknownLength;
+    uint64_t v = _cbor_value_extract_int64_helper(value);
+    *length = (size_t)v;
+    if (*length != v)
+        return CborErrorDataTooLarge;
+    return CborNoError;
+}
+
+CBOR_PRIVATE_API CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
+                                                   size_t *buflen, CborValue *next);
+CBOR_PRIVATE_API CborError _cbor_value_dup_string(const CborValue *value, void **buffer,
+                                                  size_t *buflen, CborValue *next);
+
+CBOR_API CborError cbor_value_calculate_string_length(const CborValue *value, size_t *length);
+
+CBOR_INLINE_API CborError cbor_value_copy_text_string(const CborValue *value, char *buffer,
+                                                      size_t *buflen, CborValue *next)
+{
+    assert(cbor_value_is_text_string(value));
+    return _cbor_value_copy_string(value, buffer, buflen, next);
+}
+CBOR_INLINE_API CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer,
+                                                      size_t *buflen, CborValue *next)
+{
+    assert(cbor_value_is_byte_string(value));
+    return _cbor_value_copy_string(value, buffer, buflen, next);
+}
+
+CBOR_INLINE_API CborError cbor_value_dup_text_string(const CborValue *value, char **buffer,
+                                                     size_t *buflen, CborValue *next)
+{
+    assert(cbor_value_is_text_string(value));
+    return _cbor_value_dup_string(value, (void **)buffer, buflen, next);
+}
+CBOR_INLINE_API CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer,
+                                                     size_t *buflen, CborValue *next)
+{
+    assert(cbor_value_is_byte_string(value));
+    return _cbor_value_dup_string(value, (void **)buffer, buflen, next);
+}
+
+CBOR_PRIVATE_API CborError _cbor_value_get_string_chunk(const CborValue *value, const void **bufferptr,
+                                                        size_t *len, CborValue *next);
+CBOR_INLINE_API CborError cbor_value_get_text_string_chunk(const CborValue *value, const char **bufferptr,
+                                                           size_t *len, CborValue *next)
+{
+    assert(cbor_value_is_text_string(value));
+    return _cbor_value_get_string_chunk(value, (const void **)bufferptr, len, next);
+}
+CBOR_INLINE_API CborError cbor_value_get_byte_string_chunk(const CborValue *value, const uint8_t **bufferptr,
+                                                           size_t *len, CborValue *next)
+{
+    assert(cbor_value_is_byte_string(value));
+    return _cbor_value_get_string_chunk(value, (const void **)bufferptr, len, next);
+}
+
+CBOR_API CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result);
+
+/* Maps and arrays */
+CBOR_INLINE_API bool cbor_value_is_array(const CborValue *value)
+{ return value->type == CborArrayType; }
+CBOR_INLINE_API bool cbor_value_is_map(const CborValue *value)
+{ return value->type == CborMapType; }
+
+CBOR_INLINE_API CborError cbor_value_get_array_length(const CborValue *value, size_t *length)
+{
+    assert(cbor_value_is_array(value));
+    if (!cbor_value_is_length_known(value))
+        return CborErrorUnknownLength;
+    uint64_t v = _cbor_value_extract_int64_helper(value);
+    *length = (size_t)v;
+    if (*length != v)
+        return CborErrorDataTooLarge;
+    return CborNoError;
+}
+
+CBOR_INLINE_API CborError cbor_value_get_map_length(const CborValue *value, size_t *length)
+{
+    assert(cbor_value_is_map(value));
+    if (!cbor_value_is_length_known(value))
+        return CborErrorUnknownLength;
+    uint64_t v = _cbor_value_extract_int64_helper(value);
+    *length = (size_t)v;
+    if (*length != v)
+        return CborErrorDataTooLarge;
+    return CborNoError;
+}
+
+CBOR_API CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element);
+
+/* Floating point */
+CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value)
+{ return value->type == CborHalfFloatType; }
+CBOR_API CborError cbor_value_get_half_float(const CborValue *value, void *result);
+
+CBOR_INLINE_API bool cbor_value_is_float(const CborValue *value)
+{ return value->type == CborFloatType; }
+CBOR_INLINE_API CborError cbor_value_get_float(const CborValue *value, float *result)
+{
+    assert(cbor_value_is_float(value));
+    assert(value->flags & CborIteratorFlag_IntegerValueTooLarge);
+    uint32_t data = (uint32_t)_cbor_value_decode_int64_internal(value);
+    memcpy(result, &data, sizeof(*result));
+    return CborNoError;
+}
+
+CBOR_INLINE_API bool cbor_value_is_double(const CborValue *value)
+{ return value->type == CborDoubleType; }
+CBOR_INLINE_API CborError cbor_value_get_double(const CborValue *value, double *result)
+{
+    assert(cbor_value_is_double(value));
+    assert(value->flags & CborIteratorFlag_IntegerValueTooLarge);
+    uint64_t data = _cbor_value_decode_int64_internal(value);
+    memcpy(result, &data, sizeof(*result));
+    return CborNoError;
+}
+
+/* Validation API */
+CBOR_API CborError cbor_value_validate(const CborValue *it, int flags);
+
+/* Human-readable (dump) API */
+
+typedef CborError (*CborStreamFunction)(void *token, const char *fmt, ...)
+#ifdef __GNUC__
+    __attribute__((__format__(printf, 2, 3)))
+#endif
+;
+
+CBOR_API CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags);
+
+/* The following API requires a hosted C implementation (uses FILE*) */
+#if !defined(__STDC_HOSTED__) || __STDC_HOSTED__-0 == 1
+CBOR_API CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags);
+CBOR_API CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value);
+CBOR_INLINE_API CborError cbor_value_to_pretty(FILE *out, const CborValue *value)
+{
+    CborValue copy = *value;
+    return cbor_value_to_pretty_advance_flags(out, &copy, CborPrettyDefaultFlags);
+}
+#endif /* __STDC_HOSTED__ check */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBOR_H */
diff --git a/ext/tinycbor/src/cbor_buf_reader.c b/ext/tinycbor/src/cbor_buf_reader.c
new file mode 100644
index 0000000..54ec067
--- /dev/null
+++ b/ext/tinycbor/src/cbor_buf_reader.c
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#include "cbor_buf_reader.h"
+#include "compilersupport_p.h"
+
+CBOR_INLINE_API uint16_t get16(const uint8_t *ptr)
+{
+    uint16_t result;
+    memcpy(&result, ptr, sizeof(result));
+    return cbor_ntohs(result);
+}
+
+CBOR_INLINE_API uint32_t get32(const uint8_t *ptr)
+{
+    uint32_t result;
+    memcpy(&result, ptr, sizeof(result));
+    return cbor_ntohl(result);
+}
+
+CBOR_INLINE_API uint64_t get64(const uint8_t *ptr)
+{
+    uint64_t result;
+    memcpy(&result, ptr, sizeof(result));
+    return cbor_ntohll(result);
+}
+
+CBOR_INLINE_API uintptr_t get_string_chunk(const uint8_t *ptr)
+{
+    return (uintptr_t)ptr;
+}
+
+static uint8_t
+cbuf_buf_reader_get8(struct cbor_decoder_reader *d, int offset)
+{
+    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
+    return cb->buffer[offset];
+}
+
+static uint16_t
+cbuf_buf_reader_get16(struct cbor_decoder_reader *d, int offset)
+{
+    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
+    return get16(cb->buffer + offset);
+}
+
+static uint32_t
+cbuf_buf_reader_get32(struct cbor_decoder_reader *d, int offset)
+{
+    uint32_t val;
+    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
+    val = get32(cb->buffer + offset);
+    return val;
+}
+
+static uint64_t
+cbuf_buf_reader_get64(struct cbor_decoder_reader *d, int offset)
+{
+    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
+    return get64(cb->buffer + offset);
+}
+
+static uintptr_t
+cbor_buf_reader_get_string_chunk(struct cbor_decoder_reader *d,
+                                 int offset, size_t *len)
+{
+    struct cbor_buf_reader *cb = (struct cbor_buf_reader *)d;
+
+    (void)*len;
+
+    return get_string_chunk(cb->buffer + offset);
+}
+
+static uintptr_t
+cbor_buf_reader_cmp(struct cbor_decoder_reader *d, char *dst, int src_offset,
+                    size_t len)
+{
+    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
+
+    return !memcmp(dst, cb->buffer + src_offset, len);
+}
+
+static uintptr_t
+cbor_buf_reader_cpy(struct cbor_decoder_reader *d, char *dst, int src_offset,
+                    size_t len)
+{
+    struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d;
+    return (uintptr_t) memcpy(dst, cb->buffer + src_offset, len);
+}
+
+void
+cbor_buf_reader_init(struct cbor_buf_reader *cb, const uint8_t *buffer,
+                     size_t data)
+{
+    cb->buffer = buffer;
+    cb->r.get8 = &cbuf_buf_reader_get8;
+    cb->r.get16 = &cbuf_buf_reader_get16;
+    cb->r.get32 = &cbuf_buf_reader_get32;
+    cb->r.get64 = &cbuf_buf_reader_get64;
+    cb->r.cmp = &cbor_buf_reader_cmp;
+    cb->r.cpy = &cbor_buf_reader_cpy;
+    cb->r.get_string_chunk = &cbor_buf_reader_get_string_chunk;
+    cb->r.message_size = data;
+}
diff --git a/ext/tinycbor/src/cbor_buf_reader.h b/ext/tinycbor/src/cbor_buf_reader.h
new file mode 100644
index 0000000..70408fd
--- /dev/null
+++ b/ext/tinycbor/src/cbor_buf_reader.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_BUF_READER_H
+#define CBOR_BUF_READER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "cbor_decoder_reader.h"
+
+struct cbor_buf_reader {
+    struct cbor_decoder_reader r;
+    const uint8_t *buffer;
+};
+
+void cbor_buf_reader_init(struct cbor_buf_reader *cb, const uint8_t *buffer,
+                          size_t data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBOR_BUF_READER_H */
+
diff --git a/ext/tinycbor/src/cbor_buf_writer.c b/ext/tinycbor/src/cbor_buf_writer.c
new file mode 100644
index 0000000..fb401bc
--- /dev/null
+++ b/ext/tinycbor/src/cbor_buf_writer.c
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#include "cbor.h"
+#include "cbor_buf_writer.h"
+
+CBOR_INLINE_API int
+would_overflow(struct cbor_buf_writer *cb, size_t len)
+{
+    ptrdiff_t remaining = (ptrdiff_t)cb->end;
+
+    if (!remaining)
+        return 1;
+    remaining -= (ptrdiff_t)cb->ptr;
+    remaining -= (ptrdiff_t)len;
+    return (remaining < 0);
+}
+
+int
+cbor_buf_writer(struct cbor_encoder_writer *arg, const char *data, int len)
+{
+    struct cbor_buf_writer *cb = (struct cbor_buf_writer *) arg;
+
+    if (would_overflow(cb, len)) {
+        if (cb->end != NULL) {
+            len -= cb->end - cb->ptr;
+            cb->end = NULL;
+            cb->bytes_needed = 0;
+        }
+
+        cb->bytes_needed += len;
+
+        return CborErrorOutOfMemory;
+    }
+
+    memcpy(cb->ptr, data, len);
+    cb->ptr += len;
+    cb->enc.bytes_written += len;
+    return CborNoError;
+}
+
+void
+cbor_buf_writer_init(struct cbor_buf_writer *cb, uint8_t *buffer, size_t size)
+{
+    cb->ptr = buffer;
+    cb->end = buffer + size;
+    cb->enc.bytes_written = 0;
+    cb->bytes_needed = 0;
+    cb->enc.write = cbor_buf_writer;
+}
+
+size_t
+cbor_buf_writer_buffer_size(struct cbor_buf_writer *cb, const uint8_t *buffer)
+{
+    return (size_t)(cb->ptr - buffer);
+}
+
+size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder)
+{
+    struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer;
+
+    return wr->end ? 0 : (size_t)wr->bytes_needed;
+}
+
+size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer)
+{
+    struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer;
+
+    return (size_t)(wr->ptr - buffer);
+}
+
+uint8_t *_cbor_encoder_get_buffer_pointer(const CborEncoder *encoder)
+{
+    struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer;
+
+    return wr->ptr;
+}
+
diff --git a/ext/tinycbor/src/cbor_buf_writer.h b/ext/tinycbor/src/cbor_buf_writer.h
new file mode 100644
index 0000000..f9f714f
--- /dev/null
+++ b/ext/tinycbor/src/cbor_buf_writer.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_BUF_WRITER_H
+#define CBOR_BUF_WRITER_H
+
+#include "cbor_encoder_writer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct cbor_buf_writer {
+    struct cbor_encoder_writer enc;
+    uint8_t *ptr;
+    const uint8_t *end;
+    int bytes_needed;
+};
+
+struct CborEncoder;
+
+void cbor_buf_writer_init(struct cbor_buf_writer *cb, uint8_t *buffer,
+                          size_t data);
+size_t cbor_buf_writer_buffer_size(struct cbor_buf_writer *cb,
+                                   const uint8_t *buffer);
+size_t cbor_encoder_get_extra_bytes_needed(const struct CborEncoder *encoder);
+size_t cbor_encoder_get_buffer_size(const struct CborEncoder *encoder,
+                                    const uint8_t *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBOR_BUF_WRITER_H */
diff --git a/ext/tinycbor/src/cbor_cnt_writer.h b/ext/tinycbor/src/cbor_cnt_writer.h
new file mode 100644
index 0000000..7cf3464
--- /dev/null
+++ b/ext/tinycbor/src/cbor_cnt_writer.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_CNT_WRITER_H
+#define CBOR_CNT_WRITER_H
+
+#include "cbor.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    /* use this count writer if you want to try out a cbor encoding to see
+     * how long it would be (before allocating memory). This replaced the
+     * code in tinycbor.h that would try to do this once the encoding failed
+     * in a buffer.  Its much easier to understand this way (for me)
+     */
+
+struct CborCntWriter {
+    struct cbor_encoder_writer enc;
+};
+
+static inline int
+cbor_cnt_writer(struct cbor_encoder_writer *arg, const char *data, int len) {
+    struct CborCntWriter *cb = (struct CborCntWriter *) arg;
+    cb->enc.bytes_written += len;
+    return CborNoError;
+}
+
+static inline void
+cbor_cnt_writer_init(struct CborCntWriter *cb) {
+    cb->enc.bytes_written = 0;
+    cb->enc.write = &cbor_cnt_writer;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBOR_CNT_WRITER_H */
+
diff --git a/ext/tinycbor/src/cbor_decoder_reader.h b/ext/tinycbor/src/cbor_decoder_reader.h
new file mode 100644
index 0000000..c3ecaba
--- /dev/null
+++ b/ext/tinycbor/src/cbor_decoder_reader.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_DECODER_WRITER_H
+#define CBOR_DECODER_WRITER_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct cbor_decoder_reader;
+
+typedef uint8_t (cbor_reader_get8)(struct cbor_decoder_reader *d, int offset);
+typedef uint16_t (cbor_reader_get16)(struct cbor_decoder_reader *d, int offset);
+typedef uint32_t (cbor_reader_get32)(struct cbor_decoder_reader *d, int offset);
+typedef uint64_t (cbor_reader_get64)(struct cbor_decoder_reader *d, int offset);
+typedef uintptr_t (cbor_memcmp)(struct cbor_decoder_reader *d, char *buf, int offset, size_t len);
+typedef uintptr_t (cbor_memcpy)(struct cbor_decoder_reader *d, char *buf, int offset, size_t len);
+typedef uintptr_t (cbor_get_string_chunk)(struct cbor_decoder_reader *d, int offset, size_t *len);
+
+struct cbor_decoder_reader {
+    cbor_reader_get8  *get8;
+    cbor_reader_get16 *get16;
+    cbor_reader_get32 *get32;
+    cbor_reader_get64 *get64;
+    cbor_memcmp       *cmp;
+    cbor_memcpy       *cpy;
+    cbor_get_string_chunk *get_string_chunk;
+    size_t             message_size;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ext/tinycbor/src/cbor_defs.h b/ext/tinycbor/src/cbor_defs.h
new file mode 100644
index 0000000..a4975c6
--- /dev/null
+++ b/ext/tinycbor/src/cbor_defs.h
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_DEFS_H
+#define CBOR_DEFS_H
+
+#include <limits.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#ifndef SIZE_MAX
+/* Some systems fail to define SIZE_MAX in <stdint.h>, even though C99 requires it...
+ * Conversion from signed to unsigned is defined in 6.3.1.3 (Signed and unsigned integers) p2,
+ * which says: "the value is converted by repeatedly adding or subtracting one more than the
+ * maximum value that can be represented in the new type until the value is in the range of the
+ * new type."
+ * So -1 gets converted to size_t by adding SIZE_MAX + 1, which results in SIZE_MAX.
+ */
+#  define SIZE_MAX ((size_t)-1)
+#endif
+
+#ifndef CBOR_API
+#  define CBOR_API
+#endif
+#ifndef CBOR_PRIVATE_API
+#  define CBOR_PRIVATE_API
+#endif
+#ifndef CBOR_INLINE_API
+#  if defined(__cplusplus)
+#    define CBOR_INLINE inline
+#    define CBOR_INLINE_API inline
+#  else
+#    define CBOR_INLINE_API static CBOR_INLINE
+#    if defined(_MSC_VER)
+#      define CBOR_INLINE __inline
+#    elif defined(__GNUC__)
+#      define CBOR_INLINE __inline__
+#    elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#      define CBOR_INLINE inline
+#    else
+#      define CBOR_INLINE
+#    endif
+#  endif
+#endif
+
+typedef enum CborType {
+    CborIntegerType     = 0x00,
+    CborByteStringType  = 0x40,
+    CborTextStringType  = 0x60,
+    CborArrayType       = 0x80,
+    CborMapType         = 0xa0,
+    CborTagType         = 0xc0,
+    CborSimpleType      = 0xe0,
+    CborBooleanType     = 0xf5,
+    CborNullType        = 0xf6,
+    CborUndefinedType   = 0xf7,
+    CborHalfFloatType   = 0xf9,
+    CborFloatType       = 0xfa,
+    CborDoubleType      = 0xfb,
+
+    CborInvalidType     = 0xff              /* equivalent to the break byte, so it will never be used */
+} CborType;
+
+typedef uint64_t CborTag;
+
+typedef enum CborKnownTags {
+    CborDateTimeStringTag          = 0,        /* RFC 3339 format: YYYY-MM-DD hh:mm:ss+zzzz */
+    CborUnixTime_tTag              = 1,
+    CborPositiveBignumTag          = 2,
+    CborNegativeBignumTag          = 3,
+    CborDecimalTag                 = 4,
+    CborBigfloatTag                = 5,
+    CborExpectedBase64urlTag       = 21,
+    CborExpectedBase64Tag          = 22,
+    CborExpectedBase16Tag          = 23,
+    CborUriTag                     = 32,
+    CborBase64urlTag               = 33,
+    CborBase64Tag                  = 34,
+    CborRegularExpressionTag       = 35,
+    CborMimeMessageTag             = 36,       /* RFC 2045-2047 */
+    CborSignatureTag               = 55799
+} CborKnownTags;
+
+/* #define the constants so we can check with #ifdef */
+#define CborDateTimeStringTag CborDateTimeStringTag
+#define CborUnixTime_tTag CborUnixTime_tTag
+#define CborPositiveBignumTag CborPositiveBignumTag
+#define CborNegativeBignumTag CborNegativeBignumTag
+#define CborDecimalTag CborDecimalTag
+#define CborBigfloatTag CborBigfloatTag
+#define CborCOSE_Encrypt0Tag CborCOSE_Encrypt0Tag
+#define CborCOSE_Mac0Tag CborCOSE_Mac0Tag
+#define CborCOSE_Sign1Tag CborCOSE_Sign1Tag
+#define CborExpectedBase64urlTag CborExpectedBase64urlTag
+#define CborExpectedBase64Tag CborExpectedBase64Tag
+#define CborExpectedBase16Tag CborExpectedBase16Tag
+#define CborEncodedCborTag CborEncodedCborTag
+#define CborUrlTag CborUrlTag
+#define CborBase64urlTag CborBase64urlTag
+#define CborBase64Tag CborBase64Tag
+#define CborRegularExpressionTag CborRegularExpressionTag
+#define CborMimeMessageTag CborMimeMessageTag
+#define CborCOSE_EncryptTag CborCOSE_EncryptTag
+#define CborCOSE_MacTag CborCOSE_MacTag
+#define CborCOSE_SignTag CborCOSE_SignTag
+#define CborSignatureTag CborSignatureTag
+
+/* Error API */
+
+typedef enum CborError {
+    CborNoError = 0,
+
+    /* errors in all modes */
+    CborUnknownError,
+    CborErrorUnknownLength,         /* request for length in array, map, or string with indeterminate length */
+    CborErrorAdvancePastEOF,
+    CborErrorIO,
+
+    /* parser errors streaming errors */
+    CborErrorGarbageAtEnd = 256,
+    CborErrorUnexpectedEOF,
+    CborErrorUnexpectedBreak,
+    CborErrorUnknownType,           /* can only heppen in major type 7 */
+    CborErrorIllegalType,           /* type not allowed here */
+    CborErrorIllegalNumber,
+    CborErrorIllegalSimpleType,     /* types of value less than 32 encoded in two bytes */
+
+    /* parser errors in strict mode parsing only */
+    CborErrorUnknownSimpleType = 512,
+    CborErrorUnknownTag,
+    CborErrorInappropriateTagForType,
+    CborErrorDuplicateObjectKeys,
+    CborErrorInvalidUtf8TextString,
+    CborErrorExcludedType,
+    CborErrorExcludedValue,
+    CborErrorImproperValue,
+    CborErrorOverlongEncoding,
+    CborErrorMapKeyNotString,
+    CborErrorMapNotSorted,
+    CborErrorMapKeysNotUnique,
+
+    /* encoder errors */
+    CborErrorTooManyItems = 768,
+    CborErrorTooFewItems,
+
+    /* internal implementation errors */
+    CborErrorDataTooLarge = 1024,
+    CborErrorNestingTooDeep,
+    CborErrorUnsupportedType,
+
+    /* errors in converting to JSON */
+    CborErrorJsonObjectKeyIsAggregate,
+    CborErrorJsonObjectKeyNotString,
+    CborErrorJsonNotImplemented,
+
+    CborErrorOutOfMemory = (int) (~0U / 2 + 1),
+    CborErrorInternalError = (int) (~0U / 2)    /* INT_MAX on two's complement machines */
+} CborError;
+
+/* Parser Flags */
+
+enum CborParserIteratorFlags
+{
+    CborIteratorFlag_IntegerValueTooLarge   = 0x01,
+    CborIteratorFlag_NegativeInteger        = 0x02,
+    CborIteratorFlag_IteratingStringChunks  = 0x02,
+    CborIteratorFlag_UnknownLength          = 0x04,
+    CborIteratorFlag_ContainerIsMap         = 0x20
+};
+
+enum CborValidationFlags {
+    /* Bit mapping:
+     *  bits 0-7 (8 bits):      canonical format
+     *  bits 8-11 (4 bits):     canonical format & strict mode
+     *  bits 12-20 (8 bits):    strict mode
+     *  bits 21-31 (10 bits):   other
+     */
+
+    CborValidateShortestIntegrals           = 0x0001,
+    CborValidateShortestFloatingPoint       = 0x0002,
+    CborValidateShortestNumbers             = CborValidateShortestIntegrals | CborValidateShortestFloatingPoint,
+    CborValidateNoIndeterminateLength       = 0x0100,
+    CborValidateMapIsSorted                 = 0x0200 | CborValidateNoIndeterminateLength,
+
+    CborValidateCanonicalFormat             = 0x0fff,
+
+    CborValidateMapKeysAreUnique            = 0x1000 | CborValidateMapIsSorted,
+    CborValidateTagUse                      = 0x2000,
+    CborValidateUtf8                        = 0x4000,
+
+    CborValidateStrictMode                  = 0xfff00,
+
+    CborValidateMapKeysAreString            = 0x100000,
+    CborValidateNoUndefined                 = 0x200000,
+    CborValidateNoTags                      = 0x400000,
+    CborValidateFiniteFloatingPoint         = 0x800000,
+    /* unused                               = 0x1000000, */
+    /* unused                               = 0x2000000, */
+
+    CborValidateNoUnknownSimpleTypesSA      = 0x4000000,
+    CborValidateNoUnknownSimpleTypes        = 0x8000000 | CborValidateNoUnknownSimpleTypesSA,
+    CborValidateNoUnknownTagsSA             = 0x10000000,
+    CborValidateNoUnknownTagsSR             = 0x20000000 | CborValidateNoUnknownTagsSA,
+    CborValidateNoUnknownTags               = 0x40000000 | CborValidateNoUnknownTagsSR,
+
+    CborValidateCompleteData                = (int)0x80000000,
+
+    CborValidateStrictest                   = (int)~0U,
+    CborValidateBasic                       = 0
+};
+
+static const size_t CborIndefiniteLength = SIZE_MAX;
+
+/* The following API requires a hosted C implementation (uses FILE*) */
+#if !defined(__STDC_HOSTED__) || __STDC_HOSTED__-0 == 1
+
+enum CborPrettyFlags {
+    CborPrettyNumericEncodingIndicators     = 0x01,
+    CborPrettyTextualEncodingIndicators     = 0,
+
+    CborPrettyIndicateIndetermineLength     = 0x02,
+    CborPrettyIndicateOverlongNumbers       = 0x04,
+
+    CborPrettyShowStringFragments           = 0x100,
+    CborPrettyMergeStringFragments          = 0,
+
+    CborPrettyDefaultFlags          = CborPrettyIndicateIndetermineLength
+};
+
+#endif /* __STDC_HOSTED__ check */
+
+#endif
diff --git a/ext/tinycbor/src/cbor_encoder_writer.h b/ext/tinycbor/src/cbor_encoder_writer.h
new file mode 100644
index 0000000..37fd399
--- /dev/null
+++ b/ext/tinycbor/src/cbor_encoder_writer.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_ENCODER_H
+#define CBOR_ENCODER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct cbor_encoder_writer;
+
+typedef int (cbor_encoder_write)(struct cbor_encoder_writer *, const char *data, int len);
+
+typedef struct cbor_encoder_writer {
+    cbor_encoder_write *write;
+    int                 bytes_written;
+} cbor_encoder_writer;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBOR_ENCODER_WRITER_H */
diff --git a/ext/tinycbor/src/cborencoder.c b/ext/tinycbor/src/cborencoder.c
new file mode 100644
index 0000000..de66cad
--- /dev/null
+++ b/ext/tinycbor/src/cborencoder.c
@@ -0,0 +1,627 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE 1
+#endif
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE 1
+#endif
+#ifndef __STDC_LIMIT_MACROS
+#  define __STDC_LIMIT_MACROS 1
+#endif
+
+#include "cbor.h"
+#include "cborinternal_p.h"
+#include "compilersupport_p.h"
+#include "cbor_buf_writer.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * \defgroup CborEncoding Encoding to CBOR
+ * \brief Group of functions used to encode data to CBOR.
+ *
+ * CborEncoder is used to encode data into a CBOR stream. The outermost
+ * CborEncoder is initialized by calling cbor_encoder_init(), with the buffer
+ * where the CBOR stream will be stored. The outermost CborEncoder is usually
+ * used to encode exactly one item, most often an array or map. It is possible
+ * to encode more than one item, but care must then be taken on the decoder
+ * side to ensure the state is reset after each item was decoded.
+ *
+ * Nested CborEncoder objects are created using cbor_encoder_create_array() and
+ * cbor_encoder_create_map(), later closed with cbor_encoder_close_container()
+ * or cbor_encoder_close_container_checked(). The pairs of creation and closing
+ * must be exactly matched and their parameters are always the same.
+ *
+ * CborEncoder writes directly to the user-supplied buffer, without extra
+ * buffering. CborEncoder does not allocate memory and CborEncoder objects are
+ * usually created on the stack of the encoding functions.
+ *
+ * The example below initializes a CborEncoder object with a buffer and encodes
+ * a single integer.
+ *
+ * \code
+ *      uint8_t buf[16];
+ *      CborEncoder encoder;
+ *      cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
+ *      cbor_encode_int(&encoder, some_value);
+ * \endcode
+ *
+ * As explained before, usually the outermost CborEncoder object is used to add
+ * one array or map, which in turn contains multiple elements. The example
+ * below creates a CBOR map with one element: a key "foo" and a boolean value.
+ *
+ * \code
+ *      uint8_t buf[16];
+ *      CborEncoder encoder, mapEncoder;
+ *      cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
+ *      cbor_encoder_create_map(&encoder, &mapEncoder, 1);
+ *      cbor_encode_text_stringz(&mapEncoder, "foo");
+ *      cbor_encode_boolean(&mapEncoder, some_value);
+ *      cbor_encoder_close_container(&encoder, &mapEncoder);
+ * \endcode
+ *
+ * <h3 class="groupheader">Error checking and buffer size</h2>
+ *
+ * All functions operating on CborEncoder return a condition of type CborError.
+ * If the encoding was successful, they return CborNoError. Some functions do
+ * extra checking on the input provided and may return some other error
+ * conditions (for example, cbor_encode_simple_value() checks that the type is
+ * of the correct type).
+ *
+ * In addition, all functions check whether the buffer has enough bytes to
+ * encode the item being appended. If that is not possible, they return
+ * CborErrorOutOfMemory.
+ *
+ * It is possible to continue with the encoding of data past the first function
+ * that returns CborErrorOutOfMemory. CborEncoder functions will not overrun
+ * the buffer, but will instead count how many more bytes are needed to
+ * complete the encoding. At the end, you can obtain that count by calling
+ * cbor_encoder_get_extra_bytes_needed().
+ *
+ * \section1 Finalizing the encoding
+ *
+ * Once all items have been appended and the containers have all been properly
+ * closed, the user-supplied buffer will contain the CBOR stream and may be
+ * immediately used. To obtain the size of the buffer, call
+ * cbor_encoder_get_buffer_size() with the original buffer pointer.
+ *
+ * The example below illustrates how one can encode an item with error checking
+ * and then pass on the buffer for network sending.
+ *
+ * \code
+ *      uint8_t buf[16];
+ *      CborError err;
+ *      CborEncoder encoder, mapEncoder;
+ *      cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
+ *      err = cbor_encoder_create_map(&encoder, &mapEncoder, 1);
+ *      if (!err)
+ *          return err;
+ *      err = cbor_encode_text_stringz(&mapEncoder, "foo");
+ *      if (!err)
+ *          return err;
+ *      err = cbor_encode_boolean(&mapEncoder, some_value);
+ *      if (!err)
+ *          return err;
+ *      err = cbor_encoder_close_container_checked(&encoder, &mapEncoder);
+ *      if (!err)
+ *          return err;
+ *
+ *      size_t len = cbor_encoder_get_buffer_size(&encoder, buf);
+ *      send_payload(buf, len);
+ *      return CborNoError;
+ * \endcode
+ *
+ * Finally, the example below illustrates expands on the one above and also
+ * deals with dynamically growing the buffer if the initial allocation wasn't
+ * big enough. Note the two places where the error checking was replaced with
+ * an cbor_assertion, showing where the author assumes no error can occur.
+ *
+ * \code
+ * uint8_t *encode_string_array(const char **strings, int n, size_t *bufsize)
+ * {
+ *     CborError err;
+ *     CborEncoder encoder, arrayEncoder;
+ *     size_t size = 256;
+ *     uint8_t *buf = NULL;
+ *
+ *     while (1) {
+ *         int i;
+ *         size_t more_bytes;
+ *         uint8_t *nbuf = realloc(buf, size);
+ *         if (nbuf == NULL)
+ *             goto error;
+ *         buf = nbuf;
+ *
+ *         cbor_encoder_init(&encoder, &buf, size, 0);
+ *         err = cbor_encoder_create_array(&encoder, &arrayEncoder, n);
+ *         cbor_assert(err);         // can't fail, the buffer is always big enough
+ *
+ *         for (i = 0; i < n; ++i) {
+ *             err = cbor_encode_text_stringz(&arrayEncoder, strings[i]);
+ *             if (err && err != CborErrorOutOfMemory)
+ *                 goto error;
+ *         }
+ *
+ *         err = cbor_encoder_close_container_checked(&encoder, &arrayEncoder);
+ *         cbor_assert(err);         // shouldn't fail!
+ *
+ *         more_bytes = cbor_encoder_get_extra_bytes_needed(encoder);
+ *         if (more_size) {
+ *             // buffer wasn't big enough, try again
+ *             size += more_bytes;
+ *             continue;
+ *         }
+ *
+ *         *bufsize = cbor_encoder_get_buffer_size(encoder, buf);
+ *         return buf;
+ *     }
+ *  error:
+ *     free(buf);
+ *     return NULL;
+ *  }
+ * \endcode
+ */
+
+/**
+ * \addtogroup CborEncoding
+ * @{
+ */
+
+/**
+ * \struct CborEncoder
+ * Structure used to encode to CBOR.
+ */
+
+#ifndef NO_DFLT_WRITER
+/**
+ * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a
+ * buffer of size \a size. The \a flags field is currently unused and must be
+ * zero.
+ */
+void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags)
+{
+    cbor_buf_writer_init(&encoder->wr, buffer, size);
+
+    cbor_encoder_cust_writer_init(encoder, &encoder->wr.enc, flags);
+}
+#endif
+
+/**
+ * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a
+ * buffer of size \a size. The \a flags field is currently unused and must be
+ * zero.
+ */
+void cbor_encoder_cust_writer_init(CborEncoder *encoder, struct cbor_encoder_writer *w, int flags)
+{
+    encoder->writer = w;
+    encoder->added = 0;
+    encoder->flags = flags;
+    encoder->container_size = 0;
+}
+
+
+#ifndef NO_FLOAT_SUPPORT
+static inline void put16(void *where, uint16_t v)
+{
+    v = cbor_htons(v);
+    memcpy(where, &v, sizeof(v));
+}
+#endif
+
+/* Note: Since this is currently only used in situations where OOM is the only
+ * valid error, we KNOW this to be true.  Thus, this function now returns just 'true',
+ * but if in the future, any function starts returning a non-OOM error, this will need
+ * to be changed to the test.  At the moment, this is done to prevent more branches
+ * being created in the tinycbor output */
+static inline bool isOomError(CborError err)
+{
+    (void) err;
+    return true;
+}
+
+#ifndef NO_FLOAT_SUPPORT
+static inline void put32(void *where, uint32_t v)
+{
+    v = cbor_htonl(v);
+    memcpy(where, &v, sizeof(v));
+}
+#endif
+
+static inline void put64(void *where, uint64_t v)
+{
+    v = cbor_htonll(v);
+    memcpy(where, &v, sizeof(v));
+}
+
+static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len)
+{
+    return (CborError)encoder->writer->write(encoder->writer, (const char *)data, len);
+}
+
+static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte)
+{
+    return append_to_buffer(encoder, &byte, 1);
+}
+
+static inline CborError encode_number_no_update(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
+{
+    /* Little-endian would have been so much more convenient here:
+     * We could just write at the beginning of buf but append_to_buffer
+     * only the necessary bytes.
+     * Since it has to be big endian, do it the other way around:
+     * write from the end. */
+    uint64_t buf[2];
+    uint8_t *const bufend = (uint8_t *)buf + sizeof(buf);
+    uint8_t *bufstart = bufend - 1;
+    put64(buf + 1, ui);     /* we probably have a bunch of zeros in the beginning */
+
+    if (ui < Value8Bit) {
+        *bufstart += shiftedMajorType;
+    } else {
+        uint8_t more = 0;
+        if (ui > 0xffU)
+            ++more;
+        if (ui > 0xffffU)
+            ++more;
+        if (ui > 0xffffffffU)
+            ++more;
+        bufstart -= (size_t)1 << more;
+        *bufstart = shiftedMajorType + Value8Bit + more;
+    }
+
+    return append_to_buffer(encoder, bufstart, bufend - bufstart);
+}
+
+static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
+{
+    ++encoder->added;
+    return encode_number_no_update(encoder, ui, shiftedMajorType);
+}
+
+/**
+ * Appends the unsigned 64-bit integer \a value to the CBOR stream provided by
+ * \a encoder.
+ *
+ * \sa cbor_encode_negative_int, cbor_encode_int
+ */
+CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
+{
+    return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
+}
+
+/**
+ * Appends the negative 64-bit integer whose absolute value is \a
+ * absolute_value to the CBOR stream provided by \a encoder.
+ *
+ * \sa cbor_encode_uint, cbor_encode_int
+ */
+CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value)
+{
+    return encode_number(encoder, absolute_value, NegativeIntegerType << MajorTypeShift);
+}
+
+/**
+ * Appends the signed 64-bit integer \a value to the CBOR stream provided by
+ * \a encoder.
+ *
+ * \sa cbor_encode_negative_int, cbor_encode_uint
+ */
+CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
+{
+    /* adapted from code in RFC 7049 appendix C (pseudocode) */
+    uint64_t ui = value >> 63;              /* extend sign to whole length */
+    uint8_t majorType = ui & 0x20;          /* extract major type */
+    ui ^= value;                            /* complement negatives */
+    return encode_number(encoder, ui, majorType);
+}
+
+/**
+ * Appends the CBOR Simple Type of value \a value to the CBOR stream provided by
+ * \a encoder.
+ *
+ * This function may return error CborErrorIllegalSimpleType if the \a value
+ * variable contains a number that is not a valid simple type.
+ */
+CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
+{
+#ifndef CBOR_ENCODER_NO_CHECK_USER
+    /* check if this is a valid simple type */
+    if (value >= HalfPrecisionFloat && value <= Break)
+        return CborErrorIllegalSimpleType;
+#endif
+    return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
+}
+
+#ifndef NO_FLOAT_SUPPORT
+/**
+ * Appends the floating-point value of type \a fpType and pointed to by \a
+ * value to the CBOR stream provided by \a encoder. The value of \a fpType must
+ * be one of CborHalfFloatType, CborFloatType or CborDoubleType, otherwise the
+ * behavior of this function is undefined.
+ *
+ * This function is useful for code that needs to pass through floating point
+ * values but does not wish to have the actual floating-point code.
+ *
+ * \sa cbor_encode_half_float, cbor_encode_float, cbor_encode_double
+ */
+CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value)
+{
+    uint8_t buf[1 + sizeof(uint64_t)];
+    cbor_assert(fpType == CborHalfFloatType || fpType == CborFloatType || fpType == CborDoubleType);
+    buf[0] = fpType;
+
+    unsigned size = 2U << (fpType - CborHalfFloatType);
+    if (size == 8)
+        put64(buf + 1, *(const uint64_t*)value);
+    else if (size == 4)
+        put32(buf + 1, *(const uint32_t*)value);
+    else
+        put16(buf + 1, *(const uint16_t*)value);
+    ++encoder->added;
+    return append_to_buffer(encoder, buf, size + 1);
+}
+#endif
+
+/**
+ * Appends the CBOR tag \a tag to the CBOR stream provided by \a encoder.
+ *
+ * \sa CborTag
+ */
+CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
+{
+    /* tags don't count towards the number of elements in an array or map */
+    return encode_number_no_update(encoder, tag, TagType << MajorTypeShift);
+}
+
+static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string)
+{
+    CborError err = encode_number(encoder, length, shiftedMajorType);
+    if (err && !isOomError(err))
+        return err;
+    return append_to_buffer(encoder, string, length);
+}
+
+/**
+ * \fn CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string)
+ *
+ * Appends the null-terminated text string \a string to the CBOR stream
+ * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
+ * TinyCBOR makes no verification of correctness. The terminating null is not
+ * included in the stream.
+ *
+ * \sa cbor_encode_text_string, cbor_encode_byte_string
+ */
+
+/**
+ * Appends the text string \a string of length \a length to the CBOR stream
+ * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
+ * TinyCBOR makes no verification of correctness.
+ *
+ * \sa CborError cbor_encode_text_stringz, cbor_encode_byte_string
+ */
+CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length)
+{
+    return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
+}
+
+/**
+ * Appends the byte string \a string of length \a length to the CBOR stream
+ * provided by \a encoder. CBOR byte strings are arbitrary raw data.
+ *
+ * \sa cbor_encode_text_stringz, cbor_encode_text_string
+ */
+CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
+{
+    return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
+}
+
+#ifdef __GNUC__
+__attribute__((noinline))
+#endif
+static CborError create_container(CborEncoder *encoder, CborEncoder *container, size_t length, uint8_t shiftedMajorType)
+{
+    CborError err;
+    container->writer = encoder->writer;
+    ++encoder->added;
+    container->added = 0;
+    container->container_size = length;
+
+    cbor_static_assert(((MapType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == CborIteratorFlag_ContainerIsMap);
+    cbor_static_assert(((ArrayType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == 0);
+    container->flags = shiftedMajorType & CborIteratorFlag_ContainerIsMap;
+
+    if (length == CborIndefiniteLength) {
+        container->flags |= CborIteratorFlag_UnknownLength;
+        err = append_byte_to_buffer(container, shiftedMajorType + IndefiniteLength);
+    } else {
+        err = encode_number_no_update(container, length, shiftedMajorType);
+    }
+    return err;
+}
+
+/**
+ * Creates a CBOR array in the CBOR stream provided by \a encoder and
+ * initializes \a arrayEncoder so that items can be added to the array using
+ * the CborEncoder functions. The array must be terminated by calling either
+ * cbor_encoder_close_container() or cbor_encoder_close_container_checked()
+ * with the same \a encoder and \a arrayEncoder parameters.
+ *
+ * The number of items inserted into the array must be exactly \a length items,
+ * otherwise the stream is invalid. If the number of items is not known when
+ * creating the array, the constant \ref CborIndefiniteLength may be passed as
+ * length instead.
+ *
+ * \sa cbor_encoder_create_map
+ */
+CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length)
+{
+    return create_container(encoder, arrayEncoder, length, ArrayType << MajorTypeShift);
+}
+
+/**
+ * Creates a CBOR map in the CBOR stream provided by \a encoder and
+ * initializes \a mapEncoder so that items can be added to the map using
+ * the CborEncoder functions. The map must be terminated by calling either
+ * cbor_encoder_close_container() or cbor_encoder_close_container_checked()
+ * with the same \a encoder and \a mapEncoder parameters.
+ *
+ * The number of pair of items inserted into the map must be exactly \a length
+ * items, otherwise the stream is invalid. If the number of items is not known
+ * when creating the map, the constant \ref CborIndefiniteLength may be passed as
+ * length instead.
+ *
+ * \b{Implementation limitation:} TinyCBOR cannot encode more than SIZE_MAX/2
+ * key-value pairs in the stream. If the length \a length is larger than this
+ * value, this function returns error CborErrorDataTooLarge.
+ *
+ * \sa cbor_encoder_create_array
+ */
+CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length)
+{
+    if (length != CborIndefiniteLength && length > SIZE_MAX / 2)
+        return CborErrorDataTooLarge;
+    return create_container(encoder, mapEncoder, length, MapType << MajorTypeShift);
+}
+
+/**
+ * Closes the CBOR container (array or map) provided by \a containerEncoder and
+ * updates the CBOR stream provided by \a encoder. Both parameters must be the
+ * same as were passed to cbor_encoder_create_array() or
+ * cbor_encoder_create_map().
+ *
+ * This function does not verify that the number of items (or pair of items, in
+ * the case of a map) was correct. To execute that verification, call
+ * cbor_encoder_close_container_checked() instead.
+ *
+ * \sa cbor_encoder_create_array(), cbor_encoder_create_map()
+ */
+CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder)
+{
+    size_t container_size;
+
+    encoder->writer = containerEncoder->writer;
+
+    if (containerEncoder->flags & CborIteratorFlag_UnknownLength) {
+        return append_byte_to_buffer(encoder, BreakByte);
+    } else {
+        container_size = containerEncoder->container_size;
+        if (containerEncoder->flags & CborIteratorFlag_ContainerIsMap) {
+            container_size = containerEncoder->container_size * 2;
+        }
+
+        return container_size == containerEncoder->added ? CborNoError :
+            container_size < containerEncoder->added ? CborErrorTooManyItems : CborErrorTooFewItems;
+    }
+}
+
+/**
+ * \fn CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
+ *
+ * Appends the boolean value \a value to the CBOR stream provided by \a encoder.
+ */
+
+/**
+ * \fn CborError cbor_encode_null(CborEncoder *encoder)
+ *
+ * Appends the CBOR type representing a null value to the CBOR stream provided
+ * by \a encoder.
+ *
+ * \sa cbor_encode_undefined()
+ */
+
+/**
+ * \fn CborError cbor_encode_undefined(CborEncoder *encoder)
+ *
+ * Appends the CBOR type representing an undefined value to the CBOR stream
+ * provided by \a encoder.
+ *
+ * \sa cbor_encode_null()
+ */
+
+/**
+ * \fn CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
+ *
+ * Appends the IEEE 754 half-precision (16-bit) floating point value pointed to
+ * by \a value to the CBOR stream provided by \a encoder.
+ *
+ * \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double()
+ */
+
+/**
+ * \fn CborError cbor_encode_float(CborEncoder *encoder, float value)
+ *
+ * Appends the IEEE 754 single-precision (32-bit) floating point value \a value
+ * to the CBOR stream provided by \a encoder.
+ *
+ * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_double()
+ */
+
+/**
+ * \fn CborError cbor_encode_double(CborEncoder *encoder, double value)
+ *
+ * Appends the IEEE 754 double-precision (64-bit) floating point value \a value
+ * to the CBOR stream provided by \a encoder.
+ *
+ * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float()
+ */
+
+/**
+ * \fn size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer)
+ *
+ * Returns the total size of the buffer starting at \a buffer after the
+ * encoding finished without errors. The \a encoder and \a buffer arguments
+ * must be the same as supplied to cbor_encoder_init().
+ *
+ * If the encoding process had errors, the return value of this function is
+ * meaningless. If the only errors were CborErrorOutOfMemory, instead use
+ * cbor_encoder_get_extra_bytes_needed() to find out by how much to grow the
+ * buffer before encoding again.
+ *
+ * See \ref CborEncoding for an example of using this function.
+ *
+ * \sa cbor_encoder_init(), cbor_encoder_get_extra_bytes_needed(), CborEncoding
+ */
+
+/**
+ * \fn size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder)
+ *
+ * Returns how many more bytes the original buffer supplied to
+ * cbor_encoder_init() needs to be extended by so that no CborErrorOutOfMemory
+ * condition will happen for the encoding. If the buffer was big enough, this
+ * function returns 0. The \a encoder must be the original argument as passed
+ * to cbor_encoder_init().
+ *
+ * This function is usually called after an encoding sequence ended with one or
+ * more CborErrorOutOfMemory errors, but no other error. If any other error
+ * happened, the return value of this function is meaningless.
+ *
+ * See \ref CborEncoding for an example of using this function.
+ *
+ * \sa cbor_encoder_init(), cbor_encoder_get_buffer_size(), CborEncoding
+ */
+
+/** @} */
diff --git a/ext/tinycbor/src/cborerrorstrings.c b/ext/tinycbor/src/cborerrorstrings.c
new file mode 100644
index 0000000..41319e4
--- /dev/null
+++ b/ext/tinycbor/src/cborerrorstrings.c
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#include "cbor_defs.h"
+#include "cbor.h"
+
+#ifndef _
+#  define _(msg)    msg
+#endif
+
+/**
+ * \enum CborError
+ * \ingroup CborGlobals
+ * The CborError enum contains the possible error values used by the CBOR encoder and decoder.
+ *
+ * TinyCBOR functions report success by returning CborNoError, or one error
+ * condition by returning one of the values below. One exception is the
+ * out-of-memory condition (CborErrorOutOfMemory), which the functions for \ref
+ * CborEncoding may report in bit-wise OR with other conditions.
+ *
+ * This technique allows code to determine whether the only error condition was
+ * a lack of buffer space, which may not be a fatal condition if the buffer can
+ * be resized. Additionally, the functions for \ref CborEncoding may continue
+ * to be used even after CborErrorOutOfMemory is returned, and instead they
+ * will simply calculate the extra space needed.
+ *
+ * \value CborNoError                   No error occurred
+ * \omitvalue CborUnknownError
+ * \value CborErrorUnknownLength        Request for the length of an array, map or string whose length is not provided in the CBOR stream
+ * \value CborErrorAdvancePastEOF       Not enough data in the stream to decode item (decoding would advance past end of stream)
+ * \value CborErrorIO                   An I/O error occurred, probably due to an out-of-memory situation
+ * \value CborErrorGarbageAtEnd         Bytes exist past the end of the CBOR stream
+ * \value CborErrorUnexpectedEOF        End of stream reached unexpectedly
+ * \value CborErrorUnexpectedBreak      A CBOR break byte was found where not expected
+ * \value CborErrorUnknownType          An unknown type (future extension to CBOR) was found in the stream
+ * \value CborErrorIllegalType          An invalid type was found while parsing a chunked CBOR string
+ * \value CborErrorIllegalNumber        An illegal initial byte (encoding unspecified additional information) was found
+ * \value CborErrorIllegalSimpleType    An illegal encoding of a CBOR Simple Type of value less than 32 was found
+ * \omitvalue CborErrorUnknownSimpleType
+ * \omitvalue CborErrorUnknownTag
+ * \omitvalue CborErrorInappropriateTagForType
+ * \omitvalue CborErrorDuplicateObjectKeys
+ * \value CborErrorInvalidUtf8TextString Illegal UTF-8 encoding found while parsing CBOR Text String
+ * \value CborErrorTooManyItems         Too many items were added to CBOR map or array of pre-determined length
+ * \value CborErrorTooFewItems          Too few items were added to CBOR map or array of pre-determeined length
+ * \value CborErrorDataTooLarge         Data item size exceeds TinyCBOR's implementation limits
+ * \value CborErrorNestingTooDeep       Data item nesting exceeds TinyCBOR's implementation limits
+ * \omitvalue CborErrorUnsupportedType
+ * \value CborErrorJsonObjectKeyIsAggregate Conversion to JSON failed because the key in a map is a CBOR map or array
+ * \value CborErrorJsonObjectKeyNotString Conversion to JSON failed because the key in a map is not a text string
+ * \value CborErrorOutOfMemory          During CBOR encoding, the buffer provided is insufficient for encoding the data item;
+ *                                      in other situations, TinyCBOR failed to allocate memory
+ * \value CborErrorInternalError        An internal error occurred in TinyCBOR
+ */
+
+/**
+ * \ingroup CborGlobals
+ * Returns the error string corresponding to the CBOR error condition \a error.
+ */
+const char *cbor_error_string(CborError error)
+{
+    switch (error) {
+    case CborNoError:
+        return "";
+
+    case CborUnknownError:
+        return _("unknown error");
+
+    case CborErrorOutOfMemory:
+        return _("out of memory/need more memory");
+
+    case CborErrorUnknownLength:
+        return _("unknown length (attempted to get the length of a map/array/string of indeterminate length");
+
+    case CborErrorAdvancePastEOF:
+        return _("attempted to advance past EOF");
+
+    case CborErrorIO:
+        return _("I/O error");
+
+    case CborErrorGarbageAtEnd:
+        return _("garbage after the end of the content");
+
+    case CborErrorUnexpectedEOF:
+        return _("unexpected end of data");
+
+    case CborErrorUnexpectedBreak:
+        return _("unexpected 'break' byte");
+
+    case CborErrorUnknownType:
+        return _("illegal byte (encodes future extension type)");
+
+    case CborErrorIllegalType:
+        return _("mismatched string type in chunked string");
+
+    case CborErrorIllegalNumber:
+        return _("illegal initial byte (encodes unspecified additional information)");
+
+    case CborErrorIllegalSimpleType:
+        return _("illegal encoding of simple type smaller than 32");
+
+    case CborErrorUnknownSimpleType:
+        return _("unknown simple type");
+
+    case CborErrorUnknownTag:
+        return _("unknown tag");
+
+    case CborErrorInappropriateTagForType:
+        return _("inappropriate tag for type");
+
+    case CborErrorDuplicateObjectKeys:
+        return _("duplicate keys in object");
+
+    case CborErrorInvalidUtf8TextString:
+        return _("invalid UTF-8 content in string");
+
+    case CborErrorExcludedType:
+        return _("excluded type found");
+
+    case CborErrorExcludedValue:
+        return _("excluded value found");
+
+    case CborErrorImproperValue:
+    case CborErrorOverlongEncoding:
+        return _("value encoded in non-canonical form");
+
+    case CborErrorMapKeyNotString:
+    case CborErrorJsonObjectKeyNotString:
+        return _("key in map is not a string");
+
+    case CborErrorMapNotSorted:
+        return _("map is not sorted");
+
+    case CborErrorMapKeysNotUnique:
+        return _("map keys are not unique");
+
+    case CborErrorTooManyItems:
+        return _("too many items added to encoder");
+
+    case CborErrorTooFewItems:
+        return _("too few items added to encoder");
+
+    case CborErrorDataTooLarge:
+        return _("internal error: data too large");
+
+    case CborErrorNestingTooDeep:
+        return _("internal error: too many nested containers found in recursive function");
+
+    case CborErrorUnsupportedType:
+        return _("unsupported type");
+
+    case CborErrorJsonObjectKeyIsAggregate:
+        return _("conversion to JSON failed: key in object is an array or map");
+
+    case CborErrorJsonNotImplemented:
+        return _("conversion to JSON failed: open_memstream unavailable");
+
+    case CborErrorInternalError:
+        return _("internal error");
+    }
+    return cbor_error_string(CborUnknownError);
+}
diff --git a/ext/tinycbor/src/cborinternal_p.h b/ext/tinycbor/src/cborinternal_p.h
new file mode 100644
index 0000000..ddeb2c2
--- /dev/null
+++ b/ext/tinycbor/src/cborinternal_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBORINTERNAL_P_H
+#define CBORINTERNAL_P_H
+
+#include "compilersupport_p.h"
+
+#ifndef CBOR_INTERNAL_API
+#  define CBOR_INTERNAL_API
+#endif
+
+#ifndef CBOR_PARSER_MAX_RECURSIONS
+#  define CBOR_PARSER_MAX_RECURSIONS 1024
+#endif
+
+/*
+ * CBOR Major types
+ * Encoded in the high 3 bits of the descriptor byte
+ * See http://tools.ietf.org/html/rfc7049#section-2.1
+ */
+typedef enum CborMajorTypes {
+    UnsignedIntegerType = 0U,
+    NegativeIntegerType = 1U,
+    ByteStringType = 2U,
+    TextStringType = 3U,
+    ArrayType = 4U,
+    MapType = 5U,           /* a.k.a. object */
+    TagType = 6U,
+    SimpleTypesType = 7U
+} CborMajorTypes;
+
+/*
+ * CBOR simple and floating point types
+ * Encoded in the low 8 bits of the descriptor byte when the
+ * Major Type is 7.
+ */
+typedef enum CborSimpleTypes {
+    FalseValue              = 20,
+    TrueValue               = 21,
+    NullValue               = 22,
+    UndefinedValue          = 23,
+    SimpleTypeInNextByte    = 24,   /* not really a simple type */
+    HalfPrecisionFloat      = 25,   /* ditto */
+    SinglePrecisionFloat    = 26,   /* ditto */
+    DoublePrecisionFloat    = 27,   /* ditto */
+    Break                   = 31
+} CborSimpleTypes;
+
+enum {
+    SmallValueBitLength     = 5U,
+    SmallValueMask          = (1U << SmallValueBitLength) - 1,      /* 31 */
+    Value8Bit               = 24U,
+    Value16Bit              = 25U,
+    Value32Bit              = 26U,
+    Value64Bit              = 27U,
+    IndefiniteLength        = 31U,
+
+    MajorTypeShift          = SmallValueBitLength,
+    MajorTypeMask           = (int) (~0U << MajorTypeShift),
+
+    BreakByte               = (unsigned)Break | (SimpleTypesType << MajorTypeShift)
+};
+
+CBOR_INTERNAL_API CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const CborParser *p, int *offset, uint64_t *len);
+CBOR_INTERNAL_API CBOR_INTERNAL_API_CC CborError _cbor_value_prepare_string_iteration(CborValue *it);
+
+#endif /* CBORINTERNAL_P_H */
diff --git a/ext/tinycbor/src/cborjson.h b/ext/tinycbor/src/cborjson.h
new file mode 100644
index 0000000..8ff27b9
--- /dev/null
+++ b/ext/tinycbor/src/cborjson.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBORJSON_H
+#define CBORJSON_H
+
+#include "cbor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Conversion to JSON */
+enum CborToJsonFlags
+{
+    CborConvertAddMetadata = 1,
+    CborConvertTagsToObjects = 2,
+    CborConvertIgnoreTags = 0,
+
+    CborConvertObeyByteStringTags = 0,
+    CborConvertByteStringsToBase64Url = 4,
+
+    CborConvertRequireMapStringKeys = 0,
+    CborConvertStringifyMapKeys = 8,
+
+    CborConvertDefaultFlags = 0
+};
+
+CBOR_API CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags);
+CBOR_INLINE_API CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags)
+{
+    CborValue copy = *value;
+    return cbor_value_to_json_advance(out, &copy, flags);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBORJSON_H */
+
diff --git a/ext/tinycbor/src/cborparser.c b/ext/tinycbor/src/cborparser.c
new file mode 100644
index 0000000..a796f67
--- /dev/null
+++ b/ext/tinycbor/src/cborparser.c
@@ -0,0 +1,1554 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE 1
+#endif
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE 1
+#endif
+#ifndef __STDC_LIMIT_MACROS
+#  define __STDC_LIMIT_MACROS 1
+#endif
+
+#include "cbor.h"
+#include "cborinternal_p.h"
+#include "compilersupport_p.h"
+
+#include <string.h>
+
+#include "cbor_buf_reader.h"
+
+#ifndef CBOR_PARSER_MAX_RECURSIONS
+#  define CBOR_PARSER_MAX_RECURSIONS 1024
+#endif
+
+/**
+ * \defgroup CborParsing Parsing CBOR streams
+ * \brief Group of functions used to parse CBOR streams.
+ *
+ * TinyCBOR provides functions for pull-based stream parsing of a CBOR-encoded
+ * payload. The main data type for the parsing is a CborValue, which behaves
+ * like an iterator and can be used to extract the encoded data. It is first
+ * initialized with a call to cbor_parser_init() and is usually used to extract
+ * exactly one item, most often an array or map.
+ *
+ * Nested CborValue objects can be parsed using cbor_value_enter_container().
+ * Each call to cbor_value_enter_container() must be matched by a call to
+ * cbor_value_leave_container(), with the exact same parameters.
+ *
+ * The example below initializes a CborParser object, begins the parsing with a
+ * CborValue and decodes a single integer:
+ *
+ * \code
+ * int extract_int(const uint8_t *buffer, size_t len)
+ * {
+ *     CborParser parser;
+ *     CborValue value;
+ *     int result;
+ *     cbor_parser_init(buffer, len, 0, &buffer, &value);
+ *     cbor_value_get_int(&value, &result);
+ *     return result;
+ * }
+ * \endcode
+ *
+ * The code above does no error checking, which means it assumes the data comes
+ * from a source trusted to send one properly-encoded integer. The following
+ * example does the exact same operation, but includes error parsing and
+ * returns 0 on parsing failure:
+ *
+ * \code
+ * int extract_int(const uint8_t *buffer, size_t len)
+ * {
+ *     CborParser parser;
+ *     CborValue value;
+ *     int result;
+ *     if (cbor_parser_init(buffer, len, 0, &buffer, &value) != CborNoError)
+ *         return 0;
+ *     if (!cbor_value_is_integer(&value) ||
+ *             cbor_value_get_int(&value, &result) != CborNoError)
+ *         return 0;
+ *     return result;
+ * }
+ * \endcode
+ *
+ * Note, in the example above, that one can't distinguish a parsing failure
+ * from an encoded value of zero. Reporting a parsing error is left as an
+ * exercise to the reader.
+ *
+ * The code above does not execute a range-check either: it is possible that
+ * the value decoded from the CBOR stream encodes a number larger than what can
+ * be represented in a variable of type \c{int}. If detecting that case is
+ * important, the code should call cbor_value_get_int_checked() instead.
+ *
+ * <h3 class="groupheader">Memory and parsing constraints</h3>
+ *
+ * TinyCBOR is designed to run with little memory and with minimal overhead.
+ * Except where otherwise noted, the parser functions always run on constant
+ * time (O(1)), do not recurse and never allocate memory (thus, stack usage is
+ * bounded and is O(1)).
+ *
+ * <h3 class="groupheader">Error handling and preconditions</h3>
+ *
+ * All functions operating on a CborValue return a CborError condition, with
+ * CborNoError standing for the normal situation in which no parsing error
+ * occurred. All functions may return parsing errors in case the stream cannot
+ * be decoded properly, be it due to corrupted data or due to reaching the end
+ * of the input buffer.
+ *
+ * Error conditions must not be ignored. All decoder functions have undefined
+ * behavior if called after an error has been reported, and may crash.
+ *
+ * Some functions are also documented to have preconditions, like
+ * cbor_value_get_int() requiring that the input be an integral value.
+ * Violation of preconditions also results in undefined behavior and the
+ * program may crash.
+ */
+
+/**
+ * \addtogroup CborParsing
+ * @{
+ */
+
+/**
+ * \struct CborValue
+ *
+ * This type contains one value parsed from the CBOR stream. Each CborValue
+ * behaves as an iterator in a StAX-style parser.
+ *
+ * \if privatedocs
+ * Implementation details: the CborValue contains these fields:
+ * \list
+ *   \li ptr: pointer to the actual data
+ *   \li flags: flags from the decoder
+ *   \li extra: partially decoded integer value (0, 1 or 2 bytes)
+ *   \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
+ * \endlist
+ * \endif
+ */
+
+CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const CborParser *p, int *offset, uint64_t *len)
+{
+    uint8_t additional_information = p->d->get8(p->d, *offset) & SmallValueMask;
+    ++*offset;
+    if (additional_information < Value8Bit) {
+        *len = additional_information;
+        return CborNoError;
+    }
+    if (unlikely(additional_information > Value64Bit))
+        return CborErrorIllegalNumber;
+
+    size_t bytesNeeded = (size_t)(1 << (additional_information - Value8Bit));
+    if (unlikely(bytesNeeded > (size_t)(p->end - *offset))) {
+        return CborErrorUnexpectedEOF;
+    } else if (bytesNeeded == 1) {
+        *len = p->d->get8(p->d, *offset);
+    } else if (bytesNeeded == 2) {
+        *len =  p->d->get16(p->d, *offset);
+    } else if (bytesNeeded == 4) {
+        *len =  p->d->get32(p->d, *offset);
+    } else {
+        *len =  p->d->get64(p->d, *offset);
+    }
+    *offset += bytesNeeded;
+    return CborNoError;
+}
+
+static CborError extract_length(const CborParser *parser,
+                                    int *offset, size_t *len)
+{
+    uint64_t v;
+    CborError err = _cbor_value_extract_number(parser, offset, &v);
+    if (err) {
+        *len = 0;
+        return err;
+    }
+
+    *len = (size_t)v;
+    if (v != *len)
+        return CborErrorDataTooLarge;
+    return CborNoError;
+}
+
+static bool is_fixed_type(uint8_t type)
+{
+    return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
+           type != CborMapType;
+}
+
+static CborError preparse_value(CborValue *it)
+{
+    const CborParser *parser = it->parser;
+    it->type = CborInvalidType;
+    /* are we at the end? */
+    if (it->offset == parser->end)
+        return CborErrorUnexpectedEOF;
+
+    uint8_t descriptor = parser->d->get8(parser->d, it->offset);
+    uint8_t type = descriptor & MajorTypeMask;
+    it->type = type;
+    it->flags = 0;
+    it->remainingclen = 0;
+    it->extra = (descriptor &= SmallValueMask);
+
+    size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
+
+    if (descriptor > Value64Bit) {
+        if (unlikely(descriptor != IndefiniteLength))
+            return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
+        if (likely(!is_fixed_type(type))) {
+            /* special case */
+            it->flags |= CborIteratorFlag_UnknownLength;
+            it->type = type;
+            return CborNoError;
+        }
+        return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
+    }
+
+    if (bytesNeeded + 1 > (size_t)(parser->end - it->offset))
+        return CborErrorUnexpectedEOF;
+
+    uint8_t majortype = type >> MajorTypeShift;
+    if (majortype == NegativeIntegerType) {
+        it->flags |= CborIteratorFlag_NegativeInteger;
+        it->type = CborIntegerType;
+    } else if (majortype == SimpleTypesType) {
+        switch (descriptor) {
+        case FalseValue:
+            it->extra = false;
+            it->type = CborBooleanType;
+            break;
+
+        case SinglePrecisionFloat:
+        case DoublePrecisionFloat:
+            it->flags |= CborIteratorFlag_IntegerValueTooLarge;
+            /* fall through */
+        case TrueValue:
+        case NullValue:
+        case UndefinedValue:
+        case HalfPrecisionFloat:
+            it->type = parser->d->get8(parser->d, it->offset);
+            break;
+
+        case SimpleTypeInNextByte:
+            it->extra = parser->d->get8(parser->d, it->offset + 1);
+#ifndef CBOR_PARSER_NO_STRICT_CHECKS
+            if (unlikely(it->extra < 32)) {
+                it->type = CborInvalidType;
+                return CborErrorIllegalSimpleType;
+            }
+#endif
+            break;
+
+        case 28:
+        case 29:
+        case 30:
+        case Break:
+            cbor_assert(false);  /* these conditions can't be reached */
+            return CborErrorUnexpectedBreak;
+        }
+        return CborNoError;
+    }
+
+    /* try to decode up to 16 bits */
+    if (descriptor < Value8Bit)
+        return CborNoError;
+
+    if (descriptor == Value8Bit)
+        it->extra = parser->d->get8(parser->d, it->offset + 1);
+    else if (descriptor == Value16Bit)
+        it->extra = parser->d->get16(parser->d, it->offset + 1);
+    else
+        it->flags |= CborIteratorFlag_IntegerValueTooLarge;     /* Value32Bit or Value64Bit */
+    return CborNoError;
+}
+
+static CborError preparse_next_value(CborValue *it)
+{
+    if (it->remaining != UINT32_MAX) {
+        /* don't decrement the item count if the current item is tag: they don't count */
+        if (it->type != CborTagType && !--it->remaining) {
+            it->type = CborInvalidType;
+            return CborNoError;
+        }
+    } else if (it->remaining == UINT32_MAX && it->offset != it->parser->end &&
+        it->parser->d->get8(it->parser->d, it->offset) == (uint8_t)BreakByte) {
+        /* end of map or array */
+        ++it->offset;
+        it->type = CborInvalidType;
+        it->remaining = 0;
+        return CborNoError;
+    }
+
+    return preparse_value(it);
+}
+
+static CborError advance_internal(CborValue *it)
+{
+    uint64_t length;
+    CborError err = _cbor_value_extract_number(it->parser, &it->offset,  &length);
+    cbor_assert(err == CborNoError);
+
+    if (it->type == CborByteStringType || it->type == CborTextStringType) {
+        cbor_assert(length == (size_t)length);
+        cbor_assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
+        it->offset += length;
+    }
+
+    return preparse_next_value(it);
+}
+
+/** \internal
+ *
+ * Decodes the CBOR integer value when it is larger than the 16 bits available
+ * in value->extra. This function requires that value->flags have the
+ * CborIteratorFlag_IntegerValueTooLarge flag set.
+ *
+ * This function is also used to extract single- and double-precision floating
+ * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
+ * Value64Bit).
+ */
+uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
+{
+    uint8_t val = value->parser->d->get8(value->parser->d, value->offset);
+
+    cbor_assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
+           value->type == CborFloatType || value->type == CborDoubleType);
+
+    /* since the additional information can only be Value32Bit or Value64Bit,
+     * we just need to test for the one bit those two options differ */
+    cbor_assert((val & SmallValueMask) == Value32Bit || (val & SmallValueMask) == Value64Bit);
+    if ((val & 1) == (Value32Bit & 1))
+        return value->parser->d->get32(value->parser->d, value->offset + 1);
+
+    cbor_assert((val & SmallValueMask) == Value64Bit);
+        return value->parser->d->get64(value->parser->d, value->offset + 1);
+}
+
+#ifndef NO_DFLT_READER
+/**
+ * Initializes the CBOR parser for parsing \a size bytes beginning at \a
+ * buffer. Parsing will use flags set in \a flags. The iterator to the first
+ * element is returned in \a it.
+ *
+ * The \a parser structure needs to remain valid throughout the decoding
+ * process. It is not thread-safe to share one CborParser among multiple
+ * threads iterating at the same time, but the object can be copied so multiple
+ * threads can iterate.
+ */
+CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
+{
+    memset(parser, 0, sizeof(*parser));
+
+    cbor_buf_reader_init(&parser->br, buffer, size);
+
+    return cbor_parser_cust_reader_init(&parser->br.r, flags, parser, it);
+}
+#endif
+
+/**
+ * Initializes the CBOR parser for parsing. It uses the \a decoder reader. Parsing will
+ * use flags set in \a flags. The iterator to the first element is returned in \a it.
+ *
+ * The \a parser structure needs to remain valid throughout the decoding
+ * process. It is not thread-safe to share one CborParser among multiple
+ * threads iterating at the same time, but the object can be copied so multiple
+ * threads can iterate.
+ */
+CborError cbor_parser_cust_reader_init(struct cbor_decoder_reader *r, int flags, CborParser *parser, CborValue *it)
+{
+    parser->d = r;
+    parser->end = r->message_size;
+    parser->flags = flags;
+    it->parser = parser;
+    it->offset = 0;
+    it->remaining = 1;/* there's one type altogether, usually an array or map */
+    return preparse_value(it);
+}
+
+/**
+ * \fn bool cbor_value_at_end(const CborValue *it)
+ *
+ * Returns true if \a it has reached the end of the iteration, usually when
+ * advancing after the last item in an array or map.
+ *
+ * In the case of the outermost CborValue object, this function returns true
+ * after decoding a single element. A pointer to the first byte of the
+ * remaining data (if any) can be obtained with cbor_value_get_next_byte().
+ *
+ * \sa cbor_value_advance(), cbor_value_is_valid(), cbor_value_get_next_byte()
+ */
+
+/**
+ * \fn const uint8_t *cbor_value_get_next_byte(const CborValue *it)
+ *
+ * Returns a pointer to the next byte that would be decoded if this CborValue
+ * object were advanced.
+ *
+ * This function is useful if cbor_value_at_end() returns true for the
+ * outermost CborValue: the pointer returned is the first byte of the data
+ * remaining in the buffer, if any. Code can decide whether to begin decoding a
+ * new CBOR data stream from this point, or parse some other data appended to
+ * the same buffer.
+ *
+ * This function may be used even after a parsing error. If that occurred,
+ * then this function returns a pointer to where the parsing error occurred.
+ * Note that the error recovery is not precise and the pointer may not indicate
+ * the exact byte containing bad data.
+ *
+ * \sa cbor_value_at_end()
+ */
+
+/**
+ * \fn bool cbor_value_is_valid(const CborValue *it)
+ *
+ * Returns true if the iterator \a it contains a valid value. Invalid iterators
+ * happen when iteration reaches the end of a container (see \ref
+ * cbor_value_at_end()) or when a search function resulted in no matches.
+ *
+ * \sa cbor_value_advance(), cbor_valie_at_end(), cbor_value_get_type()
+ */
+
+/**
+ * Performs a basic validation of the CBOR stream pointed by \a it and returns
+ * the error it found. If no error was found, it returns CborNoError and the
+ * application can iterate over the items with certainty that no other errors
+ * will appear during parsing.
+ *
+ * A basic validation checks for:
+ * \list
+ *   \li absence of undefined additional information bytes;
+ *   \li well-formedness of all numbers, lengths, and simple values;
+ *   \li string contents match reported sizes;
+ *   \li arrays and maps contain the number of elements they are reported to have;
+ * \endlist
+ *
+ * For further checks, see cbor_value_validate().
+ *
+ * This function has the same timing and memory requirements as
+ * cbor_value_advance().
+ *
+ * \sa cbor_value_validate(), cbor_value_advance()
+ */
+CborError cbor_value_validate_basic(const CborValue *it)
+{
+    CborValue value = *it;
+    return cbor_value_advance(&value);
+}
+
+/**
+ * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
+ * are: integers, tags, simple types (including boolean, null and undefined
+ * values) and floating point types.
+ *
+ * If the type is not of fixed size, this function has undefined behavior. Code
+ * must be sure that the current type is one of the fixed-size types before
+ * calling this function. This function is provided because it can guarantee
+ * that runs in constant time (O(1)).
+ *
+ * If the caller is not able to determine whether the type is fixed or not, code
+ * can use the cbor_value_advance() function instead.
+ *
+ * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_enter_container(), cbor_value_leave_container()
+ */
+CborError cbor_value_advance_fixed(CborValue *it)
+{
+    cbor_assert(it->type != CborInvalidType);
+    cbor_assert(is_fixed_type(it->type));
+    if (!it->remaining)
+        return CborErrorAdvancePastEOF;
+    return advance_internal(it);
+}
+
+static CborError advance_recursive(CborValue *it, int nestingLevel)
+{
+    if (is_fixed_type(it->type))
+        return advance_internal(it);
+
+    if (!cbor_value_is_container(it)) {
+        size_t len = SIZE_MAX;
+        return _cbor_value_copy_string(it, NULL, &len, it);
+    }
+
+    /* map or array */
+    if (nestingLevel == 0)
+        return CborErrorNestingTooDeep;
+
+    CborError err;
+    CborValue recursed;
+    err = cbor_value_enter_container(it, &recursed);
+    if (err)
+        return err;
+    while (!cbor_value_at_end(&recursed)) {
+        err = advance_recursive(&recursed, nestingLevel - 1);
+        if (err)
+            return err;
+    }
+    return cbor_value_leave_container(it, &recursed);
+}
+
+
+/**
+ * Advances the CBOR value \a it by one element, skipping over containers.
+ * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
+ * value of any type. However, if the type is a container (map or array) or a
+ * string with a chunked payload, this function will not run in constant time
+ * and will recurse into itself (it will run on O(n) time for the number of
+ * elements or chunks and will use O(n) memory for the number of nested
+ * containers).
+ *
+ * The number of recursions can be limited at compile time to avoid stack
+ * exhaustion in constrained systems.
+ *
+ * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_enter_container(), cbor_value_leave_container()
+ */
+CborError cbor_value_advance(CborValue *it)
+{
+    cbor_assert(it->type != CborInvalidType);
+    if (!it->remaining)
+        return CborErrorAdvancePastEOF;
+    return advance_recursive(it, CBOR_PARSER_MAX_RECURSIONS);
+}
+
+/**
+ * \fn bool cbor_value_is_tag(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR tag.
+ *
+ * \sa cbor_value_get_tag(), cbor_value_skip_tag()
+ */
+
+/**
+ * \fn CborError cbor_value_get_tag(const CborValue *value, CborTag *result)
+ *
+ * Retrieves the CBOR tag value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to a CBOR tag value, the
+ * behavior is undefined, so checking with \ref cbor_value_get_type or with
+ * \ref cbor_value_is_tag is recommended.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_tag()
+ */
+
+/**
+ * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
+ * already not pointing to a tag, then this function returns it unchanged.
+ *
+ * This function does not run in constant time: it will run on O(n) for n being
+ * the number of tags. It does use constant memory (O(1) memory requirements).
+ *
+ * \sa cbor_value_advance_fixed(), cbor_value_advance()
+ */
+CborError cbor_value_skip_tag(CborValue *it)
+{
+    while (cbor_value_is_tag(it)) {
+        CborError err = cbor_value_advance_fixed(it);
+        if (err)
+            return err;
+    }
+    return CborNoError;
+}
+
+/**
+ * \fn bool cbor_value_is_container(const CborValue *it)
+ *
+ * Returns true if the \a it value is a container and requires recursion in
+ * order to decode (maps and arrays), false otherwise.
+ */
+
+/**
+ * Creates a CborValue iterator pointing to the first element of the container
+ * represented by \a it and saves it in \a recursed. The \a it container object
+ * needs to be kept and passed again to cbor_value_leave_container() in order
+ * to continue iterating past this container.
+ *
+ * The \a it CborValue iterator must point to a container.
+ *
+ * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
+ */
+CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
+{
+    CborError err;
+    cbor_assert(cbor_value_is_container(it));
+    *recursed = *it;
+
+    if (it->flags & CborIteratorFlag_UnknownLength) {
+        recursed->remaining = UINT32_MAX;
+        ++recursed->offset;
+        err = preparse_value(recursed);
+        if (err != CborErrorUnexpectedBreak)
+            return err;
+        /* actually, break was expected here
+         * it's just an empty container */
+        ++recursed->offset;
+    } else {
+        uint64_t len;
+        err = _cbor_value_extract_number(recursed->parser, &recursed->offset, &len);
+        cbor_assert(err == CborNoError);
+
+        recursed->remaining = (uint32_t)len;
+        if (recursed->remaining != len || len == UINT32_MAX) {
+            /* back track the pointer to indicate where the error occurred */
+            recursed->offset = it->offset;
+            return CborErrorDataTooLarge;
+        }
+        if (recursed->type == CborMapType) {
+            /* maps have keys and values, so we need to multiply by 2 */
+            if (recursed->remaining > UINT32_MAX / 2) {
+                /* back track the pointer to indicate where the error occurred */
+                recursed->offset = it->offset;
+                return CborErrorDataTooLarge;
+            }
+            recursed->remaining *= 2;
+        }
+        if (len != 0)
+            return preparse_value(recursed);
+    }
+
+    /* the case of the empty container */
+    recursed->type = CborInvalidType;
+    recursed->remaining = 0;
+    return CborNoError;
+}
+
+/**
+ * Updates \a it to point to the next element after the container. The \a
+ * recursed object needs to point to the element obtained either by advancing
+ * the last element of the container (via cbor_value_advance(),
+ * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
+ * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
+ *
+ * The \a it and \a recursed parameters must be the exact same as passed to
+ * cbor_value_enter_container().
+ *
+ * \sa cbor_value_enter_container(), cbor_value_at_end()
+ */
+CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
+{
+    cbor_assert(cbor_value_is_container(it));
+    cbor_assert(recursed->type == CborInvalidType);
+    it->offset = recursed->offset;
+
+    return preparse_next_value(it);
+}
+
+
+/**
+ * \fn CborType cbor_value_get_type(const CborValue *value)
+ *
+ * Returns the type of the CBOR value that the iterator \a value points to. If
+ * \a value does not point to a valid value, this function returns \ref
+ * CborInvalidType.
+ *
+ * TinyCBOR also provides functions to test directly if a given CborValue object
+ * is of a given type, like cbor_value_is_text_string() and cbor_value_is_null().
+ *
+ * \sa cbor_value_is_valid()
+ */
+
+/**
+ * \fn bool cbor_value_is_null(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR null type.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_undefined()
+ */
+
+/**
+ * \fn bool cbor_value_is_undefined(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR undefined type.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_null()
+ */
+
+/**
+ * \fn bool cbor_value_is_boolean(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR boolean
+ * type (true or false).
+ *
+ * \sa cbor_value_is_valid(), cbor_value_get_boolean()
+ */
+
+/**
+ * \fn CborError cbor_value_get_boolean(const CborValue *value, bool *result)
+ *
+ * Retrieves the boolean value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to a boolean value, the
+ * behavior is undefined, so checking with \ref cbor_value_get_type or with
+ * \ref cbor_value_is_boolean is recommended.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_boolean()
+ */
+
+/**
+ * \fn bool cbor_value_is_simple_type(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR Simple Type
+ * type (other than true, false, null and undefined).
+ *
+ * \sa cbor_value_is_valid(), cbor_value_get_simple_type()
+ */
+
+/**
+ * \fn CborError cbor_value_get_simple_type(const CborValue *value, uint8_t *result)
+ *
+ * Retrieves the CBOR Simple Type value that \a value points to and stores it
+ * in \a result. If the iterator \a value does not point to a simple_type
+ * value, the behavior is undefined, so checking with \ref cbor_value_get_type
+ * or with \ref cbor_value_is_simple_type is recommended.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_simple_type()
+ */
+
+/**
+ * \fn bool cbor_value_is_integer(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR integer
+ * type.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_get_int, cbor_value_get_int64, cbor_value_get_uint64, cbor_value_get_raw_integer
+ */
+
+/**
+ * \fn bool cbor_value_is_unsigned_integer(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR unsigned
+ * integer type (positive values or zero).
+ *
+ * \sa cbor_value_is_valid(), cbor_value_get_uint64()
+ */
+
+/**
+ * \fn bool cbor_value_is_negative_integer(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR negative
+ * integer type.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_get_int, cbor_value_get_int64, cbor_value_get_raw_integer
+ */
+
+/**
+ * \fn CborError cbor_value_get_int(const CborValue *value, int *result)
+ *
+ * Retrieves the CBOR integer value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to an integer value, the
+ * behavior is undefined, so checking with \ref cbor_value_get_type or with
+ * \ref cbor_value_is_integer is recommended.
+ *
+ * Note that this function does not do range-checking: integral values that do
+ * not fit in a variable of type \c{int} are silently truncated to fit. Use
+ * cbor_value_get_int_checked() that is not acceptable.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer()
+ */
+
+/**
+ * \fn CborError cbor_value_get_int64(const CborValue *value, int64_t *result)
+ *
+ * Retrieves the CBOR integer value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to an integer value, the
+ * behavior is undefined, so checking with \ref cbor_value_get_type or with
+ * \ref cbor_value_is_integer is recommended.
+ *
+ * Note that this function does not do range-checking: integral values that do
+ * not fit in a variable of type \c{int64_t} are silently truncated to fit. Use
+ * cbor_value_get_int64_checked() that is not acceptable.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer()
+ */
+
+/**
+ * \fn CborError cbor_value_get_uint64(const CborValue *value, uint64_t *result)
+ *
+ * Retrieves the CBOR integer value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to an unsigned integer
+ * value, the behavior is undefined, so checking with \ref cbor_value_get_type
+ * or with \ref cbor_value_is_unsigned_integer is recommended.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_unsigned_integer()
+ */
+
+/**
+ * \fn CborError cbor_value_get_raw_integer(const CborValue *value, uint64_t *result)
+ *
+ * Retrieves the CBOR integer value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to an integer value, the
+ * behavior is undefined, so checking with \ref cbor_value_get_type or with
+ * \ref cbor_value_is_integer is recommended.
+ *
+ * This function is provided because CBOR negative integers can assume values
+ * that cannot be represented with normal 64-bit integer variables.
+ *
+ * If the integer is unsigned (that is, if cbor_value_is_unsigned_integer()
+ * returns true), then \a result will contain the actual value. If the integer
+ * is negative, then \a result will contain the absolute value of that integer,
+ * minus one. That is, \c {actual = -result - 1}. On architectures using two's
+ * complement for representation of negative integers, it is equivalent to say
+ * that \a result will contain the bitwise negation of the actual value.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer()
+ */
+
+/**
+ * Retrieves the CBOR integer value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to an integer value, the
+ * behavior is undefined, so checking with \ref cbor_value_get_type or with
+ * \ref cbor_value_is_integer is recommended.
+ *
+ * Unlike cbor_value_get_int64(), this function performs a check to see if the
+ * stored integer fits in \a result without data loss. If the number is outside
+ * the valid range for the data type, this function returns the recoverable
+ * error CborErrorDataTooLarge. In that case, use either
+ * cbor_value_get_uint64() (if the number is positive) or
+ * cbor_value_get_raw_integer().
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer(), cbor_value_get_int64()
+ */
+CborError cbor_value_get_int64_checked(const CborValue *value, int64_t *result)
+{
+    cbor_assert(cbor_value_is_integer(value));
+    uint64_t v = _cbor_value_extract_int64_helper(value);
+
+    /* Check before converting, as the standard says (C11 6.3.1.3 paragraph 3):
+     * "[if] the new type is signed and the value cannot be represented in it; either the
+     *  result is implementation-defined or an implementation-defined signal is raised."
+     *
+     * The range for int64_t is -2^63 to 2^63-1 (int64_t is required to be
+     * two's complement, C11 7.20.1.1 paragraph 3), which in CBOR is
+     * represented the same way, differing only on the "sign bit" (the major
+     * type).
+     */
+
+    if (unlikely(v > (uint64_t)INT64_MAX))
+        return CborErrorDataTooLarge;
+
+    *result = v;
+    if (value->flags & CborIteratorFlag_NegativeInteger)
+        *result = -*result - 1;
+    return CborNoError;
+}
+
+/**
+ * Retrieves the CBOR integer value that \a value points to and stores it in \a
+ * result. If the iterator \a value does not point to an integer value, the
+ * behavior is undefined, so checking with \ref cbor_value_get_type or with
+ * \ref cbor_value_is_integer is recommended.
+ *
+ * Unlike cbor_value_get_int(), this function performs a check to see if the
+ * stored integer fits in \a result without data loss. If the number is outside
+ * the valid range for the data type, this function returns the recoverable
+ * error CborErrorDataTooLarge. In that case, use one of the other integer
+ * functions to obtain the value.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer(), cbor_value_get_int64(),
+ *     cbor_value_get_uint64(), cbor_value_get_int64_checked(), cbor_value_get_raw_integer()
+ */
+CborError cbor_value_get_int_checked(const CborValue *value, int *result)
+{
+    cbor_assert(cbor_value_is_integer(value));
+    uint64_t v = _cbor_value_extract_int64_helper(value);
+
+    /* Check before converting, as the standard says (C11 6.3.1.3 paragraph 3):
+     * "[if] the new type is signed and the value cannot be represented in it; either the
+     *  result is implementation-defined or an implementation-defined signal is raised."
+     *
+     * But we can convert from signed to unsigned without fault (paragraph 2).
+     *
+     * The range for int is implementation-defined and int is not guaranteed use
+     * two's complement representation (int32_t is).
+     */
+
+    if (value->flags & CborIteratorFlag_NegativeInteger) {
+        if (unlikely(v > (unsigned) -(INT_MIN + 1)))
+            return CborErrorDataTooLarge;
+
+        *result = (int)v;
+        *result = -*result - 1;
+    } else {
+        if (unlikely(v > (uint64_t)INT_MAX))
+            return CborErrorDataTooLarge;
+
+        *result = (int)v;
+    }
+    return CborNoError;
+
+}
+
+/**
+ * \fn bool cbor_value_is_length_known(const CborValue *value)
+ *
+ * Returns true if the length of this type is known without calculation. That
+ * is, if the length of this CBOR string, map or array is encoded in the data
+ * stream, this function returns true. If the length is not encoded, it returns
+ * false.
+ *
+ * If the length is known, code can call cbor_value_get_string_length(),
+ * cbor_value_get_array_length() or cbor_value_get_map_length() to obtain the
+ * length. If the length is not known but is necessary, code can use the
+ * cbor_value_calculate_string_length() function (no equivalent function is
+ * provided for maps and arrays).
+ */
+
+/**
+ * \fn bool cbor_value_is_text_string(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR text
+ * string. CBOR text strings are UTF-8 encoded and usually contain
+ * human-readable text.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_get_string_length(), cbor_value_calculate_string_length(),
+ *     cbor_value_copy_text_string(), cbor_value_dup_text_string()
+ */
+
+/**
+ * \fn bool cbor_value_is_byte_string(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR text
+ * string. CBOR byte strings are binary data with no specified encoding or
+ * format.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_get_string_length(), cbor_value_calculate_string_length(),
+ *     cbor_value_copy_byte_string(), cbor_value_dup_byte_string()
+ */
+
+/**
+ * \fn CborError cbor_value_get_string_length(const CborValue *value, size_t *length)
+ *
+ * Extracts the length of the byte or text string that \a value points to and
+ * stores it in \a result. If the iterator \a value does not point to a text
+ * string or a byte string, the behaviour is undefined, so checking with \ref
+ * cbor_value_get_type, with \ref cbor_value_is_text_string or \ref
+ * cbor_value_is_byte_string is recommended.
+ *
+ * If the length of this string is not encoded in the CBOR data stream, this
+ * function will return the recoverable error CborErrorUnknownLength. You may
+ * also check whether that is the case by using cbor_value_is_length_known().
+ *
+ * If the length of the string is required but the length was not encoded, use
+ * cbor_value_calculate_string_length(), but note that that function does not
+ * run in constant time.
+ *
+ * \note On 32-bit platforms, this function will return error condition of \ref
+ * CborErrorDataTooLarge if the stream indicates a length that is too big to
+ * fit in 32-bit.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_length_known(), cbor_value_calculate_string_length()
+ */
+
+/**
+ * Calculates the length of the byte or text string that \a value points to and
+ * stores it in \a len. If the iterator \a value does not point to a text
+ * string or a byte string, the behaviour is undefined, so checking with \ref
+ * cbor_value_get_type, with \ref cbor_value_is_text_string or \ref
+ * cbor_value_is_byte_string is recommended.
+ *
+ * This function is different from cbor_value_get_string_length() in that it
+ * calculates the length even for strings sent in chunks. For that reason, this
+ * function may not run in constant time (it will run in O(n) time on the
+ * number of chunks). It does use constant memory (O(1)).
+ *
+ * \note On 32-bit platforms, this function will return error condition of \ref
+ * CborErrorDataTooLarge if the stream indicates a length that is too big to
+ * fit in 32-bit.
+ *
+ * \sa cbor_value_get_string_length(), cbor_value_copy_text_string(), cbor_value_copy_byte_string(), cbor_value_is_length_known()
+ */
+CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
+{
+    *len = SIZE_MAX;
+    return _cbor_value_copy_string(value, NULL, len, NULL);
+}
+
+static inline void prepare_string_iteration(CborValue *it)
+{
+    if (!cbor_value_is_length_known(it)) {
+        /* chunked string: we're before the first chunk;
+         * advance to the first chunk */
+        ++it->offset;
+        it->flags |= CborIteratorFlag_IteratingStringChunks;
+    }
+}
+
+CBOR_INTERNAL_API_CC CborError _cbor_value_prepare_string_iteration(CborValue *it)
+{
+    cbor_assert((it->flags & CborIteratorFlag_IteratingStringChunks) == 0);
+    prepare_string_iteration(it);
+
+    /* are we at the end? */
+    if (it->offset == it->parser->end)
+        return CborErrorUnexpectedEOF;
+
+    return CborNoError;
+}
+
+static const void *
+get_string_chunk_update(CborValue *it, const void **bufferptr, size_t *len)
+{
+    *bufferptr = (const void *)it->parser->d->get_string_chunk(it->parser->d,
+                 it->offset, len);
+    it->offset += *len;
+    it->remainingclen -= *len;
+
+    return *bufferptr;
+}
+
+static CborError get_string_chunk(CborValue *it, const void **bufferptr, size_t *len)
+{
+    CborError err;
+
+
+    if (it->remainingclen) {
+        *len = it->remainingclen;
+
+        *bufferptr = get_string_chunk_update(it, bufferptr, len);
+
+        return CborNoError;
+    }
+
+    /* Possible states:
+     * length known | iterating | meaning
+     *     no       |    no     | before the first chunk of a chunked string
+     *     yes      |    no     | at a non-chunked string
+     *     no       |    yes    | second or later chunk
+     *     yes      |    yes    | after a non-chunked string
+     */
+    if (it->flags & CborIteratorFlag_IteratingStringChunks) {
+        /* already iterating */
+        if (cbor_value_is_length_known(it)) {
+            /* if the length was known, it wasn't chunked, so finish iteration */
+            goto last_chunk;
+        }
+    } else {
+        prepare_string_iteration(it);
+    }
+
+    uint8_t val;
+
+    val = it->parser->d->get8(it->parser->d, it->offset);
+
+    /* are we at the end? */
+    if (it->offset == it->parser->end)
+        return CborErrorUnexpectedEOF;
+
+    if (val == (uint8_t)BreakByte) {
+        /* last chunk */
+        ++it->offset;
+last_chunk:
+        *bufferptr = NULL;
+        *len = 0;
+        it->remainingclen = 0;
+        return preparse_next_value(it);
+    } else if ((val & MajorTypeMask) == it->type) {
+        err = extract_length(it->parser, &it->offset, len);
+        if (err)
+            return err;
+
+        if (*len > (size_t)(it->parser->end - it->offset))
+            return CborErrorUnexpectedEOF;
+
+        it->remainingclen = *len;
+
+        *bufferptr = get_string_chunk_update(it, bufferptr, len);
+
+    } else {
+        return CborErrorIllegalType;
+    }
+
+    it->flags |= CborIteratorFlag_IteratingStringChunks;
+    return CborNoError;
+}
+
+/**
+ * \fn CborError cbor_value_get_text_string_chunk(const CborValue *value, const char **bufferptr, size_t *len, CborValue *next)
+ *
+ * Extracts one text string chunk pointed to by \a value and stores a pointer
+ * to the data in \a buffer and the size in \a len, which must not be null. If
+ * no more chunks are available, then \a bufferptr will be set to null. This
+ * function may be used to iterate over any string without causing its contents
+ * to be copied to a separate buffer, like the convenience function
+ * cbor_value_copy_text_string() does.
+ *
+ * It is designed to be used in code like:
+ *
+ * \code
+ *   if (cbor_value_is_text_string(value)) {
+ *       char *ptr;
+ *       size_t len;
+ *       while (1) {
+ *           err = cbor_value_get_text_string_chunk(value, &ptr, &len, &value));
+ *           if (err) return err;
+ *           if (ptr == NULL) return CborNoError;
+ *           consume(ptr, len);
+ *       }
+ *   }
+ * \endcode
+ *
+ * If the iterator \a value does not point to a text string, the behaviour is
+ * undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_text_string is recommended.
+ *
+ * The \a next pointer, if not null, will be updated to point to the next item
+ * after this string. During iteration, the pointer must only be passed back
+ * again to this function; passing it to any other function in this library
+ * results in undefined behavior. If there are no more chunks to be read from
+ * \a value, then \a next will be set to the next item after this string; if \a
+ * value points to the last item, then \a next will be invalid.
+ *
+ * \note This function does not perform UTF-8 validation on the incoming text
+ * string.
+ *
+ * \sa cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_caculate_string_length(), cbor_value_get_byte_string_chunk()
+ */
+
+/**
+ * \fn CborError cbor_value_get_byte_string_chunk(const CborValue *value, const char **bufferptr, size_t *len, CborValue *next)
+ *
+ * Extracts one byte string chunk pointed to by \a value and stores a pointer
+ * to the data in \a buffer and the size in \a len, which must not be null. If
+ * no more chunks are available, then \a bufferptr will be set to null. This
+ * function may be used to iterate over any string without causing its contents
+ * to be copied to a separate buffer, like the convenience function
+ * cbor_value_copy_byte_string() does.
+ *
+ * It is designed to be used in code like:
+ *
+ * \code
+ *   if (cbor_value_is_byte_string(value)) {
+ *       char *ptr;
+ *       size_t len;
+ *       while (1) {
+ *           err = cbor_value_get_byte_string_chunk(value, &ptr, &len, &value));
+ *           if (err) return err;
+ *           if (ptr == NULL) return CborNoError;
+ *           consume(ptr, len);
+ *       }
+ *   }
+ * \endcode
+ *
+ * If the iterator \a value does not point to a byte string, the behaviour is
+ * undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_byte_string is recommended.
+ *
+ * The \a next pointer, if not null, will be updated to point to the next item
+ * after this string. During iteration, the pointer must only be passed back
+ * again to this function; passing it to any other function in this library
+ * results in undefined behavior. If there are no more chunks to be read from
+ * \a value, then \a next will be set to the next item after this string; if \a
+ * value points to the last item, then \a next will be invalid.
+ *
+ * \sa cbor_value_dup_byte_string(), cbor_value_copy_byte_string(), cbor_value_caculate_string_length(), cbor_value_get_text_string_chunk()
+ */
+
+CborError _cbor_value_get_string_chunk(const CborValue *value, const void **bufferptr,
+                                                        size_t *len, CborValue *next)
+{
+    CborValue tmp;
+    if (!next)
+        next = &tmp;
+    *next = *value;
+
+    return get_string_chunk(next, bufferptr, len);
+}
+
+/* We return uintptr_t so that we can pass memcpy directly as the iteration
+ * function. The choice is to optimize for memcpy, which is used in the base
+ * parser API (cbor_value_copy_string), while memcmp is used in convenience API
+ * only. */
+typedef uintptr_t (*IterateFunction)(struct cbor_decoder_reader *d, char *dst, int src_offset, size_t len);
+
+static uintptr_t iterate_noop(struct cbor_decoder_reader *d, char *dst, int src_offset,  size_t len)
+{
+    (void)d;
+    (void)dst;
+    (void)src_offset;
+    (void)len;
+    return true;
+}
+
+static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
+                                       bool *result, CborValue *next, IterateFunction func)
+{
+    cbor_assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
+
+    CborError err;
+    CborValue tmp;
+    size_t total = 0;
+    const void *ptr;
+
+    if (!next)
+        next = &tmp;
+    *next = *value;
+    *result = true;
+
+    while (1) {
+        size_t newTotal;
+        size_t chunkLen = 0;
+        err = get_string_chunk(next, &ptr, &chunkLen);
+        if (err)
+            return err;
+        if (!ptr)
+            break;
+
+        if (unlikely(add_check_overflow(total, chunkLen, &newTotal)))
+            return CborErrorDataTooLarge;
+
+        if (*result && *buflen >= newTotal)
+            *result = !!func(value->parser->d, buffer + total, next->offset - chunkLen, chunkLen);
+        else
+            *result = false;
+
+        total = newTotal;
+    }
+
+    *buflen = total;
+
+    return CborNoError;
+}
+
+/**
+ * \fn CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, size_t *buflen, CborValue *next)
+ *
+ * Copies the string pointed by \a value into the buffer provided at \a buffer
+ * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
+ * copy anything and will only update the \a next value.
+ *
+ * If the iterator \a value does not point to a text string, the behaviour is
+ * undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_text_string is recommended.
+ *
+ * If the provided buffer length was too small, this function returns an error
+ * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
+ * of the string in order to preallocate a buffer, use
+ * cbor_value_calculate_string_length().
+ *
+ * On success, this function sets the number of bytes copied to \c{*buflen}. If
+ * the buffer is large enough, this function will insert a null byte after the
+ * last copied byte, to facilitate manipulation of text strings. That byte is
+ * not included in the returned value of \c{*buflen}.
+ *
+ * The \a next pointer, if not null, will be updated to point to the next item
+ * after this string. If \a value points to the last item, then \a next will be
+ * invalid.
+ *
+ * This function may not run in constant time (it will run in O(n) time on the
+ * number of chunks). It requires constant memory (O(1)).
+ *
+ * \note This function does not perform UTF-8 validation on the incoming text
+ * string.
+ *
+ * \sa cbor_value_get_text_string_chunk() cbor_value_dup_text_string(), cbor_value_copy_byte_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
+ */
+
+/**
+ * \fn CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, size_t *buflen, CborValue *next)
+ *
+ * Copies the string pointed by \a value into the buffer provided at \a buffer
+ * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
+ * copy anything and will only update the \a next value.
+ *
+ * If the iterator \a value does not point to a byte string, the behaviour is
+ * undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_byte_string is recommended.
+ *
+ * If the provided buffer length was too small, this function returns an error
+ * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
+ * of the string in order to preallocate a buffer, use
+ * cbor_value_calculate_string_length().
+ *
+ * On success, this function sets the number of bytes copied to \c{*buflen}. If
+ * the buffer is large enough, this function will insert a null byte after the
+ * last copied byte, to facilitate manipulation of null-terminated strings.
+ * That byte is not included in the returned value of \c{*buflen}.
+ *
+ * The \a next pointer, if not null, will be updated to point to the next item
+ * after this string. If \a value points to the last item, then \a next will be
+ * invalid.
+ *
+ * This function may not run in constant time (it will run in O(n) time on the
+ * number of chunks). It requires constant memory (O(1)).
+ *
+ * \sa cbor_value_get_byte_string_chunk(), cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
+ */
+
+CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
+                                 size_t *buflen, CborValue *next)
+{
+    bool copied_all;
+    CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next,
+                                          buffer ? (IterateFunction) value->parser->d->cpy : iterate_noop);
+    if (err) {
+        return err;
+    }
+
+    if (!copied_all) {
+        return CborErrorOutOfMemory;
+    }
+
+    if (buffer) {
+        *((uint8_t *)buffer + *buflen) = '\0';
+    }
+
+    return CborNoError;
+}
+
+/**
+ * Compares the entry \a value with the string \a string and store the result
+ * in \a result. If the value is different from \a string \a result will
+ * contain \c false.
+ *
+ * The entry at \a value may be a tagged string. If \a is not a string or a
+ * tagged string, the comparison result will be false.
+ *
+ * CBOR requires text strings to be encoded in UTF-8, but this function does
+ * not validate either the strings in the stream or the string \a string to be
+ * matched. Moreover, comparison is done on strict codepoint comparison,
+ * without any Unicode normalization.
+ *
+ * This function may not run in constant time (it will run in O(n) time on the
+ * number of chunks). It requires constant memory (O(1)).
+ *
+ * \sa cbor_value_skip_tag(), cbor_value_copy_text_string()
+ */
+CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
+{
+    CborValue copy = *value;
+    CborError err = cbor_value_skip_tag(&copy);
+
+    if (err)
+        return err;
+    if (!cbor_value_is_text_string(&copy)) {
+        *result = false;
+        return CborNoError;
+    }
+
+    size_t len = strlen(string);
+    err = iterate_string_chunks(&copy, CONST_CAST(char *, string), &len,
+                                result, NULL, value->parser->d->cmp);
+    if (err) {
+        return err;
+    }
+
+    if (*result && string[len] != '\0') {
+        *result = false;
+    }
+
+    return CborNoError;
+}
+
+/**
+ * \fn bool cbor_value_is_array(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR array.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_map()
+ */
+
+/**
+ * \fn CborError cbor_value_get_array_length(const CborValue *value, size_t *length)
+ *
+ * Extracts the length of the CBOR array that \a value points to and stores it
+ * in \a result. If the iterator \a value does not point to a CBOR array, the
+ * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_array is recommended.
+ *
+ * If the length of this array is not encoded in the CBOR data stream, this
+ * function will return the recoverable error CborErrorUnknownLength. You may
+ * also check whether that is the case by using cbor_value_is_length_known().
+ *
+ * \note On 32-bit platforms, this function will return error condition of \ref
+ * CborErrorDataTooLarge if the stream indicates a length that is too big to
+ * fit in 32-bit.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_length_known()
+ */
+
+/**
+ * \fn bool cbor_value_is_map(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR map.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_array()
+ */
+
+/**
+ * \fn CborError cbor_value_get_map_length(const CborValue *value, size_t *length)
+ *
+ * Extracts the length of the CBOR map that \a value points to and stores it in
+ * \a result. If the iterator \a value does not point to a CBOR map, the
+ * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_map is recommended.
+ *
+ * If the length of this map is not encoded in the CBOR data stream, this
+ * function will return the recoverable error CborErrorUnknownLength. You may
+ * also check whether that is the case by using cbor_value_is_length_known().
+ *
+ * \note On 32-bit platforms, this function will return error condition of \ref
+ * CborErrorDataTooLarge if the stream indicates a length that is too big to
+ * fit in 32-bit.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_length_known()
+ */
+
+/**
+ * Attempts to find the value in map \a map that corresponds to the text string
+ * entry \a string. If the iterator \a value does not point to a CBOR map, the
+ * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_map is recommended.
+ *
+ * If the item is found, it is stored in \a result. If no item is found
+ * matching the key, then \a result will contain an element of type \ref
+ * CborInvalidType. Matching is performed using
+ * cbor_value_text_string_equals(), so tagged strings will also match.
+ *
+ * This function has a time complexity of O(n) where n is the number of
+ * elements in the map to be searched. In addition, this function is has O(n)
+ * memory requirement based on the number of nested containers (maps or arrays)
+ * found as elements of this map.
+ *
+ * \sa cbor_value_is_valid(), cbor_value_text_string_equals(), cbor_value_advance()
+ */
+CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
+{
+    cbor_assert(cbor_value_is_map(map));
+    size_t len = strlen(string);
+    CborError err = cbor_value_enter_container(map, element);
+    if (err)
+        goto error;
+
+    while (!cbor_value_at_end(element)) {
+        /* find the non-tag so we can compare */
+        err = cbor_value_skip_tag(element);
+        if (err)
+            goto error;
+        if (cbor_value_is_text_string(element)) {
+            bool equals;
+            size_t dummyLen = len;
+            err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
+                                        &equals, element, map->parser->d->cmp);
+            if (err)
+                goto error;
+            if (equals && string[dummyLen] == '\0')
+                return preparse_value(element);
+        } else {
+            /* skip this key */
+            err = cbor_value_advance(element);
+            if (err)
+                goto error;
+        }
+
+        /* skip this value */
+        err = cbor_value_skip_tag(element);
+        if (err)
+            goto error;
+        err = cbor_value_advance(element);
+        if (err)
+            goto error;
+    }
+
+    /* not found */
+    element->type = CborInvalidType;
+    return CborNoError;
+
+error:
+    element->type = CborInvalidType;
+    return err;
+}
+
+/**
+ * \fn bool cbor_value_is_float(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR
+ * single-precision floating point (32-bit).
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_double(), cbor_value_is_half_float()
+ */
+
+/**
+ * \fn CborError cbor_value_get_float(const CborValue *value, float *result)
+ *
+ * Retrieves the CBOR single-precision floating point (32-bit) value that \a
+ * value points to and stores it in \a result. If the iterator \a value does
+ * not point to a single-precision floating point value, the behavior is
+ * undefined, so checking with \ref cbor_value_get_type or with \ref
+ * cbor_value_is_float is recommended.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_float(), cbor_value_get_double()
+ */
+
+/**
+ * \fn bool cbor_value_is_double(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR
+ * double-precision floating point (64-bit).
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_float(), cbor_value_is_half_float()
+ */
+
+/**
+ * \fn CborError cbor_value_get_double(const CborValue *value, float *result)
+ *
+ * Retrieves the CBOR double-precision floating point (64-bit) value that \a
+ * value points to and stores it in \a result. If the iterator \a value does
+ * not point to a double-precision floating point value, the behavior is
+ * undefined, so checking with \ref cbor_value_get_type or with \ref
+ * cbor_value_is_double is recommended.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_double(), cbor_value_get_float()
+ */
+
+/**
+ * \fn bool cbor_value_is_half_float(const CborValue *value)
+ *
+ * Returns true if the iterator \a value is valid and points to a CBOR
+ * single-precision floating point (16-bit).
+ *
+ * \sa cbor_value_is_valid(), cbor_value_is_double(), cbor_value_is_float()
+ */
+
+/**
+ * Retrieves the CBOR half-precision floating point (16-bit) value that \a
+ * value points to and stores it in \a result. If the iterator \a value does
+ * not point to a half-precision floating point value, the behavior is
+ * undefined, so checking with \ref cbor_value_get_type or with \ref
+ * cbor_value_is_half_float is recommended.
+ *
+ * Note: since the C language does not have a standard type for half-precision
+ * floating point, this function takes a \c{void *} as a parameter for the
+ * storage area, which must be at least 16 bits wide.
+ *
+ * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_float()
+ */
+CborError cbor_value_get_half_float(const CborValue *value, void *result)
+{
+    cbor_assert(cbor_value_is_half_float(value));
+
+    /* size has been computed already */
+    uint16_t v = value->parser->d->get16(value->parser->d, value->offset + 1);
+    memcpy(result, &v, sizeof(v));
+    return CborNoError;
+}
+
+
+/** @} */
diff --git a/ext/tinycbor/src/cborparser_dup_string.c b/ext/tinycbor/src/cborparser_dup_string.c
new file mode 100644
index 0000000..1fda05e
--- /dev/null
+++ b/ext/tinycbor/src/cborparser_dup_string.c
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE 1
+#endif
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE 1
+#endif
+#ifndef __STDC_LIMIT_MACROS
+#  define __STDC_LIMIT_MACROS 1
+#endif
+
+#include "cbor.h"
+#include <stdlib.h>
+#include "compilersupport_p.h"
+
+/**
+ * \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
+ *
+ * Allocates memory for the string pointed by \a value and copies it into this
+ * buffer. The pointer to the buffer is stored in \a buffer and the number of
+ * bytes copied is stored in \a len (those variables must not be NULL).
+ *
+ * If the iterator \a value does not point to a text string, the behaviour is
+ * undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_text_string is recommended.
+ *
+ * If \c malloc returns a NULL pointer, this function will return error
+ * condition \ref CborErrorOutOfMemory.
+ *
+ * On success, \c{*buffer} will contain a valid pointer that must be freed by
+ * calling \c{free()}. This is the case even for zero-length strings.
+ *
+ * The \a next pointer, if not null, will be updated to point to the next item
+ * after this string. If \a value points to the last item, then \a next will be
+ * invalid.
+ *
+ * This function may not run in constant time (it will run in O(n) time on the
+ * number of chunks). It requires constant memory (O(1)) in addition to the
+ * malloc'ed block.
+ *
+ * \note This function does not perform UTF-8 validation on the incoming text
+ * string.
+ *
+ * \sa cbor_value_get_text_string_chunk(), cbor_value_copy_text_string(), cbor_value_dup_byte_string()
+ */
+
+/**
+ * \fn CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, size_t *buflen, CborValue *next)
+ *
+ * Allocates memory for the string pointed by \a value and copies it into this
+ * buffer. The pointer to the buffer is stored in \a buffer and the number of
+ * bytes copied is stored in \a len (those variables must not be NULL).
+ *
+ * If the iterator \a value does not point to a byte string, the behaviour is
+ * undefined, so checking with \ref cbor_value_get_type or \ref
+ * cbor_value_is_byte_string is recommended.
+ *
+ * If \c malloc returns a NULL pointer, this function will return error
+ * condition \ref CborErrorOutOfMemory.
+ *
+ * On success, \c{*buffer} will contain a valid pointer that must be freed by
+ * calling \c{free()}. This is the case even for zero-length strings.
+ *
+ * The \a next pointer, if not null, will be updated to point to the next item
+ * after this string. If \a value points to the last item, then \a next will be
+ * invalid.
+ *
+ * This function may not run in constant time (it will run in O(n) time on the
+ * number of chunks). It requires constant memory (O(1)) in addition to the
+ * malloc'ed block.
+ *
+ * \sa cbor_value_get_text_string_chunk(), cbor_value_copy_byte_string(), cbor_value_dup_text_string()
+ */
+CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next)
+{
+    cbor_assert(buffer);
+    cbor_assert(buflen);
+    *buflen = SIZE_MAX;
+    CborError err = _cbor_value_copy_string(value, NULL, buflen, NULL);
+    if (err)
+        return err;
+
+    ++*buflen;
+    *buffer = malloc(*buflen);
+    if (!*buffer) {
+        /* out of memory */
+        return CborErrorOutOfMemory;
+    }
+    err = _cbor_value_copy_string(value, *buffer, buflen, next);
+    if (err) {
+        free(*buffer);
+        return err;
+    }
+    return CborNoError;
+}
diff --git a/ext/tinycbor/src/cborpretty.c b/ext/tinycbor/src/cborpretty.c
new file mode 100644
index 0000000..800d68c
--- /dev/null
+++ b/ext/tinycbor/src/cborpretty.c
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+#ifndef __STDC_LIMIT_MACROS
+#  define __STDC_LIMIT_MACROS 1
+#endif
+
+#include "cbor.h"
+#include "compilersupport_p.h"
+#include "cborinternal_p.h"
+#include "utf8_p.h"
+
+#include <float.h>
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+
+/**
+ * \defgroup CborPretty Converting CBOR to text
+ * \brief Group of functions used to convert CBOR to text form.
+ *
+ * This group contains two functions that are can be used to convert one
+ * CborValue object to a text representation. This module attempts to follow
+ * the recommendations from RFC 7049 section 6 "Diagnostic Notation", though it
+ * has a few differences. They are noted below.
+ *
+ * TinyCBOR does not provide a way to convert from the text representation back
+ * to encoded form. To produce a text form meant to be parsed, CborToJson is
+ * recommended instead.
+ *
+ * Either of the functions in this section will attempt to convert exactly one
+ * CborValue object to text. Those functions may return any error documented
+ * for the functions for CborParsing. In addition, if the C standard library
+ * stream functions return with error, the text conversion will return with
+ * error CborErrorIO.
+ *
+ * These functions also perform UTF-8 validation in CBOR text strings. If they
+ * encounter a sequence of bytes that not permitted in UTF-8, they will return
+ * CborErrorInvalidUtf8TextString. That includes encoding of surrogate points
+ * in UTF-8.
+ *
+ * \warning The output type produced by these functions is not guaranteed to
+ * remain stable. A future update of TinyCBOR may produce different output for
+ * the same input and parsers may be unable to handle them.
+ *
+ * \sa CborParsing, CborToJson, cbor_parser_init()
+ */
+
+/**
+ * \addtogroup CborPretty
+ * @{
+ * <h2 class="groupheader">Text format</h2>
+ *
+ * As described in RFC 7049 section 6 "Diagnostic Notation", the format is
+ * largely borrowed from JSON, but modified to suit CBOR's different data
+ * types. TinyCBOR makes further modifications to distinguish different, but
+ * similar values.
+ *
+ * CBOR values are currently encoded as follows:
+ * \par Integrals (unsigned and negative)
+ *      Base-10 (decimal) text representation of the value
+ * \par Byte strings:
+ *      <tt>"h'"</tt> followed by the Base16 (hex) representation of the binary data, followed by an ending quote (')
+ * \par Text strings:
+ *      C-style escaped string in quotes, with C11/C++11 escaping of Unicode codepoints above U+007F.
+ * \par Tags:
+ *      Tag value, with the tagged value in parentheses. No special encoding of the tagged value is performed.
+ * \par Simple types:
+ *      <tt>"simple(nn)"</tt> where \c nn is the simple value
+ * \par Null:
+ *      \c null
+ * \par Undefined:
+ *      \c undefined
+ * \par Booleans:
+ *      \c true or \c false
+ * \par Floating point:
+ *      If NaN or infinite, the actual words \c NaN or \c infinite.
+ *      Otherwise, the decimal representation with as many digits as necessary to ensure no loss of information.
+ *      By default, float values are suffixed by "f" and half-float values suffixed by "f16" (doubles have no suffix).
+ *      If the CborPrettyNumericEncodingIndicators flag is active, the values instead are encoded following the
+ *      Section 6 recommended encoding indicators: float values are suffixed with "_2" and half-float with "_1".
+ *      A dot is always present.
+ * \par Arrays:
+ *      Comma-separated list of elements, enclosed in square brackets ("[" and "]").
+ * \par Maps:
+ *      Comma-separated list of key-value pairs, with the key and value separated
+ *      by a colon (":"), enclosed in curly braces ("{" and "}").
+ *
+ * The CborPrettyFlags enumerator contains flags to control some aspects of the
+ * encoding:
+ * \par String fragmentation
+ *      When the CborPrettyShowStringFragments option is active, text and byte
+ *      strings that are transmitted in fragments are shown instead inside
+ *      parentheses ("(" and ")") with no preceding number and each fragment is
+ *      displayed individually. If a tag precedes the string, then the output
+ *      will contain a double set of parentheses. If the option is not active,
+ *      the fragments are merged together and the display will not show any
+ *      difference from a string transmitted with determinate length.
+ * \par Encoding indicators
+ *      Numbers and lengths in CBOR can be encoded in multiple representations.
+ *      If the CborPrettyIndicateOverlongNumbers option is active, numbers
+ *      and lengths that are transmitted in a longer encoding than necessary
+ *      will be indicated, by appending an underscore ("_") to either the
+ *      number or the opening bracket or brace, followed by a number
+ *      indicating the CBOR additional information: 0 for 1 byte, 1 for 2
+ *      bytes, 2 for 4 bytes and 3 for 8 bytes.
+ *      If the CborPrettyIndicateIndetermineLength option is active, maps,
+ *      arrays and strings encoded with indeterminate length will be marked by
+ *      an underscore after the opening bracket or brace or the string (if not
+ *      showing fragments), without a number after it.
+ */
+
+/**
+ * \enum CborPrettyFlags
+ * The CborPrettyFlags enum contains flags that control the conversion of CBOR to text format.
+ *
+ * \value CborPrettyNumericEncodingIndicators   Use numeric encoding indicators instead of textual for float and half-float.
+ * \value CborPrettyTextualEncodingIndicators   Use textual encoding indicators for float ("f") and half-float ("f16").
+ * \value CborPrettyIndicateIndetermineLength   Indicate when a map or array has indeterminate length.
+ * \value CborPrettyIndicateOverlongNumbers     Indicate when a number or length was encoded with more bytes than needed.
+ * \value CborPrettyShowStringFragments         If the byte or text string is transmitted in chunks, show each individually.
+ * \value CborPrettyMergeStringFragment         Merge all chunked byte or text strings and display them in a single entry.
+ * \value CborPrettyDefaultFlags       Default conversion flags.
+ */
+
+static void printRecursionLimit(CborStreamFunction stream, void *out)
+{
+    stream(out, "<nesting too deep, recursion stopped>");
+}
+
+static CborError hexDump(CborStreamFunction stream, void *out, const void *ptr, size_t n)
+{
+    const uint8_t *buffer = (const uint8_t *)ptr;
+    CborError err = CborNoError;
+    while (n-- && !err)
+        err = stream(out, "%02" PRIx8, *buffer++);
+
+    return err;
+}
+
+/* This function decodes buffer as UTF-8 and prints as escaped UTF-16.
+ * On UTF-8 decoding error, it returns CborErrorInvalidUtf8TextString */
+static CborError utf8EscapedDump(CborStreamFunction stream, void *out, const void *ptr, size_t n)
+{
+    const uint8_t *buffer = (const uint8_t *)ptr;
+    const uint8_t * const end = buffer + n;
+    CborError err = CborNoError;
+
+    while (buffer < end && !err) {
+        uint32_t uc = get_utf8(&buffer, end);
+        if (uc == ~0U)
+            return CborErrorInvalidUtf8TextString;
+
+        if (uc < 0x80) {
+            /* single-byte UTF-8 */
+            if (uc < 0x7f && uc >= 0x20 && uc != '\\' && uc != '"') {
+                err = stream(out, "%c", (char)uc);
+                continue;
+            }
+
+            /* print as an escape sequence */
+            char escaped = (char)uc;
+            switch (uc) {
+            case '"':
+            case '\\':
+                break;
+            case '\b':
+                escaped = 'b';
+                break;
+            case '\f':
+                escaped = 'f';
+                break;
+            case '\n':
+                escaped = 'n';
+                break;
+            case '\r':
+                escaped = 'r';
+                break;
+            case '\t':
+                escaped = 't';
+                break;
+            default:
+                goto print_utf16;
+            }
+            err = stream(out, "\\%c", escaped);
+            continue;
+        }
+
+        /* now print the sequence */
+        if (uc > 0xffffU) {
+            /* needs surrogate pairs */
+            err = stream(out, "\\u%04" PRIX32 "\\u%04" PRIX32,
+                         (uc >> 10) + 0xd7c0,    /* high surrogate */
+                         (uc % 0x0400) + 0xdc00);
+        } else {
+print_utf16:
+            /* no surrogate pair needed */
+            err = stream(out, "\\u%04" PRIX32, uc);
+        }
+    }
+    return err;
+}
+
+static const char *resolve_indicator(const CborValue *it, int flags)
+{
+    static const char indicators[8][3] = {
+        "_0", "_1", "_2", "_3",
+        "", "", "",             /* these are not possible */
+        "_"
+    };
+    const char *no_indicator = indicators[5];   /* empty string */
+    uint8_t additional_information;
+    uint8_t expected_information;
+    uint64_t value;
+    CborError err;
+    int offset;
+    uint8_t val;
+
+    if (it->offset == it->parser->end)
+        return NULL;    /* CborErrorUnexpectedEOF */
+
+    val = it->parser->d->get8(it->parser->d, it->offset);
+
+    additional_information = (val & SmallValueMask);
+    if (additional_information < Value8Bit)
+        return no_indicator;
+
+    /* determine whether to show anything */
+    if ((flags & CborPrettyIndicateIndetermineLength) &&
+            additional_information == IndefiniteLength)
+        return indicators[IndefiniteLength - Value8Bit];
+    if ((flags & CborPrettyIndicateOverlongNumbers) == 0)
+        return no_indicator;
+
+    offset = it->offset;
+
+    err = _cbor_value_extract_number(it->parser, &offset, &value);
+    if (err)
+        return NULL;    /* CborErrorUnexpectedEOF */
+
+    expected_information = Value8Bit - 1;
+    if (value >= Value8Bit)
+        ++expected_information;
+    if (value > 0xffU)
+        ++expected_information;
+    if (value > 0xffffU)
+        ++expected_information;
+    if (value > 0xffffffffU)
+        ++expected_information;
+    return expected_information == additional_information ?
+                no_indicator :
+                indicators[additional_information - Value8Bit];
+}
+
+static const char *get_indicator(const CborValue *it, int flags)
+{
+    return resolve_indicator(it, flags);
+}
+
+static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft);
+static CborError container_to_pretty(CborStreamFunction stream, void *out, CborValue *it, CborType containerType,
+                                     int flags, int recursionsLeft)
+{
+    if (!recursionsLeft) {
+        printRecursionLimit(stream, out);
+        return CborNoError; /* do allow the dumping to continue */
+    }
+
+    const char *comma = "";
+    CborError err = CborNoError;
+    while (!cbor_value_at_end(it) && !err) {
+        err = stream(out, "%s", comma);
+        comma = ", ";
+
+        if (!err)
+            err = value_to_pretty(stream, out, it, flags, recursionsLeft);
+
+        if (containerType == CborArrayType)
+            continue;
+
+        /* map: that was the key, so get the value */
+        if (!err)
+            err = stream(out, ": ");
+        if (!err)
+            err = value_to_pretty(stream, out, it, flags, recursionsLeft);
+    }
+    return err;
+}
+
+static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft)
+{
+    CborError err = CborNoError;
+    CborType type = cbor_value_get_type(it);
+    switch (type) {
+    case CborArrayType:
+    case CborMapType: {
+        /* recursive type */
+        CborValue recursed;
+        const char *indicator = get_indicator(it, flags);
+        const char *space = *indicator ? " " : indicator;
+
+        err = stream(out, "%c%s%s", type == CborArrayType ? '[' : '{', indicator, space);
+        if (err)
+            return err;
+
+        err = cbor_value_enter_container(it, &recursed);
+        if (err) {
+            it->offset = recursed.offset;
+            return err;       /* parse error */
+        }
+        err = container_to_pretty(stream, out, &recursed, type, flags, recursionsLeft - 1);
+        if (err) {
+            it->offset = recursed.offset;
+            return err;       /* parse error */
+        }
+        err = cbor_value_leave_container(it, &recursed);
+        if (err)
+            return err;       /* parse error */
+
+        return stream(out, type == CborArrayType ? "]" : "}");
+    }
+
+    case CborIntegerType: {
+        uint64_t val;
+        cbor_value_get_raw_integer(it, &val);    /* can't fail */
+
+        if (cbor_value_is_unsigned_integer(it)) {
+            err = stream(out, "%" PRIu64, val);
+        } else {
+            /* CBOR stores the negative number X as -1 - X
+             * (that is, -1 is stored as 0, -2 as 1 and so forth) */
+            if (++val) {                /* unsigned overflow may happen */
+                err = stream(out, "-%" PRIu64, val);
+            } else {
+                /* overflown
+                 *   0xffff`ffff`ffff`ffff + 1 =
+                 * 0x1`0000`0000`0000`0000 = 18446744073709551616 (2^64) */
+                err = stream(out, "-18446744073709551616");
+            }
+        }
+        if (!err)
+            err = stream(out, "%s", get_indicator(it, flags));
+        break;
+    }
+
+    case CborByteStringType:
+    case CborTextStringType: {
+        size_t n = 0;
+        const void *ptr;
+        bool showingFragments = (flags & CborPrettyShowStringFragments) && !cbor_value_is_length_known(it);
+        const char *separator = "";
+        char close = '\'';
+        char open[3] = "h'";
+        const char *indicator = NULL;
+
+        if (type == CborTextStringType) {
+            close = open[0] = '"';
+            open[1] = '\0';
+        }
+
+        if (showingFragments) {
+            err = stream(out, "(_ ");
+            if (!err)
+                err = _cbor_value_prepare_string_iteration(it);
+        } else {
+            err = stream(out, "%s", open);
+        }
+
+        while (!err) {
+            if (showingFragments || indicator == NULL) {
+                /* any iteration, except the second for a non-chunked string */
+                indicator = resolve_indicator(it, flags);
+            }
+
+            err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
+            if (!ptr)
+                break;
+
+            if (!err && showingFragments)
+                err = stream(out, "%s%s", separator, open);
+            if (!err)
+                err = (type == CborByteStringType ?
+                           hexDump(stream, out, ptr, n) :
+                           utf8EscapedDump(stream, out, ptr, n));
+            if (!err && showingFragments) {
+                err = stream(out, "%c%s", close, indicator);
+                separator = ", ";
+            }
+        }
+
+        if (!err) {
+            if (showingFragments)
+                err = stream(out, ")");
+            else
+                err = stream(out, "%c%s", close, indicator);
+        }
+        return err;
+    }
+
+    case CborTagType: {
+        CborTag tag;
+        cbor_value_get_tag(it, &tag);       /* can't fail */
+        err = stream(out, "%" PRIu64 "%s(", tag, get_indicator(it, flags));
+        if (!err)
+            err = cbor_value_advance_fixed(it);
+        if (!err && recursionsLeft)
+            err = value_to_pretty(stream, out, it, flags, recursionsLeft - 1);
+        else if (!err)
+            printRecursionLimit(stream, out);
+        if (!err)
+            err = stream(out, ")");
+        return err;
+    }
+
+    case CborSimpleType: {
+        /* simple types can't fail and can't have overlong encoding */
+        uint8_t simple_type;
+        cbor_value_get_simple_type(it, &simple_type);
+        err = stream(out, "simple(%" PRIu8 ")", simple_type);
+        break;
+    }
+
+    case CborNullType:
+        err = stream(out, "null");
+        break;
+
+    case CborUndefinedType:
+        err = stream(out, "undefined");
+        break;
+
+    case CborBooleanType: {
+        bool val;
+        cbor_value_get_boolean(it, &val);       /* can't fail */
+        err = stream(out, val ? "true" : "false");
+        break;
+    }
+#ifndef NO_FLOAT_SUPPORT
+    case CborDoubleType: {
+        const char *suffix;
+        double val;
+        int r;
+        if (false) {
+            float f;
+    case CborFloatType:
+            cbor_value_get_float(it, &f);
+            val = f;
+            suffix = flags & CborPrettyNumericEncodingIndicators ? "_2" : "f";
+        } else if (false) {
+            uint16_t f16;
+    case CborHalfFloatType:
+            cbor_value_get_half_float(it, &f16);
+            val = decode_half(f16);
+            suffix = flags & CborPrettyNumericEncodingIndicators ? "_1" : "f16";
+        } else {
+            cbor_value_get_double(it, &val);
+            suffix = "";
+        }
+
+        if ((flags & CborPrettyNumericEncodingIndicators) == 0) {
+            r = fpclassify(val);
+            if (r == FP_NAN || r == FP_INFINITE)
+                suffix = "";
+        }
+
+        uint64_t ival = (uint64_t)fabs(val);
+        if (ival == fabs(val)) {
+            /* this double value fits in a 64-bit integer, so show it as such
+             * (followed by a floating point suffix, to disambiguate) */
+            err = stream(out, "%s%" PRIu64 ".%s", val < 0 ? "-" : "", ival, suffix);
+        } else {
+            /* this number is definitely not a 64-bit integer */
+            err = stream(out, "%." DBL_DECIMAL_DIG_STR "g%s", val, suffix);
+        }
+        break;
+    }
+#endif
+    case CborInvalidType:
+        err = stream(out, "invalid");
+        if (err)
+            return err;
+    }
+
+    if (!err)
+        err = cbor_value_advance_fixed(it);
+    return err;
+}
+
+/**
+ * Converts the current CBOR type pointed by \a value to its textual
+ * representation and writes it to the stream by calling the \a streamFunction.
+ * If an error occurs, this function returns an error code similar to
+ * CborParsing.
+ *
+ * The textual representation can be controlled by the \a flags parameter (see
+ * CborPrettyFlags for more information).
+ *
+ * If no error ocurred, this function advances \a value to the next element.
+ * Often, concatenating the text representation of multiple elements can be
+ * done by appending a comma to the output stream.
+ *
+ * The \a streamFunction function will be called with the \a token value as the
+ * first parameter and a printf-style format string as the second, with a variable
+ * number of further parameters.
+ *
+ * \sa cbor_value_to_pretty(), cbor_value_to_json_advance()
+ */
+CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags)
+{
+    return value_to_pretty(streamFunction, token, value, flags, CBOR_PARSER_MAX_RECURSIONS);
+}
+
+/** @} */
diff --git a/ext/tinycbor/src/cborpretty_stdio.c b/ext/tinycbor/src/cborpretty_stdio.c
new file mode 100644
index 0000000..f905e86
--- /dev/null
+++ b/ext/tinycbor/src/cborpretty_stdio.c
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#include "cbor.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+static CborError cbor_fprintf(void *out, const char *fmt, ...)
+{
+    int n;
+
+    va_list list;
+    va_start(list, fmt);
+    n = vfprintf((FILE *)out, fmt, list);
+    va_end(list);
+
+    return n < 0 ? CborErrorIO : CborNoError;
+}
+
+/**
+ * \fn CborError cbor_value_to_pretty(FILE *out, const CborValue *value)
+ *
+ * Converts the current CBOR type pointed by \a value to its textual
+ * representation and writes it to the \a out stream. If an error occurs, this
+ * function returns an error code similar to CborParsing.
+ *
+ * \sa cbor_value_to_pretty_advance(), cbor_value_to_json_advance()
+ */
+
+/**
+ * Converts the current CBOR type pointed by \a value to its textual
+ * representation and writes it to the \a out stream. If an error occurs, this
+ * function returns an error code similar to CborParsing.
+ *
+ * If no error ocurred, this function advances \a value to the next element.
+ * Often, concatenating the text representation of multiple elements can be
+ * done by appending a comma to the output stream.
+ *
+ * \sa cbor_value_to_pretty(), cbor_value_to_pretty_stream(), cbor_value_to_json_advance()
+ */
+CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value)
+{
+    return cbor_value_to_pretty_stream(cbor_fprintf, out, value, CborPrettyDefaultFlags);
+}
+
+/**
+ * Converts the current CBOR type pointed by \a value to its textual
+ * representation and writes it to the \a out stream. If an error occurs, this
+ * function returns an error code similar to CborParsing.
+ *
+ * The textual representation can be controlled by the \a flags parameter (see
+ * CborPrettyFlags for more information).
+ *
+ * If no error ocurred, this function advances \a value to the next element.
+ * Often, concatenating the text representation of multiple elements can be
+ * done by appending a comma to the output stream.
+ *
+ * \sa cbor_value_to_pretty_stream(), cbor_value_to_pretty(), cbor_value_to_json_advance()
+ */
+CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags)
+{
+    return cbor_value_to_pretty_stream(cbor_fprintf, out, value, flags);
+}
+
diff --git a/ext/tinycbor/src/cbortojson.c b/ext/tinycbor/src/cbortojson.c
new file mode 100644
index 0000000..babb23d
--- /dev/null
+++ b/ext/tinycbor/src/cbortojson.c
@@ -0,0 +1,688 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+#define _GNU_SOURCE 1
+#define _POSIX_C_SOURCE 200809L
+#ifndef __STDC_LIMIT_MACROS
+#  define __STDC_LIMIT_MACROS 1
+#endif
+
+#include "cbor.h"
+#include "cborjson.h"
+#include "compilersupport_p.h"
+
+#include <float.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/**
+ * \defgroup CborToJson Converting CBOR to JSON
+ * \brief Group of functions used to convert CBOR to JSON.
+ *
+ * This group contains two functions that are can be used to convert one
+ * CborValue object to an equivalent JSON representation. This module attempts
+ * to follow the recommendations from RFC 7049 section 4.1 "Converting from
+ * CBOR to JSON", though it has a few differences. They are noted below.
+ *
+ * These functions produce a "minified" JSON output, with no spacing,
+ * indentation or line breaks. If those are necessary, they need to be applied
+ * in a post-processing phase.
+ *
+ * Note that JSON cannot support all CBOR types with fidelity, so the
+ * conversion is usually lossy. For that reason, TinyCBOR supports adding a set
+ * of metadata JSON values that can be used by a JSON-to-CBOR converter to
+ * restore the original data types.
+ *
+ * The TinyCBOR library does not provide a way to convert from JSON
+ * representation back to encoded form. However, it provides a tool called
+ * \c json2cbor which can be used for that purpose. That tool supports the
+ * metadata format that these functions may produce.
+ *
+ * Either of the functions in this section will attempt to convert exactly one
+ * CborValue object to JSON. Those functions may return any error documented
+ * for the functions for CborParsing. In addition, if the C standard library
+ * stream functions return with error, the text conversion will return with
+ * error CborErrorIO.
+ *
+ * These functions also perform UTF-8 validation in CBOR text strings. If they
+ * encounter a sequence of bytes that not permitted in UTF-8, they will return
+ * CborErrorInvalidUtf8TextString. That includes encoding of surrogate points
+ * in UTF-8.
+ *
+ * \warning The metadata produced by these functions is not guaranteed to
+ * remain stable. A future update of TinyCBOR may produce different output for
+ * the same input and parsers may be unable to handle them.
+ *
+ * \sa CborParsing, CborPretty, cbor_parser_init()
+ */
+
+/**
+ * \addtogroup CborToJson
+ * @{
+ * <h2 class="groupheader">Conversion limitations</h2>
+ *
+ * When converting from CBOR to JSON, there may be information loss. This
+ * section lists the possible scenarios.
+ *
+ * \par Number precision:
+ * ALL JSON numbers, due to its JavaScript heritage, are IEEE 754
+ * double-precision floating point. This means JSON is not capable of
+ * representing integers numbers outside the range [-(2<sup>53</sup>)+1,
+ * 2<sup>53</sup>-1] and is not capable of representing NaN or infinite. If the
+ * CBOR data contains a number outside the valid range, the conversion will
+ * lose precision. If the input was NaN or infinite, the result of the
+ * conversion will be "null". In addition, the distinction between half-,
+ * single- and double-precision is lost.
+ *
+ * \par
+ * If enabled, the original value and original type are stored in the metadata.
+ *
+ * \par Non-native types:
+ * CBOR's type system is richer than JSON's, which means some data values
+ * cannot be represented when converted to JSON. The conversion silently turns
+ * them into strings: CBOR simple types become "simple(nn)" where \c nn is the
+ * simple type's value, with the exception of CBOR undefined, which becomes
+ * "undefined", while CBOR byte strings are converted to an Base16, Base64, or
+ * Base64url encoding
+ *
+ * \par
+ * If enabled, the original type is stored in the metadata.
+ *
+ * \par Presence of tags:
+ * JSON has no support for tagged values, so by default tags are dropped when
+ * converting to JSON. However, if the CborConvertObeyByteStringTags option is
+ * active (default), then certain known tags are honored and are used to format
+ * the conversion of the tagged byte string to JSON.
+ *
+ * \par
+ * If the CborConvertTagsToObjects option is active, then the tag and the
+ * tagged value are converted to to a JSON object. Otherwise, if enabled, the
+ * last (innermost) tag is stored in the metadata.
+ *
+ * \par Non-string keys in maps:
+ * JSON requires all Object keys to be strings, while CBOR does not. By
+ * default, if a non-string key is found, the conversion fails with error
+ * CborErrorJsonObjectKeyNotString. If the CborConvertStringifyMapKeys option
+ * is active, then the conversion attempts to create a string representation
+ * using CborPretty. Note that the \c json2cbor tool is not able to parse this
+ * back to the original form.
+ *
+ * \par Duplicate keys in maps:
+ * Neither JSON nor CBOR allow duplicated keys, but current TinyCBOR does not
+ * validate that this is the case. If there are duplicated keys in the input,
+ * they will be repeated in the output, which may JSON tools may flag as
+ * invalid. In addition to that, if the CborConvertStringifyMapKeys option is
+ * active, it is possible that a non-string key in a CBOR map will be converted
+ * to a string form that is identical to another key.
+ *
+ * \par
+ * When metadata support is active, the conversion will add extra key-value
+ * pairs to the JSON output so it can store the metadata. It is possible that
+ * the keys for the metadata clash with existing keys in the JSON map.
+ */
+
+extern FILE *open_memstream(char **bufptr, size_t *sizeptr);
+
+enum ConversionStatusFlags {
+    TypeWasNotNative            = 0x100,    /* anything but strings, boolean, null, arrays and maps */
+    TypeWasTagged               = 0x200,
+    NumberPrecisionWasLost      = 0x400,
+    NumberWasNaN                = 0x800,
+    NumberWasInfinite           = 0x1000,
+    NumberWasNegative           = 0x2000,   /* always used with NumberWasInifite or NumberWasTooBig */
+
+    FinalTypeMask               = 0xff
+};
+
+typedef struct ConversionStatus {
+    CborTag lastTag;
+    uint64_t originalNumber;
+    int flags;
+} ConversionStatus;
+
+static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status);
+
+static CborError dump_bytestring_base16(char **result, CborValue *it)
+{
+    static const char characters[] = "0123456789abcdef";
+    size_t i;
+    size_t n = 0;
+    uint8_t *buffer;
+    CborError err = cbor_value_calculate_string_length(it, &n);
+    if (err)
+        return err;
+
+    /* a Base16 (hex) output is twice as big as our buffer */
+    buffer = (uint8_t *)malloc(n * 2 + 1);
+    *result = (char *)buffer;
+
+    /* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */
+    ++n;
+    err = cbor_value_copy_byte_string(it, buffer + n - 1, &n, it);
+    cbor_assert(err == CborNoError);
+
+    for (i = 0; i < n; ++i) {
+        uint8_t byte = buffer[n + i];
+        buffer[2*i]     = characters[byte >> 4];
+        buffer[2*i + 1] = characters[byte & 0xf];
+    }
+    return CborNoError;
+}
+
+static CborError generic_dump_base64(char **result, CborValue *it, const char alphabet[65])
+{
+    size_t n = 0, i;
+    uint8_t *buffer, *out, *in;
+    CborError err = cbor_value_calculate_string_length(it, &n);
+    if (err)
+        return err;
+
+    /* a Base64 output (untruncated) has 4 bytes for every 3 in the input */
+    size_t len = (n + 5) / 3 * 4;
+    out = buffer = (uint8_t *)malloc(len + 1);
+    *result = (char *)buffer;
+
+    /* we read our byte string at the tail end of the buffer
+     * so we can do an in-place conversion while iterating forwards */
+    in = buffer + len - n;
+
+    /* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */
+    ++n;
+    err = cbor_value_copy_byte_string(it, in, &n, it);
+    cbor_assert(err == CborNoError);
+
+    uint_least32_t val = 0;
+    for (i = 0; n - i >= 3; i += 3) {
+        /* read 3 bytes x 8 bits = 24 bits */
+        if (false) {
+#ifdef __GNUC__
+        } else if (i) {
+            __builtin_memcpy(&val, in + i - 1, sizeof(val));
+            val = cbor_ntohl(val);
+#endif
+        } else {
+            val = (in[i] << 16) | (in[i + 1] << 8) | in[i + 2];
+        }
+
+        /* write 4 chars x 6 bits = 24 bits */
+        *out++ = alphabet[(val >> 18) & 0x3f];
+        *out++ = alphabet[(val >> 12) & 0x3f];
+        *out++ = alphabet[(val >> 6) & 0x3f];
+        *out++ = alphabet[val & 0x3f];
+    }
+
+    /* maybe 1 or 2 bytes left */
+    if (n - i) {
+        /* we can read in[i + 1] even if it's past the end of the string because
+         * we know (by construction) that it's a NUL byte */
+#ifdef __GNUC__
+        uint16_t val16;
+        __builtin_memcpy(&val16, in + i, sizeof(val16));
+        val = cbor_ntohs(val16);
+#else
+        val = (in[i] << 8) | in[i + 1];
+#endif
+        val <<= 8;
+
+        /* the 65th character in the alphabet is our filler: either '=' or '\0' */
+        out[4] = '\0';
+        out[3] = alphabet[64];
+        if (n - i == 2) {
+            /* write the third char in 3 chars x 6 bits = 18 bits */
+            out[2] = alphabet[(val >> 6) & 0x3f];
+        } else {
+            out[2] = alphabet[64];  /* filler */
+        }
+        out[1] = alphabet[(val >> 12) & 0x3f];
+        out[0] = alphabet[(val >> 18) & 0x3f];
+    } else {
+        out[0] = '\0';
+    }
+
+    return CborNoError;
+}
+
+static CborError dump_bytestring_base64(char **result, CborValue *it)
+{
+    static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
+                                   "ghijklmn" "opqrstuv" "wxyz0123" "456789+/" "=";
+    return generic_dump_base64(result, it, alphabet);
+}
+
+static CborError dump_bytestring_base64url(char **result, CborValue *it)
+{
+    static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
+                                   "ghijklmn" "opqrstuv" "wxyz0123" "456789-_";
+    return generic_dump_base64(result, it, alphabet);
+}
+
+static CborError add_value_metadata(FILE *out, CborType type, const ConversionStatus *status)
+{
+    int flags = status->flags;
+    if (flags & TypeWasTagged) {
+        /* extract the tagged type, which may be JSON native */
+        type = flags & FinalTypeMask;
+        flags &= ~(FinalTypeMask | TypeWasTagged);
+
+        if (fprintf(out, "\"tag\":\"%" PRIu64 "\"%s", status->lastTag,
+                    flags & ~TypeWasTagged ? "," : "") < 0)
+            return CborErrorIO;
+    }
+
+    if (!flags)
+        return CborNoError;
+
+    /* print at least the type */
+    if (fprintf(out, "\"t\":%d", type) < 0)
+        return CborErrorIO;
+
+    if (flags & NumberWasNaN)
+        if (fprintf(out, ",\"v\":\"nan\"") < 0)
+            return CborErrorIO;
+    if (flags & NumberWasInfinite)
+        if (fprintf(out, ",\"v\":\"%sinf\"", flags & NumberWasNegative ? "-" : "") < 0)
+            return CborErrorIO;
+    if (flags & NumberPrecisionWasLost)
+        if (fprintf(out, ",\"v\":\"%c%" PRIx64 "\"", flags & NumberWasNegative ? '-' : '+',
+                    status->originalNumber) < 0)
+            return CborErrorIO;
+    if (type == CborSimpleType)
+        if (fprintf(out, ",\"v\":%d", (int)status->originalNumber) < 0)
+            return CborErrorIO;
+    return CborNoError;
+}
+
+static CborError find_tagged_type(CborValue *it, CborTag *tag, CborType *type)
+{
+    CborError err = CborNoError;
+    *type = cbor_value_get_type(it);
+    while (*type == CborTagType) {
+        cbor_value_get_tag(it, tag);    /* can't fail */
+        err = cbor_value_advance_fixed(it);
+        if (err)
+            return err;
+
+        *type = cbor_value_get_type(it);
+    }
+    return err;
+}
+
+static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
+{
+    CborTag tag;
+    CborError err;
+
+    if (flags & CborConvertTagsToObjects) {
+        cbor_value_get_tag(it, &tag);       /* can't fail */
+        err = cbor_value_advance_fixed(it);
+        if (err)
+            return err;
+
+        if (fprintf(out, "{\"tag%" PRIu64 "\":", tag) < 0)
+            return CborErrorIO;
+
+        CborType type = cbor_value_get_type(it);
+        err = value_to_json(out, it, flags, type, status);
+        if (err)
+            return err;
+        if (flags & CborConvertAddMetadata && status->flags) {
+            if (fprintf(out, ",\"tag%" PRIu64 "$cbor\":{", tag) < 0 ||
+                    add_value_metadata(out, type, status) != CborNoError ||
+                    fputc('}', out) < 0)
+                return CborErrorIO;
+        }
+        if (fputc('}', out) < 0)
+            return CborErrorIO;
+        status->flags = TypeWasNotNative | CborTagType;
+        return CborNoError;
+    }
+
+    CborType type;
+    err = find_tagged_type(it, &status->lastTag, &type);
+    if (err)
+        return err;
+    tag = status->lastTag;
+
+    /* special handling of byte strings? */
+    if (type == CborByteStringType && (flags & CborConvertByteStringsToBase64Url) == 0 &&
+            (tag == CborNegativeBignumTag || tag == CborExpectedBase16Tag || tag == CborExpectedBase64Tag)) {
+        char *str;
+        char *pre = "";
+
+        if (tag == CborNegativeBignumTag) {
+            pre = "~";
+            err = dump_bytestring_base64url(&str, it);
+        } else if (tag == CborExpectedBase64Tag) {
+            err = dump_bytestring_base64(&str, it);
+        } else { /* tag == CborExpectedBase16Tag */
+            err = dump_bytestring_base16(&str, it);
+        }
+        if (err)
+            return err;
+        err = fprintf(out, "\"%s%s\"", pre, str) < 0 ? CborErrorIO : CborNoError;
+        free(str);
+        status->flags = TypeWasNotNative | TypeWasTagged | CborByteStringType;
+        return err;
+    }
+
+    /* no special handling */
+    err = value_to_json(out, it, flags, type, status);
+    status->flags |= TypeWasTagged | type;
+    return err;
+}
+
+static CborError stringify_map_key(char **key, CborValue *it, int flags, CborType type)
+{
+    (void)flags;    /* unused */
+    (void)type;     /* unused */
+#ifdef WITHOUT_OPEN_MEMSTREAM
+    (void)key;      /* unused */
+    (void)it;       /* unused */
+    return CborErrorJsonNotImplemented;
+#else
+    size_t size;
+
+    FILE *memstream = open_memstream(key, &size);
+    if (memstream == NULL)
+        return CborErrorOutOfMemory;        /* could also be EMFILE, but it's unlikely */
+    CborError err = cbor_value_to_pretty_advance(memstream, it);
+
+    if (unlikely(fclose(memstream) < 0 || *key == NULL))
+        return CborErrorInternalError;
+    return err;
+#endif
+}
+
+static CborError array_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
+{
+    const char *comma = "";
+    while (!cbor_value_at_end(it)) {
+        if (fprintf(out, "%s", comma) < 0)
+            return CborErrorIO;
+        comma = ",";
+
+        CborError err = value_to_json(out, it, flags, cbor_value_get_type(it), status);
+        if (err)
+            return err;
+    }
+    return CborNoError;
+}
+
+static CborError map_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
+{
+    const char *comma = "";
+    CborError err;
+    while (!cbor_value_at_end(it)) {
+        char *key;
+        if (fprintf(out, "%s", comma) < 0)
+            return CborErrorIO;
+        comma = ",";
+
+        CborType keyType = cbor_value_get_type(it);
+        if (likely(keyType == CborTextStringType)) {
+            size_t n = 0;
+            err = cbor_value_dup_text_string(it, &key, &n, it);
+        } else if (flags & CborConvertStringifyMapKeys) {
+            err = stringify_map_key(&key, it, flags, keyType);
+        } else {
+            return CborErrorJsonObjectKeyNotString;
+        }
+        if (err)
+            return err;
+
+        /* first, print the key */
+        if (fprintf(out, "\"%s\":", key) < 0)
+            return CborErrorIO;
+
+        /* then, print the value */
+        CborType valueType = cbor_value_get_type(it);
+        err = value_to_json(out, it, flags, valueType, status);
+
+        /* finally, print any metadata we may have */
+        if (flags & CborConvertAddMetadata) {
+            if (!err && keyType != CborTextStringType) {
+                if (fprintf(out, ",\"%s$keycbordump\":true", key) < 0)
+                    err = CborErrorIO;
+            }
+            if (!err && status->flags) {
+                if (fprintf(out, ",\"%s$cbor\":{", key) < 0 ||
+                        add_value_metadata(out, valueType, status) != CborNoError ||
+                        fputc('}', out) < 0)
+                    err = CborErrorIO;
+            }
+        }
+
+        free(key);
+        if (err)
+            return err;
+    }
+    return CborNoError;
+}
+
+static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status)
+{
+    CborError err;
+    status->flags = 0;
+
+    switch (type) {
+    case CborArrayType:
+    case CborMapType: {
+        /* recursive type */
+        CborValue recursed;
+        err = cbor_value_enter_container(it, &recursed);
+        if (err) {
+            it->offset = recursed.offset;
+            return err;       /* parse error */
+        }
+        if (fputc(type == CborArrayType ? '[' : '{', out) < 0)
+            return CborErrorIO;
+
+        err = (type == CborArrayType) ?
+                  array_to_json(out, &recursed, flags, status) :
+                  map_to_json(out, &recursed, flags, status);
+        if (err) {
+            it->offset = recursed.offset;
+            return err;       /* parse error */
+        }
+
+        if (fputc(type == CborArrayType ? ']' : '}', out) < 0)
+            return CborErrorIO;
+        err = cbor_value_leave_container(it, &recursed);
+        if (err)
+            return err;       /* parse error */
+
+        status->flags = 0;    /* reset, there are never conversion errors for us */
+        return CborNoError;
+    }
+
+    case CborIntegerType: {
+        double num;     /* JS numbers are IEEE double precision */
+        uint64_t val;
+        cbor_value_get_raw_integer(it, &val);    /* can't fail */
+        num = (double)val;
+
+        if (cbor_value_is_negative_integer(it)) {
+            num = -num - 1;                     /* convert to negative */
+            if ((uint64_t)(-num - 1) != val) {
+                status->flags = NumberPrecisionWasLost | NumberWasNegative;
+                status->originalNumber = val;
+            }
+        } else {
+            if ((uint64_t)num != val) {
+                status->flags = NumberPrecisionWasLost;
+                status->originalNumber = val;
+            }
+        }
+        if (fprintf(out, "%.0f", num) < 0)  /* this number has no fraction, so no decimal points please */
+            return CborErrorIO;
+        break;
+    }
+
+    case CborByteStringType:
+    case CborTextStringType: {
+        char *str;
+        if (type == CborByteStringType) {
+            err = dump_bytestring_base64url(&str, it);
+            status->flags = TypeWasNotNative;
+        } else {
+            size_t n = 0;
+            err = cbor_value_dup_text_string(it, &str, &n, it);
+        }
+        if (err)
+            return err;
+        err = (fprintf(out, "\"%s\"", str) < 0) ? CborErrorIO : CborNoError;
+        free(str);
+        return err;
+    }
+
+    case CborTagType:
+        return tagged_value_to_json(out, it, flags, status);
+
+    case CborSimpleType: {
+        uint8_t simple_type;
+        cbor_value_get_simple_type(it, &simple_type);  /* can't fail */
+        status->flags = TypeWasNotNative;
+        status->originalNumber = simple_type;
+        if (fprintf(out, "\"simple(%" PRIu8 ")\"", simple_type) < 0)
+            return CborErrorIO;
+        break;
+    }
+
+    case CborNullType:
+        if (fprintf(out, "null") < 0)
+            return CborErrorIO;
+        break;
+
+    case CborUndefinedType:
+        status->flags = TypeWasNotNative;
+        if (fprintf(out, "\"undefined\"") < 0)
+            return CborErrorIO;
+        break;
+
+    case CborBooleanType: {
+        bool val;
+        cbor_value_get_boolean(it, &val);       /* can't fail */
+        if (fprintf(out, val ? "true" : "false") < 0)
+            return CborErrorIO;
+        break;
+    }
+#ifndef NO_FLOAT_SUPPORT
+    case CborDoubleType: {
+        double val;
+        if (false) {
+            float f;
+    case CborFloatType:
+            status->flags = TypeWasNotNative;
+            cbor_value_get_float(it, &f);
+            val = f;
+        } else if (false) {
+            uint16_t f16;
+    case CborHalfFloatType:
+            status->flags = TypeWasNotNative;
+            cbor_value_get_half_float(it, &f16);
+            val = decode_half(f16);
+        } else {
+            cbor_value_get_double(it, &val);
+        }
+
+        int r = fpclassify(val);
+        if (r == FP_NAN || r == FP_INFINITE) {
+            if (fprintf(out, "null") < 0)
+                return CborErrorIO;
+            status->flags |= r == FP_NAN ? NumberWasNaN :
+                                           NumberWasInfinite | (val < 0 ? NumberWasNegative : 0);
+        } else {
+            uint64_t ival = (uint64_t)fabs(val);
+            if ((double)ival == fabs(val)) {
+                /* print as integer so we get the full precision */
+                r = fprintf(out, "%s%" PRIu64, val < 0 ? "-" : "", ival);
+                status->flags |= TypeWasNotNative;   /* mark this integer number as a double */
+            } else {
+                /* this number is definitely not a 64-bit integer */
+                r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g", val);
+            }
+            if (r < 0)
+                return CborErrorIO;
+        }
+        break;
+    }
+#endif
+
+    case CborInvalidType:
+    default:
+        return CborErrorUnknownType;
+    }
+
+    return cbor_value_advance_fixed(it);
+}
+
+/**
+
+ * \enum CborToJsonFlags
+ * The CborToJsonFlags enum contains flags that control the conversion of CBOR to JSON.
+ *
+ * \value CborConvertAddMetadata        Adds metadata to facilitate restoration of the original CBOR data.
+ * \value CborConvertTagsToObjects      Converts CBOR tags to JSON objects
+ * \value CborConvertIgnoreTags         (default) Ignore CBOR tags, except for byte strings
+ * \value CborConvertObeyByteStringTags (default) Honor formatting of CBOR byte strings if so tagged
+ * \value CborConvertByteStringsToBase64Url Force the conversion of all CBOR byte strings to Base64url encoding, despite any tags
+ * \value CborConvertRequireMapStringKeys (default) Require CBOR map keys to be strings, failing the conversion if they are not
+ * \value CborConvertStringifyMapKeys   Convert non-string keys in CBOR maps to a string form
+ * \value CborConvertDefaultFlags       Default conversion flags.
+ */
+
+/**
+ * \fn CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags)
+ *
+ * Converts the current CBOR type pointed by \a value to JSON and writes that
+ * to the \a out stream. If an error occurs, this function returns an error
+ * code similar to CborParsing. The \a flags parameter indicates one of the
+ * flags from CborToJsonFlags that control the conversion.
+ *
+ * \sa cbor_value_to_json_advance(), cbor_value_to_pretty()
+ */
+
+/**
+ * Converts the current CBOR type pointed by \a value to JSON and writes that
+ * to the \a out stream. If an error occurs, this function returns an error
+ * code similar to CborParsing. The \a flags parameter indicates one of the
+ * flags from CborToJsonFlags that control the conversion.
+ *
+ * If no error ocurred, this function advances \a value to the next element.
+ *
+ * \sa cbor_value_to_json(), cbor_value_to_pretty_advance()
+ */
+CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags)
+{
+    ConversionStatus status;
+    return value_to_json(out, value, flags, cbor_value_get_type(value), &status);
+}
+
+/** @} */
diff --git a/ext/tinycbor/src/cborvalidation.c b/ext/tinycbor/src/cborvalidation.c
new file mode 100644
index 0000000..4d093e4
--- /dev/null
+++ b/ext/tinycbor/src/cborvalidation.c
@@ -0,0 +1,675 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE 1
+#endif
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE 1
+#endif
+#ifndef __STDC_LIMIT_MACROS
+#  define __STDC_LIMIT_MACROS 1
+#endif
+
+#include "cbor.h"
+#include "cborinternal_p.h"
+#include "compilersupport_p.h"
+#include "utf8_p.h"
+
+#include <string.h>
+
+#ifndef CBOR_NO_FLOATING_POINT
+#  include <float.h>
+#  include <math.h>
+#endif
+
+
+#ifndef CBOR_PARSER_MAX_RECURSIONS
+#  define CBOR_PARSER_MAX_RECURSIONS 1024
+#endif
+
+/**
+ * \addtogroup CborParsing
+ * @{
+ */
+
+/**
+ * \enum CborValidationFlags
+ * The CborValidationFlags enum contains flags that control the validation of a
+ * CBOR stream.
+ *
+ * \value CborValidateBasic         Validates only the syntax correctedness of the stream.
+ * \value CborValidateCanonical     Validates that the stream is in canonical format, according to
+ *                                  RFC 7049 section 3.9.
+ * \value CborValidateStrictMode    Performs strict validation, according to RFC 7049 section 3.10.
+ * \value CborValidateStrictest     Attempt to perform the strictest validation we know of.
+ *
+ * \value CborValidateShortestIntegrals     (Canonical) Validate that integral numbers and lengths are
+ *                                          enconded in their shortest form possible.
+ * \value CborValidateShortestFloatingPoint (Canonical) Validate that floating-point numbers are encoded
+ *                                          in their shortest form possible.
+ * \value CborValidateShortestNumbers       (Canonical) Validate both integrals and floating-point numbers
+ *                                          are in their shortest form possible.
+ * \value CborValidateNoIndeterminateLength (Canonical) Validate that no string, array or map uses
+ *                                          indeterminate length encoding.
+ * \value CborValidateMapIsSorted           (Canonical & Strict mode) Validate that map keys appear in
+ *                                          sorted order.
+ * \value CborValidateMapKeysAreUnique      (Strict mode) Validate that map keys are unique.
+ * \value CborValidateTagUse                (Strict mode) Validate that known tags are used with the
+ *                                          correct types. This does not validate that the content of
+ *                                          those types is syntactically correct.
+ * \value CborValidateUtf8                  (Strict mode) Validate that text strings are appropriately
+ *                                          encoded in UTF-8.
+ * \value CborValidateMapKeysAreString      Validate that all map keys are text strings.
+ * \value CborValidateNoUndefined           Validate that no elements of type "undefined" are present.
+ * \value CborValidateNoTags                Validate that no tags are used.
+ * \value CborValidateFiniteFloatingPoint   Validate that all floating point numbers are finite (no NaN or
+ *                                          infinities are allowed).
+ * \value CborValidateCompleteData          Validate that the stream is complete and there is no more data
+ *                                          in the buffer.
+ * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
+ *                                          with IANA.
+ * \value CborValidateNoUnknownSimpleTypes  Validate that all simple types used are registered with IANA.
+ * \value CborValidateNoUnknownTagsSA       Validate that all Standard Actions tags are registered with IANA.
+ * \value CborValidateNoUnknownTagsSR       Validate that all Standard Actions and Specification Required tags
+ *                                          are registered with IANA (see below for limitations).
+ * \value CborValidateNoUnkonwnTags         Validate that all tags are registered with IANA
+ *                                          (see below for limitations).
+ *
+ * \par Simple type registry
+ * The CBOR specification requires that registration for use of the first 19
+ * simple types must be done by way of Standards Action. The rest of the simple
+ * types only require a specification. The official list can be obtained from
+ *  https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml.
+ *
+ * \par
+ * There are no registered simple types recognized by this release of TinyCBOR
+ * (beyond those defined by RFC 7049).
+ *
+ * \par Tag registry
+ * The CBOR specification requires that registration for use of the first 23
+ * tags must be done by way of Standards Action. The next up to tag 255 only
+ * require a specification. Finally, all other tags can be registered on a
+ * first-come-first-serve basis. The official list can be ontained from
+ *  https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml.
+ *
+ * \par
+ * Given the variability of this list, TinyCBOR cannot recognize all tags
+ * registered with IANA. Instead, the implementation only recognizes tags
+ * that are backed by an RFC.
+ *
+ * \par
+ * These are the tags known to the current TinyCBOR release:
+<table>
+  <tr>
+    <th>Tag</th>
+    <th>Data Item</th>
+    <th>Semantics</th>
+  </tr>
+  <tr>
+    <td>0</td>
+    <td>UTF-8 text string</td>
+    <td>Standard date/time string</td>
+  </td>
+  <tr>
+    <td>1</td>
+    <td>integer</td>
+    <td>Epoch-based date/time</td>
+  </td>
+  <tr>
+    <td>2</td>
+    <td>byte string</td>
+    <td>Positive bignum</td>
+  </td>
+  <tr>
+    <td>3</td>
+    <td>byte string</td>
+    <td>Negative bignum</td>
+  </td>
+  <tr>
+    <td>4</td>
+    <td>array</td>
+    <td>Decimal fraction</td>
+  </td>
+  <tr>
+    <td>5</td>
+    <td>array</td>
+    <td>Bigfloat</td>
+  </td>
+  <tr>
+    <td>16</td>
+    <td>array</td>
+    <td>COSE Single Recipient Encrypted Data Object (RFC 8152)</td>
+  </td>
+  <tr>
+    <td>17</td>
+    <td>array</td>
+    <td>COSE Mac w/o Recipients Object (RFC 8152)</td>
+  </td>
+  <tr>
+    <td>18</td>
+    <td>array</td>
+    <td>COSE Single Signer Data Object (RFC 8162)</td>
+  </td>
+  <tr>
+    <td>21</td>
+    <td>byte string, array, map</td>
+    <td>Expected conversion to base64url encoding</td>
+  </td>
+  <tr>
+    <td>22</td>
+    <td>byte string, array, map</td>
+    <td>Expected conversion to base64 encoding</td>
+  </td>
+  <tr>
+    <td>23</td>
+    <td>byte string, array, map</td>
+    <td>Expected conversion to base16 encoding</td>
+  </td>
+  <tr>
+    <td>24</td>
+    <td>byte string</td>
+    <td>Encoded CBOR data item</td>
+  </td>
+  <tr>
+    <td>32</td>
+    <td>UTF-8 text string</td>
+    <td>URI</td>
+  </td>
+  <tr>
+    <td>33</td>
+    <td>UTF-8 text string</td>
+    <td>base64url</td>
+  </td>
+  <tr>
+    <td>34</td>
+    <td>UTF-8 text string</td>
+    <td>base64</td>
+  </td>
+  <tr>
+    <td>35</td>
+    <td>UTF-8 text string</td>
+    <td>Regular expression</td>
+  </td>
+  <tr>
+    <td>36</td>
+    <td>UTF-8 text string</td>
+    <td>MIME message</td>
+  </td>
+  <tr>
+    <td>96</td>
+    <td>array</td>
+    <td>COSE Encrypted Data Object (RFC 8152)</td>
+  </td>
+  <tr>
+    <td>97</td>
+    <td>array</td>
+    <td>COSE MACed Data Object (RFC 8152)</td>
+  </td>
+  <tr>
+    <td>98</td>
+    <td>array</td>
+    <td>COSE Signed Data Object (RFC 8152)</td>
+  </td>
+  <tr>
+    <td>55799</td>
+    <td>any</td>
+    <td>Self-describe CBOR</td>
+  </td>
+</table>
+ */
+
+struct KnownTagData { uint32_t tag; uint32_t types; };
+static const struct KnownTagData knownTagData[] = {
+    { 0, (uint8_t)CborTextStringType },
+    { 1, (uint8_t)(CborIntegerType+1) },
+    { 2, (uint8_t)CborByteStringType },
+    { 3, (uint8_t)CborByteStringType },
+    { 4, (uint8_t)CborArrayType },
+    { 5, (uint8_t)CborArrayType },
+    { 16, (uint8_t)CborArrayType },
+    { 17, (uint8_t)CborArrayType },
+    { 18, (uint8_t)CborArrayType },
+    { 21, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
+    { 22, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
+    { 23, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
+    { 24, (uint8_t)CborByteStringType },
+    { 32, (uint8_t)CborTextStringType },
+    { 33, (uint8_t)CborTextStringType },
+    { 34, (uint8_t)CborTextStringType },
+    { 35, (uint8_t)CborTextStringType },
+    { 36, (uint8_t)CborTextStringType },
+    { 96, (uint8_t)CborArrayType },
+    { 97, (uint8_t)CborArrayType },
+    { 98, (uint8_t)CborArrayType },
+    { 55799, 0U }
+};
+
+static CborError validate_value(CborValue *it, int flags, int recursionLeft);
+
+static inline CborError validate_utf8_string(const void *ptr, size_t n)
+{
+    const uint8_t *buffer = (const uint8_t *)ptr;
+    const uint8_t * const end = buffer + n;
+    while (buffer < end) {
+        uint32_t uc = get_utf8(&buffer, end);
+        if (uc == ~0U)
+            return CborErrorInvalidUtf8TextString;
+    }
+    return CborNoError;
+}
+
+static inline CborError validate_simple_type(uint8_t simple_type, int flags)
+{
+    /* At current time, all known simple types are those from RFC 7049,
+     * which are parsed by the parser into different CBOR types.
+     * That means that if we've got here, the type is unknown */
+    if (simple_type < 32)
+        return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError;
+    return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ?
+                CborErrorUnknownSimpleType : CborNoError;
+}
+
+static inline CborError validate_number(const CborValue *it, CborType type, int flags)
+{
+    CborError err = CborNoError;
+    uint64_t value;
+    int offset;
+
+    if ((flags & CborValidateShortestIntegrals) == 0)
+        return err;
+    if (type >= CborHalfFloatType && type <= CborDoubleType)
+        return err;     /* checked elsewhere */
+
+    offset = it->offset;
+    err = _cbor_value_extract_number(it->parser, &offset, &value);
+    if (err)
+        return err;
+
+    size_t bytesUsed = (size_t)(offset - it->offset - 1);
+    size_t bytesNeeded = 0;
+    if (value >= Value8Bit)
+        ++bytesNeeded;
+    if (value > 0xffU)
+        ++bytesNeeded;
+    if (value > 0xffffU)
+        bytesNeeded += 2;
+    if (value > 0xffffffffU)
+        bytesNeeded += 4;
+    if (bytesNeeded < bytesUsed)
+        return CborErrorOverlongEncoding;
+    return CborNoError;
+}
+
+static inline CborError validate_tag(CborValue *it, CborTag tag, int flags, int recursionLeft)
+{
+    CborType type = cbor_value_get_type(it);
+    const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
+    const struct KnownTagData *tagData = knownTagData;
+    const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
+
+    if (!recursionLeft)
+        return CborErrorNestingTooDeep;
+    if (flags & CborValidateNoTags)
+        return CborErrorExcludedType;
+
+    /* find the tag data, if any */
+    for ( ; tagData != knownTagDataEnd; ++tagData) {
+        if (tagData->tag < tag)
+            continue;
+        if (tagData->tag > tag)
+            tagData = NULL;
+        break;
+    }
+    if (tagData == knownTagDataEnd)
+        tagData = NULL;
+
+    if (flags & CborValidateNoUnknownTags && !tagData) {
+        /* tag not found */
+        if (flags & CborValidateNoUnknownTagsSA && tag < 24)
+            return CborErrorUnknownTag;
+        if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
+            return CborErrorUnknownTag;
+        if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
+            return CborErrorUnknownTag;
+    }
+
+    if (flags & CborValidateTagUse && tagData && tagData->types) {
+        uint32_t allowedTypes = tagData->types;
+
+        /* correct Integer so it's not zero */
+        if (type == CborIntegerType)
+            type = (CborType)(type + 1);
+
+        while (allowedTypes) {
+            if ((uint8_t)(allowedTypes & 0xff) == type)
+                break;
+            allowedTypes >>= 8;
+        }
+        if (!allowedTypes)
+            return CborErrorInappropriateTagForType;
+    }
+
+    return validate_value(it, flags, recursionLeft);
+}
+
+#ifndef CBOR_NO_FLOATING_POINT
+static inline CborError validate_floating_point(CborValue *it, CborType type, int flags)
+{
+    CborError err;
+    double val;
+    float valf;
+    uint16_t valf16;
+
+    if (type != CborDoubleType) {
+        if (type == CborFloatType) {
+            err = cbor_value_get_float(it, &valf);
+            val = valf;
+        } else {
+#  ifdef CBOR_NO_HALF_FLOAT_TYPE
+            (void)val16;
+            return CborErrorUnsupportedType;
+#  else
+            err = cbor_value_get_half_float(it, &valf16);
+            val = decode_half(valf16);
+#  endif
+        }
+    } else {
+        err = cbor_value_get_double(it, &val);
+    }
+    cbor_assert(err == CborNoError);     /* can't fail */
+
+    int r = fpclassify(val);
+    if (r == FP_NAN || r == FP_INFINITE) {
+        if (flags & CborValidateFiniteFloatingPoint)
+            return CborErrorExcludedValue;
+        if (flags & CborValidateShortestFloatingPoint) {
+            if (type == CborDoubleType)
+                return CborErrorOverlongEncoding;
+#  ifndef CBOR_NO_HALF_FLOAT_TYPE
+            if (type == CborFloatType)
+                return CborErrorOverlongEncoding;
+            if (r == FP_NAN && valf16 != 0x7e00)
+                return CborErrorImproperValue;
+            if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
+                return CborErrorImproperValue;
+#  endif
+        }
+    }
+
+    if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
+        if (type == CborDoubleType) {
+            valf = (float)val;
+            if ((double)valf == val)
+                return CborErrorOverlongEncoding;
+        }
+#  ifndef CBOR_NO_HALF_FLOAT_TYPE
+        if (type == CborFloatType) {
+            valf16 = encode_half(valf);
+            if (valf == decode_half(valf16))
+                return CborErrorOverlongEncoding;
+        }
+#  endif
+    }
+
+    return CborNoError;
+}
+#endif
+
+static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft)
+{
+    CborError err;
+    int previous = -1;
+    int previous_end;
+
+    if (!recursionLeft)
+        return CborErrorNestingTooDeep;
+
+    while (!cbor_value_at_end(it)) {
+        int current;
+
+        if (containerType == CborMapType) {
+            current = it->offset;
+            if (flags & CborValidateMapKeysAreString) {
+                CborType type = cbor_value_get_type(it);
+                if (type == CborTagType) {
+                    /* skip the tags */
+                    CborValue copy = *it;
+                    err = cbor_value_skip_tag(&copy);
+                    if (err)
+                        return err;
+                    type = cbor_value_get_type(&copy);
+                }
+                if (type != CborTextStringType)
+                    return CborErrorMapKeyNotString;
+            }
+        }
+
+        err = validate_value(it, flags, recursionLeft);
+        if (err)
+            return err;
+
+        if (containerType != CborMapType)
+            continue;
+
+        if (flags & CborValidateMapIsSorted) {
+            if (previous != -1) {
+                uint64_t len1, len2;
+                int offset;
+
+                /* extract the two lengths */
+                offset = previous;
+                _cbor_value_extract_number(it->parser, &offset, &len1);
+                offset = current;
+                _cbor_value_extract_number(it->parser, &offset, &len2);
+
+                if (len1 > len2)
+                    return CborErrorMapNotSorted;
+                if (len1 == len2) {
+                    int bytelen1 = (previous_end - previous);
+                    int bytelen2 = (it->offset - current);
+                    int i;
+
+                    for (i = 0; i < (bytelen1 <= bytelen2 ? bytelen1 : bytelen2); i++) {
+                        int r = it->parser->d->get8(it->parser->d, previous + i) -
+                            it->parser->d->get8(it->parser->d, current + i);
+
+                        if (r < 0) {
+                            break;
+                        }
+                        if (r == 0 && bytelen1 != bytelen2)
+                            r = bytelen1 < bytelen2 ? -1 : +1;
+                        if (r > 0)
+                            return CborErrorMapNotSorted;
+                        if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique)
+                            return CborErrorMapKeysNotUnique;
+                    }
+                }
+            }
+
+            previous = current;
+            previous_end = it->offset;
+        }
+
+        /* map: that was the key, so get the value */
+        err = validate_value(it, flags, recursionLeft);
+        if (err)
+            return err;
+    }
+    return CborNoError;
+}
+
+static CborError validate_value(CborValue *it, int flags, int recursionLeft)
+{
+    CborError err;
+    CborType type = cbor_value_get_type(it);
+
+    if (cbor_value_is_length_known(it)) {
+        err = validate_number(it, type, flags);
+        if (err)
+            return err;
+    } else {
+        if (flags & CborValidateNoIndeterminateLength)
+            return CborErrorUnknownLength;
+    }
+
+    switch (type) {
+    case CborArrayType:
+    case CborMapType: {
+        /* recursive type */
+        CborValue recursed;
+        err = cbor_value_enter_container(it, &recursed);
+        if (!err)
+            err = validate_container(&recursed, type, flags, recursionLeft - 1);
+        if (err) {
+            it->offset = recursed.offset;
+            return err;
+        }
+        err = cbor_value_leave_container(it, &recursed);
+        if (err)
+            return err;
+        return CborNoError;
+    }
+
+    case CborIntegerType: {
+        uint64_t val;
+        err = cbor_value_get_raw_integer(it, &val);
+        cbor_assert(err == CborNoError);         /* can't fail */
+
+        break;
+    }
+
+    case CborByteStringType:
+    case CborTextStringType: {
+        size_t n = 0;
+        const void *ptr;
+
+        err = _cbor_value_prepare_string_iteration(it);
+        if (err)
+            return err;
+
+        while (1) {
+            err = validate_number(it, type, flags);
+            if (err)
+                return err;
+
+            err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
+            if (err)
+                return err;
+            if (!ptr)
+                break;
+
+            if (type == CborTextStringType && flags & CborValidateUtf8) {
+                err = validate_utf8_string(ptr, n);
+                if (err)
+                    return err;
+            }
+        }
+
+        return CborNoError;
+    }
+
+    case CborTagType: {
+        CborTag tag;
+        err = cbor_value_get_tag(it, &tag);
+        cbor_assert(err == CborNoError);     /* can't fail */
+
+        err = cbor_value_advance_fixed(it);
+        if (err)
+            return err;
+        err = validate_tag(it, tag, flags, recursionLeft - 1);
+        if (err)
+            return err;
+
+        return CborNoError;
+    }
+
+    case CborSimpleType: {
+        uint8_t simple_type;
+        err = cbor_value_get_simple_type(it, &simple_type);
+        cbor_assert(err == CborNoError);     /* can't fail */
+        err = validate_simple_type(simple_type, flags);
+        if (err)
+            return err;
+        break;
+    }
+
+    case CborNullType:
+    case CborBooleanType:
+        break;
+
+    case CborUndefinedType:
+        if (flags & CborValidateNoUndefined)
+            return CborErrorExcludedType;
+        break;
+
+    case CborHalfFloatType:
+    case CborFloatType:
+    case CborDoubleType: {
+#ifdef CBOR_NO_FLOATING_POINT
+        return CborErrorUnsupportedType;
+#else
+        err = validate_floating_point(it, type, flags);
+        if (err)
+            return err;
+        break;
+    }
+#endif /* !CBOR_NO_FLOATING_POINT */
+
+    case CborInvalidType:
+        return CborErrorUnknownType;
+    }
+
+    err = cbor_value_advance_fixed(it);
+    return err;
+}
+
+/**
+ * Performs a full validation controlled by the \a flags options of the CBOR
+ * stream pointed by \a it and returns the error it found. If no error was
+ * found, it returns CborNoError and the application can iterate over the items
+ * with certainty that no other errors will appear during parsing.
+ *
+ * If \a flags is CborValidateBasic, the result should be the same as
+ * cbor_value_validate_basic().
+ *
+ * This function has the same timing and memory requirements as
+ * cbor_value_advance() and cbor_value_validate_basic().
+ *
+ * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
+ */
+CborError cbor_value_validate(const CborValue *it, int flags)
+{
+    CborValue value = *it;
+    CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
+    if (err)
+        return err;
+    if (flags & CborValidateCompleteData && it->offset != it->parser->end)
+        return CborErrorGarbageAtEnd;
+    return CborNoError;
+}
+
+/**
+ * @}
+ */
diff --git a/ext/tinycbor/src/compilersupport_p.h b/ext/tinycbor/src/compilersupport_p.h
new file mode 100644
index 0000000..b7831f9
--- /dev/null
+++ b/ext/tinycbor/src/compilersupport_p.h
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef COMPILERSUPPORT_H
+#define COMPILERSUPPORT_H
+
+#include "cbor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _BSD_SOURCE
+#  define _BSD_SOURCE
+#endif
+#ifndef _DEFAULT_SOURCE
+#  define _DEFAULT_SOURCE
+#endif
+#ifndef assert
+#  include <assert.h>
+#endif
+#include <float.h>
+#include <math.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifndef __cplusplus
+#  include <stdbool.h>
+#endif
+
+#ifdef __F16C__
+#  include <immintrin.h>
+#endif
+
+#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L || __cpp_static_assert >= 200410
+#  define cbor_static_assert(x)         static_assert(x, #x)
+#elif !defined(__cplusplus) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && (__STDC_VERSION__ > 199901L)
+#  define cbor_static_assert(x)         static_assert(x, #x)
+#else
+#  define cbor_static_assert(x)         ((void)sizeof(char[2*!!(x) - 1]))
+#endif
+#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
+/* inline is a keyword */
+#else
+/* use the definition from cbor.h */
+#  define inline    CBOR_INLINE
+#endif
+
+#ifdef NDEBUG
+#  define cbor_assert(cond)     do { if (!(cond)) unreachable(); } while (0)
+#else
+#  define cbor_assert(cond)     assert(cond)
+#endif
+
+#ifndef STRINGIFY
+#define STRINGIFY(x)            STRINGIFY2(x)
+#endif
+#define STRINGIFY2(x)           #x
+
+#if !defined(UINT32_MAX) || !defined(INT64_MAX)
+/* C89? We can define UINT32_MAX portably, but not INT64_MAX */
+#  error "Your system has stdint.h but that doesn't define UINT32_MAX or INT64_MAX"
+#endif
+
+#ifndef DBL_DECIMAL_DIG
+/* DBL_DECIMAL_DIG is C11 */
+#  define DBL_DECIMAL_DIG       17
+#endif
+#define DBL_DECIMAL_DIG_STR     STRINGIFY(DBL_DECIMAL_DIG)
+
+#if defined(__GNUC__) && defined(__i386__) && !defined(__iamcu__)
+#  define CBOR_INTERNAL_API_CC          __attribute__((regparm(3)))
+#elif defined(_MSC_VER) && defined(_M_IX86)
+#  define CBOR_INTERNAL_API_CC          __fastcall
+#else
+#  define CBOR_INTERNAL_API_CC
+#endif
+
+#ifndef __has_builtin
+#  define __has_builtin(x)  0
+#endif
+
+#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) || \
+    (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32))
+#  if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#    define cbor_ntohll     __builtin_bswap64
+#    define cbor_htonll     __builtin_bswap64
+#    define cbor_ntohl      __builtin_bswap32
+#    define cbor_htonl      __builtin_bswap32
+#    ifdef __INTEL_COMPILER
+#      define cbor_ntohs    _bswap16
+#      define cbor_htons    _bswap16
+#    elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16)
+#      define cbor_ntohs    __builtin_bswap16
+#      define cbor_htons    __builtin_bswap16
+#    else
+#      define cbor_ntohs(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8))
+#      define cbor_htons    cbor_ntohs
+#    endif
+#  else
+#    define cbor_ntohll
+#    define cbor_htonll
+#    define cbor_ntohl
+#    define cbor_htonl
+#    define cbor_ntohs
+#    define cbor_htons
+#  endif
+#elif defined(__sun)
+#  include <sys/byteorder.h>
+#elif defined(_MSC_VER)
+/* MSVC, which implies Windows, which implies little-endian and sizeof(long) == 4 */
+#  include <stdlib.h>
+#  define cbor_ntohll       _byteswap_uint64
+#  define cbor_htonll       _byteswap_uint64
+#  define cbor_ntohl        _byteswap_ulong
+#  define cbor_htonl        _byteswap_ulong
+#  define cbor_ntohs        _byteswap_ushort
+#  define cbor_htons        _byteswap_ushort
+#endif
+#ifndef cbor_ntohs
+#  include <arpa/inet.h>
+#  define cbor_ntohs        ntohs
+#  define cbor_htons        htons
+#endif
+#ifndef cbor_ntohl
+#  include <arpa/inet.h>
+#  define cbor_ntohl        ntohl
+#  define cbor_htonl        htonl
+#endif
+#ifndef cbor_ntohll
+#  define cbor_ntohll       ntohll
+#  define cbor_htonll       htonll
+/* ntohll isn't usually defined */
+#  ifndef ntohll
+#    if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#      define ntohll
+#      define htonll
+#    elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#      define ntohll(x)       ((ntohl((uint32_t)(x)) * UINT64_C(0x100000000)) + (ntohl((x) >> 32)))
+#      define htonll          ntohll
+#    else
+#      error "Unable to determine byte order!"
+#    endif
+#  endif
+#endif
+
+
+#ifdef __cplusplus
+#  define CONST_CAST(t, v)  const_cast<t>(v)
+#else
+/* C-style const_cast without triggering a warning with -Wcast-qual */
+#  define CONST_CAST(t, v)  (t)(uintptr_t)(v)
+#endif
+
+#ifdef __GNUC__
+#ifndef likely
+#  define likely(x)     __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#  define unlikely(x)   __builtin_expect(!!(x), 0)
+#endif
+#  define unreachable() __builtin_unreachable()
+#elif defined(_MSC_VER)
+#  define likely(x)     (x)
+#  define unlikely(x)   (x)
+#  define unreachable() __assume(0)
+#else
+#  define likely(x)     (x)
+#  define unlikely(x)   (x)
+#  define unreachable() do {} while (0)
+#endif
+
+static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r)
+{
+#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow)
+    return __builtin_add_overflow(v1, v2, r);
+#else
+    /* unsigned additions are well-defined */
+    *r = v1 + v2;
+    return v1 > v1 + v2;
+#endif
+}
+
+static inline unsigned short encode_half(double val)
+{
+#ifdef __F16C__
+    return _cvtss_sh((float)val, 3);
+#else
+    uint64_t v;
+    memcpy(&v, &val, sizeof(v));
+    int sign = v >> 63 << 15;
+    int exp = (v >> 52) & 0x7ff;
+    int mant = v << 12 >> 12 >> (53-11);    /* keep only the 11 most significant bits of the mantissa */
+    exp -= 1023;
+    if (exp == 1024) {
+        /* infinity or NaN */
+        exp = 16;
+        mant >>= 1;
+    } else if (exp >= 16) {
+        /* overflow, as largest number */
+        exp = 15;
+        mant = 1023;
+    } else if (exp >= -14) {
+        /* regular normal */
+    } else if (exp >= -24) {
+        /* subnormal */
+        mant |= 1024;
+        mant >>= -(exp + 14);
+        exp = -15;
+    } else {
+        /* underflow, make zero */
+        return 0;
+    }
+
+    /* safe cast here as bit operations above guarantee not to overflow */
+    return (unsigned short)(sign | ((exp + 15) << 10) | mant);
+#endif
+}
+
+/* this function was copied & adapted from RFC 7049 Appendix D */
+static inline double decode_half(unsigned short half)
+{
+#ifdef __F16C__
+    return _cvtsh_ss(half);
+#else
+    int exp = (half >> 10) & 0x1f;
+    int mant = half & 0x3ff;
+    double val;
+    if (exp == 0) val = ldexp(mant, -24);
+    else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
+    else val = mant == 0 ? INFINITY : NAN;
+    return half & 0x8000 ? -val : val;
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COMPILERSUPPORT_H */
+
diff --git a/ext/tinycbor/src/open_memstream.c b/ext/tinycbor/src/open_memstream.c
new file mode 100644
index 0000000..eaa53e5
--- /dev/null
+++ b/ext/tinycbor/src/open_memstream.c
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+#define _GNU_SOURCE 1
+
+#ifndef WITHOUT_OPEN_MEMSTREAM
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__unix__) || defined(__APPLE__)
+#  include <unistd.h>
+#endif
+#ifdef __APPLE__
+typedef int RetType;
+typedef int LenType;
+#elif __GLIBC__
+typedef ssize_t RetType;
+typedef size_t LenType;
+#else
+#  error "Cannot implement open_memstream!"
+#endif
+
+#include "compilersupport_p.h"
+
+struct Buffer
+{
+    char **ptr;
+    size_t *len;
+    size_t alloc;
+};
+
+static RetType write_to_buffer(void *cookie, const char *data, LenType len)
+{
+    struct Buffer *b = (struct Buffer *)cookie;
+    char *ptr = *b->ptr;
+    size_t newsize;
+
+    errno = EFBIG;
+    if (unlikely(add_check_overflow(*b->len, len, &newsize)))
+        return -1;
+
+    if (newsize > b->alloc) {
+        // make room
+        size_t newalloc = newsize + newsize / 2 + 1;    // give 50% more room
+        ptr = realloc(ptr, newalloc);
+        if (ptr == NULL)
+            return -1;
+        b->alloc = newalloc;
+        *b->ptr = ptr;
+    }
+
+    memcpy(ptr + *b->len, data, len);
+    *b->len = newsize;
+    return len;
+}
+
+static int close_buffer(void *cookie)
+{
+    struct Buffer *b = (struct Buffer *)cookie;
+    if (*b->ptr)
+        (*b->ptr)[*b->len] = '\0';
+    free(b);
+    return 0;
+}
+
+FILE *open_memstream(char **bufptr, size_t *lenptr)
+{
+    struct Buffer *b = (struct Buffer *)malloc(sizeof(struct Buffer));
+    if (b == NULL)
+        return NULL;
+    b->alloc = 0;
+    b->len = lenptr;
+    b->ptr = bufptr;
+    *bufptr = NULL;
+    *lenptr = 0;
+
+#ifdef __APPLE__
+    return funopen(b, NULL, write_to_buffer, NULL, close_buffer);
+#elif __GLIBC__
+    static const cookie_io_functions_t vtable = {
+        NULL,
+        write_to_buffer,
+        NULL,
+        close_buffer
+    };
+    return fopencookie(b, "w", vtable);
+#endif
+}
+
+#endif
diff --git a/ext/tinycbor/src/parsetags.pl b/ext/tinycbor/src/parsetags.pl
new file mode 100755
index 0000000..18be146
--- /dev/null
+++ b/ext/tinycbor/src/parsetags.pl
@@ -0,0 +1,116 @@
+#!/usr/bin/perl -l
+## Copyright (C) 2017 Intel Corporation
+##
+## Permission is hereby granted, free of charge, to any person obtaining a copy
+## of this software and associated documentation files (the "Software"), to deal
+## in the Software without restriction, including without limitation the rights
+## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+## copies of the Software, and to permit persons to whom the Software is
+## furnished to do so, subject to the following conditions:
+##
+## The above copyright notice and this permission notice shall be included in
+## all copies or substantial portions of the Software.
+##
+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+## THE SOFTWARE.
+##
+use strict;
+my $fname = shift @ARGV
+    or die("Usage: parsetags.pl tags.txt");
+open TAGS, "<", $fname
+    or die("Cannot open $fname: $!");
+
+my %typedescriptions = (
+    "Integer" => "integer",
+    "ByteString" => "byte string",
+    "TextString" => "UTF-8 text string",
+    "Array" => "array",
+    "Map" => "map",
+    "Tag" => "tag",     # shouldn't happen
+    "Simple" => "any simple type",
+    "Boolean" => "boolean",
+    "Null" => "null",
+    "Undefined" => "undefined",
+    "HalfFloat" => "IEEE 754 half-precision floating point",
+    "Float" => "IEEE 754 single-precision floating point",
+    "Double" => "IEEE 754 double-precision floating point"
+);
+
+my %tags;
+while (<TAGS>) {
+    s/\s*#.*$//;
+    next if /^$/;
+    chomp;
+
+    die("Could not parse line \"$_\"")
+        unless /^(\d+);(\w+);([\w,]*);(.*)$/;
+    $tags{$1}{id} = $2;
+    $tags{$1}{semantic} = $4;
+    my @types = split(',', $3);
+    $tags{$1}{types} = \@types;
+}
+close TAGS or die;
+
+my @tagnumbers = sort { $a <=> $b } keys %tags;
+
+print "==== HTML listing ====";
+print "<table>\n  <tr>\n    <th>Tag</th>\n    <th>Data Item</th>\n    <th>Semantics</th>\n  </tr>";
+for my $n (@tagnumbers) {
+    print "  <tr>";
+    print "    <td>$n</td>";
+
+    my @types = @{$tags{$n}{types}};
+    @types = map { $typedescriptions{$_}; } @types;
+    unshift @types, "any"
+        if (scalar @types == 0);
+    printf "    <td>%s</td>\n", join(', ', @types);
+    printf "    <td>%s</td>\n", $tags{$n}{semantic};
+    print "  </td>";
+}
+print "</table>";
+
+print "\n==== enum listing for cbor.h ====\n";
+printf "typedef enum CborKnownTags {";
+my $comma = "";
+for my $n (@tagnumbers) {
+    printf "%s\n    Cbor%sTag%s = %d", $comma,
+        $tags{$n}{id},
+        ' ' x (23 - length($tags{$n}{id})),
+        $n;
+    $comma = ",";
+}
+print "\n} CborKnownTags;";
+print "\n/* #define the constants so we can check with #ifdef */";
+for my $n (@tagnumbers) {
+    printf "#define Cbor%sTag Cbor%sTag\n", $tags{$n}{id}, $tags{$n}{id};
+}
+
+print "\n==== search table ====\n";
+print "struct KnownTagData { uint32_t tag; uint32_t types; };";
+printf "static const struct KnownTagData knownTagData[] = {";
+$comma = "";
+for my $n (@tagnumbers) {
+    my @types = @{$tags{$n}{types}};
+
+    my $typemask;
+    my $shift = 0;
+    for my $type (@types) {
+        die("Too many match types for tag $n") if $shift == 32;
+        my $actualtype = "Cbor${type}Type";
+        $actualtype = "($actualtype+1)" if $type eq "Integer";
+        $typemask .= " | " if $typemask ne "";
+        $typemask .= "((uint8_t)$actualtype << $shift)" if $shift;
+        $typemask .= "(uint8_t)$actualtype" unless $shift;
+        $shift += 8;
+    }
+    $typemask = "0U" if $typemask eq "";
+
+    printf "%s\n    { %d, %s }", $comma, $n, $typemask;
+    $comma = ",";
+}
+print "\n};";
diff --git a/ext/tinycbor/src/src.pri b/ext/tinycbor/src/src.pri
new file mode 100644
index 0000000..1624598
--- /dev/null
+++ b/ext/tinycbor/src/src.pri
@@ -0,0 +1,17 @@
+SOURCES += \
+    $$PWD/cborencoder.c \
+    $$PWD/cborerrorstrings.c \
+    $$PWD/cborparser.c \
+    $$PWD/cborparser_dup_string.c \
+    $$PWD/cborpretty.c \
+    $$PWD/cbortojson.c \
+    $$PWD/cborvalidation.c \
+    $$PWD/cbor_buf_reader.c \
+    $$PWD/cbor_buf_writer.c
+
+
+HEADERS += $$PWD/cbor.h $$PWD/tinycbor-version.h
+QMAKE_CFLAGS *= $$QMAKE_CFLAGS_SPLIT_SECTIONS
+QMAKE_LFLAGS *= $$QMAKE_LFLAGS_GCSECTIONS
+INCLUDEPATH += $$PWD/
+CONFIG(release, debug|release): DEFINES += NDEBUG
diff --git a/ext/tinycbor/src/tags.txt b/ext/tinycbor/src/tags.txt
new file mode 100644
index 0000000..ef78cfb
--- /dev/null
+++ b/ext/tinycbor/src/tags.txt
@@ -0,0 +1,23 @@
+# Tag number; Tag ID; Applicable types (comma-separated); Semantics
+0;DateTimeString;TextString;Standard date/time string
+1;UnixTime_t;Integer;Epoch-based date/time
+2;PositiveBignum;ByteString;Positive bignum
+3;NegativeBignum;ByteString;Negative bignum
+4;Decimal;Array;Decimal fraction
+5;Bigfloat;Array;Bigfloat
+16;COSE_Encrypt0;Array;COSE Single Recipient Encrypted Data Object (RFC 8152)
+17;COSE_Mac0;Array;COSE Mac w/o Recipients Object (RFC 8152)
+18;COSE_Sign1;Array;COSE Single Signer Data Object (RFC 8162)
+21;ExpectedBase64url;ByteString,Array,Map;Expected conversion to base64url encoding
+22;ExpectedBase64;ByteString,Array,Map;Expected conversion to base64 encoding
+23;ExpectedBase16;ByteString,Array,Map;Expected conversion to base16 encoding
+24;EncodedCbor;ByteString;Encoded CBOR data item
+32;Url;TextString;URI
+33;Base64url;TextString;base64url
+34;Base64;TextString;base64
+35;RegularExpression;TextString;Regular expression
+36;MimeMessage;TextString;MIME message
+96;COSE_Encrypt;Array;COSE Encrypted Data Object (RFC 8152)
+97;COSE_Mac;Array;COSE MACed Data Object (RFC 8152)
+98;COSE_Sign;Array;COSE Signed Data Object (RFC 8152)
+55799;Signature;;Self-describe CBOR
diff --git a/ext/tinycbor/src/tinycbor-version.h b/ext/tinycbor/src/tinycbor-version.h
new file mode 100644
index 0000000..19936e5
--- /dev/null
+++ b/ext/tinycbor/src/tinycbor-version.h
@@ -0,0 +1,3 @@
+#define TINYCBOR_VERSION_MAJOR      0
+#define TINYCBOR_VERSION_MINOR      5
+#define TINYCBOR_VERSION_PATCH      0
diff --git a/ext/tinycbor/src/tinycbor.pro b/ext/tinycbor/src/tinycbor.pro
new file mode 100644
index 0000000..980dfd1
--- /dev/null
+++ b/ext/tinycbor/src/tinycbor.pro
@@ -0,0 +1,6 @@
+TEMPLATE = lib
+CONFIG += static
+CONFIG -= qt
+DESTDIR = ../lib
+
+include(src.pri)
diff --git a/ext/tinycbor/src/utf8_p.h b/ext/tinycbor/src/utf8_p.h
new file mode 100644
index 0000000..661c428
--- /dev/null
+++ b/ext/tinycbor/src/utf8_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef CBOR_UTF8_H
+#define CBOR_UTF8_H
+
+#include "compilersupport_p.h"
+
+#include <stdint.h>
+
+static inline uint32_t get_utf8(const uint8_t **buffer, const uint8_t *end)
+{
+    uint32_t uc;
+    ptrdiff_t n = end - *buffer;
+    if (n == 0)
+        return ~0U;
+
+    uc = *(*buffer)++;
+    if (uc < 0x80) {
+        /* single-byte UTF-8 */
+        return uc;
+    }
+
+    /* multi-byte UTF-8, decode it */
+    int charsNeeded;
+    uint32_t min_uc;
+    if (unlikely(uc <= 0xC1))
+        return ~0U;
+    if (uc < 0xE0) {
+        /* two-byte UTF-8 */
+        charsNeeded = 2;
+        min_uc = 0x80;
+        uc &= 0x1f;
+    } else if (uc < 0xF0) {
+        /* three-byte UTF-8 */
+        charsNeeded = 3;
+        min_uc = 0x800;
+        uc &= 0x0f;
+    } else if (uc < 0xF5) {
+        /* four-byte UTF-8 */
+        charsNeeded = 4;
+        min_uc = 0x10000;
+        uc &= 0x07;
+    } else {
+        return ~0U;
+    }
+
+    if (n < charsNeeded - 1)
+        return ~0U;
+
+    /* first continuation character */
+    uint8_t b = *(*buffer)++;
+    if ((b & 0xc0) != 0x80)
+        return ~0U;
+    uc <<= 6;
+    uc |= b & 0x3f;
+
+    if (charsNeeded > 2) {
+        /* second continuation character */
+        b = *(*buffer)++;
+        if ((b & 0xc0) != 0x80)
+            return ~0U;
+        uc <<= 6;
+        uc |= b & 0x3f;
+
+        if (charsNeeded > 3) {
+            /* third continuation character */
+            b = *(*buffer)++;
+            if ((b & 0xc0) != 0x80)
+                return ~0U;
+            uc <<= 6;
+            uc |= b & 0x3f;
+        }
+    }
+
+    /* overlong sequence? surrogate pair? out or range? */
+    if (uc < min_uc || uc - 0xd800U < 2048U || uc > 0x10ffff)
+        return ~0U;
+
+    return uc;
+}
+
+#endif // CBOR_UTF8_H
diff --git a/ext/tinycbor/tests/.gitignore b/ext/tinycbor/tests/.gitignore
new file mode 100644
index 0000000..e65577d
--- /dev/null
+++ b/ext/tinycbor/tests/.gitignore
@@ -0,0 +1,15 @@
+Makefile
+debug
+moc_predefs.h
+release
+target_wrapper.*
+
+# The executables
+cpp/cpp
+cpp/cpp.exe
+encoder/encoder
+encoder/encoder.exe
+parser/parser
+parser/parser.exe
+tojson/tojson
+tojson/tojson.exe
diff --git a/ext/tinycbor/tests/cpp/cpp.pro b/ext/tinycbor/tests/cpp/cpp.pro
new file mode 100644
index 0000000..5e9e608
--- /dev/null
+++ b/ext/tinycbor/tests/cpp/cpp.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase parallel_test c++11
+QT = core testlib
+
+SOURCES = tst_cpp.cpp
+INCLUDEPATH += ../../src
diff --git a/ext/tinycbor/tests/cpp/tst_cpp.cpp b/ext/tinycbor/tests/cpp/tst_cpp.cpp
new file mode 100644
index 0000000..e221906
--- /dev/null
+++ b/ext/tinycbor/tests/cpp/tst_cpp.cpp
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
... 4315 lines suppressed ...

-- 
To stop receiving notification emails like this one, please contact
ccollins@apache.org.