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.
 
 
 
 
 
 

238 lines
7.0 KiB

#include "selfdrive/boardd/panda.h"
#include <cassert>
#include <stdexcept>
#include "cereal/messaging/messaging.h"
#include "panda/board/dlc_to_len.h"
#include "selfdrive/common/gpio.h"
#include "selfdrive/common/swaglog.h"
#include "selfdrive/common/util.h"
Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) {
if (!open(serial)) {
throw std::runtime_error("Error connecting to panda");
}
hw_type = get_hw_type();
assert((hw_type != cereal::PandaState::PandaType::WHITE_PANDA) &&
(hw_type != cereal::PandaState::PandaType::GREY_PANDA));
has_rtc = (hw_type == cereal::PandaState::PandaType::UNO) ||
(hw_type == cereal::PandaState::PandaType::DOS);
}
Panda::~Panda() {}
void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param) {
write(0xdc, (uint16_t)safety_model, safety_param);
}
void Panda::set_unsafe_mode(uint16_t unsafe_mode) {
write(0xdf, unsafe_mode, 0);
}
cereal::PandaState::PandaType Panda::get_hw_type() {
unsigned char hw_query[1] = {0};
read(0xc1, 0, 0, hw_query, 1);
return (cereal::PandaState::PandaType)(hw_query[0]);
}
void Panda::set_rtc(struct tm sys_time) {
// tm struct has year defined as years since 1900
write(0xa1, (uint16_t)(1900 + sys_time.tm_year), 0);
write(0xa2, (uint16_t)(1 + sys_time.tm_mon), 0);
write(0xa3, (uint16_t)sys_time.tm_mday, 0);
// write(0xa4, (uint16_t)(1 + sys_time.tm_wday), 0);
write(0xa5, (uint16_t)sys_time.tm_hour, 0);
write(0xa6, (uint16_t)sys_time.tm_min, 0);
write(0xa7, (uint16_t)sys_time.tm_sec, 0);
}
struct tm Panda::get_rtc() {
struct __attribute__((packed)) timestamp_t {
uint16_t year; // Starts at 0
uint8_t month;
uint8_t day;
uint8_t weekday;
uint8_t hour;
uint8_t minute;
uint8_t second;
} rtc_time = {0};
read(0xa0, 0, 0, (unsigned char*)&rtc_time, sizeof(rtc_time));
struct tm new_time = { 0 };
new_time.tm_year = rtc_time.year - 1900; // tm struct has year defined as years since 1900
new_time.tm_mon = rtc_time.month - 1;
new_time.tm_mday = rtc_time.day;
new_time.tm_hour = rtc_time.hour;
new_time.tm_min = rtc_time.minute;
new_time.tm_sec = rtc_time.second;
return new_time;
}
void Panda::set_fan_speed(uint16_t fan_speed) {
write(0xb1, fan_speed, 0);
}
uint16_t Panda::get_fan_speed() {
uint16_t fan_speed_rpm = 0;
read(0xb2, 0, 0, (unsigned char*)&fan_speed_rpm, sizeof(fan_speed_rpm));
return fan_speed_rpm;
}
void Panda::set_ir_pwr(uint16_t ir_pwr) {
write(0xb0, ir_pwr, 0);
}
health_t Panda::get_state() {
health_t health {0};
read(0xd2, 0, 0, (unsigned char*)&health, sizeof(health));
return health;
}
void Panda::set_loopback(bool loopback) {
write(0xe5, loopback, 0);
}
std::optional<std::vector<uint8_t>> Panda::get_firmware_version() {
std::vector<uint8_t> fw_sig_buf(128);
int read_1 = read(0xd3, 0, 0, &fw_sig_buf[0], 64);
int read_2 = read(0xd4, 0, 0, &fw_sig_buf[64], 64);
return ((read_1 == 64) && (read_2 == 64)) ? std::make_optional(fw_sig_buf) : std::nullopt;
}
std::optional<std::string> Panda::get_serial() {
char serial_buf[17] = {'\0'};
int err = read(0xd0, 0, 0, (uint8_t*)serial_buf, 16);
return err >= 0 ? std::make_optional(serial_buf) : std::nullopt;
}
void Panda::set_power_saving(bool power_saving) {
write(0xe7, power_saving, 0);
}
void Panda::set_usb_power_mode(cereal::PeripheralState::UsbPowerMode power_mode) {
write(0xe6, (uint16_t)power_mode, 0);
}
void Panda::send_heartbeat(bool engaged) {
write(0xf3, engaged, 0);
}
void Panda::set_can_speed_kbps(uint16_t bus, uint16_t speed) {
write(0xde, bus, (speed * 10));
}
void Panda::set_data_speed_kbps(uint16_t bus, uint16_t speed) {
write(0xf9, bus, (speed * 10));
}
static uint8_t len_to_dlc(uint8_t len) {
if (len <= 8) {
return len;
}
if (len <= 24) {
return 8 + ((len - 8) / 4) + ((len % 4) ? 1 : 0);
} else {
return 11 + (len / 16) + ((len % 16) ? 1 : 0);
}
}
static void write_packet(uint8_t *dest, int *write_pos, const uint8_t *src, size_t size) {
for (int i = 0, &pos = *write_pos; i < size; ++i, ++pos) {
// Insert counter every 64 bytes (first byte of 64 bytes USB packet)
if (pos % USBPACKET_MAX_SIZE == 0) {
dest[pos] = pos / USBPACKET_MAX_SIZE;
pos++;
}
dest[pos] = src[i];
}
}
void Panda::pack_can_buffer(const capnp::List<cereal::CanData>::Reader &can_data_list,
std::function<void(uint8_t *, size_t)> write_func) {
int32_t pos = 0;
uint8_t send_buf[2 * USB_TX_SOFT_LIMIT];
for (auto cmsg : can_data_list) {
// check if the message is intended for this panda
uint8_t bus = cmsg.getSrc();
if (bus < bus_offset || bus >= (bus_offset + BUS_CNT)) {
continue;
}
auto can_data = cmsg.getDat();
uint8_t data_len_code = len_to_dlc(can_data.size());
assert(can_data.size() <= ((hw_type == cereal::PandaState::PandaType::RED_PANDA) ? 64 : 8));
assert(can_data.size() == dlc_to_len[data_len_code]);
can_header header;
header.addr = cmsg.getAddress();
header.extended = (cmsg.getAddress() >= 0x800) ? 1 : 0;
header.data_len_code = data_len_code;
header.bus = bus - bus_offset;
write_packet(send_buf, &pos, (uint8_t *)&header, sizeof(can_header));
write_packet(send_buf, &pos, (uint8_t *)can_data.begin(), can_data.size());
if (pos >= USB_TX_SOFT_LIMIT) {
write_func(send_buf, pos);
pos = 0;
}
}
// send remaining packets
if (pos > 0) write_func(send_buf, pos);
}
void Panda::can_send(capnp::List<cereal::CanData>::Reader can_data_list) {
pack_can_buffer(can_data_list, [=](uint8_t* data, size_t size) {
bulk_write(3, data, size, 5);
});
}
bool Panda::can_receive(std::vector<can_frame>& out_vec) {
uint8_t data[RECV_SIZE];
int recv = bulk_read(0x81, (uint8_t*)data, RECV_SIZE);
if (!comms_healthy) {
return false;
}
if (recv == RECV_SIZE) {
LOGW("Panda receive buffer full");
}
return (recv <= 0) ? true : unpack_can_buffer(data, recv, out_vec);
}
bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector<can_frame> &out_vec) {
recv_buf.clear();
for (int i = 0; i < size; i += USBPACKET_MAX_SIZE) {
if (data[i] != i / USBPACKET_MAX_SIZE) {
LOGE("CAN: MALFORMED USB RECV PACKET");
comms_healthy = false;
return false;
}
int chunk_len = std::min((int)USBPACKET_MAX_SIZE, (size - i));
recv_buf.insert(recv_buf.end(), &data[i + 1], &data[i + chunk_len]);
}
int pos = 0;
while (pos < recv_buf.size()) {
can_header header;
memcpy(&header, &recv_buf[pos], CANPACKET_HEAD_SIZE);
can_frame &canData = out_vec.emplace_back();
canData.busTime = 0;
canData.address = header.addr;
canData.src = header.bus + bus_offset;
if (header.rejected) { canData.src += CANPACKET_REJECTED; }
if (header.returned) { canData.src += CANPACKET_RETURNED; }
const uint8_t data_len = dlc_to_len[header.data_len_code];
canData.dat.assign((char *)&recv_buf[pos + CANPACKET_HEAD_SIZE], data_len);
pos += CANPACKET_HEAD_SIZE + data_len;
}
return true;
}