nmgr_uart; add a transport to use for serial when shell is not needed.
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/8cf9cf31 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/8cf9cf31 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/8cf9cf31 Branch: refs/heads/develop Commit: 8cf9cf31c58d16a64c580c0a512610836a088852 Parents: 23f8224 Author: Marko Kiiskila <ma...@runtime.io> Authored: Fri Oct 7 13:39:31 2016 -0700 Committer: Marko Kiiskila <ma...@runtime.io> Committed: Fri Oct 7 13:39:31 2016 -0700 ---------------------------------------------------------------------- mgmt/newtmgr/transport/nmgr_uart/pkg.yml | 34 ++ .../newtmgr/transport/nmgr_uart/src/nmgr_uart.c | 355 +++++++++++++++++++ mgmt/newtmgr/transport/nmgr_uart/syscfg.yml | 28 ++ 3 files changed, 417 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8cf9cf31/mgmt/newtmgr/transport/nmgr_uart/pkg.yml ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/transport/nmgr_uart/pkg.yml b/mgmt/newtmgr/transport/nmgr_uart/pkg.yml new file mode 100644 index 0000000..449e3ef --- /dev/null +++ b/mgmt/newtmgr/transport/nmgr_uart/pkg.yml @@ -0,0 +1,34 @@ +# +# 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/newtmgr/transport/nmgr_uart +pkg.description: Newtmgr transport over raw UART +pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - newtmgr + - uart + +pkg.deps: + - kernel/os + - hw/drivers/uart + - mgmt/newtmgr + +pkg.init_function: nmgr_uart_pkg_init +pkg.init_stage: 5 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8cf9cf31/mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c b/mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c new file mode 100644 index 0000000..c7fa34d --- /dev/null +++ b/mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c @@ -0,0 +1,355 @@ +/** + * 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 <assert.h> + +#include <syscfg/syscfg.h> +#include <bsp/bsp.h> + +#include <os/os.h> +#include <mgmt/mgmt.h> +#include <newtmgr/newtmgr.h> +#include <uart/uart.h> + +#include <crc/crc16.h> +#include <base64/base64.h> + +#define SHELL_NLIP_PKT 0x0609 +#define SHELL_NLIP_DATA 0x0414 +#define SHELL_NLIP_MAX_FRAME 128 + +#define NUS_EV_TO_STATE(ptr) \ + (struct nmgr_uart_state *)((uint8_t *)ptr - \ + (int)&(((struct nmgr_uart_state *)0)->nus_cb_ev)) + +struct nmgr_uart_state { + struct nmgr_transport nus_transport; /* keep first in struct */ + struct os_event nus_cb_ev; + struct uart_dev *nus_dev; + struct os_mbuf *nus_tx; + int nus_tx_off; + struct os_mbuf_pkthdr *nus_rx_pkt; + struct os_mbuf_pkthdr *nus_rx_q; + struct os_mbuf_pkthdr *nus_rx; +}; + +/* + * Header for frames arriving over serial. + */ +struct nmgr_ser_hdr { + uint16_t nsh_seq; + uint16_t nsh_len; +}; + +static struct nmgr_uart_state nmgr_uart_state; + +static uint16_t +nmgr_uart_mtu(struct os_mbuf *m) +{ + return MGMT_MAX_MTU; +} + +/* + * Called by mgmt to queue packet out to UART. + */ +static int +nmgr_uart_out(struct nmgr_transport *nt, struct os_mbuf *m) +{ + struct nmgr_uart_state *nus = (struct nmgr_uart_state *)nt; + struct os_mbuf_pkthdr *mpkt; + struct os_mbuf *n; + char tmp_buf[12]; + uint16_t crc; + char *dst; + int off; + int boff; + int slen; + int sr; + int rc; + int last; + int tx_sz; + + assert(OS_MBUF_IS_PKTHDR(m)); + mpkt = OS_MBUF_PKTHDR(m); + + off = 0; + crc = CRC16_INITIAL_CRC; + for (n = m; n; n = SLIST_NEXT(n, om_next)) { + crc = crc16_ccitt(crc, n->om_data, n->om_len); + } + crc = htons(crc); + dst = os_mbuf_extend(m, sizeof(crc)); + if (!dst) { + goto err; + } + memcpy(dst, &crc, sizeof(crc)); + + n = os_msys_get(SHELL_NLIP_MAX_FRAME, 0); + if (!n || OS_MBUF_TRAILINGSPACE(n) < 32) { + goto err; + } + + while (off < mpkt->omp_len) { + tx_sz = 2; + dst = os_mbuf_extend(n, 2); + if (off == 0) { + *(uint16_t *)dst = htons(SHELL_NLIP_PKT); + *(uint16_t *)tmp_buf = htons(mpkt->omp_len); + boff = 2; + } else { + *(uint16_t *)dst = htons(SHELL_NLIP_DATA); + boff = 0; + } + + while (off < mpkt->omp_len) { + slen = mpkt->omp_len - off; + last = 1; + if (slen > sizeof(tmp_buf) + boff) { + slen = sizeof(tmp_buf) - boff; + last = 0; + } + if (tx_sz + BASE64_ENCODE_SIZE(slen + boff) >= 124) { + break; + } + rc = os_mbuf_copydata(m, off, slen, tmp_buf + boff); + assert(rc == 0); + + off += slen; + slen += boff; + + dst = os_mbuf_extend(n, BASE64_ENCODE_SIZE(slen)); + if (!dst) { + goto err; + } + tx_sz += base64_encode(tmp_buf, slen, dst, last); + boff = 0; + } + + if (os_mbuf_append(n, "\n", 1)) { + goto err; + } + } + + os_mbuf_free_chain(m); + OS_ENTER_CRITICAL(sr); + if (!nus->nus_tx) { + nus->nus_tx = n; + uart_start_tx(nus->nus_dev); + } else { + os_mbuf_concat(nus->nus_tx, n); + } + OS_EXIT_CRITICAL(sr); + + return 0; +err: + os_mbuf_free_chain(m); + os_mbuf_free_chain(n); + return -1; +} + +/* + * Called by UART driver to send out next character. + * + * Interrupts disabled when nmgr_uart_tx_char/nmgr_uart_rx_char are called. + */ +static int +nmgr_uart_tx_char(void *arg) +{ + struct nmgr_uart_state *nus = (struct nmgr_uart_state *)arg; + struct os_mbuf *m; + uint8_t ch; + + if (!nus->nus_tx) { + /* + * Out of data. Return -1 makes UART stop asking for more. + */ + return -1; + } + while (nus->nus_tx->om_len == nus->nus_tx_off) { + /* + * If no active mbuf, move to next one. + */ + m = SLIST_NEXT(nus->nus_tx, om_next); + os_mbuf_free(nus->nus_tx); + nus->nus_tx = m; + + nus->nus_tx_off = 0; + if (!nus->nus_tx) { + return -1; + } + } + + os_mbuf_copydata(nus->nus_tx, nus->nus_tx_off++, 1, &ch); + + return ch; +} + +/* + * Check for full packet. If frame is not right, free the mbuf. + */ +static void +nmgr_uart_rx_pkt(struct nmgr_uart_state *nus, struct os_mbuf_pkthdr *rxm) +{ + struct os_mbuf *m; + struct nmgr_ser_hdr *nsh; + uint16_t crc; + int rc; + + m = OS_MBUF_PKTHDR_TO_MBUF(rxm); + + if (rxm->omp_len <= sizeof(uint16_t) + sizeof(crc)) { + goto err; + } + + nsh = (struct nmgr_ser_hdr *)m->om_data; + switch (nsh->nsh_seq) { + case htons(SHELL_NLIP_PKT): + if (nus->nus_rx_pkt) { + os_mbuf_free_chain(OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx_pkt)); + nus->nus_rx_pkt = NULL; + } + break; + case htons(SHELL_NLIP_DATA): + if (!nus->nus_rx_pkt) { + goto err; + } + break; + default: + goto err; + } + m->om_data[m->om_len] = '\0'; /* XXXX wrong */ + rc = base64_decode((char *)m->om_data + 2, (char *)m->om_data + 2); + if (rc < 0) { + goto err; + } + rxm->omp_len = m->om_len = rc + 2; + if (nus->nus_rx_pkt) { + os_mbuf_adj(m, 2); + os_mbuf_concat(OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx_pkt), m); + } else { + nus->nus_rx_pkt = rxm; + } + + m = OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx_pkt); + nsh = (struct nmgr_ser_hdr *)m->om_data; + if (nus->nus_rx_pkt->omp_len - sizeof(*nsh) == ntohs(nsh->nsh_len)) { + os_mbuf_adj(m, 4); + os_mbuf_adj(m, -2); + nmgr_rx_req(&nus->nus_transport, m); + nus->nus_rx_pkt = NULL; + } + return; +err: + os_mbuf_free_chain(m); +} + +/* + * Callback from mgmt task context. + */ +static void +nmgr_uart_rx_frame(struct os_event *ev) +{ + struct nmgr_uart_state *nus = NUS_EV_TO_STATE(ev); + struct os_mbuf_pkthdr *m; + int sr; + + OS_ENTER_CRITICAL(sr); + m = nus->nus_rx_q; + nus->nus_rx_q = NULL; + OS_EXIT_CRITICAL(sr); + if (m) { + nmgr_uart_rx_pkt(nus, m); + } +} + +/* + * Receive a character from UART. + */ +static int +nmgr_uart_rx_char(void *arg, uint8_t data) +{ + struct nmgr_uart_state *nus = (struct nmgr_uart_state *)arg; + struct os_mbuf *m; + int rc; + + if (!nus->nus_rx) { + m = os_msys_get_pkthdr(SHELL_NLIP_MAX_FRAME, 0); + if (!m) { + return 0; + } + nus->nus_rx = OS_MBUF_PKTHDR(m); + if (OS_MBUF_TRAILINGSPACE(m) < SHELL_NLIP_MAX_FRAME) { + /* + * mbuf is too small. + */ + os_mbuf_free_chain(m); + nus->nus_rx = NULL; + return 0; + } + } + + m = OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx); + if (data == '\n') { + /* + * Full line of input. Process it outside interrupt context. + */ + assert(!nus->nus_rx_q); + nus->nus_rx_q = nus->nus_rx; + nus->nus_rx = NULL; + os_eventq_put(g_mgmt_evq, &nus->nus_cb_ev); + return 0; + } else { + rc = os_mbuf_append(m, &data, 1); + if (rc == 0) { + return 0; + } + } + /* failed */ + nus->nus_rx->omp_len = 0; + m->om_len = 0; + os_mbuf_free_chain(SLIST_NEXT(m, om_next)); + SLIST_NEXT(m, om_next) = NULL; + return 0; +} + +void +nmgr_uart_pkg_init(void) +{ + struct nmgr_uart_state *nus = &nmgr_uart_state; + int rc; + struct uart_conf uc = { + .uc_speed = MYNEWT_VAL(NMGR_UART_SPEED), + .uc_databits = 8, + .uc_stopbits = 1, + .uc_parity = UART_PARITY_NONE, + .uc_flow_ctl = UART_FLOW_CTL_NONE, + .uc_tx_char = nmgr_uart_tx_char, + .uc_rx_char = nmgr_uart_rx_char, + .uc_cb_arg = nus + }; + + rc = nmgr_transport_init(&nus->nus_transport, nmgr_uart_out, nmgr_uart_mtu); + assert(rc == 0); + + nus->nus_dev = + (struct uart_dev *)os_dev_open(MYNEWT_VAL(NMGR_UART), 0, &uc); + assert(nus->nus_dev); + + mgmt_cb_init(&nus->nus_cb_ev, nmgr_uart_rx_frame); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8cf9cf31/mgmt/newtmgr/transport/nmgr_uart/syscfg.yml ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/transport/nmgr_uart/syscfg.yml b/mgmt/newtmgr/transport/nmgr_uart/syscfg.yml new file mode 100644 index 0000000..0ede1ed --- /dev/null +++ b/mgmt/newtmgr/transport/nmgr_uart/syscfg.yml @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + NMGR_UART: + description: 'UART port number to use for newtmgr' + value: CONSOLE_UART + + NMGR_UART_SPEED: + description: 'Baudrate for newtmgr UART' + value: CONSOLE_UART_SPEED +