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