mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-07-25 14:52:03 +08:00
d5b884f824
0dcd84d7 Toyota safety: integer division bug 9a268f33 Toyota Safety: cleaner var types 8638650d bump panda version 9ab6a562 gmlan recv test a1a2d979 gmlan test 8efa3897 detect ack f5fab4b4 nicer err ad4d4231 add gmlan fail count bb41ff75 test 998f7c01 oops, set recessive 80051bea autoretry on chime 813218de GM: allowing higher brakes in Volt, so decel can reach between 3 and 3.5 m/s2 74ad3d65 GM: max param definitions 38a9ea9a added gm safety for steering (#123) bf5db45a Safety: made the driver steer check common so it can be shared across multiple safety files ef079e6d Safety: made rate limit check also common dc3cc240 Safety: made common the max torque check as well dbc3568a removing extra spaces 1966bdf3 Safety: made real time rate limit check a shared function e2144776 use timer for can bitbanging cb927337 minor bitbang refactor ed2920cf support extended addressing in canbitbang 36df0996 move speed be46c7a3 Merge pull request #122 from commaai/gmbitbang 7edc88e5 put that back fa66e4b7 Revert "handle rollover" 2ce3a26a handle rollover 223a1fb6 cleanin it up 1ba79077 that space tho d917386b bitbanging works 74af4417 can crc 932d7278 bit stuffing support be225227 bros ok match bros 55da0b65 rigol yea, dj pauly d yea a5775835 working on gmbitbang 875c2bd3 Cadillac: block OP messages if OP is on 7caba241 Addition to Bosch safety to support Hatchback (#111) 63ca46bc modify before we forward bf70f515 Safety: increase buffer for sampled signals. TBD a violation feedback from board to prevent car faults b0541a83 Cadillac: monitoring the 4 torque messages independently cd1dba9f Cadillac: fixed bug in regression safety ca0b6beb Cadillac: fixed typo. Need better regression tests to catch this d9f1e616 Cadillac: simplified the ignition code by removing the timeout logic and resetting controls_allowed = 0 at each init 293fd1ac GM: using real ignition logic. Creedit to Jamezz 8fa507b6 GM: simplified max steer check logic, Cadillac: fixed can parsing bug c7e2c2d6 Cadillac (#119) 83bcaa39 small logic cleanup (#118) 9d92bf27 Cadillac: need to specify car name in const 79ab5af8 Toyota: moved common functions into safety header file 40c8ddaf Cadillac ignition: simplified logic 69be556d Cadillac: better ignition logic d176220c Ignition: made a default hook for GPIO bea51874 Cadillac: added max steer safety dbc11a17 Cadillac: always controls allowed for now ace232a9 Cadillac: ignition bug e2c89d6b Cadillac: changed ignition logic to be based on can presence 528f901b Cadillac: simpler ignition logic 4e79ecf1 Cadillac: added safety file placeholder git-subtree-dir: panda git-subtree-split: 0dcd84d7912cd72d3aeaad4653007d1f178a1567
486 lines
13 KiB
C
486 lines
13 KiB
C
// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE, CAN2_TX, CAN2_RX0, CAN2_SCE, CAN3_TX, CAN3_RX0, CAN3_SCE
|
|
#define ALL_CAN_SILENT 0xFF
|
|
#define ALL_CAN_BUT_MAIN_SILENT 0xFE
|
|
#define ALL_CAN_LIVE 0
|
|
|
|
int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_SILENT;
|
|
|
|
// ********************* instantiate queues *********************
|
|
|
|
#define can_buffer(x, size) \
|
|
CAN_FIFOMailBox_TypeDef elems_##x[size]; \
|
|
can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = size, .elems = (CAN_FIFOMailBox_TypeDef *)&elems_##x };
|
|
|
|
can_buffer(rx_q, 0x1000)
|
|
can_buffer(tx1_q, 0x100)
|
|
can_buffer(tx2_q, 0x100)
|
|
|
|
#ifdef PANDA
|
|
can_buffer(tx3_q, 0x100)
|
|
can_buffer(txgmlan_q, 0x100)
|
|
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q, &can_txgmlan_q};
|
|
#else
|
|
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q};
|
|
#endif
|
|
|
|
// ********************* interrupt safe queue *********************
|
|
|
|
int can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) {
|
|
int ret = 0;
|
|
|
|
enter_critical_section();
|
|
if (q->w_ptr != q->r_ptr) {
|
|
*elem = q->elems[q->r_ptr];
|
|
if ((q->r_ptr + 1) == q->fifo_size) q->r_ptr = 0;
|
|
else q->r_ptr += 1;
|
|
ret = 1;
|
|
}
|
|
exit_critical_section();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int can_push(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) {
|
|
int ret = 0;
|
|
uint32_t next_w_ptr;
|
|
|
|
enter_critical_section();
|
|
if ((q->w_ptr + 1) == q->fifo_size) next_w_ptr = 0;
|
|
else next_w_ptr = q->w_ptr + 1;
|
|
if (next_w_ptr != q->r_ptr) {
|
|
q->elems[q->w_ptr] = *elem;
|
|
q->w_ptr = next_w_ptr;
|
|
ret = 1;
|
|
}
|
|
exit_critical_section();
|
|
if (ret == 0) puts("can_push failed!\n");
|
|
return ret;
|
|
}
|
|
|
|
void can_clear(can_ring *q) {
|
|
enter_critical_section();
|
|
q->w_ptr = 0;
|
|
q->r_ptr = 0;
|
|
exit_critical_section();
|
|
}
|
|
|
|
// assign CAN numbering
|
|
// bus num: Can bus number on ODB connector. Sent to/from USB
|
|
// Min: 0; Max: 127; Bit 7 marks message as receipt (bus 129 is receipt for but 1)
|
|
// cans: Look up MCU can interface from bus number
|
|
// can number: numeric lookup for MCU CAN interfaces (0 = CAN1, 1 = CAN2, etc);
|
|
// bus_lookup: Translates from 'can number' to 'bus number'.
|
|
// can_num_lookup: Translates from 'bus number' to 'can number'.
|
|
// can_forwarding: Given a bus num, lookup bus num to forward to. -1 means no forward.
|
|
|
|
int can_rx_cnt = 0;
|
|
int can_tx_cnt = 0;
|
|
int can_txd_cnt = 0;
|
|
int can_err_cnt = 0;
|
|
|
|
// NEO: Bus 1=CAN1 Bus 2=CAN2
|
|
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
|
|
#ifdef PANDA
|
|
CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3};
|
|
uint8_t bus_lookup[] = {0,1,2};
|
|
uint8_t can_num_lookup[] = {0,1,2,-1};
|
|
int8_t can_forwarding[] = {-1,-1,-1,-1};
|
|
uint32_t can_speed[] = {5000, 5000, 5000, 333};
|
|
bool can_autobaud_enabled[] = {false, false, false, false};
|
|
#define CAN_MAX 3
|
|
#else
|
|
CAN_TypeDef *cans[] = {CAN1, CAN2};
|
|
uint8_t bus_lookup[] = {1,0};
|
|
uint8_t can_num_lookup[] = {1,0};
|
|
int8_t can_forwarding[] = {-1,-1};
|
|
uint32_t can_speed[] = {5000, 5000};
|
|
bool can_autobaud_enabled[] = {false, false};
|
|
#define CAN_MAX 2
|
|
#endif
|
|
|
|
uint32_t can_autobaud_speeds[] = {5000, 2500, 1250, 1000, 10000};
|
|
#define AUTOBAUD_SPEEDS_LEN (sizeof(can_autobaud_speeds) / sizeof(can_autobaud_speeds[0]))
|
|
|
|
#define CANIF_FROM_CAN_NUM(num) (cans[num])
|
|
#ifdef PANDA
|
|
#define CAN_NUM_FROM_CANIF(CAN) (CAN==CAN1 ? 0 : (CAN==CAN2 ? 1 : 2))
|
|
#define CAN_NAME_FROM_CANIF(CAN) (CAN==CAN1 ? "CAN1" : (CAN==CAN2 ? "CAN2" : "CAN3"))
|
|
#else
|
|
#define CAN_NUM_FROM_CANIF(CAN) (CAN==CAN1 ? 0 : 1)
|
|
#define CAN_NAME_FROM_CANIF(CAN) (CAN==CAN1 ? "CAN1" : "CAN2")
|
|
#endif
|
|
#define BUS_NUM_FROM_CAN_NUM(num) (bus_lookup[num])
|
|
#define CAN_NUM_FROM_BUS_NUM(num) (can_num_lookup[num])
|
|
|
|
// other option
|
|
/*#define CAN_QUANTA 16
|
|
#define CAN_SEQ1 13
|
|
#define CAN_SEQ2 2*/
|
|
|
|
// this is needed for 1 mbps support
|
|
#define CAN_QUANTA 8
|
|
#define CAN_SEQ1 6 // roundf(quanta * 0.875f) - 1;
|
|
#define CAN_SEQ2 1 // roundf(quanta * 0.125f);
|
|
|
|
#define CAN_PCLK 24000
|
|
// 333 = 33.3 kbps
|
|
// 5000 = 500 kbps
|
|
#define can_speed_to_prescaler(x) (CAN_PCLK / CAN_QUANTA * 10 / (x))
|
|
|
|
void can_autobaud_speed_increment(uint8_t can_number) {
|
|
uint32_t autobaud_speed = can_autobaud_speeds[0];
|
|
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
|
|
for (int i = 0; i < AUTOBAUD_SPEEDS_LEN; i++) {
|
|
if (can_speed[bus_number] == can_autobaud_speeds[i]) {
|
|
if (i+1 < AUTOBAUD_SPEEDS_LEN) {
|
|
autobaud_speed = can_autobaud_speeds[i+1];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
can_speed[bus_number] = autobaud_speed;
|
|
#ifdef DEBUG
|
|
CAN_TypeDef* CAN = CANIF_FROM_CAN_NUM(can_number);
|
|
puts(CAN_NAME_FROM_CANIF(CAN));
|
|
puts(" auto-baud test ");
|
|
putui(can_speed[bus_number]);
|
|
puts(" cbps\n");
|
|
#endif
|
|
}
|
|
|
|
void process_can(uint8_t can_number);
|
|
|
|
void can_set_speed(uint8_t can_number) {
|
|
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
|
|
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
|
|
|
|
while (true) {
|
|
// initialization mode
|
|
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ;
|
|
while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK);
|
|
|
|
// set time quanta from defines
|
|
CAN->BTR = (CAN_BTR_TS1_0 * (CAN_SEQ1-1)) |
|
|
(CAN_BTR_TS2_0 * (CAN_SEQ2-1)) |
|
|
(can_speed_to_prescaler(can_speed[bus_number]) - 1);
|
|
|
|
// silent loopback mode for debugging
|
|
if (can_loopback) {
|
|
CAN->BTR |= CAN_BTR_SILM | CAN_BTR_LBKM;
|
|
}
|
|
if (can_silent & (1 << can_number)) {
|
|
CAN->BTR |= CAN_BTR_SILM;
|
|
}
|
|
|
|
// reset
|
|
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_ABOM;
|
|
|
|
#define CAN_TIMEOUT 1000000
|
|
int tmp = 0;
|
|
while((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK && tmp < CAN_TIMEOUT) tmp++;
|
|
if (tmp < CAN_TIMEOUT) {
|
|
return;
|
|
}
|
|
|
|
if (can_autobaud_enabled[bus_number]) {
|
|
can_autobaud_speed_increment(can_number);
|
|
} else {
|
|
puts("CAN init FAILED!!!!!\n");
|
|
puth(can_number); puts(" ");
|
|
puth(BUS_NUM_FROM_CAN_NUM(can_number)); puts("\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void can_init(uint8_t can_number) {
|
|
if (can_number == 0xff) return;
|
|
|
|
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
|
|
set_can_enable(CAN, 1);
|
|
can_set_speed(can_number);
|
|
|
|
// accept all filter
|
|
CAN->FMR |= CAN_FMR_FINIT;
|
|
|
|
// no mask
|
|
CAN->sFilterRegister[0].FR1 = 0;
|
|
CAN->sFilterRegister[0].FR2 = 0;
|
|
CAN->sFilterRegister[14].FR1 = 0;
|
|
CAN->sFilterRegister[14].FR2 = 0;
|
|
CAN->FA1R |= 1 | (1 << 14);
|
|
|
|
CAN->FMR &= ~(CAN_FMR_FINIT);
|
|
|
|
// enable certain CAN interrupts
|
|
CAN->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0;
|
|
|
|
switch (can_number) {
|
|
case 0:
|
|
NVIC_EnableIRQ(CAN1_TX_IRQn);
|
|
NVIC_EnableIRQ(CAN1_RX0_IRQn);
|
|
NVIC_EnableIRQ(CAN1_SCE_IRQn);
|
|
break;
|
|
case 1:
|
|
NVIC_EnableIRQ(CAN2_TX_IRQn);
|
|
NVIC_EnableIRQ(CAN2_RX0_IRQn);
|
|
NVIC_EnableIRQ(CAN2_SCE_IRQn);
|
|
break;
|
|
#ifdef CAN3
|
|
case 2:
|
|
NVIC_EnableIRQ(CAN3_TX_IRQn);
|
|
NVIC_EnableIRQ(CAN3_RX0_IRQn);
|
|
NVIC_EnableIRQ(CAN3_SCE_IRQn);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
// in case there are queued up messages
|
|
process_can(can_number);
|
|
}
|
|
|
|
void can_init_all() {
|
|
for (int i=0; i < CAN_MAX; i++) {
|
|
can_init(i);
|
|
}
|
|
}
|
|
|
|
void can_set_gmlan(int bus) {
|
|
#ifdef PANDA
|
|
if (bus == -1 || bus != can_num_lookup[3]) {
|
|
// GMLAN OFF
|
|
switch (can_num_lookup[3]) {
|
|
case 1:
|
|
puts("disable GMLAN on CAN2\n");
|
|
set_can_mode(1, 0);
|
|
bus_lookup[1] = 1;
|
|
can_num_lookup[1] = 1;
|
|
can_num_lookup[3] = -1;
|
|
can_init(1);
|
|
break;
|
|
case 2:
|
|
puts("disable GMLAN on CAN3\n");
|
|
set_can_mode(2, 0);
|
|
bus_lookup[2] = 2;
|
|
can_num_lookup[2] = 2;
|
|
can_num_lookup[3] = -1;
|
|
can_init(2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bus == 1) {
|
|
puts("GMLAN on CAN2\n");
|
|
// GMLAN on CAN2
|
|
set_can_mode(1, 1);
|
|
bus_lookup[1] = 3;
|
|
can_num_lookup[1] = -1;
|
|
can_num_lookup[3] = 1;
|
|
can_init(1);
|
|
} else if (bus == 2 && revision == PANDA_REV_C) {
|
|
puts("GMLAN on CAN3\n");
|
|
// GMLAN on CAN3
|
|
set_can_mode(2, 1);
|
|
bus_lookup[2] = 3;
|
|
can_num_lookup[2] = -1;
|
|
can_num_lookup[3] = 2;
|
|
can_init(2);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// CAN error
|
|
void can_sce(CAN_TypeDef *CAN) {
|
|
enter_critical_section();
|
|
|
|
can_err_cnt += 1;
|
|
#ifdef DEBUG
|
|
if (CAN==CAN1) puts("CAN1: ");
|
|
if (CAN==CAN2) puts("CAN2: ");
|
|
#ifdef CAN3
|
|
if (CAN==CAN3) puts("CAN3: ");
|
|
#endif
|
|
puts("MSR:");
|
|
puth(CAN->MSR);
|
|
puts(" TSR:");
|
|
puth(CAN->TSR);
|
|
puts(" RF0R:");
|
|
puth(CAN->RF0R);
|
|
puts(" RF1R:");
|
|
puth(CAN->RF1R);
|
|
puts(" ESR:");
|
|
puth(CAN->ESR);
|
|
puts("\n");
|
|
#endif
|
|
|
|
uint8_t can_number = CAN_NUM_FROM_CANIF(CAN);
|
|
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
|
|
if (can_autobaud_enabled[bus_number] && (CAN->ESR & CAN_ESR_LEC)) {
|
|
can_autobaud_speed_increment(can_number);
|
|
can_set_speed(can_number);
|
|
}
|
|
|
|
// clear current send
|
|
CAN->TSR |= CAN_TSR_ABRQ0;
|
|
CAN->MSR &= ~(CAN_MSR_ERRI);
|
|
CAN->MSR = CAN->MSR;
|
|
|
|
exit_critical_section();
|
|
}
|
|
|
|
// ***************************** CAN *****************************
|
|
|
|
void process_can(uint8_t can_number) {
|
|
if (can_number == 0xff) return;
|
|
|
|
enter_critical_section();
|
|
|
|
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
|
|
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
|
|
#ifdef DEBUG
|
|
puts("process CAN TX\n");
|
|
#endif
|
|
|
|
// check for empty mailbox
|
|
CAN_FIFOMailBox_TypeDef to_send;
|
|
if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) {
|
|
// add successfully transmitted message to my fifo
|
|
if ((CAN->TSR & CAN_TSR_RQCP0) == CAN_TSR_RQCP0) {
|
|
can_txd_cnt += 1;
|
|
|
|
if ((CAN->TSR & CAN_TSR_TXOK0) == CAN_TSR_TXOK0) {
|
|
CAN_FIFOMailBox_TypeDef to_push;
|
|
to_push.RIR = CAN->sTxMailBox[0].TIR;
|
|
to_push.RDTR = (CAN->sTxMailBox[0].TDTR & 0xFFFF000F) | ((CAN_BUS_RET_FLAG | bus_number) << 4);
|
|
to_push.RDLR = CAN->sTxMailBox[0].TDLR;
|
|
to_push.RDHR = CAN->sTxMailBox[0].TDHR;
|
|
can_push(&can_rx_q, &to_push);
|
|
}
|
|
|
|
if ((CAN->TSR & CAN_TSR_TERR0) == CAN_TSR_TERR0) {
|
|
#ifdef DEBUG
|
|
puts("CAN TX ERROR!\n");
|
|
#endif
|
|
}
|
|
|
|
if ((CAN->TSR & CAN_TSR_ALST0) == CAN_TSR_ALST0) {
|
|
#ifdef DEBUG
|
|
puts("CAN TX ARBITRATION LOST!\n");
|
|
#endif
|
|
}
|
|
|
|
// clear interrupt
|
|
// careful, this can also be cleared by requesting a transmission
|
|
CAN->TSR |= CAN_TSR_RQCP0;
|
|
}
|
|
|
|
if (can_pop(can_queues[bus_number], &to_send)) {
|
|
can_tx_cnt += 1;
|
|
// only send if we have received a packet
|
|
CAN->sTxMailBox[0].TDLR = to_send.RDLR;
|
|
CAN->sTxMailBox[0].TDHR = to_send.RDHR;
|
|
CAN->sTxMailBox[0].TDTR = to_send.RDTR;
|
|
CAN->sTxMailBox[0].TIR = to_send.RIR;
|
|
}
|
|
}
|
|
|
|
exit_critical_section();
|
|
}
|
|
|
|
// CAN receive handlers
|
|
// blink blue when we are receiving CAN messages
|
|
void can_rx(uint8_t can_number) {
|
|
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
|
|
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
|
|
while (CAN->RF0R & CAN_RF0R_FMP0) {
|
|
if (can_autobaud_enabled[bus_number]) {
|
|
can_autobaud_enabled[bus_number] = false;
|
|
puts(CAN_NAME_FROM_CANIF(CAN));
|
|
#ifdef DEBUG
|
|
puts(" auto-baud ");
|
|
putui(can_speed[bus_number]);
|
|
puts(" cbps\n");
|
|
#endif
|
|
}
|
|
|
|
can_rx_cnt += 1;
|
|
|
|
// can is live
|
|
pending_can_live = 1;
|
|
|
|
// add to my fifo
|
|
CAN_FIFOMailBox_TypeDef to_push;
|
|
to_push.RIR = CAN->sFIFOMailBox[0].RIR;
|
|
to_push.RDTR = CAN->sFIFOMailBox[0].RDTR;
|
|
to_push.RDLR = CAN->sFIFOMailBox[0].RDLR;
|
|
to_push.RDHR = CAN->sFIFOMailBox[0].RDHR;
|
|
|
|
// modify RDTR for our API
|
|
to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (bus_number << 4);
|
|
|
|
// forwarding (panda only)
|
|
#ifdef PANDA
|
|
int bus_fwd_num = can_forwarding[bus_number] != -1 ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push);
|
|
if (bus_fwd_num != -1) {
|
|
CAN_FIFOMailBox_TypeDef to_send;
|
|
to_send.RIR = to_push.RIR | 1; // TXRQ
|
|
to_send.RDTR = to_push.RDTR;
|
|
to_send.RDLR = to_push.RDLR;
|
|
to_send.RDHR = to_push.RDHR;
|
|
can_send(&to_send, bus_fwd_num);
|
|
}
|
|
#endif
|
|
|
|
safety_rx_hook(&to_push);
|
|
|
|
#ifdef PANDA
|
|
set_led(LED_BLUE, 1);
|
|
#endif
|
|
can_push(&can_rx_q, &to_push);
|
|
|
|
// next
|
|
CAN->RF0R |= CAN_RF0R_RFOM0;
|
|
}
|
|
}
|
|
|
|
#ifndef CUSTOM_CAN_INTERRUPTS
|
|
|
|
void CAN1_TX_IRQHandler() { process_can(0); }
|
|
void CAN1_RX0_IRQHandler() { can_rx(0); }
|
|
void CAN1_SCE_IRQHandler() { can_sce(CAN1); }
|
|
|
|
void CAN2_TX_IRQHandler() { process_can(1); }
|
|
void CAN2_RX0_IRQHandler() { can_rx(1); }
|
|
void CAN2_SCE_IRQHandler() { can_sce(CAN2); }
|
|
|
|
#ifdef CAN3
|
|
void CAN3_TX_IRQHandler() { process_can(2); }
|
|
void CAN3_RX0_IRQHandler() { can_rx(2); }
|
|
void CAN3_SCE_IRQHandler() { can_sce(CAN3); }
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#include "canbitbang.h"
|
|
|
|
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) {
|
|
if (safety_tx_hook(to_push) && !can_autobaud_enabled[bus_number]) {
|
|
if (bus_number < BUS_MAX) {
|
|
// add CAN packet to send queue
|
|
// bus number isn't passed through
|
|
to_push->RDTR &= 0xF;
|
|
if (bus_number == 3 && can_num_lookup[3] == 0xFF) {
|
|
// TODO: why uint8 bro? only int8?
|
|
bitbang_gmlan(to_push);
|
|
} else {
|
|
can_push(can_queues[bus_number], to_push);
|
|
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void can_set_forwarding(int from, int to) {
|
|
can_forwarding[from] = to;
|
|
}
|