]> mj.ucw.cz Git - home-hw.git/blob - bsb/firmware/main.c
ca30ffe1e6c02244e211ed285ed85c5aa87a1f44
[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 enum usb_string {
426         STR_MANUFACTURER = 1,
427         STR_PRODUCT,
428         STR_SERIAL,
429 };
430
431 static char usb_serial_number[13];
432
433 static const char *usb_strings[] = {
434         "United Computer Wizards",
435         "BSB Gateway",
436         usb_serial_number,
437 };
438
439 static const struct usb_device_descriptor device = {
440         .bLength = USB_DT_DEVICE_SIZE,
441         .bDescriptorType = USB_DT_DEVICE,
442         .bcdUSB = 0x0200,
443         .bDeviceClass = 0xFF,
444         .bDeviceSubClass = 0,
445         .bDeviceProtocol = 0,
446         .bMaxPacketSize0 = 64,
447         .idVendor = BSB_USB_VENDOR,
448         .idProduct = BSB_USB_PRODUCT,
449         .bcdDevice = BSB_USB_VERSION,
450         .iManufacturer = STR_MANUFACTURER,
451         .iProduct = STR_PRODUCT,
452         .iSerialNumber = STR_SERIAL,
453         .bNumConfigurations = 1,
454 };
455
456 static const struct usb_endpoint_descriptor endpoints[] = {{
457         // Bulk end-point for sending frames to BSB
458         .bLength = USB_DT_ENDPOINT_SIZE,
459         .bDescriptorType = USB_DT_ENDPOINT,
460         .bEndpointAddress = 0x01,
461         .bmAttributes = USB_ENDPOINT_ATTR_BULK,
462         .wMaxPacketSize = 64,
463         .bInterval = 1,
464 },{
465         // Interrupt end-point for receiving frames from BSB
466         .bLength = USB_DT_ENDPOINT_SIZE,
467         .bDescriptorType = USB_DT_ENDPOINT,
468         .bEndpointAddress = 0x82,
469         .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
470         .wMaxPacketSize = 64,
471         .bInterval = 1,
472 }};
473
474 static const struct usb_interface_descriptor iface = {
475         .bLength = USB_DT_INTERFACE_SIZE,
476         .bDescriptorType = USB_DT_INTERFACE,
477         .bInterfaceNumber = 0,
478         .bAlternateSetting = 0,
479         .bNumEndpoints = 2,
480         .bInterfaceClass = 0xFF,
481         .bInterfaceSubClass = 0,
482         .bInterfaceProtocol = 0,
483         .iInterface = 0,
484         .endpoint = endpoints,
485 };
486
487 static const struct usb_dfu_descriptor dfu_function = {
488         .bLength = sizeof(struct usb_dfu_descriptor),
489         .bDescriptorType = DFU_FUNCTIONAL,
490         .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
491         .wDetachTimeout = 255,
492         .wTransferSize = 1024,
493         .bcdDFUVersion = 0x0100,
494 };
495
496 static const struct usb_interface_descriptor dfu_iface = {
497         .bLength = USB_DT_INTERFACE_SIZE,
498         .bDescriptorType = USB_DT_INTERFACE,
499         .bInterfaceNumber = 1,
500         .bAlternateSetting = 0,
501         .bNumEndpoints = 0,
502         .bInterfaceClass = 0xFE,
503         .bInterfaceSubClass = 1,
504         .bInterfaceProtocol = 1,
505         .iInterface = 0,
506
507         .extra = &dfu_function,
508         .extralen = sizeof(dfu_function),
509 };
510
511 static const struct usb_interface ifaces[] = {{
512         .num_altsetting = 1,
513         .altsetting = &iface,
514 }, {
515         .num_altsetting = 1,
516         .altsetting = &dfu_iface,
517 }};
518
519 static const struct usb_config_descriptor config = {
520         .bLength = USB_DT_CONFIGURATION_SIZE,
521         .bDescriptorType = USB_DT_CONFIGURATION,
522         .wTotalLength = 0,
523         .bNumInterfaces = 2,
524         .bConfigurationValue = 1,
525         .iConfiguration = 0,
526         .bmAttributes = 0x80,
527         .bMaxPower = 50,        // multiplied by 2 mA
528         .interface = ifaces,
529 };
530
531 static byte usb_configured;
532 static byte usb_ep82_pending;
533 static uint8_t usbd_control_buffer[64];
534
535 static enum usbd_request_return_codes control_cb(
536         usbd_device *dev UNUSED,
537         struct usb_setup_data *req,
538         uint8_t **buf,
539         uint16_t *len,
540         void (**complete)(usbd_device *dev, struct usb_setup_data *req) UNUSED)
541 {
542         if (req->bmRequestType != 0xc0 || req->bRequest != 0x00)
543                 return USBD_REQ_NOTSUPP;
544
545         // We support reading of statistics via control requests
546         debug_printf("USB: Reading statistics\n");
547         uint n = MIN(*len, sizeof(bsb_stats));
548         memcpy(*buf, (char *) &bsb_stats, n);
549         *len = n;
550
551         return USBD_REQ_HANDLED;
552 }
553
554 static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
555 {
556         // Reset to bootloader, which implements the rest of DFU
557         debug_printf("Switching to DFU\n");
558         debug_flush();
559         scb_reset_core();
560 }
561
562 static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
563         struct usb_setup_data *req,
564         uint8_t **buf UNUSED,
565         uint16_t *len UNUSED,
566         void (**complete)(usbd_device *dev, struct usb_setup_data *req))
567 {
568         if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
569                 return USBD_REQ_NOTSUPP;
570
571         *complete = dfu_detach_complete;
572         return USBD_REQ_HANDLED;
573 }
574
575 static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED)
576 {
577         // We received a frame from the USB host
578         byte buf[64];
579         uint len = usbd_ep_read_packet(dev, 0x01, buf, sizeof(buf));
580         debug_printf("USB: Host sent %u bytes\n", len);
581         bsb_send(buf, len);
582 }
583
584 static void ep82_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED)
585 {
586         // The frame was accepted by the USB host
587         debug_printf("USB: Interrupt done\n");
588         usb_ep82_pending = 0;
589 }
590
591 static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED)
592 {
593         usbd_register_control_callback(
594                 dev,
595                 USB_REQ_TYPE_VENDOR,
596                 USB_REQ_TYPE_TYPE,
597                 control_cb);
598         usbd_register_control_callback(
599                 dev,
600                 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
601                 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
602                 dfu_control_cb);
603         usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb);
604         usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 64, ep82_cb);
605         usb_configured = 1;
606 }
607
608 static void reset_cb(void)
609 {
610         debug_printf("USB: Reset\n");
611         usb_configured = 0;
612         usb_ep82_pending = 0;
613 }
614
615 static volatile bool usb_event_pending;
616
617 void usb_lp_can_rx0_isr(void)
618 {
619         /*
620          *  We handle USB in the main loop to avoid race conditions between
621          *  USB interrupts and other code. However, we need an interrupt to
622          *  up the main loop from sleep.
623          *
624          *  We set up only the low-priority ISR, because high-priority ISR handles
625          *  only double-buffered bulk transfers and isochronous transfers.
626          */
627         nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
628         usb_event_pending = 1;
629 }
630
631 static void usb_init(void)
632 {
633         // Simulate USB disconnect
634         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
635         gpio_clear(GPIOA, GPIO11 | GPIO12);
636         delay_ms(100);
637
638         usbd_dev = usbd_init(
639                 &st_usbfs_v1_usb_driver,
640                 &device,
641                 &config,
642                 usb_strings,
643                 ARRAY_SIZE(usb_strings),
644                 usbd_control_buffer,
645                 sizeof(usbd_control_buffer)
646         );
647         usbd_register_reset_callback(usbd_dev, reset_cb);
648         usbd_register_set_config_callback(usbd_dev, set_config_cb);
649         usb_event_pending = 1;
650 }
651
652 /*** Main ***/
653
654 int main(void)
655 {
656         clock_init();
657         gpio_init();
658         tick_init();
659         usart_init();
660         desig_get_unique_id_as_dfu(usb_serial_number);
661         random_init();
662
663         debug_printf("Hail, Lord Damian! Thy BSB interface is ready.\n");
664
665         bsb_init();
666         usb_init();
667
668         u32 last_blink = 0;
669         u32 last_step = 0;
670
671         for (;;) {
672                 if (ms_ticks - last_blink >= 100) {
673                         debug_led_toggle();
674                         last_blink = ms_ticks;
675                 }
676
677                 if (usb_event_pending) {
678                         usbd_poll(usbd_dev);
679                         usb_event_pending = 0;
680                         nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ);
681                         nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
682                 }
683
684                 if (usb_configured) {
685                         // Passing of received frames to USB
686                         if (!usb_ep82_pending) {
687                                 if (bsb_rx_frame_len) {
688                                         barrier();
689                                         usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len);
690                                         usb_ep82_pending = 1;
691                                         barrier();
692                                         bsb_rx_frame_len = 0;
693                                         debug_printf("USB: Sending frame to interrupt EP\n");
694                                 }
695                                 if (bsb_tx_result != TX_RESULT_NONE) {
696                                         usbd_ep_write_packet(usbd_dev, 0x82, &bsb_tx_result, 1);
697                                         usb_ep82_pending = 1;
698                                         gpio_set(GPIOB, GPIO0);         // Turn the TX LED off
699                                         debug_printf("USB: Sending status %u to interrupt EP\n", bsb_tx_result);
700                                         bsb_tx_result = TX_RESULT_NONE;
701                                 }
702                         }
703                 }
704
705                 if (ms_ticks != last_step) {
706                         last_step = ms_ticks;
707                         bsb_rx_step();
708                         bsb_tx_step();
709                 }
710
711                 wait_for_interrupt();
712         }
713
714         return 0;
715 }