Convert to threaded operation by default

Rather than polling each interface in turn, execute the interface
handling periodically.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
This commit is contained in:
Jonathan Bell
2022-07-13 15:00:11 +01:00
parent 687ba956f4
commit e698ea5d5c
3 changed files with 102 additions and 25 deletions

View File

@@ -24,11 +24,16 @@
*/
#include <pico/stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "tusb.h"
#include "picoprobe_config.h"
TaskHandle_t uart_taskhandle;
TickType_t last_wake, interval = 100;
static uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE];
static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE];
@@ -40,7 +45,9 @@ void cdc_uart_init(void) {
uart_init(PICOPROBE_UART_INTERFACE, PICOPROBE_UART_BAUDRATE);
}
void cdc_task(void) {
void cdc_task(void)
{
static int was_connected = 0;
uint rx_len = 0;
// Consume uart fifo regardless even if not connected
@@ -49,6 +56,7 @@ void cdc_task(void) {
}
if (tud_cdc_connected()) {
was_connected = 1;
int written = 0;
/* Implicit overflow if we don't write all the bytes to the host.
* Also throw away bytes if we can't write... */
@@ -69,17 +77,50 @@ void cdc_task(void) {
tx_len = tud_cdc_read(tx_buf, watermark);
uart_write_blocking(PICOPROBE_UART_INTERFACE, tx_buf, tx_len);
}
} else {
/* Clear out characters that may be left
- note that this doesn't include buffers already under hardware control */
} else if (was_connected) {
tud_cdc_write_clear();
was_connected = 0;
}
}
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding) {
picoprobe_info("New baud rate %d\n", line_coding->bit_rate);
uart_deinit(PICOPROBE_UART_INTERFACE);
tud_cdc_write_clear();
tud_cdc_read_flush();
uart_init(PICOPROBE_UART_INTERFACE, line_coding->bit_rate);
void cdc_thread(void *ptr)
{
BaseType_t delayed;
last_wake = xTaskGetTickCount();
/* Threaded with a polling interval that scales according to linerate */
while (1) {
cdc_task();
delayed = xTaskDelayUntil(&last_wake, interval);
if (delayed == pdFALSE)
last_wake = xTaskGetTickCount();
}
}
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding)
{
/* Set the tick thread interval to the amount of time it takes to
* fill up half a FIFO. Millis is too coarse for integer divide.
*/
uint32_t micros = (1000 * 1000 * 16 * 10) / MAX(line_coding->bit_rate, 1);
/* Modifying state, so park the thread before changing it. */
vTaskSuspend(uart_taskhandle);
interval = MAX(1, micros / ((1000 * 1000) / configTICK_RATE_HZ));
picoprobe_info("New baud rate %d micros %d interval %u\n",
line_coding->bit_rate, micros, interval);
uart_deinit(PICOPROBE_UART_INTERFACE);
tud_cdc_write_clear();
tud_cdc_read_flush();
uart_init(PICOPROBE_UART_INTERFACE, line_coding->bit_rate);
vTaskResume(uart_taskhandle);
}
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{
/* CDC drivers use linestate as a bodge to activate/deactivate the interface.
* Resume our UART polling on activate, stop on deactivate */
if (!dtr && !rts)
vTaskSuspend(uart_taskhandle);
else
vTaskResume(uart_taskhandle);
}

View File

@@ -26,7 +26,10 @@
#ifndef CDC_UART_H
#define CDC_UART_H
void cdc_thread(void *ptr);
void cdc_uart_init(void);
void cdc_task(void);
extern TaskHandle_t uart_taskhandle;
#endif

View File

@@ -47,9 +47,40 @@
static uint8_t TxDataBuffer[CFG_TUD_HID_EP_BUFSIZE];
static uint8_t RxDataBuffer[CFG_TUD_HID_EP_BUFSIZE];
void dap_task(void);
#define THREADED 1
#define UART_TASK_PRIO (tskIDLE_PRIORITY + 3)
#define TUD_TASK_PRIO (tskIDLE_PRIORITY + 2)
#define DAP_TASK_PRIO (tskIDLE_PRIORITY + 1)
static TaskHandle_t dap_taskhandle, tud_taskhandle;
void usb_thread(void *ptr)
{
do {
tud_task();
// Trivial delay to save power
vTaskDelay(1);
} while (1);
}
void dap_thread(void *ptr)
{
uint32_t resp_len;
do {
if (tud_vendor_available()) {
tud_vendor_read(RxDataBuffer, sizeof(RxDataBuffer));
resp_len = DAP_ProcessCommand(RxDataBuffer, TxDataBuffer);
tud_vendor_write(TxDataBuffer, resp_len);
} else {
// Trivial delay to save power
vTaskDelay(2);
}
} while (1);
}
int main(void) {
uint32_t resp_len;
board_init();
usb_serial_init();
@@ -64,31 +95,33 @@ int main(void) {
picoprobe_info("Welcome to Picoprobe!\n");
while (1) {
tud_task(); // tinyusb device task
if (THREADED) {
/* UART needs to preempt USB as if we don't, characters get lost */
xTaskCreate(cdc_thread, "UART", configMINIMAL_STACK_SIZE, NULL, UART_TASK_PRIO, &uart_taskhandle);
xTaskCreate(usb_thread, "TUD", configMINIMAL_STACK_SIZE, NULL, TUD_TASK_PRIO, &tud_taskhandle);
/* Lowest priority thread is debug - need to shuffle buffers before we can toggle swd... */
xTaskCreate(dap_thread, "DAP", configMINIMAL_STACK_SIZE, NULL, DAP_TASK_PRIO, &dap_taskhandle);
vTaskStartScheduler();
}
while (!THREADED) {
tud_task();
cdc_task();
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM)
probe_task();
led_task();
#elif (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
dap_task();
if (tud_vendor_available()) {
tud_vendor_read(RxDataBuffer, sizeof(RxDataBuffer));
resp_len = DAP_ProcessCommand(RxDataBuffer, TxDataBuffer);
tud_vendor_write(TxDataBuffer, resp_len);
}
#endif
}
return 0;
}
void dap_task(void)
{
uint32_t count;
uint32_t resp_len;
if (tud_vendor_available()) {
count = tud_vendor_read(RxDataBuffer, sizeof(RxDataBuffer));
resp_len = DAP_ProcessCommand(RxDataBuffer, TxDataBuffer);
tud_vendor_write(TxDataBuffer, resp_len);
}
}
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented