J2534_WIN: STYLE ONLY. Split files for my sanity.
parent
7036cf9206
commit
30615a3774
|
@ -301,3 +301,6 @@ __pycache__/
|
|||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# installer
|
||||
*.exe
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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));
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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:
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue