|
|
@ -364,12 +364,14 @@ uint8_t Panda::len_to_dlc(uint8_t len) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Panda::can_send(capnp::List<cereal::CanData>::Reader can_data_list) { |
|
|
|
void Panda::can_send(capnp::List<cereal::CanData>::Reader can_data_list) { |
|
|
|
send.resize(72 * can_data_list.size()); // TODO: need to include 1 byte for each usb 64bytes frame
|
|
|
|
if (send.size() < (can_data_list.size() * CANPACKET_MAX_SIZE)) { |
|
|
|
|
|
|
|
send.resize(can_data_list.size() * CANPACKET_MAX_SIZE); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int msg_count = 0; |
|
|
|
int msg_count = 0; |
|
|
|
while (msg_count < can_data_list.size()) { |
|
|
|
while (msg_count < can_data_list.size()) { |
|
|
|
uint32_t pos = 0; |
|
|
|
uint32_t pos = 0; |
|
|
|
while (pos < 256) { |
|
|
|
while (pos < USB_TX_SOFT_LIMIT) { |
|
|
|
if (msg_count == can_data_list.size()) { break; } |
|
|
|
if (msg_count == can_data_list.size()) { break; } |
|
|
|
auto cmsg = can_data_list[msg_count]; |
|
|
|
auto cmsg = can_data_list[msg_count]; |
|
|
|
|
|
|
|
|
|
|
@ -384,26 +386,31 @@ void Panda::can_send(capnp::List<cereal::CanData>::Reader can_data_list) { |
|
|
|
assert(can_data.size() <= (hw_type == cereal::PandaState::PandaType::RED_PANDA) ? 64 : 8); |
|
|
|
assert(can_data.size() <= (hw_type == cereal::PandaState::PandaType::RED_PANDA) ? 64 : 8); |
|
|
|
assert(can_data.size() == dlc_to_len[data_len_code]); |
|
|
|
assert(can_data.size() == dlc_to_len[data_len_code]); |
|
|
|
|
|
|
|
|
|
|
|
*(uint32_t*)&send[pos+1] = (cmsg.getAddress() << 3); |
|
|
|
can_header header; |
|
|
|
if (cmsg.getAddress() >= 0x800) { |
|
|
|
header.addr = cmsg.getAddress(); |
|
|
|
*(uint32_t*)&send[pos+1] |= (1 << 2); |
|
|
|
header.extended = (cmsg.getAddress() >= 0x800) ? 1 : 0; |
|
|
|
} |
|
|
|
header.data_len_code = data_len_code; |
|
|
|
send[pos] = data_len_code << 4 | ((bus - bus_offset) << 1); |
|
|
|
header.bus = bus - bus_offset; |
|
|
|
memcpy(&send[pos+5], can_data.begin(), can_data.size()); |
|
|
|
memcpy(&send[pos], &header, CANPACKET_HEAD_SIZE); |
|
|
|
|
|
|
|
memcpy(&send[pos+CANPACKET_HEAD_SIZE], can_data.begin(), can_data.size()); |
|
|
|
|
|
|
|
|
|
|
|
pos += CANPACKET_HEAD_SIZE + dlc_to_len[data_len_code]; |
|
|
|
pos += CANPACKET_HEAD_SIZE + dlc_to_len[data_len_code]; |
|
|
|
msg_count++; |
|
|
|
msg_count++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (pos > 0) { // Helps not to spam with ZLP
|
|
|
|
if (pos > 0) { // Helps not to spam with ZLP
|
|
|
|
// insert counter
|
|
|
|
// Counter needs to be inserted every 64 bytes (first byte of 64 bytes USB packet)
|
|
|
|
uint8_t counter = 0; |
|
|
|
uint8_t counter = 0; |
|
|
|
for (int i = 0; i < pos; i += 64) { |
|
|
|
uint8_t to_write[USB_TX_SOFT_LIMIT+128]; |
|
|
|
send.insert(send.begin() + i, counter); |
|
|
|
int ptr = 0; |
|
|
|
|
|
|
|
for (int i = 0; i < pos; i += 63) { |
|
|
|
|
|
|
|
to_write[ptr] = counter; |
|
|
|
|
|
|
|
int copy_size = ((pos - i) < 63) ? (pos - i) : 63; |
|
|
|
|
|
|
|
memcpy(&to_write[ptr+1], &(send.data()[i]) , copy_size); |
|
|
|
|
|
|
|
ptr += copy_size + 1; |
|
|
|
counter++; |
|
|
|
counter++; |
|
|
|
pos++; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
usb_bulk_write(3, (uint8_t*)send.data(), pos, 5); |
|
|
|
usb_bulk_write(3, to_write, ptr, 5); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -415,7 +422,6 @@ bool Panda::can_receive(std::vector<can_frame>& out_vec) { |
|
|
|
// Not sure if this can happen
|
|
|
|
// Not sure if this can happen
|
|
|
|
if (recv < 0) recv = 0; |
|
|
|
if (recv < 0) recv = 0; |
|
|
|
|
|
|
|
|
|
|
|
// TODO: Might change from full to overloaded? if > some threshold that is lower than RECV_SIZE, let's say 80-90%
|
|
|
|
|
|
|
|
if (recv == RECV_SIZE) { |
|
|
|
if (recv == RECV_SIZE) { |
|
|
|
LOGW("Receive buffer full"); |
|
|
|
LOGW("Receive buffer full"); |
|
|
|
} |
|
|
|
} |
|
|
@ -426,17 +432,18 @@ bool Panda::can_receive(std::vector<can_frame>& out_vec) { |
|
|
|
|
|
|
|
|
|
|
|
out_vec.reserve(out_vec.size() + (recv / CANPACKET_HEAD_SIZE)); |
|
|
|
out_vec.reserve(out_vec.size() + (recv / CANPACKET_HEAD_SIZE)); |
|
|
|
|
|
|
|
|
|
|
|
static uint8_t tail[72]; |
|
|
|
static uint8_t tail[CANPACKET_MAX_SIZE]; |
|
|
|
uint8_t tail_size = 0; |
|
|
|
uint8_t tail_size = 0; |
|
|
|
uint8_t counter = 0; |
|
|
|
uint8_t counter = 0; |
|
|
|
for (int i = 0; i < recv; i += 64) { |
|
|
|
for (int i = 0; i < recv; i += 64) { |
|
|
|
|
|
|
|
// Check for counter every 64 bytes (length of USB packet)
|
|
|
|
if (counter != data[i]) { |
|
|
|
if (counter != data[i]) { |
|
|
|
LOGE("CAN: MALFORMED USB RECV PACKET"); |
|
|
|
LOGE("CAN: MALFORMED USB RECV PACKET"); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
counter++; |
|
|
|
counter++; |
|
|
|
uint8_t chunk_len = ((recv - i) > 64) ? 63 : (recv - i - 1); // as 1 is always reserved for counter
|
|
|
|
uint8_t chunk_len = ((recv - i) > 64) ? 63 : (recv - i - 1); // as 1 is always reserved for counter
|
|
|
|
uint8_t chunk[72]; |
|
|
|
uint8_t chunk[CANPACKET_MAX_SIZE]; |
|
|
|
memcpy(chunk, tail, tail_size); |
|
|
|
memcpy(chunk, tail, tail_size); |
|
|
|
memcpy(&chunk[tail_size], &data[i+1], chunk_len); |
|
|
|
memcpy(&chunk[tail_size], &data[i+1], chunk_len); |
|
|
|
chunk_len += tail_size; |
|
|
|
chunk_len += tail_size; |
|
|
@ -447,21 +454,22 @@ bool Panda::can_receive(std::vector<can_frame>& out_vec) { |
|
|
|
uint8_t pckt_len = CANPACKET_HEAD_SIZE + data_len; |
|
|
|
uint8_t pckt_len = CANPACKET_HEAD_SIZE + data_len; |
|
|
|
if (pckt_len <= (chunk_len - pos)) { |
|
|
|
if (pckt_len <= (chunk_len - pos)) { |
|
|
|
can_frame canData; |
|
|
|
can_frame canData; |
|
|
|
|
|
|
|
can_header header; |
|
|
|
|
|
|
|
memcpy(&header, &chunk[pos], CANPACKET_HEAD_SIZE); |
|
|
|
canData.busTime = 0; |
|
|
|
canData.busTime = 0; |
|
|
|
canData.address = (*(uint32_t*)&chunk[pos+1]) >> 3; |
|
|
|
canData.address = header.addr; |
|
|
|
canData.src = ((chunk[pos] >> 1) & 0x7) + bus_offset; |
|
|
|
canData.src = header.bus + bus_offset; |
|
|
|
|
|
|
|
|
|
|
|
bool rejected = chunk[pos+1] & 0x1; |
|
|
|
if (header.rejected) { canData.src += CANPACKET_REJECTED; } |
|
|
|
bool returned = (chunk[pos+1] >> 1) & 0x1; |
|
|
|
if (header.returned) { canData.src += CANPACKET_RETURNED; } |
|
|
|
if (rejected) { canData.src += CANPACKET_REJECTED; } |
|
|
|
canData.dat.assign((char*)&chunk[pos+CANPACKET_HEAD_SIZE], data_len); |
|
|
|
if (returned) { canData.src += CANPACKET_RETURNED; } |
|
|
|
|
|
|
|
canData.dat.assign((char*)&chunk[pos+5], data_len); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pos += pckt_len; |
|
|
|
pos += pckt_len; |
|
|
|
|
|
|
|
|
|
|
|
// add to vector
|
|
|
|
// add to vector
|
|
|
|
out_vec.push_back(canData); |
|
|
|
out_vec.push_back(canData); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
// Keep partial CAN packet until next USB packet
|
|
|
|
tail_size = (chunk_len - pos); |
|
|
|
tail_size = (chunk_len - pos); |
|
|
|
memcpy(tail, &chunk[pos], tail_size); |
|
|
|
memcpy(tail, &chunk[pos], tail_size); |
|
|
|
break; |
|
|
|
break; |
|
|
|