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