]> mj.ucw.cz Git - home-hw.git/blob - bsb/firmware/main.c
BSB: Receiving works
[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
9 #include <libopencm3/cm3/cortex.h>
10 #include <libopencm3/cm3/nvic.h>
11 #include <libopencm3/cm3/systick.h>
12 #include <libopencm3/cm3/scb.h>
13 #include <libopencm3/stm32/rcc.h>
14 #include <libopencm3/stm32/desig.h>
15 #include <libopencm3/stm32/gpio.h>
16 #include <libopencm3/stm32/timer.h>
17 #include <libopencm3/stm32/usart.h>
18 #include <libopencm3/usb/dfu.h>
19 #include <libopencm3/usb/usbd.h>
20
21 #include <string.h>
22
23 /*** Hardware init ***/
24
25 static void clock_init(void)
26 {
27         rcc_clock_setup_in_hse_8mhz_out_72mhz();
28
29         rcc_periph_clock_enable(RCC_GPIOA);
30         rcc_periph_clock_enable(RCC_GPIOB);
31         rcc_periph_clock_enable(RCC_GPIOC);
32         rcc_periph_clock_enable(RCC_USART1);
33         rcc_periph_clock_enable(RCC_USART3);
34         rcc_periph_clock_enable(RCC_USB);
35
36         rcc_periph_reset_pulse(RST_GPIOA);
37         rcc_periph_reset_pulse(RST_GPIOB);
38         rcc_periph_reset_pulse(RST_GPIOC);
39         rcc_periph_reset_pulse(RST_USART1);
40         rcc_periph_reset_pulse(RST_USART3);
41         rcc_periph_reset_pulse(RST_USB);
42 }
43
44 static void gpio_init(void)
45 {
46         // PA9 = TXD1 for debugging console
47         // PA10 = RXD1 for debugging console
48         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
49         gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
50
51         // PC13 = BluePill LED
52         gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
53         gpio_clear(GPIOC, GPIO13);
54
55         // PB0 = yellow LED*, PB1 = green LED*
56         gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO0 | GPIO1);
57         gpio_set(GPIOB, GPIO0 | GPIO1);
58
59         // PB10 = TXD3 for BSB
60         // PB11 = RXD3 for BSB
61         // FIXME: TX turned off temporarily
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_RX);
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 /*** BSB ***/
102
103 #define BSB_MAX_SIZE 32
104 #define BSB_RX_TIMEOUT 10  // ms
105
106 #define DEBUG_BSB
107 #ifdef DEBUG_BSB
108 #define BSB_DEBUG(x...) debug_printf(x)
109 #else
110 #define BSB_DEBUG(x...) do { } while (0)
111 #endif
112
113 static byte bsb_rx_buf[BSB_MAX_SIZE];
114 static byte bsb_rx_len;
115 static u16 bsb_rx_crc;
116 static volatile u32 bsb_rx_timestamp;
117
118 // Passing received frames to the main loop
119 static byte bsb_rx_frame[BSB_MAX_SIZE];
120 static volatile byte bsb_rx_frame_len;
121 static byte bsb_rx_frame_led;
122
123 struct bsb_stat {
124         u32 rx_noise;
125         u32 rx_errors;
126         u32 rx_invalid;
127         u32 rx_overruns;
128         u32 rx_timeouts;
129         u32 rx_bad_crc;
130         u32 rx_ok;
131 };
132
133 static struct bsb_stat bsb_stat;
134
135 static u16 bsb_crc_update(u16 crc, byte data)
136 {
137         crc = crc ^ (data << 8);
138         for (uint i=0; i<8; i++) {
139                 if (crc & 0x8000)
140                         crc = (crc << 1) ^ 0x1021;
141                 else
142                         crc <<= 1;
143         }
144         return crc;
145 }
146
147 void usart3_isr(void)
148 {
149         u32 status = USART_SR(USART3);
150
151         if (status & USART_SR_RXNE) {
152                 uint ch = ~usart_recv(USART3) & 0xff;
153                 bsb_rx_timestamp = ms_ticks;
154                 BSB_DEBUG(" %02x", ch);
155
156                 if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
157                         bsb_stat.rx_errors++;
158                         bsb_rx_len = 0;
159                 } else if (!bsb_rx_len) {
160                         // Start of frame
161                         if (ch == 0xdc) {
162                                 bsb_rx_buf[bsb_rx_len++] = ch;
163                                 bsb_rx_crc = bsb_crc_update(0, ch);
164                                 BSB_DEBUG("<");
165                         } else {
166                                 bsb_stat.rx_noise++;
167                                 BSB_DEBUG("?");
168                         }
169                 } else {
170                         bsb_rx_buf[bsb_rx_len++] = ch;
171                         bsb_rx_crc = bsb_crc_update(bsb_rx_crc, ch);
172                         if (bsb_rx_len < 4) {
173                                 // First three bytes: SOF, source addr, destination addr
174                         } else if (bsb_rx_len == 4) {
175                                 // Received length byte
176                                 if (bsb_rx_buf[3] < 7 || bsb_rx_buf[3] > BSB_MAX_SIZE) {
177                                         bsb_stat.rx_invalid++;
178                                         bsb_rx_len = 0;
179                                         BSB_DEBUG("!L");
180                                 }
181                         } else if (bsb_rx_len == bsb_rx_buf[3]) {
182                                 // Received a complete frame: check CRC and pass it to the main loop
183                                 if (bsb_rx_crc) {
184                                         bsb_stat.rx_bad_crc++;
185                                         BSB_DEBUG("!C");
186                                 } else {
187                                         if (bsb_rx_frame_len) {
188                                                 // The previous one was not sent yet
189                                                 bsb_stat.rx_overruns++;
190                                                 BSB_DEBUG("!O");
191                                         } else {
192                                                 memcpy(bsb_rx_frame, bsb_rx_buf, bsb_rx_buf[3]);
193                                                 bsb_rx_frame_len = bsb_rx_buf[3];
194                                                 bsb_stat.rx_ok++;
195                                                 BSB_DEBUG(".");
196                                         }
197                                         gpio_clear(GPIOB, GPIO1);
198                                         bsb_rx_frame_led = 100;
199                                 }
200                                 bsb_rx_len = 0;
201                         }
202                 }
203         }
204 }
205
206 static void bsb_init(void)
207 {
208         usart_set_baudrate(USART3, 4800);
209         usart_set_databits(USART3, 9);
210         usart_set_stopbits(USART3, USART_STOPBITS_1);
211         usart_set_mode(USART3, USART_MODE_RX);
212         usart_set_parity(USART3, USART_PARITY_ODD);
213         usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
214
215         usart_enable(USART3);
216         nvic_enable_irq(NVIC_USART3_IRQ);
217         usart_enable_rx_interrupt(USART3);
218 }
219
220 /*** USB ***/
221
222 static usbd_device *usbd_dev;
223
224 static const struct usb_device_descriptor device = {
225         .bLength = USB_DT_DEVICE_SIZE,
226         .bDescriptorType = USB_DT_DEVICE,
227         .bcdUSB = 0x0200,
228         .bDeviceClass = 0xFF,
229         .bDeviceSubClass = 0,
230         .bDeviceProtocol = 0,
231         .bMaxPacketSize0 = 64,
232         .idVendor = 0x4242,
233         .idProduct = 0x0003,
234         .bcdDevice = 0x0200,
235         .iManufacturer = 1,
236         .iProduct = 2,
237         .iSerialNumber = 3,
238         .bNumConfigurations = 1,
239 };
240
241 static const struct usb_endpoint_descriptor endpoints[] = {{
242         .bLength = USB_DT_ENDPOINT_SIZE,
243         .bDescriptorType = USB_DT_ENDPOINT,
244         .bEndpointAddress = 0x81,
245         .bmAttributes = USB_ENDPOINT_ATTR_BULK,
246         .wMaxPacketSize = 64,
247         .bInterval = 1,
248 },{
249         .bLength = USB_DT_ENDPOINT_SIZE,
250         .bDescriptorType = USB_DT_ENDPOINT,
251         .bEndpointAddress = 0x82,
252         .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
253         .wMaxPacketSize = 64,
254         .bInterval = 1,
255 }};
256
257 static const struct usb_interface_descriptor iface = {
258         .bLength = USB_DT_INTERFACE_SIZE,
259         .bDescriptorType = USB_DT_INTERFACE,
260         .bInterfaceNumber = 0,
261         .bAlternateSetting = 0,
262         .bNumEndpoints = 2,
263         .bInterfaceClass = 0xFF,
264         .bInterfaceSubClass = 0,
265         .bInterfaceProtocol = 0,
266         .iInterface = 0,
267         .endpoint = endpoints,
268 };
269
270 static const struct usb_dfu_descriptor dfu_function = {
271         .bLength = sizeof(struct usb_dfu_descriptor),
272         .bDescriptorType = DFU_FUNCTIONAL,
273         .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
274         .wDetachTimeout = 255,
275         .wTransferSize = 1024,
276         .bcdDFUVersion = 0x0100,
277 };
278
279 static const struct usb_interface_descriptor dfu_iface = {
280         .bLength = USB_DT_INTERFACE_SIZE,
281         .bDescriptorType = USB_DT_INTERFACE,
282         .bInterfaceNumber = 1,
283         .bAlternateSetting = 0,
284         .bNumEndpoints = 0,
285         .bInterfaceClass = 0xFE,
286         .bInterfaceSubClass = 1,
287         .bInterfaceProtocol = 1,
288         .iInterface = 0,
289
290         .extra = &dfu_function,
291         .extralen = sizeof(dfu_function),
292 };
293
294 static const struct usb_interface ifaces[] = {{
295         .num_altsetting = 1,
296         .altsetting = &iface,
297 }, {
298         .num_altsetting = 1,
299         .altsetting = &dfu_iface,
300 }};
301
302 static const struct usb_config_descriptor config = {
303         .bLength = USB_DT_CONFIGURATION_SIZE,
304         .bDescriptorType = USB_DT_CONFIGURATION,
305         .wTotalLength = 0,
306         .bNumInterfaces = 2,
307         .bConfigurationValue = 1,
308         .iConfiguration = 0,
309         .bmAttributes = 0x80,
310         .bMaxPower = 50,        // multiplied by 2 mA
311         .interface = ifaces,
312 };
313
314 static char usb_serial_number[13];
315
316 static const char *usb_strings[] = {
317         "United Computer Wizards",
318         "BSB Gateway",
319         usb_serial_number,
320 };
321
322 static byte usb_configured;
323 static byte usb_rx_pending;
324 static uint8_t usbd_control_buffer[64];
325
326 static enum usbd_request_return_codes control_cb(
327         usbd_device *dev UNUSED,
328         struct usb_setup_data *req,
329         uint8_t **buf,
330         uint16_t *len,
331         void (**complete)(usbd_device *dev, struct usb_setup_data *req) UNUSED)
332 {
333         if (req->bmRequestType != 0xc0 || req->bRequest != 0x00)
334                 return USBD_REQ_NOTSUPP;
335
336         // We support reading of statistics via control requests
337         debug_printf("USB: Reading statistics\n");
338         uint n = MIN(*len, sizeof(bsb_stat));
339         memcpy(*buf, (char *) &bsb_stat, n);
340         *len = n;
341
342         return USBD_REQ_HANDLED;
343 }
344
345 static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
346 {
347         // Reset to bootloader, which implements the rest of DFU
348         debug_printf("Switching to DFU\n");
349         debug_flush();
350         scb_reset_core();
351 }
352
353 static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
354         struct usb_setup_data *req,
355         uint8_t **buf UNUSED,
356         uint16_t *len UNUSED,
357         void (**complete)(usbd_device *dev, struct usb_setup_data *req))
358 {
359         if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
360                 return USBD_REQ_NOTSUPP;
361
362         *complete = dfu_detach_complete;
363         return USBD_REQ_HANDLED;
364 }
365
366 static void ep81_cb(usbd_device *dev, uint8_t ep UNUSED)
367 {
368         byte buf[4];
369         put_u32_be(buf, ms_ticks);
370         usbd_ep_write_packet(dev, 0x81, buf, sizeof(buf));
371         debug_printf("USB: Bulk write\n");
372 }
373
374 static void rx_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED)
375 {
376         // Received packet passed through interrupt end-point
377         debug_printf("USB: RX EP done\n");
378         usb_rx_pending = 0;
379 }
380
381 static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED)
382 {
383         usbd_register_control_callback(dev,
384                 USB_REQ_TYPE_VENDOR,
385                 USB_REQ_TYPE_TYPE,
386                 control_cb);
387         usbd_register_control_callback(dev,
388                 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
389                 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
390                 dfu_control_cb);
391         usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb);
392         usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, rx_cb);
393         ep81_cb(dev, 0);
394         usb_configured = 1;
395 }
396
397 static void reset_cb(void)
398 {
399         debug_printf("USB: Reset\n");
400         usb_configured = 0;
401 }
402
403 static volatile bool usb_event_pending;
404
405 void usb_lp_can_rx0_isr(void)
406 {
407         /*
408          *  We handle USB in the main loop to avoid race conditions between
409          *  USB interrupts and other code. However, we need an interrupt to
410          *  up the main loop from sleep.
411          *
412          *  We set up only the low-priority ISR, because high-priority ISR handles
413          *  only double-buffered bulk transfers and isochronous transfers.
414          */
415         nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
416         usb_event_pending = 1;
417 }
418
419 static void usb_init(void)
420 {
421         // Simulate USB disconnect
422         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
423         gpio_clear(GPIOA, GPIO11 | GPIO12);
424         delay_ms(1000);
425
426         usbd_dev = usbd_init(
427                 &st_usbfs_v1_usb_driver,
428                 &device,
429                 &config,
430                 usb_strings,
431                 ARRAY_SIZE(usb_strings),
432                 usbd_control_buffer,
433                 sizeof(usbd_control_buffer)
434         );
435         usbd_register_reset_callback(usbd_dev, reset_cb);
436         usbd_register_set_config_callback(usbd_dev, set_config_cb);
437         usb_event_pending = 1;
438 }
439
440 /*** Main ***/
441
442 int main(void)
443 {
444         clock_init();
445         gpio_init();
446         tick_init();
447         usart_init();
448         desig_get_unique_id_as_dfu(usb_serial_number);
449
450         debug_printf("Hello, kitty!\n");
451
452         bsb_init();
453         usb_init();
454
455         u32 last_ds_step = 0;
456
457         for (;;) {
458                 if (ms_ticks - last_ds_step >= 100) {
459                         debug_led_toggle();
460                         gpio_toggle(GPIOB, GPIO0);
461                         last_ds_step = ms_ticks;
462                 }
463
464                 if (usb_event_pending) {
465                         usbd_poll(usbd_dev);
466                         usb_event_pending = 0;
467                         nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ);
468                         nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
469                 }
470
471                 if (usb_configured) {
472                         // Passing of received packets to USB
473                         if (!usb_rx_pending) {
474                                 if (bsb_rx_frame_len) {
475                                         barrier();
476                                         usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len);
477                                         usb_rx_pending = 1;
478                                         barrier();
479                                         bsb_rx_frame_len = 0;
480                                         debug_printf("USB: RX started\n");
481                                 }
482                         }
483                 }
484
485                 // Packet timeouts
486                 cm_disable_interrupts();
487                 barrier();
488                 if (bsb_rx_len && ms_ticks - bsb_rx_timestamp >= BSB_RX_TIMEOUT) {
489                         bsb_rx_len = 0;
490                         bsb_stat.rx_timeouts++;
491                         BSB_DEBUG("!T");
492                 }
493                 if (bsb_rx_frame_led) {
494                         if (!--bsb_rx_frame_led)
495                                 gpio_set(GPIOB, GPIO1);
496                 }
497                 cm_enable_interrupts();
498
499                 wait_for_interrupt();
500         }
501
502         return 0;
503 }