sys/shell: add support for newtmgr over shell

Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/44504b96
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/44504b96
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/44504b96

Branch: refs/heads/master
Commit: 44504b96f941907fd23dd56eeab8453859373245
Parents: 038dc7f
Author: Michał Narajowski <michal.narajow...@codecoup.pl>
Authored: Wed May 3 10:48:54 2017 +0200
Committer: Michał Narajowski <michal.narajow...@codecoup.pl>
Committed: Wed May 3 12:12:41 2017 +0200

----------------------------------------------------------------------
 sys/shell/include/shell/shell.h |   7 +
 sys/shell/pkg.yml               |   2 +
 sys/shell/src/shell.c           |  32 +++++
 sys/shell/src/shell_nlip.c      | 252 +++++++++++++++++++++++++++++++++++
 sys/shell/src/shell_priv.h      |  11 ++
 sys/shell/syscfg.yml            |   3 +
 6 files changed, 307 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/44504b96/sys/shell/include/shell/shell.h
----------------------------------------------------------------------
diff --git a/sys/shell/include/shell/shell.h b/sys/shell/include/shell/shell.h
index fdb263a..38cb606 100644
--- a/sys/shell/include/shell/shell.h
+++ b/sys/shell/include/shell/shell.h
@@ -101,6 +101,13 @@ void shell_register_prompt_handler(shell_prompt_function_t 
handler);
  */
 void shell_register_default_module(const char *name);
 
+#if MYNEWT_VAL(SHELL_NEWTMGR)
+struct os_mbuf;
+typedef int (*shell_nlip_input_func_t)(struct os_mbuf *, void *arg);
+int shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg);
+int shell_nlip_output(struct os_mbuf *m);
+#endif
+
 #if MYNEWT_VAL(SHELL_COMPAT)
 int shell_cmd_register(struct shell_cmd *sc);
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/44504b96/sys/shell/pkg.yml
----------------------------------------------------------------------
diff --git a/sys/shell/pkg.yml b/sys/shell/pkg.yml
index 1f38a8d..71d88a5 100644
--- a/sys/shell/pkg.yml
+++ b/sys/shell/pkg.yml
@@ -26,6 +26,8 @@ pkg.keywords:
 pkg.deps:
     - kernel/os
     - time/datetime
+    - encoding/base64
+    - util/crc
 pkg.req_apis:
     - console
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/44504b96/sys/shell/src/shell.c
----------------------------------------------------------------------
diff --git a/sys/shell/src/shell.c b/sys/shell/src/shell.c
index d186aa7..959a0a3 100644
--- a/sys/shell/src/shell.c
+++ b/sys/shell/src/shell.c
@@ -381,6 +381,30 @@ shell_process_command(char *line)
     console_printf("%s", get_prompt());
 }
 
+#if MYNEWT_VAL(SHELL_NEWTMGR)
+static void
+shell_process_nlip_line(char *shell_line)
+{
+    size_t shell_line_len;
+
+    shell_line_len = strlen(shell_line);
+    if (shell_line_len > 2) {
+        if (shell_line[0] == SHELL_NLIP_PKT_START1 &&
+                shell_line[1] == SHELL_NLIP_PKT_START2) {
+            shell_nlip_clear_pkt();
+            shell_nlip_process(&shell_line[2], shell_line_len - 2);
+        } else if (shell_line[0] == SHELL_NLIP_DATA_START1 &&
+                shell_line[1] == SHELL_NLIP_DATA_START2) {
+            shell_nlip_process(&shell_line[2], shell_line_len - 2);
+        } else {
+            shell_process_command(shell_line);
+        }
+    } else {
+        shell_process_command(shell_line);
+    }
+}
+#endif
+
 static void
 shell(struct os_event *ev)
 {
@@ -397,7 +421,11 @@ shell(struct os_event *ev)
         return;
     }
 
+#if MYNEWT_VAL(SHELL_NEWTMGR)
+    shell_process_nlip_line(cmd->line);
+#else
     shell_process_command(cmd->line);
+#endif
     os_eventq_put(&avail_queue, ev);
 }
 
@@ -893,6 +921,10 @@ shell_init(void)
     prompt = SHELL_PROMPT;
     console_set_queues(&avail_queue, os_eventq_dflt_get());
 
