Skip to content

Commit

Permalink
Squashed 'panda/' changes from ef880b7..0dcd84d
Browse files Browse the repository at this point in the history
0dcd84d Toyota safety: integer division bug
9a268f3 Toyota Safety: cleaner var types
8638650 bump panda version
9ab6a56 gmlan recv test
a1a2d97 gmlan test
8efa389 detect ack
f5fab4b nicer err
ad4d423 add gmlan fail count
bb41ff7 test
998f7c0 oops, set recessive
80051be autoretry on chime
813218d GM: allowing higher brakes in Volt, so decel can reach between 3 and 3.5 m/s2
74ad3d6 GM: max param definitions
38a9ea9 added gm safety for steering (#123)
bf5db45 Safety: made the driver steer check common so it can be shared across multiple safety files
ef079e6 Safety: made rate limit check also common
dc3cc24 Safety: made common the max torque check as well
dbc3568 removing extra spaces
1966bdf Safety: made real time rate limit check a shared function
e214477 use timer for can bitbanging
cb92733 minor bitbang refactor
ed2920c support extended addressing in canbitbang
36df0996 move speed
be46c7a Merge pull request #122 from commaai/gmbitbang
7edc88e put that back
fa66e4b Revert "handle rollover"
2ce3a26a handle rollover
223a1fb cleanin it up
1ba7907 that space tho
d917386 bitbanging works
74af441 can crc
932d727 bit stuffing support
be22522 bros ok match bros
55da0b6 rigol yea, dj pauly d yea
a577583 working on gmbitbang
875c2bd3 Cadillac: block OP messages if OP is on
7caba24 Addition to Bosch safety to support Hatchback (#111)
63ca46b modify before we forward
bf70f51 Safety: increase buffer for sampled signals. TBD a violation feedback from board to prevent car faults
b0541a8 Cadillac: monitoring the 4 torque messages independently
cd1dba9 Cadillac: fixed bug in regression safety
ca0b6be Cadillac: fixed typo. Need better regression tests to catch this
d9f1e61 Cadillac: simplified the ignition code by removing the timeout logic and resetting controls_allowed = 0 at each init
293fd1a GM: using real ignition logic. Creedit to Jamezz
8fa507b GM: simplified max steer check logic, Cadillac: fixed can parsing bug
c7e2c2d Cadillac (#119)
83bcaa3 small logic cleanup (#118)
9d92bf2 Cadillac: need to specify car name in const
79ab5af Toyota: moved common functions into safety header file
40c8dda Cadillac ignition: simplified logic
69be556 Cadillac: better ignition logic
d176220 Ignition: made a default hook for GPIO
bea5187 Cadillac: added max steer safety
dbc11a1 Cadillac: always controls allowed for now
ace232a Cadillac: ignition bug
e2c89d6 Cadillac: changed ignition logic to be based on can presence
528f901 Cadillac: simpler ignition logic
4e79ecf Cadillac: added safety file placeholder

git-subtree-dir: panda
git-subtree-split: 0dcd84d
  • Loading branch information
Vehicle Researcher committed Jun 17, 2018
1 parent dcacbf6 commit d5b884f
Show file tree
Hide file tree
Showing 24 changed files with 1,291 additions and 139 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.1.1
v1.1.2
16 changes: 12 additions & 4 deletions board/drivers/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ void can_rx(uint8_t can_number) {
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);
Expand All @@ -428,8 +431,6 @@ void can_rx(uint8_t can_number) {
}
#endif

// modify RDTR for our API
to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (bus_number << 4);
safety_rx_hook(&to_push);

#ifdef PANDA
Expand Down Expand Up @@ -460,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));
}
}
}
}
Expand Down
203 changes: 203 additions & 0 deletions board/drivers/canbitbang.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#define MAX_BITS_CAN_PACKET (200)

// 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<<i)) != 0;
}
return in_len;
}

int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) {
char pkt[MAX_BITS_CAN_PACKET];
char footer[] = {
1, // CRC delimiter
1, // ACK
1, // ACK delimiter
1,1,1,1,1,1,1, // EOF
1,1,1, // IFS
};

int len = 0;

// test packet
int dlc_len = to_bang->RDTR & 0xF;
len = append_int(pkt, len, 0, 1); // Start-of-frame

if (to_bang->RIR & 4) {
// extended identifier
len = append_int(pkt, len, to_bang->RIR >> 21, 11); // Identifier
len = append_int(pkt, len, 3, 2); // SRR+IDE
len = append_int(pkt, len, (to_bang->RIR >> 3) & ((1<<18)-1), 18); // Identifier
len = append_int(pkt, len, 0, 3); // RTR+r1+r0
} else {
// standard identifier
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);
}
}

