X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=bsb%2Ffirmware%2Fmain.c;h=bb0c48e53bf140ae98ade0e46e9da73180760dbf;hb=37082aba8175e02e86271010ee372d2f34fc6413;hp=e7237e1cf5101cc6f7fdb8b269a34fa5c2773e8e;hpb=d2a47ff7858e03000280d640566c8142578ebf02;p=home-hw.git diff --git a/bsb/firmware/main.c b/bsb/firmware/main.c index e7237e1..bb0c48e 100644 --- a/bsb/firmware/main.c +++ b/bsb/firmware/main.c @@ -5,6 +5,7 @@ */ #include "util.h" +#include "interface.h" #include #include @@ -30,12 +31,14 @@ static void clock_init(void) rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); rcc_periph_clock_enable(RCC_USART1); + rcc_periph_clock_enable(RCC_USART3); rcc_periph_clock_enable(RCC_USB); rcc_periph_reset_pulse(RST_GPIOA); rcc_periph_reset_pulse(RST_GPIOB); rcc_periph_reset_pulse(RST_GPIOC); rcc_periph_reset_pulse(RST_USART1); + rcc_periph_reset_pulse(RST_USART3); rcc_periph_reset_pulse(RST_USB); } @@ -56,8 +59,7 @@ static void gpio_init(void) // PB10 = TXD3 for BSB // PB11 = RXD3 for BSB - // FIXME: TX turned off temporarily - // gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10); + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10); gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11); } @@ -66,7 +68,7 @@ static void usart_init(void) usart_set_baudrate(USART1, 115200); usart_set_databits(USART1, 8); usart_set_stopbits(USART1, USART_STOPBITS_1); - usart_set_mode(USART1, USART_MODE_TX_RX); + usart_set_mode(USART1, USART_MODE_TX); usart_set_parity(USART1, USART_PARITY_NONE); usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); @@ -84,7 +86,7 @@ void sys_tick_handler(void) static void tick_init(void) { - systick_set_frequency(1000, 72000000); + systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000); systick_counter_enable(); systick_interrupt_enable(); } @@ -96,69 +98,359 @@ static void delay_ms(uint ms) ; } +/*** Random generator ***/ + +static u32 rng_state; + +static u32 random_u32(void) +{ + rng_state *= 2654289733; + return rng_state; +} + +static void random_init(void) +{ + u32 desig[3]; + desig_get_unique_id(desig); + rng_state = desig[0] ^ desig[1] ^ desig[2]; +} + /*** BSB ***/ #define BSB_MAX_SIZE 32 -#define BSB_RX_TIMEOUT 2 // 1-2 ms => 2-4 byte periods of silence +#define BSB_RX_TIMEOUT 10 // If no byte was received for this time, end the current frame [ms] +#define BSB_TX_IDLE_LINE 100 // Consider the line idle if no byte was received for this time [ms] +#define BSB_TX_MAX_ATTEMPTS 3 +#define BSB_TX_WAIT_LOG 8 // base 2 log of pre-frame waiting time in ms +#define BSB_TX_TIMEOUT 10000 // Total time to transmit a frame including all retries and waiting for reply [ms] +#define BSB_REPLY_TIMEOUT 1000 // How long to wait for a reply [ms] + +#undef DEBUG_BSB +#ifdef DEBUG_BSB +#define BSB_DEBUG(x) debug_putc(x) +#else +#define BSB_DEBUG(x) do { } while (0) +#endif + +struct bsb_state { + byte rx_len; // Bytes received so far + byte rx_led; // Countdown to turning RX LED off + u16 rx_crc; + volatile u32 rx_timestamp; // Last byte received + + byte tx_state; // TX_STATE_xxx + byte tx_len; + byte tx_send_index; + byte tx_check_index; + byte tx_attempts; + byte tx_result; // TX_RESULT_xxx + u32 tx_start_timestamp; + u32 tx_ticks_to_send; + u32 tx_end_timestamp; + u32 reply_type_mask; // Expected reply types (0=no reply) + + byte rx_buf[BSB_MAX_SIZE]; + byte tx_buf[BSB_MAX_SIZE]; +}; -static byte bsb_rx_buf[BSB_MAX_SIZE]; -static byte bsb_rx_len; -static volatile u32 bsb_rx_timestamp; +static struct bsb_state bsb; -// Passing received frames to the main loop -static byte bsb_rx_frame[BSB_MAX_SIZE]; +// Passing received frames and status codes to the main loop +static byte bsb_rx_status_and_frame[1 + BSB_MAX_SIZE]; static volatile byte bsb_rx_frame_len; -static byte bsb_rx_frame_led; - -struct bsb_stat { - u32 rx_noise; - u32 rx_errors; - u32 rx_invalid; - u32 rx_overruns; - u32 rx_timeouts; +static byte bsb_tx_result; + +enum bsb_tx_state { + TX_STATE_OFF, + TX_STATE_WAITING_FOR_IDLE_LINE, + TX_STATE_PRE_PACKET_DELAY, + TX_STATE_SENDING, + TX_STATE_SENT, + TX_STATE_WAITING_FOR_REPLY, + TX_STATE_COLLISION, }; -static struct bsb_stat bsb_stat; +static struct bsb_stats bsb_stats; + +static void bsb_attempt_tx(void); + +static u16 bsb_crc_update(u16 crc, byte data) +{ + crc = crc ^ (data << 8); + for (uint i=0; i<8; i++) { + if (crc & 0x8000) + crc = (crc << 1) ^ 0x1021; + else + crc <<= 1; + } + return crc; +} void usart3_isr(void) { u32 status = USART_SR(USART3); if (status & USART_SR_RXNE) { - uint ch = usart_recv(USART3); - bsb_rx_timestamp = ms_ticks; - - if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) { - bsb_stat.rx_errors++; - bsb_rx_len = 0; - } else if (!bsb_rx_len && ch != 0xdc) { - // Waiting for start of frame - bsb_stat.rx_noise++; - } else { - bsb_rx_buf[bsb_rx_len++] = ch; - if (bsb_rx_len < 4) { - // First three bytes: SOF, source addr, destination addr - } else if (bsb_rx_len == 4) { - // Received length byte - if (bsb_rx_buf[3] < 7 || bsb_rx_buf[3] > BSB_MAX_SIZE) { - bsb_stat.rx_invalid++; - bsb_rx_len = 0; + uint ch = ~usart_recv(USART3) & 0xff; + bsb.rx_timestamp = ms_ticks; +#ifdef DEBUG_BSB + debug_printf(" %02x", ch); +#endif + + if (bsb.tx_state == TX_STATE_SENDING) { + // We are hearing the echo of a transmitted packet, check it for collisions + if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) { + BSB_DEBUG('e'); + bsb.tx_state = TX_STATE_COLLISION; + } else if (ch == bsb.tx_buf[bsb.tx_check_index++]) { + if (bsb.tx_check_index >= bsb.tx_len) { + BSB_DEBUG('d'); + bsb.tx_state = TX_STATE_SENT; } - } else if (bsb_rx_len == bsb_rx_buf[3]) { - // Received a complete frame: pass it to the main loop - if (bsb_rx_frame_len) { - // The previous one was not sent yet - bsb_stat.rx_overruns++; + } else { + BSB_DEBUG('c'); + bsb.tx_state = TX_STATE_COLLISION; + } + } else { + // Regular receive + if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) { + bsb_stats.rx_errors++; + bsb.rx_len = 0; + } else if (!bsb.rx_len) { + // Start of frame + if (ch == 0xdc) { + bsb.rx_buf[bsb.rx_len++] = ch; + bsb.rx_crc = bsb_crc_update(0, ch); + BSB_DEBUG('<'); } else { - memcpy(bsb_rx_frame, bsb_rx_buf, bsb_rx_buf[3]); - barrier(); - bsb_rx_frame_len = bsb_rx_buf[3]; - bsb_rx_frame_led = 100; - gpio_clear(GPIOB, GPIO1); + bsb_stats.rx_noise++; + BSB_DEBUG('?'); + } + } else { + bsb.rx_buf[bsb.rx_len++] = ch; + bsb.rx_crc = bsb_crc_update(bsb.rx_crc, ch); + if (bsb.rx_len < 4) { + // First three bytes: SOF, source addr, destination addr + } else if (bsb.rx_len == 4) { + // Received length byte + if (bsb.rx_buf[BF_LEN] < 7 || bsb.rx_buf[BF_LEN] > BSB_MAX_SIZE) { + bsb_stats.rx_invalid++; + bsb.rx_len = 0; + BSB_DEBUG('L'); + } + } else if (bsb.rx_len == bsb.rx_buf[BF_LEN]) { + // Received a complete frame: check CRC and pass it to the main loop + if (bsb.rx_crc) { + bsb_stats.rx_bad_crc++; + BSB_DEBUG('C'); + } else { + if (bsb_rx_frame_len) { + // The previous one was not sent yet + bsb_stats.rx_overruns++; + BSB_DEBUG('O'); + } else { + bsb_rx_frame_len = bsb.rx_buf[BF_LEN]; + memcpy(bsb_rx_status_and_frame + 1, bsb.rx_buf, bsb_rx_frame_len); + bsb_stats.rx_ok++; + BSB_DEBUG('.'); + // Will match with expected replies in main loop + } + gpio_clear(GPIOB, GPIO1); + bsb.rx_led = 100; + } + bsb.rx_len = 0; } } } } + + if (status & USART_SR_TXE) { + if (bsb.tx_state == TX_STATE_SENDING && bsb.tx_send_index < bsb.tx_len) { + BSB_DEBUG('>'); + usart_send(USART3, bsb.tx_buf[bsb.tx_send_index++] ^ 0xff); + } else { + usart_disable_tx_interrupt(USART3); + // Main loop will be notified by receiving the echo of our frame, + // so we do not need to wait for the "transmit complete" flag. + } + } +} + +static void bsb_rx_step(void) +{ + cm_disable_interrupts(); + barrier(); + if (bsb.rx_len && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) { + bsb.rx_len = 0; + bsb_stats.rx_timeouts++; + BSB_DEBUG('T'); + } + if (bsb.rx_led) { + if (!--bsb.rx_led) + gpio_set(GPIOB, GPIO1); + } + cm_enable_interrupts(); +} + +static void bsb_tx_step(void) +{ + switch (bsb.tx_state) { + case TX_STATE_WAITING_FOR_IDLE_LINE: + if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE) + return; + bsb.tx_state = TX_STATE_PRE_PACKET_DELAY; + BSB_DEBUG('i'); + // Fall thru + case TX_STATE_PRE_PACKET_DELAY: + if (ms_ticks - bsb.tx_start_timestamp > BSB_TX_TIMEOUT) { + bsb.tx_state = TX_STATE_OFF; + bsb_tx_result = TX_RESULT_TIMEOUT; + bsb_stats.tx_timeouts++; + return; + } + if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE) { + bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE; + BSB_DEBUG('n'); + return; + } + if (--bsb.tx_ticks_to_send) + return; + BSB_DEBUG('s'); + bsb.rx_timestamp = ms_ticks; + barrier(); + bsb.tx_state = TX_STATE_SENDING; + barrier(); + usart_enable_tx_interrupt(USART3); + return; + case TX_STATE_SENDING: + // In this state, we can race with the USART interrupt handler + cm_disable_interrupts(); + if (bsb.tx_state == TX_STATE_SENDING && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) { + // The echo of our packet was truncated due to collision + bsb.tx_state = TX_STATE_COLLISION; + BSB_DEBUG('t'); + } + cm_enable_interrupts(); + return; + case TX_STATE_COLLISION: + bsb_stats.tx_collisions++; + bsb_attempt_tx(); + return; + case TX_STATE_SENT: + if (!bsb.reply_type_mask) { + // The frame needs no reply => confirm transmission + bsb_stats.tx_ok_no_reply++; + bsb.tx_state = TX_STATE_OFF; + bsb_tx_result = TX_RESULT_OK; + } else { + bsb.tx_state = TX_STATE_WAITING_FOR_REPLY; + bsb.tx_end_timestamp = ms_ticks; + BSB_DEBUG('w'); + } + return; + case TX_STATE_WAITING_FOR_REPLY: + if (ms_ticks - bsb.tx_end_timestamp > BSB_REPLY_TIMEOUT) { + // We did not receive a reply. Maybe the request was lost? Re-transmit it. + bsb_stats.tx_reply_timeouts++; + BSB_DEBUG('t'); + bsb_attempt_tx(); + } + return; + default: + ; + } +} + +static void bsb_attempt_tx(void) +{ + if (bsb.tx_attempts++ >= BSB_TX_MAX_ATTEMPTS) { + bsb.tx_state = TX_STATE_OFF; + bsb_tx_result = TX_RESULT_TOO_MANY_RETRIES; + return; + } + + bsb.tx_ticks_to_send = (random_u32() | 0x80000000) >> (32 - BSB_TX_WAIT_LOG - (bsb.tx_attempts-1)); + + bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE; + bsb.tx_send_index = 0; + bsb.tx_check_index = 0; + debug_printf("TX: Attempt #%u, wait for %u ms\n", bsb.tx_attempts, (uint) bsb.tx_ticks_to_send); +} + +static void bsb_send(byte *buf, uint len) +{ + // If a transmit is in progress, declare overrrun + if (bsb_tx_result != TX_RESULT_NONE) { + bsb_stats.tx_overruns++; + return; + } + if (bsb.tx_state != TX_STATE_OFF) { + bsb_stats.tx_overruns++; + bsb_tx_result = TX_RESULT_OVERRUN; + return; + } + + // Check frame validity + if (len < 7 || len > BSB_MAX_SIZE || buf[BF_SOF] != 0xdc || buf[BF_LEN] != len) { + bsb_stats.tx_rejects++; + bsb_tx_result = TX_RESULT_MALFORMED; + return; + } + + // Detect frame type and prepare expected reply types + if (buf[BF_OP] == BSB_OP_QUERY) { + // So far, we allow only QUERY frames + bsb.reply_type_mask = (1 << BSB_OP_ANSWER) | (1 << BSB_OP_ERROR); + } else { + bsb_stats.tx_rejects++; + bsb_tx_result = TX_RESULT_FORBIDDEN; + return; + } + + // Fill in source address + buf[BF_SRC] = 0x80 + BSB_ADDR_GATEWAY; + + // Calculate CRC + u16 crc = 0; + for (uint i = 0; i < len - 2; i++) + crc = bsb_crc_update(crc, buf[i]); + buf[len-2] = crc >> 8; + buf[len-1] = crc; + debug_printf("TX: Prepared frame: type=%02x dest=%02x len=%u crc=%04x reply=%08x\n", buf[BF_OP], buf[BF_DEST], len, crc, (uint) bsb.reply_type_mask); + + // Queue frame for transmission + memcpy(bsb.tx_buf, buf, len); + bsb.tx_len = len; + bsb.tx_start_timestamp = ms_ticks; + bsb.tx_attempts = 0; + bsb_attempt_tx(); + + // Light the TX LED + gpio_clear(GPIOB, GPIO0); +} + +static void bsb_check_reply(void) +{ + // Match received frame in bsb_rx_status_and_frame to expected replies + // and set the status in byte 0. + + byte *frame = bsb_rx_status_and_frame + 1; + // XXX: This might be executed too fast, so we can still be in TX_STATE_SENT + if (bsb.tx_state == TX_STATE_WAITING_FOR_REPLY || bsb.tx_state == TX_STATE_SENT) { + if (frame[BF_DEST] == BSB_ADDR_GATEWAY && + frame[BF_SRC] == bsb.tx_buf[BF_DEST] ^ 0x80 && + frame[BF_OP] < 32 && + bsb.reply_type_mask & (1 << frame[BF_OP])) { + debug_printf("BSB: Matched reply\n"); + bsb.tx_state = TX_STATE_OFF; + bsb_stats.tx_ok_replied++; + bsb_rx_status_and_frame[0] = TX_RESULT_OK; + gpio_set(GPIOB, GPIO0); // Turn the TX LED off + return; + } + } + + bsb_rx_status_and_frame[0] = TX_RESULT_NONE; } static void bsb_init(void) @@ -179,6 +471,20 @@ static void bsb_init(void) static usbd_device *usbd_dev; +enum usb_string { + STR_MANUFACTURER = 1, + STR_PRODUCT, + STR_SERIAL, +}; + +static char usb_serial_number[13]; + +static const char *usb_strings[] = { + "United Computer Wizards", + "BSB Gateway", + usb_serial_number, +}; + static const struct usb_device_descriptor device = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, @@ -187,23 +493,25 @@ static const struct usb_device_descriptor device = { .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, - .idVendor = 0x4242, - .idProduct = 0x0003, - .bcdDevice = 0x0200, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, + .idVendor = BSB_USB_VENDOR, + .idProduct = BSB_USB_PRODUCT, + .bcdDevice = BSB_USB_VERSION, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIAL, .bNumConfigurations = 1, }; static const struct usb_endpoint_descriptor endpoints[] = {{ + // Bulk end-point for sending frames to BSB .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x81, + .bEndpointAddress = 0x01, .bmAttributes = USB_ENDPOINT_ATTR_BULK, .wMaxPacketSize = 64, .bInterval = 1, },{ + // Interrupt end-point for receiving frames from BSB .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x82, @@ -269,16 +577,8 @@ static const struct usb_config_descriptor config = { .interface = ifaces, }; -static char usb_serial_number[13]; - -static const char *usb_strings[] = { - "United Computer Wizards", - "BSB Gateway", - usb_serial_number, -}; - static byte usb_configured; -static byte usb_rx_pending; +static byte usb_ep82_pending; static uint8_t usbd_control_buffer[64]; static enum usbd_request_return_codes control_cb( @@ -292,9 +592,9 @@ static enum usbd_request_return_codes control_cb( return USBD_REQ_NOTSUPP; // We support reading of statistics via control requests - debug_printf("USB: Control request: Read statistics\n"); - uint n = MIN(*len, sizeof(bsb_stat)); - memcpy(*buf, (char *) &bsb_stat, n); + debug_printf("USB: Reading statistics\n"); + uint n = MIN(*len, sizeof(bsb_stats)); + memcpy(*buf, (char *) &bsb_stats, n); *len = n; return USBD_REQ_HANDLED; @@ -321,34 +621,36 @@ static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED, return USBD_REQ_HANDLED; } -static void ep81_cb(usbd_device *dev, uint8_t ep UNUSED) +static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED) { - byte buf[4]; - put_u32_be(buf, ms_ticks); - usbd_ep_write_packet(dev, 0x81, buf, sizeof(buf)); - debug_printf("USB: Bulk write\n"); + // We received a frame from the USB host + byte buf[64]; + uint len = usbd_ep_read_packet(dev, 0x01, buf, sizeof(buf)); + debug_printf("USB: Host sent %u bytes\n", len); + bsb_send(buf, len); } -static void rx_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED) +static void ep82_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED) { - // Received packet passed through interrupt end-point - debug_printf("USB: RX EP done\n"); - usb_rx_pending = 0; + // The frame was accepted by the USB host + debug_printf("USB: Interrupt done\n"); + usb_ep82_pending = 0; } static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED) { - usbd_register_control_callback(dev, + usbd_register_control_callback( + dev, USB_REQ_TYPE_VENDOR, USB_REQ_TYPE_TYPE, control_cb); - usbd_register_control_callback(dev, + usbd_register_control_callback( + dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, dfu_control_cb); - usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb); - usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, rx_cb); - ep81_cb(dev, 0); + usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb); + usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 64, ep82_cb); usb_configured = 1; } @@ -356,6 +658,7 @@ static void reset_cb(void) { debug_printf("USB: Reset\n"); usb_configured = 0; + usb_ep82_pending = 0; } static volatile bool usb_event_pending; @@ -379,7 +682,7 @@ static void usb_init(void) // Simulate USB disconnect gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12); gpio_clear(GPIOA, GPIO11 | GPIO12); - delay_ms(1000); + delay_ms(100); usbd_dev = usbd_init( &st_usbfs_v1_usb_driver, @@ -404,19 +707,20 @@ int main(void) tick_init(); usart_init(); desig_get_unique_id_as_dfu(usb_serial_number); + random_init(); - debug_printf("Hello, kitty!\n"); + debug_printf("Hail, Lord Damian! Thy BSB interface is ready.\n"); bsb_init(); usb_init(); - u32 last_ds_step = 0; + u32 last_blink = 0; + u32 last_step = 0; for (;;) { - if (ms_ticks - last_ds_step >= 100) { + if (ms_ticks - last_blink >= 100) { debug_led_toggle(); - gpio_toggle(GPIOB, GPIO0); - last_ds_step = ms_ticks; + last_blink = ms_ticks; } if (usb_event_pending) { @@ -427,31 +731,33 @@ int main(void) } if (usb_configured) { - // Passing of received packets to USB - if (!usb_rx_pending) { + // Passing of received frames to USB + if (!usb_ep82_pending) { if (bsb_rx_frame_len) { + // Received frame, possibly marked as reply barrier(); - usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len); - usb_rx_pending = 1; + bsb_check_reply(); + usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_status_and_frame, 1 + bsb_rx_frame_len); + usb_ep82_pending = 1; barrier(); bsb_rx_frame_len = 0; - debug_printf("USB: RX started\n"); + debug_printf("USB: Sending frame to interrupt EP\n"); + } else if (bsb_tx_result != TX_RESULT_NONE) { + // Only a transmission result + usbd_ep_write_packet(usbd_dev, 0x82, &bsb_tx_result, 1); + usb_ep82_pending = 1; + gpio_set(GPIOB, GPIO0); // Turn the TX LED off + debug_printf("USB: Sending status %u to interrupt EP\n", bsb_tx_result); + bsb_tx_result = TX_RESULT_NONE; } } } - // Packet timeouts - cm_disable_interrupts(); - barrier(); - if (bsb_rx_len && (bsb_rx_timestamp - ms_ticks) >= BSB_RX_TIMEOUT) { - bsb_rx_len = 0; - bsb_stat.rx_timeouts++; - } - if (bsb_rx_frame_led) { - if (!--bsb_rx_frame_led) - gpio_set(GPIOB, GPIO1); + if (ms_ticks != last_step) { + last_step = ms_ticks; + bsb_rx_step(); + bsb_tx_step(); } - cm_enable_interrupts(); wait_for_interrupt(); }