J2534 iso14230 (#563)

* ISO14230

* ISO9141 (excluding 5 baud init)

* j2534 5 baud init

* disable unsupported pin select protocols

* update README for new installer

* cleanup

* cleanup

* J2534 windows registry ISO9141 flag

* make it easier to select dev J2534 driver

* update README with new installer
master
Greg Hogan 2020-07-10 14:43:31 -07:00 committed by GitHub
parent 390b8bce81
commit b3e278755c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 772 additions and 224 deletions

View File

@ -304,3 +304,4 @@ __pycache__/
# installer
*.exe
*.zip

View File

@ -17,10 +17,9 @@ ______/\\\\\\\\\\\____/\\\\\\\\\_______/\\\\\\\\\\\\\\\______/\\\\\\\\\\________
|_| (Code by Jessy Diamond Exum)
```
# Installing J2534 driver:
[Download](https://github.com/commaai/panda/files/4017364/panda.J2534.driver.install.zip)
[Download](https://github.com/commaai/panda/files/4844692/panda.J2534.driver.install.zip)
Depending on what version of windows you are on, you may need to separately install the WinUSB driver (see next section).
@ -80,8 +79,8 @@ features.
- [ ] **J1850PWM** *(Outdated, and not physically supported by the panda)*
- [X] **CAN**
- [X] **ISO15765**
- [ ] **ISO9141** *(This protocol could be implemented if 5 BAUD init support is added to the panda.)*
- [ ] **ISO14230/KWP2000** *(Could be supported with FAST init, 5baud init if panda adds support for 5bps serial)*
- [X] **ISO9141**
- [X] **ISO14230/KWP2000**
# Building the Project:
@ -116,7 +115,6 @@ code will not work, so without this file, the installer will refuse to build.
- Apply a style-guide and consistent naming convention for Classes/Functions/Variables.
- Send multiple messages (each with a different address) from a given connection at the same time.
- Implement ISO14230/KWP2000 FAST (LIN communication is already supported with the raw panda USB driver).
- Find more documentation about SW_CAN_PS (Single Wire CAN, aka GMLAN).
- Find example of client using a _PS version of a protocol (PS is pin select, and may support using different CAN buses).

View File

@ -7,7 +7,7 @@ J2534Connection::J2534Connection(
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
) : panda_dev(panda_dev), ProtocolID(ProtocolID), Flags(Flags), BaudRate(BaudRate), port(0) { }
) : panda_dev(panda_dev), ProtocolID(ProtocolID), Flags(Flags), BaudRate(BaudRate), Parity(0), port(0) { }
unsigned long J2534Connection::validateTxMsg(PASSTHRU_MSG* msg) {
if (msg->DataSize < this->getMinMsgLen() || msg->DataSize > this->getMaxMsgLen())
@ -60,7 +60,7 @@ long J2534Connection::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMs
long J2534Connection::PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
//There doesn't seem to be much reason to implement the timeout here.
for (int msgnum = 0; msgnum < *pNumMsgs; msgnum++) {
for (unsigned int msgnum = 0; msgnum < *pNumMsgs; msgnum++) {
PASSTHRU_MSG* msg = &pMsg[msgnum];
if (msg->ProtocolID != this->ProtocolID) {
*pNumMsgs = msgnum;
@ -87,7 +87,7 @@ long J2534Connection::PassThruStartPeriodicMsg(PASSTHRU_MSG *pMsg, unsigned long
if (pMsg->ProtocolID != this->ProtocolID) return ERR_MSG_PROTOCOL_ID;
if (TimeInterval < 5 || TimeInterval > 65535) return ERR_INVALID_TIME_INTERVAL;
for (int i = 0; i < this->periodicMessages.size(); i++) {
for (unsigned int i = 0; i < this->periodicMessages.size(); i++) {
if (periodicMessages[i] != nullptr) continue;
*pMsgID = i;
@ -114,11 +114,11 @@ long J2534Connection::PassThruStopPeriodicMsg(unsigned long MsgID) {
long J2534Connection::PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID) {
for (int i = 0; i < this->filters.size(); i++) {
for (unsigned int i = 0; i < this->filters.size(); i++) {
if (filters[i] == nullptr) {
try {
auto newfilter = std::make_shared<J2534MessageFilter>(this, FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg);
for (int check_idx = 0; check_idx < filters.size(); check_idx++) {
for (unsigned int check_idx = 0; check_idx < filters.size(); check_idx++) {
if (filters[check_idx] == nullptr) continue;
if (filters[check_idx] == newfilter) {
filters[i] = nullptr;
@ -147,28 +147,99 @@ long J2534Connection::PassThruIoctl(unsigned long IoctlID, void *pInput, void *p
return STATUS_NOERROR;
}
long J2534Connection::init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) { return ERR_FAILED; }
long J2534Connection::initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput) { return ERR_FAILED; }
long J2534Connection::init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) {
if (pInput->NumOfBytes == 1) {
if (auto panda_ps = this->panda_dev.lock()) {
auto resp = panda_ps->kline_five_baud_init(pInput->BytePtr[0]);
if (resp.size() > 0) {
auto key_bytes = resp.c_str();
if (pOutput->NumOfBytes >= 1) {
pOutput->BytePtr[0] = key_bytes[0];
}
if (pOutput->NumOfBytes >= 2) {
pOutput->BytePtr[1] = key_bytes[1];
}
return STATUS_NOERROR;
}
}
}
return ERR_FAILED;
}
long J2534Connection::initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput) {
if (auto panda_ps = this->panda_dev.lock()) {
auto start_comm = std::string((char*)pInput->Data, pInput->DataSize);
auto resp = panda_ps->kline_wakeup_start_comm(start_comm);
if (resp.size() > 0) {
pOutput->ProtocolID = pInput->ProtocolID;
pOutput->RxStatus = 0;
pOutput->TxFlags = 0;
pOutput->Timestamp = pInput->Timestamp;
pOutput->ExtraDataIndex = resp.size();
memcpy(pOutput->Data, resp.c_str(), resp.size());
pOutput->DataSize = resp.size();
return STATUS_NOERROR;
}
}
return ERR_FAILED;
}
long J2534Connection::clearTXBuff() {
if (auto panda_ps = this->panda_dev.lock()) {
synchronized(staged_writes_lock) {
this->txbuff = {};
panda_ps->panda->can_clear(panda::PANDA_CAN1_TX);
switch (this->ProtocolID)
{
case CAN:
case CAN_PS:
case ISO15765:
case ISO15765_PS:
panda_ps->panda->can_clear(panda::PANDA_CAN1_TX);
break;
case ISO9141:
case ISO9141_PS:
case ISO14230:
case ISO14230_PS:
panda_ps->panda->serial_clear(panda::SERIAL_LIN1);
panda_ps->panda->serial_clear(panda::SERIAL_LIN2);
break;
default:
break;
}
}
return STATUS_NOERROR;
}
return STATUS_NOERROR;
return ERR_FAILED;
}
long J2534Connection::clearRXBuff() {
if (auto panda_ps = this->panda_dev.lock()) {
synchronized(messageRxBuff_mutex) {
this->messageRxBuff = {};
panda_ps->panda->can_clear(panda::PANDA_CAN_RX);
switch (this->ProtocolID)
{
case CAN:
case CAN_PS:
case ISO15765:
case ISO15765_PS:
panda_ps->panda->can_clear(panda::PANDA_CAN_RX);
break;
case ISO9141:
case ISO9141_PS:
case ISO14230:
case ISO14230_PS:
panda_ps->panda->serial_clear(panda::SERIAL_LIN1);
panda_ps->panda->serial_clear(panda::SERIAL_LIN2);
break;
default:
break;
}
}
return STATUS_NOERROR;
}
return STATUS_NOERROR;
return ERR_FAILED;
}
long J2534Connection::clearPeriodicMsgs() {
for (int i = 0; i < this->periodicMessages.size(); i++) {
for (unsigned int i = 0; i < this->periodicMessages.size(); i++) {
if (periodicMessages[i] == nullptr) continue;
this->periodicMessages[i]->cancel();
this->periodicMessages[i] = nullptr;
@ -185,6 +256,10 @@ void J2534Connection::setBaud(unsigned long baud) {
this->BaudRate = baud;
}
void J2534Connection::setParity(unsigned long parity) {
this->Parity = parity;
}
void J2534Connection::schedultMsgTx(std::shared_ptr<Action> msgout) {
if (auto panda_ps = this->panda_dev.lock()) {
synchronized(staged_writes_lock) {
@ -226,6 +301,9 @@ void J2534Connection::processIOCTLSetConfig(unsigned long Parameter, unsigned lo
case LOOPBACK: // 0 (OFF), 1 (ON) [0]
this->loopback = (Value != 0);
break;
case PARITY:
this->setParity(Value);
break;
case ISO15765_WFT_MAX:
break;
case NODE_ADDRESS: // J1850PWM Related (Not supported by panda). HDS requires these to 'work'.
@ -247,7 +325,6 @@ void J2534Connection::processIOCTLSetConfig(unsigned long Parameter, unsigned lo
case TIDLE:
case TINIL:
case TWUP:
case PARITY:
case T1_MAX: // SCI related options. The panda does not appear to support this
case T2_MAX:
case T3_MAX:
@ -259,9 +336,9 @@ void J2534Connection::processIOCTLSetConfig(unsigned long Parameter, unsigned lo
}
// reserved parameters usually mean special equiptment is required
if (Parameter >= 0x20) {
throw ERR_NOT_SUPPORTED;
}
//if (Parameter >= 0x20) {
// throw ERR_NOT_SUPPORTED;
//}
}
unsigned long J2534Connection::processIOCTLGetConfig(unsigned long Parameter) {

View File

@ -51,14 +51,15 @@ public:
//IOCTL functions
long init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput);
long initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput);
virtual long init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput);
virtual long initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput);
long clearTXBuff();
long clearRXBuff();
long clearPeriodicMsgs();
long clearMsgFilters();
virtual void setBaud(unsigned long baud);
virtual void setParity(unsigned long parity);
unsigned long getBaud() {
return this->BaudRate;
@ -124,6 +125,7 @@ protected:
unsigned long ProtocolID;
unsigned long Flags;
unsigned long BaudRate;
unsigned long Parity;
unsigned long port;
std::weak_ptr<PandaJ2534Device> panda_dev;

View File

@ -0,0 +1,83 @@
#include "stdafx.h"
#include "J2534Connection_ISO14230.h"
#include "MessageTx_ISO14230.h"
#include "Timer.h"
J2534Connection_ISO14230::J2534Connection_ISO14230(
std::shared_ptr<PandaJ2534Device> panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
) : J2534Connection(panda_dev, ProtocolID, Flags, BaudRate) {
this->port = 0;
if (BaudRate % 100 || BaudRate < 2400 || BaudRate > 115200)
throw ERR_INVALID_BAUDRATE;
panda_dev->panda->set_uart_baud(panda::SERIAL_LIN1, BaudRate);
panda_dev->panda->set_uart_baud(panda::SERIAL_LIN2, BaudRate);
};
unsigned long J2534Connection_ISO14230::validateTxMsg(PASSTHRU_MSG* msg) {
if (msg->DataSize < this->getMinMsgLen() || msg->DataSize > this->getMaxMsgLen())
return ERR_INVALID_MSG;
return STATUS_NOERROR;
}
std::shared_ptr<MessageTx> J2534Connection_ISO14230::parseMessageTx(PASSTHRU_MSG& msg) {
return std::dynamic_pointer_cast<MessageTx>(std::make_shared<MessageTx_ISO14230>(shared_from_this(), msg));
}
void J2534Connection_ISO14230::setBaud(unsigned long BaudRate) {
if (auto panda_dev = this->getPandaDev()) {
if (BaudRate % 100 || BaudRate < 2400 || BaudRate > 115200)
throw ERR_NOT_SUPPORTED;
panda_dev->panda->set_uart_baud(panda::SERIAL_LIN1, BaudRate);
panda_dev->panda->set_uart_baud(panda::SERIAL_LIN2, BaudRate);
return J2534Connection::setBaud(BaudRate);
} else {
throw ERR_DEVICE_NOT_CONNECTED;
}
}
void J2534Connection_ISO14230::setParity(unsigned long Parity) {
if (auto panda_dev = this->getPandaDev()) {
panda::PANDA_SERIAL_PORT_PARITY parity;
switch (Parity) {
case 0:
parity = panda::PANDA_PARITY_OFF;
break;
case 1:
parity = panda::PANDA_PARITY_ODD;
break;
case 2:
parity = panda::PANDA_PARITY_EVEN;
break;
default:
throw ERR_NOT_SUPPORTED;
}
panda_dev->panda->set_uart_parity(panda::SERIAL_LIN1, parity);
panda_dev->panda->set_uart_parity(panda::SERIAL_LIN2, parity);
return J2534Connection::setParity(Parity);
}
else {
throw ERR_DEVICE_NOT_CONNECTED;
}
}
void J2534Connection_ISO14230::processMessage(const J2534Frame& msg) {
FILTER_RESULT filter_res = FILTER_RESULT_NEUTRAL;
for (auto filter : this->filters) {
if (filter == nullptr) continue;
FILTER_RESULT current_check_res = filter->check(msg);
if (current_check_res == FILTER_RESULT_BLOCK) return;
if (current_check_res == FILTER_RESULT_PASS) filter_res = FILTER_RESULT_PASS;
}
if (filter_res == FILTER_RESULT_PASS) {
addMsgToRxQueue(J2534Frame(msg.ProtocolID, START_OF_MESSAGE, 0, 0));
addMsgToRxQueue(msg);
}
}

View File

@ -0,0 +1,39 @@
#pragma once
#include "J2534Connection.h"
#include "panda_shared/panda.h"
class J2534Connection_ISO14230 : public J2534Connection {
public:
J2534Connection_ISO14230(
std::shared_ptr<PandaJ2534Device> panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
);
virtual unsigned long validateTxMsg(PASSTHRU_MSG* msg);
virtual std::shared_ptr<MessageTx> parseMessageTx(PASSTHRU_MSG& pMsg);
virtual void setBaud(unsigned long baud);
virtual void setParity(unsigned long Parity);
virtual unsigned long getMinMsgLen() {
return 2;
}
virtual unsigned long getMaxMsgLen() {
return KLINE_MSG_MAX_LEN;
}
virtual unsigned long getMaxMsgSingleFrameLen() {
return KLINE_MSG_MAX_LEN;
}
virtual bool isProtoCan() {
return FALSE;
}
virtual void processMessage(const J2534Frame& msg);
};

View File

@ -18,10 +18,20 @@ public:
Data += msg_in.addr & 0xFF;
Data += std::string((char*)&msg_in.dat, msg_in.len);
Timestamp = msg_in.recv_time;
TxFlags = 0;
RxStatus = (msg_in.addr_29b ? CAN_29BIT_ID : 0) |
(msg_in.is_receipt ? TX_MSG_TYPE : 0);
}
J2534Frame(unsigned long protocol, const panda::PANDA_KLINE_MSG& msg_in) {
ProtocolID = protocol;
ExtraDataIndex = msg_in.data.size() - (msg_in.valid ? 1 : 0);
Data = msg_in.data;
Timestamp = 0;
TxFlags = 0;
RxStatus = 0;
}
J2534Frame(const PASSTHRU_MSG& msg) {
this->ProtocolID = msg.ProtocolID;
this->RxStatus = msg.RxStatus;

View File

@ -79,7 +79,7 @@ FILTER_RESULT J2534MessageFilter::check(const J2534Frame& msg) {
if (msg.Data.size() < this->maskMsg.size()) {
matches = FALSE;
} else {
for (int i = 0; i < this->maskMsg.size(); i++) {
for (unsigned int i = 0; i < this->maskMsg.size(); i++) {
if (this->patternMsg[i] != (msg.Data[i] & this->maskMsg[i])) {
matches = FALSE;
break;

View File

@ -0,0 +1,40 @@
#include "stdafx.h"
#include "MessageTx_ISO14230.h"
#include "J2534Connection_ISO14230.h"
MessageTx_ISO14230::MessageTx_ISO14230(
std::shared_ptr<J2534Connection> connection_in,
PASSTHRU_MSG& to_send
) : MessageTx(connection_in, to_send), sentyet(FALSE), txInFlight(FALSE) {};
void MessageTx_ISO14230::execute() {
if (auto conn_sp = this->connection.lock()) {
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
if (panda_dev_sp->kline_send(this->fullmsg.Data)) {
if (auto conn_sp = this->connection.lock())
{
if (conn_sp->loopback) {
auto echo = J2534Frame(conn_sp->getProtocol(), TX_MSG_TYPE, 0, this->fullmsg.Timestamp);
echo.Data = std::string(this->fullmsg.Data);
echo.ExtraDataIndex = this->fullmsg.Data.size();
conn_sp->addMsgToRxQueue(J2534Frame(conn_sp->getProtocol(), START_OF_MESSAGE, 0, this->fullmsg.Timestamp));
conn_sp->addMsgToRxQueue(echo);
}
}
this->txInFlight = FALSE;
this->sentyet = TRUE;
}
// remove action since echo was read back in kline_send()
panda_dev_sp->removeConnectionTopAction(conn_sp, shared_from_this());
}
}
}
BOOL MessageTx_ISO14230::checkTxReceipt(J2534Frame frame) {
throw "not implemented!";
}
void MessageTx_ISO14230::reset() {
sentyet = FALSE;
txInFlight = FALSE;
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <memory>
#include "MessageTx.h"
class J2534Connection;
class MessageTx_ISO14230 : public MessageTx
{
public:
MessageTx_ISO14230(
std::shared_ptr<J2534Connection> connection_in,
PASSTHRU_MSG& to_send
);
virtual void execute();
virtual BOOL checkTxReceipt(J2534Frame frame);
virtual BOOL isFinished() {
return !txInFlight && sentyet;
};
virtual BOOL txReady() {
return !sentyet;
};
virtual void reset();
private:
BOOL sentyet;
BOOL txInFlight;
};

View File

@ -12,6 +12,9 @@ PandaJ2534Device::PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) : tx
this->thread_kill_event = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD klineListenThreadID;
this->kline_recv_handle = CreateThread(NULL, 0, _kline_recv_threadBootstrap, (LPVOID)this, 0, &klineListenThreadID);
DWORD canListenThreadID;
this->can_recv_handle = CreateThread(NULL, 0, _can_recv_threadBootstrap, (LPVOID)this, 0, &canListenThreadID);
@ -25,7 +28,11 @@ PandaJ2534Device::PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) : tx
PandaJ2534Device::~PandaJ2534Device() {
SetEvent(this->thread_kill_event);
DWORD res = WaitForSingleObject(this->can_recv_handle, INFINITE);
DWORD res = WaitForSingleObject(this->kline_recv_handle, INFINITE);
CloseHandle(this->kline_recv_handle);
res = WaitForSingleObject(this->can_recv_handle, INFINITE);
CloseHandle(this->can_recv_handle);
res = WaitForSingleObject(this->can_process_handle, INFINITE);
@ -73,6 +80,89 @@ DWORD PandaJ2534Device::addChannel(std::shared_ptr<J2534Connection>& conn, unsig
return STATUS_NOERROR;
}
std::string PandaJ2534Device::kline_five_baud_init(uint8_t addr) {
synchronized(kline_rx_mutex) {
Sleep(300); // W1
this->panda->kline_slow_init(true, true, addr);
// wakeup sometimes adds a leading null char
this->panda->serial_clear(panda::SERIAL_LIN1);
this->panda->serial_clear(panda::SERIAL_LIN2);
// read 0x55 KB1 KB2
auto key_bytes = this->panda->serial_read(panda::SERIAL_LIN1, 3, 300);
auto bytes = key_bytes.c_str();
if (key_bytes.size() == 3 && bytes[0] == 0x55) {
Sleep(25); // W4
// send inverted KB2
auto kb2_inv = std::string(1, ~bytes[2]);
if (this->panda->serial_write(panda::SERIAL_LIN1, kb2_inv)) {
// read addr inverted
auto addr_inv = this->panda->serial_read(panda::SERIAL_LIN1, 1, 50);
if (addr_inv.size() == 1 && addr_inv.c_str()[0] == ~addr) {
// return only KB1 KB2
return key_bytes.substr(1, 2);
}
}
}
}
return std::string();
}
std::string PandaJ2534Device::kline_wakeup_start_comm(std::string& start_comm) {
synchronized(kline_rx_mutex) {
Sleep(25);
this->panda->kline_fast_init(true, true);
// wakeup sometimes adds a leading null char
this->panda->serial_clear(panda::SERIAL_LIN1);
this->panda->serial_clear(panda::SERIAL_LIN2);
// send start communication message
if (this->panda->kline_send(panda::SERIAL_LIN1, start_comm)) {
Sleep(25);
// read start communication response
return this->panda->serial_read(panda::SERIAL_LIN1, KLINE_MSG_MAX_LEN, 20);
}
}
return std::string();
}
BOOL PandaJ2534Device::kline_send(std::string& data) {
// since send reads echo, block rx thread
synchronized(kline_rx_mutex) {
return this->panda->kline_send(panda::SERIAL_LIN1, data) ? TRUE : FALSE;
}
}
DWORD PandaJ2534Device::kline_recv_thread() {
this->panda->serial_clear(panda::SERIAL_LIN1);
while (true) {
if (!WaitForSingleObject(this->thread_kill_event, 0)) {
break;
}
std::vector<panda::PANDA_KLINE_MSG> msg_recv;
synchronized(kline_rx_mutex) {
msg_recv = this->panda->kline_recv(panda::SERIAL_LIN1);
}
if (msg_recv.empty()) {
Sleep(1);
continue;
}
for (auto msg : msg_recv) {
for (auto& conn : this->connections) {
if (conn != nullptr && !conn->isProtoCan()) {
J2534Frame msg_out(conn->getProtocol(), msg);
conn->processMessage(msg_out);
}
}
}
}
return 0;
}
DWORD PandaJ2534Device::can_recv_thread() {
this->panda->can_clear(panda::PANDA_CAN_RX);
this->panda->can_rx_q_push(this->thread_kill_event);

View File

@ -52,9 +52,19 @@ public:
//transmission is complete. This tracks what is still waiting to hear an echo.
std::queue<std::shared_ptr<MessageTx>> txMsgsAwaitingEcho;
std::string kline_five_baud_init(uint8_t addr);
std::string kline_wakeup_start_comm(std::string& start_comm);
BOOL kline_send(std::string& data);
private:
HANDLE thread_kill_event;
HANDLE kline_recv_handle;
static DWORD WINAPI _kline_recv_threadBootstrap(LPVOID This) {
return ((PandaJ2534Device*)This)->kline_recv_thread();
}
DWORD kline_recv_thread();
HANDLE can_recv_handle;
static DWORD WINAPI _can_recv_threadBootstrap(LPVOID This) {
return ((PandaJ2534Device*)This)->can_recv_thread();
@ -80,4 +90,6 @@ private:
std::set<std::shared_ptr<J2534Connection>> ConnTxSet;
Mutex connTXSet_mutex;
BOOL txInProgress;
Mutex kline_rx_mutex;
};

View File

@ -7,6 +7,7 @@
#include "J2534_v0404.h"
#include "panda_shared/panda.h"
#include "J2534Connection.h"
#include "J2534Connection_ISO14230.h"
#include "J2534Connection_CAN.h"
#include "J2534Connection_ISO15765.h"
#include "PandaJ2534Device.h"
@ -95,10 +96,10 @@ PANDAJ2534DLL_API long PTAPI PassThruOpen(void *pName, unsigned long *pDevice
if (new_panda == nullptr) {
if(sn == "" && pandas.size() == 1)
return ret_code(ERR_DEVICE_IN_USE);
for (auto& pn : pandas) {
if (pn->panda->get_usb_sn() == sn)
return ret_code(ERR_DEVICE_IN_USE);
}
//for (auto& pn : pandas) {
// if (pn->panda->get_usb_sn() == sn)
// return ret_code(ERR_DEVICE_IN_USE);
//}
return ret_code(ERR_DEVICE_NOT_CONNECTED);
}
@ -140,36 +141,36 @@ PANDAJ2534DLL_API long PTAPI PassThruConnect(unsigned long DeviceID, unsigned lo
switch (ProtocolID) {
//SW seems to refer to Single Wire. https://www.nxp.com/files-static/training_pdf/20451_BUS_COMM_WBT.pdf
//SW_ protocols may be touched on here: https://www.iso.org/obp/ui/#iso:std:iso:22900:-2:ed-1:v1:en
//case J1850VPW: // These protocols are outdated and will not be supported. HDS wants them to not fail to open.
//case J1850PWM: // ^-- it appears HDS no longer needs this, and TIS needs it disabled --^
//case J1850VPW_PS:
//case J1850PWM_PS:
case ISO9141: //This protocol could be implemented if 5 BAUD init support is added to the panda.
case ISO9141_PS:
case ISO14230: //Only supporting Fast init until panda adds support for 5 BAUD init.
case ISO14230_PS:
conn = std::make_shared<J2534Connection>(panda, ProtocolID, Flags, BaudRate);
break;
case CAN:
case CAN_PS:
//case SW_CAN_PS:
conn = std::make_shared<J2534Connection_CAN>(panda, ProtocolID, Flags, BaudRate);
break;
case ISO15765:
case ISO15765_PS:
conn = std::make_shared<J2534Connection_ISO15765>(panda, ProtocolID, Flags, BaudRate);
break;
//case SW_ISO15765_PS: // SW = Single Wire. GMLAN is a SW CAN protocol
//case GM_UART_PS: // PS = Pin Select. Handles different ports.
//Looks like SCI based protocols may not be compatible with the panda:
//http://mdhmotors.com/can-communications-vehicle-network-protocols/3/
//case SCI_A_ENGINE:
//case SCI_A_TRANS:
//case SCI_B_ENGINE:
//case J1850VPW: // These protocols are outdated and will not be supported. HDS wants them to not fail to open.
//case J1850PWM: // ^-- it appears HDS no longer needs this, and TIS needs it disabled --^
//case J1850VPW_PS:
//case J1850PWM_PS:
case ISO9141:
//case ISO9141_PS:
case ISO14230:
//case ISO14230_PS:
conn = std::make_shared<J2534Connection_ISO14230>(panda, ProtocolID, Flags, BaudRate);
break;
case CAN:
//case CAN_PS:
//case SW_CAN_PS:
conn = std::make_shared<J2534Connection_CAN>(panda, ProtocolID, Flags, BaudRate);
break;
case ISO15765:
//case ISO15765_PS:
conn = std::make_shared<J2534Connection_ISO15765>(panda, ProtocolID, Flags, BaudRate);
break;
//case SW_ISO15765_PS: // SW = Single Wire. GMLAN is a SW CAN protocol
//case GM_UART_PS: // PS = Pin Select. Handles different ports.
//Looks like SCI based protocols may not be compatible with the panda:
//http://mdhmotors.com/can-communications-vehicle-network-protocols/3/
//case SCI_A_ENGINE:
//case SCI_A_TRANS:
//case SCI_B_ENGINE:
//case SCI_B_TRANS:
//case J2610_PS:
default:
return ret_code(ERR_INVALID_PROTOCOL_ID);
//case J2610_PS:
default:
return ret_code(ERR_INVALID_PROTOCOL_ID);
}
} catch (int e) {
return ret_code(e);
@ -424,6 +425,7 @@ PANDAJ2534DLL_API long PTAPI PassThruIoctl(unsigned long ChannelID, unsigned lon
break;
default:
printf("Got unknown IIOCTL %X\n", IoctlID);
return ret_code(ERR_INVALID_IOCTL_ID);
}
return ret_code(STATUS_NOERROR);

View File

@ -91,6 +91,7 @@
<ClInclude Include="..\panda\panda.h" />
<ClInclude Include="constants_ISO15765.h" />
<ClInclude Include="dllmain.h" />
<ClInclude Include="J2534Connection_ISO14230.h" />
<ClInclude Include="MessagePeriodic.h" />
<ClInclude Include="MessageRx.h" />
<ClInclude Include="J2534Connection.h" />
@ -103,6 +104,7 @@
<ClInclude Include="MessageTx.h" />
<ClInclude Include="MessageTxTimeout.h" />
<ClInclude Include="MessageTx_CAN.h" />
<ClInclude Include="MessageTx_ISO14230.h" />
<ClInclude Include="MessageTx_ISO15765.h" />
<ClInclude Include="PandaJ2534Device.h" />
<ClInclude Include="resource.h" />
@ -122,11 +124,13 @@
</ClCompile>
<ClCompile Include="J2534Connection.cpp" />
<ClCompile Include="J2534Connection_CAN.cpp" />
<ClCompile Include="J2534Connection_ISO14230.cpp" />
<ClCompile Include="J2534Connection_ISO15765.cpp" />
<ClCompile Include="J2534MessageFilter.cpp" />
<ClCompile Include="MessagePeriodic.cpp" />
<ClCompile Include="MessageTxTimeout.cpp" />
<ClCompile Include="MessageTx_CAN.cpp" />
<ClCompile Include="MessageTx_ISO14230.cpp" />
<ClCompile Include="MessageTx_ISO15765.cpp" />
<ClCompile Include="PandaJ2534Device.cpp" />
<ClCompile Include="pandaJ2534DLL.cpp" />

View File

@ -1,155 +1,173 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Header Files\depends">
<UniqueIdentifier>{a4cd0bce-0a2a-43d9-9c9f-b21a3b607e90}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\boilerplate">
<UniqueIdentifier>{a85ee263-380d-4d37-b167-6629cfd5177f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\boilerplate">
<UniqueIdentifier>{010a0176-a146-4d3a-824a-fd683904774d}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\J2534_CAN">
<UniqueIdentifier>{71c9502a-ee59-4d5e-873f-c9cc792e7c76}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\J2534_ISO15765">
<UniqueIdentifier>{4fd3183a-c457-430c-b762-f767a5788bca}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\J2534_ISO15765">
<UniqueIdentifier>{53cd179e-22d8-43e2-bc61-516d3861fae6}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\J2534_CAN">
<UniqueIdentifier>{08d548b5-4d0b-4ce4-85e6-5ff3fc987758}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="J2534Connection.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PandaJ2534Device.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534MessageFilter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="synchronize.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534Connection_CAN.h">
<Filter>Header Files\J2534_CAN</Filter>
</ClInclude>
<ClInclude Include="J2534Connection_ISO15765.h">
<Filter>Header Files\J2534_ISO15765</Filter>
</ClInclude>
<ClInclude Include="J2534_v0404.h">
<Filter>Header Files\depends</Filter>
</ClInclude>
<ClInclude Include="..\panda\panda.h">
<Filter>Header Files\depends</Filter>
</ClInclude>
<ClInclude Include="dllmain.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="J2534Frame.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MessageTx_ISO15765.h">
<Filter>Header Files\J2534_ISO15765</Filter>
</ClInclude>
<ClInclude Include="MessageRx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="constants_ISO15765.h">
<Filter>Header Files\J2534_ISO15765</Filter>
</ClInclude>
<ClInclude Include="MessageTx_CAN.h">
<Filter>Header Files\J2534_CAN</Filter>
</ClInclude>
<ClInclude Include="MessageTxTimeout.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Action.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MessageTx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MessagePeriodic.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pandaJ2534DLL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534Connection.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PandaJ2534Device.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534MessageFilter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534Connection_CAN.cpp">
<Filter>Source Files\J2534_CAN</Filter>
</ClCompile>
<ClCompile Include="J2534Connection_ISO15765.cpp">
<Filter>Source Files\J2534_ISO15765</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files\boilerplate</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files\boilerplate</Filter>
</ClCompile>
<ClCompile Include="MessageTx_ISO15765.cpp">
<Filter>Source Files\J2534_ISO15765</Filter>
</ClCompile>
<ClCompile Include="MessageTxTimeout.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MessageTx_CAN.cpp">
<Filter>Source Files\J2534_CAN</Filter>
</ClCompile>
<ClCompile Include="MessagePeriodic.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="pandaJ2534DLL.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="ClassDiagram.cd" />
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Header Files\depends">
<UniqueIdentifier>{a4cd0bce-0a2a-43d9-9c9f-b21a3b607e90}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\boilerplate">
<UniqueIdentifier>{a85ee263-380d-4d37-b167-6629cfd5177f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\boilerplate">
<UniqueIdentifier>{010a0176-a146-4d3a-824a-fd683904774d}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\J2534_CAN">
<UniqueIdentifier>{71c9502a-ee59-4d5e-873f-c9cc792e7c76}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\J2534_ISO15765">
<UniqueIdentifier>{4fd3183a-c457-430c-b762-f767a5788bca}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\J2534_ISO15765">
<UniqueIdentifier>{53cd179e-22d8-43e2-bc61-516d3861fae6}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\J2534_CAN">
<UniqueIdentifier>{08d548b5-4d0b-4ce4-85e6-5ff3fc987758}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\J2534_ISO14230">
<UniqueIdentifier>{b5c1874e-d3f8-4465-89c5-2e2b7e9f4fa4}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\J2534_ISO14230">
<UniqueIdentifier>{b5a39015-f3ca-4888-bd5f-785aeec91345}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="J2534Connection.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PandaJ2534Device.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534MessageFilter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="synchronize.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534Connection_CAN.h">
<Filter>Header Files\J2534_CAN</Filter>
</ClInclude>
<ClInclude Include="J2534Connection_ISO15765.h">
<Filter>Header Files\J2534_ISO15765</Filter>
</ClInclude>
<ClInclude Include="J2534_v0404.h">
<Filter>Header Files\depends</Filter>
</ClInclude>
<ClInclude Include="..\panda\panda.h">
<Filter>Header Files\depends</Filter>
</ClInclude>
<ClInclude Include="dllmain.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files\boilerplate</Filter>
</ClInclude>
<ClInclude Include="J2534Frame.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MessageTx_ISO15765.h">
<Filter>Header Files\J2534_ISO15765</Filter>
</ClInclude>
<ClInclude Include="MessageRx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="constants_ISO15765.h">
<Filter>Header Files\J2534_ISO15765</Filter>
</ClInclude>
<ClInclude Include="MessageTx_CAN.h">
<Filter>Header Files\J2534_CAN</Filter>
</ClInclude>
<ClInclude Include="MessageTxTimeout.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Action.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MessageTx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MessagePeriodic.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534Connection_ISO14230.h">
<Filter>Header Files\J2534_ISO14230</Filter>
</ClInclude>
<ClInclude Include="MessageTx_ISO14230.h">
<Filter>Header Files\J2534_ISO14230</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pandaJ2534DLL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534Connection.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PandaJ2534Device.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534MessageFilter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534Connection_CAN.cpp">
<Filter>Source Files\J2534_CAN</Filter>
</ClCompile>
<ClCompile Include="J2534Connection_ISO15765.cpp">
<Filter>Source Files\J2534_ISO15765</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files\boilerplate</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files\boilerplate</Filter>
</ClCompile>
<ClCompile Include="MessageTx_ISO15765.cpp">
<Filter>Source Files\J2534_ISO15765</Filter>
</ClCompile>
<ClCompile Include="MessageTxTimeout.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MessageTx_CAN.cpp">
<Filter>Source Files\J2534_CAN</Filter>
</ClCompile>
<ClCompile Include="MessagePeriodic.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534Connection_ISO14230.cpp">
<Filter>Source Files\J2534_ISO14230</Filter>
</ClCompile>
<ClCompile Include="MessageTx_ISO14230.cpp">
<Filter>Source Files\J2534_ISO14230</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="pandaJ2534DLL.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="ClassDiagram.cd" />
</ItemGroup>
</Project>

View File

@ -131,7 +131,7 @@ Section "J2534 Driver"
WriteRegDWORD HKLM "${J2534_Reg_Path}" "SCI_B_ENGINE" 00000000
WriteRegDWORD HKLM "${J2534_Reg_Path}" "SCI_B_TRANS" 00000000
WriteRegDWORD HKLM "${J2534_Reg_Path}" "J1850PWM" 00000000
WriteRegDWORD HKLM "${J2534_Reg_Path}" "ISO9141" 00000000
WriteRegDWORD HKLM "${J2534_Reg_Path}" "ISO9141" 00000001
WriteRegDWORD HKLM "${J2534_Reg_Path}" "ISO14230" 00000001
WriteRegStr HKLM "${J2534_Reg_Path}" "Name" "panda"
WriteRegStr HKLM "${J2534_Reg_Path}" "Vendor" "comma.ai"

View File

@ -11,6 +11,9 @@
#define CAN_TRANSMIT 1
#define CAN_EXTENDED 4
#define KLINE_HEADER_FMT_ADDR_MASK 0xC0
#define KLINE_HEADER_FMT_LEN_MASK 0x3F
using namespace panda;
Panda::Panda(
@ -451,7 +454,7 @@ bool Panda::can_rx_q_push(HANDLE kill_event, DWORD timeoutms) {
return TRUE;
}
void Panda::can_rx_q_pop(PANDA_CAN_MSG msg_out[], int &count) {
void Panda::can_rx_q_pop(PANDA_CAN_MSG msg_out[], int& count) {
count = 0;
// No data left in queue
@ -461,8 +464,8 @@ void Panda::can_rx_q_pop(PANDA_CAN_MSG msg_out[], int &count) {
}
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);
for (unsigned long 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;
}
@ -481,7 +484,7 @@ std::vector<PANDA_CAN_MSG> Panda::can_recv() {
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);
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);
}
@ -508,15 +511,127 @@ std::string Panda::serial_read(PANDA_SERIAL_PORT port_number) {
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;
std::string Panda::serial_read(PANDA_SERIAL_PORT port_number, unsigned int len, unsigned int timeout_ms) {
std::string result = std::string();
auto ms_remaining = timeout_ms;
char buff[0x40];
while (len > 0 && ms_remaining > 0) {
int retlen = this->control_transfer(REQUEST_IN, 0xe0, port_number, 0, &buff, min(len, 0x40), 0);
if (retlen <= 0) {
ms_remaining -= 1;
Sleep(1);
continue;
}
result += std::string(buff, retlen);
len -= retlen;
ms_remaining = timeout_ms;
}
return result;
}
int Panda::serial_write(PANDA_SERIAL_PORT port_number, const std::string& data) {
int retcount = 0;
for (int i = 0; i < data.size(); i += 0x3F) {
std::string slice = std::string(1, (char)port_number) + data.substr(i, min(data.size() - i, 0x3F));
int retlen;
if (this->bulk_write(2, slice.c_str(), slice.size(), (PULONG)&retlen, 0) == FALSE) return -1;
if (retlen != slice.size()) return -1;
retcount += retlen - 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;
}
uint8_t Panda::kline_checksum(const char* data, size_t size) {
unsigned int checksum = 0;
for (int i = 0; i < size; i++) {
checksum += (uint8_t)data[i];
}
return (uint8_t)(checksum % 0x100);
}
PANDA_KLINE_MSG Panda::kline_parse(const std::string& data, bool add_checksum) {
auto bytes = data.c_str();
auto size = data.size();
PANDA_KLINE_MSG msg_in;
ZeroMemory(&msg_in, sizeof(PANDA_KLINE_MSG));
msg_in.data = std::string(data);
unsigned int i = 0;
unsigned int len = 0;
unsigned int expected_len = 2;
if (size > i) {
// data layout: Fmt [Tgt] [Src] [Len] Data CS <- [ ] indicates optional
msg_in.addr_type = (PANDA_KLINE_ADDR_TYPE)(bytes[i] & KLINE_HEADER_FMT_ADDR_MASK);
len = bytes[i++] & KLINE_HEADER_FMT_LEN_MASK;
if (msg_in.addr_type != 0 && size > i + 2) {
expected_len += 2;
msg_in.target = bytes[i++];
msg_in.source = bytes[i++];
}
if (len == 0 && size > i + 1) {
expected_len += 1;
len = bytes[i++];
}
expected_len += len;
if (expected_len == size) {
auto checksum = this->kline_checksum(bytes, size - 1);
if (msg_in.checksum == checksum) {
msg_in.valid = true;
}
}
else if (add_checksum && expected_len == size + 1) {
msg_in.checksum = this->kline_checksum(bytes, size);
msg_in.data += std::string(1, (char)msg_in.checksum);
msg_in.valid = true;
}
}
return msg_in;
}
bool Panda::kline_slow_init(bool k, bool l, uint8_t addr) {
return this->control_transfer(REQUEST_OUT, 0xf4, k && l ? 2 : (uint16_t)l, (uint16_t)addr, NULL, 0, 0) != -1;
}
bool Panda::kline_fast_init(bool k, bool l) {
return this->control_transfer(REQUEST_OUT, 0xf0, k && l ? 2 : (uint16_t)l, 0, NULL, 0, 0) != -1;
}
std::vector<PANDA_KLINE_MSG> Panda::kline_recv(PANDA_SERIAL_PORT port_number) {
if (port_number != SERIAL_LIN1 && port_number != SERIAL_LIN2) {
throw "invalid serial port number";
}
std::vector<PANDA_KLINE_MSG> msg_recv;
while (1) {
// P1/P4 max time between bytes is 20ms
auto result = this->serial_read(port_number, KLINE_MSG_MAX_LEN, 20);
if (result.size() == 0) {
break;
}
auto msg_in = this->kline_parse(result, false);
// TODO: only add if msg_in.valid ???
msg_recv.push_back(msg_in);
}
return msg_recv;
}
bool Panda::kline_send(PANDA_SERIAL_PORT port_number, const std::string& data) {
if (port_number != SERIAL_LIN1 && port_number != SERIAL_LIN2) {
throw "invalid serial port number";
}
auto msg_out = this->kline_parse(data, true);
auto result = this->serial_write(port_number, msg_out.data);
auto echo = this->serial_read(port_number, msg_out.data.size(), 5);
if (echo != msg_out.data) {
return false;
}
return true;
}

View File

@ -33,6 +33,7 @@
#define LIN_MSG_MAX_LEN 10
#define CAN_RX_QUEUE_LEN 10000
#define CAN_RX_MSG_LEN 1000
#define KLINE_MSG_MAX_LEN 260
//template class __declspec(dllexport) std::basic_string<char>;
@ -108,6 +109,21 @@ namespace panda {
bool addr_29b;
} PANDA_CAN_MSG;
typedef enum _PANDA_KLINE_ADDR_TYPE : uint8_t {
PANDA_KLINE_ADDR_NONE = 0,
PANDA_KLINE_ADDR_PHYS = 0x80,
PANDA_KLINE_ADDR_FUNC = 0xC0,
} PANDA_KLINE_ADDR_TYPE;
typedef struct _PANDA_KLINE_MSG {
PANDA_KLINE_ADDR_TYPE addr_type;
uint8_t target;
uint8_t source;
std::string data;
uint8_t checksum;
bool valid;
} PANDA_KLINE_MSG;
//Copied from https://stackoverflow.com/a/31488113
class Timer
{
@ -179,8 +195,17 @@ namespace panda {
bool can_clear(PANDA_CAN_PORT_CLEAR bus);
std::string serial_read(PANDA_SERIAL_PORT port_number);
int serial_write(PANDA_SERIAL_PORT port_number, const void* buff, uint16_t len);
std::string serial_read(PANDA_SERIAL_PORT port_number, unsigned int len, unsigned int timeout_ms);
int serial_write(PANDA_SERIAL_PORT port_number, const std::string& data);
bool serial_clear(PANDA_SERIAL_PORT port_number);
uint8_t kline_checksum(const char* data, size_t size);
PANDA_KLINE_MSG kline_parse(const std::string& data, bool add_checksum);
bool kline_slow_init(bool k, bool l, uint8_t addr);
bool kline_fast_init(bool k, bool l);
std::vector<PANDA_KLINE_MSG> kline_recv(PANDA_SERIAL_PORT port_number);
bool kline_send(PANDA_SERIAL_PORT port_number, const std::string& data);
private:
Panda(
WINUSB_INTERFACE_HANDLE WinusbHandle,