| static uint16_t rx_count[RX_NUM]; | static uint16_t rx_count[RX_NUM]; | ||||
| static uint16_t rx_index[RX_NUM]; | static uint16_t rx_index[RX_NUM]; | ||||
| static uint16_t rx_packet_size=0; | 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) | void usb_serial_reset(void) | ||||
| { | { | ||||
| void usb_serial_configure(void) | void usb_serial_configure(void) | ||||
| { | { | ||||
| int i; | |||||
| printf("usb_serial_configure\n"); | printf("usb_serial_configure\n"); | ||||
| if (usb_high_speed) { | if (usb_high_speed) { | ||||
| tx_packet_size = CDC_TX_SIZE_480; | tx_packet_size = CDC_TX_SIZE_480; | ||||
| memset(rx_transfer, 0, sizeof(rx_transfer)); | memset(rx_transfer, 0, sizeof(rx_transfer)); | ||||
| memset(rx_count, 0, sizeof(rx_count)); | memset(rx_count, 0, sizeof(rx_count)); | ||||
| memset(rx_index, 0, sizeof(rx_index)); | 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_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_rx(CDC_RX_ENDPOINT, rx_packet_size, 0, rx_event); | ||||
| usb_config_tx(CDC_TX_ENDPOINT, tx_packet_size, 1, NULL); | 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); | 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 | // read a block of bytes to a buffer | ||||
| int usb_serial_read(void *buffer, uint32_t size) | int usb_serial_read(void *buffer, uint32_t size) | ||||
| { | { | ||||
| // Quick and dirty to make it at least limp... | |||||
| uint8_t *p = (uint8_t *)buffer; | uint8_t *p = (uint8_t *)buffer; | ||||
| uint32_t count=0; | 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; | 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 | // discard any buffered input | ||||
| void usb_serial_flush_input(void) | 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 | // 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 | // 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. | // software. If it's too long, we stall the user's program when no software is running. |