openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
4.1 KiB

/*
CAN transactions to and from the host come in the form of
a certain number of CANPacket_t. The transaction is split
into multiple transfers or chunks.
* comms_can_read outputs this buffer in chunks of a specified length.
chunks are always the given length, except the last one.
* comms_can_write reads in this buffer in chunks.
* both functions maintain an overflow buffer for a partial CANPacket_t that
spans multiple transfers/chunks.
* the overflow buffers are reset by a dedicated control transfer handler,
which is sent by the host on each start of a connection.
*/
typedef struct {
uint32_t ptr;
uint32_t tail_size;
uint8_t data[72];
} asm_buffer;
static asm_buffer can_read_buffer = {.ptr = 0U, .tail_size = 0U};
int comms_can_read(uint8_t *data, uint32_t max_len) {
uint32_t pos = 0U;
// Send tail of previous message if it is in buffer
if (can_read_buffer.ptr > 0U) {
uint32_t overflow_len = MIN(max_len - pos, can_read_buffer.ptr);
(void)memcpy(&data[pos], can_read_buffer.data, overflow_len);
pos += overflow_len;
(void)memcpy(can_read_buffer.data, &can_read_buffer.data[overflow_len], can_read_buffer.ptr - overflow_len);
can_read_buffer.ptr -= overflow_len;
}
if (can_read_buffer.ptr == 0U) {
// Fill rest of buffer with new data
CANPacket_t can_packet;
while ((pos < max_len) && can_pop(&can_rx_q, &can_packet)) {
uint32_t pckt_len = CANPACKET_HEAD_SIZE + dlc_to_len[can_packet.data_len_code];
if ((pos + pckt_len) <= max_len) {
(void)memcpy(&data[pos], (uint8_t*)&can_packet, pckt_len);
pos += pckt_len;
} else {
(void)memcpy(&data[pos], (uint8_t*)&can_packet, max_len - pos);
can_read_buffer.ptr += pckt_len - (max_len - pos);
// cppcheck-suppress objectIndex
(void)memcpy(can_read_buffer.data, &((uint8_t*)&can_packet)[(max_len - pos)], can_read_buffer.ptr);
pos = max_len;
}
}
}
return pos;
}
static asm_buffer can_write_buffer = {.ptr = 0U, .tail_size = 0U};
// send on CAN
void comms_can_write(const uint8_t *data, uint32_t len) {
uint32_t pos = 0U;
// Assembling can message with data from buffer
if (can_write_buffer.ptr != 0U) {
if (can_write_buffer.tail_size <= (len - pos)) {
// we have enough data to complete the buffer
CANPacket_t to_push = {0};
(void)memcpy(&can_write_buffer.data[can_write_buffer.ptr], &data[pos], can_write_buffer.tail_size);
can_write_buffer.ptr += can_write_buffer.tail_size;
pos += can_write_buffer.tail_size;
// send out
(void)memcpy((uint8_t*)&to_push, can_write_buffer.data, can_write_buffer.ptr);
can_send(&to_push, to_push.bus, false);
// reset overflow buffer
can_write_buffer.ptr = 0U;
can_write_buffer.tail_size = 0U;
} else {
// maybe next time
uint32_t data_size = len - pos;
(void) memcpy(&can_write_buffer.data[can_write_buffer.ptr], &data[pos], data_size);
can_write_buffer.tail_size -= data_size;
can_write_buffer.ptr += data_size;
pos += data_size;
}
}
// rest of the message
while (pos < len) {
uint32_t pckt_len = CANPACKET_HEAD_SIZE + dlc_to_len[(data[pos] >> 4U)];
if ((pos + pckt_len) <= len) {
CANPacket_t to_push = {0};
(void)memcpy((uint8_t*)&to_push, &data[pos], pckt_len);
can_send(&to_push, to_push.bus, false);
pos += pckt_len;
} else {
(void)memcpy(can_write_buffer.data, &data[pos], len - pos);
can_write_buffer.ptr = len - pos;
can_write_buffer.tail_size = pckt_len - can_write_buffer.ptr;
pos += can_write_buffer.ptr;
}
}
refresh_can_tx_slots_available();
}
void comms_can_reset(void) {
can_write_buffer.ptr = 0U;
can_write_buffer.tail_size = 0U;
can_read_buffer.ptr = 0U;
can_read_buffer.tail_size = 0U;
}
// TODO: make this more general!
void refresh_can_tx_slots_available(void) {
if (can_tx_check_min_slots_free(MAX_CAN_MSGS_PER_USB_BULK_TRANSFER)) {
can_tx_comms_resume_usb();
}
if (can_tx_check_min_slots_free(MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER)) {
can_tx_comms_resume_spi();
}
}