Add support for the USB CDC Serial JTAG console
This commit is contained in:
parent
a3712ac990
commit
384aff1d09
|
@ -12,6 +12,14 @@
|
||||||
#include "task/task.h"
|
#include "task/task.h"
|
||||||
#include "linput.h"
|
#include "linput.h"
|
||||||
|
|
||||||
|
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||||
|
#include "driver/usb_serial_jtag.h"
|
||||||
|
#include "esp_vfs_usb_serial_jtag.h"
|
||||||
|
#include "esp_vfs_dev.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
int platform_init (void)
|
int platform_init (void)
|
||||||
{
|
{
|
||||||
platform_ws2812_init();
|
platform_ws2812_init();
|
||||||
|
@ -34,6 +42,16 @@ int platform_gpio_output_exists( unsigned gpio ) { return GPIO_IS_VALID_OUTPUT_G
|
||||||
#define PLATFORM_UART_EVENT_RX (UART_EVENT_MAX + 3)
|
#define PLATFORM_UART_EVENT_RX (UART_EVENT_MAX + 3)
|
||||||
#define PLATFORM_UART_EVENT_BREAK (UART_EVENT_MAX + 4)
|
#define PLATFORM_UART_EVENT_BREAK (UART_EVENT_MAX + 4)
|
||||||
|
|
||||||
|
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||||
|
#define ADJUST_IDR(id,retval) if (id-- == 0) return retval
|
||||||
|
#define ADJUST_ID(id) if (id-- == 0) return
|
||||||
|
#define UNADJUST_ID(id) id++
|
||||||
|
#else
|
||||||
|
#define ADJUST_IDR(id, retval)
|
||||||
|
#define ADJUST_ID(id)
|
||||||
|
#define UNADJUST_ID(id)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned rx_buf_sz;
|
unsigned rx_buf_sz;
|
||||||
unsigned tx_buf_sz;
|
unsigned tx_buf_sz;
|
||||||
|
@ -65,60 +83,125 @@ uart_status_t uart_status[NUM_UART];
|
||||||
task_handle_t uart_event_task_id = 0;
|
task_handle_t uart_event_task_id = 0;
|
||||||
SemaphoreHandle_t sem = NULL;
|
SemaphoreHandle_t sem = NULL;
|
||||||
|
|
||||||
|
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||||
|
task_handle_t usbcdc_event_task_id = 0;
|
||||||
|
static uart_status_t usbcdc_status;
|
||||||
|
SemaphoreHandle_t usbcdc_sem = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern bool uart_on_data_cb(unsigned id, const char *buf, size_t len);
|
extern bool uart_on_data_cb(unsigned id, const char *buf, size_t len);
|
||||||
extern bool uart_on_error_cb(unsigned id, const char *buf, size_t len);
|
extern bool uart_on_error_cb(unsigned id, const char *buf, size_t len);
|
||||||
|
|
||||||
void uart_event_task( task_param_t param, task_prio_t prio ) {
|
static void handle_uart_data(unsigned int id, uart_event_post_t *post, uart_status_t *us) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < post->size) {
|
||||||
|
if (id == CONFIG_ESP_CONSOLE_UART_NUM && run_input) {
|
||||||
|
unsigned used = feed_lua_input(post->data + i, post->size - i);
|
||||||
|
i += used;
|
||||||
|
} else {
|
||||||
|
char ch = post->data[i];
|
||||||
|
us->line_buffer[us->line_position] = ch;
|
||||||
|
us->line_position++;
|
||||||
|
|
||||||
|
uint16_t need_len = us->need_len;
|
||||||
|
int16_t end_char = us->end_char;
|
||||||
|
size_t max_wanted =
|
||||||
|
(end_char >= 0 && need_len == 0) ? LUA_MAXINPUT : need_len;
|
||||||
|
bool at_end = (us->line_position >= max_wanted);
|
||||||
|
bool end_char_found =
|
||||||
|
(end_char >= 0 && (uint8_t)ch == (uint8_t)end_char);
|
||||||
|
if (at_end || end_char_found) {
|
||||||
|
uart_on_data_cb(id, us->line_buffer, us->line_position);
|
||||||
|
us->line_position = 0;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_event_task(task_param_t param, task_prio_t prio)
|
||||||
|
{
|
||||||
uart_event_post_t *post = (uart_event_post_t *)param;
|
uart_event_post_t *post = (uart_event_post_t *)param;
|
||||||
unsigned id = post->id;
|
unsigned id = post->id;
|
||||||
uart_status_t *us = &uart_status[id];
|
uart_status_t *us = &uart_status[id];
|
||||||
|
UNADJUST_ID(id);
|
||||||
xSemaphoreGive(sem);
|
xSemaphoreGive(sem);
|
||||||
if(post->type == PLATFORM_UART_EVENT_DATA) {
|
if (post->type == PLATFORM_UART_EVENT_DATA)
|
||||||
size_t i = 0;
|
{
|
||||||
while (i < post->size)
|
handle_uart_data(id, post, us);
|
||||||
{
|
|
||||||
if (id == CONFIG_ESP_CONSOLE_UART_NUM && run_input) {
|
|
||||||
unsigned used = feed_lua_input(post->data + i, post->size - i);
|
|
||||||
i += used;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char ch = post->data[i];
|
|
||||||
us->line_buffer[us->line_position] = ch;
|
|
||||||
us->line_position++;
|
|
||||||
|
|
||||||
uint16_t need_len = us->need_len;
|
|
||||||
int16_t end_char = us->end_char;
|
|
||||||
size_t max_wanted =
|
|
||||||
(end_char >= 0 && need_len == 0) ? LUA_MAXINPUT : need_len;
|
|
||||||
bool at_end = (us->line_position >= max_wanted);
|
|
||||||
bool end_char_found =
|
|
||||||
(end_char >= 0 && (uint8_t)ch == (uint8_t)end_char);
|
|
||||||
if (at_end || end_char_found) {
|
|
||||||
uart_on_data_cb(id, us->line_buffer, us->line_position);
|
|
||||||
us->line_position = 0;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(post->data);
|
free(post->data);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
const char *err;
|
const char *err;
|
||||||
switch(post->type) {
|
switch (post->type)
|
||||||
case PLATFORM_UART_EVENT_OOM:
|
{
|
||||||
err = "out_of_memory";
|
case PLATFORM_UART_EVENT_OOM:
|
||||||
break;
|
err = "out_of_memory";
|
||||||
case PLATFORM_UART_EVENT_BREAK:
|
break;
|
||||||
err = "break";
|
case PLATFORM_UART_EVENT_BREAK:
|
||||||
break;
|
err = "break";
|
||||||
case PLATFORM_UART_EVENT_RX:
|
break;
|
||||||
default:
|
case PLATFORM_UART_EVENT_RX:
|
||||||
err = "rx_error";
|
default:
|
||||||
|
err = "rx_error";
|
||||||
}
|
}
|
||||||
uart_on_error_cb(id, err, strlen(err));
|
uart_on_error_cb(id, err, strlen(err));
|
||||||
}
|
}
|
||||||
free(post);
|
free(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||||
|
void usbcdc_event_task(task_param_t param, task_prio_t prio)
|
||||||
|
{
|
||||||
|
uart_event_post_t *post = (uart_event_post_t *)param;
|
||||||
|
xSemaphoreGive(usbcdc_sem);
|
||||||
|
handle_uart_data(0, post, &usbcdc_status);
|
||||||
|
free(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void task_usbcdc(void *pvParameters) {
|
||||||
|
// 4 chosen as a number smaller than the number of nodemcu task slots
|
||||||
|
// available, to make it unlikely we encounter a task_post failing
|
||||||
|
if (usbcdc_sem == NULL)
|
||||||
|
usbcdc_sem = xSemaphoreCreateCounting(4, 4);
|
||||||
|
|
||||||
|
uart_event_post_t *post = NULL;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (post == NULL) {
|
||||||
|
post = (uart_event_post_t *)malloc(sizeof(uart_event_post_t) + 64 * sizeof(char));
|
||||||
|
if (post == NULL) {
|
||||||
|
ESP_LOGE(UART_TAG, "Can not alloc memory in task_usbcdc()");
|
||||||
|
// reboot here?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
post->data = (void *)(post + 1);
|
||||||
|
post->type = PLATFORM_UART_EVENT_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = usb_serial_jtag_read_bytes(post->data, 64, portMAX_DELAY);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (post->data[i] == '\r') {
|
||||||
|
post->data[i] = '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post->size = len;
|
||||||
|
xSemaphoreTake(usbcdc_sem, portMAX_DELAY);
|
||||||
|
if (!task_post_medium(usbcdc_event_task_id, (task_param_t)post))
|
||||||
|
{
|
||||||
|
ESP_LOGE(UART_TAG, "Task event overrun in task_usbcdc()");
|
||||||
|
xSemaphoreGive(usbcdc_sem);
|
||||||
|
} else {
|
||||||
|
post = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void task_uart( void *pvParameters ){
|
static void task_uart( void *pvParameters ){
|
||||||
unsigned id = (unsigned)pvParameters;
|
unsigned id = (unsigned)pvParameters;
|
||||||
|
|
||||||
|
@ -207,6 +290,7 @@ static void task_uart( void *pvParameters ){
|
||||||
// pins must not be null for non-console uart
|
// pins must not be null for non-console uart
|
||||||
uint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int parity, int stopbits, uart_pins_t* pins )
|
uint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int parity, int stopbits, uart_pins_t* pins )
|
||||||
{
|
{
|
||||||
|
ADJUST_IDR(id, baud);
|
||||||
int flow_control = UART_HW_FLOWCTRL_DISABLE;
|
int flow_control = UART_HW_FLOWCTRL_DISABLE;
|
||||||
if(pins->flow_control & PLATFORM_UART_FLOW_CTS) flow_control |= UART_HW_FLOWCTRL_CTS;
|
if(pins->flow_control & PLATFORM_UART_FLOW_CTS) flow_control |= UART_HW_FLOWCTRL_CTS;
|
||||||
if(pins->flow_control & PLATFORM_UART_FLOW_RTS) flow_control |= UART_HW_FLOWCTRL_RTS;
|
if(pins->flow_control & PLATFORM_UART_FLOW_RTS) flow_control |= UART_HW_FLOWCTRL_RTS;
|
||||||
|
@ -258,23 +342,25 @@ uint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int pari
|
||||||
|
|
||||||
void platform_uart_setmode(unsigned id, unsigned mode)
|
void platform_uart_setmode(unsigned id, unsigned mode)
|
||||||
{
|
{
|
||||||
uart_mode_t uartMode;
|
uart_mode_t uartMode;
|
||||||
|
|
||||||
switch(mode)
|
ADJUST_IDR(id,);
|
||||||
{
|
|
||||||
case PLATFORM_UART_MODE_IRDA:
|
switch(mode)
|
||||||
uartMode = UART_MODE_IRDA; break;
|
{
|
||||||
case PLATFORM_UART_MODE_RS485_COLLISION_DETECT:
|
case PLATFORM_UART_MODE_IRDA:
|
||||||
uartMode = UART_MODE_RS485_COLLISION_DETECT; break;
|
uartMode = UART_MODE_IRDA; break;
|
||||||
case PLATFORM_UART_MODE_RS485_APP_CONTROL:
|
case PLATFORM_UART_MODE_RS485_COLLISION_DETECT:
|
||||||
uartMode = UART_MODE_RS485_APP_CTRL; break;
|
uartMode = UART_MODE_RS485_COLLISION_DETECT; break;
|
||||||
case PLATFORM_UART_MODE_HALF_DUPLEX:
|
case PLATFORM_UART_MODE_RS485_APP_CONTROL:
|
||||||
uartMode = UART_MODE_RS485_HALF_DUPLEX; break;
|
uartMode = UART_MODE_RS485_APP_CTRL; break;
|
||||||
case PLATFORM_UART_MODE_UART:
|
case PLATFORM_UART_MODE_HALF_DUPLEX:
|
||||||
default:
|
uartMode = UART_MODE_RS485_HALF_DUPLEX; break;
|
||||||
uartMode = UART_MODE_UART; break;
|
case PLATFORM_UART_MODE_UART:
|
||||||
}
|
default:
|
||||||
uart_set_mode(id, uartMode);
|
uartMode = UART_MODE_UART; break;
|
||||||
|
}
|
||||||
|
uart_set_mode(id, uartMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform_uart_send_multi( unsigned id, const char *data, size_t len )
|
void platform_uart_send_multi( unsigned id, const char *data, size_t len )
|
||||||
|
@ -285,6 +371,7 @@ void platform_uart_send_multi( unsigned id, const char *data, size_t len )
|
||||||
putchar (data[ i ]);
|
putchar (data[ i ]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
ADJUST_ID(id);
|
||||||
uart_write_bytes(id, data, len);
|
uart_write_bytes(id, data, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,16 +380,20 @@ void platform_uart_send( unsigned id, uint8_t data )
|
||||||
{
|
{
|
||||||
if (id == CONFIG_ESP_CONSOLE_UART_NUM)
|
if (id == CONFIG_ESP_CONSOLE_UART_NUM)
|
||||||
putchar (data);
|
putchar (data);
|
||||||
else
|
else {
|
||||||
|
ADJUST_ID(id);
|
||||||
uart_write_bytes(id, (const char *)&data, 1);
|
uart_write_bytes(id, (const char *)&data, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform_uart_flush( unsigned id )
|
void platform_uart_flush( unsigned id )
|
||||||
{
|
{
|
||||||
if (id == CONFIG_ESP_CONSOLE_UART_NUM)
|
if (id == CONFIG_ESP_CONSOLE_UART_NUM)
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
else
|
else {
|
||||||
|
ADJUST_ID(id);
|
||||||
uart_tx_flush(id);
|
uart_tx_flush(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -311,6 +402,57 @@ int platform_uart_start( unsigned id )
|
||||||
if(uart_event_task_id == 0)
|
if(uart_event_task_id == 0)
|
||||||
uart_event_task_id = task_get_id( uart_event_task );
|
uart_event_task_id = task_get_id( uart_event_task );
|
||||||
|
|
||||||
|
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||||
|
if (id == 0) {
|
||||||
|
if (usbcdc_event_task_id == 0) {
|
||||||
|
usbcdc_event_task_id = task_get_id(usbcdc_event_task);
|
||||||
|
|
||||||
|
|
||||||
|
/* Disable buffering on stdin */
|
||||||
|
setvbuf(stdin, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||||
|
esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
||||||
|
/* Move the caret to the beginning of the next line on '\n' */
|
||||||
|
esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||||
|
|
||||||
|
/* Enable blocking mode on stdin and stdout */
|
||||||
|
fcntl(fileno(stdout), F_SETFL, 0);
|
||||||
|
fcntl(fileno(stdin), F_SETFL, 0);
|
||||||
|
|
||||||
|
usb_serial_jtag_driver_config_t usb_serial_jtag_config;
|
||||||
|
usb_serial_jtag_config.rx_buffer_size = 1024;
|
||||||
|
usb_serial_jtag_config.tx_buffer_size = 1024;
|
||||||
|
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
/* Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes */
|
||||||
|
ret = usb_serial_jtag_driver_install(&usb_serial_jtag_config);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell vfs to use usb-serial-jtag driver */
|
||||||
|
esp_vfs_usb_serial_jtag_use_driver();
|
||||||
|
}
|
||||||
|
usbcdc_status.line_buffer = malloc(LUA_MAXINPUT);
|
||||||
|
usbcdc_status.line_position = 0;
|
||||||
|
if(usbcdc_status.line_buffer == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *pcName = "usbcdc";
|
||||||
|
if(xTaskCreate(task_usbcdc, pcName, 4096, (void*)id, ESP_TASK_MAIN_PRIO + 1, &usbcdc_status.taskHandle) != pdPASS) {
|
||||||
|
free(usbcdc_status.line_buffer);
|
||||||
|
usbcdc_status.line_buffer = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ADJUST_IDR(id, -1);
|
||||||
|
|
||||||
uart_status_t *us = & uart_status[id];
|
uart_status_t *us = & uart_status[id];
|
||||||
|
|
||||||
esp_err_t ret = uart_driver_install(id, uart_buf_sz_cfg[id].rx_buf_sz, uart_buf_sz_cfg[id].tx_buf_sz, 3, & us->queue, 0);
|
esp_err_t ret = uart_driver_install(id, uart_buf_sz_cfg[id].rx_buf_sz, uart_buf_sz_cfg[id].tx_buf_sz, 3, & us->queue, 0);
|
||||||
|
@ -342,6 +484,7 @@ void platform_uart_stop( unsigned id )
|
||||||
if (id == CONFIG_ESP_CONSOLE_UART_NUM)
|
if (id == CONFIG_ESP_CONSOLE_UART_NUM)
|
||||||
;
|
;
|
||||||
else {
|
else {
|
||||||
|
ADJUST_IDR(id,);
|
||||||
uart_status_t *us = & uart_status[id];
|
uart_status_t *us = & uart_status[id];
|
||||||
uart_driver_delete(id);
|
uart_driver_delete(id);
|
||||||
if(us->line_buffer) free(us->line_buffer);
|
if(us->line_buffer) free(us->line_buffer);
|
||||||
|
@ -354,6 +497,19 @@ void platform_uart_stop( unsigned id )
|
||||||
int platform_uart_get_config(unsigned id, uint32_t *baudp, uint32_t *databitsp, uint32_t *parityp, uint32_t *stopbitsp) {
|
int platform_uart_get_config(unsigned id, uint32_t *baudp, uint32_t *databitsp, uint32_t *parityp, uint32_t *stopbitsp) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||||
|
if (id == 0) {
|
||||||
|
// Return dummy values
|
||||||
|
*baudp = 115200;
|
||||||
|
*databitsp = 8;
|
||||||
|
*parityp = PLATFORM_UART_PARITY_NONE;
|
||||||
|
*stopbitsp = PLATFORM_UART_STOPBITS_1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ADJUST_IDR(id, -1);
|
||||||
|
|
||||||
err = uart_get_baudrate(id, baudp);
|
err = uart_get_baudrate(id, baudp);
|
||||||
if (err != ESP_OK) return -1;
|
if (err != ESP_OK) return -1;
|
||||||
*baudp &= 0xFFFFFFFE; // round down
|
*baudp &= 0xFFFFFFFE; // round down
|
||||||
|
@ -403,6 +559,7 @@ int platform_uart_get_config(unsigned id, uint32_t *baudp, uint32_t *databitsp,
|
||||||
|
|
||||||
int platform_uart_set_wakeup_threshold(unsigned id, unsigned threshold)
|
int platform_uart_set_wakeup_threshold(unsigned id, unsigned threshold)
|
||||||
{
|
{
|
||||||
|
ADJUST_IDR(id, 0);
|
||||||
esp_err_t err = uart_set_wakeup_threshold(id, threshold);
|
esp_err_t err = uart_set_wakeup_threshold(id, threshold);
|
||||||
return (err == ESP_OK) ? 0 : -1;
|
return (err == ESP_OK) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue