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) {
|
||||
// Register interrupts (max data rate: 115200 baud)
|
||||
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){
|
||||
|
|
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) {
|
||||
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:
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue