Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | /* * Copyright Runtime.io 2018. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ /** @file * @brief Shell transport for the mcumgr SMP protocol. */ #include <string.h> #include <zephyr.h> #include <init.h> #include "net/buf.h" #include "mgmt/mgmt.h" #include "mgmt/serial.h" #include "mgmt/buf.h" #include "mgmt/smp.h" #include "mgmt/smp_shell.h" static struct zephyr_smp_transport smp_shell_transport; static struct mcumgr_serial_rx_ctxt smp_shell_rx_ctxt; /** SMP mcumgr frame fragments. */ enum smp_shell_esc_mcumgr { ESC_MCUMGR_PKT_1, ESC_MCUMGR_PKT_2, ESC_MCUMGR_FRAG_1, ESC_MCUMGR_FRAG_2, }; /** These states indicate whether an mcumgr frame is being received. */ enum smp_shell_mcumgr_state { SMP_SHELL_MCUMGR_STATE_NONE, SMP_SHELL_MCUMGR_STATE_HEADER, SMP_SHELL_MCUMGR_STATE_PAYLOAD }; static int read_mcumgr_byte(struct smp_shell_data *data, u8_t byte) { bool frag_1; bool frag_2; bool pkt_1; bool pkt_2; pkt_1 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_PKT_1); pkt_2 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_PKT_2); frag_1 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_FRAG_1); frag_2 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_FRAG_2); if (pkt_2 || frag_2) { /* Already fully framed. */ return SMP_SHELL_MCUMGR_STATE_PAYLOAD; } if (pkt_1) { if (byte == MCUMGR_SERIAL_HDR_PKT_2) { /* Final framing byte received. */ atomic_set_bit(&data->esc_state, ESC_MCUMGR_PKT_2); return SMP_SHELL_MCUMGR_STATE_PAYLOAD; } } else if (frag_1) { if (byte == MCUMGR_SERIAL_HDR_FRAG_2) { /* Final framing byte received. */ atomic_set_bit(&data->esc_state, ESC_MCUMGR_FRAG_2); return SMP_SHELL_MCUMGR_STATE_PAYLOAD; } } else { if (byte == MCUMGR_SERIAL_HDR_PKT_1) { /* First framing byte received. */ atomic_set_bit(&data->esc_state, ESC_MCUMGR_PKT_1); return SMP_SHELL_MCUMGR_STATE_HEADER; } else if (byte == MCUMGR_SERIAL_HDR_FRAG_1) { /* First framing byte received. */ atomic_set_bit(&data->esc_state, ESC_MCUMGR_FRAG_1); return SMP_SHELL_MCUMGR_STATE_HEADER; } } /* Non-mcumgr byte received. */ return SMP_SHELL_MCUMGR_STATE_NONE; } bool smp_shell_rx_byte(struct smp_shell_data *data, uint8_t byte) { int mcumgr_state; mcumgr_state = read_mcumgr_byte(data, byte); if (mcumgr_state == SMP_SHELL_MCUMGR_STATE_NONE) { /* Not an mcumgr command; let the shell process the byte. */ return false; } /* * The received byte is part of an mcumgr command. Process the byte * and return true to indicate that shell should ignore it. */ if (data->cur + data->end < sizeof(data->mcumgr_buff) - 1) { data->mcumgr_buff[data->cur++] = byte; } if (mcumgr_state == SMP_SHELL_MCUMGR_STATE_PAYLOAD && byte == '\n') { data->mcumgr_buff[data->cur + data->end] = '\0'; data->cmd_rdy = true; atomic_clear_bit(&data->esc_state, ESC_MCUMGR_PKT_1); atomic_clear_bit(&data->esc_state, ESC_MCUMGR_PKT_2); atomic_clear_bit(&data->esc_state, ESC_MCUMGR_FRAG_1); atomic_clear_bit(&data->esc_state, ESC_MCUMGR_FRAG_2); data->cur = 0U; data->end = 0U; } return true; } void smp_shell_process(struct smp_shell_data *data) { if (data->cmd_rdy) { data->cmd_rdy = false; struct net_buf *nb; int line_len; /* Strip the trailing newline. */ line_len = strlen(data->mcumgr_buff) - 1; nb = mcumgr_serial_process_frag(&smp_shell_rx_ctxt, data->mcumgr_buff, line_len); if (nb != NULL) { zephyr_smp_rx_req(&smp_shell_transport, nb); } } } static u16_t smp_shell_get_mtu(const struct net_buf *nb) { return CONFIG_MCUMGR_SMP_SHELL_MTU; } static int smp_shell_tx_raw(const void *data, int len, void *arg) { /* Cast away const. */ k_str_out((void *)data, len); return 0; } static int smp_shell_tx_pkt(struct zephyr_smp_transport *zst, struct net_buf *nb) { int rc; rc = mcumgr_serial_tx_pkt(nb->data, nb->len, smp_shell_tx_raw, NULL); mcumgr_buf_free(nb); return rc; } static int smp_shell_init(struct device *dev) { ARG_UNUSED(dev); zephyr_smp_transport_init(&smp_shell_transport, smp_shell_tx_pkt, smp_shell_get_mtu, NULL, NULL); return 0; } SYS_INIT(smp_shell_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); |