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 # installer
*.exe *.exe
*.zip

View File

@ -17,10 +17,9 @@ ______/\\\\\\\\\\\____/\\\\\\\\\_______/\\\\\\\\\\\\\\\______/\\\\\\\\\\________
|_| (Code by Jessy Diamond Exum) |_| (Code by Jessy Diamond Exum)
``` ```
# Installing J2534 driver: # 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). 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)* - [ ] **J1850PWM** *(Outdated, and not physically supported by the panda)*
- [X] **CAN** - [X] **CAN**
- [X] **ISO15765** - [X] **ISO15765**
- [ ] **ISO9141** *(This protocol could be implemented if 5 BAUD init support is added to the panda.)* - [X] **ISO9141**
- [ ] **ISO14230/KWP2000** *(Could be supported with FAST init, 5baud init if panda adds support for 5bps serial)* - [X] **ISO14230/KWP2000**
# Building the Project: # 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. - 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. - 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 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). - 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 ProtocolID,
unsigned long Flags, unsigned long Flags,
unsigned long BaudRate 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) { unsigned long J2534Connection::validateTxMsg(PASSTHRU_MSG* msg) {
if (msg->DataSize < this->getMinMsgLen() || msg->DataSize > this->getMaxMsgLen()) 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) { 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. //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]; PASSTHRU_MSG* msg = &pMsg[msgnum];
if (msg->ProtocolID != this->ProtocolID) { if (msg->ProtocolID != this->ProtocolID) {
*pNumMsgs = msgnum; *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 (pMsg->ProtocolID != this->ProtocolID) return ERR_MSG_PROTOCOL_ID;
if (TimeInterval < 5 || TimeInterval > 65535) return ERR_INVALID_TIME_INTERVAL; 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; if (periodicMessages[i] != nullptr) continue;
*pMsgID = i; *pMsgID = i;
@ -114,11 +114,11 @@ long J2534Connection::PassThruStopPeriodicMsg(unsigned long MsgID) {
long J2534Connection::PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg, long J2534Connection::PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID) { 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) { if (filters[i] == nullptr) {
try { try {
auto newfilter = std::make_shared<J2534MessageFilter>(this, FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg); 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] == nullptr) continue;
if (filters[check_idx] == newfilter) { if (filters[check_idx] == newfilter) {
filters[i] = nullptr; filters[i] = nullptr;
@ -147,28 +147,99 @@ long J2534Connection::PassThruIoctl(unsigned long IoctlID, void *pInput, void *p
return STATUS_NOERROR; return STATUS_NOERROR;
} }
long J2534Connection::init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) { return ERR_FAILED; } long J2534Connection::init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) {
long J2534Connection::initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput) { return ERR_FAILED; } 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() { long J2534Connection::clearTXBuff() {
if (auto panda_ps = this->panda_dev.lock()) { if (auto panda_ps = this->panda_dev.lock()) {
synchronized(staged_writes_lock) { synchronized(staged_writes_lock) {
this->txbuff = {}; 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() { long J2534Connection::clearRXBuff() {
if (auto panda_ps = this->panda_dev.lock()) { if (auto panda_ps = this->panda_dev.lock()) {
synchronized(messageRxBuff_mutex) { synchronized(messageRxBuff_mutex) {
this->messageRxBuff = {}; 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() { 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; if (periodicMessages[i] == nullptr) continue;
this->periodicMessages[i]->cancel(); this->periodicMessages[i]->cancel();
this->periodicMessages[i] = nullptr; this->periodicMessages[i] = nullptr;
@ -185,6 +256,10 @@ void J2534Connection::setBaud(unsigned long baud) {
this->BaudRate = baud; this->BaudRate = baud;
} }
void J2534Connection::setParity(unsigned long parity) {
this->Parity = parity;
}
void J2534Connection::schedultMsgTx(std::shared_ptr<Action> msgout) { void J2534Connection::schedultMsgTx(std::shared_ptr<Action> msgout) {
if (auto panda_ps = this->panda_dev.lock()) { if (auto panda_ps = this->panda_dev.lock()) {
synchronized(staged_writes_lock) { synchronized(staged_writes_lock) {
@ -226,6 +301,9 @@ void J2534Connection::processIOCTLSetConfig(unsigned long Parameter, unsigned lo
case LOOPBACK: // 0 (OFF), 1 (ON) [0] case LOOPBACK: // 0 (OFF), 1 (ON) [0]
this->loopback = (Value != 0); this->loopback = (Value != 0);
break; break;
case PARITY:
this->setParity(Value);
break;
case ISO15765_WFT_MAX: case ISO15765_WFT_MAX:
break; break;
case NODE_ADDRESS: // J1850PWM Related (Not supported by panda). HDS requires these to 'work'. 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 TIDLE:
case TINIL: case TINIL:
case TWUP: case TWUP:
case PARITY:
case T1_MAX: // SCI related options. The panda does not appear to support this case T1_MAX: // SCI related options. The panda does not appear to support this
case T2_MAX: case T2_MAX:
case T3_MAX: case T3_MAX:
@ -259,9 +336,9 @@ void J2534Connection::processIOCTLSetConfig(unsigned long Parameter, unsigned lo
} }
// reserved parameters usually mean special equiptment is required // reserved parameters usually mean special equiptment is required
if (Parameter >= 0x20) { //if (Parameter >= 0x20) {
throw ERR_NOT_SUPPORTED; // throw ERR_NOT_SUPPORTED;
} //}
} }
unsigned long J2534Connection::processIOCTLGetConfig(unsigned long Parameter) { unsigned long J2534Connection::processIOCTLGetConfig(unsigned long Parameter) {

View File

@ -51,14 +51,15 @@ public:
//IOCTL functions //IOCTL functions
long init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput); virtual long init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput);
long initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput); virtual long initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput);
long clearTXBuff(); long clearTXBuff();
long clearRXBuff(); long clearRXBuff();
long clearPeriodicMsgs(); long clearPeriodicMsgs();
long clearMsgFilters(); long clearMsgFilters();
virtual void setBaud(unsigned long baud); virtual void setBaud(unsigned long baud);
virtual void setParity(unsigned long parity);
unsigned long getBaud() { unsigned long getBaud() {
return this->BaudRate; return this->BaudRate;
@ -124,6 +125,7 @@ protected:
unsigned long ProtocolID; unsigned long ProtocolID;
unsigned long Flags; unsigned long Flags;
unsigned long BaudRate; unsigned long BaudRate;
unsigned long Parity;
unsigned long port; unsigned long port;
std::weak_ptr<PandaJ2534Device> panda_dev; 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 += msg_in.addr & 0xFF;
Data += std::string((char*)&msg_in.dat, msg_in.len); Data += std::string((char*)&msg_in.dat, msg_in.len);
Timestamp = msg_in.recv_time; Timestamp = msg_in.recv_time;
TxFlags = 0;
RxStatus = (msg_in.addr_29b ? CAN_29BIT_ID : 0) | RxStatus = (msg_in.addr_29b ? CAN_29BIT_ID : 0) |
(msg_in.is_receipt ? TX_MSG_TYPE : 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) { J2534Frame(const PASSTHRU_MSG& msg) {
this->ProtocolID = msg.ProtocolID; this->ProtocolID = msg.ProtocolID;
this->RxStatus = msg.RxStatus; this->RxStatus = msg.RxStatus;

View File

@ -79,7 +79,7 @@ FILTER_RESULT J2534MessageFilter::check(const J2534Frame& msg) {
if (msg.Data.size() < this->maskMsg.size()) { if (msg.Data.size() < this->maskMsg.size()) {
matches = FALSE; matches = FALSE;
} else { } 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])) { if (this->patternMsg[i] != (msg.Data[i] & this->maskMsg[i])) {
matches = FALSE; matches = FALSE;
break; 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); 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; DWORD canListenThreadID;
this->can_recv_handle = CreateThread(NULL, 0, _can_recv_threadBootstrap, (LPVOID)this, 0, &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() { PandaJ2534Device::~PandaJ2534Device() {
SetEvent(this->thread_kill_event); 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); CloseHandle(this->can_recv_handle);
res = WaitForSingleObject(this->can_process_handle, INFINITE); res = WaitForSingleObject(this->can_process_handle, INFINITE);
@ -73,6 +80,89 @@ DWORD PandaJ2534Device::addChannel(std::shared_ptr<J2534Connection>& conn, unsig
return STATUS_NOERROR; 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() { DWORD PandaJ2534Device::can_recv_thread() {
this->panda->can_clear(panda::PANDA_CAN_RX); this->panda->can_clear(panda::PANDA_CAN_RX);
this->panda->can_rx_q_push(this->thread_kill_event); 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. //transmission is complete. This tracks what is still waiting to hear an echo.
std::queue<std::shared_ptr<MessageTx>> txMsgsAwaitingEcho; 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: private:
HANDLE thread_kill_event; 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; HANDLE can_recv_handle;
static DWORD WINAPI _can_recv_threadBootstrap(LPVOID This) { static DWORD WINAPI _can_recv_threadBootstrap(LPVOID This) {
return ((PandaJ2534Device*)This)->can_recv_thread(); return ((PandaJ2534Device*)This)->can_recv_thread();
@ -80,4 +90,6 @@ private:
std::set<std::shared_ptr<J2534Connection>> ConnTxSet; std::set<std::shared_ptr<J2534Connection>> ConnTxSet;
Mutex connTXSet_mutex; Mutex connTXSet_mutex;
BOOL txInProgress; BOOL txInProgress;
Mutex kline_rx_mutex;
}; };

View File

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

View File

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

View File

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

View File

@ -11,6 +11,9 @@
#define CAN_TRANSMIT 1 #define CAN_TRANSMIT 1
#define CAN_EXTENDED 4 #define CAN_EXTENDED 4
#define KLINE_HEADER_FMT_ADDR_MASK 0xC0
#define KLINE_HEADER_FMT_LEN_MASK 0x3F
using namespace panda; using namespace panda;
Panda::Panda( Panda::Panda(
@ -451,7 +454,7 @@ bool Panda::can_rx_q_push(HANDLE kill_event, DWORD timeoutms) {
return TRUE; 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; count = 0;
// No data left in queue // 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; auto r_ptr = this->r_ptr;
for (int i = 0; i < this->can_rx_q[r_ptr].count; i += sizeof(PANDA_CAN_MSG_INTERNAL)) { 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); 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); msg_out[count] = parse_can_recv(in_msg_raw);
++count; ++count;
} }
@ -481,7 +484,7 @@ std::vector<PANDA_CAN_MSG> Panda::can_recv() {
return msg_recv; return msg_recv;
for (int i = 0; i < retcount; i += sizeof(PANDA_CAN_MSG_INTERNAL)) { 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); auto in_msg = parse_can_recv(in_msg_raw);
msg_recv.push_back(in_msg); msg_recv.push_back(in_msg);
} }
@ -508,15 +511,127 @@ std::string Panda::serial_read(PANDA_SERIAL_PORT port_number) {
return result; return result;
} }
int Panda::serial_write(PANDA_SERIAL_PORT port_number, const void* buff, uint16_t len) { std::string Panda::serial_read(PANDA_SERIAL_PORT port_number, unsigned int len, unsigned int timeout_ms) {
std::string dat; std::string result = std::string();
dat += port_number; auto ms_remaining = timeout_ms;
dat += std::string((char*)buff, len); char buff[0x40];
int retcount; while (len > 0 && ms_remaining > 0) {
if (this->bulk_write(2, dat.c_str(), len+1, (PULONG)&retcount, 0) == FALSE) return -1; 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; return retcount;
} }
bool Panda::serial_clear(PANDA_SERIAL_PORT port_number) { bool Panda::serial_clear(PANDA_SERIAL_PORT port_number) {
return this->control_transfer(REQUEST_OUT, 0xf2, port_number, 0, NULL, 0, 0) != -1; 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 LIN_MSG_MAX_LEN 10
#define CAN_RX_QUEUE_LEN 10000 #define CAN_RX_QUEUE_LEN 10000
#define CAN_RX_MSG_LEN 1000 #define CAN_RX_MSG_LEN 1000
#define KLINE_MSG_MAX_LEN 260
//template class __declspec(dllexport) std::basic_string<char>; //template class __declspec(dllexport) std::basic_string<char>;
@ -108,6 +109,21 @@ namespace panda {
bool addr_29b; bool addr_29b;
} PANDA_CAN_MSG; } 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 //Copied from https://stackoverflow.com/a/31488113
class Timer class Timer
{ {
@ -179,8 +195,17 @@ namespace panda {
bool can_clear(PANDA_CAN_PORT_CLEAR bus); bool can_clear(PANDA_CAN_PORT_CLEAR bus);
std::string serial_read(PANDA_SERIAL_PORT port_number); 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); 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: private:
Panda( Panda(
WINUSB_INTERFACE_HANDLE WinusbHandle, WINUSB_INTERFACE_HANDLE WinusbHandle,