char pkt_stuffed[MAX_BITS_CAN_PACKET];
int gmlan_sending = -1;
int gmlan_sendmax = -1;

int gmlan_silent_count = 0;
int gmlan_fail_count = 0;
#define REQUIRED_SILENT_TIME 10
#define MAX_FAIL_COUNT 10

void TIM4_IRQHandler(void) {
if (TIM4->SR & TIM_SR_UIF && gmlan_sendmax != -1) {
int read = get_gpio_input(GPIOB, 12);
if (gmlan_silent_count < REQUIRED_SILENT_TIME) {
if (read == 0) {
gmlan_silent_count = 0;
} else {
gmlan_silent_count++;
}
} else if (gmlan_silent_count == REQUIRED_SILENT_TIME) {
int retry = 0;
// in send loop
if (gmlan_sending > 0 && // not first bit
(read == 0 && pkt_stuffed[gmlan_sending-1] == 1) && // bus wrongly dominant
gmlan_sending != (gmlan_sendmax-11)) { //not ack bit
puts("GMLAN ERR: bus driven at ");
puth(gmlan_sending);
puts("\n");
retry = 1;
} else if (read == 1 && gmlan_sending == (gmlan_sendmax-11)) { // recessive during ACK
puts("GMLAN ERR: didn't recv ACK\n");
retry = 1;
}
if (retry) {
// reset sender (retry after 7 silent)
set_bitbanged_gmlan(1); // recessive
gmlan_silent_count = 0;
gmlan_sending = 0;
gmlan_fail_count++;
if (gmlan_fail_count == MAX_FAIL_COUNT) {
puts("GMLAN ERR: giving up send\n");
}
} else {
set_bitbanged_gmlan(pkt_stuffed[gmlan_sending]);
gmlan_sending++;
}
}
if (gmlan_sending == gmlan_sendmax || gmlan_fail_count == MAX_FAIL_COUNT) {
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_INPUT);
TIM4->DIER = 0; // no update interrupt
TIM4->CR1 = 0; // disable timer
gmlan_sendmax = -1; // exit
}
}
TIM4->SR = 0;
}

void bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) {
// TODO: make failure less silent
if (gmlan_sendmax != -1) return;

int len = get_bit_message(pkt_stuffed, to_bang);
gmlan_fail_count = 0;
gmlan_silent_count = 0;
gmlan_sending = 0;
gmlan_sendmax = len;

// setup for bitbang loop
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);

// setup
TIM4->PSC = 48-1; // tick on 1 us
TIM4->CR1 = TIM_CR1_CEN; // enable
TIM4->ARR = 30-1; // 33.3 kbps

// in case it's disabled
NVIC_EnableIRQ(TIM4_IRQn);

// run the interrupt
TIM4->DIER = TIM_DIER_UIE; // update interrupt
TIM4->SR = 0;
}

#endif

2 changes: 1 addition & 1 deletion board/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void periph_init() {
RCC->APB1ENR |= RCC_APB1ENR_DACEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
//RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
Expand Down
100 changes: 100 additions & 0 deletions board/safety.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
// sample struct that keeps 3 samples in memory
struct sample_t {
int values[6];
int min;
int max;
} sample_t_default = {{0}, 0, 0};

void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push);
int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send);
int safety_tx_lin_hook(int lin_num, uint8_t *data, int len);
int safety_ignition_hook();
uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last);
int to_signed(int d, int bits);
void update_sample(struct sample_t *sample, int sample_new);
int max_limit_check(int val, const int MAX);
int dist_to_meas_check(int val, int val_last, struct sample_t *val_meas,
const int MAX_RATE_UP, const int MAX_RATE_DOWN, const int MAX_ERROR);
int driver_limit_check(int val, int val_last, struct sample_t *val_driver,
const int MAX, const int MAX_RATE_UP, const int MAX_RATE_DOWN,
const int MAX_ALLOWANCE, const int DRIVER_FACTOR);
int rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA);

typedef void (*safety_hook_init)(int16_t param);
typedef void (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push);
Expand Down Expand Up @@ -31,6 +48,7 @@ int controls_allowed = 0;
#endif
#include "safety/safety_gm.h"
#include "safety/safety_ford.h"
#include "safety/safety_cadillac.h"
#include "safety/safety_elm327.h"

