initial ftdi stuff
This commit is contained in:
parent
a1561ee35a
commit
45cce4dfff
|
@ -20,7 +20,7 @@
|
|||
#else
|
||||
#define CFG_TUD_CDC 2
|
||||
#endif
|
||||
#define CFG_TUD_VENDOR 1
|
||||
#define CFG_TUD_VENDOR 2
|
||||
|
||||
/* don't access storage for RAM-only builds */
|
||||
#if !PICO_NO_FLASH
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <tusb.h>
|
||||
|
||||
#include "mode.h"
|
||||
#include "thread.h"
|
||||
#include "usbstdio.h"
|
||||
#include "vnd_cfg.h"
|
||||
|
||||
#include "m_ftdi/bsp-feature.h"
|
||||
|
||||
#include "ftdi.h"
|
||||
|
||||
#ifdef DBOARD_HAS_FTDI
|
||||
static cothread_t ftdithread;
|
||||
static uint8_t ftdistack[THREAD_STACK_SIZE];
|
||||
|
||||
static void ftdi_thread_fn(void) {
|
||||
ftdi_init();
|
||||
thread_yield();
|
||||
while (1) {
|
||||
ftdi_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);
|
||||
|
||||
#ifdef DBOARD_HAS_FTDI
|
||||
ftdithread = co_derive(ftdistack, sizeof ftdistack, ftdi_thread_fn);
|
||||
thread_enter(ftdithread);
|
||||
#endif
|
||||
}
|
||||
static void leave_cb(void) {
|
||||
#ifdef DBOARD_HAS_FTDI
|
||||
ftdi_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void task_cb(void) {
|
||||
#ifdef DBOARD_HAS_FTDI
|
||||
ftdi_task();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void handle_cmd_cb(uint8_t cmd) {
|
||||
switch (cmd) {
|
||||
default:
|
||||
vnd_cfg_write_strf(cfg_resp_illcmd, "unknown mode5 command %02x", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
STRID_LANGID = 0,
|
||||
STRID_MANUFACTURER,
|
||||
STRID_PRODUCT,
|
||||
STRID_SERIAL,
|
||||
|
||||
STRID_CONFIG,
|
||||
|
||||
STRID_IF_VND_CFG,
|
||||
STRID_IF_VND_FTDI_IFA,
|
||||
STRID_IF_VND_FTDI_IFB,
|
||||
STRID_IF_CDC_STDIO,
|
||||
};
|
||||
enum {
|
||||
ITF_NUM_VND_FTDI_IFA,
|
||||
ITF_NUM_VND_FTDI_IFB,
|
||||
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
ITF_NUM_VND_CFG,
|
||||
#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
|
||||
+ TUD_VENDOR_DESC_LEN
|
||||
+ TUD_VENDOR_DESC_LEN
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
+ TUD_VENDOR_DESC_LEN
|
||||
#endif
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
+ TUD_CDC_DESC_LEN
|
||||
#endif
|
||||
};
|
||||
|
||||
#define EPNUM_VND_FTDI_IFA_OUT 0x02
|
||||
#define EPNUM_VND_FTDI_IFA_IN 0x81
|
||||
#define EPNUM_VND_FTDI_IFB_OUT 0x04
|
||||
#define EPNUM_VND_FTDI_IFB_IN 0x83
|
||||
|
||||
#define EPNUM_VND_CFG_OUT 0x05
|
||||
#define EPNUM_VND_CFG_IN 0x85
|
||||
#define EPNUM_CDC_STDIO_OUT 0x06
|
||||
#define EPNUM_CDC_STDIO_IN 0x86
|
||||
#define EPNUM_CDC_STDIO_NOTIF 0x87
|
||||
|
||||
// clang-format off
|
||||
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),
|
||||
|
||||
TUD_VENDOR_DESCRIPTOR_EX(ITF_NUM_VND_FTDI_IFA, STRID_IF_VND_FTDI_IFA,
|
||||
EPNUM_VND_FTDI_IFA_OUT, EPNUM_VND_FTDI_IFA_IN, CFG_TUD_VENDOR_RX_BUFSIZE, 255, 255),
|
||||
TUD_VENDOR_DESCRIPTOR_EX(ITF_NUM_VND_FTDI_IFB, STRID_IF_VND_FTDI_IFB,
|
||||
EPNUM_VND_FTDI_IFB_OUT, EPNUM_VND_FTDI_IFB_IN, CFG_TUD_VENDOR_RX_BUFSIZE, 255, 255),
|
||||
|
||||
#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
|
||||
|
||||
#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[] = {
|
||||
NULL,
|
||||
|
||||
[STRID_CONFIG] = "Configuration descriptor",
|
||||
// max string length check: |||||||||||||||||||||||||||||||
|
||||
[STRID_IF_VND_CFG ] = "Device cfg/ctl interface",
|
||||
[STRID_IF_VND_FTDI_IFA] = "FT2232C interface A",
|
||||
[STRID_IF_VND_FTDI_IFB] = "FT2232C interface B",
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
[STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)",
|
||||
#endif
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static const tusb_desc_device_t desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0110, // TODO: 0x0200 ? is an eeprom option
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = 0x0403, // ?
|
||||
.idProduct = 0x6010, // ?
|
||||
.bcdDevice = 0x0500, // required!
|
||||
|
||||
.iManufacturer = STRID_MANUFACTURER,
|
||||
.iProduct = STRID_PRODUCT,
|
||||
.iSerialNumber = STRID_SERIAL,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
static const uint8_t* my_descriptor_device_cb(void) {
|
||||
return (const uint8_t*)&desc_device;
|
||||
}
|
||||
|
||||
extern struct mode m_05_ftdi;
|
||||
// clang-format off
|
||||
struct mode m_05_ftdi = {
|
||||
.name = "FTDI FT2232C (single-channel) emulation mode",
|
||||
.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,
|
||||
|
||||
#ifdef DBOARD_HAS_FTDI
|
||||
.tud_descriptor_device_cb = my_descriptor_device_cb,
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_FTDI
|
||||
.tud_vendor_control_xfer_cb = ftdi_control_xfer_cb,
|
||||
#endif
|
||||
};
|
||||
// clang-format on
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
#include "tusb_config.h"
|
||||
#include <tusb.h>
|
||||
|
||||
// for handling USB bulk commands
|
||||
void ftdi_init(void) {
|
||||
|
||||
}
|
||||
void ftdi_deinit(void) {
|
||||
|
||||
}
|
||||
void ftdi_task(void) {
|
||||
|
||||
}
|
||||
|
||||
bool ftdi_control_xfer_cb(uint8_t rhport, uint8_t stage,
|
||||
tusb_control_request_t const* req) {
|
||||
// return true: don't stall
|
||||
// return false: stall
|
||||
|
||||
// not a vendor request -> not meant for this code
|
||||
if (req->bmRequestType_bit.type != TUSB_REQ_TYPE_VENDOR) return true;
|
||||
|
||||
// index = interface number (A/B)
|
||||
// out/in bRequest wValue wIndex data wLength
|
||||
// RESET: out 0 0 index
|
||||
// TCIFLUSH: out 0 2 index
|
||||
// TCOFLUSH: out 0 1 index
|
||||
// SETMODEMCTRL:out 1 (mask:8<<8 | data:8) // bit0=dtr bit1=rts
|
||||
// SETFLOWCTRL: out 2 xon?1:0 (flowctrl | index) // flowctrl: 0=disable, 1=ctsrts, 2=dtrdsr 4=xonxoff FROM VALUE, not set/reset!
|
||||
// SETBAUDRATE: out 3 brate index // 48 MHz clocks, /16?
|
||||
// SETLINEPROP: out 4 (break:1<<14 | stop:2<<11 | parity:3<<8 | bits:8) ; break: off/on, stop=1/15/2, parity=none/odd/even/mark/space; bits=7/8
|
||||
// POLLMODEMSTAT:in 5 0 index &modemstat len=2 // first byte: bit0..3=0 bit4=cts bit5=dts bit6=ri bit7=rlsd ; second byte: bit0=dr bit1=oe bit2=pe bit3=fe bit4=bi bit5=thre bit6=temt bit7=fifoerr
|
||||
// SETEVENTCHAR:out 6 (endis:1<<8 | char)
|
||||
// SETERRORCHAR:out 7 (endir:1<<8 | char)
|
||||
// <there is no bReqest 8>
|
||||
// SETLATENCY: out 9 latency(1..255)
|
||||
// GETLATENCY: in 0xa 0 index &latency len=1
|
||||
// SETBITBANG: out 0xb dirmask:8<<8 | mode:8 // mode: MPSSE mode: 0=serial/fifo, 1=bitbang, 2=mpsse, 4=syncbb, (8=mcu 16=opto)
|
||||
// READPINS: in 0xc 0 index &pins len=1
|
||||
// READEEPROM: in 0x90 0 eepaddr &val 2 // eepaddr in 16-bit units(?)
|
||||
// WRITEEEPROM: out 0x91 value eepaddr
|
||||
// ERASEEEPROM: out 0x92 0 0
|
||||
|
||||
// eeprom layout:
|
||||
// max size is 128 words (256 bytes), little-endian
|
||||
// 00: type, driver, .. stuff (chanA byte, chanB byte)
|
||||
// 01: VID
|
||||
// 02: PID
|
||||
// 03: bcdDevice
|
||||
// 04: byte08: flags: bit7=1 bit6=1=selfpowered bit5=1=remotewakeup ; byte09=max power, 2mA units
|
||||
// 05: bit0=epin isochr, bit1=epout isochr, bit2=suspend pulldn, bit3=serialno use, bit4=usbver change, bit5..7=0
|
||||
// 06: USB version
|
||||
// 07: byte0E=manufstr.off-0x80, byte0F=manufstr.len (in bytes, but 16-bit ascii)
|
||||
// 08: ^ but product
|
||||
// 09: ^ but serial
|
||||
// 0a: chip type (66 etc)
|
||||
// TODO: checksum
|
||||
|
||||
// ftdi_write_data(), ftdi_read_data(): bulk xfer
|
||||
|
||||
// input/tristate: 200K pullup
|
||||
// SI/WU: let's ignore this
|
||||
// UART mode: standard stuff
|
||||
// FIFO mode: RDF#=0: enable output. RD# rising when RXF#=0: fetch next byte
|
||||
// TXF#=0: enable input. WR falling when TXF#=0: write byte
|
||||
// bitbang mode: ^ similar, no RDF#/TXF#, RD#/WR# (now WR# jenai WR) pos depends on UART mode std (UART vs FIFO)
|
||||
// sync bitbang: doesn't use RD#/WR#, clocked by baudrate control
|
||||
// MPSSE: lots of magic. TCK/SK, TDI/DO, TDO/DI, TMS/CS, GPIOL0..3, GPIOH0..3(7?)
|
||||
|
||||
// bulk xfer formats:
|
||||
// * UART: ok I guess
|
||||
// * FIFO: same
|
||||
// * bitbang, sync bitbang: ???? (just data or also clock stuff?? ?)
|
||||
// * MPSSE: see separate PDF
|
||||
|
||||
switch (stage) {
|
||||
case CONTROL_STAGE_SETUP:
|
||||
// tud_control_status(rhport, req); : acknowledge
|
||||
// tud_control_xfer(rhport, req, bufaddr, size); : ack + there's a data phase with stuff to do
|
||||
// write: send bufaddr value. read: data stage will have bufaddr filled out
|
||||
return false; // stall if not recognised
|
||||
case CONTROL_STAGE_DATA:
|
||||
// TODO: stuff?
|
||||
// 'bufaddr' from setup stage is now filled in for reads
|
||||
return true;
|
||||
default: return true; // ignore
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// vim: set et:
|
||||
|
||||
#ifndef FTDI_H_
|
||||
#define FTDI_H_
|
||||
|
||||
#include "tusb_config.h"
|
||||
#include <tusb.h>
|
||||
|
||||
// for handling USB bulk commands
|
||||
void ftdi_init(void);
|
||||
void ftdi_deinit(void);
|
||||
void ftdi_task(void);
|
||||
|
||||
bool ftdi_control_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
||||
tusb_control_request_t const* req);
|
||||
|
||||
#endif
|
||||
|
|
@ -39,7 +39,7 @@ struct mode {
|
|||
void (*tud_cdc_line_coding_cb)(uint8_t itf, cdc_line_coding_t const* line_coding);
|
||||
#endif
|
||||
//#if CFG_TUD_VENDOR > 0
|
||||
bool (*tud_vendor_control_xfer_cb)(uint8_t rhport, uint8_t ep_addr,
|
||||
bool (*tud_vendor_control_xfer_cb)(uint8_t rhport, uint8_t stage,
|
||||
tusb_control_request_t const* req);
|
||||
//#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue