| @@ -72,15 +72,13 @@ static uint8_t rx_buffer[RX_NUM * CDC_RX_SIZE_480]; | |||
| static uint16_t rx_count[RX_NUM]; | |||
| static uint16_t rx_index[RX_NUM]; | |||
| static uint16_t rx_packet_size=0; | |||
| static volatile uint8_t rx_head; | |||
| static volatile uint8_t rx_tail; | |||
| static uint8_t rx_list[RX_NUM + 1]; | |||
| static volatile uint32_t rx_available; | |||
| static void rx_queue_transfer(int i); | |||
| static void rx_event(transfer_t *t); | |||
| static void rx_event(transfer_t *t) | |||
| { | |||
| int len = rx_packet_size - ((t->status >> 16) & 0x7FFF); | |||
| int index = t->callback_param; | |||
| //printf("rx event, len=%d, i=%d\n", len, index); | |||
| rx_count[index] = len; | |||
| rx_index[index] = 0; | |||
| } | |||
| void usb_serial_reset(void) | |||
| { | |||
| @@ -90,6 +88,8 @@ void usb_serial_reset(void) | |||
| void usb_serial_configure(void) | |||
| { | |||
| int i; | |||
| printf("usb_serial_configure\n"); | |||
| if (usb_high_speed) { | |||
| tx_packet_size = CDC_TX_SIZE_480; | |||
| @@ -104,73 +104,162 @@ void usb_serial_configure(void) | |||
| memset(rx_transfer, 0, sizeof(rx_transfer)); | |||
| memset(rx_count, 0, sizeof(rx_count)); | |||
| memset(rx_index, 0, sizeof(rx_index)); | |||
| rx_head = 0; | |||
| rx_tail = 0; | |||
| rx_available = 0; | |||
| usb_config_tx(CDC_ACM_ENDPOINT, CDC_ACM_SIZE, 0, NULL); // size same 12 & 480 | |||
| usb_config_rx(CDC_RX_ENDPOINT, rx_packet_size, 0, rx_event); | |||
| usb_config_tx(CDC_TX_ENDPOINT, tx_packet_size, 1, NULL); | |||
| usb_prepare_transfer(rx_transfer + 0, rx_buffer + 0, rx_packet_size, 0); | |||
| usb_receive(CDC_RX_ENDPOINT, rx_transfer + 0); | |||
| for (i=0; i < RX_NUM; i++) rx_queue_transfer(i); | |||
| timer_config(usb_serial_flush_callback, TRANSMIT_FLUSH_TIMEOUT); | |||
| } | |||
| // get the next character, or -1 if nothing received | |||
| int usb_serial_getchar(void) | |||
| /*************************************************************************/ | |||
| /** Receive **/ | |||
| /*************************************************************************/ | |||
| static void rx_queue_transfer(int i) | |||
| { | |||
| if (rx_index[0] < rx_count[0]) { | |||
| int c = rx_buffer[rx_index[0]++]; | |||
| if (rx_index[0] >= rx_count[0]) { | |||
| // reschedule transfer | |||
| usb_prepare_transfer(rx_transfer + 0, rx_buffer + 0, rx_packet_size, 0); | |||
| usb_receive(CDC_RX_ENDPOINT, rx_transfer + 0); | |||
| } | |||
| return c; | |||
| } | |||
| return -1; | |||
| NVIC_DISABLE_IRQ(IRQ_USB1); | |||
| printf("rx queue i=%d\n", i); | |||
| usb_prepare_transfer(rx_transfer + i, rx_buffer + i * CDC_RX_SIZE_480, rx_packet_size, i); | |||
| usb_receive(CDC_RX_ENDPOINT, rx_transfer + i); | |||
| NVIC_ENABLE_IRQ(IRQ_USB1); | |||
| } | |||
| // peek at the next character, or -1 if nothing received | |||
| int usb_serial_peekchar(void) | |||
| // called by USB interrupt when any packet is received | |||
| static void rx_event(transfer_t *t) | |||
| { | |||
| if (rx_index[0] < rx_count[0]) { | |||
| return rx_buffer[rx_index[0]]; | |||
| int len = rx_packet_size - ((t->status >> 16) & 0x7FFF); | |||
| int i = t->callback_param; | |||
| printf("rx event, len=%d, i=%d\n", len, i); | |||
| if (len > 0) { | |||
| // received a packet with data | |||
| uint32_t head = rx_head; | |||
| if (head != rx_tail) { | |||
| // a previous packet is still buffered | |||
| uint32_t ii = rx_list[head]; | |||
| uint32_t count = rx_count[ii]; | |||
| if (len <= CDC_RX_SIZE_480 - count) { | |||
| // previous buffer has enough free space for this packet's data | |||
| memcpy(rx_buffer + ii * CDC_RX_SIZE_480 + count, | |||
| rx_buffer + i * CDC_RX_SIZE_480, len); | |||
| rx_count[ii] = count + len; | |||
| rx_available += len; | |||
| rx_queue_transfer(i); | |||
| // TODO: trigger serialEvent | |||
| return; | |||
| } | |||
| } | |||
| // add this packet to rx_list | |||
| rx_count[i] = len; | |||
| rx_index[i] = 0; | |||
| if (++head > RX_NUM) head = 0; | |||
| rx_list[head] = i; | |||
| rx_head = head; | |||
| rx_available += len; | |||
| // TODO: trigger serialEvent | |||
| } else { | |||
| // received a zero length packet | |||
| rx_queue_transfer(i); | |||
| } | |||
| return -1; | |||
| } | |||
| // number of bytes available in the receive buffer | |||
| int usb_serial_available(void) | |||
| { | |||
| return rx_count[0] - rx_index[0]; | |||
| } | |||
| //static int maxtimes=0; | |||
| // read a block of bytes to a buffer | |||
| int usb_serial_read(void *buffer, uint32_t size) | |||
| { | |||
| // Quick and dirty to make it at least limp... | |||
| uint8_t *p = (uint8_t *)buffer; | |||
| uint32_t count=0; | |||
| while (size) { | |||
| int ch = usb_serial_getchar(); | |||
| if (ch == -1) break; | |||
| *p++ = (uint8_t)ch; | |||
| size--; | |||
| count++; | |||
| NVIC_DISABLE_IRQ(IRQ_USB1); | |||
| //if (++maxtimes > 15) while (1) ; | |||
| uint32_t tail = rx_tail; | |||
| //printf("usb_serial_read, size=%d, tail=%d, head=%d\n", size, tail, rx_head); | |||
| while (count < size && tail != rx_head) { | |||
| if (++tail > RX_NUM) tail = 0; | |||
| uint32_t i = rx_list[tail]; | |||
| uint32_t len = size - count; | |||
| uint32_t avail = rx_count[i] - rx_index[i]; | |||
| //printf("usb_serial_read, count=%d, size=%d, i=%d, index=%d, len=%d, avail=%d, c=%c\n", | |||
| //count, size, i, rx_index[i], len, avail, rx_buffer[i * CDC_RX_SIZE_480]); | |||
| if (avail > len) { | |||
| // partially consume this packet | |||
| memcpy(p, rx_buffer + i * CDC_RX_SIZE_480 + rx_index[i], len); | |||
| rx_available -= len; | |||
| rx_index[i] += len; | |||
| count += len; | |||
| } else { | |||
| // fully consume this packet | |||
| memcpy(p, rx_buffer + i * CDC_RX_SIZE_480 + rx_index[i], avail); | |||
| p += avail; | |||
| rx_available -= avail; | |||
| count += avail; | |||
| rx_tail = tail; | |||
| rx_queue_transfer(i); | |||
| } | |||
| } | |||
| NVIC_ENABLE_IRQ(IRQ_USB1); | |||
| return count; | |||
| } | |||
| // peek at the next character, or -1 if nothing received | |||
| int usb_serial_peekchar(void) | |||
| { | |||
| uint32_t tail = rx_tail; | |||
| if (tail == rx_head) return -1; | |||
| if (++tail > RX_NUM) tail = 0; | |||
| uint32_t i = rx_list[tail]; | |||
| return rx_buffer[i * CDC_RX_SIZE_480 + rx_index[i]]; | |||
| } | |||
| // number of bytes available in the receive buffer | |||
| int usb_serial_available(void) | |||
| { | |||
| return rx_available; | |||
| } | |||
| // discard any buffered input | |||
| void usb_serial_flush_input(void) | |||
| { | |||
| if (rx_index[0] < rx_count[0]) { | |||
| rx_index[0] = rx_count[0]; | |||
| usb_prepare_transfer(rx_transfer + 0, rx_buffer + 0, rx_packet_size, 0); | |||
| usb_receive(CDC_RX_ENDPOINT, rx_transfer + 0); | |||
| uint32_t tail = rx_tail; | |||
| while (tail != rx_head) { | |||
| if (++tail > RX_NUM) tail = 0; | |||
| uint32_t i = rx_list[tail]; | |||
| rx_available -= rx_count[i] - rx_index[i]; | |||
| rx_queue_transfer(i); | |||
| rx_tail = tail; | |||
| } | |||
| } | |||
| // get the next character, or -1 if nothing received | |||
| int usb_serial_getchar(void) | |||
| { | |||
| uint8_t c; | |||
| if (usb_serial_read(&c, 1)) return c; | |||
| return -1; | |||
| } | |||
| /*************************************************************************/ | |||
| /** Transmit **/ | |||
| /*************************************************************************/ | |||
| // When the PC isn't listening, how long do we wait before discarding data? If this is | |||
| // too short, we risk losing data during the stalls that are common with ordinary desktop | |||
| // software. If it's too long, we stall the user's program when no software is running. | |||