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