J2534_WIN: STYLE ONLY. Split files for my sanity.

master
Jessy Diamond Exum 2017-09-09 03:25:36 -07:00
parent 7036cf9206
commit 30615a3774
18 changed files with 510 additions and 368 deletions

View File

@ -301,3 +301,6 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
# installer
*.exe

View File

@ -1,5 +1,4 @@
#ifndef _PANDA_H_
#define _PANDA_H_
#pragma once
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the PANDA_EXPORTS
@ -174,4 +173,3 @@ namespace panda {
};
}
#endif

View File

@ -0,0 +1,86 @@
#include "stdafx.h"
#include "J2534Connection.h"
J2534Connection::J2534Connection(
panda::Panda* panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
) : panda_dev(panda_dev), ProtocolID(ProtocolID), Flags(Flags), BaudRate(BaudRate), port(0) {
InitializeCriticalSectionAndSpinCount(&this->message_access_lock, 0x00000400);
}
J2534Connection::~J2534Connection() {
DeleteCriticalSection(&this->message_access_lock);
}
long J2534Connection::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
*pNumMsgs = 0;
return STATUS_NOERROR;
}
long J2534Connection::PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) { return STATUS_NOERROR; }
long J2534Connection::PassThruStartPeriodicMsg(PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval) { return STATUS_NOERROR; }
long J2534Connection::PassThruStopPeriodicMsg(unsigned long MsgID) { return STATUS_NOERROR; }
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++) {
if (filters[i] == nullptr) {
filters[i].reset(new J2534MessageFilter(FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg));
*pFilterID = i;
return STATUS_NOERROR;
}
}
return ERR_EXCEEDED_LIMIT;
}
long J2534Connection::PassThruStopMsgFilter(unsigned long FilterID) {
if (FilterID >= this->filters.size() || this->filters[FilterID] == nullptr)
return ERR_INVALID_FILTER_ID;
this->filters[FilterID] = nullptr;
return STATUS_NOERROR;
}
long J2534Connection::PassThruIoctl(unsigned long IoctlID, void *pInput, void *pOutput) {
return STATUS_NOERROR;
}
long J2534Connection::init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) { return STATUS_NOERROR; }
long J2534Connection::initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput) { return STATUS_NOERROR; }
long J2534Connection::clearTXBuff() { return STATUS_NOERROR; }
long J2534Connection::clearRXBuff() { return STATUS_NOERROR; }
long J2534Connection::clearPeriodicMsgs() { return STATUS_NOERROR; }
long J2534Connection::clearMsgFilters() {
for (auto& filter : this->filters) filter = nullptr;
return STATUS_NOERROR;
}
long J2534Connection::clearFunctMsgLookupTable(PASSTHRU_MSG* pInput) { return STATUS_NOERROR; }
long J2534Connection::addtoFunctMsgLookupTable(PASSTHRU_MSG* pInput) { return STATUS_NOERROR; }
long J2534Connection::deleteFromFunctMsgLookupTable() { return STATUS_NOERROR; }
long J2534Connection::setBaud(unsigned long baud) {
this->BaudRate = baud;
return STATUS_NOERROR;
}
unsigned long J2534Connection::getBaud() {
return this->BaudRate;
}
unsigned long J2534Connection::getProtocol() {
return this->ProtocolID;
}
bool J2534Connection::isProtoCan() {
return this->ProtocolID == CAN || this->ProtocolID == CAN_PS;
}
unsigned long J2534Connection::getPort() {
return this->port;
}
void J2534Connection::processMessage(const PASSTHRU_MSG_INTERNAL& msg) {
EnterCriticalSection(&this->message_access_lock);
this->messages.push(msg);
LeaveCriticalSection(&this->message_access_lock);
}

View File

