From 328086939f0f152f9cfc140530d44e4a716685b6 Mon Sep 17 00:00:00 2001 From: Rahix <rahix@rahix.de> Date: Sat, 3 Aug 2019 12:28:27 +0200 Subject: [PATCH] fix(serial): Fix UART receive call violating API rules Signed-off-by: Rahix <rahix@rahix.de> --- epicardium/epicardium.h | 51 +++++++++++++++++++++++++++++-------- epicardium/modules/serial.c | 23 ++++++++++------- pycardium/main.c | 7 ++--- pycardium/mphalport.c | 21 +++++++++++++-- pycardium/mphalport.h | 3 +++ 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 7b486428..a9b17b49 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -29,8 +29,9 @@ typedef unsigned int size_t; /* clang-format off */ #define API_SYSTEM_EXIT 0x1 /* TODO */ #define API_SYSTEM_EXEC 0x2 /* TODO */ -#define API_UART_WRITE 0x3 -#define API_UART_READ 0x4 +#define API_UART_WRITE_STR 0x3 +#define API_UART_READ_CHAR 0x4 +#define API_UART_READ_STR 0x5 /* TODO */ #define API_STREAM_READ 0x6 #define API_INTERRUPT_ENABLE 0x7 #define API_INTERRUPT_DISABLE 0x8 @@ -102,7 +103,7 @@ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id)); #define EPIC_INT_RESET 0 /** ``^C`` interrupt. See :c:func:`epic_isr_ctrl_c` for details. */ #define EPIC_INT_CTRL_C 1 -/** TODO */ +/** UART Receive interrupt. See :c:func:`epic_isr_uart_rx`. */ #define EPIC_INT_UART_RX 2 /** RTC Alarm interrupt. See :c:func:`epic_isr_rtc_alarm` */ #define EPIC_INT_RTC_ALARM 3 @@ -129,19 +130,49 @@ API_ISR(EPIC_INT_RESET, epic_isr_reset); * :param str: String to write. Does not necessarily have to be NULL-terminated. * :param length: Amount of bytes to print. */ -API(API_UART_WRITE, void epic_uart_write_str(const char *str, intptr_t length)); +API(API_UART_WRITE_STR, void epic_uart_write_str( + const char *str, + intptr_t length +)); /** - * Blocking read a single character from any connected serial device. - * ``epic_uart_read_chr`` only returns once one byte has been read. * - * .. todo:: + * Try reading a single character from any connected serial device. If nothing + * is available, :c:func:`epic_uart_read_char` returns ``(-1)``. * - * This API function is currently in violation of the API rules. + * :return: The byte or ``(-1)`` if no byte was available. + */ +API(API_UART_READ_CHAR, int epic_uart_read_char(void)); + +/** + * **Interrupt Service Routine** + * + * UART receive interrupt. This interrupt is triggered whenever a new character + * becomes available on any connected UART device. This function is weakly + * aliased to :c:func:`epic_isr_default` by default. + * + * **Example**: * - * :return: The byte. + * .. code-block:: cpp + * + * void epic_isr_uart_rx(void) + * { + * char buffer[33]; + * int n = epic_uart_read_str(&buffer, sizeof(buffer) - 1); + * buffer[n] = '\0'; + * printf("Got: %s\n", buffer); + * } + * + * int main(void) + * { + * epic_interrupt_enable(EPIC_INT_UART_RX); + * + * while (1) { + * __WFI(); + * } + * } */ -API(API_UART_READ, char epic_uart_read_chr(void)); +API_ISR(EPIC_INT_UART_RX, epic_isr_uart_rx); /** * **Interrupt Service Routine** diff --git a/epicardium/modules/serial.c b/epicardium/modules/serial.c index 71df9e1e..ac573757 100644 --- a/epicardium/modules/serial.c +++ b/epicardium/modules/serial.c @@ -1,5 +1,7 @@ -#include <stdint.h> -#include <stdio.h> +#include "epicardium.h" +#include "api/interrupt-sender.h" +#include "modules/log.h" +#include "modules/modules.h" #include "max32665.h" #include "cdcacm.h" @@ -9,9 +11,8 @@ #include "task.h" #include "queue.h" -#include "modules.h" -#include "modules/log.h" -#include "api/interrupt-sender.h" +#include <stdint.h> +#include <stdio.h> /* Task ID for the serial handler */ TaskHandle_t serial_task_id = NULL; @@ -31,13 +32,15 @@ void epic_uart_write_str(const char *str, intptr_t length) } /* - * Blocking API-call to read a character from the queue. + * API-call to read a character from the queue. */ -char epic_uart_read_chr(void) +int epic_uart_read_char(void) { char chr; - xQueueReceive(read_queue, &chr, portMAX_DELAY); - return chr; + if (xQueueReceive(read_queue, &chr, 0) == pdTRUE) { + return (int)chr; + } + return (-1); } /* Interrupt handler needed for SDK UART implementation */ @@ -64,6 +67,8 @@ static void enqueue_char(char chr) /* Queue overran, wait a bit */ vTaskDelay(portTICK_PERIOD_MS * 50); } + + api_interrupt_trigger(EPIC_INT_UART_RX); } void vSerialTask(void *pvParameters) diff --git a/pycardium/main.c b/pycardium/main.c index 273e85eb..4d708727 100644 --- a/pycardium/main.c +++ b/pycardium/main.c @@ -1,3 +1,5 @@ +#include "mphalport.h" + #include "max32665.h" #include "lib/utils/pyexec.h" @@ -13,12 +15,11 @@ extern void *__HeapBase, *__HeapLimit; int main(void) { + pycardium_hal_init(); + mp_stack_set_top(&__StackTop); mp_stack_set_limit((mp_int_t)&__StackLimit); - /* TMR5 is used to notify on keyboard interrupt */ - NVIC_EnableIRQ(TMR5_IRQn); - while (1) { gc_init(&__HeapBase + 1024 * 10, &__HeapLimit); diff --git a/pycardium/mphalport.c b/pycardium/mphalport.c index b97c1dd4..1fa75b64 100644 --- a/pycardium/mphalport.c +++ b/pycardium/mphalport.c @@ -1,5 +1,5 @@ -#include "api/common.h" #include "epicardium.h" +#include "api/common.h" #include "max32665.h" #include "mxc_delay.h" @@ -20,6 +20,19 @@ #include <stdio.h> #include <string.h> +/* Initialize everything for MicroPython */ +void pycardium_hal_init(void) +{ + /* TMR5 is used for interrupts from Epicardium */ + NVIC_EnableIRQ(TMR5_IRQn); + + /* + * Enable UART RX Interrupt so Pycardium can sleep until + * a character becomes available. + */ + epic_interrupt_enable(EPIC_INT_UART_RX); +} + /****************************************************************************** * Serial Communication */ @@ -27,7 +40,11 @@ /* Receive single character */ int mp_hal_stdin_rx_chr(void) { - return (int)epic_uart_read_chr(); + int chr; + while ((chr = epic_uart_read_char()) < 0) { + __WFI(); + } + return chr; } /* Send a string */ diff --git a/pycardium/mphalport.h b/pycardium/mphalport.h index ad34087f..5827a483 100644 --- a/pycardium/mphalport.h +++ b/pycardium/mphalport.h @@ -1,3 +1,6 @@ #include "py/mpconfig.h" void mp_hal_set_interrupt_char(char c); + +/* Init everything */ +void pycardium_hal_init(void); -- GitLab