Skip to content

Commit be46c7a

Browse files
authored
Merge pull request #122 from commaai/gmbitbang
Gmbitbang
2 parents 875c2bd + 7edc88e commit be46c7a

File tree

5 files changed

+260
-2
lines changed

5 files changed

+260
-2
lines changed

board/drivers/can.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -461,14 +461,21 @@ void CAN3_SCE_IRQHandler() { can_sce(CAN3); }
461461

462462
#endif
463463

464+
#include "canbitbang.h"
465+
464466
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) {
465467
if (safety_tx_hook(to_push) && !can_autobaud_enabled[bus_number]) {
466468
if (bus_number < BUS_MAX) {
467469
// add CAN packet to send queue
468470
// bus number isn't passed through
469471
to_push->RDTR &= 0xF;
470-
can_push(can_queues[bus_number], to_push);
471-
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
472+
if (bus_number == 3 && can_num_lookup[3] == 0xFF) {
473+
// TODO: why uint8 bro? only int8?
474+
bitbang_gmlan(to_push);
475+
} else {
476+
can_push(can_queues[bus_number], to_push);
477+
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
478+
}
472479
}
473480
}
474481
}

board/drivers/canbitbang.h

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#define MAX_BITS_CAN_PACKET (64+44+25)
2+
3+
// returns out_len
4+
int do_bitstuff(char *out, char *in, int in_len) {
5+
int last_bit = -1;
6+
int bit_cnt = 0;
7+
int j = 0;
8+
for (int i = 0; i < in_len; i++) {
9+
char bit = in[i];
10+
out[j++] = bit;
11+
12+
// do the stuffing
13+
if (bit == last_bit) {
14+
bit_cnt++;
15+
if (bit_cnt == 5) {
16+
// 5 in a row the same, do stuff
17+
last_bit = !bit;
18+
out[j++] = last_bit;
19+
bit_cnt = 1;
20+
}
21+
} else {
22+
// this is a new bit
23+
last_bit = bit;
24+
bit_cnt = 1;
25+
}
26+
}
27+
return j;
28+
}
29+
30+
int append_crc(char *in, int in_len) {
31+
int crc = 0;
32+
for (int i = 0; i < in_len; i++) {
33+
crc <<= 1;
34+
if (in[i] ^ ((crc>>15)&1)) {
35+
crc = crc ^ 0x4599;
36+
}
37+
crc &= 0x7fff;
38+
}
39+
for (int i = 14; i >= 0; i--) {
40+
in[in_len++] = (crc>>i)&1;
41+
}
42+
return in_len;
43+
}
44+
45+
int append_bits(char *in, int in_len, char *app, int app_len) {
46+
for (int i = 0; i < app_len; i++) {
47+
in[in_len++] = app[i];
48+
}
49+
return in_len;
50+
}
51+
52+
int append_int(char *in, int in_len, int val, int val_len) {
53+
for (int i = val_len-1; i >= 0; i--) {
54+
in[in_len++] = (val&(1<<i)) != 0;
55+
}
56+
return in_len;
57+
}
58+
59+
int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) {
60+
char pkt[MAX_BITS_CAN_PACKET];
61+
char footer[] = {
62+
1, // CRC delimiter
63+
1, // ACK
64+
1, // ACK delimiter
65+
1,1,1,1,1,1,1, // EOF
66+
1,1,1, // IFS
67+
};
68+
#define SPEEED 30
69+
70+
int len = 0;
71+
72+
// test packet
73+
int dlc_len = to_bang->RDTR & 0xF;
74+
len = append_int(pkt, len, 0, 1); // Start-of-frame
75+
len = append_int(pkt, len, to_bang->RIR >> 21, 11); // Identifier
76+
len = append_int(pkt, len, 0, 3); // RTR+IDE+reserved
77+
len = append_int(pkt, len, dlc_len, 4); // Data length code
78+
79+
// append data
80+
for (int i = 0; i < dlc_len; i++) {
81+
unsigned char dat = ((unsigned char *)(&(to_bang->RDLR)))[i];
82+
len = append_int(pkt, len, dat, 8);
83+
}
84+
85+
// append crc
86+
len = append_crc(pkt, len);
87+
88+
// do bitstuffing
89+
len = do_bitstuff(out, pkt, len);
90+
91+
// append footer
92+
len = append_bits(out, len, footer, sizeof(footer));
93+
return len;
94+
}
95+
96+
// hardware stuff below this line
97+
98+
#ifdef PANDA
99+
100+
void set_bitbanged_gmlan(int val) {
101+
if (val) {
102+
GPIOB->ODR |= (1 << 13);
103+
} else {
104+
GPIOB->ODR &= ~(1 << 13);
105+
}
106+
}
107+
108+
void bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) {
109+
puts("called bitbang_gmlan\n");
110+
111+
char pkt_stuffed[MAX_BITS_CAN_PACKET];
112+
int len = get_bit_message(pkt_stuffed, to_bang);
113+
114+
// actual bitbang loop
115+
set_bitbanged_gmlan(1); // recessive
116+
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
117+
enter_critical_section();
118+
119+
// wait for bus silent for 7 frames
120+
int silent_count = 0;
121+
while (silent_count < 7) {
122+
int read = get_gpio_input(GPIOB, 12);
123+
silent_count++;
124+
if (read == 0) {
125+
silent_count = 0;
126+
}
127+
int lwait = TIM2->CNT;
128+
while (get_ts_elapsed(TIM2->CNT, lwait) < SPEEED);
129+
}
130+
131+
// send my message with optional failure
132+
int last = 1;
133+
int init = TIM2->CNT;
134+
for (int i = 0; i < len; i++) {
135+
while (get_ts_elapsed(TIM2->CNT, init) < (SPEEED*i));
136+
int read = get_gpio_input(GPIOB, 12);
137+
if ((read == 0 && last == 1) && i != (len-11)) {
138+
puts("ERR: bus driven at ");
139+
puth(i);
140+
puts("\n");
141+
goto fail;
142+
}
143+
set_bitbanged_gmlan(pkt_stuffed[i]);
144+
last = pkt_stuffed[i];
145+
}
146+
147+
fail:
148+
set_bitbanged_gmlan(1); // recessive
149+
exit_critical_section();
150+
set_gpio_mode(GPIOB, 13, MODE_INPUT);
151+
152+
puts("bitbang done\n");
153+
}
154+
155+
#endif
156+