+#if MYNEWT_VAL(SHELL_NEWTMGR)
+    shell_nlip_init();
+#endif
+
 #if MYNEWT_VAL(SHELL_COMPLETION)
     console_set_completion_cb(completion);
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/44504b96/sys/shell/src/shell_nlip.c
----------------------------------------------------------------------
diff --git a/sys/shell/src/shell_nlip.c b/sys/shell/src/shell_nlip.c
new file mode 100644
index 0000000..e967cd2
--- /dev/null
+++ b/sys/shell/src/shell_nlip.c
@@ -0,0 +1,252 @@
+/*
+ * 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"
+
+#if MYNEWT_VAL(SHELL_NEWTMGR)
+#include <stddef.h>
+#include "os/os.h"
+#include "os/endian.h"
+#include "base64/base64.h"
+#include "crc/crc16.h"
+#include "console/console.h"
+#include "shell/shell.h"
+#include "shell_priv.h"
+
+static shell_nlip_input_func_t g_shell_nlip_in_func;
+static void *g_shell_nlip_in_arg;
+static struct os_mqueue g_shell_nlip_mq;
+static struct os_mbuf *g_nlip_mbuf;
+static uint16_t g_nlip_expected_len;
+
+void
+shell_nlip_clear_pkt(void)
+{
+    if (g_nlip_mbuf) {
+        os_mbuf_free_chain(g_nlip_mbuf);
+        g_nlip_mbuf = NULL;
+    }
+    g_nlip_expected_len = 0;
+}
+
+int
+shell_nlip_process(char *data, int len)
+{
+    uint16_t copy_len;
+    int rc;
+    struct os_mbuf *m;
+    uint16_t crc;
+
+    rc = base64_decode(data, data);
+    if (rc < 0) {
+        goto err;
+    }
+    len = rc;
+
+    if (g_nlip_mbuf == NULL) {
+        if (len < 2) {
+            rc = -1;
+            goto err;
+        }
+
+        g_nlip_expected_len = ntohs(*(uint16_t *) data);
+        g_nlip_mbuf = os_msys_get_pkthdr(g_nlip_expected_len, 0);
+        if (!g_nlip_mbuf) {
+            rc = -1;
+            goto err;
+        }
+
+        data += sizeof(uint16_t);
+        len -= sizeof(uint16_t);
+    }
+
+    copy_len = min(g_nlip_expected_len - OS_MBUF_PKTHDR(g_nlip_mbuf)->omp_len,
+            len);
+
+    rc = os_mbuf_copyinto(g_nlip_mbuf, OS_MBUF_PKTHDR(g_nlip_mbuf)->omp_len,
+            data, copy_len);
+    if (rc != 0) {
+        goto err;
+    }
+
+    if (OS_MBUF_PKTHDR(g_nlip_mbuf)->omp_len == g_nlip_expected_len) {
+        if (g_shell_nlip_in_func) {
+            crc = CRC16_INITIAL_CRC;
+            for (m = g_nlip_mbuf; m; m = SLIST_NEXT(m, om_next)) {
+                crc = crc16_ccitt(crc, m->om_data, m->om_len);
+            }
+            if (crc == 0 && g_nlip_expected_len >= sizeof(crc)) {
+                os_mbuf_adj(g_nlip_mbuf, -sizeof(crc));
+                g_shell_nlip_in_func(g_nlip_mbuf, g_shell_nlip_in_arg);
+            } else {
+                os_mbuf_free_chain(g_nlip_mbuf);
+            }
+        } else {
+            os_mbuf_free_chain(g_nlip_mbuf);
+        }
+        g_nlip_mbuf = NULL;
+        g_nlip_expected_len = 0;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+static int
+shell_nlip_mtx(struct os_mbuf *m)
+{
+#define SHELL_NLIP_MTX_BUF_SIZE (12)
+    uint8_t readbuf[SHELL_NLIP_MTX_BUF_SIZE];
+    char encodebuf[BASE64_ENCODE_SIZE(SHELL_NLIP_MTX_BUF_SIZE)];
+    char pkt_seq[3] = { '\n', SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
+    char esc_seq[2] = { SHELL_NLIP_DATA_START1, SHELL_NLIP_DATA_START2 };
+    uint16_t totlen;
+    uint16_t dlen;
+    uint16_t off;
+    uint16_t crc;
+    int rb_off;
+    int elen;
+    uint16_t nwritten;
+    uint16_t linelen;
+    int rc;
+    struct os_mbuf *tmp;
+    void *ptr;
+
+    /* Convert the mbuf into a packet.
+     *
+     * starts with 06 09
+     * base64 encode:
+     *  - total packet length (uint16_t)
+     *  - data
+     *  - crc
+     * base64 encoded data must be less than 122 bytes per line to
+     * avoid overflows and adhere to convention.
+     *
+     * continuation packets are preceded by 04 20 until the entire
+     * buffer has been sent.
+     */
+    crc = CRC16_INITIAL_CRC;
+    for (tmp = m; tmp; tmp = SLIST_NEXT(tmp, om_next)) {
+        crc = crc16_ccitt(crc, tmp->om_data, tmp->om_len);
+    }
+    crc = htons(crc);
+    ptr = os_mbuf_extend(m, sizeof(crc));
+    if (!ptr) {
+        rc = -1;
+        goto err;
+    }
+    memcpy(ptr, &crc, sizeof(crc));
+
+    totlen = OS_MBUF_PKTHDR(m)->omp_len;
+    nwritten = 0;
+    off = 0;
+
+    /* Start a packet */
+    console_write(pkt_seq, sizeof(pkt_seq));
+
+    linelen = 0;
+
+    rb_off = 2;
+    dlen = htons(totlen);
+    memcpy(readbuf, &dlen, sizeof(dlen));
+
+    while (totlen > 0) {
+        dlen = min(SHELL_NLIP_MTX_BUF_SIZE - rb_off, totlen);
+
+        rc = os_mbuf_copydata(m, off, dlen, readbuf + rb_off);
+        if (rc != 0) {
+            goto err;
+        }
+        off += dlen;
+
+        /* If the next packet will overwhelm the line length, truncate
+         * this line.
+         */
+        if (linelen +
+                BASE64_ENCODE_SIZE(min(SHELL_NLIP_MTX_BUF_SIZE - rb_off,
+                        totlen - dlen)) >= 120) {
+            elen = base64_encode(readbuf, dlen + rb_off, encodebuf, 1);
+            console_write(encodebuf, elen);
+            console_write("\n", 1);
+            console_write(esc_seq, sizeof(esc_seq));
+            linelen = 0;
+        } else {
+            elen = base64_encode(readbuf, dlen + rb_off, encodebuf, 0);
+            console_write(encodebuf, elen);
+            linelen += elen;
+        }
+
+        rb_off = 0;
+
+        nwritten += elen;
+        totlen -= dlen;
+    }
+
+    elen = base64_pad(encodebuf, linelen);
+    console_write(encodebuf, elen);
+
+    console_write("\n", 1);
+
+    return (0);
+err:
+    return (rc);
+}
+
+int
+shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg)
+{
+    g_shell_nlip_in_func = nf;
+    g_shell_nlip_in_arg = arg;
+
+    return (0);
+}
+
+int
+shell_nlip_output(struct os_mbuf *m)
+{
+    return os_mqueue_put(&g_shell_nlip_mq, os_eventq_dflt_get(), m);
+}
+
+static void
+shell_event_data_in(struct os_event *ev)
+{
+    struct os_mbuf *m;
+
+    /* Copy data out of the mbuf 12 bytes at a time and write it to
+     * the console.
+     */
+    while (1) {
+        m = os_mqueue_get(&g_shell_nlip_mq);
+        if (!m) {
+            break;
+        }
+
+        (void) shell_nlip_mtx(m);
+
+        os_mbuf_free_chain(m);
+    }
+}
+
+void
+shell_nlip_init(void)
+{
+    os_mqueue_init(&g_shell_nlip_mq, shell_event_data_in, NULL);
+}
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/44504b96/sys/shell/src/shell_priv.h
----------------------------------------------------------------------
diff --git a/sys/shell/src/shell_priv.h b/sys/shell/src/shell_priv.h
index fbb44c2..2efa2cd 100644
--- a/sys/shell/src/shell_priv.h
+++ b/sys/shell/src/shell_priv.h
@@ -26,6 +26,17 @@ extern "C" {
 
 #include "shell/shell.h"
 
+#if MYNEWT_VAL(SHELL_NEWTMGR)
+#define SHELL_NLIP_PKT_START1 (6)
+#define SHELL_NLIP_PKT_START2 (9)
+#define SHELL_NLIP_DATA_START1 (4)
+#define SHELL_NLIP_DATA_START2 (20)
+
+int shell_nlip_process(char *data, int len);
+void shell_nlip_init(void);
+void shell_nlip_clear_pkt(void);
+#endif
+
 void shell_os_register(shell_register_function_t register_func);
 void shell_prompt_register(shell_register_function_t register_func);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/44504b96/sys/shell/syscfg.yml
----------------------------------------------------------------------
diff --git a/sys/shell/syscfg.yml b/sys/shell/syscfg.yml
index e4d78f8..72b686d 100644
--- a/sys/shell/syscfg.yml
+++ b/sys/shell/syscfg.yml
@@ -44,6 +44,9 @@ syscfg.defs:
     SHELL_COMPLETION:
         description: 'Include completion functionality'
         value: 1
+    SHELL_NEWTMGR:
+        description: 'Enable newtmgr over shell'
+        value: 1
 
     SHELL_OS_MODULE:
         description: 'Include shell os module'

Reply via email to