@ -0,0 +1,63 @@
#pragma once
#include "panda/panda.h"
#include "J2534_v0404.h"
#include "J2534MessageFilter.h"
class J2534Connection {
public:
J2534Connection(
panda::Panda* panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
);
~J2534Connection();
virtual long PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
virtual long PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
virtual long PassThruStartPeriodicMsg(PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval);
virtual long PassThruStopPeriodicMsg(unsigned long MsgID);
virtual long PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID);
virtual long PassThruStopMsgFilter(unsigned long FilterID);
virtual long PassThruIoctl(unsigned long IoctlID, void *pInput, void *pOutput);
long init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput);
long initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput);
long clearTXBuff();
long clearRXBuff();
long clearPeriodicMsgs();
long clearMsgFilters();
long clearFunctMsgLookupTable(PASSTHRU_MSG* pInput);
long addtoFunctMsgLookupTable(PASSTHRU_MSG* pInput);
long deleteFromFunctMsgLookupTable();
long setBaud(unsigned long baud);
unsigned long getBaud();
unsigned long getProtocol();
bool isProtoCan();
unsigned long getPort();
void processMessage(const PASSTHRU_MSG_INTERNAL& msg);
bool loopback = FALSE;
protected:
unsigned long ProtocolID;
unsigned long Flags;
unsigned long BaudRate;
unsigned long port;
//Should only be used while the panda device exists, so a pointer should be ok.
panda::Panda* panda_dev;
std::queue<PASSTHRU_MSG_INTERNAL> messages;
std::array<std::unique_ptr<J2534MessageFilter>, 10> filters;
CRITICAL_SECTION message_access_lock;
};

View File

@ -0,0 +1,74 @@
#include "stdafx.h"
#include "J2534Connection_CAN.h"
#include "Timer.h"
#define val_is_29bit(num) (((num) & CAN_29BIT_ID) == CAN_29BIT_ID)
J2534Connection_CAN::J2534Connection_CAN(
panda::Panda* panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
) : J2534Connection(panda_dev, ProtocolID, Flags, BaudRate) {
this->port = 0;
};
long J2534Connection_CAN::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
//Timeout of 0 means return immediately. Non zero means WAIT for that time then return. Dafuk.
long err_code = STATUS_NOERROR;
Timer t = Timer();
unsigned long msgnum = 0;
while (msgnum < *pNumMsgs) {
if (Timeout > 0 && t.getTimePassed() >= Timeout) {
err_code = ERR_TIMEOUT;
break;
}
EnterCriticalSection(&this->message_access_lock);
if (Timeout == 0 && this->messages.empty()) {
LeaveCriticalSection(&this->message_access_lock);
break;
}
auto msg_in = this->messages.front();
this->messages.pop();
LeaveCriticalSection(&this->message_access_lock);
//if (this->_is_29bit() != msg_in.addr_29b) {}
PASSTHRU_MSG *msg_out = &pMsg[msgnum++];
msg_out->ProtocolID = this->ProtocolID;
msg_out->DataSize = msg_in.DataSize;
memcpy(msg_out->Data, msg_in.Data.c_str(), msg_in.DataSize);
msg_out->Timestamp = msg_in.Timestamp;
msg_out->RxStatus = msg_in.RxStatus ? CAN_29BIT_ID : 0;
if (msgnum == *pNumMsgs) break;
}
if (msgnum == 0)
err_code = ERR_BUFFER_EMPTY;
*pNumMsgs = msgnum;
return err_code;
}
long J2534Connection_CAN::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++) {
PASSTHRU_MSG* msg = &pMsg[msgnum];
if (msg->ProtocolID != this->ProtocolID) {
*pNumMsgs = msgnum;
return ERR_MSG_PROTOCOL_ID;
}
if (msg->DataSize < 4 || msg->DataSize >(8 + 4) || val_is_29bit(msg->TxFlags) != this->_is_29bit()) {
*pNumMsgs = msgnum;
return ERR_INVALID_MSG;
}
uint32_t addr = msg->Data[0] << 24 | msg->Data[1] << 16 | msg->Data[2] << 8 | msg->Data[3];
if (this->panda_dev->can_send(addr, this->_is_29bit(), &msg->Data[4], msg->DataSize - 4, panda::PANDA_CAN1) == FALSE) {
*pNumMsgs = msgnum;
return ERR_INVALID_MSG;
}
}
return STATUS_NOERROR;
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "J2534Connection.h"
#include "panda/panda.h"
class J2534Connection_CAN : public J2534Connection {
public:
J2534Connection_CAN(
panda::Panda* panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
);
virtual long PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
virtual long PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
bool _is_29bit() {
return (this->Flags & CAN_29BIT_ID) == CAN_29BIT_ID;
}
};

