J2534_WIN: J2534Device sharable between threads.

master
Jessy Diamond Exum 2017-09-25 23:08:14 -07:00
parent 779a66096b
commit cac68e5422
9 changed files with 183 additions and 67 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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() {

View File

@ -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

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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.