1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <shell/shell.h>
7 #include <shell/shell_uart.h>
8 #include <drivers/uart.h>
9 #include <device.h>
10
shell_init_from_work(struct k_work * work)11 void shell_init_from_work(struct k_work *work)
12 {
13 const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
14 bool log_backend = CONFIG_SHELL_BACKEND_SERIAL_LOG_LEVEL > 0;
15 uint32_t level =
16 (CONFIG_SHELL_BACKEND_SERIAL_LOG_LEVEL > LOG_LEVEL_DBG) ?
17 CONFIG_LOG_MAX_LEVEL : CONFIG_SHELL_BACKEND_SERIAL_LOG_LEVEL;
18
19 shell_init(shell_backend_uart_get_ptr(), dev, true, log_backend, level);
20 }
21
shell_reinit_trigger(void)22 static void shell_reinit_trigger(void)
23 {
24 static struct k_work shell_init_work;
25
26 k_work_init(&shell_init_work, shell_init_from_work);
27 int err = k_work_submit(&shell_init_work);
28
29 (void)err;
30 __ASSERT_NO_MSG(err >= 0);
31 }
32
direct_uart_callback(const struct device * dev,void * user_data)33 static void direct_uart_callback(const struct device *dev, void *user_data)
34 {
35 static uint8_t buf[1];
36 static bool tx_busy;
37
38 uart_irq_update(dev);
39
40
41 if (uart_irq_rx_ready(dev)) {
42 while (uart_fifo_read(dev, buf, sizeof(buf))) {
43 if (!tx_busy) {
44 uart_irq_tx_enable(dev);
45 }
46 }
47 }
48
49 if (uart_irq_tx_ready(dev)) {
50 if (!tx_busy) {
51 (void)uart_fifo_fill(dev, buf, sizeof(buf));
52 tx_busy = true;
53 } else {
54 tx_busy = false;
55 uart_irq_tx_disable(dev);
56 if (buf[0] == 'x') {
57 uart_irq_rx_disable(dev);
58 shell_reinit_trigger();
59 }
60 }
61 }
62 }
63
uart_poll_timer_stopped(struct k_timer * timer)64 static void uart_poll_timer_stopped(struct k_timer *timer)
65 {
66 shell_reinit_trigger();
67 }
68
uart_poll_timeout(struct k_timer * timer)69 static void uart_poll_timeout(struct k_timer *timer)
70 {
71 char c;
72 const struct device *dev = k_timer_user_data_get(timer);
73
74 while (uart_poll_in(dev, &c) == 0) {
75 if (c != 'x') {
76 uart_poll_out(dev, c);
77 } else {
78 k_timer_stop(timer);
79 }
80 }
81 }
82
83 K_TIMER_DEFINE(uart_poll_timer, uart_poll_timeout, uart_poll_timer_stopped);
84
shell_uninit_cb(const struct shell * shell,int res)85 static void shell_uninit_cb(const struct shell *shell, int res)
86 {
87 __ASSERT_NO_MSG(res >= 0);
88 const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
89
90 if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN)) {
91 /* connect uart to my handler */
92 uart_irq_callback_user_data_set(dev, direct_uart_callback, NULL);
93 uart_irq_rx_enable(dev);
94 } else {
95 k_timer_user_data_set(&uart_poll_timer, (void *)dev);
96 k_timer_start(&uart_poll_timer, K_MSEC(10), K_MSEC(10));
97 }
98 }
99
cmd_uart_release(const struct shell * shell,size_t argc,char ** argv)100 static int cmd_uart_release(const struct shell *shell, size_t argc, char **argv)
101 {
102 ARG_UNUSED(argc);
103 ARG_UNUSED(argv);
104
105 if (shell != shell_backend_uart_get_ptr()) {
106 shell_error(shell, "Command dedicated for shell over uart");
107 return -EINVAL;
108 }
109
110 shell_print(shell, "Uninitializing shell, use 'x' to reinitialize");
111 shell_uninit(shell, shell_uninit_cb);
112
113 return 0;
114 }
115
116 SHELL_CMD_REGISTER(shell_uart_release, NULL,
117 "Uninitialize shell instance and release uart, start loopback "
118 "on uart. Shell instance is renitialized when 'x' is pressed",
119 cmd_uart_release);
120