tests/gmbitbang/rigol.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python
2+
import numpy as np
3+
import visa
4+
import matplotlib.pyplot as plt
5+
6+
resources = visa.ResourceManager()
7+
print resources.list_resources()
8+
9+
scope = resources.open_resource('USB0::0x1AB1::0x04CE::DS1ZA184652242::INSTR', timeout=2000, chunk_size=1024000)
10+
print(scope.query('*IDN?').strip())
11+
12+
#voltscale = scope.ask_for_values(':CHAN1:SCAL?')[0]
13+
#voltoffset = scope.ask_for_values(":CHAN1:OFFS?")[0]
14+
15+
#scope.write(":STOP")
16+
scope.write(":WAV:POIN:MODE RAW")
17+
scope.write(":WAV:DATA? CHAN1")[10:]
18+
rawdata = scope.read_raw()
19+
data = np.frombuffer(rawdata, 'B')
20+
print data.shape
21+
22+
s1 = data[0:650]
23+
s2 = data[650:]
24+
s1i = np.argmax(s1 > 100)
25+
s2i = np.argmax(s2 > 100)
26+
s1 = s1[s1i:]
27+
s2 = s2[s2i:]
28+
29+
plt.plot(s1)
30+
plt.plot(s2)
31+
plt.show()
32+
#data = (data - 130.0 - voltoffset/voltscale*25) / 25 * voltscale
33+
34+
print data
35+

tests/gmbitbang/test.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python
2+
import time
3+
from panda import Panda
4+
5+
p1 = Panda('430026000951363338383037')
6+
p2 = Panda('380016000551363338383037')
7+
8+
# this is a test, no safety
9+
p1.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
10+
p2.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
11+
12+
# get versions
13+
print(p1.get_version())
14+
print(p2.get_version())
15+
16+
# this sets bus 2 to actually be GMLAN
17+
p2.set_gmlan(bus=2)
18+
19+
# send w bitbang then without
20+
while 1:
21+
p1.set_gmlan(bus=None)
22+
p1.can_send(123, "\x01\x02\x03\x04\x05\x06\x07\x08", bus=3)
23+
p1.set_gmlan(bus=2)
24+
p1.can_send(123, "\x01\x02\x03\x04\x05\x06\x07\x08", bus=3)
25+
time.sleep(0.01)
26+
print p2.can_recv()
27+
exit(0)
28+

tests/gmbitbang/test_packer.c

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <stdio.h>
2+
#include <stdint.h>
3+
4+
typedef struct {
5+
uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */
6+
uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */
7+
uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */
8+
uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */
9+
} CAN_FIFOMailBox_TypeDef;
10+
11+
#include "../../board/drivers/canbitbang.h"
12+
13+
int main() {
14+
char out[300];
15+
CAN_FIFOMailBox_TypeDef to_bang = {0};
16+
to_bang.RIR = 20 << 21;
17+
to_bang.RDTR = 1;
18+
to_bang.RDLR = 1;
19+
20+
int len = get_bit_message(out, &to_bang);
21+
printf("T:");
22+
for (int i = 0; i < len; i++) {
23+
printf("%d", out[i]);
24+
}
25+
printf("\n");
26+
printf("R:0000010010100000100010000010011110111010100111111111111111");
27+
printf("\n");
28+
return 0;
29+
}
30+
31+
32+

0 commit comments

Comments
 (0)