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