USBDriverTimer(USBDriver *d) : driver(d) { } | USBDriverTimer(USBDriver *d) : driver(d) { } | ||||
void init(USBDriver *d) { driver = d; }; | void init(USBDriver *d) { driver = d; }; | ||||
void start(uint32_t microseconds); | void start(uint32_t microseconds); | ||||
void stop(); | |||||
void *pointer; | void *pointer; | ||||
uint32_t integer; | uint32_t integer; | ||||
uint32_t started_micros; // testing only | uint32_t started_micros; // testing only | ||||
class USBSerial: public USBDriver, public Stream { | class USBSerial: public USBDriver, public Stream { | ||||
public: | public: | ||||
enum { BUFFER_SIZE = 390 }; // must hold at least 6 max size packets, plus 2 extra bytes | enum { BUFFER_SIZE = 390 }; // must hold at least 6 max size packets, plus 2 extra bytes | ||||
USBSerial(USBHost &host) { init(); } | |||||
USBSerial(USBHost &host) : txtimer(this) { init(); } | |||||
void begin(uint32_t baud, uint32_t format=0); | void begin(uint32_t baud, uint32_t format=0); | ||||
void end(void); | void end(void); | ||||
virtual int available(void); | virtual int available(void); | ||||
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); | virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); | ||||
virtual void control(const Transfer_t *transfer); | virtual void control(const Transfer_t *transfer); | ||||
virtual void disconnect(); | virtual void disconnect(); | ||||
virtual void timer_event(USBDriverTimer *whichTimer); | |||||
private: | private: | ||||
static void rx_callback(const Transfer_t *transfer); | static void rx_callback(const Transfer_t *transfer); | ||||
static void tx_callback(const Transfer_t *transfer); | static void tx_callback(const Transfer_t *transfer); | ||||
private: | private: | ||||
Pipe_t mypipes[3] __attribute__ ((aligned(32))); | Pipe_t mypipes[3] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | ||||
USBDriverTimer txtimer; | |||||
uint32_t bigbuffer[(BUFFER_SIZE+3)/4]; | uint32_t bigbuffer[(BUFFER_SIZE+3)/4]; | ||||
setup_t setup; | setup_t setup; | ||||
uint8_t setupdata[8]; | uint8_t setupdata[8]; |
list->next = this; | list->next = this; | ||||
} | } | ||||
void USBDriverTimer::stop() | |||||
{ | |||||
__disable_irq(); | |||||
if (active_timers) { | |||||
if (active_timers == this) { | |||||
USBHS_GPTIMER1CTL = 0; | |||||
if (next) { | |||||
uint32_t usec_til_next = USBHS_GPTIMER1CTL & 0xFFFFFF; | |||||
usec_til_next += next->usec; | |||||
next->usec = usec_til_next; | |||||
USBHS_GPTIMER1LD = usec_til_next; | |||||
USBHS_GPTIMER1CTL = USBHS_GPTIMERCTL_RST | USBHS_GPTIMERCTL_RUN; | |||||
next->prev = NULL; | |||||
active_timers = next; | |||||
} else { | |||||
active_timers = NULL; | |||||
} | |||||
} else { | |||||
for (USBDriverTimer *t = active_timers->next; t; t = t->next) { | |||||
if (t == this) { | |||||
t->prev->next = t->next; | |||||
if (t->next) { | |||||
t->next->usec += t->usec; | |||||
t->next->prev = t->prev; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
__enable_irq(); | |||||
} | |||||
static uint32_t QH_capabilities1(uint32_t nak_count_reload, uint32_t control_endpoint_flag, | static uint32_t QH_capabilities1(uint32_t nak_count_reload, uint32_t control_endpoint_flag, | ||||
uint32_t max_packet_length, uint32_t head_of_list, uint32_t data_toggle_control, | uint32_t max_packet_length, uint32_t head_of_list, uint32_t data_toggle_control, |
#define print USBHost::print | #define print USBHost::print | ||||
#define println USBHost::println | #define println USBHost::println | ||||
/************************************************************/ | |||||
// Initialization and claiming of devices & interfaces | |||||
/************************************************************/ | |||||
void USBSerial::init() | void USBSerial::init() | ||||
{ | { | ||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
} | } | ||||
/************************************************************/ | |||||
// Control Transfer For Configuration | |||||
/************************************************************/ | |||||
void USBSerial::control(const Transfer_t *transfer) | void USBSerial::control(const Transfer_t *transfer) | ||||
} | } | ||||
} | } | ||||
/************************************************************/ | |||||
// Interrupt-based Data Movement | |||||
/************************************************************/ | |||||
void USBSerial::rx_callback(const Transfer_t *transfer) | void USBSerial::rx_callback(const Transfer_t *transfer) | ||||
{ | { | ||||
if (!transfer->driver) return; | if (!transfer->driver) return; | ||||
println("tx2:"); | println("tx2:"); | ||||
txstate &= 0xFD; | txstate &= 0xFD; | ||||
} | } | ||||
// TODO: anything need to be done with latency timeout? | |||||
} | } | ||||
void USBSerial::timer_event(USBDriverTimer *whichTimer) | |||||
{ | |||||
println("txtimer"); | |||||
uint32_t count; | |||||
uint32_t head = txhead; | |||||
uint32_t tail = txtail; | |||||
if (head == tail) { | |||||
return; // nothing to transmit | |||||
} else if (head > tail) { | |||||
count = head - tail; | |||||
} else { | |||||
count = txsize + head - tail; | |||||
} | |||||
uint8_t *p; | |||||
if ((txstate & 0x01) == 0) { | |||||
p = tx1; | |||||
txstate |= 0x01; | |||||
} else if ((txstate & 0x02) == 0) { | |||||
p = tx2; | |||||
txstate |= 0x02; | |||||
} else { | |||||
txtimer.start(1200); | |||||
return; // no outgoing buffers available, try again later | |||||
} | |||||
if (++tail >= txsize) tail = 0; | |||||
uint32_t n = txsize - tail; | |||||
if (n > count) n = count; | |||||
memcpy(p, txbuf + tail, n); | |||||
if (n >= count) { | |||||
tail += n - 1; | |||||
if (tail >= txsize) tail = 0; | |||||
} else { | |||||
uint32_t len = count - n; | |||||
memcpy(p + n, txbuf, len); | |||||
tail = len - 1; | |||||
} | |||||
txtail = tail; | |||||
queue_Data_Transfer(txpipe, p, count, this); | |||||
} | |||||
/************************************************************/ | |||||
// User Functions - must disable USBHQ IRQ for EHCI access | |||||
/************************************************************/ | |||||
void USBSerial::begin(uint32_t baud, uint32_t format) | void USBSerial::begin(uint32_t baud, uint32_t format) | ||||
{ | { | ||||
void USBSerial::end(void) | void USBSerial::end(void) | ||||
{ | { | ||||
// TODO: lower DTR | |||||
} | } | ||||
int USBSerial::available(void) | int USBSerial::available(void) | ||||
return 1; | return 1; | ||||
} | } | ||||
} | } | ||||
// TODO: otherwise set a latency timer to transmit partial packet | |||||
// otherwise, set a latency timer to later transmit partial packet | |||||
txtimer.stop(); | |||||
txtimer.start(3500); | |||||
NVIC_ENABLE_IRQ(IRQ_USBHS); | NVIC_ENABLE_IRQ(IRQ_USBHS); | ||||
return 1; | return 1; | ||||
} | } | ||||