]> mj.ucw.cz Git - home-hw.git/blob - bsb/firmware/main.c
BSB: Transmit implemented
[home-hw.git] / bsb / firmware / main.c
1 /*
2  *      Boiler System Bus Gateway
3  *
4  *      (c) 2020 Martin Mareš <mj@ucw.cz>
5  */
6
7 #include "util.h"
8 #include "interface.h"
9
10 #include <libopencm3/cm3/cortex.h>
11 #include <libopencm3/cm3/nvic.h>
12 #include <libopencm3/cm3/systick.h>
13 #include <libopencm3/cm3/scb.h>
14 #include <libopencm3/stm32/rcc.h>
15 #include <libopencm3/stm32/desig.h>
16 #include <libopencm3/stm32/gpio.h>
17 #include <libopencm3/stm32/timer.h>
18 #include <libopencm3/stm32/usart.h>
19 #include <libopencm3/usb/dfu.h>
20 #include <libopencm3/usb/usbd.h>
21
22 #include <string.h>
23
24 /*** Hardware init ***/
25
26 static void clock_init(void)
27 {
28         rcc_clock_setup_in_hse_8mhz_out_72mhz();
29
30         rcc_periph_clock_enable(RCC_GPIOA);
31         rcc_periph_clock_enable(RCC_GPIOB);
32         rcc_periph_clock_enable(RCC_GPIOC);
33         rcc_periph_clock_enable(RCC_USART1);
34         rcc_periph_clock_enable(RCC_USART3);
35         rcc_periph_clock_enable(RCC_USB);
36
37         rcc_periph_reset_pulse(RST_GPIOA);
38         rcc_periph_reset_pulse(RST_GPIOB);
39         rcc_periph_reset_pulse(RST_GPIOC);
40         rcc_periph_reset_pulse(RST_USART1);
41         rcc_periph_reset_pulse(RST_USART3);
42         rcc_periph_reset_pulse(RST_USB);
43 }
44
45 static void gpio_init(void)
46 {
47         // PA9 = TXD1 for debugging console
48         // PA10 = RXD1 for debugging console
49         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
50         gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
51
52         // PC13 = BluePill LED
53         gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
54         gpio_clear(GPIOC, GPIO13);
55
56         // PB0 = yellow LED*, PB1 = green LED*
57         gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO0 | GPIO1);
58         gpio_set(GPIOB, GPIO0 | GPIO1);
59
60         // PB10 = TXD3 for BSB
61         // PB11 = RXD3 for BSB
62         gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10);
63         gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11);
64 }
65
66 static void usart_init(void)
67 {
68         usart_set_baudrate(USART1, 115200);
69         usart_set_databits(USART1, 8);
70         usart_set_stopbits(USART1, USART_STOPBITS_1);
71         usart_set_mode(USART1, USART_MODE_TX);
72         usart_set_parity(USART1, USART_PARITY_NONE);
73         usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
74
75         usart_enable(USART1);
76 }
77
78 /*** System ticks ***/
79
80 static volatile u32 ms_ticks;
81
82 void sys_tick_handler(void)
83 {
84         ms_ticks++;
85 }
86
87 static void tick_init(void)
88 {
89         systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
90         systick_counter_enable();
91         systick_interrupt_enable();
92 }
93
94 static void delay_ms(uint ms)
95 {
96         u32 start_ticks = ms_ticks;
97         while (ms_ticks - start_ticks < ms)
98                 ;
99 }
100
101 /*** Random generator ***/
102
103 static u32 rng_state;
104
105 static u32 random_u32(void)
106 {
107         rng_state *= 2654289733;
108         return rng_state;
109 }
110
111 static void random_init(void)
112 {
113         u32 desig[3];
114         desig_get_unique_id(desig);
115         rng_state = desig[0] ^ desig[1] ^ desig[2];
116 }
117
118 /*** BSB ***/
119
120 #define BSB_MAX_SIZE 32
121 #define BSB_RX_TIMEOUT 10       // ms
122 #define BSB_TX_IDLE_LINE 100    // ms
123 #define BSB_TX_MAX_ATTEMPTS 3
124 #define BSB_TX_WAIT_LOG 10      // base 2 log of timeout in ms
125 #define BSB_TX_TIMEOUT 10000    // ms
126
127 #define DEBUG_BSB
128 #ifdef DEBUG_BSB
129 #define BSB_DEBUG(x) debug_putc(x)
130 #else
131 #define BSB_DEBUG(x) do { } while (0)
132 #endif
133
134 struct bsb_state {
135         byte rx_len;                    // Bytes received so far
136         byte rx_led;                    // Countdown to turning RX LED off
137         u16 rx_crc;
138         volatile u32 rx_timestamp;      // Last byte received
139
140         byte tx_state;                  // TX_STATE_xxx
141         byte tx_len;
142         byte tx_send_index;
143         byte tx_check_index;
144         byte tx_attempts;
145         byte tx_result;                 // TX_RESULT_xxx
146         u32 tx_start_timestamp;
147         u32 tx_ticks_to_send;
148
149         byte rx_buf[BSB_MAX_SIZE];
150         byte tx_buf[BSB_MAX_SIZE];
151 };
152
153 static struct bsb_state bsb;
154
155 // Passing received frames and status codes to the main loop
156 static byte bsb_rx_frame[BSB_MAX_SIZE];
157 static volatile byte bsb_rx_frame_len;
158 static byte bsb_tx_result;
159
160 enum bsb_tx_state {
161         TX_STATE_OFF,
162         TX_STATE_WAITING_FOR_IDLE_LINE,
163         TX_STATE_PRE_PACKET_DELAY,
164         TX_STATE_SENDING,
165         TX_STATE_DONE,
166         TX_STATE_COLLISION,
167 };
168
169 static struct bsb_stats bsb_stats;
170
171 static void bsb_attempt_tx(void);
172
173 static u16 bsb_crc_update(u16 crc, byte data)
174 {
175         crc = crc ^ (data << 8);
176         for (uint i=0; i<8; i++) {
177                 if (crc & 0x8000)
178                         crc = (crc << 1) ^ 0x1021;
179                 else
180                         crc <<= 1;
181         }
182         return crc;
183 }
184
185 void usart3_isr(void)
186 {
187         u32 status = USART_SR(USART3);
188
189         if (status & USART_SR_RXNE) {
190                 uint ch = ~usart_recv(USART3) & 0xff;
191                 bsb.rx_timestamp = ms_ticks;
192 #ifdef DEBUG_BSB
193                 debug_printf(" %02x", ch);
194 #endif
195
196                 if (bsb.tx_state == TX_STATE_SENDING) {
197                         // We are hearing the echo of a transmitted packet, check it for collisions
198                         if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
199                                 BSB_DEBUG('e');
200                                 bsb.tx_state = TX_STATE_COLLISION;
201                         } else if (ch == bsb.tx_buf[bsb.tx_check_index++]) {
202                                 if (bsb.tx_check_index >= bsb.tx_len) {
203                                         BSB_DEBUG('d');
204                                         bsb.tx_state = TX_STATE_DONE;
205                                 }
206                         } else {
207                                 BSB_DEBUG('c');
208                                 bsb.tx_state = TX_STATE_COLLISION;
209                         }
210                 } else {
211                         // Regular receive
212                         if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
213                                 bsb_stats.rx_errors++;
214                                 bsb.rx_len = 0;
215                         } else if (!bsb.rx_len) {
216                                 // Start of frame
217                                 if (ch == 0xdc) {
218                                         bsb.rx_buf[bsb.rx_len++] = ch;
219                                         bsb.rx_crc = bsb_crc_update(0, ch);
220                                         BSB_DEBUG('<');
221                                 } else {
222                                         bsb_stats.rx_noise++;
223                                         BSB_DEBUG('?');
224                                 }
225                         } else {
226                                 bsb.rx_buf[bsb.rx_len++] = ch;
227                                 bsb.rx_crc = bsb_crc_update(bsb.rx_crc, ch);
228                                 if (bsb.rx_len < 4) {
229                                         // First three bytes: SOF, source addr, destination addr
230                                 } else if (bsb.rx_len == 4) {
231                                         // Received length byte
232                                         if (bsb.rx_buf[3] < 7 || bsb.rx_buf[3] > BSB_MAX_SIZE) {
233                                                 bsb_stats.rx_invalid++;
234                                                 bsb.rx_len = 0;
235                                                 BSB_DEBUG('L');
236                                         }
237                                 } else if (bsb.rx_len == bsb.rx_buf[3]) {
238                                         // Received a complete frame: check CRC and pass it to the main loop
239                                         if (bsb.rx_crc) {
240                                                 bsb_stats.rx_bad_crc++;
241                                                 BSB_DEBUG('C');
242                                         } else {
243                                                 if (bsb_rx_frame_len) {
244                                                         // The previous one was not sent yet
245                                                         bsb_stats.rx_overruns++;
246                                                         BSB_DEBUG('O');
247                                                 } else {
248                                                         memcpy(bsb_rx_frame, bsb.rx_buf, bsb.rx_buf[3]);
249                                                         bsb_rx_frame_len = bsb.rx_buf[3] - 2;
250                                                         bsb_stats.rx_ok++;
251                                                         BSB_DEBUG('.');
252                                                 }
253                                                 gpio_clear(GPIOB, GPIO1);
254                                                 bsb.rx_led = 100;
255                                         }
256                                         bsb.rx_len = 0;
257                                 }
258                         }
259                 }
260         }
261
262         if (status & USART_SR_TXE) {
263                 if (bsb.tx_state == TX_STATE_SENDING && bsb.tx_send_index < bsb.tx_len) {
264                         BSB_DEBUG('>');
265                         usart_send(USART3, bsb.tx_buf[bsb.tx_send_index++] ^ 0xff);
266                 } else {
267                         usart_disable_tx_interrupt(USART3);
268                         // Main loop will be notified by receiving the echo of our frame,
269                         // so we do not need to wait for the "transmit complete" flag.
270                 }
271         }
272 }
273
274 static void bsb_rx_step(void)
275 {
276         cm_disable_interrupts();
277         barrier();
278         if (bsb.rx_len && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) {
279                 bsb.rx_len = 0;
280                 bsb_stats.rx_timeouts++;
281                 BSB_DEBUG('T');
282         }
283         if (bsb.rx_led) {
284                 if (!--bsb.rx_led)
285                         gpio_set(GPIOB, GPIO1);
286         }
287         cm_enable_interrupts();
288 }
289
290 static void bsb_tx_step(void)
291 {
292         switch (bsb.tx_state) {
293                 case TX_STATE_WAITING_FOR_IDLE_LINE:
294                         if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE)
295                                 return;
296                         bsb.tx_state = TX_STATE_PRE_PACKET_DELAY;
297                         BSB_DEBUG('i');
298                         // Fall thru
299                 case TX_STATE_PRE_PACKET_DELAY:
300                         if (ms_ticks - bsb.tx_start_timestamp > BSB_TX_TIMEOUT) {
301                                 bsb.tx_state = TX_STATE_OFF;
302                                 bsb_tx_result = TX_RESULT_TIMEOUT;
303                                 bsb_stats.tx_timeouts++;
304                                 return;
305                         }
306                         if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE) {
307                                 bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE;
308                                 BSB_DEBUG('n');
309                                 return;
310                         }
311                         if (--bsb.tx_ticks_to_send)
312                                 return;
313                         BSB_DEBUG('s');
314                         bsb.rx_timestamp = ms_ticks;
315                         barrier();
316                         bsb.tx_state = TX_STATE_SENDING;
317                         barrier();
318                         usart_enable_tx_interrupt(USART3);
319                         return;
320                 case TX_STATE_SENDING:
321                         // In this state, we can race with the USART interrupt handler
322                         cm_disable_interrupts();
323                         if (bsb.tx_state == TX_STATE_SENDING && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) {
324                                 // The echo of our packet was truncated due to collision
325                                 bsb.tx_state = TX_STATE_COLLISION;
326                                 BSB_DEBUG('t');
327                         }
328                         cm_enable_interrupts();
329                         return;
330                 case TX_STATE_COLLISION:
331                         bsb_stats.tx_collisions++;
332                         bsb_attempt_tx();
333                         return;
334                 case TX_STATE_DONE:
335                         bsb_stats.tx_ok++;
336                         bsb.tx_state = TX_STATE_OFF;
337                         bsb_tx_result = TX_RESULT_OK;
338                         return;
339                 default:
340                         ;
341         }
342 }
343
344 static void bsb_attempt_tx(void)
345 {
346         if (bsb.tx_attempts++ >= BSB_TX_MAX_ATTEMPTS) {
347                 bsb_tx_result = TX_RESULT_TOO_MANY_RETRIES;
348                 bsb.tx_state = TX_STATE_OFF;
349                 return;
350         }
351
352         bsb.tx_ticks_to_send = (random_u32() | 0x80000000) >> (32 - BSB_TX_WAIT_LOG - (bsb.tx_attempts-1));
353
354         bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE;
355         bsb.tx_send_index = 0;
356         bsb.tx_check_index = 0;
357         debug_printf("TX: Attempt #%u, wait for %u ms\n", bsb.tx_attempts, (uint) bsb.tx_ticks_to_send);
358 }
359
360 static void bsb_send(byte *buf, uint len)
361 {
362         // If a transmit is in progress, declare overrrun
363         if (bsb_tx_result != TX_RESULT_NONE) {
364                 bsb_stats.tx_overruns++;
365                 return;
366         }
367         if (bsb.tx_state != TX_STATE_OFF) {
368                 bsb_stats.tx_overruns++;
369                 bsb_tx_result = TX_RESULT_OVERRUN;
370                 return;
371         }
372
373         // Check frame validity
374         if (len < 5 || len > BSB_MAX_SIZE - 2 || buf[0] != 0xdc || buf[3] != len + 2) {
375                 bsb_stats.tx_rejects++;
376                 bsb_tx_result = TX_RESULT_MALFORMED;
377                 return;
378         }
379
380         // So far, we allow only QUERY frames from address 42
381         if (buf[1] != 0x80 + 42 && buf[4] != 0x06) {
382                 bsb_stats.tx_rejects++;
383                 bsb_tx_result = TX_RESULT_FORBIDDEN;
384                 return;
385         }
386
387         // Copy frame and calculate CRC
388         u16 crc = 0;
389         for (uint i=0; i<len; i++) {
390                 bsb.tx_buf[i] = buf[i];
391                 crc = bsb_crc_update(crc, buf[i]);
392         }
393         bsb.tx_buf[len++] = crc >> 8;
394         bsb.tx_buf[len++] = crc;
395         debug_printf("TX: Prepared frame of %u bytes with CRC %04x\n", len, crc);
396
397         // Queue frame for transmission
398         bsb.tx_len = len;
399         bsb.tx_start_timestamp = ms_ticks;
400         bsb.tx_attempts = 0;
401         bsb_attempt_tx();
402
403         // Light the TX LED
404         gpio_clear(GPIOB, GPIO0);
405 }
406
407 static void bsb_init(void)
408 {
409         usart_set_baudrate(USART3, 4800);
410         usart_set_databits(USART3, 9);
411         usart_set_stopbits(USART3, USART_STOPBITS_1);
412         usart_set_mode(USART3, USART_MODE_TX_RX);
413         usart_set_parity(USART3, USART_PARITY_ODD);
414         usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
415
416         usart_enable(USART3);
417         nvic_enable_irq(NVIC_USART3_IRQ);
418         usart_enable_rx_interrupt(USART3);
419 }
420
421 /*** USB ***/
422
423 static usbd_device *usbd_dev;
424
425 static const struct usb_device_descriptor device = {
426         .bLength = USB_DT_DEVICE_SIZE,
427         .bDescriptorType = USB_DT_DEVICE,
428         .bcdUSB = 0x0200,
429         .bDeviceClass = 0xFF,
430         .bDeviceSubClass = 0,
431         .bDeviceProtocol = 0,
432         .bMaxPacketSize0 = 64,
433         .idVendor = 0x4242,
434         .idProduct = 0x0003,
435         .bcdDevice = 0x0200,
436         .iManufacturer = 1,
437         .iProduct = 2,
438         .iSerialNumber = 3,
439         .bNumConfigurations = 1,
440 };
441
442 static const struct usb_endpoint_descriptor endpoints[] = {{
443         // Bulk end-point for sending frames to BSB
444         .bLength = USB_DT_ENDPOINT_SIZE,
445         .bDescriptorType = USB_DT_ENDPOINT,
446         .bEndpointAddress = 0x01,
447         .bmAttributes = USB_ENDPOINT_ATTR_BULK,
448         .wMaxPacketSize = 64,
449         .bInterval = 1,
450 },{
451         // Interrupt end-point for receiving frames from BSB
452         .bLength = USB_DT_ENDPOINT_SIZE,
453         .bDescriptorType = USB_DT_ENDPOINT,
454         .bEndpointAddress = 0x82,
455         .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
456         .wMaxPacketSize = 64,
457         .bInterval = 1,
458 }};
459
460 static const struct usb_interface_descriptor iface = {
461         .bLength = USB_DT_INTERFACE_SIZE,
462         .bDescriptorType = USB_DT_INTERFACE,
463         .bInterfaceNumber = 0,
464         .bAlternateSetting = 0,
465         .bNumEndpoints = 2,
466         .bInterfaceClass = 0xFF,
467         .bInterfaceSubClass = 0,
468         .bInterfaceProtocol = 0,
469         .iInterface = 0,
470         .endpoint = endpoints,
471 };
472
473 static const struct usb_dfu_descriptor dfu_function = {
474         .bLength = sizeof(struct usb_dfu_descriptor),
475         .bDescriptorType = DFU_FUNCTIONAL,
476         .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
477         .wDetachTimeout = 255,
478         .wTransferSize = 1024,
479         .bcdDFUVersion = 0x0100,
480 };
481
482 static const struct usb_interface_descriptor dfu_iface = {
483         .bLength = USB_DT_INTERFACE_SIZE,
484         .bDescriptorType = USB_DT_INTERFACE,
485         .bInterfaceNumber = 1,
486         .bAlternateSetting = 0,
487         .bNumEndpoints = 0,
488         .bInterfaceClass = 0xFE,
489         .bInterfaceSubClass = 1,
490         .bInterfaceProtocol = 1,
491         .iInterface = 0,
492
493         .extra = &dfu_function,
494         .extralen = sizeof(dfu_function),
495 };
496
497 static const struct usb_interface ifaces[] = {{
498         .num_altsetting = 1,
499         .altsetting = &iface,
500 }, {
501         .num_altsetting = 1,
502         .altsetting = &dfu_iface,
503 }};
504
505 static const struct usb_config_descriptor config = {
506         .bLength = USB_DT_CONFIGURATION_SIZE,
507         .bDescriptorType = USB_DT_CONFIGURATION,
508         .wTotalLength = 0,
509         .bNumInterfaces = 2,
510         .bConfigurationValue = 1,
511         .iConfiguration = 0,
512         .bmAttributes = 0x80,
513         .bMaxPower = 50,        // multiplied by 2 mA
514         .interface = ifaces,
515 };
516
517 static char usb_serial_number[13];
518
519 static const char *usb_strings[] = {
520         "United Computer Wizards",
521         "BSB Gateway",
522         usb_serial_number,
523 };
524
525 static byte usb_configured;
526 static byte usb_ep82_pending;
527 static uint8_t usbd_control_buffer[64];
528
529 static enum usbd_request_return_codes control_cb(
530         usbd_device *dev UNUSED,
531         struct usb_setup_data *req,
532         uint8_t **buf,
533         uint16_t *len,
534         void (**complete)(usbd_device *dev, struct usb_setup_data *req) UNUSED)
535 {
536         if (req->bmRequestType != 0xc0 || req->bRequest != 0x00)
537                 return USBD_REQ_NOTSUPP;
538
539         // We support reading of statistics via control requests
540         debug_printf("USB: Reading statistics\n");
541         uint n = MIN(*len, sizeof(bsb_stats));
542         memcpy(*buf, (char *) &bsb_stats, n);
543         *len = n;
544
545         return USBD_REQ_HANDLED;
546 }
547
548 static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
549 {
550         // Reset to bootloader, which implements the rest of DFU
551         debug_printf("Switching to DFU\n");
552         debug_flush();
553         scb_reset_core();
554 }
555
556 static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
557         struct usb_setup_data *req,
558         uint8_t **buf UNUSED,
559         uint16_t *len UNUSED,
560         void (**complete)(usbd_device *dev, struct usb_setup_data *req))
561 {
562         if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
563                 return USBD_REQ_NOTSUPP;
564
565         *complete = dfu_detach_complete;
566         return USBD_REQ_HANDLED;
567 }
568
569 static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED)
570 {
571         // We received a frame from the USB host
572         byte buf[64];
573         uint len = usbd_ep_read_packet(dev, 0x01, buf, sizeof(buf));
574         debug_printf("USB: Host sent %u bytes\n", len);
575         bsb_send(buf, len);
576 }
577
578 static void ep82_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED)
579 {
580         // The frame was accepted by the USB host
581         debug_printf("USB: Interrupt done\n");
582         usb_ep82_pending = 0;
583 }
584
585 static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED)
586 {
587         usbd_register_control_callback(
588                 dev,
589                 USB_REQ_TYPE_VENDOR,
590                 USB_REQ_TYPE_TYPE,
591                 control_cb);
592         usbd_register_control_callback(
593                 dev,
594                 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
595                 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
596                 dfu_control_cb);
597         usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb);
598         usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 64, ep82_cb);
599         usb_configured = 1;
600 }
601
602 static void reset_cb(void)
603 {
604         debug_printf("USB: Reset\n");
605         usb_configured = 0;
606         usb_ep82_pending = 0;
607 }
608
609 static volatile bool usb_event_pending;
610
611 void usb_lp_can_rx0_isr(void)
612 {
613         /*
614          *  We handle USB in the main loop to avoid race conditions between
615          *  USB interrupts and other code. However, we need an interrupt to
616          *  up the main loop from sleep.
617          *
618          *  We set up only the low-priority ISR, because high-priority ISR handles
619          *  only double-buffered bulk transfers and isochronous transfers.
620          */
621         nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
622         usb_event_pending = 1;
623 }
624
625 static void usb_init(void)
626 {
627         // Simulate USB disconnect
628         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
629         gpio_clear(GPIOA, GPIO11 | GPIO12);
630         delay_ms(100);
631
632         usbd_dev = usbd_init(
633                 &st_usbfs_v1_usb_driver,
634                 &device,
635                 &config,
636                 usb_strings,
637                 ARRAY_SIZE(usb_strings),
638                 usbd_control_buffer,
639                 sizeof(usbd_control_buffer)
640         );
641         usbd_register_reset_callback(usbd_dev, reset_cb);
642         usbd_register_set_config_callback(usbd_dev, set_config_cb);
643         usb_event_pending = 1;
644 }
645
646 /*** Main ***/
647
648 int main(void)
649 {
650         clock_init();
651         gpio_init();
652         tick_init();
653         usart_init();
654         desig_get_unique_id_as_dfu(usb_serial_number);
655         random_init();
656
657         debug_printf("Hail, Lord Damian! Thy BSB interface is ready.\n");
658
659         bsb_init();
660         usb_init();
661
662         u32 last_blink = 0;
663         u32 last_step = 0;
664
665         for (;;) {
666                 if (ms_ticks - last_blink >= 100) {
667                         debug_led_toggle();
668                         last_blink = ms_ticks;
669                 }
670
671                 if (usb_event_pending) {
672                         usbd_poll(usbd_dev);
673                         usb_event_pending = 0;
674                         nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ);
675                         nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
676                 }
677
678                 if (usb_configured) {
679                         // Passing of received frames to USB
680                         if (!usb_ep82_pending) {
681                                 if (bsb_rx_frame_len) {
682                                         barrier();
683                                         usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len);
684                                         usb_ep82_pending = 1;
685                                         barrier();
686                                         bsb_rx_frame_len = 0;
687                                         debug_printf("USB: Sending frame to interrupt EP\n");
688                                 }
689                                 if (bsb_tx_result != TX_RESULT_NONE) {
690                                         usbd_ep_write_packet(usbd_dev, 0x82, &bsb_tx_result, 1);
691                                         usb_ep82_pending = 1;
692                                         gpio_set(GPIOB, GPIO0);         // Turn the TX LED off
693                                         debug_printf("USB: Sending status %u to interrupt EP\n", bsb_tx_result);
694                                         bsb_tx_result = TX_RESULT_NONE;
695                                 }
696                         }
697                 }
698
699                 if (ms_ticks != last_step) {
700                         last_step = ms_ticks;
701                         bsb_rx_step();
702                         bsb_tx_step();
703                 }
704
705                 wait_for_interrupt();
706         }
707
708         return 0;
709 }