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 compliance
master
Greg Hogan 2020-06-18 11:17:00 -07:00 committed by GitHub
parent 1e6854eb8f
commit 31f8a0d862
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 52 deletions

View File

@ -273,15 +273,27 @@ void uart_set_baud(USART_TypeDef *u, unsigned int baud) {
void uart_init(uart_ring *q, int baud) {
// Register interrupts (max data rate: 115200 baud)
REGISTER_INTERRUPT(USART1_IRQn, USART1_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_1)
REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2)
REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3)
REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5)
REGISTER_INTERRUPT(DMA2_Stream5_IRQn, DMA2_Stream5_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_UART_DMA) // Called twice per buffer
if(q->uart == USART1){
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)
} else if (q->uart == USART3){
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)
} 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
}
// Set baud and enable peripheral with TX and RX mode
uart_set_baud(q->uart, baud);
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
if(q->uart == USART1){

View File

@ -249,8 +249,11 @@ void usb_cb_enumeration_complete() {
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) {
unsigned int resp_len = 0;
uart_ring *ur = NULL;
int i;
uint32_t ts;
uint32_t ts_timer;
timestamp_t t;
bool k_wakeup;
bool l_wakeup;
switch (setup->b.bRequest) {
// **** 0xa0: get rtc time
case 0xa0:
@ -557,38 +560,45 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
case 0xe7:
set_power_save_state(setup->b.wValue.w);
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:
if (setup->b.wValue.w == 1U) {
GPIOC->ODR &= ~(1U << 10);
GPIOC->MODER &= ~GPIO_MODER_MODER10_1;
GPIOC->MODER |= GPIO_MODER_MODER10_0;
} else {
GPIOC->ODR &= ~(1U << 12);
GPIOC->MODER &= ~GPIO_MODER_MODER12_1;
GPIOC->MODER |= GPIO_MODER_MODER12_0;
k_wakeup = (setup->b.wValue.w == 0U) || (setup->b.wValue.w == 2U);
l_wakeup = (setup->b.wValue.w == 1U) || (setup->b.wValue.w == 2U);
ts = TIM2->CNT;
ts_timer = ts;
if (k_wakeup) {
set_gpio_output(GPIOC, 12, false);
}
if (l_wakeup) {
set_gpio_output(GPIOC, 10, false);
}
for (i = 0; i < 80; i++) {
delay(8000);
if (setup->b.wValue.w == 1U) {
GPIOC->ODR |= (1U << 10);
GPIOC->ODR &= ~(1U << 10);
} else {
GPIOC->ODR |= (1U << 12);
GPIOC->ODR &= ~(1U << 12);
// hold low for 25 ms
while (get_ts_elapsed(TIM2->CNT, ts) < 25000U) {
// toggle pin every 5 ms to reset TXD dominant time-out timer
if (get_ts_elapsed(TIM2->CNT, ts_timer) >= 5000U) {
ts_timer = TIM2->CNT;
if (k_wakeup) {
register_set_bits(&(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) {
GPIOC->MODER &= ~GPIO_MODER_MODER10_0;
GPIOC->MODER |= GPIO_MODER_MODER10_1;
} else {
GPIOC->MODER &= ~GPIO_MODER_MODER12_0;
GPIOC->MODER |= GPIO_MODER_MODER12_1;
if (k_wakeup) {
set_gpio_mode(GPIOC, 12, MODE_ALTERNATE);
}
delay(140 * 9000);
if (l_wakeup) {
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;
// **** 0xf1: Clear CAN ring buffer.
case 0xf1:

View File

@ -1,6 +1,5 @@
# python library to interface with panda
import datetime
import binascii
import struct
import hashlib
import socket
@ -44,7 +43,7 @@ def parse_can_buffer(dat):
address = f1 >> 21
dddat = ddat[8:8 + (f2 & 0xF)]
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))
return ret
@ -489,7 +488,7 @@ class Panda(object):
for addr, _, dat, bus in arr:
assert len(dat) <= 8
if DEBUG:
print(" W %x: %s" % (addr, binascii.hexlify(dat)))
print(f" W 0x{addr:x}: 0x{dat.hex()}")
if addr >= 0x800:
rir = (addr << 3) | transmit | extended
else:
@ -572,10 +571,11 @@ class Panda(object):
# ******************* kline *******************
# 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:
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:
print("kline wakeup done")
@ -587,7 +587,7 @@ class Panda(object):
if len(ret) == 0:
break
elif DEBUG:
print("kline drain: " + binascii.hexlify(ret))
print(f"kline drain: 0x{ret.hex()}")
bret += ret
return bytes(bret)
@ -596,35 +596,31 @@ class Panda(object):
while len(echo) != cnt:
ret = self._handle.controlRead(Panda.REQUEST_OUT, 0xe0, bus, 0, cnt - len(echo))
if DEBUG and len(ret) > 0:
print("kline recv: " + binascii.hexlify(ret))
print(f"kline recv: 0x{ret.hex()}")
echo += ret
return bytes(echo)
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)
if checksum:
x += get_checksum(x)
x += bytes([sum(x) % 0x100])
for i in range(0, len(x), 0xf):
ts = x[i:i + 0xf]
if DEBUG:
print("kline send: " + binascii.hexlify(ts))
print(f"kline send: 0x{ts.hex()}")
self._handle.bulkWrite(2, bytes([bus]) + ts)
echo = self.kline_ll_recv(len(ts), bus=bus)
if echo != ts:
print("**** ECHO ERROR %d ****" % i)
print(binascii.hexlify(echo))
print(binascii.hexlify(ts))
print(f"**** ECHO ERROR {i} ****")
print(f"0x{echo.hex()}")
print(f"0x{ts.hex()}")
assert echo == ts
def kline_recv(self, bus=2):
msg = self.kline_ll_recv(2, bus=bus)
msg += self.kline_ll_recv(ord(msg[1]) - 2, bus=bus)
def kline_recv(self, bus=2, header_len=4):
# read header (last byte is length)
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
def send_heartbeat(self):