]> mj.ucw.cz Git - home-hw.git/blob - bsb/firmware/main.c
BSB: Bug fixes
[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       // If no byte was received for this time, end the current frame [ms]
122 #define BSB_TX_IDLE_LINE 100    // Consider the line idle if no byte was received for this time [ms]
123 #define BSB_TX_MAX_ATTEMPTS 3
124 #define BSB_TX_WAIT_LOG 8       // base 2 log of pre-frame waiting time in ms
125 #define BSB_TX_TIMEOUT 10000    // Total time to transmit a frame including all retries and waiting for reply [ms]
126 #define BSB_REPLY_TIMEOUT 1000  // How long to wait for a reply [ms]
127
128 #undef DEBUG_BSB
129 #ifdef DEBUG_BSB
130 #define BSB_DEBUG(x) debug_putc(x)
131 #else
132 #define BSB_DEBUG(x) do { } while (0)
133 #endif
134
135 struct bsb_state {
136         byte rx_len;                    // Bytes received so far
137         byte rx_led;                    // Countdown to turning RX LED off
138         u16 rx_crc;
139         volatile u32 rx_timestamp;      // Last byte received
140
141         byte tx_state;                  // TX_STATE_xxx
142         byte tx_len;
143         byte tx_send_index;
144         byte tx_check_index;
145         byte tx_attempts;
146         byte tx_result;                 // TX_RESULT_xxx
147         byte tx_want_reply;
148         u32 tx_start_timestamp;
149         u32 tx_ticks_to_send;
150         u32 tx_end_timestamp;
151
152         byte rx_buf[BSB_MAX_SIZE];
153         byte tx_buf[BSB_MAX_SIZE];
154 };
155
156 static struct bsb_state bsb;
157
158 // Passing received frames and status codes to the main loop
159 static byte bsb_rx_status_and_frame[1 + BSB_MAX_SIZE];
160 static volatile byte bsb_rx_frame_len;
161 static byte bsb_tx_result;
162
163 enum bsb_tx_state {
164         TX_STATE_OFF,
165         TX_STATE_WAITING_FOR_IDLE_LINE,
166         TX_STATE_PRE_PACKET_DELAY,
167         TX_STATE_SENDING,
168         TX_STATE_SENT,
169         TX_STATE_WAITING_FOR_REPLY,
170         TX_STATE_COLLISION,
171 };
172
173 static struct bsb_stats bsb_stats;
174
175 static void bsb_attempt_tx(void);
176
177 static u16 bsb_crc_update(u16 crc, byte data)
178 {
179         crc = crc ^ (data << 8);
180         for (uint i=0; i<8; i++) {
181                 if (crc & 0x8000)
182                         crc = (crc << 1) ^ 0x1021;
183                 else
184                         crc <<= 1;
185         }
186         return crc;
187 }
188
189 void usart3_isr(void)
190 {
191         u32 status = USART_SR(USART3);
192
193         if (status & USART_SR_RXNE) {
194                 uint ch = ~usart_recv(USART3) & 0xff;
195                 bsb.rx_timestamp = ms_ticks;
196 #ifdef DEBUG_BSB
197                 debug_printf(" %02x", ch);
198 #endif
199
200                 if (bsb.tx_state == TX_STATE_SENDING) {
201                         // We are hearing the echo of a transmitted packet, check it for collisions
202                         if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
203                                 BSB_DEBUG('e');
204                                 bsb.tx_state = TX_STATE_COLLISION;
205                         } else if (ch == bsb.tx_buf[bsb.tx_check_index++]) {
206                                 if (bsb.tx_check_index >= bsb.tx_len) {
207                                         BSB_DEBUG('d');
208                                         bsb.tx_state = TX_STATE_SENT;
209                                 }
210                         } else {
211                                 BSB_DEBUG('c');
212                                 bsb.tx_state = TX_STATE_COLLISION;
213                         }
214                 } else {
215                         // Regular receive
216                         if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
217                                 bsb_stats.rx_errors++;
218                                 bsb.rx_len = 0;
219                         } else if (!bsb.rx_len) {
220                                 // Start of frame
221                                 if (ch == 0xdc) {
222                                         bsb.rx_buf[bsb.rx_len++] = ch;
223                                         bsb.rx_crc = bsb_crc_update(0, ch);
224                                         BSB_DEBUG('<');
225                                 } else {
226                                         bsb_stats.rx_noise++;
227                                         BSB_DEBUG('?');
228                                 }
229                         } else {
230                                 bsb.rx_buf[bsb.rx_len++] = ch;
231                                 bsb.rx_crc = bsb_crc_update(bsb.rx_crc, ch);
232                                 if (bsb.rx_len < 4) {
233                                         // First three bytes: SOF, source addr, destination addr
234                                 } else if (bsb.rx_len == 4) {
235                                         // Received length byte
236                                         if (bsb.rx_buf[BF_LEN] < 7 || bsb.rx_buf[BF_LEN] > BSB_MAX_SIZE) {
237                                                 bsb_stats.rx_invalid++;
238                                                 bsb.rx_len = 0;
239                                                 BSB_DEBUG('L');
240                                         }
241                                 } else if (bsb.rx_len == bsb.rx_buf[BF_LEN]) {
242                                         // Received a complete frame: check CRC and pass it to the main loop
243                                         if (bsb.rx_crc) {
244                                                 bsb_stats.rx_bad_crc++;
245                                                 BSB_DEBUG('C');
246                                         } else {
247                                                 if (bsb_rx_frame_len) {
248                                                         // The previous one was not sent yet
249                                                         bsb_stats.rx_overruns++;
250                                                         BSB_DEBUG('O');
251                                                 } else {
252                                                         bsb_rx_frame_len = bsb.rx_buf[BF_LEN];
253                                                         memcpy(bsb_rx_status_and_frame + 1, bsb.rx_buf, bsb_rx_frame_len);
254                                                         bsb_stats.rx_ok++;
255                                                         BSB_DEBUG('.');
256                                                         // Will match with expected replies in main loop
257                                                 }
258                                                 gpio_clear(GPIOB, GPIO1);
259                                                 bsb.rx_led = 100;
260                                         }
261                                         bsb.rx_len = 0;
262                                 }
263                         }
264                 }
265         }
266
267         if (status & USART_SR_TXE) {
268                 if (bsb.tx_state == TX_STATE_SENDING && bsb.tx_send_index < bsb.tx_len) {
269                         BSB_DEBUG('>');
270                         usart_send(USART3, bsb.tx_buf[bsb.tx_send_index++] ^ 0xff);
271                 } else {
272                         usart_disable_tx_interrupt(USART3);
273                         // Main loop will be notified by receiving the echo of our frame,
274                         // so we do not need to wait for the "transmit complete" flag.
275                 }
276         }
277 }
278
279 static void bsb_rx_step(void)
280 {
281         cm_disable_interrupts();
282         barrier();
283         if (bsb.rx_len && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) {
284                 bsb.rx_len = 0;
285                 bsb_stats.rx_timeouts++;
286                 BSB_DEBUG('T');
287         }
288         if (bsb.rx_led) {
289                 if (!--bsb.rx_led)
290                         gpio_set(GPIOB, GPIO1);
291         }
292         cm_enable_interrupts();
293 }
294
295 static void bsb_tx_step(void)
296 {
297         switch (bsb.tx_state) {
298                 case TX_STATE_WAITING_FOR_IDLE_LINE:
299                         if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE)
300                                 return;
301                         bsb.tx_state = TX_STATE_PRE_PACKET_DELAY;
302                         BSB_DEBUG('i');
303                         // Fall thru
304                 case TX_STATE_PRE_PACKET_DELAY:
305                         if (ms_ticks - bsb.tx_start_timestamp > BSB_TX_TIMEOUT) {
306                                 bsb.tx_state = TX_STATE_OFF;
307                                 bsb_tx_result = TX_RESULT_TIMEOUT;
308                                 bsb_stats.tx_timeouts++;
309                                 return;
310                         }
311                         if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE) {
312                                 bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE;
313                                 BSB_DEBUG('n');
314                                 return;
315                         }
316                         if (--bsb.tx_ticks_to_send)
317                                 return;
318                         BSB_DEBUG('s');
319                         bsb.rx_timestamp = ms_ticks;
320                         barrier();
321                         bsb.tx_state = TX_STATE_SENDING;
322                         barrier();
323                         usart_enable_tx_interrupt(USART3);
324                         return;
325                 case TX_STATE_SENDING:
326                         // In this state, we can race with the USART interrupt handler
327                         cm_disable_interrupts();
328                         if (bsb.tx_state == TX_STATE_SENDING && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) {
329                                 // The echo of our packet was truncated due to collision
330                                 bsb.tx_state = TX_STATE_COLLISION;
331                                 BSB_DEBUG('t');
332                         }
333                         cm_enable_interrupts();
334                         return;
335                 case TX_STATE_COLLISION:
336                         bsb_stats.tx_collisions++;
337                         bsb_attempt_tx();
338                         return;
339                 case TX_STATE_SENT:
340                         if (!bsb.tx_want_reply) {
341                                 // The frame needs no reply => confirm transmission
342                                 bsb_stats.tx_ok_no_reply++;
343                                 bsb.tx_state = TX_STATE_OFF;
344                                 bsb_tx_result = TX_RESULT_OK;
345                         } else {
346                                 bsb.tx_state = TX_STATE_WAITING_FOR_REPLY;
347                                 bsb.tx_end_timestamp = ms_ticks;
348                                 BSB_DEBUG('w');
349                         }
350                         return;
351                 case TX_STATE_WAITING_FOR_REPLY:
352                         if (ms_ticks - bsb.tx_end_timestamp > BSB_REPLY_TIMEOUT) {
353                                 // We did not receive a reply. Maybe the request was lost? Re-transmit it.
354                                 bsb_stats.tx_reply_timeouts++;
355                                 BSB_DEBUG('t');
356                                 bsb_attempt_tx();
357                         }
358                         return;
359                 default:
360                         ;
361         }
362 }
363
364 static void bsb_attempt_tx(void)
365 {
366         if (bsb.tx_attempts++ >= BSB_TX_MAX_ATTEMPTS) {
367                 bsb.tx_state = TX_STATE_OFF;
368                 bsb_tx_result = TX_RESULT_TOO_MANY_RETRIES;
369                 return;
370         }
371
372         bsb.tx_ticks_to_send = (random_u32() | 0x80000000) >> (32 - BSB_TX_WAIT_LOG - (bsb.tx_attempts-1));
373
374         bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE;
375         bsb.tx_send_index = 0;
376         bsb.tx_check_index = 0;
377         debug_printf("TX: Attempt #%u, wait for %u ms\n", bsb.tx_attempts, (uint) bsb.tx_ticks_to_send);
378 }
379
380 static void bsb_send(byte *buf, uint len)
381 {
382         // If a transmit is in progress, declare overrrun
383         if (bsb_tx_result != TX_RESULT_NONE) {
384                 bsb_stats.tx_overruns++;
385                 return;
386         }
387         if (bsb.tx_state != TX_STATE_OFF) {
388                 bsb_stats.tx_overruns++;
389                 bsb_tx_result = TX_RESULT_OVERRUN;
390                 return;
391         }
392
393         // Check frame validity
394         if (len < 7 || len > BSB_MAX_SIZE || buf[BF_SOF] != 0xdc || buf[BF_LEN] != len) {
395                 bsb_stats.tx_rejects++;
396                 bsb_tx_result = TX_RESULT_MALFORMED;
397                 return;
398         }
399
400         // Detect frame type and prepare expected reply types
401         if (buf[BF_OP] == BSB_OP_QUERY) {
402                 // So far, we allow only QUERY frames
403                 bsb.tx_want_reply = 1;
404         } else {
405                 bsb_stats.tx_rejects++;
406                 bsb_tx_result = TX_RESULT_FORBIDDEN;
407                 return;
408         }
409
410         // Fill in source address
411         buf[BF_SRC] = 0x80 + BSB_ADDR_GATEWAY;
412
413         // Calculate CRC
414         u16 crc = 0;
415         for (uint i = 0; i < len - 2; i++)
416                 crc = bsb_crc_update(crc, buf[i]);
417         buf[len-2] = crc >> 8;
418         buf[len-1] = crc;
419         debug_printf("TX: Prepared frame: type=%02x dest=%02x len=%u crc=%04x want_reply=%u\n", buf[BF_OP], buf[BF_DEST], len, crc, bsb.tx_want_reply);
420
421         // Queue frame for transmission
422         memcpy(bsb.tx_buf, buf, len);
423         bsb.tx_len = len;
424         bsb.tx_start_timestamp = ms_ticks;
425         bsb.tx_attempts = 0;
426         bsb_attempt_tx();
427
428         // Light the TX LED
429         gpio_clear(GPIOB, GPIO0);
430 }
431
432 static bool bsb_is_reply_for(byte *reply, byte *req) {
433         // Check source and destination address
434         if (reply[BF_DEST] != BSB_ADDR_GATEWAY ||
435             reply[BF_SRC] != (req[BF_DEST] ^ 0x80))
436                 return 0;
437
438         // Extract body of request and reply
439         byte *rq = req + BF_BODY;
440         byte *rp = reply + BF_BODY;
441         uint rq_len = req[BF_LEN];
442         uint rp_len = reply[BF_LEN];
443         if (rq_len < BF_BODY + 2 || rp_len < BF_BODY + 2)
444                 return 0;
445         rq_len -= BF_BODY + 2;
446         rp_len -= BF_BODY + 2;
447
448         // debug_printf("BSB: Matching reply op=%u/len=%u for op=%u/len=%u\n", reply[BF_OP], rp_len, req[BF_OP], rq_len);
449
450         switch (req[BF_OP]) {
451                 case BSB_OP_QUERY:
452                         switch (reply[BF_OP]) {
453                                 case BSB_OP_ANSWER:
454                                         if (rq_len >= 4 && rp_len >= 4 &&
455                                             rq[0] == rp[1] &&           // This is byte-swapped. Why?
456                                             rq[1] == rp[0] &&
457                                             rq[2] == rp[2] &&
458                                             rq[3] == rp[3])
459                                                 return 1;
460                                         return 0;
461                                 case BSB_OP_ERROR:
462                                         return 1;
463                         }
464                         return 0;
465                 default:
466                         return 0;
467         }
468 }
469
470 static void bsb_check_reply(void)
471 {
472         // Match received frame in bsb_rx_status_and_frame to expected replies
473         // and set the status in byte 0.
474
475         byte *frame = bsb_rx_status_and_frame + 1;
476         // XXX: This might be executed too fast, so we can still be in TX_STATE_SENT
477         if ((bsb.tx_state == TX_STATE_WAITING_FOR_REPLY || bsb.tx_state == TX_STATE_SENT) &&
478              bsb.tx_want_reply &&
479              bsb_is_reply_for(frame, bsb.tx_buf)) {
480                         debug_printf("BSB: Matched reply\n");
481                         bsb.tx_state = TX_STATE_OFF;
482                         bsb_stats.tx_ok_replied++;
483                         bsb_rx_status_and_frame[0] = TX_RESULT_OK;
484                         gpio_set(GPIOB, GPIO0);         // Turn the TX LED off
485                         return;
486         }
487
488         bsb_rx_status_and_frame[0] = TX_RESULT_NONE;
489 }
490
491 static void bsb_init(void)
492 {
493         usart_set_baudrate(USART3, 4800);
494         usart_set_databits(USART3, 9);
495         usart_set_stopbits(USART3, USART_STOPBITS_1);
496         usart_set_mode(USART3, USART_MODE_TX_RX);
497         usart_set_parity(USART3, USART_PARITY_ODD);
498         usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
499
500         usart_enable(USART3);
501         nvic_enable_irq(NVIC_USART3_IRQ);
502         usart_enable_rx_interrupt(USART3);
503 }
504
505 /*** USB ***/
506
507 static usbd_device *usbd_dev;
508
509 enum usb_string {
510         STR_MANUFACTURER = 1,
511         STR_PRODUCT,
512         STR_SERIAL,
513 };
514
515 static char usb_serial_number[13];
516
517 static const char *usb_strings[] = {
518         "United Computer Wizards",
519         "BSB Gateway",
520         usb_serial_number,
521 };
522
523 static const struct usb_device_descriptor device = {
524         .bLength = USB_DT_DEVICE_SIZE,
525         .bDescriptorType = USB_DT_DEVICE,
526         .bcdUSB = 0x0200,
527         .bDeviceClass = 0xFF,
528         .bDeviceSubClass = 0,
529         .bDeviceProtocol = 0,
530         .bMaxPacketSize0 = 64,
531         .idVendor = BSB_USB_VENDOR,
532         .idProduct = BSB_USB_PRODUCT,
533         .bcdDevice = BSB_USB_VERSION,
534         .iManufacturer = STR_MANUFACTURER,
535         .iProduct = STR_PRODUCT,
536         .iSerialNumber = STR_SERIAL,
537         .bNumConfigurations = 1,
538 };
539
540 static const struct usb_endpoint_descriptor endpoints[] = {{
541         // Bulk end-point for sending frames to BSB
542         .bLength = USB_DT_ENDPOINT_SIZE,
543         .bDescriptorType = USB_DT_ENDPOINT,
544         .bEndpointAddress = 0x01,
545         .bmAttributes = USB_ENDPOINT_ATTR_BULK,
546         .wMaxPacketSize = 64,
547         .bInterval = 1,
548 },{
549         // Interrupt end-point for receiving frames from BSB
550         .bLength = USB_DT_ENDPOINT_SIZE,
551         .bDescriptorType = USB_DT_ENDPOINT,
552         .bEndpointAddress = 0x82,
553         .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
554         .wMaxPacketSize = 64,
555         .bInterval = 1,
556 }};
557
558 static const struct usb_interface_descriptor iface = {
559         .bLength = USB_DT_INTERFACE_SIZE,
560         .bDescriptorType = USB_DT_INTERFACE,
561         .bInterfaceNumber = 0,
562         .bAlternateSetting = 0,
563         .bNumEndpoints = 2,
564         .bInterfaceClass = 0xFF,
565         .bInterfaceSubClass = 0,
566         .bInterfaceProtocol = 0,
567         .iInterface = 0,
568         .endpoint = endpoints,
569 };
570
571 static const struct usb_dfu_descriptor dfu_function = {
572         .bLength = sizeof(struct usb_dfu_descriptor),
573         .bDescriptorType = DFU_FUNCTIONAL,
574         .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
575         .wDetachTimeout = 255,
576         .wTransferSize = 1024,
577         .bcdDFUVersion = 0x0100,
578 };
579
580 static const struct usb_interface_descriptor dfu_iface = {
581         .bLength = USB_DT_INTERFACE_SIZE,
582         .bDescriptorType = USB_DT_INTERFACE,
583         .bInterfaceNumber = 1,
584         .bAlternateSetting = 0,
585         .bNumEndpoints = 0,
586         .bInterfaceClass = 0xFE,
587         .bInterfaceSubClass = 1,
588         .bInterfaceProtocol = 1,
589         .iInterface = 0,
590
591         .extra = &dfu_function,
592         .extralen = sizeof(dfu_function),
593 };
594
595 static const struct usb_interface ifaces[] = {{
596         .num_altsetting = 1,
597         .altsetting = &iface,
598 }, {
599         .num_altsetting = 1,
600         .altsetting = &dfu_iface,
601 }};
602
603 static const struct usb_config_descriptor config = {
604         .bLength = USB_DT_CONFIGURATION_SIZE,
605         .bDescriptorType = USB_DT_CONFIGURATION,
606         .wTotalLength = 0,
607         .bNumInterfaces = 2,
608         .bConfigurationValue = 1,
609         .iConfiguration = 0,
610         .bmAttributes = 0x80,
611         .bMaxPower = 50,        // multiplied by 2 mA
612         .interface = ifaces,
613 };
614
615 static byte usb_configured;
616 static byte usb_ep82_pending;
617 static uint8_t usbd_control_buffer[64];
618
619 static enum usbd_request_return_codes control_cb(
620         usbd_device *dev UNUSED,
621         struct usb_setup_data *req,
622         uint8_t **buf,
623         uint16_t *len,
624         void (**complete)(usbd_device *dev, struct usb_setup_data *req) UNUSED)
625 {
626         if (req->bmRequestType != 0xc0 || req->bRequest != 0x00)
627                 return USBD_REQ_NOTSUPP;
628
629         // We support reading of statistics via control requests
630         debug_printf("USB: Reading statistics\n");
631         uint n = MIN(*len, sizeof(bsb_stats));
632         memcpy(*buf, (char *) &bsb_stats, n);
633         *len = n;
634
635         return USBD_REQ_HANDLED;
636 }
637
638 static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
639 {
640         // Reset to bootloader, which implements the rest of DFU
641         debug_printf("Switching to DFU\n");
642         debug_flush();
643         scb_reset_core();
644 }
645
646 static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
647         struct usb_setup_data *req,
648         uint8_t **buf UNUSED,
649         uint16_t *len UNUSED,
650         void (**complete)(usbd_device *dev, struct usb_setup_data *req))
651 {
652         if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
653                 return USBD_REQ_NOTSUPP;
654
655         *complete = dfu_detach_complete;
656         return USBD_REQ_HANDLED;
657 }
658
659 static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED)
660 {
661         // We received a frame from the USB host
662         byte buf[64];
663         uint len = usbd_ep_read_packet(dev, 0x01, buf, sizeof(buf));
664         debug_printf("USB: Host sent %u bytes\n", len);
665         bsb_send(buf, len);
666 }
667
668 static void ep82_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED)
669 {
670         // The frame was accepted by the USB host
671         debug_printf("USB: Interrupt done\n");
672         usb_ep82_pending = 0;
673 }
674
675 static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED)
676 {
677         usbd_register_control_callback(
678                 dev,
679                 USB_REQ_TYPE_VENDOR,
680                 USB_REQ_TYPE_TYPE,
681                 control_cb);
682         usbd_register_control_callback(
683                 dev,
684                 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
685                 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
686                 dfu_control_cb);
687         usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb);
688         usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 64, ep82_cb);
689         usb_configured = 1;
690 }
691
692 static void reset_cb(void)
693 {
694         debug_printf("USB: Reset\n");
695         usb_configured = 0;
696         usb_ep82_pending = 0;
697 }
698
699 static volatile bool usb_event_pending;
700
701 void usb_lp_can_rx0_isr(void)
702 {
703         /*
704          *  We handle USB in the main loop to avoid race conditions between
705          *  USB interrupts and other code. However, we need an interrupt to
706          *  up the main loop from sleep.
707          *
708          *  We set up only the low-priority ISR, because high-priority ISR handles
709          *  only double-buffered bulk transfers and isochronous transfers.
710          */
711         nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
712         usb_event_pending = 1;
713 }
714
715 static void usb_init(void)
716 {
717         // Simulate USB disconnect
718         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
719         gpio_clear(GPIOA, GPIO11 | GPIO12);
720         delay_ms(100);
721
722         usbd_dev = usbd_init(
723                 &st_usbfs_v1_usb_driver,
724                 &device,
725                 &config,
726                 usb_strings,
727                 ARRAY_SIZE(usb_strings),
728                 usbd_control_buffer,
729                 sizeof(usbd_control_buffer)
730         );
731         usbd_register_reset_callback(usbd_dev, reset_cb);
732         usbd_register_set_config_callback(usbd_dev, set_config_cb);
733         usb_event_pending = 1;
734 }
735
736 /*** Main ***/
737
738 int main(void)
739 {
740         clock_init();
741         gpio_init();
742         tick_init();
743         usart_init();
744         desig_get_unique_id_as_dfu(usb_serial_number);
745         random_init();
746
747         debug_printf("Hail, Lord Damian! Thy BSB interface is ready.\n");
748
749         bsb_init();
750         usb_init();
751
752         u32 last_blink = 0;
753         u32 last_step = 0;
754
755         for (;;) {
756                 if (ms_ticks - last_blink >= 100) {
757                         debug_led_toggle();
758                         last_blink = ms_ticks;
759                 }
760
761                 if (usb_event_pending) {
762                         usbd_poll(usbd_dev);
763                         usb_event_pending = 0;
764                         nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ);
765                         nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
766                 }
767
768                 if (usb_configured) {
769                         // Passing of received frames to USB
770                         if (!usb_ep82_pending) {
771                                 if (bsb_rx_frame_len) {
772                                         // Received frame, possibly marked as reply
773                                         barrier();
774                                         bsb_check_reply();
775                                         usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_status_and_frame, 1 + bsb_rx_frame_len);
776                                         usb_ep82_pending = 1;
777                                         barrier();
778                                         bsb_rx_frame_len = 0;
779                                         debug_printf("USB: Sending frame to interrupt EP\n");
780                                 } else if (bsb_tx_result != TX_RESULT_NONE) {
781                                         // Only a transmission result
782                                         usbd_ep_write_packet(usbd_dev, 0x82, &bsb_tx_result, 1);
783                                         usb_ep82_pending = 1;
784                                         gpio_set(GPIOB, GPIO0);         // Turn the TX LED off
785                                         debug_printf("USB: Sending status %u to interrupt EP\n", bsb_tx_result);
786                                         bsb_tx_result = TX_RESULT_NONE;
787                                 }
788                         }
789                 }
790
791                 if (ms_ticks != last_step) {
792                         last_step = ms_ticks;
793                         bsb_rx_step();
794                         bsb_tx_step();
795                 }
796
797                 wait_for_interrupt();
798         }
799
800         return 0;
801 }