+void usart3_isr(void)
+{
+ u32 status = USART_SR(USART3);
+
+ if (status & USART_SR_RXNE) {
+ uint ch = ~usart_recv(USART3) & 0xff;
+ bsb_rx_timestamp = ms_ticks;
+ BSB_DEBUG(" %02x", ch);
+
+ if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
+ bsb_stat.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 {
+ bsb_stat.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[3] < 7 || bsb_rx_buf[3] > BSB_MAX_SIZE) {
+ bsb_stat.rx_invalid++;
+ bsb_rx_len = 0;
+ BSB_DEBUG("!L");
+ }
+ } else if (bsb_rx_len == bsb_rx_buf[3]) {
+ // Received a complete frame: check CRC and pass it to the main loop
+ if (bsb_rx_crc) {
+ bsb_stat.rx_bad_crc++;
+ BSB_DEBUG("!C");
+ } else {
+ if (bsb_rx_frame_len) {
+ // The previous one was not sent yet
+ bsb_stat.rx_overruns++;
+ BSB_DEBUG("!O");
+ } else {
+ memcpy(bsb_rx_frame, bsb_rx_buf, bsb_rx_buf[3]);
+ bsb_rx_frame_len = bsb_rx_buf[3];
+ bsb_stat.rx_ok++;
+ BSB_DEBUG(".");
+ }
+ gpio_clear(GPIOB, GPIO1);
+ bsb_rx_frame_led = 100;
+ }
+ bsb_rx_len = 0;
+ }
+ }
+ }
+}
+
+static void bsb_init(void)
+{
+ usart_set_baudrate(USART3, 4800);
+ usart_set_databits(USART3, 9);
+ usart_set_stopbits(USART3, USART_STOPBITS_1);
+ usart_set_mode(USART3, USART_MODE_RX);
+ usart_set_parity(USART3, USART_PARITY_ODD);
+ usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
+
+ usart_enable(USART3);
+ nvic_enable_irq(NVIC_USART3_IRQ);
+ usart_enable_rx_interrupt(USART3);