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'