This commit is contained in:
jaseg 2023-05-23 20:02:38 +02:00
parent ebb9c72384
commit c7b7e6b1d5
13 changed files with 510 additions and 110 deletions

View file

@ -9,6 +9,7 @@ struct adc_state {
uint32_t dma_ccr3;
int32_t data[2];
bool has_adc;
bool overload[2];
ErrorCode error;
};

View file

@ -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__ */

View file

@ -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__ */

View file

@ -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));

92
include/proto.h Normal file
View file

@ -0,0 +1,92 @@
#ifndef __PROTO_H__
#define __PROTO_H__
#include <global.h>
#include <serial.h>
#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__ */

View file

@ -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__

View file

@ -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;
};

View file

@ -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 */
}

View file

@ -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;
}

View file

@ -3,6 +3,7 @@
#include <adc.h>
#include <serial.h>
#include <proto.h>
#include <lcd.h>
#include <led.h>
#include <usb_if.h>
@ -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)

158
src/proto.c Normal file
View file

@ -0,0 +1,158 @@
#include <proto.h>
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);
}
}

View file

@ -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<<CRC_CR_REV_IN_Pos) | CRC_CR_RESET;
for (size_t i=offsetof(struct ll_pkt, pid); i<pkt_len; i++)

View file

@ -180,6 +180,8 @@ static usbd_respond usb_control(usbd_device *dev, usbd_ctlreq *req, usbd_rqc_cal
return usbd_ack;
default:
st_usb.error = ERR_PROTOCOL;
st_usb.last_error = sys_time_us;
return usbd_fail;
}
}
@ -194,6 +196,7 @@ static void usb_cobs_rx(usbd_device *dev, uint8_t event, uint8_t ep) {
int rc = cobs_decode_incremental(&st_usb.cobs_state, (char*)st_usb.usb_pkbuf, sizeof(st_usb.usb_pkbuf), buf[i]);
if (rc < 0) { /* Framing error */
st_usb.error = ERR_PROTOCOL;
st_usb.last_error = sys_time_us;
st_usb.cobs_synchronized = false;
} else if (rc > 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);