K line fix (#559)
* enable UART RX interrupts * update debug prints for python3 * improve kline functions and fix checksum * k-line wake-up conforming to KWP2000 fast init * fix timing * toggle k and l line together by default * k-line wakeup using timer * k and l were flipped * fix misra compliancemaster
parent
1e6854eb8f
commit
31f8a0d862
|
@ -273,15 +273,27 @@ void uart_set_baud(USART_TypeDef *u, unsigned int baud) {
|
||||||
|
|
||||||
void uart_init(uart_ring *q, int baud) {
|
void uart_init(uart_ring *q, int baud) {
|
||||||
// Register interrupts (max data rate: 115200 baud)
|
// Register interrupts (max data rate: 115200 baud)
|
||||||
|
if(q->uart == USART1){
|
||||||
REGISTER_INTERRUPT(USART1_IRQn, USART1_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_1)
|
REGISTER_INTERRUPT(USART1_IRQn, USART1_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_1)
|
||||||
|
} else if (q->uart == USART2){
|
||||||
REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2)
|
REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2)
|
||||||
|
} else if (q->uart == USART3){
|
||||||
REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3)
|
REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3)
|
||||||
|
} else if (q->uart == UART5){
|
||||||
REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5)
|
REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5)
|
||||||
|
} else {
|
||||||
|
// UART not used. Skip registering interrupts
|
||||||
|
}
|
||||||
|
if(q->dma_rx){
|
||||||
REGISTER_INTERRUPT(DMA2_Stream5_IRQn, DMA2_Stream5_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_UART_DMA) // Called twice per buffer
|
REGISTER_INTERRUPT(DMA2_Stream5_IRQn, DMA2_Stream5_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_UART_DMA) // Called twice per buffer
|
||||||
|
}
|
||||||
|
|
||||||
// Set baud and enable peripheral with TX and RX mode
|
// Set baud and enable peripheral with TX and RX mode
|
||||||
uart_set_baud(q->uart, baud);
|
uart_set_baud(q->uart, baud);
|
||||||
q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||||
|
if ((q->uart == USART2) || (q->uart == USART3) || (q->uart == UART5)) {
|
||||||
|
q->uart->CR1 |= USART_CR1_RXNEIE;
|
||||||
|
}
|
||||||
|
|
||||||
// Enable UART interrupts
|
// Enable UART interrupts
|
||||||
if(q->uart == USART1){
|
if(q->uart == USART1){
|
||||||
|
|
62
board/main.c
62
board/main.c
|
@ -249,8 +249,11 @@ void usb_cb_enumeration_complete() {
|
||||||
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) {
|
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) {
|
||||||
unsigned int resp_len = 0;
|
unsigned int resp_len = 0;
|
||||||
uart_ring *ur = NULL;
|
uart_ring *ur = NULL;
|
||||||
int i;
|
uint32_t ts;
|
||||||
|
uint32_t ts_timer;
|
||||||
timestamp_t t;
|
timestamp_t t;
|
||||||
|
bool k_wakeup;
|
||||||
|
bool l_wakeup;
|
||||||
switch (setup->b.bRequest) {
|
switch (setup->b.bRequest) {
|
||||||
// **** 0xa0: get rtc time
|
// **** 0xa0: get rtc time
|
||||||
case 0xa0:
|
case 0xa0:
|
||||||
|
@ -557,38 +560,45 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
|
||||||
case 0xe7:
|
case 0xe7:
|
||||||
set_power_save_state(setup->b.wValue.w);
|
set_power_save_state(setup->b.wValue.w);
|
||||||
break;
|
break;
|
||||||
// **** 0xf0: do k-line wValue pulse on uart2 for Acura
|
// **** 0xf0: k-line/l-line wake-up pulse for KWP2000 fast initialization
|
||||||
case 0xf0:
|
case 0xf0:
|
||||||
if (setup->b.wValue.w == 1U) {
|
k_wakeup = (setup->b.wValue.w == 0U) || (setup->b.wValue.w == 2U);
|
||||||
GPIOC->ODR &= ~(1U << 10);
|
l_wakeup = (setup->b.wValue.w == 1U) || (setup->b.wValue.w == 2U);
|
||||||
GPIOC->MODER &= ~GPIO_MODER_MODER10_1;
|
|
||||||
GPIOC->MODER |= GPIO_MODER_MODER10_0;
|
ts = TIM2->CNT;
|
||||||
} else {
|
ts_timer = ts;
|
||||||
GPIOC->ODR &= ~(1U << 12);
|
if (k_wakeup) {
|
||||||
GPIOC->MODER &= ~GPIO_MODER_MODER12_1;
|
set_gpio_output(GPIOC, 12, false);
|
||||||
GPIOC->MODER |= GPIO_MODER_MODER12_0;
|
}
|
||||||
|
if (l_wakeup) {
|
||||||
|
set_gpio_output(GPIOC, 10, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 80; i++) {
|
// hold low for 25 ms
|
||||||
delay(8000);
|
while (get_ts_elapsed(TIM2->CNT, ts) < 25000U) {
|
||||||
if (setup->b.wValue.w == 1U) {
|
// toggle pin every 5 ms to reset TXD dominant time-out timer
|
||||||
GPIOC->ODR |= (1U << 10);
|
if (get_ts_elapsed(TIM2->CNT, ts_timer) >= 5000U) {
|
||||||
GPIOC->ODR &= ~(1U << 10);
|
ts_timer = TIM2->CNT;
|
||||||
} else {
|
if (k_wakeup) {
|
||||||
GPIOC->ODR |= (1U << 12);
|
register_set_bits(&(GPIOC->ODR), (1U << 12));
|
||||||
GPIOC->ODR &= ~(1U << 12);
|
register_clear_bits(&(GPIOC->ODR), (1U << 12));
|
||||||
|
}
|
||||||
|
if (l_wakeup) {
|
||||||
|
register_set_bits(&(GPIOC->ODR), (1U << 10));
|
||||||
|
register_clear_bits(&(GPIOC->ODR), (1U << 10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setup->b.wValue.w == 1U) {
|
if (k_wakeup) {
|
||||||
GPIOC->MODER &= ~GPIO_MODER_MODER10_0;
|
set_gpio_mode(GPIOC, 12, MODE_ALTERNATE);
|
||||||
GPIOC->MODER |= GPIO_MODER_MODER10_1;
|
|
||||||
} else {
|
|
||||||
GPIOC->MODER &= ~GPIO_MODER_MODER12_0;
|
|
||||||
GPIOC->MODER |= GPIO_MODER_MODER12_1;
|
|
||||||
}
|
}
|
||||||
|
if (l_wakeup) {
|
||||||
delay(140 * 9000);
|
set_gpio_mode(GPIOC, 10, MODE_ALTERNATE);
|
||||||
|
}
|
||||||
|
// hold high until 49ms have passed
|
||||||
|
// (start communication needs to follow 49ms to 51ms after start of wakeup)
|
||||||
|
while (get_ts_elapsed(TIM2->CNT, ts) < 49000U) {}
|
||||||
break;
|
break;
|
||||||
// **** 0xf1: Clear CAN ring buffer.
|
// **** 0xf1: Clear CAN ring buffer.
|
||||||
case 0xf1:
|
case 0xf1:
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# python library to interface with panda
|
# python library to interface with panda
|
||||||
import datetime
|
import datetime
|
||||||
import binascii
|
|
||||||
import struct
|
import struct
|
||||||
import hashlib
|
import hashlib
|
||||||
import socket
|
import socket
|
||||||
|
@ -44,7 +43,7 @@ def parse_can_buffer(dat):
|
||||||
address = f1 >> 21
|
address = f1 >> 21
|
||||||
dddat = ddat[8:8 + (f2 & 0xF)]
|
dddat = ddat[8:8 + (f2 & 0xF)]
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(" R %x: %s" % (address, binascii.hexlify(dddat)))
|
print(f" R 0x{address:x}: 0x{dddat.hex()}")
|
||||||
ret.append((address, f2 >> 16, dddat, (f2 >> 4) & 0xFF))
|
ret.append((address, f2 >> 16, dddat, (f2 >> 4) & 0xFF))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -489,7 +488,7 @@ class Panda(object):
|
||||||
for addr, _, dat, bus in arr:
|
for addr, _, dat, bus in arr:
|
||||||
assert len(dat) <= 8
|
assert len(dat) <= 8
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(" W %x: %s" % (addr, binascii.hexlify(dat)))
|
print(f" W 0x{addr:x}: 0x{dat.hex()}")
|
||||||
if addr >= 0x800:
|
if addr >= 0x800:
|
||||||
rir = (addr << 3) | transmit | extended
|
rir = (addr << 3) | transmit | extended
|
||||||
else:
|
else:
|
||||||
|
@ -572,10 +571,11 @@ class Panda(object):
|
||||||
# ******************* kline *******************
|
# ******************* kline *******************
|
||||||
|
|
||||||
# pulse low for wakeup
|
# pulse low for wakeup
|
||||||
def kline_wakeup(self):
|
def kline_wakeup(self, k=True, l=True):
|
||||||
|
assert k or l, "must specify k-line, l-line, or both"
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("kline wakeup...")
|
print("kline wakeup...")
|
||||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf0, 0, 0, b'')
|
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf0, 2 if k and l else int(l), 0, b'')
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("kline wakeup done")
|
print("kline wakeup done")
|
||||||
|
|
||||||
|
@ -587,7 +587,7 @@ class Panda(object):
|
||||||
if len(ret) == 0:
|
if len(ret) == 0:
|
||||||
break
|
break
|
||||||
elif DEBUG:
|
elif DEBUG:
|
||||||
print("kline drain: " + binascii.hexlify(ret))
|
print(f"kline drain: 0x{ret.hex()}")
|
||||||
bret += ret
|
bret += ret
|
||||||
return bytes(bret)
|
return bytes(bret)
|
||||||
|
|
||||||
|
@ -596,35 +596,31 @@ class Panda(object):
|
||||||
while len(echo) != cnt:
|
while len(echo) != cnt:
|
||||||
ret = self._handle.controlRead(Panda.REQUEST_OUT, 0xe0, bus, 0, cnt - len(echo))
|
ret = self._handle.controlRead(Panda.REQUEST_OUT, 0xe0, bus, 0, cnt - len(echo))
|
||||||
if DEBUG and len(ret) > 0:
|
if DEBUG and len(ret) > 0:
|
||||||
print("kline recv: " + binascii.hexlify(ret))
|
print(f"kline recv: 0x{ret.hex()}")
|
||||||
echo += ret
|
echo += ret
|
||||||
return bytes(echo)
|
return bytes(echo)
|
||||||
|
|
||||||
def kline_send(self, x, bus=2, checksum=True):
|
def kline_send(self, x, bus=2, checksum=True):
|
||||||
def get_checksum(dat):
|
|
||||||
result = 0
|
|
||||||
result += sum(map(ord, dat)) if isinstance(b'dat', str) else sum(dat)
|
|
||||||
result = -result
|
|
||||||
return struct.pack("B", result % 0x100)
|
|
||||||
|
|
||||||
self.kline_drain(bus=bus)
|
self.kline_drain(bus=bus)
|
||||||
if checksum:
|
if checksum:
|
||||||
x += get_checksum(x)
|
x += bytes([sum(x) % 0x100])
|
||||||
for i in range(0, len(x), 0xf):
|
for i in range(0, len(x), 0xf):
|
||||||
ts = x[i:i + 0xf]
|
ts = x[i:i + 0xf]
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("kline send: " + binascii.hexlify(ts))
|
print(f"kline send: 0x{ts.hex()}")
|
||||||
self._handle.bulkWrite(2, bytes([bus]) + ts)
|
self._handle.bulkWrite(2, bytes([bus]) + ts)
|
||||||
echo = self.kline_ll_recv(len(ts), bus=bus)
|
echo = self.kline_ll_recv(len(ts), bus=bus)
|
||||||
if echo != ts:
|
if echo != ts:
|
||||||
print("**** ECHO ERROR %d ****" % i)
|
print(f"**** ECHO ERROR {i} ****")
|
||||||
print(binascii.hexlify(echo))
|
print(f"0x{echo.hex()}")
|
||||||
print(binascii.hexlify(ts))
|
print(f"0x{ts.hex()}")
|
||||||
assert echo == ts
|
assert echo == ts
|
||||||
|
|
||||||
def kline_recv(self, bus=2):
|
def kline_recv(self, bus=2, header_len=4):
|
||||||
msg = self.kline_ll_recv(2, bus=bus)
|
# read header (last byte is length)
|
||||||
msg += self.kline_ll_recv(ord(msg[1]) - 2, bus=bus)
|
msg = self.kline_ll_recv(header_len, bus=bus)
|
||||||
|
# read data (add one byte to length for checksum)
|
||||||
|
msg += self.kline_ll_recv(msg[-1]+1, bus=bus)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def send_heartbeat(self):
|
def send_heartbeat(self):
|
||||||
|
|
Loading…
Reference in New Issue