diff --git a/board/drivers/can.h b/board/drivers/can.h index d5daa054d516d7..cd809704b9a407 100644 --- a/board/drivers/can.h +++ b/board/drivers/can.h @@ -461,14 +461,21 @@ void CAN3_SCE_IRQHandler() { can_sce(CAN3); } #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; - can_push(can_queues[bus_number], to_push); - process_can(CAN_NUM_FROM_BUS_NUM(bus_number)); + 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)); + } } } } diff --git a/board/drivers/canbitbang.h b/board/drivers/canbitbang.h new file mode 100644 index 00000000000000..608f286cc44459 --- /dev/null +++ b/board/drivers/canbitbang.h @@ -0,0 +1,156 @@ +#define MAX_BITS_CAN_PACKET (64+44+25) + +// returns out_len +int do_bitstuff(char *out, char *in, int in_len) { + int last_bit = -1; + int bit_cnt = 0; + int j = 0; + for (int i = 0; i < in_len; i++) { + char bit = in[i]; + out[j++] = bit; + + // do the stuffing + if (bit == last_bit) { + bit_cnt++; + if (bit_cnt == 5) { + // 5 in a row the same, do stuff + last_bit = !bit; + out[j++] = last_bit; + bit_cnt = 1; + } + } else { + // this is a new bit + last_bit = bit; + bit_cnt = 1; + } + } + return j; +} + +int append_crc(char *in, int in_len) { + int crc = 0; + for (int i = 0; i < in_len; i++) { + crc <<= 1; + if (in[i] ^ ((crc>>15)&1)) { + crc = crc ^ 0x4599; + } + crc &= 0x7fff; + } + for (int i = 14; i >= 0; i--) { + in[in_len++] = (crc>>i)&1; + } + return in_len; +} + +int append_bits(char *in, int in_len, char *app, int app_len) { + for (int i = 0; i < app_len; i++) { + in[in_len++] = app[i]; + } + return in_len; +} + +int append_int(char *in, int in_len, int val, int val_len) { + for (int i = val_len-1; i >= 0; i--) { + in[in_len++] = (val&(1<RDTR & 0xF; + len = append_int(pkt, len, 0, 1); // Start-of-frame + len = append_int(pkt, len, to_bang->RIR >> 21, 11); // Identifier + len = append_int(pkt, len, 0, 3); // RTR+IDE+reserved + len = append_int(pkt, len, dlc_len, 4); // Data length code + + // append data + for (int i = 0; i < dlc_len; i++) { + unsigned char dat = ((unsigned char *)(&(to_bang->RDLR)))[i]; + len = append_int(pkt, len, dat, 8); + } + + // append crc + len = append_crc(pkt, len); + + // do bitstuffing + len = do_bitstuff(out, pkt, len); + + // append footer + len = append_bits(out, len, footer, sizeof(footer)); + return len; +} + +// hardware stuff below this line + +#ifdef PANDA + +void set_bitbanged_gmlan(int val) { + if (val) { + GPIOB->ODR |= (1 << 13); + } else { + GPIOB->ODR &= ~(1 << 13); + } +} + +void bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) { + puts("called bitbang_gmlan\n"); + + char pkt_stuffed[MAX_BITS_CAN_PACKET]; + int len = get_bit_message(pkt_stuffed, to_bang); + + // actual bitbang loop + set_bitbanged_gmlan(1); // recessive + set_gpio_mode(GPIOB, 13, MODE_OUTPUT); + enter_critical_section(); + + // wait for bus silent for 7 frames + int silent_count = 0; + while (silent_count < 7) { + int read = get_gpio_input(GPIOB, 12); + silent_count++; + if (read == 0) { + silent_count = 0; + } + int lwait = TIM2->CNT; + while (get_ts_elapsed(TIM2->CNT, lwait) < SPEEED); + } + + // send my message with optional failure + int last = 1; + int init = TIM2->CNT; + for (int i = 0; i < len; i++) { + while (get_ts_elapsed(TIM2->CNT, init) < (SPEEED*i)); + int read = get_gpio_input(GPIOB, 12); + if ((read == 0 && last == 1) && i != (len-11)) { + puts("ERR: bus driven at "); + puth(i); + puts("\n"); + goto fail; + } + set_bitbanged_gmlan(pkt_stuffed[i]); + last = pkt_stuffed[i]; + } + +fail: + set_bitbanged_gmlan(1); // recessive + exit_critical_section(); + set_gpio_mode(GPIOB, 13, MODE_INPUT); + + puts("bitbang done\n"); +} + +#endif + diff --git a/tests/gmbitbang/rigol.py b/tests/gmbitbang/rigol.py new file mode 100755 index 00000000000000..3d690fdd84c725 --- /dev/null +++ b/tests/gmbitbang/rigol.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +import numpy as np +import visa +import matplotlib.pyplot as plt + +resources = visa.ResourceManager() +print resources.list_resources() + +scope = resources.open_resource('USB0::0x1AB1::0x04CE::DS1ZA184652242::INSTR', timeout=2000, chunk_size=1024000) +print(scope.query('*IDN?').strip()) + +#voltscale = scope.ask_for_values(':CHAN1:SCAL?')[0] +#voltoffset = scope.ask_for_values(":CHAN1:OFFS?")[0] + +#scope.write(":STOP") +scope.write(":WAV:POIN:MODE RAW") +scope.write(":WAV:DATA? CHAN1")[10:] +rawdata = scope.read_raw() +data = np.frombuffer(rawdata, 'B') +print data.shape + +s1 = data[0:650] +s2 = data[650:] +s1i = np.argmax(s1 > 100) +s2i = np.argmax(s2 > 100) +s1 = s1[s1i:] +s2 = s2[s2i:] + +plt.plot(s1) +plt.plot(s2) +plt.show() +#data = (data - 130.0 - voltoffset/voltscale*25) / 25 * voltscale + +print data + diff --git a/tests/gmbitbang/test.py b/tests/gmbitbang/test.py new file mode 100755 index 00000000000000..987bb682053dc9 --- /dev/null +++ b/tests/gmbitbang/test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +import time +from panda import Panda + +p1 = Panda('430026000951363338383037') +p2 = Panda('380016000551363338383037') + +# this is a test, no safety +p1.set_safety_mode(Panda.SAFETY_ALLOUTPUT) +p2.set_safety_mode(Panda.SAFETY_ALLOUTPUT) + +# get versions +print(p1.get_version()) +print(p2.get_version()) + +# this sets bus 2 to actually be GMLAN +p2.set_gmlan(bus=2) + +# send w bitbang then without +while 1: + p1.set_gmlan(bus=None) + p1.can_send(123, "\x01\x02\x03\x04\x05\x06\x07\x08", bus=3) + p1.set_gmlan(bus=2) + p1.can_send(123, "\x01\x02\x03\x04\x05\x06\x07\x08", bus=3) + time.sleep(0.01) + print p2.can_recv() + exit(0) + diff --git a/tests/gmbitbang/test_packer.c b/tests/gmbitbang/test_packer.c new file mode 100644 index 00000000000000..f056dd48125d34 --- /dev/null +++ b/tests/gmbitbang/test_packer.c @@ -0,0 +1,32 @@ +#include +#include + +typedef struct { + uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */ + uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */ + uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */ + uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */ +} CAN_FIFOMailBox_TypeDef; + +#include "../../board/drivers/canbitbang.h" + +int main() { + char out[300]; + CAN_FIFOMailBox_TypeDef to_bang = {0}; + to_bang.RIR = 20 << 21; + to_bang.RDTR = 1; + to_bang.RDLR = 1; + + int len = get_bit_message(out, &to_bang); + printf("T:"); + for (int i = 0; i < len; i++) { + printf("%d", out[i]); + } + printf("\n"); + printf("R:0000010010100000100010000010011110111010100111111111111111"); + printf("\n"); + return 0; +} + + +