J2534_WIN: J2534Device sharable between threads.
parent
779a66096b
commit
cac68e5422
|
@ -2,7 +2,7 @@
|
|||
#include "J2534Connection.h"
|
||||
|
||||
J2534Connection::J2534Connection(
|
||||
panda::Panda* panda_dev,
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
#include "panda/panda.h"
|
||||
#include "J2534_v0404.h"
|
||||
#include "J2534MessageFilter.h"
|
||||
#include "PandaJ2534Device.h"
|
||||
|
||||
class J2534MessageFilter;
|
||||
class PandaJ2534Device;
|
||||
|
||||
#define check_bmask(num, mask)(((num) & mask) == mask)
|
||||
|
||||
class J2534Connection {
|
||||
public:
|
||||
J2534Connection(
|
||||
panda::Panda* panda_dev,
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
|
@ -58,8 +60,7 @@ protected:
|
|||
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::weak_ptr<PandaJ2534Device> panda_dev;
|
||||
|
||||
std::queue<PASSTHRU_MSG_INTERNAL> messages;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "Timer.h"
|
||||
|
||||
J2534Connection_CAN::J2534Connection_CAN(
|
||||
panda::Panda* panda_dev,
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
|
@ -13,7 +13,7 @@ J2534Connection_CAN::J2534Connection_CAN(
|
|||
if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
|
||||
throw ERR_INVALID_BAUDRATE;
|
||||
|
||||
this->panda_dev->set_can_speed_cbps(panda::PANDA_CAN1, BaudRate/100);
|
||||
panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, BaudRate/100);
|
||||
};
|
||||
|
||||
long J2534Connection_CAN::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
|
||||
|
@ -71,9 +71,11 @@ long J2534Connection_CAN::PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *p
|
|||
}
|
||||
|
||||
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, val_is_29bit(msg->TxFlags), &msg->Data[4], msg->DataSize - 4, panda::PANDA_CAN1) == FALSE) {
|
||||
*pNumMsgs = msgnum;
|
||||
return ERR_INVALID_MSG;
|
||||
if (auto panda_dev_sp = this->panda_dev.lock()) {
|
||||
if (panda_dev_sp->panda->can_send(addr, val_is_29bit(msg->TxFlags), &msg->Data[4], msg->DataSize - 4, panda::PANDA_CAN1) == FALSE) {
|
||||
*pNumMsgs = msgnum;
|
||||
return ERR_INVALID_MSG;
|
||||
}
|
||||
}
|
||||
}
|
||||
return STATUS_NOERROR;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
class J2534Connection_CAN : public J2534Connection {
|
||||
public:
|
||||
J2534Connection_CAN(
|
||||
panda::Panda* panda_dev,
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#define is_flowctrl(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_FLOWCTRL)
|
||||
|
||||
J2534Connection_ISO15765::J2534Connection_ISO15765(
|
||||
panda::Panda* panda_dev,
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
|
@ -28,7 +28,7 @@ J2534Connection_ISO15765::J2534Connection_ISO15765(
|
|||
if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
|
||||
throw ERR_INVALID_BAUDRATE;
|
||||
|
||||
this->panda_dev->set_can_speed_cbps(panda::PANDA_CAN1, BaudRate / 100); //J2534Connection_CAN(panda_dev, ProtocolID, Flags, BaudRate) {};
|
||||
panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, BaudRate / 100); //J2534Connection_CAN(panda_dev, ProtocolID, Flags, BaudRate) {};
|
||||
}
|
||||
|
||||
long J2534Connection_ISO15765::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
|
||||
|
@ -109,10 +109,12 @@ long J2534Connection_ISO15765::PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned lo
|
|||
}
|
||||
|
||||
memcpy_s(&snd_buff[idx], sizeof(snd_buff) - idx, &msg->Data[addrlen], payload_len);
|
||||
if (this->panda_dev->can_send(addr, val_is_29bit(msg->TxFlags), snd_buff,
|
||||
(msg_is_padded(msg) ? sizeof(snd_buff) : (payload_len + idx)), panda::PANDA_CAN1) == FALSE) {
|
||||
*pNumMsgs = msgnum;
|
||||
return ERR_INVALID_MSG;
|
||||
if (auto panda_dev_sp = this->panda_dev.lock()) {
|
||||
if (panda_dev_sp->panda->can_send(addr, val_is_29bit(msg->TxFlags), snd_buff,
|
||||
(msg_is_padded(msg) ? sizeof(snd_buff) : (payload_len + idx)), panda::PANDA_CAN1) == FALSE) {
|
||||
*pNumMsgs = msgnum;
|
||||
return ERR_INVALID_MSG;
|
||||
}
|
||||
}
|
||||
}
|
||||
return STATUS_NOERROR;
|
||||
|
@ -204,7 +206,7 @@ void J2534Connection_ISO15765::processMessage(const PASSTHRU_MSG_INTERNAL& msg)
|
|||
this->messages.push(outframe);
|
||||
LeaveCriticalSection(&this->message_access_lock);
|
||||
|
||||
convo.init_first_frame(((msg.Data[addrlen] & 0x0F) << 8) | msg.Data[addrlen + 1], msg.Data.substr(addrlen + 2, 12 - (addrlen + 2)));
|
||||
convo.init_rx_first_frame(((msg.Data[addrlen] & 0x0F) << 8) | msg.Data[addrlen + 1], msg.Data.substr(addrlen + 2, 12 - (addrlen + 2)), msg.RxStatus);
|
||||
|
||||
//Doing it this way because the filter can be 5 bytes in ext address mode.
|
||||
std::string flowfilter = filter->get_flowctrl();
|
||||
|
@ -215,42 +217,54 @@ void J2534Connection_ISO15765::processMessage(const PASSTHRU_MSG_INTERNAL& msg)
|
|||
flowstrlresp += flowfilter[4];
|
||||
flowstrlresp += std::string("\x30\x00\x00", 3);
|
||||
|
||||
this->panda_dev->can_send(flow_addr, val_is_29bit(msg.RxStatus), (const uint8_t *)flowstrlresp.c_str(), flowstrlresp.size(), panda::PANDA_CAN1);
|
||||
if (auto panda_dev_sp = this->panda_dev.lock()) {
|
||||
panda_dev_sp->panda->can_send(flow_addr, val_is_29bit(msg.RxStatus), (const uint8_t *)flowstrlresp.c_str(), flowstrlresp.size(), panda::PANDA_CAN1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRAME_CONSEC:
|
||||
{
|
||||
if (convo.expected_size == 0) return;
|
||||
if ((msg.Data[addrlen] & 0x0F) != convo.next_part) return;
|
||||
convo.next_part = (convo.next_part + 1) % 0x10;
|
||||
unsigned int payload_len = min(convo.expected_size - convo.msg.size(), (is_ext_addr ? 6 : 7));
|
||||
if (msg.Data.size() < (addrlen + 1 + payload_len)) {
|
||||
//A frame was received that could have held more data.
|
||||
//No examples of this protocol show that happening, so
|
||||
//it will be assumed that it is grounds to reset rx.
|
||||
convo.reset();
|
||||
return;
|
||||
}
|
||||
convo.msg += msg.Data.substr(addrlen + 1, payload_len);
|
||||
if (convo.msg.size() == convo.expected_size) {
|
||||
outframe.ProtocolID = ISO15765;
|
||||
outframe.Timestamp = msg.Timestamp;
|
||||
outframe.RxStatus = msg.RxStatus;
|
||||
if (is_ext_addr)
|
||||
outframe.RxStatus |= ISO15765_ADDR_TYPE;
|
||||
outframe.TxFlags = 0;
|
||||
outframe.Data = msg.Data.substr(0, addrlen) + convo.msg;
|
||||
outframe.ExtraDataIndex = outframe.Data.size();
|
||||
convo.lock();
|
||||
{
|
||||
if (convo.active == 0) {
|
||||
convo.unlock();
|
||||
return;
|
||||
}
|
||||
if ((msg.Data[addrlen] & 0x0F) != convo.next_part) {
|
||||
convo.unlock();
|
||||
return;
|
||||
}
|
||||
convo.next_part = (convo.next_part + 1) % 0x10;
|
||||
unsigned int payload_len = min(convo.bytes_remaining(), (is_ext_addr ? 6 : 7));
|
||||
if (msg.Data.size() < (addrlen + 1 + payload_len)) {
|
||||
//A frame was received that could have held more data.
|
||||
//No examples of this protocol show that happening, so
|
||||
//it will be assumed that it is grounds to reset rx.
|
||||
convo.reset();
|
||||
convo.unlock();
|
||||
return;
|
||||
}
|
||||
convo.msg += msg.Data.substr(addrlen + 1, payload_len);
|
||||
|
||||
EnterCriticalSection(&this->message_access_lock);
|
||||
this->messages.push(outframe);
|
||||
LeaveCriticalSection(&this->message_access_lock);
|
||||
if (convo.msg.size() == convo.expected_size) {
|
||||
outframe.ProtocolID = ISO15765;
|
||||
outframe.Timestamp = msg.Timestamp;
|
||||
outframe.RxStatus = msg.RxStatus;
|
||||
if (is_ext_addr)
|
||||
outframe.RxStatus |= ISO15765_ADDR_TYPE;
|
||||
outframe.TxFlags = 0;
|
||||
outframe.Data = msg.Data.substr(0, addrlen) + convo.msg;
|
||||
outframe.ExtraDataIndex = outframe.Data.size();
|
||||
|
||||
convo.reset();
|
||||
EnterCriticalSection(&this->message_access_lock);
|
||||
this->messages.push(outframe);
|
||||
LeaveCriticalSection(&this->message_access_lock);
|
||||
|
||||
convo.reset();
|
||||
}
|
||||
}
|
||||
convo.unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long J2534Connection_ISO15765::getMinMsgLen() {
|
||||
|
|
|
@ -4,30 +4,110 @@
|
|||
#include <string>
|
||||
|
||||
typedef struct ISO15765_FRAMESET {
|
||||
bool active;
|
||||
std::string msg;
|
||||
unsigned long expected_size;
|
||||
unsigned char next_part;
|
||||
bool istx;
|
||||
unsigned long flags;
|
||||
|
||||
CRITICAL_SECTION access_lock;
|
||||
|
||||
//Critical section will be required if accessed outside of processMessage
|
||||
ISO15765_FRAMESET() : msg(""), expected_size(0), next_part(0) { }
|
||||
~ISO15765_FRAMESET() { }
|
||||
|
||||
void init_first_frame(uint16_t final_size, const std::string& piece) {
|
||||
expected_size = final_size & 0xFFF;
|
||||
msg.reserve(expected_size);
|
||||
msg = piece;
|
||||
next_part = 1;
|
||||
ISO15765_FRAMESET() : active(FALSE), msg(""), expected_size(0), next_part(0), istx(FALSE), flags(0) {
|
||||
InitializeCriticalSectionAndSpinCount(&access_lock, 0x00000400);
|
||||
}
|
||||
~ISO15765_FRAMESET() {
|
||||
DeleteCriticalSection(&access_lock);
|
||||
}
|
||||
|
||||
void init_tx(std::string& payload, unsigned long bytes_already_sent, unsigned long txFlags) {
|
||||
lock();
|
||||
{
|
||||
active = TRUE;
|
||||
expected_size = 1;
|
||||
msg = payload;
|
||||
next_part = 1;
|
||||
flags = txFlags;
|
||||
istx = TRUE;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void init_rx_first_frame(uint16_t final_size, const std::string& piece, unsigned long rxFlags) {
|
||||
lock();
|
||||
{
|
||||
active = TRUE;
|
||||
expected_size = final_size & 0xFFF;
|
||||
msg.reserve(expected_size);
|
||||
msg = piece;
|
||||
next_part = 1;
|
||||
flags = rxFlags;
|
||||
istx = FALSE;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
/*void rx_add_frame(unsigned long addrlen) {
|
||||
lock();
|
||||
if (expected_size == 0) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
if ((msgin.Data[addrlen] & 0x0F) != next_part) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
next_part = (next_part + 1) % 0x10;
|
||||
unsigned int payload_len = min(expected_size - msg.size(), (is_ext_addr ? 6 : 7));
|
||||
if (msgin.Data.size() < (addrlen + 1 + payload_len)) {
|
||||
//A frame was received that could have held more data.
|
||||
//No examples of this protocol show that happening, so
|
||||
//it will be assumed that it is grounds to reset rx.
|
||||
reset();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
msg += msgin.Data.substr(addrlen + 1, payload_len);
|
||||
unlock();
|
||||
}*/
|
||||
|
||||
void reset() {
|
||||
expected_size = 0;
|
||||
msg = "";
|
||||
lock();
|
||||
{
|
||||
active = FALSE;
|
||||
expected_size = 0;
|
||||
msg = "";
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
unsigned int bytes_remaining() {
|
||||
unsigned int res;
|
||||
lock();
|
||||
{
|
||||
if(istx)
|
||||
res = this->msg.size() - this->expected_size;
|
||||
else
|
||||
res = this->expected_size - this->msg.size();
|
||||
}
|
||||
unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
void lock() {
|
||||
EnterCriticalSection(&access_lock);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
LeaveCriticalSection(&access_lock);
|
||||
}
|
||||
} ISO15765_FRAMESET;
|
||||
|
||||
class J2534Connection_ISO15765 : public J2534Connection { //J2534Connection_CAN {
|
||||
public:
|
||||
J2534Connection_ISO15765(
|
||||
panda::Panda* panda_dev,
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
|
|
|
@ -11,7 +11,7 @@ PandaJ2534Device::PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) {
|
|||
|
||||
DWORD threadid;
|
||||
this->can_kill_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
this->can_thread_handle = CreateThread(NULL, 0, _threadBootstrap, (LPVOID)this, 0, &threadid);
|
||||
this->can_thread_handle = CreateThread(NULL, 0, _can_recv_threadBootstrap, (LPVOID)this, 0, &threadid);
|
||||
};
|
||||
|
||||
PandaJ2534Device::~PandaJ2534Device() {
|
||||
|
@ -19,9 +19,12 @@ PandaJ2534Device::~PandaJ2534Device() {
|
|||
DWORD res = WaitForSingleObject(this->can_thread_handle, INFINITE);
|
||||
CloseHandle(this->can_thread_handle);
|
||||
CloseHandle(this->can_kill_event);
|
||||
|
||||
CloseHandle(this->flow_control_wakeup_event);
|
||||
CloseHandle(this->flow_control_thread_handle);
|
||||
}
|
||||
|
||||
std::unique_ptr<PandaJ2534Device> PandaJ2534Device::openByName(std::string sn) {
|
||||
std::shared_ptr<PandaJ2534Device> PandaJ2534Device::openByName(std::string sn) {
|
||||
auto p = panda::Panda::openPanda("");
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
|
@ -56,7 +59,7 @@ DWORD PandaJ2534Device::addChannel(J2534Connection* conn, unsigned long* channel
|
|||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
DWORD WINAPI PandaJ2534Device::_threadBootstrap(LPVOID This) {
|
||||
DWORD WINAPI PandaJ2534Device::_can_recv_threadBootstrap(LPVOID This) {
|
||||
return ((PandaJ2534Device*)This)->can_recv_thread();
|
||||
}
|
||||
|
||||
|
@ -90,3 +93,12 @@ DWORD PandaJ2534Device::can_recv_thread() {
|
|||
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
DWORD PandaJ2534Device::_flow_control_write_threadBootstrap(LPVOID This) {
|
||||
return ((PandaJ2534Device*)This)->flow_control_write_thread();
|
||||
}
|
||||
|
||||
DWORD PandaJ2534Device::flow_control_write_thread()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
#include "panda/panda.h"
|
||||
#include "J2534Connection.h"
|
||||
|
||||
class J2534Connection;
|
||||
|
||||
class PandaJ2534Device {
|
||||
public:
|
||||
PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda);
|
||||
|
||||
~PandaJ2534Device();
|
||||
|
||||
static std::unique_ptr<PandaJ2534Device> openByName(std::string sn);
|
||||
static std::shared_ptr<PandaJ2534Device> openByName(std::string sn);
|
||||
|
||||
DWORD closeChannel(unsigned long ChannelID);
|
||||
DWORD addChannel(J2534Connection* conn, unsigned long* channel_id);
|
||||
|
@ -19,10 +21,15 @@ public:
|
|||
std::vector<std::unique_ptr<J2534Connection>> connections;
|
||||
|
||||
private:
|
||||
static DWORD WINAPI _threadBootstrap(LPVOID This);
|
||||
|
||||
static DWORD WINAPI _can_recv_threadBootstrap(LPVOID This);
|
||||
DWORD can_recv_thread();
|
||||
|
||||
HANDLE can_thread_handle;
|
||||
HANDLE can_kill_event;
|
||||
|
||||
static DWORD WINAPI _flow_control_write_threadBootstrap(LPVOID This);
|
||||
DWORD flow_control_write_thread();
|
||||
|
||||
HANDLE flow_control_thread_handle;
|
||||
HANDLE flow_control_wakeup_event;
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// A quick way to avoid the name mangling that __stdcall liked to do
|
||||
#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
|
||||
|
||||
std::vector<std::unique_ptr<PandaJ2534Device>> pandas;
|
||||
std::vector<std::shared_ptr<PandaJ2534Device>> pandas;
|
||||
|
||||
int J25334LastError = 0;
|
||||
|
||||
|
@ -146,20 +146,20 @@ PANDAJ2534DLL_API long PTAPI PassThruConnect(unsigned long DeviceID, unsigned lo
|
|||
case J1850PWM_PS:
|
||||
case ISO9141: //This protocol could be implemented if 5 BAUD init support is added to the panda.
|
||||
case ISO9141_PS:
|
||||
conn = new J2534Connection(panda->panda.get(), ProtocolID, Flags, BaudRate);
|
||||
conn = new J2534Connection(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
case ISO14230: //Only supporting Fast init until panda adds support for 5 BAUD init.
|
||||
case ISO14230_PS:
|
||||
conn = new J2534Connection(panda->panda.get(), ProtocolID, Flags, BaudRate);
|
||||
conn = new J2534Connection(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
case CAN:
|
||||
case CAN_PS:
|
||||
//case SW_CAN_PS:
|
||||
conn = new J2534Connection_CAN(panda->panda.get(), ProtocolID, Flags, BaudRate);
|
||||
conn = new J2534Connection_CAN(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
case ISO15765:
|
||||
case ISO15765_PS:
|
||||
conn = new J2534Connection_ISO15765(panda->panda.get(), ProtocolID, Flags, BaudRate);
|
||||
conn = new J2534Connection_ISO15765(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
//case SW_ISO15765_PS: // SW = Single Wire. GMLAN is a SW CAN protocol
|
||||
//case GM_UART_PS: // PS = Pin Select. Handles different ports.
|
||||
|
|
Loading…
Reference in New Issue