const safety_hooks *current_hooks = &nooutput_hooks;
Expand Down Expand Up @@ -68,6 +86,7 @@ typedef struct {
#define SAFETY_GM 3
#define SAFETY_HONDA_BOSCH 4
#define SAFETY_FORD 5
#define SAFETY_CADILLAC 6
#define SAFETY_TOYOTA_IPAS 0x1335
#define SAFETY_TOYOTA_NOLIMITS 0x1336
#define SAFETY_ALLOUTPUT 0x1337
Expand All @@ -80,6 +99,7 @@ const safety_hook_config safety_hook_registry[] = {
{SAFETY_TOYOTA, &toyota_hooks},
{SAFETY_GM, &gm_hooks},
{SAFETY_FORD, &ford_hooks},
{SAFETY_CADILLAC, &cadillac_hooks},
{SAFETY_TOYOTA_NOLIMITS, &toyota_nolimits_hooks},
#ifdef PANDA
{SAFETY_TOYOTA_IPAS, &toyota_ipas_hooks},
Expand All @@ -101,3 +121,83 @@ int safety_set_mode(uint16_t mode, int16_t param) {
return -1;
}

// compute the time elapsed (in microseconds) from 2 counter samples
uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last) {
return ts > ts_last ? ts - ts_last : (0xFFFFFFFF - ts_last) + 1 + ts;
}

// convert a trimmed integer to signed 32 bit int
int to_signed(int d, int bits) {
if (d >= (1 << (bits - 1))) {
d -= (1 << bits);
}
return d;
}

// given a new sample, update the smaple_t struct
void update_sample(struct sample_t *sample, int sample_new) {
for (int i = sizeof(sample->values)/sizeof(sample->values[0]) - 1; i > 0; i--) {
sample->values[i] = sample->values[i-1];
}
sample->values[0] = sample_new;

// get the minimum and maximum measured samples
sample->min = sample->max = sample->values[0];
for (int i = 1; i < sizeof(sample->values)/sizeof(sample->values[0]); i++) {
if (sample->values[i] < sample->min) sample->min = sample->values[i];
if (sample->values[i] > sample->max) sample->max = sample->values[i];
}
}

int max_limit_check(int val, const int MAX) {
return (val > MAX) | (val < -MAX);
}

// check that commanded value isn't too far from measured
int dist_to_meas_check(int val, int val_last, struct sample_t *val_meas,
const int MAX_RATE_UP, const int MAX_RATE_DOWN, const int MAX_ERROR) {

// *** val rate limit check ***
int16_t highest_allowed_val = max(val_last, 0) + MAX_RATE_UP;
int16_t lowest_allowed_val = min(val_last, 0) - MAX_RATE_UP;

// if we've exceeded the meas val, we must start moving toward 0
highest_allowed_val = min(highest_allowed_val, max(val_last - MAX_RATE_DOWN, max(val_meas->max, 0) + MAX_ERROR));
lowest_allowed_val = max(lowest_allowed_val, min(val_last + MAX_RATE_DOWN, min(val_meas->min, 0) - MAX_ERROR));

// check for violation
return (val < lowest_allowed_val) || (val > highest_allowed_val);
}

// check that commanded value isn't fighting against driver
int driver_limit_check(int val, int val_last, struct sample_t *val_driver,
const int MAX, const int MAX_RATE_UP, const int MAX_RATE_DOWN,
const int MAX_ALLOWANCE, const int DRIVER_FACTOR) {

int highest_allowed = max(val_last, 0) + MAX_RATE_UP;
int lowest_allowed = min(val_last, 0) - MAX_RATE_UP;

int driver_max_limit = MAX + (MAX_ALLOWANCE + val_driver->max) * DRIVER_FACTOR;
int driver_min_limit = -MAX + (-MAX_ALLOWANCE + val_driver->min) * DRIVER_FACTOR;

// if we've exceeded the applied torque, we must start moving toward 0
highest_allowed = min(highest_allowed, max(val_last - MAX_RATE_DOWN,
max(driver_max_limit, 0)));
lowest_allowed = max(lowest_allowed, min(val_last + MAX_RATE_DOWN,
min(driver_min_limit, 0)));

// check for violation
return (val < lowest_allowed) || (val > highest_allowed);
}


// real time check, mainly used for steer torque rate limiter
int rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA) {

// *** torque real time rate limit check ***
int16_t highest_val = max(val_last, 0) + MAX_RT_DELTA;
int16_t lowest_val = min(val_last, 0) - MAX_RT_DELTA;

// check for violation
return (val < lowest_val) || (val > highest_val);
}
Loading

0 comments on commit d5b884f

Please sign in to comment.