View File

@ -0,0 +1,24 @@
#include "stdafx.h"
#include "J2534MessageFilter.h"
J2534MessageFilter::J2534MessageFilter(
unsigned int filtertype,
PASSTHRU_MSG *pMaskMsg,
PASSTHRU_MSG *pPatternMsg,
PASSTHRU_MSG *pFlowControlMsg
) : filtertype(filtertype) {
if (pMaskMsg)
memcpy(&this->MaskMsg, pMaskMsg, sizeof(PASSTHRU_MSG));
else
memset(&this->MaskMsg, 0, sizeof(PASSTHRU_MSG));
if (pPatternMsg)
memcpy(&this->PatternMsg, pPatternMsg, sizeof(PASSTHRU_MSG));
else
memset(&this->PatternMsg, 0, sizeof(PASSTHRU_MSG));
if (pFlowControlMsg)
memcpy(&this->FlowControlMsg, pFlowControlMsg, sizeof(PASSTHRU_MSG));
else
memset(&this->FlowControlMsg, 0, sizeof(PASSTHRU_MSG));
};

View File

@ -0,0 +1,17 @@
#pragma once
#include "J2534_v0404.h"
class J2534MessageFilter {
public:
J2534MessageFilter(
unsigned int filtertype,
PASSTHRU_MSG *pMaskMsg,
PASSTHRU_MSG *pPatternMsg,
PASSTHRU_MSG *pFlowControlMsg
);
private:
unsigned int filtertype;
PASSTHRU_MSG MaskMsg;
PASSTHRU_MSG PatternMsg;
PASSTHRU_MSG FlowControlMsg;
};

View File

@ -381,6 +381,17 @@ typedef struct
unsigned char Data[4128];
} PASSTHRU_MSG;
typedef struct
{
unsigned long ProtocolID;
unsigned long RxStatus;
unsigned long TxFlags;
unsigned long Timestamp;
unsigned long DataSize;
unsigned long ExtraDataIndex;
std::string Data;
} PASSTHRU_MSG_INTERNAL;
//
// J2534-1 v04.04 Function Prototypes

View File

