| uint32_t started_micros; // testing only | uint32_t started_micros; // testing only | ||||
| private: | private: | ||||
| USBDriver *driver; | USBDriver *driver; | ||||
| USBHIDInput *hidinput; | |||||
| USBHIDInput *hidinput; | |||||
| uint32_t usec; | uint32_t usec; | ||||
| USBDriverTimer *next; | USBDriverTimer *next; | ||||
| USBDriverTimer *prev; | USBDriverTimer *prev; | ||||
| }; | }; | ||||
| MIDIDeviceBase(USBHost &host, uint32_t *rx, uint32_t *tx1, uint32_t *tx2, | MIDIDeviceBase(USBHost &host, uint32_t *rx, uint32_t *tx1, uint32_t *tx2, | ||||
| uint16_t bufsize, uint32_t *rqueue, uint16_t qsize) : | uint16_t bufsize, uint32_t *rqueue, uint16_t qsize) : | ||||
| rx_buffer(rx), tx_buffer1(tx1), tx_buffer2(tx2), | |||||
| txtimer(this), rx_buffer(rx), tx_buffer1(tx1), tx_buffer2(tx2), | |||||
| rx_queue(rqueue), max_packet_size(bufsize), rx_queue_size(qsize) { | rx_queue(rqueue), max_packet_size(bufsize), rx_queue_size(qsize) { | ||||
| init(); | init(); | ||||
| } | } | ||||
| protected: | protected: | ||||
| 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 disconnect(); | virtual void disconnect(); | ||||
| virtual void timer_event(USBDriverTimer *timer); | |||||
| 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); | ||||
| void rx_data(const Transfer_t *transfer); | void rx_data(const Transfer_t *transfer); | ||||
| private: | private: | ||||
| Pipe_t *rxpipe; | Pipe_t *rxpipe; | ||||
| Pipe_t *txpipe; | Pipe_t *txpipe; | ||||
| USBDriverTimer txtimer; | |||||
| //enum { MAX_PACKET_SIZE = 64 }; | //enum { MAX_PACKET_SIZE = 64 }; | ||||
| //enum { RX_QUEUE_SIZE = 80 }; // must be more than MAX_PACKET_SIZE/4 | //enum { RX_QUEUE_SIZE = 80 }; // must be more than MAX_PACKET_SIZE/4 | ||||
| //uint32_t rx_buffer[MAX_PACKET_SIZE/4]; | //uint32_t rx_buffer[MAX_PACKET_SIZE/4]; |
| USBHS_PERIODICLISTBASE = (uint32_t)periodictable; | USBHS_PERIODICLISTBASE = (uint32_t)periodictable; | ||||
| USBHS_FRINDEX = 0; | USBHS_FRINDEX = 0; | ||||
| USBHS_ASYNCLISTADDR = 0; | USBHS_ASYNCLISTADDR = 0; | ||||
| USBHS_USBCMD = USBHS_USBCMD_ITC(8) | USBHS_USBCMD_RS | | |||||
| USBHS_USBCMD = USBHS_USBCMD_ITC(0) | USBHS_USBCMD_RS | | |||||
| USBHS_USBCMD_ASP(3) | USBHS_USBCMD_ASPE | USBHS_USBCMD_PSE | | USBHS_USBCMD_ASP(3) | USBHS_USBCMD_ASPE | USBHS_USBCMD_PSE | | ||||
| #if PERIODIC_LIST_SIZE == 8 | #if PERIODIC_LIST_SIZE == 8 | ||||
| USBHS_USBCMD_FS2 | USBHS_USBCMD_FS(3); | USBHS_USBCMD_FS2 | USBHS_USBCMD_FS(3); |
| if (!txpipe) return; | if (!txpipe) return; | ||||
| uint32_t tx_max = tx_size / 4; | uint32_t tx_max = tx_size / 4; | ||||
| while (1) { | while (1) { | ||||
| __disable_irq(); | |||||
| uint32_t tx1 = tx1_count; | uint32_t tx1 = tx1_count; | ||||
| uint32_t tx2 = tx2_count; | uint32_t tx2 = tx2_count; | ||||
| if (tx1 < tx_max && (tx2 == 0 || tx2 >= tx_max)) { | if (tx1 < tx_max && (tx2 == 0 || tx2 >= tx_max)) { | ||||
| // use tx_buffer1 | // use tx_buffer1 | ||||
| tx_buffer1[tx1++] = data; | tx_buffer1[tx1++] = data; | ||||
| tx1_count = tx1; | tx1_count = tx1; | ||||
| __disable_irq(); | |||||
| txtimer.stop(); | |||||
| if (tx1 >= tx_max) { | if (tx1 >= tx_max) { | ||||
| queue_Data_Transfer(txpipe, tx_buffer1, tx_max*4, this); | queue_Data_Transfer(txpipe, tx_buffer1, tx_max*4, this); | ||||
| } else { | } else { | ||||
| // TODO: start a timer, rather than sending the buffer | |||||
| // before it's full, to make best use of bandwidth | |||||
| tx1_count = tx_max; | |||||
| queue_Data_Transfer(txpipe, tx_buffer1, tx_max*4, this); | |||||
| txtimer.start(tx_max >= 128 ? 200 : 1500); | |||||
| } | } | ||||
| __enable_irq(); | |||||
| __enable_irq(); | |||||
| return; | return; | ||||
| } | } | ||||
| if (tx2 < tx_max) { | if (tx2 < tx_max) { | ||||
| // use tx_buffer2 | // use tx_buffer2 | ||||
| tx_buffer2[tx2++] = data; | tx_buffer2[tx2++] = data; | ||||
| tx2_count = tx2; | tx2_count = tx2; | ||||
| __disable_irq(); | |||||
| txtimer.stop(); | |||||
| if (tx2 >= tx_max) { | if (tx2 >= tx_max) { | ||||
| queue_Data_Transfer(txpipe, tx_buffer2, tx_max*4, this); | queue_Data_Transfer(txpipe, tx_buffer2, tx_max*4, this); | ||||
| } else { | } else { | ||||
| // TODO: start a timer, rather than sending the buffer | |||||
| // before it's full, to make best use of bandwidth | |||||
| tx2_count = tx_max; | |||||
| queue_Data_Transfer(txpipe, tx_buffer2, tx_max*4, this); | |||||
| txtimer.start(tx_max >= 128 ? 200 : 1500); | |||||
| } | } | ||||
| __enable_irq(); | |||||
| __enable_irq(); | |||||
| return; | return; | ||||
| } | } | ||||
| __enable_irq(); | |||||
| // TODO: call yield() ?? | |||||
| } | |||||
| } | |||||
| void MIDIDeviceBase::timer_event(USBDriverTimer *timer) | |||||
| { | |||||
| const uint32_t tx_max = tx_size / 4; | |||||
| uint32_t tx1 = tx1_count; | |||||
| if (tx1 > 0) { | |||||
| tx1_count = tx_max; | |||||
| queue_Data_Transfer(txpipe, tx_buffer1, tx1*4, this); | |||||
| } | |||||
| uint32_t tx2 = tx2_count; | |||||
| if (tx2 > 0) { | |||||
| tx2_count = tx_max; | |||||
| queue_Data_Transfer(txpipe, tx_buffer2, tx2*4, this); | |||||
| } | } | ||||
| } | } | ||||