mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-20 00:32:11 +08:00
640ab12c72
* Honda Pilot 2017 Port (#161) * Update README.md * Update fingerprints.py * Update carstate.py * Update hondacan.py * Update interface.py * Update interface.py * Update interface.py * Update README.md * Update README.md * Update README.md * Update fingerprints.py * Update carstate.py * Update hondacan.py * Update interface.py * Update carstate.py * Update hondacan.py * Update README.md * Update fingerprints.py * Update carstate.py * Update carstate.py * Update carstate.py * Update hondacan.py * Update interface.py * Update carstate.py * Update carstate.py * Update Pilot Fingerprint * Update fingerprints.py * Give pilot its own definition and not use ILX * add pilot argument * Add Pilot interface * Add pilot argument * Update interface.py * Parse Different gear on pilot * Add steer max * Fixed duplication of steer max value * Adjust PID's for steering * Update carcontroller.py * Change Steer Ratio and wheelbase * Update Steer fault values Steer fault value of 3, does not seem to effect anything * Update Kp,Ki Ratio * Update interface.py * Update readme for Pilot * add pilot * Update fingerprints.py * Update carstate.py * add signals * add signal * fix restricting video upload to wifi * Dibs on SAFETY_GM numerical value To match Panda repo. * Safety Reference for Honda Bosch * Update fingerprints.py (#210) Consolidated my fingerprint and removed duplicates and ordered the fingerprint for the RAV4H. Double Checked. * Interpolate ki/kp for steering PID loop (#200) * Interpolate ki/kp for steering PID loop Very much needed for the Volt port: car ping-pongs with low kp on high speeeds, and the loop is unstable with high kp on low speeds. Also, removes "number or array?" logic from PIController, now that all the callers use interpolation ofr ki/kp. * Pass speed to steering PID loop for ki/kp interpolation * Remove unused numbers import * Slight changes to UI and Fingerprint for Odyssey Elite (#196) * Adding back drive time to UI * Add fingerprint for Odyssey Elite * Removed extended fingerprint for Elite * Revert "Adding back drive time to UI" This reverts commit b9b02f7ff2511f28922f0bea47cd8c70bb9f4010. * Squashed 'panda/' changes from 98f29a4..67d5208 67d5208 fix signedness issue in toyota safety fe15d3f bump pandacan 11c2b08 add fault invalid 2c26e45 add sleep 27c7637 forgot the counter 3a6d7db don't hang bfa7d2e canloader works b259e2a can flasher is close to working 83f2edf isotp can support in softloader 7ae7c79 typo e85cc47 forgot the selfs 190b4f6 start work on canflasher 5c655c9 add recover support ae3457f usbflash is reliable f7a0ab0 pedal usbflash works 585d0f9 add way to call isotp be82899 despite it being bad code, move isotp 000715b start work on pedal canloader 626e312 pedal has a bootstub now 3662d1e redundant check 81e6b0d fix bug 083cd12 should have bounty to refactor that ish b65d30c bad asserts b2e6c3f isotp untested support for subaddr 30fd66a Merge pull request #93 from vntarasov/volt 06f5109 Merge pull request #94 from gregjhogan/can-printer-hex c7d098c Merge pull request #95 from gregjhogan/setup-script 22fe250 Merge pull request #99 from gregjhogan/bit-transition-example ba16ba3 Merge pull request #100 from gregjhogan/j2534-troubleshooting-instructions ad08ea4 Merge pull request #90 from gregjhogan/can-forwarding f3b6f5d added j2534 troubleshooting instructions 858d150 added script to find bits that transition from 0 to 1 c6acac8 added checking pedal interceptor message length f7226ff added brake safety checks d0c2634 added gas safety checks d378e4a removed bosch safety forwarding restriction on 29 bit addresses 5c7ef9e added bosch safety hooks and forwarding 90c64b6 add note 23de8d4 Merge pull request #97 from commaai/pedal_improvements 0261641 added missing python packages b92b235 fix bytearray encode issue 2434f1c Tweak Volt's brake pedal stickiness e2f73d2 enable has a whole byte to itself d5a9e1e correct checksum f8ed9fa better names 986a14c don't alias pointers 9b8472e add watchdog support 8f0add9 handle faults 1d917f8 split gas set into 2 values, and have a fault state 1b77026 j2534 isn't alpha anymore fbcc872 Merge pull request #92 from commaai/pedal 8a6f44b pedal is sending messages 08f464c python 3 bro is bad bro 9390961 kline checksum algo was broken... 3b7c33b add kline debug support aa622bc init values 631ea9f better refactor eb1fd75 add PEDAL adc sets ccaa310 don't build with usb 8d4d763 debug console works bd09883 comma pedal is building 75a29d5 Merge pull request #84 from gregjhogan/j2534-hds eece37d only the panda has gmlan 9f43abe Merge pull request #89 from vntarasov/volt 5364d43 Merge pull request #88 from vntarasov/smaller-firmware 377a1ec bump version for descriptor fix 4fabdf0 Merge pull request #87 from gregjhogan/usb-multi-packet-control 8580773 fix sending WinUSB Extended Properties Feature Descriptor 6908feb Chevy Volt safety 786a004 Enable optimization to reduce firmware size d70f43b hack to fix thinkpad 95ab1ae fixed flow control message padding bbd04d1 updated installer 62216d0 single standalone DLL for J2534 driver 5c9138d fixed 11 bit address issue f3b0ad2 fix LOOPBACK getting set when DATA_RATE is set b750d36 updated README a9a097f lowered CPU utilization 7c26a70 TIS needs unsupported protocols to return an error 42692b4 TIS doesn't like ChannelID being zero cf126bb SET_CONFIG return error for reserved parameters 2e99dbf fix HDS issues 8203cc8 add is_grey e946a54 add insecure_okay flag 4363b3e check webpage 4f59ded add secure mode note 6b11fb5 add autosecuring to tests b27d185 Merge pull request #86 from commaai/better_pairing 4b53b42 elm wifi isn't an automated test 99f85cb Merge pull request #85 from gregjhogan/usb-wcid 0d38060 auto-install WinUSB device driver c6653ca from python import 38cc0ee add wifi_secure_mode, boots in insecure mode git-subtree-dir: panda git-subtree-split: 67d52089a1300b86800d897f2b271e0a24cf6dd6 * Squashed 'opendbc/' changes from 81d9871..aa067f7 aa067f7 Chevy Volt tweaks (#83) a60c6c4 Toyota: change signal name in EPS_STATUS msg ce70b1a extra setme field toyota LKAS_HUD df2a552 toyota missing ACC_CONTROL checksum 48bb293 Revert "Toyota Prius: added a comma specific message to control the speed sent to the EPS" 5f42439 Toyota Prius: added a comma specific message to control the speed sent to the EPS 6f5e8b6 Pedal Interceptor: fault state VAL moved to _comma efd5f5c add setme to honda ACC_HUD 97fc335 add interceptor to civic 6f40f16 update generator script to allow for multiple imports 9ca956b add setme to toyota STEERING_IPAS e5afa57 run generator for ipas scaling 8bd1182 Toyota IPAS: proper steer angle unit f57511e acceleration pedal for gasPressed c8d1dbc high beams also. likely dashboard message. 9f1c78b high beams for genericToggle f037d42 turn signal lights (and thus hazard lights) b35bb08 turn signals 78986cf Revert "turn signals" ba946c9 turn signals 2af3ecc Speed, braking, and distance signals f40ab87 Set packet lengths, adding steering rate, adjusted speed cd59bfa units for speed_right c2fcce2 speed of right vs left side of car 4ef5fae value table for gear status 97c48e2 tighten up speed bits. brake pressue max comment. a0cbfd1 add gear status PRNDL 0c82865 initial signals for chrysler pacifica 2017 hybrid 5ed0540 add set me to toyota LKAS_HUD aecac5d add set me fields to toyota ACC_HUD 5417013 update toyota ACC_CONTROL fields e91e967 Comma Pedal: made GAS_COMMAND 6 bytes d04434a Comma Pedal: added state byte and enable bit c30b2cd Comma Pedal: sending 2 tracks on 0x200 8f72467 Volt doors and belts status (#70) 60f8b6c add set me to lkas hud honda 3c9e335 fix honda pcm gas message size 7ca471d Add 2018 Toyota CHR dbc (#78) 637fe00 set scaling to 1 for brake and gas which have no real unit 62a88d4 Volt: switch to parsing ACC buttons from powertrain CAN (#74) 3fdd47b Volt's gas pedal only and combined gas/acc (#76) 45ec9c9 Add 2017 Honda Ridgeline (#77) cbd186a Add 2018 Camry Hybrid DBC's (#73) 974eeaf Toyota: re-generated the files after cfbc9ae363f98ef 19ea195 Toyota: more vals for LKA_STATE cfbc9ae fixed inconsistent factor for speed in Honda dbc files e7db803 convert all line endings to unix style git-subtree-dir: opendbc git-subtree-split: aa067f7079aa12617f7a37d85233e51af44e1bb2 * openpilot v0.4.3 release * Squashed 'panda/' changes from 67d5208..3125232 3125232 bump version 703c0b4 Gas Interceptor: another fix to gas pressed logic 196d383 Interceptor: fixed gas pressed logic git-subtree-dir: panda git-subtree-split: 31252324d98e701c33cb6aeda20af6b549175764 * Squashed 'opendbc/' changes from aa067f7..91e882d 91e882d Updating bosch dbcs to use new format and bringing in new honda changes (#82) 9b32e2e Fix Checksum errors for CH-R (#86) git-subtree-dir: opendbc git-subtree-split: 91e882d4a04c129e12d39bcff0bbe56b75166e0f * openpilot v0.4.3 release * openpilot v0.4.3.1 release * fix bug in canpacker for Toyotas with DSU connected (#221) * update year on civic
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_NOOUTPUT) {
|
|
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;
|
|
}
|