413 lines
11 KiB
C
413 lines
11 KiB
C
// vim: set et:
|
|
|
|
#include <tusb.h>
|
|
|
|
#include "mode.h"
|
|
#include "thread.h"
|
|
#include "usbstdio.h"
|
|
#include "vnd_cfg.h"
|
|
|
|
#include "m_default/bsp-feature.h"
|
|
|
|
/* CMSIS-DAP */
|
|
#include "DAP_config.h" /* ARM code *assumes* this is included prior to DAP.h */
|
|
#include "DAP.h"
|
|
/* I2C */
|
|
#include "m_default/i2ctinyusb.h"
|
|
/* CDC UART */
|
|
#include "m_default/cdc.h"
|
|
/* CDC-Serprog */
|
|
#include "m_default/serprog.h"
|
|
/* temperature sensor */
|
|
#include "m_default/tempsensor.h"
|
|
|
|
enum m_default_cmds {
|
|
mdef_cmd_spi = mode_cmd__specific,
|
|
mdef_cmd_i2c,
|
|
mdef_cmd_tempsense,
|
|
mdef_cmd_uart_flowcnt,
|
|
};
|
|
enum m_default_feature {
|
|
mdef_feat_uart = 1<<0,
|
|
mdef_feat_cmsisdap = 1<<1,
|
|
mdef_feat_spi = 1<<2,
|
|
mdef_feat_i2c = 1<<3,
|
|
mdef_feat_tempsense = 1<<4,
|
|
};
|
|
|
|
#ifdef DBOARD_HAS_UART
|
|
static cothread_t uartthread;
|
|
static uint8_t uartstack[THREAD_STACK_SIZE];
|
|
|
|
static void uart_thread_fn(void) {
|
|
cdc_uart_init();
|
|
thread_yield();
|
|
while (1) {
|
|
cdc_uart_task();
|
|
thread_yield();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef DBOARD_HAS_SPI
|
|
static cothread_t serprogthread;
|
|
static uint8_t serprogstack[THREAD_STACK_SIZE];
|
|
|
|
static void serprog_thread_fn(void) {
|
|
cdc_serprog_init();
|
|
thread_yield();
|
|
while (1) {
|
|
cdc_serprog_task();
|
|
thread_yield();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void enter_cb(void) {
|
|
#ifdef USE_USBCDC_FOR_STDIO
|
|
stdio_usb_set_itf_num(CDC_N_STDIO);
|
|
#endif
|
|
vnd_cfg_set_itf_num(VND_N_CFG);
|
|
|
|
// TODO: CMSISDAP?
|
|
#ifdef DBOARD_HAS_I2C
|
|
i2ctu_init();
|
|
#endif
|
|
#ifdef DBOARD_HAS_UART
|
|
uartthread = co_derive(uartstack, sizeof uartstack, uart_thread_fn);
|
|
thread_enter(uartthread); // will call cdc_uart_init() on correct thread
|
|
#endif
|
|
#ifdef DBOARD_HAS_SPI
|
|
serprogthread = co_derive(serprogstack, sizeof serprogstack, serprog_thread_fn);
|
|
thread_enter(serprogthread); // will call cdc_serprog_init() on correct thread
|
|
#endif
|
|
}
|
|
static void leave_cb(void) {
|
|
// TODO: CMSISDAP?
|
|
#ifdef DBOARD_HAS_I2C
|
|
i2ctu_deinit();
|
|
#endif
|
|
#ifdef DBOARD_HAS_UART
|
|
cdc_uart_deinit();
|
|
#endif
|
|
#ifdef DBOARD_HAS_SPI
|
|
cdc_serprog_deinit();
|
|
#endif
|
|
}
|
|
|
|
static void task_cb(void) {
|
|
#ifdef DBOARD_HAS_UART
|
|
tud_task();
|
|
thread_enter(uartthread);
|
|
#endif
|
|
#ifdef DBOARD_HAS_SPI
|
|
tud_task();
|
|
thread_enter(serprogthread);
|
|
#endif
|
|
}
|
|
|
|
static void handle_cmd_cb(uint8_t cmd) {
|
|
uint8_t resp = 0;
|
|
|
|
switch (cmd) {
|
|
case mode_cmd_get_features:
|
|
#ifdef DBOARD_HAS_UART
|
|
resp |= mdef_feat_uart;
|
|
#endif
|
|
#ifdef DBOARD_HAS_CMSISDAP
|
|
resp |= mdef_feat_cmsisdap;
|
|
#endif
|
|
#ifdef DBOARD_HAS_SPI
|
|
resp |= mdef_feat_spi;
|
|
#endif
|
|
#ifdef DBOARD_HAS_I2C
|
|
resp |= mdef_feat_i2c;
|
|
#endif
|
|
#ifdef DBOARD_HAS_TEMPSENSOR
|
|
resp |= mdef_feat_tempsense;
|
|
#endif
|
|
vnd_cfg_write_resp(cfg_resp_ok, 1, &resp);
|
|
break;
|
|
case mdef_cmd_spi:
|
|
#ifdef DBOARD_HAS_SPI
|
|
sp_spi_bulk_cmd();
|
|
#else
|
|
vnd_cfg_write_str(cfg_resp_illcmd, "SPI not implemented on this device");
|
|
#endif
|
|
break;
|
|
case mdef_cmd_i2c:
|
|
#ifdef DBOARD_HAS_I2C
|
|
i2ctu_bulk_cmd();
|
|
#else
|
|
vnd_cfg_write_str(cfg_resp_illcmd, "I2C not implemented on this device");
|
|
#endif
|
|
break;
|
|
case mdef_cmd_tempsense:
|
|
#ifdef DBOARD_HAS_TEMPSENSOR
|
|
tempsense_bulk_cmd();
|
|
#else
|
|
vnd_cfg_write_str(cfg_resp_illcmd, "temperature sensor not implemented on this device");
|
|
#endif
|
|
break;
|
|
case mdef_cmd_uart_flowcnt:
|
|
#ifdef DBOARD_HAS_UART
|
|
if (cdc_uart_set_hwflow(vnd_cfg_read_byte() != 0))
|
|
vnd_cfg_write_resp(cfg_resp_ok, 0, NULL);
|
|
else
|
|
vnd_cfg_write_str(cfg_resp_illcmd, "UART flow control setting not supported on this device");
|
|
#else
|
|
vnd_cfg_write_str(cfg_resp_illcmd, "UART not implemented on this device");
|
|
#endif
|
|
break;
|
|
default:
|
|
vnd_cfg_write_strf(cfg_resp_illcmd, "unknown mode1 command %02x", cmd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define TUD_I2CTINYUSB_LEN (9)
|
|
#define TUD_I2CTINYUSB_DESCRIPTOR(_itfnum, _stridx) \
|
|
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, 0, 0, 0, _stridx \
|
|
|
|
enum {
|
|
STRID_LANGID = 0,
|
|
STRID_MANUFACTURER,
|
|
STRID_PRODUCT,
|
|
STRID_SERIAL,
|
|
|
|
STRID_CONFIG,
|
|
|
|
STRID_IF_VND_CFG,
|
|
STRID_IF_HID_CMSISDAP,
|
|
STRID_IF_VND_I2CTINYUSB,
|
|
STRID_IF_CDC_UART,
|
|
STRID_IF_CDC_SERPROG,
|
|
STRID_IF_CDC_STDIO,
|
|
};
|
|
enum {
|
|
#if CFG_TUD_VENDOR > 0
|
|
ITF_NUM_VND_CFG,
|
|
#endif
|
|
#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB)
|
|
ITF_NUM_VND_I2CTINYUSB,
|
|
#endif
|
|
#ifdef DBOARD_HAS_CMSISDAP
|
|
ITF_NUM_HID_CMSISDAP,
|
|
#endif
|
|
#ifdef DBOARD_HAS_UART
|
|
ITF_NUM_CDC_UART_COM,
|
|
ITF_NUM_CDC_UART_DATA,
|
|
#endif
|
|
#ifdef DBOARD_HAS_SPI
|
|
ITF_NUM_CDC_SERPROG_COM,
|
|
ITF_NUM_CDC_SERPROG_DATA,
|
|
#endif
|
|
#ifdef USE_USBCDC_FOR_STDIO
|
|
ITF_NUM_CDC_STDIO_COM,
|
|
ITF_NUM_CDC_STDIO_DATA,
|
|
#endif
|
|
|
|
ITF_NUM__TOTAL
|
|
};
|
|
enum {
|
|
CONFIG_TOTAL_LEN
|
|
= TUD_CONFIG_DESC_LEN
|
|
#if CFG_TUD_VENDOR > 0
|
|
+ TUD_VENDOR_DESC_LEN
|
|
#endif
|
|
#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB)
|
|
+ TUD_I2CTINYUSB_LEN
|
|
#endif
|
|
#ifdef DBOARD_HAS_CMSISDAP
|
|
+ TUD_HID_INOUT_DESC_LEN
|
|
#endif
|
|
#ifdef DBOARD_HAS_UART
|
|
+ TUD_CDC_DESC_LEN
|
|
#endif
|
|
#ifdef DBOARD_HAS_SPI
|
|
+ TUD_CDC_DESC_LEN
|
|
#endif
|
|
#ifdef USE_USBCDC_FOR_STDIO
|
|
+ TUD_CDC_DESC_LEN
|
|
#endif
|
|
};
|
|
|
|
#define EPNUM_VND_CFG_OUT 0x01
|
|
#define EPNUM_VND_CFG_IN 0x81
|
|
#define EPNUM_HID_CMSISDAP 0x02
|
|
#define EPNUM_CDC_UART_OUT 0x03
|
|
#define EPNUM_CDC_UART_IN 0x83
|
|
#define EPNUM_CDC_UART_NOTIF 0x84
|
|
#define EPNUM_CDC_SERPROG_OUT 0x05
|
|
#define EPNUM_CDC_SERPROG_IN 0x85
|
|
#define EPNUM_CDC_SERPROG_NOTIF 0x86
|
|
#define EPNUM_CDC_STDIO_OUT 0x07
|
|
#define EPNUM_CDC_STDIO_IN 0x87
|
|
#define EPNUM_CDC_STDIO_NOTIF 0x88
|
|
|
|
/*#define EPNUM_CDC_UART_OUT 0x02
|
|
#define EPNUM_CDC_UART_IN 0x82
|
|
#define EPNUM_CDC_UART_NOTIF 0x83
|
|
#define EPNUM_HID_CMSISDAP 0x04
|
|
#define EPNUM_CDC_SERPROG_OUT 0x05
|
|
#define EPNUM_CDC_SERPROG_IN 0x85
|
|
#define EPNUM_CDC_SERPROG_NOTIF 0x86
|
|
#define EPNUM_CDC_STDIO_OUT 0x07
|
|
#define EPNUM_CDC_STDIO_IN 0x87
|
|
#define EPNUM_CDC_STDIO_NOTIF 0x88*/
|
|
|
|
// clang-format off
|
|
#if CFG_TUD_HID > 0
|
|
static const uint8_t desc_hid_report[] = { // ugh
|
|
TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_EP_BUFSIZE)
|
|
};
|
|
#endif
|
|
// TODO: replace magic 64s by actual buffer size macros
|
|
static const uint8_t desc_configuration[] = {
|
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM__TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN,
|
|
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
|
|
|
#if CFG_TUD_VENDOR > 0
|
|
TUD_VENDOR_DESCRIPTOR_EX(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT,
|
|
EPNUM_VND_CFG_IN, CFG_TUD_VENDOR_RX_BUFSIZE, VND_CFG_SUBCLASS, VND_CFG_PROTOCOL),
|
|
#endif
|
|
|
|
#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB)
|
|
TUD_I2CTINYUSB_DESCRIPTOR(ITF_NUM_VND_I2CTINYUSB, STRID_IF_VND_I2CTINYUSB),
|
|
#endif
|
|
|
|
#ifdef DBOARD_HAS_CMSISDAP
|
|
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID_CMSISDAP, STRID_IF_HID_CMSISDAP,
|
|
0 /*HID_PROTOCOL_NONE*/, sizeof(desc_hid_report), EPNUM_HID_CMSISDAP,
|
|
0x80 | (EPNUM_HID_CMSISDAP + 0), CFG_TUD_HID_EP_BUFSIZE, 1),
|
|
#endif
|
|
|
|
#ifdef DBOARD_HAS_UART
|
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, STRID_IF_CDC_UART, EPNUM_CDC_UART_NOTIF,
|
|
CFG_TUD_CDC_RX_BUFSIZE, EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, CFG_TUD_CDC_RX_BUFSIZE),
|
|
#endif
|
|
|
|
#ifdef DBOARD_HAS_SPI
|
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SERPROG_COM, STRID_IF_CDC_SERPROG, EPNUM_CDC_SERPROG_NOTIF,
|
|
CFG_TUD_CDC_RX_BUFSIZE, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, CFG_TUD_CDC_RX_BUFSIZE),
|
|
#endif
|
|
|
|
#ifdef USE_USBCDC_FOR_STDIO
|
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF,
|
|
CFG_TUD_CDC_RX_BUFSIZE, EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, CFG_TUD_CDC_RX_BUFSIZE),
|
|
#endif
|
|
};
|
|
static const char* string_desc_arr[] = {
|
|
/*[STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409)
|
|
[STRID_MANUFACTURER] = "BLAHAJ CTF", // Manufacturer
|
|
[STRID_PRODUCT] = "Dragnbus (RP2040 Pico)", // Product*/
|
|
NULL,
|
|
|
|
[STRID_CONFIG] = "Configuration descriptor",
|
|
// max string length check: |||||||||||||||||||||||||||||||
|
|
[STRID_IF_VND_CFG ] = "Device cfg/ctl interface",
|
|
[STRID_IF_HID_CMSISDAP] = "CMSIS-DAP HID interface",
|
|
[STRID_IF_VND_I2CTINYUSB] = "I2C-Tiny-USB interface",
|
|
[STRID_IF_CDC_UART] = "UART CDC interface",
|
|
[STRID_IF_CDC_SERPROG] = "Serprog CDC interface",
|
|
#ifdef USE_USBCDC_FOR_STDIO
|
|
[STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)",
|
|
#endif
|
|
};
|
|
// clang-format on
|
|
|
|
#ifdef DBOARD_HAS_CMSISDAP
|
|
static const uint8_t* my_hid_descriptor_report_cb(uint8_t instance) {
|
|
(void)instance;
|
|
|
|
return desc_hid_report;
|
|
}
|
|
/*static uint16_t my_hid_get_report_cb(uint8_t instance, uint8_t report_id,
|
|
hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
|
// TODO not implemented
|
|
(void)instance;
|
|
(void)report_id;
|
|
(void)report_type;
|
|
(void)buffer;
|
|
(void)reqlen;
|
|
|
|
return 0;
|
|
}*/
|
|
|
|
static void my_hid_set_report_cb(uint8_t instance, uint8_t report_id,
|
|
hid_report_type_t report_type, uint8_t const* rx_buffer, uint16_t bufsize) {
|
|
static uint8_t tx_buffer[CFG_TUD_HID_EP_BUFSIZE];
|
|
uint32_t response_size = TU_MIN(CFG_TUD_HID_EP_BUFSIZE, bufsize);
|
|
|
|
(void)instance;
|
|
(void)report_id;
|
|
(void)report_type;
|
|
|
|
DAP_ProcessCommand(rx_buffer, tx_buffer);
|
|
|
|
tud_hid_report(0, tx_buffer, response_size);
|
|
}
|
|
#endif
|
|
|
|
#if CFG_TUD_CDC > 0
|
|
static void my_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding) {
|
|
switch (itf) {
|
|
#ifdef DBOARD_HAS_UART
|
|
case CDC_N_UART:
|
|
cdc_uart_set_coding(line_coding->bit_rate, line_coding->stop_bits,
|
|
line_coding->parity, line_coding->data_bits);
|
|
break;
|
|
#endif
|
|
#ifdef DBOARD_HAS_SPI
|
|
case CDC_N_SERPROG:
|
|
break;
|
|
#endif
|
|
#ifdef USE_USBCDC_FOR_STDIO
|
|
case CDC_N_STDIO:
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB)
|
|
static bool my_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
|
tusb_control_request_t const* req) {
|
|
return i2ctu_ctl_req(rhport, ep_addr, req);
|
|
}
|
|
#endif
|
|
|
|
extern struct mode m_01_default;
|
|
// clang-format off
|
|
struct mode m_01_default = {
|
|
.name = "Default mode with misc features",
|
|
.version = 0x0010,
|
|
.n_string_desc = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
|
|
|
|
.usb_desc = desc_configuration,
|
|
.string_desc = string_desc_arr,
|
|
|
|
.enter = enter_cb,
|
|
.leave = leave_cb,
|
|
.task = task_cb,
|
|
.handle_cmd = handle_cmd_cb,
|
|
|
|
#if defined(DBOARD_HAS_CMSISDAP) && CFG_TUD_HID > 0
|
|
#if 0
|
|
.tud_hid_get_report_cb = my_hid_get_report_cb,
|
|
#endif
|
|
.tud_hid_set_report_cb = my_hid_set_report_cb,
|
|
.tud_hid_descriptor_report_cb = my_hid_descriptor_report_cb,
|
|
#endif
|
|
|
|
#if CFG_TUD_CDC > 0
|
|
.tud_cdc_line_coding_cb = my_cdc_line_coding_cb,
|
|
#endif
|
|
|
|
#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB)
|
|
.tud_vendor_control_xfer_cb = i2ctu_ctl_req,
|
|
#endif
|
|
};
|
|
// clang-format on
|
|
|