mirror of https://github.com/commaai/panda.git
misra8.4: board/drivers (#2025)
* drivers * cleanup bootkick * bxcan cleanup * fan cleanup * harness cleanup * interrupts cleanup * registers cleanup * simple_watchdog cleanup * spi cleanup * h7 drivers * no include for now * conflict * reduce scope * cleanup
This commit is contained in:
parent
32eecd7211
commit
022d1c69a1
|
@ -1,13 +1,14 @@
|
|||
bool bootkick_ign_prev = false;
|
||||
BootState boot_state = BOOT_BOOTKICK;
|
||||
uint8_t bootkick_harness_status_prev = HARNESS_STATUS_NC;
|
||||
#include "bootkick_declarations.h"
|
||||
|
||||
uint8_t boot_reset_countdown = 0;
|
||||
uint8_t waiting_to_boot_countdown = 0;
|
||||
bool bootkick_reset_triggered = false;
|
||||
uint16_t bootkick_last_serial_ptr = 0;
|
||||
|
||||
void bootkick_tick(bool ignition, bool recent_heartbeat) {
|
||||
static uint16_t bootkick_last_serial_ptr = 0;
|
||||
static uint8_t waiting_to_boot_countdown = 0;
|
||||
static uint8_t boot_reset_countdown = 0;
|
||||
static uint8_t bootkick_harness_status_prev = HARNESS_STATUS_NC;
|
||||
static bool bootkick_ign_prev = false;
|
||||
static BootState boot_state = BOOT_BOOTKICK;
|
||||
BootState boot_state_prev = boot_state;
|
||||
const bool harness_inserted = (harness.status != bootkick_harness_status_prev) && (harness.status != HARNESS_STATUS_NC);
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
extern bool bootkick_reset_triggered;
|
||||
|
||||
void bootkick_tick(bool ignition, bool recent_heartbeat);
|
|
@ -1,9 +1,11 @@
|
|||
#include "bxcan_declarations.h"
|
||||
|
||||
// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE
|
||||
// CAN2_TX, CAN2_RX0, CAN2_SCE
|
||||
// CAN3_TX, CAN3_RX0, CAN3_SCE
|
||||
|
||||
CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3};
|
||||
uint8_t can_irq_number[3][3] = {
|
||||
CAN_TypeDef *cans[CAN_ARRAY_SIZE] = {CAN1, CAN2, CAN3};
|
||||
uint8_t can_irq_number[CAN_IRQS_ARRAY_SIZE][CAN_IRQS_ARRAY_SIZE] = {
|
||||
{ CAN1_TX_IRQn, CAN1_RX0_IRQn, CAN1_SCE_IRQn },
|
||||
{ CAN2_TX_IRQn, CAN2_RX0_IRQn, CAN2_SCE_IRQn },
|
||||
{ CAN3_TX_IRQn, CAN3_RX0_IRQn, CAN3_SCE_IRQn },
|
||||
|
@ -63,7 +65,7 @@ void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
|
|||
|
||||
// ***************************** CAN *****************************
|
||||
// CANx_SCE IRQ Handler
|
||||
void can_sce(uint8_t can_number) {
|
||||
static void can_sce(uint8_t can_number) {
|
||||
update_can_health_pkt(can_number, 1U);
|
||||
}
|
||||
|
||||
|
@ -181,17 +183,17 @@ void can_rx(uint8_t can_number) {
|
|||
}
|
||||
}
|
||||
|
||||
void CAN1_TX_IRQ_Handler(void) { process_can(0); }
|
||||
void CAN1_RX0_IRQ_Handler(void) { can_rx(0); }
|
||||
void CAN1_SCE_IRQ_Handler(void) { can_sce(0); }
|
||||
static void CAN1_TX_IRQ_Handler(void) { process_can(0); }
|
||||
static void CAN1_RX0_IRQ_Handler(void) { can_rx(0); }
|
||||
static void CAN1_SCE_IRQ_Handler(void) { can_sce(0); }
|
||||
|
||||
void CAN2_TX_IRQ_Handler(void) { process_can(1); }
|
||||
void CAN2_RX0_IRQ_Handler(void) { can_rx(1); }
|
||||
void CAN2_SCE_IRQ_Handler(void) { can_sce(1); }
|
||||
static void CAN2_TX_IRQ_Handler(void) { process_can(1); }
|
||||
static void CAN2_RX0_IRQ_Handler(void) { can_rx(1); }
|
||||
static void CAN2_SCE_IRQ_Handler(void) { can_sce(1); }
|
||||
|
||||
void CAN3_TX_IRQ_Handler(void) { process_can(2); }
|
||||
void CAN3_RX0_IRQ_Handler(void) { can_rx(2); }
|
||||
void CAN3_SCE_IRQ_Handler(void) { can_sce(2); }
|
||||
static void CAN3_TX_IRQ_Handler(void) { process_can(2); }
|
||||
static void CAN3_RX0_IRQ_Handler(void) { can_rx(2); }
|
||||
static void CAN3_SCE_IRQ_Handler(void) { can_sce(2); }
|
||||
|
||||
bool can_init(uint8_t can_number) {
|
||||
bool ret = false;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE
|
||||
// CAN2_TX, CAN2_RX0, CAN2_SCE
|
||||
// CAN3_TX, CAN3_RX0, CAN3_SCE
|
||||
|
||||
#define CAN_ARRAY_SIZE 3
|
||||
#define CAN_IRQS_ARRAY_SIZE 3
|
||||
extern CAN_TypeDef *cans[CAN_ARRAY_SIZE];
|
||||
extern uint8_t can_irq_number[CAN_IRQS_ARRAY_SIZE][CAN_IRQS_ARRAY_SIZE];
|
||||
|
||||
bool can_set_speed(uint8_t can_number);
|
||||
void can_clear_send(CAN_TypeDef *CANx, uint8_t can_number);
|
||||
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg);
|
||||
|
||||
// ***************************** CAN *****************************
|
||||
// CANx_TX IRQ Handler
|
||||
void process_can(uint8_t can_number);
|
||||
// CANx_RX0 IRQ Handler
|
||||
// blink blue when we are receiving CAN messages
|
||||
void can_rx(uint8_t can_number);
|
||||
bool can_init(uint8_t can_number);
|
|
@ -1,54 +1,25 @@
|
|||
typedef struct {
|
||||
volatile uint32_t w_ptr;
|
||||
volatile uint32_t r_ptr;
|
||||
uint32_t fifo_size;
|
||||
CANPacket_t *elems;
|
||||
} can_ring;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bus_lookup;
|
||||
uint8_t can_num_lookup;
|
||||
int8_t forwarding_bus;
|
||||
uint32_t can_speed;
|
||||
uint32_t can_data_speed;
|
||||
bool canfd_enabled;
|
||||
bool brs_enabled;
|
||||
bool canfd_non_iso;
|
||||
} bus_config_t;
|
||||
#include "can_common_declarations.h"
|
||||
|
||||
uint32_t safety_tx_blocked = 0;
|
||||
uint32_t safety_rx_invalid = 0;
|
||||
uint32_t tx_buffer_overflow = 0;
|
||||
uint32_t rx_buffer_overflow = 0;
|
||||
|
||||
can_health_t can_health[] = {{0}, {0}, {0}};
|
||||
|
||||
extern int can_live;
|
||||
extern int pending_can_live;
|
||||
|
||||
// must reinit after changing these
|
||||
extern int can_silent;
|
||||
extern bool can_loopback;
|
||||
can_health_t can_health[CAN_HEALTH_ARRAY_SIZE] = {{0}, {0}, {0}};
|
||||
|
||||
// Ignition detected from CAN meessages
|
||||
bool ignition_can = false;
|
||||
uint32_t ignition_can_cnt = 0U;
|
||||
|
||||
#define ALL_CAN_SILENT 0xFF
|
||||
#define ALL_CAN_LIVE 0
|
||||
|
||||
int can_live = 0;
|
||||
int pending_can_live = 0;
|
||||
int can_silent = ALL_CAN_SILENT;
|
||||
bool can_loopback = false;
|
||||
|
||||
// ******************* functions prototypes *********************
|
||||
bool can_init(uint8_t can_number);
|
||||
void process_can(uint8_t can_number);
|
||||
|
||||
// ********************* instantiate queues *********************
|
||||
#define can_buffer(x, size) \
|
||||
CANPacket_t elems_##x[size]; \
|
||||
static CANPacket_t elems_##x[size]; \
|
||||
extern can_ring can_##x; \
|
||||
can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = (size), .elems = (CANPacket_t *)&(elems_##x) };
|
||||
|
||||
#define CAN_RX_BUFFER_SIZE 4096U
|
||||
|
@ -68,11 +39,7 @@ can_buffer(tx3_q, CAN_TX_BUFFER_SIZE)
|
|||
|
||||
// FIXME:
|
||||
// cppcheck-suppress misra-c2012-9.3
|
||||
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q};
|
||||
|
||||
// helpers
|
||||
#define WORD_TO_BYTE_ARRAY(dst8, src32) 0[dst8] = ((src32) & 0xFFU); 1[dst8] = (((src32) >> 8U) & 0xFFU); 2[dst8] = (((src32) >> 16U) & 0xFFU); 3[dst8] = (((src32) >> 24U) & 0xFFU)
|
||||
#define BYTE_ARRAY_TO_WORD(dst32, src8) ((dst32) = 0[src8] | (1[src8] << 8U) | (2[src8] << 16U) | (3[src8] << 24U))
|
||||
can_ring *can_queues[CAN_QUEUES_ARRAY_SIZE] = {&can_tx1_q, &can_tx2_q, &can_tx3_q};
|
||||
|
||||
// ********************* interrupt safe queue *********************
|
||||
bool can_pop(can_ring *q, CANPacket_t *elem) {
|
||||
|
@ -163,17 +130,13 @@ void can_clear(can_ring *q) {
|
|||
|
||||
// Helpers
|
||||
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
|
||||
bus_config_t bus_config[] = {
|
||||
bus_config_t bus_config[BUS_CONFIG_ARRAY_SIZE] = {
|
||||
{ .bus_lookup = 0U, .can_num_lookup = 0U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
|
||||
{ .bus_lookup = 1U, .can_num_lookup = 1U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
|
||||
{ .bus_lookup = 2U, .can_num_lookup = 2U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
|
||||
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .forwarding_bus = -1, .can_speed = 333U, .can_data_speed = 333U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
|
||||
};
|
||||
|
||||
#define CANIF_FROM_CAN_NUM(num) (cans[num])
|
||||
#define BUS_NUM_FROM_CAN_NUM(num) (bus_config[num].bus_lookup)
|
||||
#define CAN_NUM_FROM_BUS_NUM(num) (bus_config[num].can_num_lookup)
|
||||
|
||||
void can_init_all(void) {
|
||||
for (uint8_t i=0U; i < PANDA_CAN_CNT; i++) {
|
||||
if (!current_board->has_canfd) {
|
||||
|
@ -191,9 +154,11 @@ void can_set_orientation(bool flipped) {
|
|||
bus_config[2].can_num_lookup = flipped ? 0U : 2U;
|
||||
}
|
||||
|
||||
#ifdef PANDA_JUNGLE
|
||||
void can_set_forwarding(uint8_t from, uint8_t to) {
|
||||
bus_config[from].forwarding_bus = to;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ignition_can_hook(CANPacket_t *to_push) {
|
||||
int bus = GET_BUS(to_push);
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t w_ptr;
|
||||
volatile uint32_t r_ptr;
|
||||
uint32_t fifo_size;
|
||||
CANPacket_t *elems;
|
||||
} can_ring;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bus_lookup;
|
||||
uint8_t can_num_lookup;
|
||||
int8_t forwarding_bus;
|
||||
uint32_t can_speed;
|
||||
uint32_t can_data_speed;
|
||||
bool canfd_enabled;
|
||||
bool brs_enabled;
|
||||
bool canfd_non_iso;
|
||||
} bus_config_t;
|
||||
|
||||
extern uint32_t safety_tx_blocked;
|
||||
extern uint32_t safety_rx_invalid;
|
||||
extern uint32_t tx_buffer_overflow;
|
||||
extern uint32_t rx_buffer_overflow;
|
||||
|
||||
#define CAN_HEALTH_ARRAY_SIZE 3
|
||||
extern can_health_t can_health[CAN_HEALTH_ARRAY_SIZE];
|
||||
|
||||
// Ignition detected from CAN meessages
|
||||
extern bool ignition_can;
|
||||
extern uint32_t ignition_can_cnt;
|
||||
|
||||
#define ALL_CAN_SILENT 0xFF
|
||||
#define ALL_CAN_LIVE 0
|
||||
|
||||
extern int can_live;
|
||||
extern int pending_can_live;
|
||||
extern int can_silent;
|
||||
extern bool can_loopback;
|
||||
|
||||
// ******************* functions prototypes *********************
|
||||
bool can_init(uint8_t can_number);
|
||||
void process_can(uint8_t can_number);
|
||||
|
||||
// ********************* instantiate queues *********************
|
||||
#define CAN_QUEUES_ARRAY_SIZE 3
|
||||
extern can_ring *can_queues[CAN_QUEUES_ARRAY_SIZE];
|
||||
|
||||
// helpers
|
||||
#define WORD_TO_BYTE_ARRAY(dst8, src32) 0[dst8] = ((src32) & 0xFFU); 1[dst8] = (((src32) >> 8U) & 0xFFU); 2[dst8] = (((src32) >> 16U) & 0xFFU); 3[dst8] = (((src32) >> 24U) & 0xFFU)
|
||||
#define BYTE_ARRAY_TO_WORD(dst32, src8) ((dst32) = 0[src8] | (1[src8] << 8U) | (2[src8] << 16U) | (3[src8] << 24U))
|
||||
|
||||
// ********************* interrupt safe queue *********************
|
||||
bool can_pop(can_ring *q, CANPacket_t *elem);
|
||||
bool can_push(can_ring *q, const CANPacket_t *elem);
|
||||
uint32_t can_slots_empty(const can_ring *q);
|
||||
|
||||
// assign CAN numbering
|
||||
// bus num: CAN Bus numbers in panda, sent to/from USB
|
||||
// Min: 0; Max: 127; Bit 7 marks message as receipt (bus 129 is receipt for but 1)
|
||||
// cans: Look up MCU can interface from bus number
|
||||
// can number: numeric lookup for MCU CAN interfaces (0 = CAN1, 1 = CAN2, etc);
|
||||
// bus_lookup: Translates from 'can number' to 'bus number'.
|
||||
// can_num_lookup: Translates from 'bus number' to 'can number'.
|
||||
// forwarding bus: If >= 0, forward all messages from this bus to the specified bus.
|
||||
|
||||
// Helpers
|
||||
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
|
||||
#define BUS_CONFIG_ARRAY_SIZE 4
|
||||
extern bus_config_t bus_config[BUS_CONFIG_ARRAY_SIZE];
|
||||
|
||||
#define CANIF_FROM_CAN_NUM(num) (cans[num])
|
||||
#define BUS_NUM_FROM_CAN_NUM(num) (bus_config[num].bus_lookup)
|
||||
#define CAN_NUM_FROM_BUS_NUM(num) (bus_config[num].can_num_lookup)
|
||||
|
||||
void can_init_all(void);
|
||||
void can_set_orientation(bool flipped);
|
||||
#ifdef PANDA_JUNGLE
|
||||
void can_set_forwarding(uint8_t from, uint8_t to);
|
||||
#endif
|
||||
void ignition_can_hook(CANPacket_t *to_push);
|
||||
bool can_tx_check_min_slots_free(uint32_t min);
|
||||
uint8_t calculate_checksum(const uint8_t *dat, uint32_t len);
|
||||
void can_set_checksum(CANPacket_t *packet);
|
||||
bool can_check_checksum(CANPacket_t *packet);
|
||||
void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook);
|
||||
bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len);
|
|
@ -1,5 +1,4 @@
|
|||
#define CLOCK_SOURCE_PERIOD_MS 50U
|
||||
#define CLOCK_SOURCE_PULSE_LEN_MS 2U
|
||||
#include "clock_source_declarations.h"
|
||||
|
||||
void clock_source_set_period(uint8_t period) {
|
||||
register_set(&(TIM1->ARR), ((period*10U) - 1U), 0xFFFFU);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#define CLOCK_SOURCE_PERIOD_MS 50U
|
||||
#define CLOCK_SOURCE_PULSE_LEN_MS 2U
|
||||
|
||||
void clock_source_set_period(uint8_t period);
|
||||
void clock_source_init(void);
|
|
@ -2,11 +2,6 @@
|
|||
|
||||
#define CODEC_I2C_ADDR 0x10
|
||||
|
||||
// 1Vpp sine wave with 1V offset
|
||||
const uint8_t fake_siren_lut[360] = { 134U, 135U, 137U, 138U, 139U, 140U, 141U, 143U, 144U, 145U, 146U, 148U, 149U, 150U, 151U, 152U, 154U, 155U, 156U, 157U, 158U, 159U, 160U, 162U, 163U, 164U, 165U, 166U, 167U, 168U, 169U, 170U, 171U, 172U, 174U, 175U, 176U, 177U, 177U, 178U, 179U, 180U, 181U, 182U, 183U, 184U, 185U, 186U, 186U, 187U, 188U, 189U, 190U, 190U, 191U, 192U, 193U, 193U, 194U, 195U, 195U, 196U, 196U, 197U, 197U, 198U, 199U, 199U, 199U, 200U, 200U, 201U, 201U, 202U, 202U, 202U, 203U, 203U, 203U, 203U, 204U, 204U, 204U, 204U, 204U, 204U, 204U, 205U, 205U, 205U, 205U, 205U, 205U, 205U, 204U, 204U, 204U, 204U, 204U, 204U, 204U, 203U, 203U, 203U, 203U, 202U, 202U, 202U, 201U, 201U, 200U, 200U, 199U, 199U, 199U, 198U, 197U, 197U, 196U, 196U, 195U, 195U, 194U, 193U, 193U, 192U, 191U, 190U, 190U, 189U, 188U, 187U, 186U, 186U, 185U, 184U, 183U, 182U, 181U, 180U, 179U, 178U, 177U, 177U, 176U, 175U, 174U, 172U, 171U, 170U, 169U, 168U, 167U, 166U, 165U, 164U, 163U, 162U, 160U, 159U, 158U, 157U, 156U, 155U, 154U, 152U, 151U, 150U, 149U, 148U, 146U, 145U, 144U, 143U, 141U, 140U, 139U, 138U, 137U, 135U, 134U, 133U, 132U, 130U, 129U, 128U, 127U, 125U, 124U, 123U, 122U, 121U, 119U, 118U, 117U, 116U, 115U, 113U, 112U, 111U, 110U, 109U, 108U, 106U, 105U, 104U, 103U, 102U, 101U, 100U, 99U, 98U, 97U, 96U, 95U, 94U, 93U, 92U, 91U, 90U, 89U, 88U, 87U, 86U, 85U, 84U, 83U, 82U, 82U, 81U, 80U, 79U, 78U, 78U, 77U, 76U, 76U, 75U, 74U, 74U, 73U, 72U, 72U, 71U, 71U, 70U, 70U, 69U, 69U, 68U, 68U, 67U, 67U, 67U, 66U, 66U, 66U, 65U, 65U, 65U, 65U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 63U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 65U, 65U, 65U, 65U, 66U, 66U, 66U, 67U, 67U, 67U, 68U, 68U, 69U, 69U, 70U, 70U, 71U, 71U, 72U, 72U, 73U, 74U, 74U, 75U, 76U, 76U, 77U, 78U, 78U, 79U, 80U, 81U, 82U, 82U, 83U, 84U, 85U, 86U, 87U, 88U, 89U, 90U, 91U, 92U, 93U, 94U, 95U, 96U, 97U, 98U, 99U, 100U, 101U, 102U, 103U, 104U, 105U, 106U, 108U, 109U, 110U, 111U, 112U, 113U, 115U, 116U, 117U, 118U, 119U, 121U, 122U, 123U, 124U, 125U, 127U, 128U, 129U, 130U, 132U, 133U };
|
||||
|
||||
bool fake_siren_enabled = false;
|
||||
|
||||
void fake_siren_codec_enable(bool enabled) {
|
||||
if (enabled) {
|
||||
bool success = true;
|
||||
|
@ -33,6 +28,8 @@ void fake_siren_codec_enable(bool enabled) {
|
|||
|
||||
|
||||
void fake_siren_set(bool enabled) {
|
||||
static bool fake_siren_enabled = false;
|
||||
|
||||
if (enabled != fake_siren_enabled) {
|
||||
fake_siren_codec_enable(enabled);
|
||||
}
|
||||
|
@ -46,6 +43,9 @@ void fake_siren_set(bool enabled) {
|
|||
}
|
||||
|
||||
void fake_siren_init(void) {
|
||||
// 1Vpp sine wave with 1V offset
|
||||
static const uint8_t fake_siren_lut[360] = { 134U, 135U, 137U, 138U, 139U, 140U, 141U, 143U, 144U, 145U, 146U, 148U, 149U, 150U, 151U, 152U, 154U, 155U, 156U, 157U, 158U, 159U, 160U, 162U, 163U, 164U, 165U, 166U, 167U, 168U, 169U, 170U, 171U, 172U, 174U, 175U, 176U, 177U, 177U, 178U, 179U, 180U, 181U, 182U, 183U, 184U, 185U, 186U, 186U, 187U, 188U, 189U, 190U, 190U, 191U, 192U, 193U, 193U, 194U, 195U, 195U, 196U, 196U, 197U, 197U, 198U, 199U, 199U, 199U, 200U, 200U, 201U, 201U, 202U, 202U, 202U, 203U, 203U, 203U, 203U, 204U, 204U, 204U, 204U, 204U, 204U, 204U, 205U, 205U, 205U, 205U, 205U, 205U, 205U, 204U, 204U, 204U, 204U, 204U, 204U, 204U, 203U, 203U, 203U, 203U, 202U, 202U, 202U, 201U, 201U, 200U, 200U, 199U, 199U, 199U, 198U, 197U, 197U, 196U, 196U, 195U, 195U, 194U, 193U, 193U, 192U, 191U, 190U, 190U, 189U, 188U, 187U, 186U, 186U, 185U, 184U, 183U, 182U, 181U, 180U, 179U, 178U, 177U, 177U, 176U, 175U, 174U, 172U, 171U, 170U, 169U, 168U, 167U, 166U, 165U, 164U, 163U, 162U, 160U, 159U, 158U, 157U, 156U, 155U, 154U, 152U, 151U, 150U, 149U, 148U, 146U, 145U, 144U, 143U, 141U, 140U, 139U, 138U, 137U, 135U, 134U, 133U, 132U, 130U, 129U, 128U, 127U, 125U, 124U, 123U, 122U, 121U, 119U, 118U, 117U, 116U, 115U, 113U, 112U, 111U, 110U, 109U, 108U, 106U, 105U, 104U, 103U, 102U, 101U, 100U, 99U, 98U, 97U, 96U, 95U, 94U, 93U, 92U, 91U, 90U, 89U, 88U, 87U, 86U, 85U, 84U, 83U, 82U, 82U, 81U, 80U, 79U, 78U, 78U, 77U, 76U, 76U, 75U, 74U, 74U, 73U, 72U, 72U, 71U, 71U, 70U, 70U, 69U, 69U, 68U, 68U, 67U, 67U, 67U, 66U, 66U, 66U, 65U, 65U, 65U, 65U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 63U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 65U, 65U, 65U, 65U, 66U, 66U, 66U, 67U, 67U, 67U, 68U, 68U, 69U, 69U, 70U, 70U, 71U, 71U, 72U, 72U, 73U, 74U, 74U, 75U, 76U, 76U, 77U, 78U, 78U, 79U, 80U, 81U, 82U, 82U, 83U, 84U, 85U, 86U, 87U, 88U, 89U, 90U, 91U, 92U, 93U, 94U, 95U, 96U, 97U, 98U, 99U, 100U, 101U, 102U, 103U, 104U, 105U, 106U, 108U, 109U, 110U, 111U, 112U, 113U, 115U, 116U, 117U, 118U, 119U, 121U, 122U, 123U, 124U, 125U, 127U, 128U, 129U, 130U, 132U, 133U };
|
||||
|
||||
// Init DAC
|
||||
register_set(&DAC1->MCR, 0U, 0xFFFFFFFFU);
|
||||
register_set(&DAC1->CR, DAC_CR_TEN1 | (6U << DAC_CR_TSEL1_Pos) | DAC_CR_DMAEN1, 0xFFFFFFFFU);
|
||||
|
|
|
@ -1,21 +1,9 @@
|
|||
struct fan_state_t {
|
||||
uint16_t tach_counter;
|
||||
uint16_t rpm;
|
||||
uint16_t target_rpm;
|
||||
uint8_t power;
|
||||
float error_integral;
|
||||
uint8_t stall_counter;
|
||||
uint8_t stall_threshold;
|
||||
uint8_t total_stall_count;
|
||||
uint8_t cooldown_counter;
|
||||
} fan_state_t;
|
||||
#include "fan_declarations.h"
|
||||
|
||||
struct fan_state_t fan_state;
|
||||
|
||||
const float FAN_I = 0.001f;
|
||||
|
||||
const uint8_t FAN_TICK_FREQ = 8U;
|
||||
const uint8_t FAN_STALL_THRESHOLD_MIN = 3U;
|
||||
const uint8_t FAN_STALL_THRESHOLD_MAX = 8U;
|
||||
static const uint8_t FAN_TICK_FREQ = 8U;
|
||||
static const uint8_t FAN_STALL_THRESHOLD_MIN = 3U;
|
||||
|
||||
|
||||
void fan_set_power(uint8_t percentage) {
|
||||
|
@ -31,6 +19,9 @@ void fan_init(void) {
|
|||
|
||||
// Call this at FAN_TICK_FREQ
|
||||
void fan_tick(void) {
|
||||
const float FAN_I = 0.001f;
|
||||
const uint8_t FAN_STALL_THRESHOLD_MAX = 8U;
|
||||
|
||||
if (current_board->fan_max_rpm > 0U) {
|
||||
// Measure fan RPM
|
||||
uint16_t fan_rpm_fast = fan_state.tach_counter * (60U * FAN_TICK_FREQ / 4U); // 4 interrupts per rotation
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
struct fan_state_t {
|
||||
uint16_t tach_counter;
|
||||
uint16_t rpm;
|
||||
uint16_t target_rpm;
|
||||
uint8_t power;
|
||||
float error_integral;
|
||||
uint8_t stall_counter;
|
||||
uint8_t stall_threshold;
|
||||
uint8_t total_stall_count;
|
||||
uint8_t cooldown_counter;
|
||||
};
|
||||
extern struct fan_state_t fan_state;
|
||||
|
||||
void fan_set_power(uint8_t percentage);
|
||||
void llfan_init(void);
|
||||
void fan_init(void);
|
||||
// Call this at FAN_TICK_FREQ
|
||||
void fan_tick(void);
|
|
@ -1,25 +1,8 @@
|
|||
// IRQs: FDCAN1_IT0, FDCAN1_IT1
|
||||
// FDCAN2_IT0, FDCAN2_IT1
|
||||
// FDCAN3_IT0, FDCAN3_IT1
|
||||
#include "fdcan_declarations.h"
|
||||
|
||||
#define CANFD
|
||||
FDCAN_GlobalTypeDef *cans[CANS_ARRAY_SIZE] = {FDCAN1, FDCAN2, FDCAN3};
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t header[2];
|
||||
volatile uint32_t data_word[CANPACKET_DATA_SIZE_MAX/4U];
|
||||
} canfd_fifo;
|
||||
|
||||
FDCAN_GlobalTypeDef *cans[] = {FDCAN1, FDCAN2, FDCAN3};
|
||||
|
||||
uint8_t can_irq_number[3][2] = {
|
||||
{ FDCAN1_IT0_IRQn, FDCAN1_IT1_IRQn },
|
||||
{ FDCAN2_IT0_IRQn, FDCAN2_IT1_IRQn },
|
||||
{ FDCAN3_IT0_IRQn, FDCAN3_IT1_IRQn },
|
||||
};
|
||||
|
||||
#define CAN_ACK_ERROR 3U
|
||||
|
||||
bool can_set_speed(uint8_t can_number) {
|
||||
static bool can_set_speed(uint8_t can_number) {
|
||||
bool ret = true;
|
||||
FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
|
||||
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
|
||||
|
@ -42,6 +25,12 @@ void can_clear_send(FDCAN_GlobalTypeDef *FDCANx, uint8_t can_number) {
|
|||
}
|
||||
|
||||
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
|
||||
uint8_t can_irq_number[3][2] = {
|
||||
{ FDCAN1_IT0_IRQn, FDCAN1_IT1_IRQn },
|
||||
{ FDCAN2_IT0_IRQn, FDCAN2_IT1_IRQn },
|
||||
{ FDCAN3_IT0_IRQn, FDCAN3_IT1_IRQn },
|
||||
};
|
||||
|
||||
FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
|
||||
uint32_t psr_reg = FDCANx->PSR;
|
||||
uint32_t ecr_reg = FDCANx->ECR;
|
||||
|
@ -241,14 +230,14 @@ void can_rx(uint8_t can_number) {
|
|||
}
|
||||
}
|
||||
|
||||
void FDCAN1_IT0_IRQ_Handler(void) { can_rx(0); }
|
||||
void FDCAN1_IT1_IRQ_Handler(void) { process_can(0); }
|
||||
static void FDCAN1_IT0_IRQ_Handler(void) { can_rx(0); }
|
||||
static void FDCAN1_IT1_IRQ_Handler(void) { process_can(0); }
|
||||
|
||||
void FDCAN2_IT0_IRQ_Handler(void) { can_rx(1); }
|
||||
void FDCAN2_IT1_IRQ_Handler(void) { process_can(1); }
|
||||
static void FDCAN2_IT0_IRQ_Handler(void) { can_rx(1); }
|
||||
static void FDCAN2_IT1_IRQ_Handler(void) { process_can(1); }
|
||||
|
||||
void FDCAN3_IT0_IRQ_Handler(void) { can_rx(2); }
|
||||
void FDCAN3_IT1_IRQ_Handler(void) { process_can(2); }
|
||||
static void FDCAN3_IT0_IRQ_Handler(void) { can_rx(2); }
|
||||
static void FDCAN3_IT1_IRQ_Handler(void) { process_can(2); }
|
||||
|
||||
bool can_init(uint8_t can_number) {
|
||||
bool ret = false;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
// IRQs: FDCAN1_IT0, FDCAN1_IT1
|
||||
// FDCAN2_IT0, FDCAN2_IT1
|
||||
// FDCAN3_IT0, FDCAN3_IT1
|
||||
|
||||
#define CANFD
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t header[2];
|
||||
volatile uint32_t data_word[CANPACKET_DATA_SIZE_MAX/4U];
|
||||
} canfd_fifo;
|
||||
|
||||
#define CANS_ARRAY_SIZE 3
|
||||
extern FDCAN_GlobalTypeDef *cans[CANS_ARRAY_SIZE];
|
||||
|
||||
#define CAN_ACK_ERROR 3U
|
||||
|
||||
void can_clear_send(FDCAN_GlobalTypeDef *FDCANx, uint8_t can_number);
|
||||
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg);
|
||||
|
||||
// ***************************** CAN *****************************
|
||||
// FDFDCANx_IT1 IRQ Handler (TX)
|
||||
void process_can(uint8_t can_number);
|
||||
// FDFDCANx_IT0 IRQ Handler (RX and errors)
|
||||
// blink blue when we are receiving CAN messages
|
||||
void can_rx(uint8_t can_number);
|
||||
bool can_init(uint8_t can_number);
|
|
@ -1,30 +1,7 @@
|
|||
#define HARNESS_STATUS_NC 0U
|
||||
#define HARNESS_STATUS_NORMAL 1U
|
||||
#define HARNESS_STATUS_FLIPPED 2U
|
||||
#include "harness_declarations.h"
|
||||
|
||||
struct harness_t {
|
||||
uint8_t status;
|
||||
uint16_t sbu1_voltage_mV;
|
||||
uint16_t sbu2_voltage_mV;
|
||||
bool relay_driven;
|
||||
bool sbu_adc_lock;
|
||||
};
|
||||
struct harness_t harness;
|
||||
|
||||
struct harness_configuration {
|
||||
const bool has_harness;
|
||||
GPIO_TypeDef * const GPIO_SBU1;
|
||||
GPIO_TypeDef * const GPIO_SBU2;
|
||||
GPIO_TypeDef * const GPIO_relay_SBU1;
|
||||
GPIO_TypeDef * const GPIO_relay_SBU2;
|
||||
const uint8_t pin_SBU1;
|
||||
const uint8_t pin_SBU2;
|
||||
const uint8_t pin_relay_SBU1;
|
||||
const uint8_t pin_relay_SBU2;
|
||||
const uint8_t adc_channel_SBU1;
|
||||
const uint8_t adc_channel_SBU2;
|
||||
};
|
||||
|
||||
// The ignition relay is only used for testing purposes
|
||||
void set_intercept_relay(bool intercept, bool ignition_relay) {
|
||||
if (current_board->harness_config->has_harness) {
|
||||
|
@ -74,7 +51,7 @@ bool harness_check_ignition(void) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
uint8_t harness_detect_orientation(void) {
|
||||
static uint8_t harness_detect_orientation(void) {
|
||||
uint8_t ret = harness.status;
|
||||
|
||||
#ifndef BOOTSTUB
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#define HARNESS_STATUS_NC 0U
|
||||
#define HARNESS_STATUS_NORMAL 1U
|
||||
#define HARNESS_STATUS_FLIPPED 2U
|
||||
|
||||
struct harness_t {
|
||||
uint8_t status;
|
||||
uint16_t sbu1_voltage_mV;
|
||||
uint16_t sbu2_voltage_mV;
|
||||
bool relay_driven;
|
||||
bool sbu_adc_lock;
|
||||
};
|
||||
extern struct harness_t harness;
|
||||
|
||||
struct harness_configuration {
|
||||
const bool has_harness;
|
||||
GPIO_TypeDef * const GPIO_SBU1;
|
||||
GPIO_TypeDef * const GPIO_SBU2;
|
||||
GPIO_TypeDef * const GPIO_relay_SBU1;
|
||||
GPIO_TypeDef * const GPIO_relay_SBU2;
|
||||
const uint8_t pin_SBU1;
|
||||
const uint8_t pin_SBU2;
|
||||
const uint8_t pin_relay_SBU1;
|
||||
const uint8_t pin_relay_SBU2;
|
||||
const uint8_t adc_channel_SBU1;
|
||||
const uint8_t adc_channel_SBU2;
|
||||
};
|
||||
|
||||
// The ignition relay is only used for testing purposes
|
||||
void set_intercept_relay(bool intercept, bool ignition_relay);
|
||||
bool harness_check_ignition(void);
|
||||
void harness_tick(void);
|
||||
void harness_init(void);
|
|
@ -1,14 +1,4 @@
|
|||
typedef struct interrupt {
|
||||
IRQn_Type irq_type;
|
||||
void (*handler)(void);
|
||||
uint32_t call_counter;
|
||||
uint32_t call_rate;
|
||||
uint32_t max_call_rate; // Call rate is defined as the amount of calls each second
|
||||
uint32_t call_rate_fault;
|
||||
} interrupt;
|
||||
|
||||
void interrupt_timer_init(void);
|
||||
uint32_t microsecond_timer_get(void);
|
||||
#include "interrupts_declarations.h"
|
||||
|
||||
void unused_interrupt_handler(void) {
|
||||
// Something is wrong if this handler is called!
|
||||
|
@ -18,23 +8,15 @@ void unused_interrupt_handler(void) {
|
|||
|
||||
interrupt interrupts[NUM_INTERRUPTS];
|
||||
|
||||
#define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate_max, rate_fault) \
|
||||
interrupts[irq_num].irq_type = (irq_num); \
|
||||
interrupts[irq_num].handler = (func_ptr); \
|
||||
interrupts[irq_num].call_counter = 0U; \
|
||||
interrupts[irq_num].call_rate = 0U; \
|
||||
interrupts[irq_num].max_call_rate = (call_rate_max); \
|
||||
interrupts[irq_num].call_rate_fault = (rate_fault);
|
||||
static bool check_interrupt_rate = false;
|
||||
|
||||
bool check_interrupt_rate = false;
|
||||
|
||||
uint8_t interrupt_depth = 0U;
|
||||
uint32_t last_time = 0U;
|
||||
uint32_t idle_time = 0U;
|
||||
uint32_t busy_time = 0U;
|
||||
static uint32_t idle_time = 0U;
|
||||
static uint32_t busy_time = 0U;
|
||||
float interrupt_load = 0.0f;
|
||||
|
||||
void handle_interrupt(IRQn_Type irq_type){
|
||||
static uint8_t interrupt_depth = 0U;
|
||||
static uint32_t last_time = 0U;
|
||||
ENTER_CRITICAL();
|
||||
if (interrupt_depth == 0U) {
|
||||
uint32_t time = microsecond_timer_get();
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct interrupt {
|
||||
IRQn_Type irq_type;
|
||||
void (*handler)(void);
|
||||
uint32_t call_counter;
|
||||
uint32_t call_rate;
|
||||
uint32_t max_call_rate; // Call rate is defined as the amount of calls each second
|
||||
uint32_t call_rate_fault;
|
||||
} interrupt;
|
||||
|
||||
void interrupt_timer_init(void);
|
||||
uint32_t microsecond_timer_get(void);
|
||||
void unused_interrupt_handler(void);
|
||||
|
||||
extern interrupt interrupts[NUM_INTERRUPTS];
|
||||
|
||||
#define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate_max, rate_fault) \
|
||||
interrupts[irq_num].irq_type = (irq_num); \
|
||||
interrupts[irq_num].handler = (func_ptr); \
|
||||
interrupts[irq_num].call_counter = 0U; \
|
||||
interrupts[irq_num].call_rate = 0U; \
|
||||
interrupts[irq_num].max_call_rate = (call_rate_max); \
|
||||
interrupts[irq_num].call_rate_fault = (rate_fault);
|
||||
|
||||
extern float interrupt_load;
|
||||
|
||||
void handle_interrupt(IRQn_Type irq_type);
|
||||
// Every second
|
||||
void interrupt_timer_handler(void);
|
||||
void init_interrupts(bool check_rate_limit);
|
|
@ -1,21 +1,11 @@
|
|||
#include "registers_declarations.h"
|
||||
|
||||
typedef struct reg {
|
||||
volatile uint32_t *address;
|
||||
uint32_t value;
|
||||
uint32_t check_mask;
|
||||
} reg;
|
||||
|
||||
// 10 bit hash with 23 as a prime
|
||||
#define REGISTER_MAP_SIZE 0x3FFU
|
||||
#define HASHING_PRIME 23U
|
||||
#define CHECK_COLLISION(hash, addr) (((uint32_t) register_map[hash].address != 0U) && (register_map[hash].address != (addr)))
|
||||
|
||||
reg register_map[REGISTER_MAP_SIZE];
|
||||
static reg register_map[REGISTER_MAP_SIZE];
|
||||
|
||||
// Hash spread in first and second iterations seems to be reasonable.
|
||||
// See: tests/development/register_hashmap_spread.py
|
||||
// Also, check the collision warnings in the debug output, and minimize those.
|
||||
uint16_t hash_addr(uint32_t input){
|
||||
static uint16_t hash_addr(uint32_t input){
|
||||
return (((input >> 16U) ^ ((((input + 1U) & 0xFFFFU) * HASHING_PRIME) & 0xFFFFU)) & REGISTER_MAP_SIZE);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct reg {
|
||||
volatile uint32_t *address;
|
||||
uint32_t value;
|
||||
uint32_t check_mask;
|
||||
} reg;
|
||||
|
||||
// 10 bit hash with 23 as a prime
|
||||
#define REGISTER_MAP_SIZE 0x3FFU
|
||||
#define HASHING_PRIME 23U
|
||||
#define CHECK_COLLISION(hash, addr) (((uint32_t) register_map[hash].address != 0U) && (register_map[hash].address != (addr)))
|
||||
|
||||
// Do not put bits in the check mask that get changed by the hardware
|
||||
void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask);
|
||||
// Set individual bits. Also add them to the check_mask.
|
||||
// Do not use this to change bits that get reset by the hardware
|
||||
void register_set_bits(volatile uint32_t *addr, uint32_t val);
|
||||
// Clear individual bits. Also add them to the check_mask.
|
||||
// Do not use this to clear bits that get set by the hardware
|
||||
void register_clear_bits(volatile uint32_t *addr, uint32_t val);
|
||||
// To be called periodically
|
||||
void check_registers(void);
|
||||
void init_registers(void);
|
|
@ -1,11 +1,6 @@
|
|||
typedef struct simple_watchdog_state_t {
|
||||
uint32_t fault;
|
||||
uint32_t last_ts;
|
||||
uint32_t threshold;
|
||||
} simple_watchdog_state_t;
|
||||
|
||||
simple_watchdog_state_t wd_state;
|
||||
#include "simple_watchdog_declarations.h"
|
||||
|
||||
static simple_watchdog_state_t wd_state;
|
||||
|
||||
void simple_watchdog_kick(void) {
|
||||
uint32_t ts = microsecond_timer_get();
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct simple_watchdog_state_t {
|
||||
uint32_t fault;
|
||||
uint32_t last_ts;
|
||||
uint32_t threshold;
|
||||
} simple_watchdog_state_t;
|
||||
|
||||
void simple_watchdog_kick(void);
|
||||
void simple_watchdog_init(uint32_t fault, uint32_t threshold);
|
|
@ -1,13 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "spi_declarations.h"
|
||||
#include "crc.h"
|
||||
|
||||
#define SPI_TIMEOUT_US 10000U
|
||||
|
||||
// got max rate from hitting a non-existent endpoint
|
||||
// in a tight loop, plus some buffer
|
||||
#define SPI_IRQ_RATE 16000U
|
||||
|
||||
#ifdef STM32H7
|
||||
#define SPI_BUF_SIZE 2048U
|
||||
// H7 DMA2 located in D2 domain, so we need to use SRAM1/SRAM2
|
||||
|
@ -19,44 +14,18 @@ uint8_t spi_buf_rx[SPI_BUF_SIZE];
|
|||
uint8_t spi_buf_tx[SPI_BUF_SIZE];
|
||||
#endif
|
||||
|
||||
#define SPI_CHECKSUM_START 0xABU
|
||||
#define SPI_SYNC_BYTE 0x5AU
|
||||
#define SPI_HACK 0x79U
|
||||
#define SPI_DACK 0x85U
|
||||
#define SPI_NACK 0x1FU
|
||||
|
||||
// SPI states
|
||||
enum {
|
||||
SPI_STATE_HEADER,
|
||||
SPI_STATE_HEADER_ACK,
|
||||
SPI_STATE_HEADER_NACK,
|
||||
SPI_STATE_DATA_RX,
|
||||
SPI_STATE_DATA_RX_ACK,
|
||||
SPI_STATE_DATA_TX
|
||||
};
|
||||
|
||||
bool spi_tx_dma_done = false;
|
||||
uint8_t spi_state = SPI_STATE_HEADER;
|
||||
uint8_t spi_endpoint;
|
||||
uint16_t spi_data_len_mosi;
|
||||
uint16_t spi_data_len_miso;
|
||||
static uint8_t spi_state = SPI_STATE_HEADER;
|
||||
static uint16_t spi_data_len_mosi;
|
||||
uint16_t spi_checksum_error_count = 0;
|
||||
bool spi_can_tx_ready = false;
|
||||
static bool spi_can_tx_ready = false;
|
||||
|
||||
const unsigned char version_text[] = "VERSION";
|
||||
|
||||
#define SPI_HEADER_SIZE 7U
|
||||
|
||||
// low level SPI prototypes
|
||||
void llspi_init(void);
|
||||
void llspi_mosi_dma(uint8_t *addr, int len);
|
||||
void llspi_miso_dma(uint8_t *addr, int len);
|
||||
static const unsigned char version_text[] = "VERSION";
|
||||
|
||||
void can_tx_comms_resume_spi(void) {
|
||||
spi_can_tx_ready = true;
|
||||
}
|
||||
|
||||
uint16_t spi_version_packet(uint8_t *out) {
|
||||
static uint16_t spi_version_packet(uint8_t *out) {
|
||||
// this protocol version request is a stable portion of
|
||||
// the panda's SPI protocol. its contents match that of the
|
||||
// panda USB descriptors and are sufficent to list/enumerate
|
||||
|
@ -100,6 +69,7 @@ uint16_t spi_version_packet(uint8_t *out) {
|
|||
return resp_len;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_SPI) || defined(BOOTSTUB)
|
||||
void spi_init(void) {
|
||||
// platform init
|
||||
llspi_init();
|
||||
|
@ -108,8 +78,9 @@ void spi_init(void) {
|
|||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool validate_checksum(const uint8_t *data, uint16_t len) {
|
||||
static bool validate_checksum(const uint8_t *data, uint16_t len) {
|
||||
// TODO: can speed this up by casting the bulk to uint32_t and xor-ing the bytes afterwards
|
||||
uint8_t checksum = SPI_CHECKSUM_START;
|
||||
for(uint16_t i = 0U; i < len; i++){
|
||||
|
@ -122,6 +93,8 @@ void spi_rx_done(void) {
|
|||
uint16_t response_len = 0U;
|
||||
uint8_t next_rx_state = SPI_STATE_HEADER_NACK;
|
||||
bool checksum_valid = false;
|
||||
static uint8_t spi_endpoint;
|
||||
static uint16_t spi_data_len_miso;
|
||||
|
||||
// parse header
|
||||
spi_endpoint = spi_buf_rx[1];
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "crc.h"
|
||||
|
||||
#define SPI_TIMEOUT_US 10000U
|
||||
|
||||
// got max rate from hitting a non-existent endpoint
|
||||
// in a tight loop, plus some buffer
|
||||
#define SPI_IRQ_RATE 16000U
|
||||
|
||||
#ifdef STM32H7
|
||||
#define SPI_BUF_SIZE 2048U
|
||||
// H7 DMA2 located in D2 domain, so we need to use SRAM1/SRAM2
|
||||
__attribute__((section(".sram12"))) extern uint8_t spi_buf_rx[SPI_BUF_SIZE];
|
||||
__attribute__((section(".sram12"))) extern uint8_t spi_buf_tx[SPI_BUF_SIZE];
|
||||
#else
|
||||
#define SPI_BUF_SIZE 1024U
|
||||
extern uint8_t spi_buf_rx[SPI_BUF_SIZE];
|
||||
extern uint8_t spi_buf_tx[SPI_BUF_SIZE];
|
||||
#endif
|
||||
|
||||
#define SPI_CHECKSUM_START 0xABU
|
||||
#define SPI_SYNC_BYTE 0x5AU
|
||||
#define SPI_HACK 0x79U
|
||||
#define SPI_DACK 0x85U
|
||||
#define SPI_NACK 0x1FU
|
||||
|
||||
// SPI states
|
||||
enum {
|
||||
SPI_STATE_HEADER,
|
||||
SPI_STATE_HEADER_ACK,
|
||||
SPI_STATE_HEADER_NACK,
|
||||
SPI_STATE_DATA_RX,
|
||||
SPI_STATE_DATA_RX_ACK,
|
||||
SPI_STATE_DATA_TX
|
||||
};
|
||||
|
||||
extern uint16_t spi_checksum_error_count;
|
||||
|
||||
#define SPI_HEADER_SIZE 7U
|
||||
|
||||
// low level SPI prototypes
|
||||
void llspi_init(void);
|
||||
void llspi_mosi_dma(uint8_t *addr, int len);
|
||||
void llspi_miso_dma(uint8_t *addr, int len);
|
||||
|
||||
void can_tx_comms_resume_spi(void);
|
||||
#if defined(ENABLE_SPI) || defined(BOOTSTUB)
|
||||
void spi_init(void);
|
||||
#endif
|
||||
void spi_rx_done(void);
|
||||
void spi_tx_done(bool reset);
|
|
@ -1,4 +1,4 @@
|
|||
void timer_init(TIM_TypeDef *TIM, int psc) {
|
||||
static void timer_init(TIM_TypeDef *TIM, int psc) {
|
||||
register_set(&(TIM->PSC), (psc-1), 0xFFFFU);
|
||||
register_set(&(TIM->DIER), TIM_DIER_UIE, 0x5F5FU);
|
||||
register_set(&(TIM->CR1), TIM_CR1_CEN, 0x3FU);
|
||||
|
|
|
@ -1,25 +1,13 @@
|
|||
#include "uart_declarations.h"
|
||||
|
||||
// IRQs: USART2, USART3, UART5
|
||||
|
||||
// ***************************** Definitions *****************************
|
||||
#define FIFO_SIZE_INT 0x400U
|
||||
|
||||
typedef struct uart_ring {
|
||||
volatile uint16_t w_ptr_tx;
|
||||
volatile uint16_t r_ptr_tx;
|
||||
uint8_t *elems_tx;
|
||||
uint32_t tx_fifo_size;
|
||||
volatile uint16_t w_ptr_rx;
|
||||
volatile uint16_t r_ptr_rx;
|
||||
uint8_t *elems_rx;
|
||||
uint32_t rx_fifo_size;
|
||||
USART_TypeDef *uart;
|
||||
void (*callback)(struct uart_ring*);
|
||||
bool overwrite;
|
||||
} uart_ring;
|
||||
|
||||
#define UART_BUFFER(x, size_rx, size_tx, uart_ptr, callback_ptr, overwrite_mode) \
|
||||
uint8_t elems_rx_##x[size_rx]; \
|
||||
uint8_t elems_tx_##x[size_tx]; \
|
||||
static uint8_t elems_rx_##x[size_rx]; \
|
||||
static uint8_t elems_tx_##x[size_tx]; \
|
||||
extern uart_ring uart_ring_##x; \
|
||||
uart_ring uart_ring_##x = { \
|
||||
.w_ptr_tx = 0, \
|
||||
.r_ptr_tx = 0, \
|
||||
|
@ -34,9 +22,6 @@ typedef struct uart_ring {
|
|||
.overwrite = (overwrite_mode) \
|
||||
};
|
||||
|
||||
// ***************************** Function prototypes *****************************
|
||||
void debug_ring_callback(uart_ring *ring);
|
||||
void uart_tx_ring(uart_ring *q);
|
||||
// ******************************** UART buffers ********************************
|
||||
|
||||
// debug = USART2
|
||||
|
@ -149,20 +134,6 @@ void print(const char *a) {
|
|||
}
|
||||
}
|
||||
|
||||
void putui(uint32_t i) {
|
||||
uint32_t i_copy = i;
|
||||
char str[11];
|
||||
uint8_t idx = 10;
|
||||
str[idx] = '\0';
|
||||
idx--;
|
||||
do {
|
||||
str[idx] = (i_copy % 10U) + 0x30U;
|
||||
idx--;
|
||||
i_copy /= 10;
|
||||
} while (i_copy != 0U);
|
||||
print(&str[idx + 1U]);
|
||||
}
|
||||
|
||||
void puthx(uint32_t i, uint8_t len) {
|
||||
const char c[] = "0123456789abcdef";
|
||||
for (int pos = ((int)len * 4) - 4; pos > -4; pos -= 4) {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
// IRQs: USART2, USART3, UART5
|
||||
|
||||
// ***************************** Definitions *****************************
|
||||
#define FIFO_SIZE_INT 0x400U
|
||||
|
||||
typedef struct uart_ring {
|
||||
volatile uint16_t w_ptr_tx;
|
||||
volatile uint16_t r_ptr_tx;
|
||||
uint8_t *elems_tx;
|
||||
uint32_t tx_fifo_size;
|
||||
volatile uint16_t w_ptr_rx;
|
||||
volatile uint16_t r_ptr_rx;
|
||||
uint8_t *elems_rx;
|
||||
uint32_t rx_fifo_size;
|
||||
USART_TypeDef *uart;
|
||||
void (*callback)(struct uart_ring*);
|
||||
bool overwrite;
|
||||
} uart_ring;
|
||||
|
||||
// ***************************** Function prototypes *****************************
|
||||
void debug_ring_callback(uart_ring *ring);
|
||||
void uart_tx_ring(uart_ring *q);
|
||||
uart_ring *get_ring_by_number(int a);
|
||||
// ************************* Low-level buffer functions *************************
|
||||
bool get_char(uart_ring *q, char *elem);
|
||||
bool injectc(uart_ring *q, char elem);
|
||||
bool put_char(uart_ring *q, char elem);
|
||||
void clear_uart_buff(uart_ring *q);
|
||||
// ************************ High-level debug functions **********************
|
||||
void putch(const char a);
|
||||
void print(const char *a);
|
||||
void puthx(uint32_t i, uint8_t len);
|
||||
void puth(unsigned int i);
|
||||
void puth2(unsigned int i);
|
||||
void puth4(unsigned int i);
|
||||
void hexdump(const void *a, int l);
|
|
@ -1,116 +1,138 @@
|
|||
// IRQs: OTG_FS
|
||||
|
||||
typedef union {
|
||||
uint16_t w;
|
||||
struct BW {
|
||||
uint8_t msb;
|
||||
uint8_t lsb;
|
||||
}
|
||||
bw;
|
||||
}
|
||||
uint16_t_uint8_t;
|
||||
|
||||
typedef union _USB_Setup {
|
||||
uint32_t d8[2];
|
||||
struct _SetupPkt_Struc
|
||||
{
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t_uint8_t wValue;
|
||||
uint16_t_uint8_t wIndex;
|
||||
uint16_t_uint8_t wLength;
|
||||
} b;
|
||||
}
|
||||
USB_Setup_TypeDef;
|
||||
#include "usb_declarations.h"
|
||||
|
||||
bool usb_enumerated = false;
|
||||
uint16_t usb_last_frame_num = 0U;
|
||||
|
||||
void usb_init(void);
|
||||
void refresh_can_tx_slots_available(void);
|
||||
static uint8_t response[USBPACKET_MAX_SIZE];
|
||||
|
||||
// **** supporting defines ****
|
||||
// current packet
|
||||
static USB_Setup_TypeDef setup;
|
||||
static uint8_t* ep0_txdata = NULL;
|
||||
static uint16_t ep0_txlen = 0;
|
||||
static bool outep3_processing = false;
|
||||
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
// Store the current interface alt setting.
|
||||
static int current_int0_alt_setting = 0;
|
||||
|
||||
#define USB_DESC_TYPE_DEVICE 0x01
|
||||
#define USB_DESC_TYPE_CONFIGURATION 0x02
|
||||
#define USB_DESC_TYPE_STRING 0x03
|
||||
#define USB_DESC_TYPE_INTERFACE 0x04
|
||||
#define USB_DESC_TYPE_ENDPOINT 0x05
|
||||
#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06
|
||||
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07
|
||||
#define USB_DESC_TYPE_BINARY_OBJECT_STORE 0x0f
|
||||
// packet read and write
|
||||
|
||||
// offsets for configuration strings
|
||||
#define STRING_OFFSET_LANGID 0x00
|
||||
#define STRING_OFFSET_IMANUFACTURER 0x01
|
||||
#define STRING_OFFSET_IPRODUCT 0x02
|
||||
#define STRING_OFFSET_ISERIAL 0x03
|
||||
#define STRING_OFFSET_ICONFIGURATION 0x04
|
||||
#define STRING_OFFSET_IINTERFACE 0x05
|
||||
static void *USB_ReadPacket(void *dest, uint16_t len) {
|
||||
uint32_t *dest_copy = (uint32_t *)dest;
|
||||
uint32_t count32b = ((uint32_t)len + 3U) / 4U;
|
||||
|
||||
// WebUSB requests
|
||||
#define WEBUSB_REQ_GET_URL 0x02
|
||||
for (uint32_t i = 0; i < count32b; i++) {
|
||||
*dest_copy = USBx_DFIFO(0U);
|
||||
dest_copy++;
|
||||
}
|
||||
return ((void *)dest_copy);
|
||||
}
|
||||
|
||||
// WebUSB types
|
||||
#define WEBUSB_DESC_TYPE_URL 0x03
|
||||
#define WEBUSB_URL_SCHEME_HTTPS 0x01
|
||||
#define WEBUSB_URL_SCHEME_HTTP 0x00
|
||||
static void USB_WritePacket(const void *src, uint16_t len, uint32_t ep) {
|
||||
#ifdef DEBUG_USB
|
||||
print("writing ");
|
||||
hexdump(src, len);
|
||||
#endif
|
||||
|
||||
// WinUSB requests
|
||||
#define WINUSB_REQ_GET_COMPATID_DESCRIPTOR 0x04
|
||||
#define WINUSB_REQ_GET_EXT_PROPS_OS 0x05
|
||||
#define WINUSB_REQ_GET_DESCRIPTOR 0x07
|
||||
uint32_t numpacket = ((uint32_t)len + (USBPACKET_MAX_SIZE - 1U)) / USBPACKET_MAX_SIZE;
|
||||
uint32_t count32b = 0;
|
||||
count32b = ((uint32_t)len + 3U) / 4U;
|
||||
|
||||
#define STS_GOUT_NAK 1
|
||||
#define STS_DATA_UPDT 2
|
||||
#define STS_XFER_COMP 3
|
||||
#define STS_SETUP_COMP 4
|
||||
#define STS_SETUP_UPDT 6
|
||||
// TODO: revisit this
|
||||
USBx_INEP(ep)->DIEPTSIZ = ((numpacket << 19) & USB_OTG_DIEPTSIZ_PKTCNT) |
|
||||
(len & USB_OTG_DIEPTSIZ_XFRSIZ);
|
||||
USBx_INEP(ep)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);
|
||||
|
||||
uint8_t response[USBPACKET_MAX_SIZE];
|
||||
// load the FIFO
|
||||
if (src != NULL) {
|
||||
const uint32_t *src_copy = (const uint32_t *)src;
|
||||
for (uint32_t i = 0; i < count32b; i++) {
|
||||
USBx_DFIFO(ep) = *src_copy;
|
||||
src_copy++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for the repeating interfaces
|
||||
#define DSCR_INTERFACE_LEN 9
|
||||
#define DSCR_ENDPOINT_LEN 7
|
||||
#define DSCR_CONFIG_LEN 9
|
||||
#define DSCR_DEVICE_LEN 18
|
||||
// IN EP 0 TX FIFO has a max size of 127 bytes (much smaller than the rest)
|
||||
// so use TX FIFO empty interrupt to send larger amounts of data
|
||||
static void USB_WritePacket_EP0(uint8_t *src, uint16_t len) {
|
||||
#ifdef DEBUG_USB
|
||||
print("writing ");
|
||||
hexdump(src, len);
|
||||
#endif
|
||||
|
||||
// endpoint types
|
||||
#define ENDPOINT_TYPE_CONTROL 0
|
||||
#define ENDPOINT_TYPE_ISO 1
|
||||
#define ENDPOINT_TYPE_BULK 2
|
||||
#define ENDPOINT_TYPE_INT 3
|
||||
uint16_t wplen = MIN(len, 0x40);
|
||||
USB_WritePacket(src, wplen, 0);
|
||||
|
||||
// These are arbitrary values used in bRequest
|
||||
#define MS_VENDOR_CODE 0x20
|
||||
#define WEBUSB_VENDOR_CODE 0x30
|
||||
if (wplen < len) {
|
||||
ep0_txdata = &src[wplen];
|
||||
ep0_txlen = len - wplen;
|
||||
USBx_DEVICE->DIEPEMPMSK |= 1;
|
||||
} else {
|
||||
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
|
||||
}
|
||||
}
|
||||
|
||||
// BOS constants
|
||||
#define BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH 0x05
|
||||
#define BINARY_OBJECT_STORE_DESCRIPTOR 0x0F
|
||||
#define WINUSB_PLATFORM_DESCRIPTOR_LENGTH 0x9E
|
||||
static void usb_reset(void) {
|
||||
// unmask endpoint interrupts, so many sets
|
||||
USBx_DEVICE->DAINT = 0xFFFFFFFFU;
|
||||
USBx_DEVICE->DAINTMSK = 0xFFFFFFFFU;
|
||||
//USBx_DEVICE->DOEPMSK = (USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_EPDM);
|
||||
//USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM | USB_OTG_DIEPMSK_ITTXFEMSK);
|
||||
//USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM);
|
||||
|
||||
// Convert machine byte order to USB byte order
|
||||
#define TOUSBORDER(num)\
|
||||
((num) & 0xFFU), (((uint16_t)(num) >> 8) & 0xFFU)
|
||||
// all interrupts for debugging
|
||||
USBx_DEVICE->DIEPMSK = 0xFFFFFFFFU;
|
||||
USBx_DEVICE->DOEPMSK = 0xFFFFFFFFU;
|
||||
|
||||
// take in string length and return the first 2 bytes of a string descriptor
|
||||
#define STRING_DESCRIPTOR_HEADER(size)\
|
||||
(((((size) * 2) + 2) & 0xFF) | 0x0300)
|
||||
// clear interrupts
|
||||
USBx_INEP(0U)->DIEPINT = 0xFF;
|
||||
USBx_OUTEP(0U)->DOEPINT = 0xFF;
|
||||
|
||||
uint8_t device_desc[] = {
|
||||
// unset the address
|
||||
USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD;
|
||||
|
||||
// set up USB FIFOs
|
||||
// RX start address is fixed to 0
|
||||
USBx->GRXFSIZ = 0x40;
|
||||
|
||||
// 0x100 to offset past GRXFSIZ
|
||||
USBx->DIEPTXF0_HNPTXFSIZ = (0x40UL << 16) | 0x40U;
|
||||
|
||||
// EP1, massive
|
||||
USBx->DIEPTXF[0] = (0x40UL << 16) | 0x80U;
|
||||
|
||||
// flush TX fifo
|
||||
USBx->GRSTCTL = USB_OTG_GRSTCTL_TXFFLSH | USB_OTG_GRSTCTL_TXFNUM_4;
|
||||
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH);
|
||||
// flush RX FIFO
|
||||
USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH;
|
||||
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH);
|
||||
|
||||
// no global NAK
|
||||
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK;
|
||||
|
||||
// ready to receive setup packets
|
||||
USBx_OUTEP(0U)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (3U << 3);
|
||||
}
|
||||
|
||||
static char to_hex_char(uint8_t a) {
|
||||
char ret;
|
||||
if (a < 10U) {
|
||||
ret = '0' + a;
|
||||
} else {
|
||||
ret = 'a' + (a - 10U);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usb_tick(void) {
|
||||
static uint16_t usb_last_frame_num = 0U;
|
||||
uint16_t current_frame_num = (USBx_DEVICE->DSTS & USB_OTG_DSTS_FNSOF_Msk) >> USB_OTG_DSTS_FNSOF_Pos;
|
||||
usb_enumerated = (current_frame_num != usb_last_frame_num);
|
||||
usb_last_frame_num = current_frame_num;
|
||||
}
|
||||
|
||||
static void usb_setup(void) {
|
||||
static uint8_t device_desc[] = {
|
||||
DSCR_DEVICE_LEN, USB_DESC_TYPE_DEVICE, //Length, Type
|
||||
0x10, 0x02, // bcdUSB max version of USB supported (2.1)
|
||||
0xFF, 0xFF, 0xFF, 0x40, // Class, Subclass, Protocol, Max Packet Size
|
||||
|
@ -119,19 +141,16 @@ uint8_t device_desc[] = {
|
|||
0x00, 0x00, // bcdDevice
|
||||
0x01, 0x02, // Manufacturer, Product
|
||||
0x03, 0x01 // Serial Number, Num Configurations
|
||||
};
|
||||
};
|
||||
|
||||
uint8_t device_qualifier[] = {
|
||||
static uint8_t device_qualifier[] = {
|
||||
0x0a, USB_DESC_TYPE_DEVICE_QUALIFIER, //Length, Type
|
||||
0x10, 0x02, // bcdUSB max version of USB supported (2.1)
|
||||
0xFF, 0xFF, 0xFF, 0x40, // bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0
|
||||
0x01, 0x00 // bNumConfigurations, bReserved
|
||||
};
|
||||
};
|
||||
|
||||
#define ENDPOINT_RCV 0x80
|
||||
#define ENDPOINT_SND 0x00
|
||||
|
||||
uint8_t configuration_desc[] = {
|
||||
static uint8_t configuration_desc[] = {
|
||||
DSCR_CONFIG_LEN, USB_DESC_TYPE_CONFIGURATION, // Length, Type,
|
||||
TOUSBORDER(0x0045U), // Total Len (uint16)
|
||||
0x01, 0x01, STRING_OFFSET_ICONFIGURATION, // Num Interface, Config Value, Configuration
|
||||
|
@ -176,48 +195,43 @@ uint8_t configuration_desc[] = {
|
|||
ENDPOINT_SND | 3, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type
|
||||
TOUSBORDER(0x0040U), // Max Packet (0x0040)
|
||||
0x00, // Polling Interval
|
||||
};
|
||||
};
|
||||
|
||||
// STRING_DESCRIPTOR_HEADER is for uint16 string descriptors
|
||||
// it takes in a string length, which is bytes/2 because unicode
|
||||
uint16_t string_language_desc[] = {
|
||||
// STRING_DESCRIPTOR_HEADER is for uint16 string descriptors
|
||||
// it takes in a string length, which is bytes/2 because unicode
|
||||
static uint16_t string_language_desc[] = {
|
||||
STRING_DESCRIPTOR_HEADER(1),
|
||||
0x0409 // american english
|
||||
};
|
||||
};
|
||||
|
||||
// these strings are all uint16's so that we don't need to spam ,0 after every character
|
||||
uint16_t string_manufacturer_desc[] = {
|
||||
// these strings are all uint16's so that we don't need to spam ,0 after every character
|
||||
static uint16_t string_manufacturer_desc[] = {
|
||||
STRING_DESCRIPTOR_HEADER(8),
|
||||
'c', 'o', 'm', 'm', 'a', '.', 'a', 'i'
|
||||
};
|
||||
};
|
||||
|
||||
uint16_t string_product_desc[] = {
|
||||
static uint16_t string_product_desc[] = {
|
||||
STRING_DESCRIPTOR_HEADER(5),
|
||||
'p', 'a', 'n', 'd', 'a'
|
||||
};
|
||||
};
|
||||
|
||||
// default serial number when we're not a panda
|
||||
uint16_t string_serial_desc[] = {
|
||||
STRING_DESCRIPTOR_HEADER(4),
|
||||
'n', 'o', 'n', 'e'
|
||||
};
|
||||
|
||||
// a string containing the default configuration index
|
||||
uint16_t string_configuration_desc[] = {
|
||||
// a string containing the default configuration index
|
||||
static uint16_t string_configuration_desc[] = {
|
||||
STRING_DESCRIPTOR_HEADER(2),
|
||||
'0', '1' // "01"
|
||||
};
|
||||
};
|
||||
|
||||
// WCID (auto install WinUSB driver)
|
||||
// https://github.com/pbatard/libwdi/wiki/WCID-Devices
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/winusb-installation#automatic-installation-of--winusb-without-an-inf-file
|
||||
// WinUSB 1.0 descriptors, this is mostly used by Windows XP
|
||||
uint8_t string_238_desc[] = {
|
||||
// WCID (auto install WinUSB driver)
|
||||
// https://github.com/pbatard/libwdi/wiki/WCID-Devices
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/winusb-installation#automatic-installation-of--winusb-without-an-inf-file
|
||||
// WinUSB 1.0 descriptors, this is mostly used by Windows XP
|
||||
static uint8_t string_238_desc[] = {
|
||||
0x12, USB_DESC_TYPE_STRING, // bLength, bDescriptorType
|
||||
'M',0, 'S',0, 'F',0, 'T',0, '1',0, '0',0, '0',0, // qwSignature (MSFT100)
|
||||
MS_VENDOR_CODE, 0x00 // bMS_VendorCode, bPad
|
||||
};
|
||||
uint8_t winusb_ext_compatid_os_desc[] = {
|
||||
};
|
||||
|
||||
static uint8_t winusb_ext_compatid_os_desc[] = {
|
||||
0x28, 0x00, 0x00, 0x00, // dwLength
|
||||
0x00, 0x01, // bcdVersion
|
||||
0x04, 0x00, // wIndex
|
||||
|
@ -228,8 +242,9 @@ uint8_t winusb_ext_compatid_os_desc[] = {
|
|||
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatible ID (WINUSB)
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subcompatible ID (none)
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Reserved
|
||||
};
|
||||
uint8_t winusb_ext_prop_os_desc[] = {
|
||||
};
|
||||
|
||||
static uint8_t winusb_ext_prop_os_desc[] = {
|
||||
0x8e, 0x00, 0x00, 0x00, // dwLength
|
||||
0x00, 0x01, // bcdVersion
|
||||
0x05, 0x00, // wIndex
|
||||
|
@ -241,18 +256,17 @@ uint8_t winusb_ext_prop_os_desc[] = {
|
|||
'D',0, 'e',0, 'v',0, 'i',0, 'c',0, 'e',0, 'I',0, 'n',0, 't',0, 'e',0, 'r',0, 'f',0, 'a',0, 'c',0, 'e',0, 'G',0, 'U',0, 'I',0, 'D',0, 0, 0, // bPropertyName (DeviceInterfaceGUID)
|
||||
0x4e, 0x00, 0x00, 0x00, // dwPropertyDataLength
|
||||
'{',0, 'c',0, 'c',0, 'e',0, '5',0, '2',0, '9',0, '1',0, 'c',0, '-',0, 'a',0, '6',0, '9',0, 'f',0, '-',0, '4',0 ,'9',0 ,'9',0 ,'5',0 ,'-',0, 'a',0, '4',0, 'c',0, '2',0, '-',0, '2',0, 'a',0, 'e',0, '5',0, '7',0, 'a',0, '5',0, '1',0, 'a',0, 'd',0, 'e',0, '9',0, '}',0, 0, 0, // bPropertyData ({CCE5291C-A69F-4995-A4C2-2AE57A51ADE9})
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Binary Object Store descriptor used to expose WebUSB (and more WinUSB) metadata
|
||||
comments are from the wicg spec
|
||||
References used:
|
||||
/*
|
||||
Binary Object Store descriptor used to expose WebUSB (and more WinUSB) metadata
|
||||
comments are from the wicg spec
|
||||
References used:
|
||||
https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
|
||||
https://github.com/sowbug/weblight/blob/192ad7a0e903542e2aa28c607d98254a12a6399d/firmware/webusb.c
|
||||
https://os.mbed.com/users/larsgk/code/USBDevice_WebUSB/file/1d8a6665d607/WebUSBDevice/
|
||||
|
||||
*/
|
||||
uint8_t binary_object_store_desc[] = {
|
||||
*/
|
||||
static uint8_t binary_object_store_desc[] = {
|
||||
// BOS header
|
||||
BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH, // bLength, this is only the length of the header
|
||||
BINARY_OBJECT_STORE_DESCRIPTOR, // bDescriptorType
|
||||
|
@ -302,13 +316,13 @@ uint8_t binary_object_store_desc[] = {
|
|||
|
||||
WINUSB_PLATFORM_DESCRIPTOR_LENGTH, 0x00, // MS OS 2.0 descriptor size (word)
|
||||
MS_VENDOR_CODE, 0x00 // vendor code, no alternate enumeration
|
||||
};
|
||||
};
|
||||
|
||||
// WinUSB 2.0 descriptor. This is what modern systems use
|
||||
// https://github.com/sowbug/weblight/blob/192ad7a0e903542e2aa28c607d98254a12a6399d/firmware/webusb.c
|
||||
// http://janaxelson.com/files/ms_os_20_descriptors.c
|
||||
// https://books.google.com/books?id=pkefBgAAQBAJ&pg=PA353&lpg=PA353
|
||||
uint8_t winusb_20_desc[WINUSB_PLATFORM_DESCRIPTOR_LENGTH] = {
|
||||
// WinUSB 2.0 descriptor. This is what modern systems use
|
||||
// https://github.com/sowbug/weblight/blob/192ad7a0e903542e2aa28c607d98254a12a6399d/firmware/webusb.c
|
||||
// http://janaxelson.com/files/ms_os_20_descriptors.c
|
||||
// https://books.google.com/books?id=pkefBgAAQBAJ&pg=PA353&lpg=PA353
|
||||
static uint8_t winusb_20_desc[WINUSB_PLATFORM_DESCRIPTOR_LENGTH] = {
|
||||
// Microsoft OS 2.0 descriptor set header (table 10)
|
||||
0x0A, 0x00, // Descriptor size (10 bytes)
|
||||
0x00, 0x00, // MS OS 2.0 descriptor set header
|
||||
|
@ -341,136 +355,8 @@ uint8_t winusb_20_desc[WINUSB_PLATFORM_DESCRIPTOR_LENGTH] = {
|
|||
'9', 0x00, '9', 0x00, '5', 0x00, '-', 0x00, 'a', 0x00, '4', 0x00, 'c', 0x00, '2', 0x00, // 48
|
||||
'-', 0x00, '2', 0x00, 'a', 0x00, 'e', 0x00, '5', 0x00, '7', 0x00, 'a', 0x00, '5', 0x00, // 64
|
||||
'1', 0x00, 'a', 0x00, 'd', 0x00, 'e', 0x00, '9', 0x00, '}', 0x00, 0x00, 0x00 // 78 bytes
|
||||
};
|
||||
};
|
||||
|
||||
// current packet
|
||||
USB_Setup_TypeDef setup;
|
||||
uint8_t usbdata[0x100] __attribute__((aligned(4)));
|
||||
uint8_t* ep0_txdata = NULL;
|
||||
uint16_t ep0_txlen = 0;
|
||||
bool outep3_processing = false;
|
||||
|
||||
// Store the current interface alt setting.
|
||||
int current_int0_alt_setting = 0;
|
||||
|
||||
// packet read and write
|
||||
|
||||
void *USB_ReadPacket(void *dest, uint16_t len) {
|
||||
uint32_t *dest_copy = (uint32_t *)dest;
|
||||
uint32_t count32b = ((uint32_t)len + 3U) / 4U;
|
||||
|
||||
for (uint32_t i = 0; i < count32b; i++) {
|
||||
*dest_copy = USBx_DFIFO(0U);
|
||||
dest_copy++;
|
||||
}
|
||||
return ((void *)dest_copy);
|
||||
}
|
||||
|
||||
void USB_WritePacket(const void *src, uint16_t len, uint32_t ep) {
|
||||
#ifdef DEBUG_USB
|
||||
print("writing ");
|
||||
hexdump(src, len);
|
||||
#endif
|
||||
|
||||
uint32_t numpacket = ((uint32_t)len + (USBPACKET_MAX_SIZE - 1U)) / USBPACKET_MAX_SIZE;
|
||||
uint32_t count32b = 0;
|
||||
count32b = ((uint32_t)len + 3U) / 4U;
|
||||
|
||||
// TODO: revisit this
|
||||
USBx_INEP(ep)->DIEPTSIZ = ((numpacket << 19) & USB_OTG_DIEPTSIZ_PKTCNT) |
|
||||
(len & USB_OTG_DIEPTSIZ_XFRSIZ);
|
||||
USBx_INEP(ep)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);
|
||||
|
||||
// load the FIFO
|
||||
if (src != NULL) {
|
||||
const uint32_t *src_copy = (const uint32_t *)src;
|
||||
for (uint32_t i = 0; i < count32b; i++) {
|
||||
USBx_DFIFO(ep) = *src_copy;
|
||||
src_copy++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IN EP 0 TX FIFO has a max size of 127 bytes (much smaller than the rest)
|
||||
// so use TX FIFO empty interrupt to send larger amounts of data
|
||||
void USB_WritePacket_EP0(uint8_t *src, uint16_t len) {
|
||||
#ifdef DEBUG_USB
|
||||
print("writing ");
|
||||
hexdump(src, len);
|
||||
#endif
|
||||
|
||||
uint16_t wplen = MIN(len, 0x40);
|
||||
USB_WritePacket(src, wplen, 0);
|
||||
|
||||
if (wplen < len) {
|
||||
ep0_txdata = &src[wplen];
|
||||
ep0_txlen = len - wplen;
|
||||
USBx_DEVICE->DIEPEMPMSK |= 1;
|
||||
} else {
|
||||
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_reset(void) {
|
||||
// unmask endpoint interrupts, so many sets
|
||||
USBx_DEVICE->DAINT = 0xFFFFFFFFU;
|
||||
USBx_DEVICE->DAINTMSK = 0xFFFFFFFFU;
|
||||
//USBx_DEVICE->DOEPMSK = (USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_EPDM);
|
||||
//USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM | USB_OTG_DIEPMSK_ITTXFEMSK);
|
||||
//USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM);
|
||||
|
||||
// all interrupts for debugging
|
||||
USBx_DEVICE->DIEPMSK = 0xFFFFFFFFU;
|
||||
USBx_DEVICE->DOEPMSK = 0xFFFFFFFFU;
|
||||
|
||||
// clear interrupts
|
||||
USBx_INEP(0U)->DIEPINT = 0xFF;
|
||||
USBx_OUTEP(0U)->DOEPINT = 0xFF;
|
||||
|
||||
// unset the address
|
||||
USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD;
|
||||
|
||||
// set up USB FIFOs
|
||||
// RX start address is fixed to 0
|
||||
USBx->GRXFSIZ = 0x40;
|
||||
|
||||
// 0x100 to offset past GRXFSIZ
|
||||
USBx->DIEPTXF0_HNPTXFSIZ = (0x40UL << 16) | 0x40U;
|
||||
|
||||
// EP1, massive
|
||||
USBx->DIEPTXF[0] = (0x40UL << 16) | 0x80U;
|
||||
|
||||
// flush TX fifo
|
||||
USBx->GRSTCTL = USB_OTG_GRSTCTL_TXFFLSH | USB_OTG_GRSTCTL_TXFNUM_4;
|
||||
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH);
|
||||
// flush RX FIFO
|
||||
USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH;
|
||||
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH);
|
||||
|
||||
// no global NAK
|
||||
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK;
|
||||
|
||||
// ready to receive setup packets
|
||||
USBx_OUTEP(0U)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (3U << 3);
|
||||
}
|
||||
|
||||
char to_hex_char(uint8_t a) {
|
||||
char ret;
|
||||
if (a < 10U) {
|
||||
ret = '0' + a;
|
||||
} else {
|
||||
ret = 'a' + (a - 10U);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usb_tick(void) {
|
||||
uint16_t current_frame_num = (USBx_DEVICE->DSTS & USB_OTG_DSTS_FNSOF_Msk) >> USB_OTG_DSTS_FNSOF_Pos;
|
||||
usb_enumerated = (current_frame_num != usb_last_frame_num);
|
||||
usb_last_frame_num = current_frame_num;
|
||||
}
|
||||
|
||||
void usb_setup(void) {
|
||||
int resp_len;
|
||||
ControlPacket_t control_req;
|
||||
|
||||
|
@ -639,7 +525,7 @@ void usb_setup(void) {
|
|||
|
||||
void usb_irqhandler(void) {
|
||||
//USBx->GINTMSK = 0;
|
||||
|
||||
static uint8_t usbdata[0x100] __attribute__((aligned(4)));
|
||||
unsigned int gintsts = USBx->GINTSTS;
|
||||
unsigned int gotgint = USBx->GOTGINT;
|
||||
unsigned int daint = USBx_DEVICE->DAINT;
|
||||
|
@ -914,11 +800,3 @@ void can_tx_comms_resume_usb(void) {
|
|||
}
|
||||
EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
void usb_soft_disconnect(bool enable) {
|
||||
if (enable) {
|
||||
USBx_DEVICE->DCTL |= USB_OTG_DCTL_SDIS;
|
||||
} else {
|
||||
USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_SDIS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
#pragma once
|
||||
|
||||
// IRQs: OTG_FS
|
||||
|
||||
typedef union {
|
||||
uint16_t w;
|
||||
struct BW {
|
||||
uint8_t msb;
|
||||
uint8_t lsb;
|
||||
}
|
||||
bw;
|
||||
} uint16_t_uint8_t;
|
||||
|
||||
typedef union _USB_Setup {
|
||||
uint32_t d8[2];
|
||||
struct _SetupPkt_Struc
|
||||
{
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t_uint8_t wValue;
|
||||
uint16_t_uint8_t wIndex;
|
||||
uint16_t_uint8_t wLength;
|
||||
} b;
|
||||
} USB_Setup_TypeDef;
|
||||
|
||||
extern bool usb_enumerated;
|
||||
|
||||
void usb_init(void);
|
||||
void refresh_can_tx_slots_available(void);
|
||||
|
||||
// **** supporting defines ****
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
|
||||
#define USB_DESC_TYPE_DEVICE 0x01
|
||||
#define USB_DESC_TYPE_CONFIGURATION 0x02
|
||||
#define USB_DESC_TYPE_STRING 0x03
|
||||
#define USB_DESC_TYPE_INTERFACE 0x04
|
||||
#define USB_DESC_TYPE_ENDPOINT 0x05
|
||||
#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06
|
||||
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07
|
||||
#define USB_DESC_TYPE_BINARY_OBJECT_STORE 0x0f
|
||||
|
||||
// offsets for configuration strings
|
||||
#define STRING_OFFSET_LANGID 0x00
|
||||
#define STRING_OFFSET_IMANUFACTURER 0x01
|
||||
#define STRING_OFFSET_IPRODUCT 0x02
|
||||
#define STRING_OFFSET_ISERIAL 0x03
|
||||
#define STRING_OFFSET_ICONFIGURATION 0x04
|
||||
#define STRING_OFFSET_IINTERFACE 0x05
|
||||
|
||||
// WebUSB requests
|
||||
#define WEBUSB_REQ_GET_URL 0x02
|
||||
|
||||
// WebUSB types
|
||||
#define WEBUSB_DESC_TYPE_URL 0x03
|
||||
#define WEBUSB_URL_SCHEME_HTTPS 0x01
|
||||
#define WEBUSB_URL_SCHEME_HTTP 0x00
|
||||
|
||||
// WinUSB requests
|
||||
#define WINUSB_REQ_GET_COMPATID_DESCRIPTOR 0x04
|
||||
#define WINUSB_REQ_GET_EXT_PROPS_OS 0x05
|
||||
#define WINUSB_REQ_GET_DESCRIPTOR 0x07
|
||||
|
||||
#define STS_GOUT_NAK 1
|
||||
#define STS_DATA_UPDT 2
|
||||
#define STS_XFER_COMP 3
|
||||
#define STS_SETUP_COMP 4
|
||||
#define STS_SETUP_UPDT 6
|
||||
|
||||
// for the repeating interfaces
|
||||
#define DSCR_INTERFACE_LEN 9
|
||||
#define DSCR_ENDPOINT_LEN 7
|
||||
#define DSCR_CONFIG_LEN 9
|
||||
#define DSCR_DEVICE_LEN 18
|
||||
|
||||
// endpoint types
|
||||
#define ENDPOINT_TYPE_CONTROL 0
|
||||
#define ENDPOINT_TYPE_ISO 1
|
||||
#define ENDPOINT_TYPE_BULK 2
|
||||
#define ENDPOINT_TYPE_INT 3
|
||||
|
||||
// These are arbitrary values used in bRequest
|
||||
#define MS_VENDOR_CODE 0x20
|
||||
#define WEBUSB_VENDOR_CODE 0x30
|
||||
|
||||
// BOS constants
|
||||
#define BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH 0x05
|
||||
#define BINARY_OBJECT_STORE_DESCRIPTOR 0x0F
|
||||
#define WINUSB_PLATFORM_DESCRIPTOR_LENGTH 0x9E
|
||||
|
||||
// Convert machine byte order to USB byte order
|
||||
#define TOUSBORDER(num)\
|
||||
((num) & 0xFFU), (((uint16_t)(num) >> 8) & 0xFFU)
|
||||
|
||||
// take in string length and return the first 2 bytes of a string descriptor
|
||||
#define STRING_DESCRIPTOR_HEADER(size)\
|
||||
(((((size) * 2) + 2) & 0xFF) | 0x0300)
|
||||
|
||||
#define ENDPOINT_RCV 0x80
|
||||
#define ENDPOINT_SND 0x00
|
||||
|
||||
// packet read and write
|
||||
void usb_tick(void);
|
||||
// ***************************** USB port *****************************
|
||||
void can_tx_comms_resume_usb(void);
|
|
@ -3,7 +3,7 @@ typedef enum {
|
|||
WATCHDOG_500_MS = 4000U,
|
||||
} WatchdogTimeout;
|
||||
|
||||
void watchdog_feed(void) {
|
||||
static void watchdog_feed(void) {
|
||||
IND_WDG->KR = 0xAAAAU;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
static bool spi_tx_dma_done = false;
|
||||
|
||||
// master -> panda DMA start
|
||||
void llspi_mosi_dma(uint8_t *addr, int len) {
|
||||
// disable DMA + SPI
|
||||
|
|
Loading…
Reference in New Issue