1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 #include <assert.h>
20 #include <stddef.h>
21 #include <inttypes.h>
22 #include "os/mynewt.h"
23 #include <uart/uart.h>
24
25 /*
26 * RX is a ring buffer, which gets drained constantly.
27 * TX blocks until buffer has been completely transmitted.
28 */
29 #define CONSOLE_HEAD_INC(cr) (((cr)->head + 1) & (sizeof((cr)->buf) - 1))
30 #define CONSOLE_TAIL_INC(cr) (((cr)->tail + 1) & (sizeof((cr)->buf) - 1))
31
32 struct {
33 uint16_t head;
34 uint16_t tail;
35 uint8_t buf[MYNEWT_VAL(CONSOLE_UART_RX_BUF_SIZE)];
36 } bs_uart_rx;
37
38 struct {
39 uint8_t *ptr;
40 int cnt;
41 } volatile bs_uart_tx;
42
43 static struct uart_dev *bs_uart;
44
45 static int bs_rx_char(void *arg, uint8_t byte);
46 static int bs_tx_char(void *arg);
47
48 int
boot_uart_open(void)49 boot_uart_open(void)
50 {
51 struct uart_conf uc = {
52 .uc_speed = MYNEWT_VAL(CONSOLE_UART_BAUD),
53 .uc_databits = 8,
54 .uc_stopbits = 1,
55 .uc_parity = UART_PARITY_NONE,
56 .uc_flow_ctl = MYNEWT_VAL(CONSOLE_UART_FLOW_CONTROL),
57 .uc_tx_char = bs_tx_char,
58 .uc_rx_char = bs_rx_char,
59 };
60
61 bs_uart = (struct uart_dev *)os_dev_open(MYNEWT_VAL(CONSOLE_UART_DEV),
62 OS_TIMEOUT_NEVER, &uc);
63 if (!bs_uart) {
64 return -1;
65 }
66 return 0;
67 }
68
69 void
boot_uart_close(void)70 boot_uart_close(void)
71 {
72 os_dev_close(&bs_uart->ud_dev);
73 bs_uart_rx.head = 0;
74 bs_uart_rx.tail = 0;
75 bs_uart_tx.cnt = 0;
76 }
77
78 static int
bs_rx_char(void * arg,uint8_t byte)79 bs_rx_char(void *arg, uint8_t byte)
80 {
81 if (CONSOLE_HEAD_INC(&bs_uart_rx) == bs_uart_rx.tail) {
82 /*
83 * RX queue full. Reader must drain this.
84 */
85 return -1;
86 }
87 bs_uart_rx.buf[bs_uart_rx.head] = byte;
88 bs_uart_rx.head = CONSOLE_HEAD_INC(&bs_uart_rx);
89 return 0;
90 }
91
92 static uint8_t
bs_pull_char(void)93 bs_pull_char(void)
94 {
95 uint8_t ch;
96
97 ch = bs_uart_rx.buf[bs_uart_rx.tail];
98 bs_uart_rx.tail = CONSOLE_TAIL_INC(&bs_uart_rx);
99 return ch;
100 }
101
102 int
boot_uart_read(char * str,int cnt,int * newline)103 boot_uart_read(char *str, int cnt, int *newline)
104 {
105 int i;
106 int sr;
107 uint8_t ch;
108
109 *newline = 0;
110 OS_ENTER_CRITICAL(sr);
111 for (i = 0; i < cnt; i++) {
112 if (bs_uart_rx.head == bs_uart_rx.tail) {
113 break;
114 }
115
116 ch = bs_pull_char();
117 if (ch == '\n') {
118 *str = '\0';
119 *newline = 1;
120 break;
121 }
122 /*
123 * Unblock interrupts allowing more incoming data.
124 */
125 OS_EXIT_CRITICAL(sr);
126 OS_ENTER_CRITICAL(sr);
127 *str++ = ch;
128 }
129 OS_EXIT_CRITICAL(sr);
130 if (i > 0 || *newline) {
131 uart_start_rx(bs_uart);
132 }
133 return i;
134 }
135
136 static int
bs_tx_char(void * arg)137 bs_tx_char(void *arg)
138 {
139 uint8_t ch;
140
141 if (!bs_uart_tx.cnt) {
142 return -1;
143 }
144
145 bs_uart_tx.cnt--;
146 ch = *bs_uart_tx.ptr;
147 bs_uart_tx.ptr++;
148 return ch;
149 }
150
151 #if MYNEWT_VAL(SELFTEST)
152 /*
153 * OS is not running, so native uart 'driver' cannot run either.
154 * At the moment unit tests don't check the responses to messages it
155 * sends, so we can drop the outgoing data here.
156 */
157 void
boot_uart_write(const char * ptr,int cnt)158 boot_uart_write(const char *ptr, int cnt)
159 {
160 }
161
162 #else
163
164 void
boot_uart_write(const char * ptr,int cnt)165 boot_uart_write(const char *ptr, int cnt)
166 {
167 int sr;
168
169 OS_ENTER_CRITICAL(sr);
170 bs_uart_tx.ptr = (uint8_t *)ptr;
171 bs_uart_tx.cnt = cnt;
172 OS_EXIT_CRITICAL(sr);
173
174 uart_start_tx(bs_uart);
175 while (bs_uart_tx.cnt);
176 }
177
178 #endif
179