@ -0,0 +1,94 @@
#include "stdafx.h"
#include "PandaJ2534Device.h"
PandaJ2534Device::PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) {
this->panda = std::move(new_panda);
this->panda->set_can_speed_kbps(panda::PANDA_CAN1, 500);
this->panda->set_safety_mode(panda::SAFETY_ALLOUTPUT);
this->panda->set_can_loopback(TRUE);
//this->panda->set_can_loopback(FALSE);
this->panda->set_alt_setting(1);
this->panda->reset_can_interrupt_pipe();
DWORD threadid;
this->can_kill_event = CreateEvent(NULL, TRUE, FALSE, NULL);
this->can_thread_handle = CreateThread(NULL, 0, _threadBootstrap, (LPVOID)this, 0, &threadid);
printf("Created PandaDevice\n");
};
PandaJ2534Device::~PandaJ2534Device() {
SetEvent(this->can_kill_event);
DWORD res = WaitForSingleObject(this->can_thread_handle, INFINITE);
CloseHandle(this->can_thread_handle);
}
std::unique_ptr<PandaJ2534Device> PandaJ2534Device::openByName(std::string sn) {
auto p = panda::Panda::openPanda("");
if (p == nullptr)
return nullptr;
return std::unique_ptr<PandaJ2534Device>(new PandaJ2534Device(std::move(p)));
}
DWORD PandaJ2534Device::closeChannel(unsigned long ChannelID) {
if (this->connections.size() <= ChannelID) return ERR_INVALID_CHANNEL_ID;
if (this->connections[ChannelID] == nullptr) return ERR_DEVICE_NOT_CONNECTED;
this->connections[ChannelID] = nullptr;
return STATUS_NOERROR;
}
DWORD PandaJ2534Device::addChannel(J2534Connection* conn, unsigned long* channel_id) {
int channel_index = -1;
for (unsigned int i = 0; i < this->connections.size(); i++)
if (this->connections[i] == nullptr) {
channel_index = i;
break;
}
if (channel_index == -1) {
if (this->connections.size() == 0xFFFF) //channelid max 16 bits
return ERR_FAILED; //Too many channels
this->connections.push_back(nullptr);
channel_index = this->connections.size() - 1;
}
this->connections[channel_index].reset(conn);
*channel_id = channel_index;
return STATUS_NOERROR;
}
DWORD WINAPI PandaJ2534Device::_threadBootstrap(LPVOID This) {
return ((PandaJ2534Device*)This)->can_recv_thread();
}
DWORD PandaJ2534Device::can_recv_thread() {
DWORD err = TRUE;
while (err) {
std::vector<panda::PANDA_CAN_MSG> msg_recv;
err = this->panda->can_recv_async(this->can_kill_event, msg_recv);
for (auto msg_in : msg_recv) {
//if (this->_is_29bit() != msg_in.addr_29b) {}
PASSTHRU_MSG_INTERNAL msg_out;
msg_out.ProtocolID = CAN;
msg_out.DataSize = msg_in.len + 4;
msg_out.Data.reserve(msg_out.DataSize);
msg_out.Data += msg_in.addr >> 24;
msg_out.Data += (msg_in.addr >> 16) & 0xFF;
msg_out.Data += (msg_in.addr >> 8) & 0xFF;
msg_out.Data += msg_in.addr & 0xFF;
std::string tmp = std::string((char*)&msg_in.dat, msg_in.len);
msg_out.Data += tmp;
msg_out.Timestamp = msg_in.recv_time;
msg_out.RxStatus = msg_in.addr_29b ? CAN_29BIT_ID : 0;
// TODO: Make this more efficient
for (auto& conn : this->connections)
if (conn->isProtoCan() && conn->getPort() == msg_in.bus)
conn->processMessage(msg_out);
}
}
return STATUS_NOERROR;
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <memory>
#include "J2534_v0404.h"
#include "panda/panda.h"
#include "J2534Connection.h"
class PandaJ2534Device {
public:
PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda);
~PandaJ2534Device();
static std::unique_ptr<PandaJ2534Device> openByName(std::string sn);
DWORD closeChannel(unsigned long ChannelID);
DWORD addChannel(J2534Connection* conn, unsigned long* channel_id);
std::unique_ptr<panda::Panda> panda;
std::vector<std::unique_ptr<J2534Connection>> connections;
private:
static DWORD WINAPI _threadBootstrap(LPVOID This);
DWORD can_recv_thread();
HANDLE can_thread_handle;
HANDLE can_kill_event;
};

View File

