mirror of
https://jihulab.com/mr-one/openpilot.git
synced 2026-10-27 04:53:44 +08:00
test: use pristine upstream panda SPI firmware (stage 2d)
This commit is contained in:
@@ -25,7 +25,6 @@ typedef struct {
|
||||
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_auto;
|
||||
@@ -71,11 +70,7 @@ extern bus_config_t bus_config[PANDA_CAN_CNT];
|
||||
|
||||
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
|
||||
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);
|
||||
@@ -92,7 +87,6 @@ struct fan_state_t {
|
||||
uint16_t tach_counter;
|
||||
uint16_t rpm;
|
||||
uint8_t power;
|
||||
float error_integral;
|
||||
uint8_t cooldown_counter;
|
||||
};
|
||||
extern struct fan_state_t fan_state;
|
||||
@@ -118,7 +112,6 @@ extern FDCAN_GlobalTypeDef *cans[PANDA_CAN_CNT];
|
||||
void can_clear_send(FDCAN_GlobalTypeDef *FDCANx, uint8_t can_number);
|
||||
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg);
|
||||
|
||||
void can_rx(uint8_t can_number);
|
||||
|
||||
// ******************** harness ********************
|
||||
|
||||
@@ -157,7 +150,6 @@ void harness_init(void);
|
||||
// ******************** interrupts ********************
|
||||
|
||||
typedef struct interrupt {
|
||||
IRQn_Type irq_type;
|
||||
void (*handler)(void);
|
||||
uint32_t call_counter;
|
||||
uint32_t call_rate;
|
||||
@@ -167,12 +159,10 @@ typedef struct 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; \
|
||||
@@ -232,48 +222,12 @@ extern uint16_t spi_error_count;
|
||||
void can_tx_comms_resume_spi(void);
|
||||
void spi_init(void);
|
||||
|
||||
// ******************** uart ********************
|
||||
#ifdef STM32H7
|
||||
|
||||
// ***************************** 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);
|
||||
// ******************** debug ********************
|
||||
bool debug_get_char(char *elem);
|
||||
void print(const char *a);
|
||||
void puthx(uint32_t i, uint8_t len);
|
||||
void puth(unsigned int i);
|
||||
#if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG)
|
||||
static void puth4(unsigned int i);
|
||||
#endif
|
||||
#if defined(DEBUG_SPI) || defined(DEBUG_USB) || defined(DEBUG_COMMS)
|
||||
static void hexdump(const void *a, int l);
|
||||
#endif
|
||||
|
||||
#endif // STM32H7
|
||||
static inline void puth4(unsigned int i);
|
||||
|
||||
// ******************** usb ********************
|
||||
|
||||
|
||||
+3
-162
@@ -188,168 +188,9 @@ void spi_init(void) {
|
||||
crc32_init();
|
||||
llspi_init();
|
||||
|
||||
// Start the first packet!
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
}
|
||||
|
||||
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++){
|
||||
checksum ^= data[i];
|
||||
}
|
||||
return checksum == 0U;
|
||||
}
|
||||
|
||||
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];
|
||||
spi_data_len_mosi = (spi_buf_rx[3] << 8) | spi_buf_rx[2];
|
||||
spi_data_len_miso = (spi_buf_rx[5] << 8) | spi_buf_rx[4];
|
||||
|
||||
if (memcmp(spi_buf_rx, version_text, 7) == 0) {
|
||||
response_len = spi_version_packet(spi_buf_tx);
|
||||
next_rx_state = SPI_STATE_HEADER_NACK;;
|
||||
} else if (spi_state == SPI_STATE_HEADER) {
|
||||
checksum_valid = validate_checksum(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
if ((spi_buf_rx[0] == SPI_SYNC_BYTE) && checksum_valid) {
|
||||
// response: ACK and start receiving data portion
|
||||
spi_buf_tx[0] = SPI_HACK;
|
||||
next_rx_state = SPI_STATE_HEADER_ACK;
|
||||
response_len = 1U;
|
||||
} else {
|
||||
// response: NACK and reset state machine
|
||||
#ifdef DEBUG_SPI
|
||||
print("- incorrect header sync or checksum "); hexdump(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
#endif
|
||||
spi_buf_tx[0] = SPI_NACK;
|
||||
next_rx_state = SPI_STATE_HEADER_NACK;
|
||||
response_len = 1U;
|
||||
}
|
||||
} else if (spi_state == SPI_STATE_DATA_RX) {
|
||||
// We got everything! Based on the endpoint specified, call the appropriate handler
|
||||
bool response_ack = false;
|
||||
checksum_valid = validate_checksum(&(spi_buf_rx[SPI_HEADER_SIZE]), spi_data_len_mosi + 1U);
|
||||
if (checksum_valid) {
|
||||
if (spi_endpoint == 0U) {
|
||||
if (spi_data_len_mosi >= sizeof(ControlPacket_t)) {
|
||||
ControlPacket_t ctrl = {0};
|
||||
(void)memcpy((uint8_t*)&ctrl, &spi_buf_rx[SPI_HEADER_SIZE], sizeof(ControlPacket_t));
|
||||
response_len = comms_control_handler(&ctrl, &spi_buf_tx[3]);
|
||||
response_ack = true;
|
||||
} else {
|
||||
print("SPI: insufficient data for control handler\n");
|
||||
}
|
||||
} else if ((spi_endpoint == 1U) || (spi_endpoint == 0x81U)) {
|
||||
if (spi_data_len_mosi == 0U) {
|
||||
response_len = comms_can_read(&(spi_buf_tx[3]), spi_data_len_miso);
|
||||
response_ack = true;
|
||||
} else {
|
||||
print("SPI: did not expect data for can_read\n");
|
||||
}
|
||||
} else if (spi_endpoint == 2U) {
|
||||
comms_endpoint2_write(&spi_buf_rx[SPI_HEADER_SIZE], spi_data_len_mosi);
|
||||
response_ack = true;
|
||||
} else if (spi_endpoint == 3U) {
|
||||
if (spi_data_len_mosi > 0U) {
|
||||
if (spi_can_tx_ready) {
|
||||
spi_can_tx_ready = false;
|
||||
comms_can_write(&spi_buf_rx[SPI_HEADER_SIZE], spi_data_len_mosi);
|
||||
response_ack = true;
|
||||
} else {
|
||||
response_ack = false;
|
||||
print("SPI: CAN NACK\n");
|
||||
}
|
||||
} else {
|
||||
print("SPI: did expect data for can_write\n");
|
||||
}
|
||||
} else if (spi_endpoint == 0xABU) {
|
||||
// test endpoint: mimics panda -> device transfer
|
||||
response_len = spi_data_len_miso;
|
||||
response_ack = true;
|
||||
} else if (spi_endpoint == 0xACU) {
|
||||
// test endpoint: mimics device -> panda transfer (with NACK)
|
||||
response_ack = false;
|
||||
} else {
|
||||
print("SPI: unexpected endpoint"); puth(spi_endpoint); print("\n");
|
||||
}
|
||||
} else {
|
||||
// Checksum was incorrect
|
||||
response_ack = false;
|
||||
#ifdef DEBUG_SPI
|
||||
print("- incorrect data checksum ");
|
||||
puth4(spi_data_len_mosi);
|
||||
print("\n");
|
||||
hexdump(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
hexdump(&(spi_buf_rx[SPI_HEADER_SIZE]), MIN(spi_data_len_mosi, 64));
|
||||
print("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!response_ack) {
|
||||
spi_buf_tx[0] = SPI_NACK;
|
||||
next_rx_state = SPI_STATE_HEADER_NACK;
|
||||
response_len = 1U;
|
||||
} else {
|
||||
// Setup response header
|
||||
spi_buf_tx[0] = SPI_DACK;
|
||||
spi_buf_tx[1] = response_len & 0xFFU;
|
||||
spi_buf_tx[2] = (response_len >> 8) & 0xFFU;
|
||||
|
||||
// Add checksum
|
||||
uint8_t checksum = SPI_CHECKSUM_START;
|
||||
for(uint16_t i = 0U; i < (response_len + 3U); i++) {
|
||||
checksum ^= spi_buf_tx[i];
|
||||
}
|
||||
spi_buf_tx[response_len + 3U] = checksum;
|
||||
response_len += 4U;
|
||||
|
||||
next_rx_state = SPI_STATE_DATA_TX;
|
||||
}
|
||||
} else {
|
||||
print("SPI: RX unexpected state: "); puth(spi_state); print("\n");
|
||||
}
|
||||
|
||||
// send out response
|
||||
if (response_len == 0U) {
|
||||
print("SPI: no response\n");
|
||||
spi_buf_tx[0] = SPI_NACK;
|
||||
spi_state = SPI_STATE_HEADER_NACK;
|
||||
response_len = 1U;
|
||||
}
|
||||
llspi_miso_dma(spi_buf_tx, response_len);
|
||||
|
||||
spi_state = next_rx_state;
|
||||
if (!checksum_valid) {
|
||||
spi_error_count += 1U;
|
||||
}
|
||||
}
|
||||
|
||||
void spi_tx_done(bool reset) {
|
||||
if ((spi_state == SPI_STATE_HEADER_NACK) || reset) {
|
||||
// Reset state
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
} else if (spi_state == SPI_STATE_HEADER_ACK) {
|
||||
// ACK was sent, queue up the RX buf for the data + checksum
|
||||
spi_state = SPI_STATE_DATA_RX;
|
||||
llspi_mosi_dma(&spi_buf_rx[SPI_HEADER_SIZE], spi_data_len_mosi + 1U);
|
||||
} else if (spi_state == SPI_STATE_DATA_TX) {
|
||||
// Reset state
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
} else {
|
||||
spi_state = SPI_STATE_HEADER;
|
||||
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
|
||||
print("SPI: TX unexpected state: "); puth(spi_state); print("\n");
|
||||
}
|
||||
// kick off the first read
|
||||
spi_buf_ready[0] = SPI_SLAVE_READY;
|
||||
llspi_queue(spi_buf_ready, 1U);
|
||||
}
|
||||
|
||||
void can_tx_comms_resume_spi(void) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
// Early bringup
|
||||
#define ENTER_BOOTLOADER_MAGIC 0xdeadbeefU
|
||||
#define ENTER_SOFTLOADER_MAGIC 0xdeadc0deU
|
||||
@@ -57,7 +59,6 @@ void early_initialization(void) {
|
||||
|
||||
if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) {
|
||||
led_init();
|
||||
current_board->init_bootloader();
|
||||
led_set(LED_GREEN, 1);
|
||||
jump_to_bootloader();
|
||||
}
|
||||
|
||||
+19
-53
@@ -25,16 +25,6 @@
|
||||
#include "board/can_comms.h"
|
||||
#include "board/main_comms.h"
|
||||
|
||||
|
||||
// ********************* Serial debugging *********************
|
||||
|
||||
void debug_ring_callback(uart_ring *ring) {
|
||||
char rcv;
|
||||
while (get_char(ring, &rcv)) {
|
||||
(void)put_char(ring, rcv); // misra-c2012-17.7: cast to void is ok: debug function
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************** safety mode ******************************
|
||||
|
||||
// this is the only way to leave silent mode
|
||||
@@ -114,13 +104,12 @@ static void __attribute__ ((noinline)) enable_fpu(void) {
|
||||
|
||||
// called at 8Hz
|
||||
static void tick_handler(void) {
|
||||
static uint32_t siren_countdown = 0; // siren plays while countdown > 0
|
||||
static uint32_t controls_allowed_countdown = 0;
|
||||
static uint8_t prev_harness_status = HARNESS_STATUS_NC;
|
||||
static uint8_t loop_counter = 0U;
|
||||
static bool relay_malfunction_prev = false;
|
||||
|
||||
if (TICK_TIMER->SR != 0U) {
|
||||
static uint32_t siren_countdown = 0; // siren plays while countdown > 0
|
||||
static uint32_t controls_allowed_countdown = 0;
|
||||
static uint8_t prev_harness_status = HARNESS_STATUS_NC;
|
||||
static uint8_t loop_counter = 0U;
|
||||
static bool relay_malfunction_prev = false;
|
||||
|
||||
heartbeat_tick_counter += 1U;
|
||||
|
||||
@@ -160,15 +149,6 @@ static void tick_handler(void) {
|
||||
|
||||
// decimated to 1Hz
|
||||
if (loop_counter == 0U) {
|
||||
//puth(usart1_dma); print(" "); puth(DMA2_Stream5->M0AR); print(" "); puth(DMA2_Stream5->NDTR); print("\n");
|
||||
#ifdef DEBUG
|
||||
print("** blink ");
|
||||
print("rx:"); puth4(can_rx_q.r_ptr); print("-"); puth4(can_rx_q.w_ptr); print(" ");
|
||||
print("tx1:"); puth4(can_tx1_q.r_ptr); print("-"); puth4(can_tx1_q.w_ptr); print(" ");
|
||||
print("tx2:"); puth4(can_tx2_q.r_ptr); print("-"); puth4(can_tx2_q.w_ptr); print(" ");
|
||||
print("tx3:"); puth4(can_tx3_q.r_ptr); print("-"); puth4(can_tx3_q.w_ptr); print("\n");
|
||||
#endif
|
||||
|
||||
// set green LED to be controls allowed
|
||||
led_set(LED_GREEN, controls_allowed);
|
||||
|
||||
@@ -302,6 +282,7 @@ int main(void) {
|
||||
|
||||
print("Config:\n");
|
||||
print(" Board type: 0x"); puth(hw_type); print("\n");
|
||||
print(" MCU UID: "); hexdump((const uint8_t *)UID_BASE, 12);
|
||||
|
||||
// init board
|
||||
current_board->init();
|
||||
@@ -331,9 +312,6 @@ int main(void) {
|
||||
REGISTER_INTERRUPT(TICK_TIMER_IRQ, tick_handler, 10U, FAULT_INTERRUPT_RATE_TICK)
|
||||
tick_timer_init();
|
||||
|
||||
#ifdef DEBUG
|
||||
print("DEBUG ENABLED\n");
|
||||
#endif
|
||||
// enable USB (right before interrupts or enum can fail!)
|
||||
usb_init();
|
||||
|
||||
@@ -365,32 +343,20 @@ int main(void) {
|
||||
}
|
||||
#endif
|
||||
if (!power_save_enabled) {
|
||||
#ifdef DEBUG_FAULTS
|
||||
if (fault_status == FAULT_STATUS_NONE) {
|
||||
#endif
|
||||
// useful for debugging, fade breaks = panda is overloaded
|
||||
for (uint32_t fade = 0U; fade < MAX_LED_FADE; fade += 1U) {
|
||||
led_set(LED_RED, true);
|
||||
delay(fade >> 4);
|
||||
led_set(LED_RED, false);
|
||||
delay((MAX_LED_FADE - fade) >> 4);
|
||||
}
|
||||
// useful for debugging, fade breaks = panda is overloaded
|
||||
for (uint32_t fade = 0U; fade < MAX_LED_FADE; fade += 1U) {
|
||||
led_set(LED_RED, true);
|
||||
delay(fade >> 4);
|
||||
led_set(LED_RED, false);
|
||||
delay((MAX_LED_FADE - fade) >> 4);
|
||||
}
|
||||
|
||||
for (uint32_t fade = MAX_LED_FADE; fade > 0U; fade -= 1U) {
|
||||
led_set(LED_RED, true);
|
||||
delay(fade >> 4);
|
||||
led_set(LED_RED, false);
|
||||
delay((MAX_LED_FADE - fade) >> 4);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FAULTS
|
||||
} else {
|
||||
led_set(LED_RED, 1);
|
||||
delay(512000U);
|
||||
led_set(LED_RED, 0);
|
||||
delay(512000U);
|
||||
}
|
||||
#endif
|
||||
for (uint32_t fade = MAX_LED_FADE; fade > 0U; fade -= 1U) {
|
||||
led_set(LED_RED, true);
|
||||
delay(fade >> 4);
|
||||
led_set(LED_RED, false);
|
||||
delay((MAX_LED_FADE - fade) >> 4);
|
||||
}
|
||||
} else {
|
||||
if ((hw_type == HW_TYPE_CUATRO) && !current_board->read_som_gpio()) {
|
||||
assert_fatal(current_safety_mode == SAFETY_SILENT, "Error: Entering low power mode while not in SAFETY_SILENT. Hanging\n");
|
||||
|
||||
+11
-33
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used
|
||||
|
||||
// Prototypes
|
||||
@@ -54,32 +56,16 @@ static int get_health_pkt(void *dat) {
|
||||
return sizeof(*health);
|
||||
}
|
||||
|
||||
// send on serial, first byte to select the ring
|
||||
// Endpoint 2 is only used by the bootstub for flashing.
|
||||
void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
|
||||
uart_ring *ur = get_ring_by_number(data[0]);
|
||||
if ((len != 0U) && (ur != NULL)) {
|
||||
if ((data[0] < 2U) || (data[0] >= 4U)) {
|
||||
for (uint32_t i = 1; i < len; i++) {
|
||||
while (!put_char(ur, data[i])) {
|
||||
// wait
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UNUSED(data);
|
||||
UNUSED(len);
|
||||
}
|
||||
|
||||
int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
||||
unsigned int resp_len = 0;
|
||||
uart_ring *ur = NULL;
|
||||
uint32_t time;
|
||||
|
||||
#ifdef DEBUG_COMMS
|
||||
print("raw control request: "); hexdump(req, sizeof(ControlPacket_t)); print("\n");
|
||||
print("- request "); puth(req->request); print("\n");
|
||||
print("- param1 "); puth(req->param1); print("\n");
|
||||
print("- param2 "); puth(req->param2); print("\n");
|
||||
#endif
|
||||
|
||||
switch (req->request) {
|
||||
// **** 0xa8: get microsecond timer
|
||||
case 0xa8:
|
||||
@@ -112,6 +98,12 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
||||
stop_mode_requested = true;
|
||||
break;
|
||||
#endif
|
||||
// **** 0xb6: read debug logs
|
||||
case 0xb6:
|
||||
while ((resp_len < req->length) && (resp_len < USBPACKET_MAX_SIZE) && debug_get_char((char*)&resp[resp_len])) {
|
||||
++resp_len;
|
||||
}
|
||||
break;
|
||||
// **** 0xc0: reset communications state
|
||||
case 0xc0:
|
||||
comms_can_reset();
|
||||
@@ -257,20 +249,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
||||
mads_set_alternative_experience(&alternative_experience);
|
||||
}
|
||||
break;
|
||||
// **** 0xe0: uart read
|
||||
case 0xe0:
|
||||
ur = get_ring_by_number(req->param1);
|
||||
if (!ur) {
|
||||
break;
|
||||
}
|
||||
|
||||
// read
|
||||
uint16_t req_length = MIN(req->length, USBPACKET_MAX_SIZE);
|
||||
while ((resp_len < req_length) &&
|
||||
get_char(ur, (char*)&resp[resp_len])) {
|
||||
++resp_len;
|
||||
}
|
||||
break;
|
||||
// **** 0xe5: set CAN loopback (for testing)
|
||||
case 0xe5:
|
||||
can_loopback = req->param1 > 0U;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "main_declarations.h"
|
||||
|
||||
// ********************* Globals **********************
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
// master -> panda DMA start
|
||||
// cppcheck-suppress constParameterPointer ; RX DMA writes through addr after return
|
||||
void llspi_mosi_dma(uint8_t *addr, int len) {
|
||||
// disable DMA + SPI
|
||||
register_clear_bits(&(SPI4->CFG1), SPI_CFG1_RXDMAEN);
|
||||
DMA2_Stream2->CR &= ~DMA_SxCR_EN;
|
||||
register_clear_bits(&(SPI4->CR1), SPI_CR1_SPE);
|
||||
#pragma once
|
||||
|
||||
// SPI4 NSS (chip select) is PE11
|
||||
#define SPI_CS_PIN 11U
|
||||
|
||||
void spi_cs_rising(void);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define SOUND_RX_BUF_SIZE 1000U
|
||||
#define SOUND_TX_BUF_SIZE (SOUND_RX_BUF_SIZE/2U)
|
||||
#define MIC_RX_BUF_SIZE 512U
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "board/sys/sys.h"
|
||||
|
||||
// WARNING: To stay in compliance with the SIL2 rules laid out in STM UM2331, we should never use any of the available hardware low power modes during safety function execution.
|
||||
|
||||
@@ -121,8 +121,6 @@ ensure_health_packet_version = partial(ensure_version, "health", "HEALTH_PACKET_
|
||||
|
||||
class Panda:
|
||||
|
||||
SERIAL_DEBUG = 0
|
||||
SERIAL_SOM_DEBUG = 4
|
||||
|
||||
USB_VIDS = (0xbbaa, 0x3801) # 0x3801 is comma's registered VID
|
||||
USB_PIDS = (0xddee, 0xddcc)
|
||||
@@ -697,16 +695,6 @@ class Panda:
|
||||
def set_canfd_auto(self, bus, auto):
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe8, bus, int(auto), b'')
|
||||
|
||||
def set_uart_baud(self, uart, rate):
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe4, uart, int(rate / 300), b'')
|
||||
|
||||
def set_uart_parity(self, uart, parity):
|
||||
# parity, 0=off, 1=even, 2=odd
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe2, uart, parity, b'')
|
||||
|
||||
def set_uart_callback(self, uart, install):
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe3, uart, int(install), b'')
|
||||
|
||||
# ******************* can *******************
|
||||
|
||||
# The panda will NAK CAN writes when there is CAN congestion.
|
||||
@@ -752,24 +740,15 @@ class Panda:
|
||||
"""
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf1, bus, 0, b'')
|
||||
|
||||
# ******************* serial *******************
|
||||
|
||||
def serial_read(self, port_number, maxlen=1024):
|
||||
ret = b''
|
||||
while 1:
|
||||
r = bytes(self._handle.controlRead(Panda.REQUEST_IN, 0xe0, port_number, 0, 0x40))
|
||||
if len(r) == 0 or len(ret) >= maxlen:
|
||||
def debug_read(self, maxlen=1024):
|
||||
"""Read up to maxlen bytes of internal debug logs."""
|
||||
ret = bytearray()
|
||||
while len(ret) < maxlen:
|
||||
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xb6, 0, 0, min(0x40, maxlen - len(ret)))
|
||||
if not dat:
|
||||
break
|
||||
ret += r
|
||||
return ret
|
||||
|
||||
def serial_write(self, port_number, ln):
|
||||
ret = 0
|
||||
if isinstance(ln, str):
|
||||
ln = bytes(ln, 'utf-8')
|
||||
for i in range(0, len(ln), 0x20):
|
||||
ret += self._handle.bulkWrite(2, struct.pack("B", port_number) + ln[i:i + 0x20])
|
||||
return ret
|
||||
ret.extend(dat)
|
||||
return bytes(ret)
|
||||
|
||||
def send_heartbeat(self, engaged=True):
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf3, engaged, 0, b'')
|
||||
|
||||
+83
-36
@@ -1,4 +1,5 @@
|
||||
import binascii
|
||||
import ctypes
|
||||
import os
|
||||
import math
|
||||
import time
|
||||
@@ -11,24 +12,11 @@ from .base import BaseHandle, BaseSTBootloaderHandle, TIMEOUT
|
||||
from .constants import McuType, MCU_TYPE_BY_IDCODE
|
||||
from .utils import logger
|
||||
|
||||
# No fcntl on Windows
|
||||
try:
|
||||
import fcntl
|
||||
except ImportError:
|
||||
fcntl = None # type: ignore
|
||||
|
||||
# No spidev on MacOS/Windows
|
||||
try:
|
||||
import spidev
|
||||
except ImportError:
|
||||
spidev = None
|
||||
|
||||
# Constants
|
||||
SYNC = 0x5A
|
||||
HACK = 0x79
|
||||
DACK = 0x85
|
||||
NACK = 0x1F
|
||||
CHECKSUM_START = 0xAB
|
||||
# Protocol, see board/drivers/spi.h
|
||||
SLAVE_READY = 0x3C
|
||||
ACK = 0xC3
|
||||
NACK = 0x5A
|
||||
INFO_ENDPOINT = 0xF0
|
||||
|
||||
REQ_HEADER = struct.Struct("<BIHH") # endpoint, id, tx_len, rx_len
|
||||
RESP_HEADER = struct.Struct("<BIH") # status, id, len
|
||||
@@ -66,40 +54,99 @@ class PandaSpiMissingAck(PandaSpiException):
|
||||
SPI_LOCK = threading.Lock()
|
||||
SPI_DEVICES = {}
|
||||
class SpiDevice:
|
||||
"""
|
||||
Provides locked, thread-safe access to a panda's SPI interface.
|
||||
"""Provides locked, thread-safe access to a panda's SPI interface.
|
||||
|
||||
xfer2 returns a view valid until the next transfer; xfer returns an owned copy.
|
||||
"""
|
||||
|
||||
MAX_SPEED = 50000000 # max of the SDM845
|
||||
|
||||
def __init__(self, speed=MAX_SPEED):
|
||||
assert speed <= self.MAX_SPEED
|
||||
# Linux asm-generic ioctl ABI (including aarch64 and x86_64), linux/spi/spidev.h.
|
||||
SPI_IOC_RD_BITS_PER_WORD = 0x80016B03
|
||||
SPI_IOC_WR_MAX_SPEED_HZ = 0x40046B04
|
||||
SPI_IOC_MESSAGE_1 = 0x40206B00
|
||||
SPI_IOC_TRANSFER = struct.Struct('=QQIIHBBBBBB')
|
||||
MAX_TRANSFER_SIZE = 4096
|
||||
|
||||
def __init__(self, speed=MAX_SPEED):
|
||||
try:
|
||||
import fcntl
|
||||
except ImportError as e:
|
||||
raise PandaSpiUnavailable("SPI requires Linux") from e
|
||||
|
||||
assert speed <= self.MAX_SPEED
|
||||
if not os.path.exists(DEV_PATH):
|
||||
raise PandaSpiUnavailable(f"SPI device not found: {DEV_PATH}")
|
||||
if spidev is None:
|
||||
raise PandaSpiUnavailable("spidev is not installed")
|
||||
|
||||
self._ioctl = fcntl.ioctl
|
||||
self._flock = fcntl.flock
|
||||
self._lock_ex, self._lock_un = fcntl.LOCK_EX, fcntl.LOCK_UN
|
||||
with SPI_LOCK:
|
||||
if speed not in SPI_DEVICES:
|
||||
SPI_DEVICES[speed] = spidev.SpiDev()
|
||||
SPI_DEVICES[speed].open(0, 0)
|
||||
SPI_DEVICES[speed].max_speed_hz = speed
|
||||
self._spidev = SPI_DEVICES[speed]
|
||||
file = open(DEV_PATH, 'r+b', buffering=0)
|
||||
try:
|
||||
self._ioctl(file.fileno(), self.SPI_IOC_WR_MAX_SPEED_HZ, struct.pack('=I', speed))
|
||||
bits = self._ioctl(file.fileno(), self.SPI_IOC_RD_BITS_PER_WORD, b'\x00')[0]
|
||||
except BaseException:
|
||||
file.close()
|
||||
raise
|
||||
SPI_DEVICES[speed] = (file, bits)
|
||||
self._file, bits = SPI_DEVICES[speed]
|
||||
|
||||
self._fd = self._file.fileno()
|
||||
self._buffer = bytearray(self.MAX_TRANSFER_SIZE)
|
||||
self._view = memoryview(self._buffer)
|
||||
address = ctypes.addressof(ctypes.c_char.from_buffer(self._buffer))
|
||||
# The kernel supports using the same buffer for transmit and receive.
|
||||
self._transfer = bytearray(self.SPI_IOC_TRANSFER.pack(address, address, 0, speed, 0, bits, 0, 0, 0, 0, 0))
|
||||
self._transfer_words = memoryview(self._transfer).cast('I')
|
||||
|
||||
@contextmanager
|
||||
def acquire(self):
|
||||
try:
|
||||
SPI_LOCK.acquire()
|
||||
fcntl.flock(self._spidev, fcntl.LOCK_EX)
|
||||
yield self._spidev
|
||||
finally:
|
||||
fcntl.flock(self._spidev, fcntl.LOCK_UN)
|
||||
SPI_LOCK.release()
|
||||
with SPI_LOCK:
|
||||
self._flock(self._fd, self._lock_ex)
|
||||
try:
|
||||
yield self
|
||||
finally:
|
||||
self._flock(self._fd, self._lock_un)
|
||||
|
||||
def fileno(self) -> int:
|
||||
return self._fd
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
pass # Connections are shared and cached by speed.
|
||||
|
||||
@classmethod
|
||||
def _check_length(cls, length: int):
|
||||
if not 0 < length <= cls.MAX_TRANSFER_SIZE:
|
||||
raise ValueError(f"SPI transfer length must be between 1 and {cls.MAX_TRANSFER_SIZE}")
|
||||
|
||||
def xfer2(self, data) -> memoryview:
|
||||
length = len(data)
|
||||
if not 0 < length <= self.MAX_TRANSFER_SIZE:
|
||||
raise ValueError(f"SPI transfer length must be between 1 and {self.MAX_TRANSFER_SIZE}")
|
||||
self._view[:length] = bytes(data)
|
||||
self._transfer_words[4] = length # len field at byte offset 16
|
||||
if self._ioctl(self._fd, self.SPI_IOC_MESSAGE_1, self._transfer) != length:
|
||||
raise OSError("Short SPI transfer")
|
||||
return self._view[:length]
|
||||
|
||||
# Both operations use one SPI_IOC_MESSAGE(1) for the single-block calls in panda.
|
||||
def xfer(self, data) -> bytes:
|
||||
return bytes(self.xfer2(data))
|
||||
|
||||
def readbytes(self, length: int) -> bytes:
|
||||
self._check_length(length)
|
||||
data = os.read(self.fileno(), length)
|
||||
if len(data) != length:
|
||||
raise OSError("Short SPI read")
|
||||
return data
|
||||
|
||||
def writebytes(self, data):
|
||||
data = bytes(data)
|
||||
self._check_length(len(data))
|
||||
if os.write(self.fileno(), data) != len(data):
|
||||
raise OSError("Short SPI write")
|
||||
|
||||
class PandaSpiHandle(BaseHandle):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user