commit
df875819f5
105 changed files with 2447 additions and 1675 deletions
@ -1 +1 @@ |
||||
v1.5.9 |
||||
v1.6.9 |
@ -0,0 +1,23 @@ |
||||
// ********************* Critical section helpers *********************
|
||||
volatile bool interrupts_enabled = false; |
||||
|
||||
void enable_interrupts(void) { |
||||
interrupts_enabled = true; |
||||
__enable_irq(); |
||||
} |
||||
|
||||
void disable_interrupts(void) { |
||||
interrupts_enabled = false; |
||||
__disable_irq(); |
||||
} |
||||
|
||||
uint8_t global_critical_depth = 0U; |
||||
#define ENTER_CRITICAL() \ |
||||
__disable_irq(); \
|
||||
global_critical_depth += 1U; |
||||
|
||||
#define EXIT_CRITICAL() \ |
||||
global_critical_depth -= 1U; \
|
||||
if ((global_critical_depth == 0U) && interrupts_enabled) { \
|
||||
__enable_irq(); \
|
||||
} |
@ -0,0 +1,164 @@ |
||||
typedef struct interrupt { |
||||
IRQn_Type irq_type; |
||||
void (*handler)(void); |
||||
uint32_t call_counter; |
||||
uint32_t max_call_rate; // Call rate is defined as the amount of calls each second
|
||||
uint32_t call_rate_fault; |
||||
} interrupt; |
||||
|
||||
void unused_interrupt_handler(void) { |
||||
// Something is wrong if this handler is called!
|
||||
puts("Unused interrupt handler called!\n"); |
||||
fault_occurred(FAULT_UNUSED_INTERRUPT_HANDLED); |
||||
} |
||||
|
||||
#define NUM_INTERRUPTS 102U // There are 102 external interrupt sources (see stm32f413.h)
|
||||
interrupt interrupts[NUM_INTERRUPTS]; |
||||
|
||||
#define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate, rate_fault) \ |
||||
interrupts[irq_num].irq_type = irq_num; \
|
||||
interrupts[irq_num].handler = func_ptr; \
|
||||
interrupts[irq_num].call_counter = 0U; \
|
||||
interrupts[irq_num].max_call_rate = call_rate; \
|
||||
interrupts[irq_num].call_rate_fault = rate_fault; |
||||
|
||||
bool check_interrupt_rate = false; |
||||
|
||||
void handle_interrupt(IRQn_Type irq_type){ |
||||
interrupts[irq_type].call_counter++; |
||||
interrupts[irq_type].handler(); |
||||
|
||||
// Check that the interrupts don't fire too often
|
||||
if(check_interrupt_rate && (interrupts[irq_type].call_counter > interrupts[irq_type].max_call_rate)){ |
||||
puts("Interrupt 0x"); puth(irq_type); puts(" fired too often (0x"); puth(interrupts[irq_type].call_counter); puts("/s)!\n"); |
||||
fault_occurred(interrupts[irq_type].call_rate_fault); |
||||
} |
||||
} |
||||
|
||||
// Reset interrupt counter every second
|
||||
void TIM6_DAC_IRQ_Handler(void) { |
||||
if (TIM6->SR != 0) { |
||||
for(uint16_t i=0U; i<NUM_INTERRUPTS; i++){ |
||||
interrupts[i].call_counter = 0U; |
||||
} |
||||
} |
||||
TIM6->SR = 0; |
||||
} |
||||
|
||||
void init_interrupts(bool check_rate_limit){ |
||||
check_interrupt_rate = check_rate_limit; |
||||
|
||||
for(uint16_t i=0U; i<NUM_INTERRUPTS; i++){ |
||||
interrupts[i].handler = unused_interrupt_handler; |
||||
} |
||||
|
||||
// Init timer 10 for a 1s interval
|
||||
register_set_bits(&(RCC->APB1ENR), RCC_APB1ENR_TIM6EN); // Enable interrupt timer peripheral
|
||||
REGISTER_INTERRUPT(TIM6_DAC_IRQn, TIM6_DAC_IRQ_Handler, 1, FAULT_INTERRUPT_RATE_INTERRUPTS) |
||||
register_set(&(TIM6->PSC), (732-1), 0xFFFFU); |
||||
register_set(&(TIM6->DIER), TIM_DIER_UIE, 0x5F5FU); |
||||
register_set(&(TIM6->CR1), TIM_CR1_CEN, 0x3FU); |
||||
TIM6->SR = 0; |
||||
NVIC_EnableIRQ(TIM6_DAC_IRQn); |
||||
} |
||||
|
||||
// ********************* Bare interrupt handlers *********************
|
||||
// Only implemented the STM32F413 interrupts for now, the STM32F203 specific ones do not fall into the scope of SIL2
|
||||
|
||||
void WWDG_IRQHandler(void) {handle_interrupt(WWDG_IRQn);} |
||||
void PVD_IRQHandler(void) {handle_interrupt(PVD_IRQn);} |
||||
void TAMP_STAMP_IRQHandler(void) {handle_interrupt(TAMP_STAMP_IRQn);} |
||||
void RTC_WKUP_IRQHandler(void) {handle_interrupt(RTC_WKUP_IRQn);} |
||||
void FLASH_IRQHandler(void) {handle_interrupt(FLASH_IRQn);} |
||||
void RCC_IRQHandler(void) {handle_interrupt(RCC_IRQn);} |
||||
void EXTI0_IRQHandler(void) {handle_interrupt(EXTI0_IRQn);} |
||||
void EXTI1_IRQHandler(void) {handle_interrupt(EXTI1_IRQn);} |
||||
void EXTI2_IRQHandler(void) {handle_interrupt(EXTI2_IRQn);} |
||||
void EXTI3_IRQHandler(void) {handle_interrupt(EXTI3_IRQn);} |
||||
void EXTI4_IRQHandler(void) {handle_interrupt(EXTI4_IRQn);} |
||||
void DMA1_Stream0_IRQHandler(void) {handle_interrupt(DMA1_Stream0_IRQn);} |
||||
void DMA1_Stream1_IRQHandler(void) {handle_interrupt(DMA1_Stream1_IRQn);} |
||||
void DMA1_Stream2_IRQHandler(void) {handle_interrupt(DMA1_Stream2_IRQn);} |
||||
void DMA1_Stream3_IRQHandler(void) {handle_interrupt(DMA1_Stream3_IRQn);} |
||||
void DMA1_Stream4_IRQHandler(void) {handle_interrupt(DMA1_Stream4_IRQn);} |
||||
void DMA1_Stream5_IRQHandler(void) {handle_interrupt(DMA1_Stream5_IRQn);} |
||||
void DMA1_Stream6_IRQHandler(void) {handle_interrupt(DMA1_Stream6_IRQn);} |
||||
void ADC_IRQHandler(void) {handle_interrupt(ADC_IRQn);} |
||||
void CAN1_TX_IRQHandler(void) {handle_interrupt(CAN1_TX_IRQn);} |
||||
void CAN1_RX0_IRQHandler(void) {handle_interrupt(CAN1_RX0_IRQn);} |
||||
void CAN1_RX1_IRQHandler(void) {handle_interrupt(CAN1_RX1_IRQn);} |
||||
void CAN1_SCE_IRQHandler(void) {handle_interrupt(CAN1_SCE_IRQn);} |
||||
void EXTI9_5_IRQHandler(void) {handle_interrupt(EXTI9_5_IRQn);} |
||||
void TIM1_BRK_TIM9_IRQHandler(void) {handle_interrupt(TIM1_BRK_TIM9_IRQn);} |
||||
void TIM1_UP_TIM10_IRQHandler(void) {handle_interrupt(TIM1_UP_TIM10_IRQn);} |
||||
void TIM1_TRG_COM_TIM11_IRQHandler(void) {handle_interrupt(TIM1_TRG_COM_TIM11_IRQn);} |
||||
void TIM1_CC_IRQHandler(void) {handle_interrupt(TIM1_CC_IRQn);} |
||||
void TIM2_IRQHandler(void) {handle_interrupt(TIM2_IRQn);} |
||||
void TIM3_IRQHandler(void) {handle_interrupt(TIM3_IRQn);} |
||||
void TIM4_IRQHandler(void) {handle_interrupt(TIM4_IRQn);} |
||||
void I2C1_EV_IRQHandler(void) {handle_interrupt(I2C1_EV_IRQn);} |
||||
void I2C1_ER_IRQHandler(void) {handle_interrupt(I2C1_ER_IRQn);} |
||||
void I2C2_EV_IRQHandler(void) {handle_interrupt(I2C2_EV_IRQn);} |
||||
void I2C2_ER_IRQHandler(void) {handle_interrupt(I2C2_ER_IRQn);} |
||||
void SPI1_IRQHandler(void) {handle_interrupt(SPI1_IRQn);} |
||||
void SPI2_IRQHandler(void) {handle_interrupt(SPI2_IRQn);} |
||||
void USART1_IRQHandler(void) {handle_interrupt(USART1_IRQn);} |
||||
void USART2_IRQHandler(void) {handle_interrupt(USART2_IRQn);} |
||||
void USART3_IRQHandler(void) {handle_interrupt(USART3_IRQn);} |
||||
void EXTI15_10_IRQHandler(void) {handle_interrupt(EXTI15_10_IRQn);} |
||||
void RTC_Alarm_IRQHandler(void) {handle_interrupt(RTC_Alarm_IRQn);} |
||||
void OTG_FS_WKUP_IRQHandler(void) {handle_interrupt(OTG_FS_WKUP_IRQn);} |
||||
void TIM8_BRK_TIM12_IRQHandler(void) {handle_interrupt(TIM8_BRK_TIM12_IRQn);} |
||||
void TIM8_UP_TIM13_IRQHandler(void) {handle_interrupt(TIM8_UP_TIM13_IRQn);} |
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void) {handle_interrupt(TIM8_TRG_COM_TIM14_IRQn);} |
||||
void TIM8_CC_IRQHandler(void) {handle_interrupt(TIM8_CC_IRQn);} |
||||
void DMA1_Stream7_IRQHandler(void) {handle_interrupt(DMA1_Stream7_IRQn);} |
||||
void FSMC_IRQHandler(void) {handle_interrupt(FSMC_IRQn);} |
||||
void SDIO_IRQHandler(void) {handle_interrupt(SDIO_IRQn);} |
||||
void TIM5_IRQHandler(void) {handle_interrupt(TIM5_IRQn);} |
||||
void SPI3_IRQHandler(void) {handle_interrupt(SPI3_IRQn);} |
||||
void UART4_IRQHandler(void) {handle_interrupt(UART4_IRQn);} |
||||
void UART5_IRQHandler(void) {handle_interrupt(UART5_IRQn);} |
||||
void TIM6_DAC_IRQHandler(void) {handle_interrupt(TIM6_DAC_IRQn);} |
||||
void TIM7_IRQHandler(void) {handle_interrupt(TIM7_IRQn);} |
||||
void DMA2_Stream0_IRQHandler(void) {handle_interrupt(DMA2_Stream0_IRQn);} |
||||
void DMA2_Stream1_IRQHandler(void) {handle_interrupt(DMA2_Stream1_IRQn);} |
||||
void DMA2_Stream2_IRQHandler(void) {handle_interrupt(DMA2_Stream2_IRQn);} |
||||
void DMA2_Stream3_IRQHandler(void) {handle_interrupt(DMA2_Stream3_IRQn);} |
||||
void DMA2_Stream4_IRQHandler(void) {handle_interrupt(DMA2_Stream4_IRQn);} |
||||
void CAN2_TX_IRQHandler(void) {handle_interrupt(CAN2_TX_IRQn);} |
||||
void CAN2_RX0_IRQHandler(void) {handle_interrupt(CAN2_RX0_IRQn);} |
||||
void CAN2_RX1_IRQHandler(void) {handle_interrupt(CAN2_RX1_IRQn);} |
||||
void CAN2_SCE_IRQHandler(void) {handle_interrupt(CAN2_SCE_IRQn);} |
||||
void OTG_FS_IRQHandler(void) {handle_interrupt(OTG_FS_IRQn);} |
||||
void DMA2_Stream5_IRQHandler(void) {handle_interrupt(DMA2_Stream5_IRQn);} |
||||
void DMA2_Stream6_IRQHandler(void) {handle_interrupt(DMA2_Stream6_IRQn);} |
||||
void DMA2_Stream7_IRQHandler(void) {handle_interrupt(DMA2_Stream7_IRQn);} |
||||
void USART6_IRQHandler(void) {handle_interrupt(USART6_IRQn);} |
||||
void I2C3_EV_IRQHandler(void) {handle_interrupt(I2C3_EV_IRQn);} |
||||
void I2C3_ER_IRQHandler(void) {handle_interrupt(I2C3_ER_IRQn);} |
||||
#ifdef STM32F4 |
||||
void DFSDM1_FLT0_IRQHandler(void) {handle_interrupt(DFSDM1_FLT0_IRQn);} |
||||
void DFSDM1_FLT1_IRQHandler(void) {handle_interrupt(DFSDM1_FLT1_IRQn);} |
||||
void CAN3_TX_IRQHandler(void) {handle_interrupt(CAN3_TX_IRQn);} |
||||
void CAN3_RX0_IRQHandler(void) {handle_interrupt(CAN3_RX0_IRQn);} |
||||
void CAN3_RX1_IRQHandler(void) {handle_interrupt(CAN3_RX1_IRQn);} |
||||
void CAN3_SCE_IRQHandler(void) {handle_interrupt(CAN3_SCE_IRQn);} |
||||
void RNG_IRQHandler(void) {handle_interrupt(RNG_IRQn);} |
||||
void FPU_IRQHandler(void) {handle_interrupt(FPU_IRQn);} |
||||
void UART7_IRQHandler(void) {handle_interrupt(UART7_IRQn);} |
||||
void UART8_IRQHandler(void) {handle_interrupt(UART8_IRQn);} |
||||
void SPI4_IRQHandler(void) {handle_interrupt(SPI4_IRQn);} |
||||
void SPI5_IRQHandler(void) {handle_interrupt(SPI5_IRQn);} |
||||
void SAI1_IRQHandler(void) {handle_interrupt(SAI1_IRQn);} |
||||
void UART9_IRQHandler(void) {handle_interrupt(UART9_IRQn);} |
||||
void UART10_IRQHandler(void) {handle_interrupt(UART10_IRQn);} |
||||
void QUADSPI_IRQHandler(void) {handle_interrupt(QUADSPI_IRQn);} |
||||
void FMPI2C1_EV_IRQHandler(void) {handle_interrupt(FMPI2C1_EV_IRQn);} |
||||
void FMPI2C1_ER_IRQHandler(void) {handle_interrupt(FMPI2C1_ER_IRQn);} |
||||
void LPTIM1_IRQHandler(void) {handle_interrupt(LPTIM1_IRQn);} |
||||
void DFSDM2_FLT0_IRQHandler(void) {handle_interrupt(DFSDM2_FLT0_IRQn);} |
||||
void DFSDM2_FLT1_IRQHandler(void) {handle_interrupt(DFSDM2_FLT1_IRQn);} |
||||
void DFSDM2_FLT2_IRQHandler(void) {handle_interrupt(DFSDM2_FLT2_IRQn);} |
||||
void DFSDM2_FLT3_IRQHandler(void) {handle_interrupt(DFSDM2_FLT3_IRQn);} |
||||
#endif |
@ -0,0 +1,81 @@ |
||||
|
||||
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]; |
||||
|
||||
// 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){ |
||||
return (((input >> 16U) ^ ((((input + 1U) & 0xFFFFU) * HASHING_PRIME) & 0xFFFFU)) & REGISTER_MAP_SIZE); |
||||
} |
||||
|
||||
// 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){ |
||||
ENTER_CRITICAL() |
||||
// Set bits in register that are also in the mask
|
||||
(*addr) = ((*addr) & (~mask)) | (val & mask); |
||||
|
||||
// Add these values to the map
|
||||
uint16_t hash = hash_addr((uint32_t) addr); |
||||
uint16_t tries = REGISTER_MAP_SIZE; |
||||
while(CHECK_COLLISION(hash, addr) && (tries > 0U)) { hash = hash_addr((uint32_t) hash); tries--;} |
||||
if (tries != 0U){ |
||||
register_map[hash].address = addr; |
||||
register_map[hash].value = (register_map[hash].value & (~mask)) | (val & mask); |
||||
register_map[hash].check_mask |= mask; |
||||
} else { |
||||
#ifdef DEBUG_FAULTS |
||||
puts("Hash collision: address 0x"); puth((uint32_t) addr); puts("!\n"); |
||||
#endif |
||||
} |
||||
EXIT_CRITICAL() |
||||
} |
||||
|
||||
// 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) { |
||||
return register_set(addr, val, 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) { |
||||
return register_set(addr, (~val), val); |
||||
} |
||||
|
||||
// To be called periodically
|
||||
void check_registers(void){ |
||||
for(uint16_t i=0U; i<REGISTER_MAP_SIZE; i++){ |
||||
if((uint32_t) register_map[i].address != 0U){ |
||||
ENTER_CRITICAL() |
||||
if((*(register_map[i].address) & register_map[i].check_mask) != (register_map[i].value & register_map[i].check_mask)){ |
||||
#ifdef DEBUG_FAULTS |
||||
puts("Register at address 0x"); puth((uint32_t) register_map[i].address); puts(" is divergent!"); |
||||
puts(" Map: 0x"); puth(register_map[i].value); |
||||
puts(" Register: 0x"); puth(*(register_map[i].address)); |
||||
puts(" Mask: 0x"); puth(register_map[i].check_mask); |
||||
puts("\n"); |
||||
#endif |
||||
fault_occurred(FAULT_REGISTER_DIVERGENT); |
||||
} |
||||
EXIT_CRITICAL() |
||||
} |
||||
} |
||||
} |
||||
|
||||
void init_registers(void) { |
||||
for(uint16_t i=0U; i<REGISTER_MAP_SIZE; i++){ |
||||
register_map[i].address = (volatile uint32_t *) 0U; |
||||
register_map[i].check_mask = 0U; |
||||
} |
||||
} |
@ -1,7 +1,7 @@ |
||||
void timer_init(TIM_TypeDef *TIM, int psc) { |
||||
TIM->PSC = psc-1; |
||||
TIM->DIER = TIM_DIER_UIE; |
||||
TIM->CR1 = TIM_CR1_CEN; |
||||
register_set(&(TIM->PSC), (psc-1), 0xFFFFU); |
||||
register_set(&(TIM->DIER), TIM_DIER_UIE, 0x5F5FU); |
||||
register_set(&(TIM->CR1), TIM_CR1_CEN, 0x3FU); |
||||
TIM->SR = 0; |
||||
} |
||||
|
||||
|
@ -0,0 +1,49 @@ |
||||
#define FAULT_STATUS_NONE 0U |
||||
#define FAULT_STATUS_TEMPORARY 1U |
||||
#define FAULT_STATUS_PERMANENT 2U |
||||
|
||||
// Fault types
|
||||
#define FAULT_RELAY_MALFUNCTION (1U << 0) |
||||
#define FAULT_UNUSED_INTERRUPT_HANDLED (1U << 1) |
||||
#define FAULT_INTERRUPT_RATE_CAN_1 (1U << 2) |
||||
#define FAULT_INTERRUPT_RATE_CAN_2 (1U << 3) |
||||
#define FAULT_INTERRUPT_RATE_CAN_3 (1U << 4) |
||||
#define FAULT_INTERRUPT_RATE_TACH (1U << 5) |
||||
#define FAULT_INTERRUPT_RATE_GMLAN (1U << 6) |
||||
#define FAULT_INTERRUPT_RATE_INTERRUPTS (1U << 7) |
||||
#define FAULT_INTERRUPT_RATE_SPI_DMA (1U << 8) |
||||
#define FAULT_INTERRUPT_RATE_SPI_CS (1U << 9) |
||||
#define FAULT_INTERRUPT_RATE_UART_1 (1U << 10) |
||||
#define FAULT_INTERRUPT_RATE_UART_2 (1U << 11) |
||||
#define FAULT_INTERRUPT_RATE_UART_3 (1U << 12) |
||||
#define FAULT_INTERRUPT_RATE_UART_5 (1U << 13) |
||||
#define FAULT_INTERRUPT_RATE_UART_DMA (1U << 14) |
||||
#define FAULT_INTERRUPT_RATE_USB (1U << 15) |
||||
#define FAULT_INTERRUPT_RATE_TIM1 (1U << 16) |
||||
#define FAULT_INTERRUPT_RATE_TIM3 (1U << 17) |
||||
#define FAULT_REGISTER_DIVERGENT (1U << 18) |
||||
|
||||
// Permanent faults
|
||||
#define PERMANENT_FAULTS 0U |
||||
|
||||
uint8_t fault_status = FAULT_STATUS_NONE; |
||||
uint32_t faults = 0U; |
||||
|
||||
void fault_occurred(uint32_t fault) { |
||||
faults |= fault; |
||||
if((PERMANENT_FAULTS & fault) != 0U){ |
||||
puts("Permanent fault occurred: 0x"); puth(fault); puts("\n"); |
||||
fault_status = FAULT_STATUS_PERMANENT; |
||||
} else { |
||||
puts("Temporary fault occurred: 0x"); puth(fault); puts("\n"); |
||||
fault_status = FAULT_STATUS_TEMPORARY; |
||||
} |
||||
} |
||||
|
||||
void fault_recovered(uint32_t fault) { |
||||
if((PERMANENT_FAULTS & fault) == 0U){ |
||||
faults &= ~fault; |
||||
} else { |
||||
puts("Cannot recover from a permanent fault!\n"); |
||||
} |
||||
} |
@ -1,59 +0,0 @@ |
||||
#!/usr/bin/env python3 |
||||
from panda import Panda |
||||
from panda.python.uds import UdsClient, NegativeResponseError, DATA_IDENTIFIER_TYPE |
||||
|
||||
if __name__ == "__main__": |
||||
address = 0x18da30f1 # Honda EPS |
||||
panda = Panda() |
||||
uds_client = UdsClient(panda, address, debug=False) |
||||
|
||||
print("tester present ...") |
||||
uds_client.tester_present() |
||||
|
||||
try: |
||||
print("") |
||||
print("read data by id: boot software id ...") |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.BOOT_SOFTWARE_IDENTIFICATION) |
||||
print(data.decode('utf-8')) |
||||
except NegativeResponseError as e: |
||||
print(e) |
||||
|
||||
try: |
||||
print("") |
||||
print("read data by id: application software id ...") |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) |
||||
print(data.decode('utf-8')) |
||||
except NegativeResponseError as e: |
||||
print(e) |
||||
|
||||
try: |
||||
print("") |
||||
print("read data by id: application data id ...") |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION) |
||||
print(data.decode('utf-8')) |
||||
except NegativeResponseError as e: |
||||
print(e) |
||||
|
||||
try: |
||||
print("") |
||||
print("read data by id: boot software fingerprint ...") |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.BOOT_SOFTWARE_FINGERPRINT) |
||||
print(data.decode('utf-8')) |
||||
except NegativeResponseError as e: |
||||
print(e) |
||||
|
||||
try: |
||||
print("") |
||||
print("read data by id: application software fingerprint ...") |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_FINGERPRINT) |
||||
print(data.decode('utf-8')) |
||||
except NegativeResponseError as e: |
||||
print(e) |
||||
|
||||
try: |
||||
print("") |
||||
print("read data by id: application data fingerprint ...") |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_DATA_FINGERPRINT) |
||||
print(data.decode('utf-8')) |
||||
except NegativeResponseError as e: |
||||
print(e) |
@ -0,0 +1,77 @@ |
||||
#!/usr/bin/env python3 |
||||
from tqdm import tqdm |
||||
from panda import Panda |
||||
from panda.python.uds import UdsClient, MessageTimeoutError, NegativeResponseError, SESSION_TYPE, DATA_IDENTIFIER_TYPE |
||||
|
||||
if __name__ == "__main__": |
||||
addrs = [0x700 + i for i in range(256)] |
||||
addrs += [0x18da0000 + (i<<8) + 0xf1 for i in range(256)] |
||||
results = {} |
||||
|
||||
panda = Panda() |
||||
panda.set_safety_mode(Panda.SAFETY_ELM327) |
||||
print("querying addresses ...") |
||||
with tqdm(addrs) as t: |
||||
for addr in t: |
||||
# skip functional broadcast addrs |
||||
if addr == 0x7df or addr == 0x18db33f1: |
||||
continue |
||||
t.set_description(hex(addr)) |
||||
|
||||
uds_client = UdsClient(panda, addr, bus=1 if panda.has_obd() else 0, timeout=0.1, debug=False) |
||||
try: |
||||
uds_client.tester_present() |
||||
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC) |
||||
except NegativeResponseError: |
||||
pass |
||||
except MessageTimeoutError: |
||||
continue |
||||
|
||||
resp = {} |
||||
|
||||
try: |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.BOOT_SOFTWARE_IDENTIFICATION) |
||||
if data: resp[DATA_IDENTIFIER_TYPE.BOOT_SOFTWARE_IDENTIFICATION] = data |
||||
except NegativeResponseError: |
||||
pass |
||||
|
||||
try: |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) |
||||
if data: resp[DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION] = data |
||||
except NegativeResponseError: |
||||
pass |
||||
|
||||
try: |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION) |
||||
if data: resp[DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION] = data |
||||
except NegativeResponseError: |
||||
pass |
||||
|
||||
try: |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.BOOT_SOFTWARE_FINGERPRINT) |
||||
if data: resp[DATA_IDENTIFIER_TYPE.BOOT_SOFTWARE_FINGERPRINT] = data |
||||
except NegativeResponseError: |
||||
pass |
||||
|
||||
try: |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_FINGERPRINT) |
||||
if data: resp[DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_FINGERPRINT] = data |
||||
except NegativeResponseError: |
||||
pass |
||||
|
||||
try: |
||||
data = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_DATA_FINGERPRINT) |
||||
if data: resp[DATA_IDENTIFIER_TYPE.APPLICATION_DATA_FINGERPRINT] = data |
||||
except NegativeResponseError: |
||||
pass |
||||
|
||||
if resp.keys(): |
||||
results[addr] = resp |
||||
|
||||
print("results:") |
||||
if len(results.items()): |
||||
for addr, resp in results.items(): |
||||
for rid, dat in resp.items(): |
||||
print(hex(addr), hex(rid), dat.decode()) |
||||
else: |
||||
print("no fw versions found!") |
@ -1,11 +1,34 @@ |
||||
from .helpers import test_all_pandas, panda_connect_and_init |
||||
import os |
||||
|
||||
from nose.tools import assert_equal |
||||
|
||||
from panda import Panda, BASEDIR |
||||
from .helpers import reset_pandas, test_all_pandas, panda_connect_and_init |
||||
|
||||
|
||||
# Reset the pandas before flashing them |
||||
def aaaa_reset_before_tests(): |
||||
reset_pandas() |
||||
|
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_recover(p): |
||||
assert p.recover(timeout=30) |
||||
|
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_flash(p): |
||||
p.flash() |
||||
|
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_get_signature(p): |
||||
fn = os.path.join(BASEDIR, "board/obj/panda.bin") |
||||
|
||||
firmware_sig = Panda.get_signature_from_firmware(fn) |
||||
panda_sig = p.get_signature() |
||||
|
||||
assert_equal(panda_sig, firmware_sig) |
||||
|
@ -0,0 +1,44 @@ |
||||
import time |
||||
from panda_jungle import PandaJungle # pylint: disable=import-error |
||||
from .helpers import panda_jungle, reset_pandas, test_all_pandas, test_all_gen2_pandas, panda_connect_and_init |
||||
|
||||
# Reset the pandas before running tests |
||||
def aaaa_reset_before_tests(): |
||||
reset_pandas() |
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_ignition(p): |
||||
try: |
||||
# Set harness orientation to #2, since the ignition line is on the wrong SBU bus :/ |
||||
panda_jungle.set_harness_orientation(PandaJungle.HARNESS_ORIENTATION_2) |
||||
reset_pandas() |
||||
p.reconnect() |
||||
panda_jungle.set_ignition(False) |
||||
time.sleep(2) |
||||
assert p.health()['ignition_line'] == False |
||||
panda_jungle.set_ignition(True) |
||||
time.sleep(2) |
||||
assert p.health()['ignition_line'] == True |
||||
finally: |
||||
panda_jungle.set_harness_orientation(PandaJungle.HARNESS_ORIENTATION_1) |
||||
|
||||
@test_all_gen2_pandas |
||||
@panda_connect_and_init |
||||
def test_orientation_detection(p): |
||||
seen_orientations = [] |
||||
for i in range(3): |
||||
panda_jungle.set_harness_orientation(i) |
||||
reset_pandas() |
||||
p.reconnect() |
||||
detected_harness_orientation = p.health()['car_harness_status'] |
||||
if (i == 0 and detected_harness_orientation != 0) or detected_harness_orientation in seen_orientations: |
||||
assert False |
||||
seen_orientations.append(detected_harness_orientation) |
||||
|
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_voltage(p): |
||||
voltage = p.health()['voltage'] |
||||
assert ((voltage > 10000) and (voltage < 14000)) |
@ -1,8 +1,12 @@ |
||||
import time |
||||
from panda import Panda |
||||
from .helpers import connect_wifi, test_white, test_all_pandas, panda_type_to_serial, panda_connect_and_init |
||||
from .helpers import reset_pandas, connect_wifi, test_white, test_all_pandas, panda_type_to_serial, panda_connect_and_init |
||||
import requests |
||||
|
||||
# Reset the pandas before running tests |
||||
def aaaa_reset_before_tests(): |
||||
reset_pandas() |
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_get_serial(p): |
@ -1,195 +0,0 @@ |
||||
|
||||
import os |
||||
import time |
||||
import random |
||||
from panda import Panda |
||||
from nose.tools import assert_equal, assert_less, assert_greater |
||||
from .helpers import time_many_sends, test_two_panda, test_two_black_panda, panda_type_to_serial, clear_can_buffers, panda_connect_and_init |
||||
|
||||
@test_two_panda |
||||
@panda_type_to_serial |
||||
@panda_connect_and_init |
||||
def test_send_recv(p_send, p_recv): |
||||
p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p_recv.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p_send.set_can_loopback(False) |
||||
p_recv.set_can_loopback(False) |
||||
|
||||
assert not p_send.legacy |
||||
assert not p_recv.legacy |
||||
|
||||
p_send.can_send_many([(0x1ba, 0, b"message", 0)]*2) |
||||
time.sleep(0.05) |
||||
p_recv.can_recv() |
||||
p_send.can_recv() |
||||
|
||||
busses = [0,1,2] |
||||
|
||||
for bus in busses: |
||||
for speed in [100, 250, 500, 750, 1000]: |
||||
p_send.set_can_speed_kbps(bus, speed) |
||||
p_recv.set_can_speed_kbps(bus, speed) |
||||
time.sleep(0.05) |
||||
|
||||
comp_kbps = time_many_sends(p_send, bus, p_recv, two_pandas=True) |
||||
|
||||
saturation_pct = (comp_kbps/speed) * 100.0 |
||||
assert_greater(saturation_pct, 80) |
||||
assert_less(saturation_pct, 100) |
||||
|
||||
print("two pandas bus {}, 100 messages at speed {:4d}, comp speed is {:7.2f}, percent {:6.2f}".format(bus, speed, comp_kbps, saturation_pct)) |
||||
|
||||
@test_two_panda |
||||
@panda_type_to_serial |
||||
@panda_connect_and_init |
||||
def test_latency(p_send, p_recv): |
||||
p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p_recv.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p_send.set_can_loopback(False) |
||||
p_recv.set_can_loopback(False) |
||||
|
||||
assert not p_send.legacy |
||||
assert not p_recv.legacy |
||||
|
||||
p_send.set_can_speed_kbps(0, 100) |
||||
p_recv.set_can_speed_kbps(0, 100) |
||||
time.sleep(0.05) |
||||
|
||||
p_send.can_send_many([(0x1ba, 0, b"testmsg", 0)]*10) |
||||
time.sleep(0.05) |
||||
p_recv.can_recv() |
||||
p_send.can_recv() |
||||
|
||||
busses = [0,1,2] |
||||
|
||||
for bus in busses: |
||||
for speed in [100, 250, 500, 750, 1000]: |
||||
p_send.set_can_speed_kbps(bus, speed) |
||||
p_recv.set_can_speed_kbps(bus, speed) |
||||
time.sleep(0.1) |
||||
|
||||
#clear can buffers |
||||
clear_can_buffers(p_send) |
||||
clear_can_buffers(p_recv) |
||||
|
||||
latencies = [] |
||||
comp_kbps_list = [] |
||||
saturation_pcts = [] |
||||
|
||||
num_messages = 100 |
||||
|
||||
for i in range(num_messages): |
||||
st = time.time() |
||||
p_send.can_send(0x1ab, b"message", bus) |
||||
r = [] |
||||
while len(r) < 1 and (time.time() - st) < 5: |
||||
r = p_recv.can_recv() |
||||
et = time.time() |
||||
r_echo = [] |
||||
while len(r_echo) < 1 and (time.time() - st) < 10: |
||||
r_echo = p_send.can_recv() |
||||
|
||||
if len(r) == 0 or len(r_echo) == 0: |
||||
print("r: {}, r_echo: {}".format(r, r_echo)) |
||||
|
||||
assert_equal(len(r),1) |
||||
assert_equal(len(r_echo),1) |
||||
|
||||
et = (et - st)*1000.0 |
||||
comp_kbps = (1+11+1+1+1+4+8*8+15+1+1+1+7) / et |
||||
latency = et - ((1+11+1+1+1+4+8*8+15+1+1+1+7) / speed) |
||||
|
||||
assert_less(latency, 5.0) |
||||
|
||||
saturation_pct = (comp_kbps/speed) * 100.0 |
||||
latencies.append(latency) |
||||
comp_kbps_list.append(comp_kbps) |
||||
saturation_pcts.append(saturation_pct) |
||||
|
||||
average_latency = sum(latencies)/num_messages |
||||
assert_less(average_latency, 1.0) |
||||
average_comp_kbps = sum(comp_kbps_list)/num_messages |
||||
average_saturation_pct = sum(saturation_pcts)/num_messages |
||||
|
||||
print("two pandas bus {}, {} message average at speed {:4d}, latency is {:5.3f}ms, comp speed is {:7.2f}, percent {:6.2f}"\ |
||||
.format(bus, num_messages, speed, average_latency, average_comp_kbps, average_saturation_pct)) |
||||
|
||||
@test_two_black_panda |
||||
@panda_type_to_serial |
||||
@panda_connect_and_init |
||||
def test_black_loopback(panda0, panda1): |
||||
# disable safety modes |
||||
panda0.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
panda1.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
|
||||
# disable loopback |
||||
panda0.set_can_loopback(False) |
||||
panda1.set_can_loopback(False) |
||||
|
||||
# clear stuff |
||||
panda0.can_send_many([(0x1ba, 0, b"testmsg", 0)]*10) |
||||
time.sleep(0.05) |
||||
panda0.can_recv() |
||||
panda1.can_recv() |
||||
|
||||
# test array (send bus, sender obd, reciever obd, expected busses) |
||||
test_array = [ |
||||
(0, False, False, [0]), |
||||
(1, False, False, [1]), |
||||
(2, False, False, [2]), |
||||
(0, False, True, [0, 1]), |
||||
(1, False, True, []), |
||||
(2, False, True, [2]), |
||||
(0, True, False, [0]), |
||||
(1, True, False, [0]), |
||||
(2, True, False, [2]), |
||||
(0, True, True, [0, 1]), |
||||
(1, True, True, [0, 1]), |
||||
(2, True, True, [2]) |
||||
] |
||||
|
||||
# test functions |
||||
def get_test_string(): |
||||
return b"test"+os.urandom(10) |
||||
|
||||
def _test_buses(send_panda, recv_panda, _test_array): |
||||
for send_bus, send_obd, recv_obd, recv_buses in _test_array: |
||||
print("\nSend bus:", send_bus, " Send OBD:", send_obd, " Recv OBD:", recv_obd) |
||||
|
||||
# set OBD on pandas |
||||
send_panda.set_gmlan(True if send_obd else None) |
||||
recv_panda.set_gmlan(True if recv_obd else None) |
||||
|
||||
# clear buffers |
||||
clear_can_buffers(send_panda) |
||||
clear_can_buffers(recv_panda) |
||||
|
||||
# send the characters |
||||
at = random.randint(1, 2000) |
||||
st = get_test_string()[0:8] |
||||
send_panda.can_send(at, st, send_bus) |
||||
time.sleep(0.1) |
||||
|
||||
# check for receive |
||||
_ = send_panda.can_recv() # cans echo |
||||
cans_loop = recv_panda.can_recv() |
||||
|
||||
loop_buses = [] |
||||
for loop in cans_loop: |
||||
print(" Loop on bus", str(loop[3])) |
||||
loop_buses.append(loop[3]) |
||||
if len(cans_loop) == 0: |
||||
print(" No loop") |
||||
|
||||
# test loop buses |
||||
recv_buses.sort() |
||||
loop_buses.sort() |
||||
assert recv_buses == loop_buses |
||||
print(" TEST PASSED") |
||||
print("\n") |
||||
|
||||
# test both orientations |
||||
print("***************** TESTING (0 --> 1) *****************") |
||||
_test_buses(panda0, panda1, test_array) |
||||
print("***************** TESTING (1 --> 0) *****************") |
||||
_test_buses(panda1, panda0, test_array) |
@ -1,16 +1,23 @@ |
||||
|
||||
import sys |
||||
import time |
||||
from .helpers import time_many_sends, connect_wifi, test_white, panda_type_to_serial |
||||
from .helpers import start_heartbeat_thread, reset_pandas, time_many_sends, connect_wifi, test_white, panda_type_to_serial |
||||
from panda import Panda, PandaWifiStreaming |
||||
from nose.tools import assert_less, assert_greater |
||||
|
||||
# Reset the pandas before running tests |
||||
def aaaa_reset_before_tests(): |
||||
reset_pandas() |
||||
|
||||
@test_white |
||||
@panda_type_to_serial |
||||
def test_udp_doesnt_drop(serials=None): |
||||
connect_wifi(serials[0]) |
||||
|
||||
p = Panda(serials[0]) |
||||
|
||||
# Start heartbeat |
||||
start_heartbeat_thread(p) |
||||
|
||||
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p.set_can_loopback(True) |
||||
|
@ -0,0 +1,202 @@ |
||||
import os |
||||
import time |
||||
import random |
||||
from panda import Panda |
||||
from nose.tools import assert_equal, assert_less, assert_greater |
||||
from .helpers import panda_jungle, start_heartbeat_thread, reset_pandas, time_many_sends, test_all_pandas, test_all_gen2_pandas, clear_can_buffers, panda_connect_and_init |
||||
|
||||
# Reset the pandas before running tests |
||||
def aaaa_reset_before_tests(): |
||||
reset_pandas() |
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_send_recv(p): |
||||
def test(p_send, p_recv): |
||||
p_send.set_can_loopback(False) |
||||
p_recv.set_can_loopback(False) |
||||
|
||||
p_send.can_send_many([(0x1ba, 0, b"message", 0)]*2) |
||||
time.sleep(0.05) |
||||
p_recv.can_recv() |
||||
p_send.can_recv() |
||||
|
||||
busses = [0,1,2] |
||||
|
||||
for bus in busses: |
||||
for speed in [100, 250, 500, 750, 1000]: |
||||
p_send.set_can_speed_kbps(bus, speed) |
||||
p_recv.set_can_speed_kbps(bus, speed) |
||||
time.sleep(0.05) |
||||
|
||||
clear_can_buffers(p_send) |
||||
clear_can_buffers(p_recv) |
||||
|
||||
comp_kbps = time_many_sends(p_send, bus, p_recv, two_pandas=True) |
||||
|
||||
saturation_pct = (comp_kbps/speed) * 100.0 |
||||
assert_greater(saturation_pct, 80) |
||||
assert_less(saturation_pct, 100) |
||||
|
||||
print("two pandas bus {}, 100 messages at speed {:4d}, comp speed is {:7.2f}, percent {:6.2f}".format(bus, speed, comp_kbps, saturation_pct)) |
||||
|
||||
# Start heartbeat |
||||
start_heartbeat_thread(p) |
||||
|
||||
# Set safety mode and power saving |
||||
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p.set_power_save(False) |
||||
|
||||
try: |
||||
# Run tests in both directions |
||||
test(p, panda_jungle) |
||||
test(panda_jungle, p) |
||||
except Exception as e: |
||||
# Raise errors again, we don't want them to get lost |
||||
raise e |
||||
finally: |
||||
# Set back to silent mode |
||||
p.set_safety_mode(Panda.SAFETY_SILENT) |
||||
|
||||
@test_all_pandas |
||||
@panda_connect_and_init |
||||
def test_latency(p): |
||||
def test(p_send, p_recv): |
||||
p_send.set_can_loopback(False) |
||||
p_recv.set_can_loopback(False) |
||||
|
||||
p_send.set_can_speed_kbps(0, 100) |
||||
p_recv.set_can_speed_kbps(0, 100) |
||||
time.sleep(0.05) |
||||
|
||||
p_send.can_send_many([(0x1ba, 0, b"testmsg", 0)]*10) |
||||
time.sleep(0.05) |
||||
p_recv.can_recv() |
||||
p_send.can_recv() |
||||
|
||||
busses = [0,1,2] |
||||
|
||||
for bus in busses: |
||||
for speed in [100, 250, 500, 750, 1000]: |
||||
p_send.set_can_speed_kbps(bus, speed) |
||||
p_recv.set_can_speed_kbps(bus, speed) |
||||
time.sleep(0.1) |
||||
|
||||
# clear can buffers |
||||
clear_can_buffers(p_send) |
||||
clear_can_buffers(p_recv) |
||||
|
||||
latencies = [] |
||||
comp_kbps_list = [] |
||||
saturation_pcts = [] |
||||
|
||||
num_messages = 100 |
||||
|
||||
for i in range(num_messages): |
||||
st = time.time() |
||||
p_send.can_send(0x1ab, b"message", bus) |
||||
r = [] |
||||
while len(r) < 1 and (time.time() - st) < 5: |
||||
r = p_recv.can_recv() |
||||
et = time.time() |
||||
r_echo = [] |
||||
while len(r_echo) < 1 and (time.time() - st) < 10: |
||||
r_echo = p_send.can_recv() |
||||
|
||||
if len(r) == 0 or len(r_echo) == 0: |
||||
print("r: {}, r_echo: {}".format(r, r_echo)) |
||||
|
||||
assert_equal(len(r),1) |
||||
assert_equal(len(r_echo),1) |
||||
|
||||
et = (et - st)*1000.0 |
||||
comp_kbps = (1+11+1+1+1+4+8*8+15+1+1+1+7) / et |
||||
latency = et - ((1+11+1+1+1+4+8*8+15+1+1+1+7) / speed) |
||||
|
||||
assert_less(latency, 5.0) |
||||
|
||||
saturation_pct = (comp_kbps/speed) * 100.0 |
||||
latencies.append(latency) |
||||
comp_kbps_list.append(comp_kbps) |
||||
saturation_pcts.append(saturation_pct) |
||||
|
||||
average_latency = sum(latencies)/num_messages |
||||
assert_less(average_latency, 1.0) |
||||
average_comp_kbps = sum(comp_kbps_list)/num_messages |
||||
average_saturation_pct = sum(saturation_pcts)/num_messages |
||||
|
||||
print("two pandas bus {}, {} message average at speed {:4d}, latency is {:5.3f}ms, comp speed is {:7.2f}, percent {:6.2f}"\ |
||||
.format(bus, num_messages, speed, average_latency, average_comp_kbps, average_saturation_pct)) |
||||
|
||||
# Start heartbeat |
||||
start_heartbeat_thread(p) |
||||
|
||||
# Set safety mode and power saving |
||||
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p.set_power_save(False) |
||||
|
||||
try: |
||||
# Run tests in both directions |
||||
test(p, panda_jungle) |
||||
test(panda_jungle, p) |
||||
except Exception as e: |
||||
# Raise errors again, we don't want them to get lost |
||||
raise e |
||||
finally: |
||||
# Set back to silent mode |
||||
p.set_safety_mode(Panda.SAFETY_SILENT) |
||||
|
||||
|
||||
@test_all_gen2_pandas |
||||
@panda_connect_and_init |
||||
def test_gen2_loopback(p): |
||||
def test(p_send, p_recv): |
||||
for bus in range(4): |
||||
obd = False |
||||
if bus == 3: |
||||
obd = True |
||||
bus = 1 |
||||
|
||||
# Clear buses |
||||
clear_can_buffers(p_send) |
||||
clear_can_buffers(p_recv) |
||||
|
||||
# Send a random string |
||||
addr = random.randint(1, 2000) |
||||
string = b"test"+os.urandom(4) |
||||
p_send.set_obd(obd) |
||||
p_recv.set_obd(obd) |
||||
time.sleep(0.2) |
||||
p_send.can_send(addr, string, bus) |
||||
time.sleep(0.2) |
||||
|
||||
content = p_recv.can_recv() |
||||
|
||||
# Check amount of messages |
||||
assert len(content) == 1 |
||||
|
||||
# Check content |
||||
assert content[0][0] == addr and content[0][2] == string |
||||
|
||||
# Check bus |
||||
assert content[0][3] == bus |
||||
|
||||
print("Bus:", bus, "OBD:", obd, "OK") |
||||
|
||||
# Start heartbeat |
||||
start_heartbeat_thread(p) |
||||
|
||||
# Set safety mode and power saving |
||||
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p.set_power_save(False) |
||||
|
||||
try: |
||||
# Run tests in both directions |
||||
test(p, panda_jungle) |
||||
test(panda_jungle, p) |
||||
except Exception as e: |
||||
# Raise errors again, we don't want them to get lost |
||||
raise e |
||||
finally: |
||||
# Set back to silent mode |
||||
p.set_safety_mode(Panda.SAFETY_SILENT) |
@ -0,0 +1,25 @@ |
||||
import time |
||||
from multiprocessing import Process |
||||
|
||||
# Note: this does not return any return values of the function, just the exit status |
||||
INTERVAL = 0.1 |
||||
def run_with_timeout(timeout, fn, *kwargs): |
||||
def runner(fn, kwargs): |
||||
try: |
||||
fn(*kwargs) |
||||
except Exception as e: |
||||
print(e) |
||||
raise e |
||||
|
||||
process = Process(target=runner, args=(fn, kwargs)) |
||||
process.start() |
||||
|
||||
counter = 0 |
||||
while process.is_alive(): |
||||
time.sleep(INTERVAL) |
||||
counter+=1 |
||||
if (counter * INTERVAL) > timeout: |
||||
process.terminate() |
||||
raise TimeoutError("Function timed out!") |
||||
if process.exitcode != 0: |
||||
raise RuntimeError("Test failed with exit code: ", str(process.exitcode)) |
@ -0,0 +1,85 @@ |
||||
import os |
||||
FNULL = open(os.devnull, 'w') |
||||
def _connect_wifi(dongle_id, pw, insecure_okay=False): |
||||
ssid = "panda-" + dongle_id |
||||
|
||||
r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT) |
||||
if not r: |
||||
# Can already ping, try connecting on wifi |
||||
try: |
||||
p = Panda("WIFI") |
||||
p.get_serial() |
||||
print("Already connected") |
||||
return |
||||
except: |
||||
pass |
||||
|
||||
print("WIFI: connecting to %s" % ssid) |
||||
|
||||
while 1: |
||||
if sys.platform == "darwin": |
||||
os.system("networksetup -setairportnetwork en0 %s %s" % (ssid, pw)) |
||||
else: |
||||
wlan_interface = subprocess.check_output(["sh", "-c", "iw dev | awk '/Interface/ {print $2}'"]).strip().decode('utf8') |
||||
cnt = 0 |
||||
MAX_TRIES = 10 |
||||
while cnt < MAX_TRIES: |
||||
print("WIFI: scanning %d" % cnt) |
||||
os.system("iwlist %s scanning > /dev/null" % wlan_interface) |
||||
os.system("nmcli device wifi rescan") |
||||
wifi_networks = [x.decode("utf8") for x in subprocess.check_output(["nmcli","dev", "wifi", "list"]).split(b"\n")] |
||||
wifi_scan = [x for x in wifi_networks if ssid in x] |
||||
if len(wifi_scan) != 0: |
||||
break |
||||
time.sleep(0.1) |
||||
# MAX_TRIES tries, ~10 seconds max |
||||
cnt += 1 |
||||
assert cnt < MAX_TRIES |
||||
if "-pair" in wifi_scan[0]: |
||||
os.system("nmcli d wifi connect %s-pair" % (ssid)) |
||||
connect_cnt = 0 |
||||
MAX_TRIES = 100 |
||||
while connect_cnt < MAX_TRIES: |
||||
connect_cnt += 1 |
||||
r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT) |
||||
if r: |
||||
print("Waiting for panda to ping...") |
||||
time.sleep(0.5) |
||||
else: |
||||
break |
||||
if insecure_okay: |
||||
break |
||||
# fetch webpage |
||||
print("connecting to insecure network to secure") |
||||
try: |
||||
r = requests.get("http://192.168.0.10/") |
||||
except requests.ConnectionError: |
||||
r = requests.get("http://192.168.0.10/") |
||||
assert r.status_code==200 |
||||
|
||||
print("securing") |
||||
try: |
||||
r = requests.get("http://192.168.0.10/secure", timeout=0.01) |
||||
except requests.exceptions.Timeout: |
||||
print("timeout http request to secure") |
||||
pass |
||||
else: |
||||
ret = os.system("nmcli d wifi connect %s password %s" % (ssid, pw)) |
||||
if os.WEXITSTATUS(ret) == 0: |
||||
#check ping too |
||||
ping_ok = False |
||||
connect_cnt = 0 |
||||
MAX_TRIES = 10 |
||||
while connect_cnt < MAX_TRIES: |
||||
connect_cnt += 1 |
||||
r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT) |
||||
if r: |
||||
print("Waiting for panda to ping...") |
||||
time.sleep(0.1) |
||||
else: |
||||
ping_ok = True |
||||
break |
||||
if ping_ok: |
||||
break |
||||
|
||||
# TODO: confirm that it's connected to the right panda |
@ -0,0 +1,50 @@ |
||||
#!/usr/bin/env python3 |
||||
import matplotlib.pyplot as plt # pylint: disable=import-error |
||||
|
||||
HASHING_PRIME = 23 |
||||
REGISTER_MAP_SIZE = 0x3FF |
||||
BYTES_PER_REG = 4 |
||||
|
||||
# From ST32F413 datasheet |
||||
REGISTER_ADDRESS_REGIONS = [ |
||||
(0x40000000, 0x40007FFF), |
||||
(0x40010000, 0x400107FF), |
||||
(0x40011000, 0x400123FF), |
||||
(0x40012C00, 0x40014BFF), |
||||
(0x40015000, 0x400153FF), |
||||
(0x40015800, 0x40015BFF), |
||||
(0x40016000, 0x400167FF), |
||||
(0x40020000, 0x40021FFF), |
||||
(0x40023000, 0x400233FF), |
||||
(0x40023800, 0x40023FFF), |
||||
(0x40026000, 0x400267FF), |
||||
(0x50000000, 0x5003FFFF), |
||||
(0x50060000, 0x500603FF), |
||||
(0x50060800, 0x50060BFF), |
||||
(0x50060800, 0x50060BFF), |
||||
(0xE0000000, 0xE00FFFFF) |
||||
] |
||||
|
||||
def hash(reg_addr): |
||||
return (((reg_addr >> 16) ^ ((((reg_addr + 1) & 0xFFFF) * HASHING_PRIME) & 0xFFFF)) & REGISTER_MAP_SIZE) |
||||
|
||||
# Calculate hash for each address |
||||
hashes = [] |
||||
double_hashes = [] |
||||
for (start_addr, stop_addr) in REGISTER_ADDRESS_REGIONS: |
||||
for addr in range(start_addr, stop_addr+1, BYTES_PER_REG): |
||||
h = hash(addr) |
||||
hashes.append(h) |
||||
double_hashes.append(hash(h)) |
||||
|
||||
# Make histograms |
||||
plt.subplot(2, 1, 1) |
||||
plt.hist(hashes, bins=REGISTER_MAP_SIZE) |
||||
plt.title("Number of collisions per hash") |
||||
plt.xlabel("Address") |
||||
|
||||
plt.subplot(2, 1, 2) |
||||
plt.hist(double_hashes, bins=REGISTER_MAP_SIZE) |
||||
plt.title("Number of collisions per double hash") |
||||
plt.xlabel("Address") |
||||
plt.show() |
@ -0,0 +1,35 @@ |
||||
#!/usr/bin/env python3 |
||||
import os |
||||
import sys |
||||
import time |
||||
import _thread |
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) |
||||
from panda import Panda |
||||
|
||||
# This script is intended to be used in conjunction with the echo_loopback_test.py test script from panda jungle. |
||||
# It sends a reversed response back for every message received containing b"test". |
||||
|
||||
def heartbeat_thread(p): |
||||
while True: |
||||
try: |
||||
p.send_heartbeat() |
||||
time.sleep(1) |
||||
except: |
||||
break |
||||
|
||||
# Resend every CAN message that has been received on the same bus, but with the data reversed |
||||
if __name__ == "__main__": |
||||
p = Panda() |
||||
_thread.start_new_thread(heartbeat_thread, (p,)) |
||||
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) |
||||
p.set_power_save(False) |
||||
|
||||
while True: |
||||
incoming = p.can_recv() |
||||
for message in incoming: |
||||
address, notused, data, bus = message |
||||
if b'test' in data: |
||||
p.can_send(address, data[::-1], bus) |
||||
|
||||
|
@ -0,0 +1 @@ |
||||
cppcheck/ |
@ -0,0 +1,36 @@ |
||||
from panda.tests.safety import libpandasafety_py |
||||
|
||||
def make_msg(bus, addr, length=8): |
||||
to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') |
||||
if addr >= 0x800: |
||||
to_send[0].RIR = (addr << 3) | 5 |
||||
else: |
||||
to_send[0].RIR = (addr << 21) | 1 |
||||
to_send[0].RDTR = length |
||||
to_send[0].RDTR |= bus << 4 |
||||
|
||||
return to_send |
||||
|
||||
def test_relay_malfunction(test, addr): |
||||
# input is a test class and the address that, if seen on bus 0, triggers |
||||
# the relay_malfunction protection logic: both tx_hook and fwd_hook are |
||||
# expected to return failure |
||||
test.assertFalse(test.safety.get_relay_malfunction()) |
||||
test.safety.safety_rx_hook(make_msg(0, addr, 8)) |
||||
test.assertTrue(test.safety.get_relay_malfunction()) |
||||
for a in range(1, 0x800): |
||||
for b in range(0, 3): |
||||
test.assertFalse(test.safety.safety_tx_hook(make_msg(b, a, 8))) |
||||
test.assertEqual(-1, test.safety.safety_fwd_hook(b, make_msg(b, a, 8))) |
||||
|
||||
def test_manually_enable_controls_allowed(test): |
||||
test.safety.set_controls_allowed(1) |
||||
test.assertTrue(test.safety.get_controls_allowed()) |
||||
test.safety.set_controls_allowed(0) |
||||
test.assertFalse(test.safety.get_controls_allowed()) |
||||
|
||||
def test_spam_can_buses(test, TX_MSGS): |
||||
for addr in range(1, 0x800): |
||||
for bus in range(0, 4): |
||||
if all(addr != m[0] or bus != m[1] for m in TX_MSGS): |
||||
test.assertFalse(test.safety.safety_tx_hook(make_msg(bus, addr, 8))) |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue