WIP
This commit is contained in:
parent
ebb9c72384
commit
c7b7e6b1d5
13 changed files with 510 additions and 110 deletions
|
|
@ -9,6 +9,7 @@ struct adc_state {
|
|||
uint32_t dma_ccr3;
|
||||
int32_t data[2];
|
||||
bool has_adc;
|
||||
bool overload[2];
|
||||
ErrorCode error;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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
92
include/proto.h
Normal 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__ */
|
||||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
16
src/adc.c
16
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 */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
183
src/main.c
183
src/main.c
|
|
@ -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
158
src/proto.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
59
src/serial.c
59
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<<CRC_CR_REV_IN_Pos) | CRC_CR_RESET;
|
||||
for (size_t i=offsetof(struct ll_pkt, pid); i<pkt_len; i++)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue