diff --git a/include/adc.h b/include/adc.h index 64d7119..7e25c3a 100644 --- a/include/adc.h +++ b/include/adc.h @@ -9,6 +9,7 @@ struct adc_state { uint32_t dma_ccr3; int32_t data[2]; bool has_adc; + bool overload[2]; ErrorCode error; }; diff --git a/include/adc_interface.h b/include/adc_interface.h index bfe1116..f8a572d 100644 --- a/include/adc_interface.h +++ b/include/adc_interface.h @@ -89,6 +89,7 @@ enum adc_reg_addr { #define ADC_CHn_CFG_DCBLK_DIS (1<<2) #define ADC_CHn_CFG_MUX_Pos 0 - +#define ADC_FSR_POS 0x7fffff +#define ADC_FSR_NEG -0x800000 #endif /* __ADC_INTERFACE_H__ */ diff --git a/include/global.h b/include/global.h index 05e1c01..1ba0609 100644 --- a/include/global.h +++ b/include/global.h @@ -23,6 +23,9 @@ #define APB1_PRESC (1<<(APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE1_Msk) >> RCC_CFGR_PPRE1_Pos])) #define AHB_PRESC (1<<(AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE_Msk) >> RCC_CFGR_HPRE_Pos])) +#define SYSTICK_INTERVAL_US 1000 + + enum ErrorCode { ERR_SUCCESS = 0, ERR_TIMEOUT, @@ -31,10 +34,58 @@ enum ErrorCode { ERR_DMA, ERR_BUSY, ERR_BUFFER_OVERFLOW, + ERR_RX_OVERRUN, + ERR_TX_OVERRUN, + ERR_FRAMING, + ERR_PROTOCOL, }; + typedef enum ErrorCode ErrorCode; +enum board_config { + /* The board assumes one of three configurations depending on connected periphery. + * + */ + + BCFG_DISPLAY, + /* When an I2C 1602 display is connected to the LCD connector on powerup, the board assumes its display + * configuration. In this configuration, the board scans the buttons connected on the Buttons connector and acts as + * a peripheral on the RS-485 bus, relaying information between the bus and the HCI peripherals. In addition to the + * LCD, the board controls three 8-digit 7-segment LED displays connected on the Buttons connector along with the + * buttons. + * + * RS-485 board address: BADDR_DISPLAY + */ + + BCFG_MOTOR, + /* When no LCD is connected and the BT0 input on the buttons connector is tied to ground, the board assumes its + * motor configuration. In this configuration, the board controls a motor connected through the Buttons and LCD + * connectors, and the USB control interface is enabled. The board acts as the host on the RS-485 bus. + * + * RS-485 board address: BADDR_MOTOR + */ + + BCFG_MEAS, + /* When no LCD is connected and the BT0 input on the buttons connector is open or tied to VDD, the board assumes its + * senesor configuration. In this configuration, the board periodically. The board acts as a peripheral on the + * RS-485 bus, relaying measurements on the bus when requested by the host. The board's bus address is set by pins + * BT1 and BT0 of the buttons connector. Both pins have pullups enabled, and will read zero when tied to ground on + * the connector. The address is the binary value of {BT2, BT1} added to BADDR_MES_BASE. With both pins open, the + * address is 11 (decimal), with BT1 tied to ground it is 10 (decimal). + * + * RS-485 board address: BADDR_MEAS_BASE + [BT2:1] + */ +}; + +enum board_addr { + BADDR_DISPLAY = 1, + BADDR_MOTOR = 2, + BADDR_MEAS_BASE = 8, +}; void delay_us(int duration_us); +extern enum board_config board_config; +extern uint64_t sys_time_us; + #endif /* __GLOBAL_H__ */ diff --git a/include/led.h b/include/led.h index e1a17ab..d59f136 100644 --- a/include/led.h +++ b/include/led.h @@ -10,9 +10,23 @@ struct apa102_pkt { uint8_t r; } __attribute__((packed)); +enum status_led { + LED_CONNECTED, + LED_ACQUIRING, + LED_ERROR, + LED_OVERLOAD, + LED_BUTTONS, + LED_DISPLAY, + LED_POWER, + LED_ENCODER, + LED_CHANNEL_A, + LED_CHANNEL_B, + LED_N_TOTAL, +}; + struct led_state { uint32_t _zeros; - struct apa102_pkt led[10]; + struct apa102_pkt led[LED_N_TOTAL]; uint32_t _ones; } __attribute__((packed)); diff --git a/include/proto.h b/include/proto.h new file mode 100644 index 0000000..35a6b99 --- /dev/null +++ b/include/proto.h @@ -0,0 +1,92 @@ +#ifndef __PROTO_H__ +#define __PROTO_H__ + +#include +#include + + +#define PROTO_RESPONSE_TIMEOUT_MS 20 +#define PROTO_UPDATE_INTERVAL_MS 200 + + +enum proto_fsm { + ST_START = 0, + ST_TIME_SYNC, + ST_FETCH_0, + ST_FETCH_1, + ST_UPDATE_DISPLAY, + ST_WAITING, +}; + +enum packet_type { + PK_TIME_SYNC, + PK_FETCH_ADC, + PK_FETCH_RESPONSE, + PK_DISPLAY_UPDATE, + PK_BUTTON_STATE, +}; + + +struct proto_state { + enum proto_fsm fsm; + uint64_t last_start; + int delta; + ErrorCode error; + uint64_t last_error; + bool timeout[3]; + const char *status_msg; + const char *error_msg; + + uint8_t rx_buttons; + bool rx_lid_open; + bool rx_estop; +}; + +enum proto_led_format { + PROTO_LED_FMT_OFF = 0x00, + PROTO_LED_FMT_DEC = 0x01, + PROTO_LED_FMT_HEX = 0x02, + PROTO_LED_FMT_DP_0 = 0x00, + PROTO_LED_FMT_DP_1 = 0x20, + PROTO_LED_FMT_DP_2 = 0x40, + PROTO_LED_FMT_DP_3 = 0x60, + PROTO_LED_FMT_DP_4 = 0x80, + PROTO_LED_FMT_DP_5 = 0xa0, + PROTO_LED_FMT_DP_6 = 0xc0, + PROTO_LED_FMT_DP_7 = 0xe0, +}; + +struct __attribute__((__packed__)) pkt_update_display { + struct ll_pkt ll_pkt; + char lcd[20*4]; + uint32_t led[3]; + uint8_t led_fmt[3]; +}; + +enum proto_display_buttons { + PROTO_DSP_BT_RED, /* Bottom left of display panel */ + PROTO_DSP_BT_GREEN, /* Bottom right of display panel */ + PROTO_DSP_BT_TOP, /* Top right of display panel, next to the LCD, above PROTO_DSP_BT_BOTTOM */ + PROTO_DSP_BT_BOTTOM, /* Top right of display panel, next to the LCD, below PROTO_DSP_BT_TOP */ + PROTO_DSP_BT_LID, /* lid switch, 1 when open */ + PROTO_DSP_BT_ESTOP, /* lid switch, 1 when pressed */ +}; + +struct __attribute__((__packed__)) pkt_button_state { + struct ll_pkt ll_pkt; + uint8_t buttons; +}; + +struct __attribute__((__packed__)) pkt_time_sync { + struct ll_pkt ll_pkt; + uint64_t timestamp; +}; + +extern struct proto_state st_proto; + + +void proto_init_host(void); +void proto_loop_host(void); + + +#endif /* __PROTO_H__ */ diff --git a/include/serial.h b/include/serial.h index 492f5f5..1d05155 100644 --- a/include/serial.h +++ b/include/serial.h @@ -25,10 +25,11 @@ struct dma_tx_buf { struct uart_dma_state { struct dma_tx_buf tx_buf; - uint32_t tx_overruns, rx_overruns; - uint32_t rx_framing_errors, rx_protocol_errors; uint32_t retransmissions, packet_count; ErrorCode error; + uint64_t last_error; + uint64_t last_packet; + uint64_t last_transmission; struct cobs_decode_state cobs_state; @@ -49,24 +50,7 @@ struct __attribute__((__packed__)) ll_pkt { uint8_t data[0]; }; -enum ctrl_pkt_type { - CTRL_PKT_RESET = 1, - CTRL_PKT_ACK = 2, - CTRL_PKT_NACK = 3, - CTRL_PKT_PING = 4, - CTRL_PKT_PONG = 5, - _USER_PKT_START = 16, -}; - -enum user_pkt_type { - USER_PKT_ADC_DATA = _USER_PKT_START+0, - USER_PKT_SET_DISPLAY = _USER_PKT_START+1, -}; - -struct __attribute__((__packed__)) user_pkt_adc_data { - struct ll_pkt hdr; - uint8_t adc_data_packed[3*2*16]; -}; +#define SER_ADDR_BROADCAST 0xff extern volatile struct uart_dma_state uart_st; @@ -75,6 +59,7 @@ int uart_send_packet_nonblocking(struct ll_pkt *pkt, size_t pkt_len); int uart_ack_packet(uint8_t idx); void uart_dma_interrupt(uint32_t channel, uint32_t flags); void uart_interrupt(uint32_t isr); + extern void uart_handle_user_packet(struct ll_pkt *pkt, size_t len); #endif // __SERIAL_H__ diff --git a/include/usb_if.h b/include/usb_if.h index 3d8394e..9d5cadb 100644 --- a/include/usb_if.h +++ b/include/usb_if.h @@ -15,7 +15,9 @@ struct usb_state { uint8_t usb_pkbuf[USB_CDC_DATA_SIZE]; struct cobs_decode_state cobs_state; bool cobs_synchronized; + bool connected; ErrorCode error; + uint64_t last_error; uint8_t txbuf[USB_CDC_DATA_SIZE]; size_t txpos; }; diff --git a/src/adc.c b/src/adc.c index bf80f74..2492925 100644 --- a/src/adc.c +++ b/src/adc.c @@ -126,6 +126,7 @@ void adc_init() { if (i == timeout) { st_adc.error = ERR_TIMEOUT; + st_adc.last_error = sys_time_us; return; } @@ -145,12 +146,14 @@ void adc_init() { void adc_dma_interrupt(uint32_t channel, uint32_t flags) { if (flags & DMA_ISR_TEIF1) { st_adc.error = ERR_DMA; + st_adc.last_error = sys_time_us; } else if (flags & DMA_ISR_TCIF1 && channel == 3) { DMA1_Channel3->CCR &= ~DMA_CCR_EN; if ((st_adc.rxbuf[0] & 0x3) != 0x1) { st_adc.error = ERR_PROTOCOL; + st_adc.last_error = sys_time_us; /* Stop timer, stopping automatic ADC acquisition */ TIM2->SMCR = 0; @@ -161,12 +164,25 @@ void adc_dma_interrupt(uint32_t channel, uint32_t flags) { val |= 0xff000000; } st_adc.data[0] = val; + + if (val > ADC_FSR_POS || val < ADC_FSR_NEG) { + st_adc.overload[0] = true; + } else { + st_adc.overload[0] = false; + } + val = (st_adc.rxbuf[6] << 16) | (st_adc.rxbuf[7] << 8) | st_adc.rxbuf[8]; if (val&0x00800000) { val |= 0xff000000; } st_adc.data[1] = val; + if (val > ADC_FSR_POS || val < ADC_FSR_NEG) { + st_adc.overload[1] = true; + } else { + st_adc.overload[1] = false; + } + while (DMA1_Channel3->CCR & DMA_CCR_EN) { /* do nothing */ } diff --git a/src/led.c b/src/led.c index b5ce5e0..2c6e3ec 100644 --- a/src/led.c +++ b/src/led.c @@ -27,3 +27,8 @@ void led_init() { DMA1_Channel5->CCR |= DMA_CCR_EN; } +void set_led(int led, uint8_t r, uint8_t g, uint8_t b) { + st_led.led[led].r = r; + st_led.led[led].g = g; + st_led.led[led].b = b; +} diff --git a/src/main.c b/src/main.c index ef59610..baade19 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -25,10 +26,14 @@ static int bt_inputs(void); static void init_7seg(void); void step_7seg(void); void decimal_7seg(int module, int value, int dp); +static void update_leds(void); +static void loop_display(void); +static void loop_motor(void); +static void loop_adc(void); -uint32_t sys_time_s; -uint32_t sys_time_us; -#define SYSTICK_INTERVAL_US 1000 + +enum board_config board_config; +uint64_t sys_time_us; int bt_inputs() { bool bt0 = !!(GPIOB->IDR & (1<<2)); @@ -40,13 +45,6 @@ int bt_inputs() { return (bt5<<5) | (bt4<<4) | (bt3<<3) | (bt2<<2) | (bt1<<1) | (bt0<<0); } -enum { - BCFG_DISPLAY, - BCFG_MOTOR, - BCFG_MEAS, -} board_config; -int board_addr; - struct { uint8_t data[3][8]; uint8_t dp[3]; @@ -326,30 +324,38 @@ int main(void) { if (st_lcd.has_lcd) { uart_dma_init(USART3, 2, 2); - const char *lines[4] = {"LINE 1 LINE 1 LINE 1", - "LINE 2 LINE 2 LINE 2", - "LINE 3 LINE 3 LINE 3", - "LINE 4 LINE 4 LINE 4"}; + const char *lines[4] = {"Display initialized ", + " ", + "Waiting for ", + "controller... "}; lcd_write_dma(lines); init_7seg(); + set_led(LED_DISPLAY, 0, 255, 0); /* green */ + set_led(LED_BUTTONS, 0, 255, 0); /* green */ board_config = BCFG_DISPLAY; - board_addr = 1; + uart_st.addr = BADDR_DISPLAY; + } else { uart_dma_init(USART3, 7, 1); int bt = bt_inputs(); if (bt&0) { + set_led(LED_DISPLAY, 0, 0, 255); /* blue */ + set_led(LED_BUTTONS, 0, 0, 255); /* blue */ + tx_state = 0; board_config = BCFG_MOTOR; - board_addr = 2; + uart_st.addr = BADDR_MOTOR; + } else { + set_led(LED_DISPLAY, 255, 0, 0); /* red */ + set_led(LED_BUTTONS, 0, 255, 255); /* cyan */ board_config = BCFG_MEAS; - board_addr = bt>>1; + uart_st.addr = BADDR_MEAS_BASE + ((bt>>1) & 3); } } usb_init(); - sys_time_s = 0; sys_time_us = 0; SysTick->LOAD = SystemCoreClock / SYSTICK_INTERVAL_US; /* 1ms interrupt interval */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; @@ -369,33 +375,130 @@ int main(void) { st_led.led[i].b = i*3; } - int cnt=0; + int n = 0; while (23) { - if (st_lcd.has_lcd) { - step_7seg(); + n++; + if (n&64) { + update_leds(); } - delay_us(1); - - if (st_7seg.digit == 0 && st_7seg.module == 0 && st_7seg.bit == 0) { - hex_7seg(2, cnt++, 0x10); - for (size_t i=0; i<10; i++) { - st_led.led[i].r += 1; - st_led.led[i].g += 2; - st_led.led[i].b += 3; - } + if (board_config == BCFG_DISPLAY) { + loop_display(); + if (board_config == BCFG_MOTOR) { + loop_motor(); + if (board_config == BCFG_MEAS) { + loop_adc(); } } } +#define LED_ERROR_TIMEOUT_MS 300 +#define LED_PULSE_STRETCH_MS 150 + +void update_leds() { + static uint64_t last_error = 0; + static int blink_flag = (sys_time_us & (512*1024-1)) < 384*1024; + + /* "Error" status LED */ + if (st_adc.has_adc && st_adc.error) { + last_error = sys_time_us; + } + + if (last_error > 0 && (sys_time_us - last_error) < LED_ERROR_TIMEOUT_MS*1000) { + set_led(LED_ERROR, 255, 0, 0); + + } else { + set_led(LED_ERROR, 0, 0, 0); + } + + /* "Connected" status LED */ + if (uart_st.error && (sys_time_us - uart_st.last_error) < LED_ERROR_TIMEOUT_MS*1000) { + /* UART protocol error */ + set_led(LED_CONNECTED, 255, 0, 0); /* red */ + + if (st_usb.error && (sys_time_us - st_usb.last_error) < LED_ERROR_TIMEOUT_MS*1000) { + /* USB error */ + set_led(LED_CONNECTED, 255, 0, 0); /* red */ + + } else if (st_usb.connected) { + if (st_usb.cobs_synchronized) { + set_led(LED_CONNECTED, 0, 255, 255); /* cyan */ + } else { + set_led(LED_CONNECTED, 0, 0, 255); /* blue */ + } + + } else if (uart_st.last_packet > 0 && (sys_time_us - uart_st.last_packet) < 1000000) { + set_led(LED_CONNECTED, 0, 255, 0); /* green */ + + } else { + /* no error, but no packets seen either. */ + set_led(LED_CONNECTED, 0, 0, 0); /* off */ + } + + /* UART rx/tx activity LED next to power/rs-485 connector */ + bool tx = uart_st.last_transmission > 0 && (sys_time_us - uart_st.last_transmission) < LED_PULSE_STRETCH_MS*1000; + bool rx = uart_st.last_packet > 0 && (sys_time_us - uart_st.last_packet) < LED_PULSE_STRETCH_MS*1000; + set_led(LED_POWER, rx*255, tx*255, 0); + + /* "Acquiring" status LED and ADC channel connector LEDs */ + if (st_adc.error && (sys_time_us - st_adc.last_error) < LED_ERROR_TIMEOUT_MS*1000) { + /* ADC hardware error */ + set_led(LED_ACQUIRING, 255, 0, 0); /* red */ + set_led(LED_OVERLOAD, 0, 0, 0); /* off */ + set_led(CHANNEL_A, 0, 0, 0); /* off */ + set_led(CHANNEL_B, 0, 0, 0); /* off */ + + } else { + if (st_adc.has_adc) { + set_led(LED_ACQUIRING, 255, 0, 0); /* green */ + if (st_adc.overload[0] || st_adc.overload[1]) { + set_led(LED_OVERLOAD, 255, 0, 0); /* red */ + } else { + set_led(LED_OVERLOAD, 0, 0, 0); /* off */ + } + + for (int i=0; i<2; i++) { + int led_ch = i == 0 ? LED_CHANNEL_A : LED_CHANNEL_B; + if (st_adc.overload[i] && !blink_flag) { + set_led(led_ch, 0, 0, 0); /* off */ + + } else { + if (st_adc.data[i] >= 0) { + int val = st_adc.data[i] >> 15; + set_led(led_ch, 255, 255-val, 255-val); /* white (0) -> red (fsr-1) */ + + } else { + int val = (-st_adc.data[i]) >> 15; + if (val == 256) { + val = 255; + } + set_led(led_ch, 255-val, 255-val, 255); /* white (0) -> blue (-fsr) */ + } + } + } + } else { + set_led(LED_ACQUIRING, 0, 0, 0); /* off */ + set_led(LED_OVERLOAD, 0, 0, 0); /* off */ + set_led(CHANNEL_A, 0, 0, 0); /* off */ + set_led(CHANNEL_B, 0, 0, 0); /* off */ + } + } +} + +void loop_display() { + step_7seg(); + delay_us(1); +} + +void loop_motor() { +} + +void loop_adc() { +} + + void SysTick_Handler() { sys_time_us += SYSTICK_INTERVAL_US; - if (sys_time_us >= 1000000) { - sys_time_s++; - sys_time_us -= 1000000; - } - decimal_7seg(0, sys_time_us, 0); - decimal_7seg(1, sys_time_s, 0); } void handle_usb_packet(void *packet, size_t len) { @@ -498,15 +601,7 @@ void *memcpy(void *restrict dest, const void *restrict src, size_t n) void *memmove(void *dest, const void *src, size_t n) { -<<<<<<< HEAD return memcpy(dest, src, n); -======= - unsigned char *d = dest; - const unsigned char *s = src; - - for (; n; n--) *d++ = *s++; - return dest; ->>>>>>> e6841f8 (serial WIP) } void *memset(void *dest, int c, size_t n) diff --git a/src/proto.c b/src/proto.c new file mode 100644 index 0000000..7c1de38 --- /dev/null +++ b/src/proto.c @@ -0,0 +1,158 @@ + +#include + +static void tx_time_sync(void); +static void tx_fetch_adc(int index); +static void proto_handle(bool timeout); +static void proto_update_lcd_strings(void); +static void tx_update_display(void); + + +struct proto_state st_proto; + + +void proto_init_host() { + memset(&st_proto, 0, sizeof(st_proto)); +} + +void proto_loop_host() { + if (sys_time_us - st_proto.last_start > PROTO_UPDATE_INTERVAL_MS*1000 - st_proto.delta ) { + st_proto.fsm = ST_START; + } else if (st_proto.fsm > ST_START && st_proto.fsm < ST_WAITING) { + if (sys_time_us - uart_st.last_transmission > PROTO_RESPONSE_TIMEOUT_MS*1000) { + proto_handle(true); + } + } +} + +/* uart handler from serial.h */ +void uart_handle_user_packet(struct ll_pkt *pkt, size_t len) { + /* FIXME process response */ + if (pkt->type == PK_BUTTON_STATE) { + st_proto.rx_buttons = ((struct pkt_button_state *)pkt)->buttons; + st_proto.rx_lid_open = st_proto.rx_buttons & PROTO_DSP_BT_LID; + st_proto.rx_estop = st_proto.rx_buttons & PROTO_DSP_BT_ESTOP; + } + + proto_handle(false); +} + +void proto_handle(bool timeout) { + switch (st_proto.fsm) { + case ST_START: + st_proto.delta += (sys_time_us - st_proto.last_start) - UPDATE_INTERVAL_MS*1000; + st_proto.last_start = sys_time_us; + tx_time_sync(); + st_proto.fsm = ST_TIME_SYNC; + /* immediately enqueue next command, since time syncs are a broadcast and do not require a response. */ + proto_handle(false); + break; + + case ST_TIME_SYNC: + tx_fetch_adc(0); + st_proto.fsm = ST_FETCH_0; + break; + + case ST_FETCH_0: + tx_fetch_adc(1); + st_proto.fsm = ST_FETCH_1; + break; + + case ST_FETCH_1: + tx_update_display(); + st_proto.fsm = ST_UPDATE_DISPLAY; + break; + + case ST_UPDATE_DISPLAY: + st_proto.fsm = ST_WAITING; + break; + + default: + st_proto.fsm = ST_WAITING; + break; + } +} + +void tx_time_sync() { + struct pkt_time_sync pk = { + .ll_pkt = { + .src = uart_st.addr, + .dst = SER_ADDR_BROADCAST, + .pid = 0, + .type = PK_TIME_SYNC, + }, + .time = sys_time_us; + }; + + ErrorCode rc = uart_send_packet_nonblocking(&pk, sizeof(pk)); + if (rc) { + st_proto.error = rc; + st_proto.last_error = sys_time_us; + proto_handle(true); + } +} + +void tx_fetch_adc(int index) { + struct ll_pkt pk = { + .src = uart_st.addr, + .dst = BADDR_MEAS_BASE + index, + .pid = 0, + .type = PK_FETCH_ADC, + }; + + ErrorCode rc = uart_send_packet_nonblocking(&pk, sizeof(pk)); + if (rc) { + st_proto.error = rc; + st_proto.last_error = sys_time_us; + proto_handle(true); + } +} + +void proto_update_lcd_strings(void) { + st_proto.status_msg = "System OK"; + st_proto.error_msg = NULL; + + if (st_proto.rx_estop) { + st_proto.error_msg = "E-Stop pressed!"; + } else if (st_proto.rx_lid_open) { + st_proto.error_msg = "Lid open!"; + } +} + +void tx_update_display() { + struct pkt_update_display pk = { + .ll_pkt = { + .src = uart_st.addr, + .dst = BADDR_DISPLAY, + .pid = 0, + .type = PK_DISPLAY_UPDATE, + }, + .led = { + sys_time_us/10000, + 0, + 0 + }, + .led_fmt = { + PROTO_LED_FMT_DEC | PROTO_LED_FMT_DP_2, + PROTO_LED_FMT_OFF, + PROTO_LED_FMT_OFF, + }, + }; + + proto_update_lcd_strings(); + + memset(pk.lcd, ' ', sizeof(pk.lcd)); + if (st_proto.error_msg) { + memcpy(pk.lcd[0], st_proto.error_msg, strlen(st_proto.error_msg)); + } else if (st_proto.status_msg) { + memcpy(pk.lcd[0], st_proto.status_msg, strlen(st_proto.status_msg)); + } + + ErrorCode rc = uart_send_packet_nonblocking(&pk, sizeof(pk)); + if (rc) { + st_proto.error = rc; + st_proto.last_error = sys_time_us; + proto_handle(true); + } +} + diff --git a/src/serial.c b/src/serial.c index b3766ba..f3ade54 100644 --- a/src/serial.c +++ b/src/serial.c @@ -58,7 +58,8 @@ void uart_dma_init(USART_TypeDef *usart, int tx_dma_ch, int addr) { void uart_interrupt(uint32_t isr) { if (isr & USART_ISR_ORE) { - uart_st.rx_overruns++; + uart_st.error = ERR_RX_OVERRUN; + uart_st.last_error = sys_time_us; return; } @@ -70,60 +71,29 @@ void uart_interrupt(uint32_t isr) { return; if (rc < 0) { - uart_st.rx_framing_errors++; + uart_st.error = ERR_RX_FRAMING; + uart_st.last_error = sys_time_us; return; } /* A complete frame received */ if (rc < (int)sizeof(struct ll_pkt)) { - uart_st.rx_protocol_errors++; + uart_st.error = ERR_RX_PROTOCOL; + uart_st.last_error = sys_time_us; return; } volatile struct ll_pkt *pkt = (volatile struct ll_pkt *)&uart_st.rx_buf; - if (pkt->dst != uart_st.addr && pkt->dst != 0xff) { + if (pkt->dst != uart_st.addr && pkt->dst != SER_ADDR_BROADCAST) { /* we are not addressed */ return; } - switch (pkt->type) { - case CTRL_PKT_RESET: - uart_dma_reset(); - break; - - case CTRL_PKT_ACK: - if (!(DMA1_Channel[uart_st.tx_dma_ch].CCR & DMA_CCR_EN)) - uart_schedule_dma(false); - break; - - case CTRL_PKT_NACK: - if (!(DMA1_Channel[uart_st.tx_dma_ch].CCR & DMA_CCR_EN)) - uart_schedule_dma(true); - break; - - case CTRL_PKT_PING: { - struct ll_pkt reply = { - .src = uart_st.addr, - .dst = pkt->src, - .pid = pkt->pid, - .type = CTRL_PKT_PONG, - }; - - rc = uart_send_packet_nonblocking(&reply, sizeof(reply)); - if (rc) { - uart_st.error = rc; - } - break; - } - - default: - if (pkt->type < _USER_PKT_START) { - uart_st.rx_protocol_errors++; - } else { - uart_handle_user_packet((struct ll_pkt *)pkt, rc); - } - break; + uart_st.last_packet = sys_time_us; + uart_handle_user_packet((struct ll_pkt *)pkt, rc); + if (!(DMA1_Channel[uart_st.tx_dma_ch].CCR & DMA_CCR_EN)) { + uart_schedule_dma(false); } } } @@ -203,6 +173,7 @@ void uart_dma_interrupt(uint32_t channel, uint32_t flags) { if (flags & DMA_ISR_TEIF1) { uart_st.error = ERR_DMA; + uart_st.last_error = sys_time_us; } else if (flags & DMA_ISR_TCIF1 && channel == uart_st.tx_dma_ch) { /* Wait for channel to turn off */ @@ -219,11 +190,11 @@ void uart_dma_interrupt(uint32_t channel, uint32_t flags) { /* len is the packet length including headers */ int uart_send_packet_nonblocking(struct ll_pkt *pkt, size_t pkt_len) { if (uart_st.tx_buf.packet_end[uart_st.tx_buf.wr_idx] != -1) { - /* Find a free slot for this packet */ - uart_st.tx_overruns++; - return ERR_BUSY; + return ERR_TX_OVERRUN; } + uart_st.last_transmission = sys_time_us; + /* make the value this wonky-ass CRC implementation produces match zlib etc. */ CRC->CR = CRC_CR_REV_OUT | (1< 0 && st_usb.cobs_synchronized) { /* Packet complete */ @@ -234,6 +237,8 @@ static usbd_respond usb_setconf (usbd_device *dev, uint8_t cfg) { usbd_ep_deconfig(dev, USB_CDC_RX_EP); usbd_reg_endpoint(dev, USB_CDC_RX_EP, 0); usbd_reg_endpoint(dev, USB_CDC_TX_EP, 0); + st_usb.error = ERR_SUCCESS; + st_usb.connected = false; return usbd_ack; case 1: @@ -254,15 +259,19 @@ static usbd_respond usb_setconf (usbd_device *dev, uint8_t cfg) { st_usb.line.bDataBits = 8; st_usb.error = ERR_SUCCESS; + st_usb.connected = true; return usbd_ack; default: + st_usb.error = ERR_PROTOCOL; + st_usb.last_error = sys_time_us; return usbd_fail; } } void usb_init() { + memset(st_usb, 0, sizeof(st_usb)); usbd_init(&st_usb.usb_dev, &usbd_hw, USB_EP0_SIZE, st_usb.usb_buf, sizeof(st_usb.usb_buf)); usbd_reg_config(&st_usb.usb_dev, usb_setconf); usbd_reg_control(&st_usb.usb_dev, usb_control);