1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2016 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <string.h>
30
31 #include "py/runtime.h"
32 #include "py/stream.h"
33 #include "py/mperrno.h"
34 #include "modmachine.h"
35
36 #include "ulog/ulog.h"
37 #include "aos_hal_uart.h"
38
39 #define LOG_TAG "machine_uart"
40
41 enum {
42 UART_NUM_0,
43 UART_NUM_1,
44 UART_NUM_2,
45 UART_NUM_3,
46 UART_NUM_MAX
47 };
48
49 enum {
50 e_DATA_WIDTH_5BIT = 5,
51 e_DATA_WIDTH_6BIT,
52 e_DATA_WIDTH_7BIT,
53 e_DATA_WIDTH_8BIT,
54 e_DATA_WIDTH_9BIT
55 };
56
57 enum {
58 e_STOP_BITS_1 = 1,
59 e_STOP_BITS_2
60 };
61
62 typedef struct _machine_uart_obj_t {
63 mp_obj_base_t base;
64 uint8_t uart_num;
65 bool uart_inited;
66 uart_dev_t dev;
67 uint16_t timeout; // timeout waiting for first char (in ms)
68 uint16_t timeout_char; // timeout waiting between chars (in ms)
69 } machine_uart_obj_t;
70
71 STATIC const char *_parity_name[] = {"None", "Odd", "Even"};
72 STATIC const char *_flowctrl_name[] = {"Disable", "CTS", "RTS", "CTS_RTS"};
73 STATIC const char *_mode_name[] = {"Tx", "Rx", "Tx_Rx"};
74 STATIC const uint8_t _bits[] = {e_DATA_WIDTH_5BIT, e_DATA_WIDTH_6BIT, e_DATA_WIDTH_7BIT, e_DATA_WIDTH_8BIT, e_DATA_WIDTH_9BIT};
75
76 const mp_obj_type_t machine_uart_type;
77
78 /******************************************************************************/
79 // MicroPython bindings for UART
80
machine_uart_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)81 STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
82 machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
83 mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, flow_ctrl=%s, mode=%s, timeout=%u, timeout_char=%u)",
84 self->uart_num, self->dev.config.baud_rate, _bits[self->dev.config.data_width],
85 _parity_name[self->dev.config.parity], self->dev.config.stop_bits,
86 _flowctrl_name[self->dev.config.flow_control], _mode_name[self->dev.config.mode],
87 self->timeout, self->timeout_char);
88 }
89
machine_uart_init_helper(machine_uart_obj_t * self,size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)90 STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
91 enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_txbuf, ARG_rxbuf, ARG_timeout, ARG_timeout_char, ARG_invert };
92 static const mp_arg_t allowed_args[] = {
93 { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 115200} },
94 { MP_QSTR_bits, MP_ARG_INT, {.u_int = e_DATA_WIDTH_8BIT} },
95 { MP_QSTR_parity, MP_ARG_OBJ, {.u_int = NO_PARITY} },
96 { MP_QSTR_stop, MP_ARG_INT, {.u_int = e_STOP_BITS_1} },
97 { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
98 { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
99 { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
100 { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
101 { MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
102 { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
103 { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
104 { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
105 { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
106 };
107 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
108 mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
109
110 uart_dev_t *dev = &self->dev;
111
112 // wait for all data to be transmitted before changing settings
113 // TODO
114
115 // set baudrate
116 int32_t baudrate = args[ARG_baudrate].u_int;
117 if (baudrate <= 0) {
118 mp_raise_ValueError(MP_ERROR_TEXT("baud rate error"));
119 } else {
120 dev->config.baud_rate = baudrate;
121 }
122
123 // set flow_control
124 uint32_t rts = args[ARG_rts].u_int;
125 uint32_t cts = args[ARG_cts].u_int;
126 if(rts && cts) {
127 dev->config.flow_control = FLOW_CONTROL_CTS_RTS;
128 } else if(cts) {
129 dev->config.flow_control = FLOW_CONTROL_CTS;
130 } else if(rts) {
131 dev->config.flow_control = FLOW_CONTROL_RTS;
132 } else {
133 dev->config.flow_control = FLOW_CONTROL_DISABLED;
134 }
135
136 // set data bits
137 uint8_t data_width = args[ARG_bits].u_int;
138 switch(data_width) {
139 case e_DATA_WIDTH_5BIT:
140 dev->config.data_width = DATA_WIDTH_5BIT;
141 break;
142
143 case e_DATA_WIDTH_6BIT:
144 dev->config.data_width = DATA_WIDTH_6BIT;
145 break;
146
147 case e_DATA_WIDTH_7BIT:
148 dev->config.data_width = DATA_WIDTH_7BIT;
149 break;
150
151 case e_DATA_WIDTH_8BIT:
152 dev->config.data_width = DATA_WIDTH_8BIT;
153 break;
154
155 case e_DATA_WIDTH_9BIT:
156 dev->config.data_width = DATA_WIDTH_9BIT;
157 break;
158
159 default:
160 mp_raise_ValueError(MP_ERROR_TEXT("invalid data bits"));
161 }
162
163 // set parity
164 if (args[ARG_parity].u_obj != MP_OBJ_NULL) {
165 if (args[ARG_parity].u_obj == mp_const_none) {
166 dev->config.parity = NO_PARITY;
167 } else {
168 mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj);
169 if (parity & 1) {
170 dev->config.parity = ODD_PARITY;
171 } else {
172 dev->config.parity = EVEN_PARITY;
173 }
174 }
175 }
176
177 // set stop bits
178 uint8_t stop_bits = args[ARG_stop].u_int;
179 switch(stop_bits) {
180 case e_STOP_BITS_1:
181 dev->config.stop_bits = STOP_BITS_1;
182 break;
183
184 case e_STOP_BITS_2:
185 dev->config.stop_bits = STOP_BITS_2;
186 break;
187
188 default:
189 mp_raise_ValueError(MP_ERROR_TEXT("invalid stop bits"));
190 }
191
192 // set timeout
193 self->timeout = args[ARG_timeout].u_int;
194
195 // set timeout_char
196 // make sure it is at least as long as a whole character (13 bits to be safe)
197 self->timeout_char = args[ARG_timeout_char].u_int;
198 uint32_t min_timeout_char = 13000 / baudrate + 1;
199 if (self->timeout_char < min_timeout_char) {
200 self->timeout_char = min_timeout_char;
201 }
202 }
203
machine_uart_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * args)204 STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
205 mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
206
207 // get uart id
208 mp_int_t uart_num = mp_obj_get_int(args[0]);
209 if (uart_num < 0 || uart_num >= UART_NUM_MAX) {
210 mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) does not exist"), uart_num);
211 }
212
213 // Attempts to use UART0 from Python has resulted in all sorts of fun errors.
214 // FIXME: UART0 is disabled for now.
215 if (uart_num == UART_NUM_0) {
216 mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) is disabled (dedicated to REPL)"), uart_num);
217 }
218
219 // create instance
220 machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t);
221 self->base.type = &machine_uart_type;
222 self->dev.port = uart_num;
223 self->dev.config.baud_rate = 115200;
224 self->dev.config.data_width = DATA_WIDTH_8BIT;
225 self->dev.config.parity = NO_PARITY;
226 self->dev.config.stop_bits = STOP_BITS_1;
227 self->dev.config.flow_control = FLOW_CONTROL_DISABLED;
228 self->dev.config.mode = MODE_TX_RX;
229 self->dev.priv = NULL;
230 self->timeout = 0;
231 self->timeout_char = 0;
232 self->uart_inited = false;
233
234 mp_map_t kw_args;
235 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
236 machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
237
238 return MP_OBJ_FROM_PTR(self);
239 }
240
machine_uart_init(size_t n_args,const mp_obj_t * args,mp_map_t * kw_args)241 STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
242 machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
243 return mp_const_none;
244 }
245 MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);
246
machine_uart_deinit(mp_obj_t self_in)247 STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) {
248 machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
249 if(self->uart_inited == true) {
250 aos_hal_uart_finalize(&self->dev);
251 }
252 return mp_const_none;
253 }
254 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit);
255
machine_uart_any(mp_obj_t self_in)256 STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
257 machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
258 mp_raise_NotImplementedError(MP_ERROR_TEXT("attenuation not supported"));
259 return MP_OBJ_NEW_SMALL_INT(0);
260 }
261 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
262
machine_uart_sendbreak(mp_obj_t self_in)263 STATIC mp_obj_t machine_uart_sendbreak(mp_obj_t self_in) {
264 machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
265 mp_raise_NotImplementedError(MP_ERROR_TEXT("attenuation not supported"));
266 return mp_const_none;
267 }
268 STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_sendbreak_obj, machine_uart_sendbreak);
269
270 STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
271 { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) },
272 { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_uart_deinit_obj) },
273 { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },
274 { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
275 { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
276 { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
277 { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
278 { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) },
279 };
280
281 STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
282
uart_init(machine_uart_obj_t * self)283 STATIC mp_int_t uart_init(machine_uart_obj_t *self) {
284 // init uart if not
285 if(self->uart_inited == false) {
286 int status = aos_hal_uart_init(&self->dev);
287 if(status != 0) {
288 LOGE(LOG_TAG, "Failed to init uart, status = %d\n", status);
289 return -status;
290 } else {
291 self->uart_inited = true;
292 }
293 }
294
295 return 0;
296 }
297
machine_uart_read(mp_obj_t self_in,void * buf_in,mp_uint_t size,int * errcode)298 STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
299 machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
300
301 // make sure we want at least 1 char
302 if (size == 0) {
303 return 0;
304 }
305
306 int status = uart_init(self);
307 if(status != 0) {
308 return status;
309 }
310
311 mp_uint_t bytes_read = 0;
312 MP_THREAD_GIL_EXIT();
313 status = aos_hal_uart_recv_II(&self->dev, buf_in, size, &bytes_read, self->timeout);
314 MP_THREAD_GIL_ENTER();
315
316 if (status != 0) {
317 LOGW(LOG_TAG, "uart read failed with status=%d", status);
318 *errcode = MP_EAGAIN;
319 return MP_STREAM_ERROR;
320 }
321
322 return bytes_read;
323 }
324
machine_uart_write(mp_obj_t self_in,const void * buf_in,mp_uint_t size,int * errcode)325 STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
326 machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
327
328 // init uart if not
329 int status = uart_init(self);
330 if(status != 0) {
331 return status;
332 }
333
334 MP_THREAD_GIL_EXIT();
335 status = aos_hal_uart_send(&self->dev, buf_in, size, self->timeout);
336 MP_THREAD_GIL_ENTER();
337
338 if (status != 0) {
339 *errcode = MP_EAGAIN;
340 return MP_STREAM_ERROR;
341 }
342
343 // return number of bytes written
344 return size;
345 }
346
machine_uart_ioctl(mp_obj_t self_in,mp_uint_t request,uintptr_t arg,int * errcode)347 STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
348 machine_uart_obj_t *self = self_in;
349 mp_uint_t ret;
350 if (request == MP_STREAM_POLL) {
351 mp_uint_t flags = arg;
352 ret = 0;
353 size_t rxbufsize = 0;
354 // uart_get_buffered_data_len(self->uart_num, &rxbufsize);
355 if ((flags & MP_STREAM_POLL_RD) && rxbufsize > 0) {
356 ret |= MP_STREAM_POLL_RD;
357 }
358 if ((flags & MP_STREAM_POLL_WR) && 1) { // FIXME: uart_tx_any_room(self->uart_num)
359 ret |= MP_STREAM_POLL_WR;
360 }
361 } else {
362 *errcode = MP_EINVAL;
363 ret = MP_STREAM_ERROR;
364 }
365 return ret;
366 }
367
368 STATIC const mp_stream_p_t uart_stream_p = {
369 .read = machine_uart_read,
370 .write = machine_uart_write,
371 .ioctl = machine_uart_ioctl,
372 .is_text = false,
373 };
374
375 const mp_obj_type_t machine_uart_type = {
376 { &mp_type_type },
377 .name = MP_QSTR_UART,
378 .print = machine_uart_print,
379 .make_new = machine_uart_make_new,
380 .getiter = mp_identity_getiter,
381 .iternext = mp_stream_unbuffered_iter,
382 .protocol = &uart_stream_p,
383 .locals_dict = (mp_obj_dict_t *)&machine_uart_locals_dict,
384 };
385