mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-06-30 02:52:04 +08:00
6d13ef279e
a648ccae Add os import
042562dd Extracted wifi connect from test helpers
ac0fd5dd query fw versions example - use extended diagnostic session
4e9d788a Remove not-needed cadillac-init
f0a5d154 typo
c093286b Add bootkick after re-enabling phone power (#401)
eadb0dbb security upgrades (#397)
7c13bec0 Command to get signature (#399)
dad439a4 static assert on size of health packet (#398)
da9da466 Fix VERSION
df4159c8 Revert "Revert "Register readback on most modules. Still need to convert the other ones (#396)""
56ec2150 Revert "Register readback on most modules. Still need to convert the other ones (#396)"
893e4861 Register readback on most modules. Still need to convert the other ones (#396)
6bbae7be VW safety: allow cancel spam on both buses to be compatible with camera and gateway integration
d5f7a287 bump panda
1bcc351f ignition_can: set it to False after 2s of not seeing CAN msgs
96137f1a VW can based ignition not needed. it has ignition line at camera as well.
1b004a18 Same flake8 version as the one in openpilot
e82ba5f2 Same pylint version as the one in openpilot
656f99b0 Interrupt refactor (NVIC_SM_1: #334) and Fault handling (#377) (PR #373)
000282e5 Fix can_logger.py to run correctly on python3 (#392)
7f9b4a59 Fix USB device enumeration on Windows 8.1 and Windows 10 (#393)
dec565c7 Update Misra test coverage, which now includes rule 2.7
fb6bc3ba Fix Misra
878dd00a solve race condition is relay_malfunction right after changing the relay status by adding a counter
2d4cb05c add a safety mode counter
a6797a21 Implement USB power mode on uno
670f90cc Merge branch 'master' of github.com:commaai/panda
ca39a5d8 Added faults integer to health packet
e1c34a1a Panda Jungle testing (#394)
2a093a39 Added heartbeat to echo test
22464356 Fixed health struct size. We should really get an automated test for this
f458d67a Add uptime counter to the health packet (#391)
16624811 enable CAN transcievers outside the set_safety_mode function, which is not related
a7c98744 bump panda ver
1192d934 Power saving refactor (#389)
d58d08fb Fix Misra 17.8: can't mod function params
bc685ac9 Minor indent
a54b86c4 Failure of set_safety_mode falls back to SILENT. Failure to set silent results in hanging
597436d3 NOOUTPUT safety mode is now SILENT. NOOUTPUT still exists but keeps C… (#388)
d229f8dc ESP forced off in EON build. this prevents ESP to be turned on when e… (#387)
8a044b34 forgot Hyundai: now also using make_msg
4f9c8796 remove abunch of lines from safety regression tests by using common make_msg function
fb814143 mispelled word
57f5ef8c Fix misra: addr can't be more than 29 bits anyway
68ff5012 typo
d5c772b0 Fixe Toyota message white-list
48197a92 Better masking for ELM mode
b8fe78c3 VW is also tested for safety replay
212d336b Safety Chrysler: Added cancel spam button check
d44b5621 fix print in example
02d579a5 functional addr handling
6249a183 tx_hook shall have a white-list of messages (#381)
8138fc14 uds: handle function addrs and fw version query example
6626a542 Fixed python health api
b9b79e8b uds zero second timeout
e0de1a4f define ALLOW_DEBUG in safety tests
86dec4b8 Safety modes that violate ISO26262 requirements are not compiled in RELEASE build
e74ed936 safety tests a bit more simplified
2027765b relay malfunction test centralized
8af1a01a clean up safety tests
e8f7a3b2 upd panda
cfcce8f0 WIP: Relay malfunction (#384)
69d9d610 No tabs in mazda safety
a86418c1 insignificant changes
f239b996 single addr was better
d063a188 Hyundai safety: re-enable button spam safety check
4d1edc06 skip tx_hook if a message is forwarded (#379)
df2ff045 bump version
168461d5 added fault state to health packet
b3e1a133 uds: better debug prints
68c39fb3 uds: no need for threads if you always drain rx
91b7c5bb bump Panda Ver
26cb4dc4 Fixed pylint error
32725cc3 Fixed misra compliance
e33b4bea Added echo script
312ba62d minor comment cleanupo
e90897a8 Fix board detection on white
0e72c183 always stop executing if safety mode fails to be set (suggested by jyoung8607)
e8d7ed1d Rename function name to not confuse safety_set_mode and set_safety_mode
ff86db65 improve uds message processing
512ab3f2 except Exception
37ce507a py3 all
bac4d854 dos and python3
501db8d1 uds drain before send and use has_obd()
f2cbec16 Added has_obd() to python library
48e5b182 Add SDK downloading to the build step (#314)
e0762c2e Add Python & USB API for controlling phone power (#313)
ba9fb69f New health packet struct also in the python libs
git-subtree-dir: panda
git-subtree-split: a648ccae4b3661ca6de7a4ac199cc44a41442b74
old-commit-hash: bc7b9b38ae
523 lines
16 KiB
C++
523 lines
16 KiB
C++
// panda.cpp : Defines the exported functions for the DLL application.
|
|
//
|
|
#include "stdafx.h"
|
|
|
|
#include "device.h"
|
|
#include "panda.h"
|
|
|
|
#define REQUEST_IN 0xC0
|
|
#define REQUEST_OUT 0x40
|
|
|
|
#define CAN_TRANSMIT 1
|
|
#define CAN_EXTENDED 4
|
|
|
|
using namespace panda;
|
|
|
|
Panda::Panda(
|
|
WINUSB_INTERFACE_HANDLE WinusbHandle,
|
|
HANDLE DeviceHandle,
|
|
tstring devPath_,
|
|
std::string sn_
|
|
) : usbh(WinusbHandle), devh(DeviceHandle), devPath(devPath_), sn(sn_) {
|
|
printf("CREATED A PANDA %s\n", this->sn.c_str());
|
|
this->set_can_loopback(FALSE);
|
|
this->set_raw_io(TRUE);
|
|
this->set_alt_setting(0);
|
|
}
|
|
|
|
Panda::~Panda() {
|
|
WinUsb_Free(this->usbh);
|
|
CloseHandle(this->devh);
|
|
printf("Cleanup Panda %s\n", this->sn.c_str());
|
|
}
|
|
|
|
std::vector<std::string> Panda::listAvailablePandas() {
|
|
std::vector<std::string> ret;
|
|
auto map_sn_to_devpath = detect_pandas();
|
|
|
|
for (auto kv : map_sn_to_devpath) {
|
|
ret.push_back(std::string(kv.first));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::unique_ptr<Panda> Panda::openPanda(std::string sn)
|
|
{
|
|
auto map_sn_to_devpath = detect_pandas();
|
|
|
|
if (map_sn_to_devpath.empty()) return nullptr;
|
|
if (map_sn_to_devpath.find(sn) == map_sn_to_devpath.end() && sn != "") return nullptr;
|
|
|
|
tstring devpath;
|
|
if (sn.empty()) {
|
|
sn = map_sn_to_devpath.begin()->first;
|
|
devpath = map_sn_to_devpath.begin()->second;
|
|
} else {
|
|
devpath = map_sn_to_devpath[sn];
|
|
}
|
|
|
|
HANDLE deviceHandle = CreateFile(devpath.c_str(),
|
|
GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE == deviceHandle) {
|
|
_tprintf(_T(" Error opening Device Handle %d.\n"),// Msg: '%s'\n"),
|
|
GetLastError());// , GetLastErrorAsString().c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
WINUSB_INTERFACE_HANDLE winusbHandle;
|
|
if (WinUsb_Initialize(deviceHandle, &winusbHandle) == FALSE) {
|
|
_tprintf(_T(" Error initializing WinUSB %d.\n"),// Msg: '%s'\n"),
|
|
GetLastError());// , GetLastErrorAsString().c_str());
|
|
CloseHandle(deviceHandle);
|
|
return nullptr;
|
|
}
|
|
|
|
return std::unique_ptr<Panda>(new Panda(winusbHandle, deviceHandle, map_sn_to_devpath[sn], sn));
|
|
}
|
|
|
|
std::string Panda::get_usb_sn() {
|
|
return std::string(this->sn);
|
|
}
|
|
|
|
int Panda::control_transfer(
|
|
uint8_t bmRequestType,
|
|
uint8_t bRequest,
|
|
uint16_t wValue,
|
|
uint16_t wIndex,
|
|
void * data,
|
|
uint16_t wLength,
|
|
unsigned int timeout
|
|
) {
|
|
UNREFERENCED_PARAMETER(timeout);
|
|
|
|
WINUSB_SETUP_PACKET SetupPacket;
|
|
ZeroMemory(&SetupPacket, sizeof(WINUSB_SETUP_PACKET));
|
|
ULONG cbSent = 0;
|
|
|
|
//Create the setup packet
|
|
SetupPacket.RequestType = bmRequestType;
|
|
SetupPacket.Request = bRequest;
|
|
SetupPacket.Value = wValue;
|
|
SetupPacket.Index = wIndex;
|
|
SetupPacket.Length = wLength;
|
|
|
|
//ULONG timeout = 10; // ms
|
|
//WinUsb_SetPipePolicy(interfaceHandle, pipeID, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);
|
|
|
|
if (WinUsb_ControlTransfer(this->usbh, SetupPacket, (PUCHAR)data, wLength, &cbSent, 0) == FALSE) {
|
|
return -1;
|
|
}
|
|
|
|
return cbSent;
|
|
}
|
|
|
|
int Panda::bulk_write(UCHAR endpoint, const void * buff, ULONG length, PULONG transferred, ULONG timeout) {
|
|
if (this->usbh == INVALID_HANDLE_VALUE || !buff || !length || !transferred) return FALSE;
|
|
|
|
if (WinUsb_WritePipe(this->usbh, endpoint, (PUCHAR)buff, length, transferred, NULL) == FALSE) {
|
|
_tprintf(_T(" Got error during bulk xfer: %d. Msg: '%s'\n"),
|
|
GetLastError(), GetLastErrorAsString().c_str());
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int Panda::bulk_read(UCHAR endpoint, void * buff, ULONG buff_size, PULONG transferred, ULONG timeout) {
|
|
if (this->usbh == INVALID_HANDLE_VALUE || !buff || !buff_size || !transferred) return FALSE;
|
|
|
|
if (WinUsb_ReadPipe(this->usbh, endpoint, (PUCHAR)buff, buff_size, transferred, NULL) == FALSE) {
|
|
_tprintf(_T(" Got error during bulk xfer: %d. Msg: '%s'\n"),
|
|
GetLastError(), GetLastErrorAsString().c_str());
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool Panda::set_alt_setting(UCHAR alt_setting) {
|
|
if (WinUsb_AbortPipe(this->usbh, 0x81) == FALSE) {
|
|
_tprintf(_T(" Error abobrting pipe before setting altsetting. continue. %d, Msg: '%s'\n"),
|
|
GetLastError(), GetLastErrorAsString().c_str());
|
|
}
|
|
if (WinUsb_SetCurrentAlternateSetting(this->usbh, alt_setting) == FALSE) {
|
|
_tprintf(_T(" Error setting usb altsetting %d, Msg: '%s'\n"),
|
|
GetLastError(), GetLastErrorAsString().c_str());
|
|
return FALSE;
|
|
}
|
|
|
|
// Either the panda or the windows usb stack can drop messages
|
|
// if an odd number of messages are sent before an interrupt IN
|
|
// message is canceled. There are some other odd behaviors, but
|
|
// the best solution so far has been to send a few messages
|
|
// before using the device to clear out the pipe. No, the windows
|
|
// functions for clearing/resetting/etc the pipe did not work.
|
|
// This took way too to figure out a workaround.
|
|
// New info. The most repeatable behavior is losing the first
|
|
// message sent after setting alt setting to 1 (even without
|
|
// receiving). Something like this happened on linux sometimes.
|
|
bool loopback_backup = this->loopback;
|
|
this->set_can_loopback(TRUE);
|
|
Sleep(20); // Give time for any sent messages to appear in the RX buffer.
|
|
this->can_clear(PANDA_CAN_RX);
|
|
// send 4 messages becaus can_recv reads 4 messages at a time
|
|
for (int i = 0; i < 4; i++) {
|
|
printf("Sending PAD %d\n", i);
|
|
if (this->can_send(0x7FF, FALSE, {}, 0, PANDA_CAN1) == FALSE) {
|
|
auto err = GetLastError();
|
|
printf("Got err on first send: %d\n", err);
|
|
}
|
|
}
|
|
Sleep(10);
|
|
//this->can_clear(PANDA_CAN_RX);
|
|
|
|
//Read the messages so they do not contaimnate the real message stream.
|
|
this->can_recv();
|
|
|
|
//this->set_can_loopback(FALSE);
|
|
this->set_can_loopback(loopback_backup);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
UCHAR Panda::get_current_alt_setting() {
|
|
UCHAR alt_setting;
|
|
if (WinUsb_GetCurrentAlternateSetting(this->usbh, &alt_setting) == FALSE) {
|
|
_tprintf(_T(" Error getting usb altsetting %d, Msg: '%s'\n"),
|
|
GetLastError(), GetLastErrorAsString().c_str());
|
|
return FALSE;
|
|
}
|
|
|
|
return alt_setting;
|
|
}
|
|
|
|
bool Panda::set_raw_io(bool val) {
|
|
UCHAR raw_io = val;
|
|
if (!WinUsb_SetPipePolicy(this->usbh, 0x81, RAW_IO, sizeof(raw_io), &raw_io)) {
|
|
_tprintf(_T(" Error setting usb raw I/O pipe policy %d, Msg: '%s'\n"),
|
|
GetLastError(), GetLastErrorAsString().c_str());
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PANDA_HEALTH Panda::get_health()
|
|
{
|
|
WINUSB_SETUP_PACKET SetupPacket;
|
|
ZeroMemory(&SetupPacket, sizeof(WINUSB_SETUP_PACKET));
|
|
ULONG cbSent = 0;
|
|
|
|
//Create the setup packet
|
|
SetupPacket.RequestType = REQUEST_IN;
|
|
SetupPacket.Request = 0xD2;
|
|
SetupPacket.Value = 0;
|
|
SetupPacket.Index = 0;
|
|
SetupPacket.Length = sizeof(UCHAR);
|
|
|
|
//uint8_t health[13];
|
|
PANDA_HEALTH health;
|
|
|
|
if (WinUsb_ControlTransfer(this->usbh, SetupPacket, (PUCHAR)&health, sizeof(health), &cbSent, 0) == FALSE) {
|
|
_tprintf(_T(" Got unexpected error while reading panda health (2nd time) %d. Msg: '%s'\n"),
|
|
GetLastError(), GetLastErrorAsString().c_str());
|
|
}
|
|
|
|
return health;
|
|
}
|
|
|
|
bool Panda::enter_bootloader() {
|
|
return this->control_transfer(REQUEST_OUT, 0xd1, 0, 0, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
std::string Panda::get_version() {
|
|
char buff[0x40];
|
|
ZeroMemory(&buff, sizeof(buff));
|
|
|
|
int xferCount = this->control_transfer(REQUEST_IN, 0xd6, 0, 0, buff, 0x40, 0);
|
|
if (xferCount == -1) return std::string();
|
|
return std::string(buff);
|
|
}
|
|
|
|
//TODO: Do hash stuff for calculating the serial.
|
|
std::string Panda::get_serial() {
|
|
char buff[0x20];
|
|
ZeroMemory(&buff, sizeof(buff));
|
|
|
|
int xferCount = this->control_transfer(REQUEST_IN, 0xD0, 0, 0, buff, 0x20, 0);
|
|
if (xferCount == -1) return std::string();
|
|
return std::string(buff);
|
|
|
|
//dat = self._handle.controlRead(REQUEST_IN, 0xd0, 0, 0, 0x20);
|
|
//hashsig, calc_hash = dat[0x1c:], hashlib.sha1(dat[0:0x1c]).digest()[0:4]
|
|
// assert(hashsig == calc_hash)
|
|
// return[dat[0:0x10], dat[0x10:0x10 + 10]]
|
|
}
|
|
|
|
//Secret appears to by raw bytes, not a string. TODO: Change returned type.
|
|
std::string Panda::get_secret() {
|
|
char buff[0x10];
|
|
ZeroMemory(&buff, sizeof(buff));
|
|
|
|
int xferCount = this->control_transfer(REQUEST_IN, 0xd0, 1, 0, buff, 0x10, 0);
|
|
if (xferCount == -1) return std::string();
|
|
return std::string(buff);
|
|
}
|
|
|
|
bool Panda::set_usb_power(bool on) {
|
|
return this->control_transfer(REQUEST_OUT, 0xe6, (int)on, 0, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::set_esp_power(bool on) {
|
|
return this->control_transfer(REQUEST_OUT, 0xd9, (int)on, 0, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::esp_reset(uint16_t bootmode = 0) {
|
|
return this->control_transfer(REQUEST_OUT, 0xda, bootmode, 0, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::set_safety_mode(PANDA_SAFETY_MODE mode = SAFETY_SILENT) {
|
|
return this->control_transfer(REQUEST_OUT, 0xdc, mode, 0, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::set_can_forwarding(PANDA_CAN_PORT from_bus, PANDA_CAN_PORT to_bus) {
|
|
if (from_bus == PANDA_CAN_UNK) return FALSE;
|
|
return this->control_transfer(REQUEST_OUT, 0xdd, from_bus, to_bus, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::set_gmlan(PANDA_GMLAN_HOST_PORT bus = PANDA_GMLAN_CAN3) {
|
|
return this->control_transfer(REQUEST_OUT, 0xdb, 1, (bus == PANDA_GMLAN_CLEAR) ? 0 : bus, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::set_can_loopback(bool enable) {
|
|
this->loopback = enable;
|
|
return this->control_transfer(REQUEST_OUT, 0xe5, enable, 0, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
//Can not use the full range of 16 bit speed.
|
|
//cbps means centa bits per second (tento of kbps)
|
|
bool Panda::set_can_speed_cbps(PANDA_CAN_PORT bus, uint16_t speed) {
|
|
if (bus == PANDA_CAN_UNK) return FALSE;
|
|
return this->control_transfer(REQUEST_OUT, 0xde, bus, speed, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
//Can not use the full range of 16 bit speed.
|
|
bool Panda::set_can_speed_kbps(PANDA_CAN_PORT bus, uint16_t speed) {
|
|
return set_can_speed_cbps(bus, speed * 10);
|
|
}
|
|
|
|
//Can not use full 32 bit range of rate
|
|
bool Panda::set_uart_baud(PANDA_SERIAL_PORT uart, uint32_t rate) {
|
|
return this->control_transfer(REQUEST_OUT, 0xe4, uart, rate / 300, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::set_uart_parity(PANDA_SERIAL_PORT uart, PANDA_SERIAL_PORT_PARITY parity) {
|
|
return this->control_transfer(REQUEST_OUT, 0xe2, uart, parity, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
bool Panda::can_send_many(const std::vector<PANDA_CAN_MSG>& can_msgs) {
|
|
std::vector<PANDA_CAN_MSG_INTERNAL> formatted_msgs;
|
|
formatted_msgs.reserve(can_msgs.size());
|
|
|
|
for (auto msg : can_msgs) {
|
|
if (msg.bus == PANDA_CAN_UNK) continue;
|
|
if (msg.len > 8) continue;
|
|
PANDA_CAN_MSG_INTERNAL tmpmsg = {};
|
|
tmpmsg.rir = (msg.addr_29b) ?
|
|
((msg.addr << 3) | CAN_TRANSMIT | CAN_EXTENDED) :
|
|
(((msg.addr & 0x7FF) << 21) | CAN_TRANSMIT);
|
|
tmpmsg.f2 = msg.len | (msg.bus << 4);
|
|
memcpy(tmpmsg.dat, msg.dat, msg.len);
|
|
formatted_msgs.push_back(tmpmsg);
|
|
}
|
|
|
|
if (formatted_msgs.size() == 0) return FALSE;
|
|
|
|
unsigned int retcount;
|
|
return this->bulk_write(3, formatted_msgs.data(),
|
|
sizeof(PANDA_CAN_MSG_INTERNAL)*formatted_msgs.size(), (PULONG)&retcount, 0);
|
|
}
|
|
|
|
bool Panda::can_send(uint32_t addr, bool addr_29b, const uint8_t *dat, uint8_t len, PANDA_CAN_PORT bus) {
|
|
if (bus == PANDA_CAN_UNK) return FALSE;
|
|
if (len > 8) return FALSE;
|
|
PANDA_CAN_MSG msg;
|
|
msg.addr_29b = addr_29b;
|
|
msg.addr = addr;
|
|
msg.len = len;
|
|
memcpy(msg.dat, dat, msg.len);
|
|
msg.bus = bus;
|
|
return this->can_send_many(std::vector<PANDA_CAN_MSG>{msg});
|
|
}
|
|
|
|
PANDA_CAN_MSG Panda::parse_can_recv(PANDA_CAN_MSG_INTERNAL *in_msg_raw) {
|
|
PANDA_CAN_MSG in_msg;
|
|
|
|
in_msg.addr_29b = (bool)(in_msg_raw->rir & CAN_EXTENDED);
|
|
in_msg.addr = (in_msg.addr_29b) ? (in_msg_raw->rir >> 3) : (in_msg_raw->rir >> 21);
|
|
in_msg.recv_time = this->runningTime.getTimePassedUS();
|
|
in_msg.recv_time_point = std::chrono::steady_clock::now();
|
|
//The timestamp from the device is (in_msg_raw->f2 >> 16),
|
|
//but this 16 bit value is a little hard to use. Using a
|
|
//timer since the initialization of this device.
|
|
in_msg.len = in_msg_raw->f2 & 0xF;
|
|
memcpy(in_msg.dat, in_msg_raw->dat, 8);
|
|
|
|
in_msg.is_receipt = ((in_msg_raw->f2 >> 4) & 0x80) == 0x80;
|
|
switch ((in_msg_raw->f2 >> 4) & 0x7F) {
|
|
case PANDA_CAN1:
|
|
in_msg.bus = PANDA_CAN1;
|
|
break;
|
|
case PANDA_CAN2:
|
|
in_msg.bus = PANDA_CAN2;
|
|
break;
|
|
case PANDA_CAN3:
|
|
in_msg.bus = PANDA_CAN3;
|
|
break;
|
|
default:
|
|
in_msg.bus = PANDA_CAN_UNK;
|
|
}
|
|
return in_msg;
|
|
}
|
|
|
|
bool Panda::can_rx_q_push(HANDLE kill_event, DWORD timeoutms) {
|
|
while (1) {
|
|
auto w_ptr = this->w_ptr;
|
|
auto n_ptr = w_ptr + 1;
|
|
if (n_ptr == CAN_RX_QUEUE_LEN) {
|
|
n_ptr = 0;
|
|
}
|
|
|
|
// Pause if there is not a slot available in the queue
|
|
if (n_ptr == this->r_ptr) {
|
|
printf("RX queue full!\n");
|
|
Sleep(1);
|
|
continue;
|
|
}
|
|
|
|
if (this->can_rx_q[n_ptr].complete) {
|
|
// TODO: is ResetEvent() faster?
|
|
CloseHandle(this->can_rx_q[n_ptr].complete);
|
|
}
|
|
|
|
// Overlapped structure required for async read.
|
|
this->can_rx_q[n_ptr].complete = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
memset(&this->can_rx_q[n_ptr].overlapped, sizeof(OVERLAPPED), 0);
|
|
this->can_rx_q[n_ptr].overlapped.hEvent = this->can_rx_q[n_ptr].complete;
|
|
this->can_rx_q[n_ptr].error = 0;
|
|
|
|
if (!WinUsb_ReadPipe(this->usbh, 0x81, this->can_rx_q[n_ptr].data, sizeof(this->can_rx_q[n_ptr].data), &this->can_rx_q[n_ptr].count, &this->can_rx_q[n_ptr].overlapped)) {
|
|
// An overlapped read will return true if done, or false with an
|
|
// error of ERROR_IO_PENDING if the transfer is still in process.
|
|
this->can_rx_q[n_ptr].error = GetLastError();
|
|
}
|
|
|
|
// Process the pipe read call from the previous invocation of this function
|
|
if (this->can_rx_q[w_ptr].error == ERROR_IO_PENDING) {
|
|
HANDLE phSignals[2] = { this->can_rx_q[w_ptr].complete, kill_event };
|
|
auto dwError = WaitForMultipleObjects(kill_event ? 2 : 1, phSignals, FALSE, timeoutms);
|
|
|
|
// Check if packet, timeout (nope), or break
|
|
if (dwError == WAIT_OBJECT_0) {
|
|
// Signal came from our usb object. Read the returned data.
|
|
if (!GetOverlappedResult(this->usbh, &this->can_rx_q[w_ptr].overlapped, &this->can_rx_q[w_ptr].count, TRUE)) {
|
|
// TODO: handle other error cases better.
|
|
dwError = GetLastError();
|
|
printf("Got overlap error %d\n", dwError);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
WinUsb_AbortPipe(this->usbh, 0x81);
|
|
|
|
// Return FALSE to show that the optional signal
|
|
// was set instead of the wait breaking from a
|
|
// message or recoverable error.
|
|
if (dwError == (WAIT_OBJECT_0 + 1)) {
|
|
return FALSE;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
else if (this->can_rx_q[w_ptr].error != 0) { // ERROR_BAD_COMMAND happens when device is unplugged.
|
|
return FALSE;
|
|
}
|
|
|
|
this->w_ptr = n_ptr;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void Panda::can_rx_q_pop(PANDA_CAN_MSG msg_out[], int &count) {
|
|
count = 0;
|
|
|
|
// No data left in queue
|
|
if (this->r_ptr == this->w_ptr) {
|
|
Sleep(1);
|
|
return;
|
|
}
|
|
|
|
auto r_ptr = this->r_ptr;
|
|
for (int i = 0; i < this->can_rx_q[r_ptr].count; i += sizeof(PANDA_CAN_MSG_INTERNAL)) {
|
|
auto in_msg_raw = (PANDA_CAN_MSG_INTERNAL *)(this->can_rx_q[r_ptr].data + i);
|
|
msg_out[count] = parse_can_recv(in_msg_raw);
|
|
++count;
|
|
}
|
|
|
|
// Advance read pointer (wrap around if needed)
|
|
++r_ptr;
|
|
this->r_ptr = (r_ptr == CAN_RX_QUEUE_LEN ? 0 : r_ptr);
|
|
}
|
|
|
|
std::vector<PANDA_CAN_MSG> Panda::can_recv() {
|
|
std::vector<PANDA_CAN_MSG> msg_recv;
|
|
int retcount;
|
|
char buff[sizeof(PANDA_CAN_MSG_INTERNAL) * 4];
|
|
|
|
if (this->bulk_read(0x81, buff, sizeof(buff), (PULONG)&retcount, 0) == FALSE)
|
|
return msg_recv;
|
|
|
|
for (int i = 0; i < retcount; i += sizeof(PANDA_CAN_MSG_INTERNAL)) {
|
|
PANDA_CAN_MSG_INTERNAL *in_msg_raw = (PANDA_CAN_MSG_INTERNAL *)(buff + i);
|
|
auto in_msg = parse_can_recv(in_msg_raw);
|
|
msg_recv.push_back(in_msg);
|
|
}
|
|
|
|
return msg_recv;
|
|
}
|
|
|
|
bool Panda::can_clear(PANDA_CAN_PORT_CLEAR bus) {
|
|
/*Clears all messages from the specified internal CAN ringbuffer as though it were drained.
|
|
bus(int) : can bus number to clear a tx queue, or 0xFFFF to clear the global can rx queue.*/
|
|
return this->control_transfer(REQUEST_OUT, 0xf1, bus, 0, NULL, 0, 0) != -1;
|
|
}
|
|
|
|
std::string Panda::serial_read(PANDA_SERIAL_PORT port_number) {
|
|
std::string result;
|
|
char buff[0x40];
|
|
while (TRUE) {
|
|
int retlen = this->control_transfer(REQUEST_IN, 0xe0, port_number, 0, &buff, 0x40, 0);
|
|
if (retlen <= 0)
|
|
break;
|
|
result += std::string(buff, retlen);
|
|
if (retlen < 0x40) break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int Panda::serial_write(PANDA_SERIAL_PORT port_number, const void* buff, uint16_t len) {
|
|
std::string dat;
|
|
dat += port_number;
|
|
dat += std::string((char*)buff, len);
|
|
int retcount;
|
|
if (this->bulk_write(2, dat.c_str(), len+1, (PULONG)&retcount, 0) == FALSE) return -1;
|
|
return retcount;
|
|
}
|
|
|
|
bool Panda::serial_clear(PANDA_SERIAL_PORT port_number) {
|
|
return this->control_transfer(REQUEST_OUT, 0xf2, port_number, 0, NULL, 0, 0) != -1;
|
|
}
|