| 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; | ||||
| } | } | ||||