@ -0,0 +1,17 @@
#include "stdafx.h"
#include "Timer.h"
Timer::Timer()
{
start = std::chrono::time_point_cast<std::chrono::milliseconds>(clock::now());
}
// gets the time elapsed from construction.
long /*milliseconds*/ Timer::getTimePassed(){
// get the new time
auto end = clock::now();
// return the difference of the times
return (end - start).count();
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <chrono>
//Copied from https://stackoverflow.com/a/31488113
class Timer
{
using clock = std::chrono::system_clock;
using time_point_type = std::chrono::time_point < clock, std::chrono::milliseconds >;
public:
Timer();
// gets the time elapsed from construction.
long /*milliseconds*/ getTimePassed();
private:
time_point_type start;
};

View File

@ -3,359 +3,12 @@
// https://web.archive.org/web/20130805013326/https://tunertools.com/prodimages/DrewTech/Manuals/PassThru_API-1.pdf
#include "stdafx.h"
#include "J2534_v0404.h"
#include "panda/panda.h"
#include "pandaJ2534DLL.h"
#include "J2534_v0404.h"
#include <string>
#include <array>
#include <queue>
#include <ctime>
#include <chrono>
// A quick way to avoid the name mangling that __stdcall liked to do
#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
class timer
{
// alias our types for simplicity
using clock = std::chrono::system_clock;
using time_point_type = std::chrono::time_point < clock, std::chrono::milliseconds >;
public:
// default constructor that stores the start time
timer()
{
start = std::chrono::time_point_cast<std::chrono::milliseconds>(clock::now());
}
// gets the time elapsed from construction.
long /*milliseconds*/ getTimePassed()
{
// get the new time
auto end = clock::now();
// return the difference of the times
return (end - start).count();
}
private:
time_point_type start;
};
typedef struct
{
unsigned long ProtocolID;
unsigned long RxStatus;
unsigned long TxFlags;
unsigned long Timestamp;
unsigned long DataSize;
unsigned long ExtraDataIndex;
std::string Data;
} PASSTHRU_MSG_INTERNAL;
class J2534_Message_Filter {
public:
J2534_Message_Filter(
unsigned int filtertype,
PASSTHRU_MSG *pMaskMsg,
PASSTHRU_MSG *pPatternMsg,
PASSTHRU_MSG *pFlowControlMsg
) : filtertype(filtertype) {
if (pMaskMsg)
memcpy(&this->MaskMsg, pMaskMsg, sizeof(PASSTHRU_MSG));
else
memset(&this->MaskMsg, 0, sizeof(PASSTHRU_MSG));
if (pPatternMsg)
memcpy(&this->PatternMsg, pPatternMsg, sizeof(PASSTHRU_MSG));
else
memset(&this->PatternMsg, 0, sizeof(PASSTHRU_MSG));
if (pFlowControlMsg)
memcpy(&this->FlowControlMsg, pFlowControlMsg, sizeof(PASSTHRU_MSG));
else
memset(&this->FlowControlMsg, 0, sizeof(PASSTHRU_MSG));
};
private:
unsigned int filtertype;
PASSTHRU_MSG MaskMsg;
PASSTHRU_MSG PatternMsg;
PASSTHRU_MSG FlowControlMsg;
};
class J2534Connection {
public:
J2534Connection(
panda::Panda* panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
) : panda_dev(panda_dev), ProtocolID(ProtocolID), Flags(Flags), BaudRate(BaudRate), port(0) {
InitializeCriticalSectionAndSpinCount(&this->message_access_lock, 0x00000400);
}
~J2534Connection() {
DeleteCriticalSection(&this->message_access_lock);
}
virtual long PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) { *pNumMsgs = 0; return STATUS_NOERROR; };
virtual long PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) { return STATUS_NOERROR; };
virtual long PassThruStartPeriodicMsg(PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval) { return STATUS_NOERROR; };
virtual long PassThruStopPeriodicMsg(unsigned long MsgID) { return STATUS_NOERROR; };
virtual long 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++) {
if (filters[i] == nullptr) {
filters[i].reset(new J2534_Message_Filter(FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg));
*pFilterID = i;
return STATUS_NOERROR;
}
}
return ERR_EXCEEDED_LIMIT;
};
virtual long PassThruStopMsgFilter(unsigned long FilterID) {
if (FilterID >= this->filters.size() || this->filters[FilterID] == nullptr)
return ERR_INVALID_FILTER_ID;
this->filters[FilterID] = nullptr;
return STATUS_NOERROR;
};
virtual long PassThruIoctl(unsigned long IoctlID, void *pInput, void *pOutput) { return STATUS_NOERROR; };
long init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) { return STATUS_NOERROR; };
long initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput) { return STATUS_NOERROR; };
long clearTXBuff() { return STATUS_NOERROR; };
long clearRXBuff() { return STATUS_NOERROR; };
long clearPeriodicMsgs() { return STATUS_NOERROR; };
long clearMsgFilters() {
for (auto& filter : this->filters) filter = nullptr;
return STATUS_NOERROR;
};
long clearFunctMsgLookupTable(PASSTHRU_MSG* pInput) { return STATUS_NOERROR; };
long addtoFunctMsgLookupTable(PASSTHRU_MSG* pInput) { return STATUS_NOERROR; };
long deleteFromFunctMsgLookupTable() { return STATUS_NOERROR; };
long setBaud(unsigned long baud) {
this->BaudRate = baud;
return STATUS_NOERROR;
}
unsigned long getBaud() {
return this->BaudRate;
}
unsigned long getProtocol() {
return this->ProtocolID;
}
bool isProtoCan() {
return this->ProtocolID == CAN || this->ProtocolID == CAN_PS;
}
unsigned long getPort() {
return this->port;
}
bool loopback = FALSE;
void processMessage(const PASSTHRU_MSG_INTERNAL& msg) {
EnterCriticalSection(&this->message_access_lock);
this->messages.push(msg);
LeaveCriticalSection(&this->message_access_lock);
}
protected:
unsigned long ProtocolID;
unsigned long Flags;
unsigned long BaudRate;
unsigned long port;
//Should only be used while the panda device exists, so a pointer should be ok.
panda::Panda* panda_dev;
std::queue<PASSTHRU_MSG_INTERNAL> messages;
std::array<std::unique_ptr<J2534_Message_Filter>, 10> filters;
CRITICAL_SECTION message_access_lock;
};
#define val_is_29bit(num) (((num) & CAN_29BIT_ID) == CAN_29BIT_ID)
class CAN_J2534Connection : public J2534Connection {
public:
CAN_J2534Connection(
panda::Panda* panda_dev,
unsigned long ProtocolID,
unsigned long Flags,
unsigned long BaudRate
) : J2534Connection(panda_dev, ProtocolID, Flags, BaudRate) {
this->port = 0;
};
virtual long PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
//Timeout of 0 means return immediately. Non zero means WAIT for that time then return. Dafuk.
long err_code = STATUS_NOERROR;
timer t = timer();
unsigned long msgnum = 0;
while (msgnum < *pNumMsgs) {
if (Timeout > 0 && t.getTimePassed() >= Timeout) {
err_code = ERR_TIMEOUT;
break;
}
EnterCriticalSection(&this->message_access_lock);
if (Timeout == 0 && this->messages.empty()) {
LeaveCriticalSection(&this->message_access_lock);
break;
}
auto msg_in = this->messages.front();
this->messages.pop();
LeaveCriticalSection(&this->message_access_lock);
//if (this->_is_29bit() != msg_in.addr_29b) {}
PASSTHRU_MSG *msg_out = &pMsg[msgnum++];
msg_out->ProtocolID = this->ProtocolID;
msg_out->DataSize = msg_in.DataSize;
memcpy(msg_out->Data, msg_in.Data.c_str(), msg_in.DataSize);
msg_out->Timestamp = msg_in.Timestamp;
msg_out->RxStatus = msg_in.RxStatus ? CAN_29BIT_ID : 0;
if (msgnum == *pNumMsgs) break;
}
if (msgnum == 0)
err_code = ERR_BUFFER_EMPTY;
*pNumMsgs = msgnum;
return err_code;
}
virtual long 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++) {
PASSTHRU_MSG* msg = &pMsg[msgnum];
if (msg->ProtocolID != this->ProtocolID) {
*pNumMsgs = msgnum;
return ERR_MSG_PROTOCOL_ID;
}
if (msg->DataSize < 4 || msg->DataSize > (8 + 4) || val_is_29bit(msg->TxFlags) != this->_is_29bit()) {
*pNumMsgs = msgnum;
return ERR_INVALID_MSG;
}
uint32_t addr = msg->Data[0] << 24 | msg->Data[1] << 16 | msg->Data[2] << 8 | msg->Data[3];
if (this->panda_dev->can_send(addr, this->_is_29bit(), &msg->Data[4], msg->DataSize - 4, panda::PANDA_CAN1) == FALSE) {
*pNumMsgs = msgnum;
return ERR_INVALID_MSG;
}
}
return STATUS_NOERROR;
}
bool _is_29bit() {
return (this->Flags & CAN_29BIT_ID) == CAN_29BIT_ID;
}
};
class PandaJ2534Device {
public:
PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) {
this->panda = std::move(new_panda);
this->panda->set_can_speed_kbps(panda::PANDA_CAN1, 500);
this->panda->set_safety_mode(panda::SAFETY_ALLOUTPUT);
this->panda->set_can_loopback(TRUE);
//this->panda->set_can_loopback(FALSE);
this->panda->set_alt_setting(1);
this->panda->reset_can_interrupt_pipe();
DWORD threadid;
this->can_kill_event = CreateEvent(NULL, TRUE, FALSE, NULL);
this->can_thread_handle = CreateThread(NULL, 0, _threadBootstrap, (LPVOID)this, 0, &threadid);
printf("Created PandaDevice\n");
};
~PandaJ2534Device() {
SetEvent(this->can_kill_event);
DWORD res = WaitForSingleObject(this->can_thread_handle, INFINITE);
CloseHandle(this->can_thread_handle);
}
static std::unique_ptr<PandaJ2534Device> openByName(std::string sn) {
auto p = panda::Panda::openPanda("");
if (p == nullptr)
return nullptr;
return std::unique_ptr<PandaJ2534Device>(new PandaJ2534Device(std::move(p)));
}
DWORD closeChannel(unsigned long ChannelID) {
if (this->connections.size() <= ChannelID) return ERR_INVALID_CHANNEL_ID;
if (this->connections[ChannelID] == nullptr) return ERR_DEVICE_NOT_CONNECTED;
this->connections[ChannelID] = nullptr;
return STATUS_NOERROR;
}
DWORD addChannel(J2534Connection* conn, unsigned long* channel_id) {
int channel_index = -1;
for (unsigned int i = 0; i < this->connections.size(); i++)
if (this->connections[i] == nullptr) {
channel_index = i;
break;
}
if (channel_index == -1) {
if (this->connections.size() == 0xFFFF) //channelid max 16 bits
return ERR_FAILED; //Too many channels
this->connections.push_back(nullptr);
channel_index = this->connections.size() - 1;
}
this->connections[channel_index].reset(conn);
*channel_id = channel_index;
return STATUS_NOERROR;
}
std::unique_ptr<panda::Panda> panda;
std::vector<std::unique_ptr<J2534Connection>> connections;
private:
static DWORD WINAPI _threadBootstrap(LPVOID This) {
return ((PandaJ2534Device*)This)->can_recv_thread();
}
DWORD can_recv_thread() {
DWORD err = TRUE;
while (err) {
std::vector<panda::PANDA_CAN_MSG> msg_recv;
err = this->panda->can_recv_async(this->can_kill_event, msg_recv);
for (auto msg_in : msg_recv) {
//if (this->_is_29bit() != msg_in.addr_29b) {}
PASSTHRU_MSG_INTERNAL msg_out;
msg_out.ProtocolID = CAN;
msg_out.DataSize = msg_in.len + 4;
msg_out.Data.reserve(msg_out.DataSize);
msg_out.Data += msg_in.addr >> 24;
msg_out.Data += (msg_in.addr >> 16) & 0xFF;
msg_out.Data += (msg_in.addr >> 8) & 0xFF;
msg_out.Data += msg_in.addr & 0xFF;
std::string tmp = std::string((char*)&msg_in.dat, msg_in.len);
msg_out.Data += tmp;
msg_out.Timestamp = msg_in.recv_time;
msg_out.RxStatus = msg_in.addr_29b ? CAN_29BIT_ID : 0;
// TODO: Make this more efficient
for (auto& conn : this->connections)
if(conn->isProtoCan() && conn->getPort() == msg_in.bus)
conn->processMessage(msg_out);
}
}
return STATUS_NOERROR;
}
HANDLE can_thread_handle;
HANDLE can_kill_event;
};
#include "J2534Connection.h"
#include "J2534Connection_CAN.h"
#include "PandaJ2534Device.h"
std::vector<std::unique_ptr<PandaJ2534Device>> pandas;
@ -432,10 +85,7 @@ PANDAJ2534DLL_API long PTAPI PassThruOpen(void *pName, unsigned long *pDevice
PANDAJ2534DLL_API long PTAPI PassThruClose(unsigned long DeviceID) {
#pragma EXPORT
if (check_valid_DeviceID(DeviceID) != STATUS_NOERROR) return J25334LastError;
//TODO Check channels are closed.
get_device(DeviceID) = nullptr;
return ret_code(STATUS_NOERROR);
}
PANDAJ2534DLL_API long PTAPI PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID,
@ -466,7 +116,7 @@ PANDAJ2534DLL_API long PTAPI PassThruConnect(unsigned long DeviceID, unsigned lo
case CAN:
case CAN_PS:
//case SW_CAN_PS:
conn = new CAN_J2534Connection(panda->panda.get(), ProtocolID, Flags, BaudRate);
conn = new J2534Connection_CAN(panda->panda.get(), ProtocolID, Flags, BaudRate);
break;
//case ISO15765:
//case ISO15765_PS:

View File

@ -1 +1,4 @@
#define PANDAJ2534DLL_API extern "C" __declspec(dllexport)
// A quick way to avoid the name mangling that __stdcall liked to do
#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)

View File

@ -85,10 +85,15 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="J2534Connection.h" />
<ClInclude Include="J2534Connection_CAN.h" />
<ClInclude Include="J2534MessageFilter.h" />
<ClInclude Include="J2534_v0404.h" />
<ClInclude Include="PandaJ2534Device.h" />
<ClInclude Include="pandaJ2534DLL.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="Timer.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
@ -99,16 +104,18 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="J2534Connection.cpp" />
<ClCompile Include="J2534Connection_CAN.cpp" />
<ClCompile Include="J2534MessageFilter.cpp" />
<ClCompile Include="PandaJ2534Device.cpp" />
<ClCompile Include="pandaJ2534DLL.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="Timer.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\panda Driver Package\panda Driver Package.vcxproj">
<Project>{bd34db24-f5dc-4992-a74f-05faf731abed}</Project>
</ProjectReference>
<ProjectReference Include="..\panda\panda.vcxproj">
<Project>{5528aefb-638d-49af-b9d4-965154e7d531}</Project>
</ProjectReference>

View File

@ -27,6 +27,21 @@
<ClInclude Include="pandaJ2534DLL.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534Connection.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PandaJ2534Device.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534Connection_CAN.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="J2534MessageFilter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -38,5 +53,20 @@
<ClCompile Include="dllmain.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="J2534Connection_CAN.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="J2534MessageFilter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,8 +1,3 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
@ -11,5 +6,8 @@
// Windows Header Files:
#include <windows.h>
// TODO: reference additional headers your program requires here
#include <string>
#include <array>
#include <queue>
#include <ctime>
#include <chrono>