fix HDS issues

master
gregjhogan 2018-02-01 00:34:03 -06:00
parent 8203cc8e59
commit 2e99dbf34a
8 changed files with 208 additions and 88 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pandaJ2534DLL", "pandaJ2534DLL\pandaJ2534DLL.vcxproj", "{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}"
ProjectSection(ProjectDependencies) = postProject
@ -24,6 +24,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ECUsim CLI", "ECUsim CLI\ECUsim CLI.vcxproj", "{D99E2FCD-21A4-4065-949A-31E34E0E69D1}"
EndProject
Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
@ -87,4 +90,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8AF3826E-406A-4F1C-BA80-B4D7FD4B52E1}
EndGlobalSection
EndGlobal

View File

@ -13,13 +13,6 @@
using namespace panda;
#pragma pack(1)
typedef struct _PANDA_CAN_MSG_INTERNAL {
uint32_t rir;
uint32_t f2;
uint8_t dat[8];
} PANDA_CAN_MSG_INTERNAL;
Panda::Panda(
WINUSB_INTERFACE_HANDLE WinusbHandle,
HANDLE DeviceHandle,
@ -28,6 +21,7 @@ Panda::Panda(
) : usbh(WinusbHandle), devh(DeviceHandle), devPath(devPath_), sn(sn_) {
printf("CREATED A PANDA %s\n", this->sn.c_str());
this->set_can_loopback(FALSE);
this->set_raw_io(TRUE);
this->set_alt_setting(0);
}
@ -167,7 +161,8 @@ bool Panda::set_alt_setting(UCHAR alt_setting) {
this->set_can_loopback(TRUE);
Sleep(20); // Give time for any sent messages to appear in the RX buffer.
this->can_clear(PANDA_CAN_RX);
for (int i = 0; i < 2; i++) {
// send 4 messages becaus can_recv reads 4 messages at a time
for (int i = 0; i < 4; i++) {
printf("Sending PAD %d\n", i);
if (this->can_send(0x7FF, FALSE, {}, 0, PANDA_CAN1) == FALSE) {
auto err = GetLastError();
@ -177,14 +172,8 @@ bool Panda::set_alt_setting(UCHAR alt_setting) {
Sleep(10);
//this->can_clear(PANDA_CAN_RX);
std::vector<PANDA_CAN_MSG> msg_recv;
if (alt_setting == 1) {
//Read the messages so they do not contaimnate the real message stream.
auto err = this->can_recv_async(NULL, msg_recv, 1000);
}
else {
msg_recv = this->can_recv();
}
//Read the messages so they do not contaimnate the real message stream.
this->can_recv();
//this->set_can_loopback(FALSE);
this->set_can_loopback(loopback_backup);
@ -203,6 +192,17 @@ UCHAR Panda::get_current_alt_setting() {
return alt_setting;
}
bool Panda::set_raw_io(bool val) {
UCHAR raw_io = val;
if (!WinUsb_SetPipePolicy(this->usbh, 0x81, RAW_IO, sizeof(raw_io), &raw_io)) {
_tprintf(_T(" Error setting usb raw I/O pipe policy %d, Msg: '%s'\n"),
GetLastError(), GetLastErrorAsString().c_str());
return FALSE;
}
return TRUE;
}
PANDA_HEALTH Panda::get_health()
{
WINUSB_SETUP_PACKET SetupPacket;
@ -351,69 +351,84 @@ bool Panda::can_send(uint32_t addr, bool addr_29b, const uint8_t *dat, uint8_t l
return this->can_send_many(std::vector<PANDA_CAN_MSG>{msg});
}
void Panda::parse_can_recv(std::vector<PANDA_CAN_MSG>& msg_recv, char *buff, int retcount) {
for (int i = 0; i < retcount; i += sizeof(PANDA_CAN_MSG_INTERNAL)) {
PANDA_CAN_MSG_INTERNAL *in_msg_raw = (PANDA_CAN_MSG_INTERNAL *)(buff + i);
PANDA_CAN_MSG in_msg;
PANDA_CAN_MSG Panda::parse_can_recv(PANDA_CAN_MSG_INTERNAL *in_msg_raw) {
PANDA_CAN_MSG in_msg;
in_msg.addr_29b = (bool)(in_msg_raw->rir & CAN_EXTENDED);
in_msg.addr = (in_msg.addr_29b) ? (in_msg_raw->rir >> 3) : (in_msg_raw->rir >> 21);
in_msg.recv_time = this->runningTime.getTimePassedUS();
in_msg.recv_time_point = std::chrono::steady_clock::now();
//The timestamp from the device is (in_msg_raw->f2 >> 16),
//but this 16 bit value is a little hard to use. Using a
//timer since the initialization of this device.
in_msg.len = in_msg_raw->f2 & 0xF;
memcpy(in_msg.dat, in_msg_raw->dat, 8);
in_msg.addr_29b = (bool)(in_msg_raw->rir & CAN_EXTENDED);
in_msg.addr = (in_msg.addr_29b) ? (in_msg_raw->rir >> 3) : (in_msg_raw->rir >> 21);
in_msg.recv_time = this->runningTime.getTimePassedUS();
in_msg.recv_time_point = std::chrono::steady_clock::now();
//The timestamp from the device is (in_msg_raw->f2 >> 16),
//but this 16 bit value is a little hard to use. Using a
//timer since the initialization of this device.
in_msg.len = in_msg_raw->f2 & 0xF;
memcpy(in_msg.dat, in_msg_raw->dat, 8);
in_msg.is_receipt = ((in_msg_raw->f2 >> 4) & 0x80) == 0x80;
switch ((in_msg_raw->f2 >> 4) & 0x7F) {
case PANDA_CAN1:
in_msg.bus = PANDA_CAN1;
break;
case PANDA_CAN2:
in_msg.bus = PANDA_CAN2;
break;
case PANDA_CAN3:
in_msg.bus = PANDA_CAN3;
break;
default:
in_msg.bus = PANDA_CAN_UNK;
}
msg_recv.push_back(in_msg);
in_msg.is_receipt = ((in_msg_raw->f2 >> 4) & 0x80) == 0x80;
switch ((in_msg_raw->f2 >> 4) & 0x7F) {
case PANDA_CAN1:
in_msg.bus = PANDA_CAN1;
break;
case PANDA_CAN2:
in_msg.bus = PANDA_CAN2;
break;
case PANDA_CAN3:
in_msg.bus = PANDA_CAN3;
break;
default:
in_msg.bus = PANDA_CAN_UNK;
}
return in_msg;
}
bool Panda::can_recv_async(HANDLE kill_event, std::vector<PANDA_CAN_MSG>& msg_buff, DWORD timeoutms) {
int retcount;
char buff[sizeof(PANDA_CAN_MSG_INTERNAL) * 4];
bool Panda::can_rx_q_push(HANDLE kill_event, DWORD timeoutms) {
while (1) {
auto w_ptr = this->w_ptr;
auto n_ptr = w_ptr + 1;
if (n_ptr == CAN_RX_QUEUE_LEN) {
n_ptr = 0;
}
// Overlapped structure required for async read.
HANDLE m_hReadFinishedEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
OVERLAPPED m_overlappedData;
memset(&m_overlappedData, sizeof(OVERLAPPED), 0);
m_overlappedData.hEvent = m_hReadFinishedEvent;
// Pause if there is not a slot available in the queue
if (n_ptr == this->r_ptr) {
printf("RX queue full!\n");
continue;
}
HANDLE phSignals[2] = { m_hReadFinishedEvent, kill_event };
if (this->can_rx_q[n_ptr].complete) {
// TODO: is ResetEvent() faster?
CloseHandle(this->can_rx_q[n_ptr].complete);
}
if (!WinUsb_ReadPipe(this->usbh, 0x81, (PUCHAR)buff, sizeof(buff), (PULONG)&retcount, &m_overlappedData)) {
// An overlapped read will return true if done, or false with an
// error of ERROR_IO_PENDING if the transfer is still in process.
DWORD dwError = GetLastError();
if (dwError == ERROR_IO_PENDING) {
dwError = WaitForMultipleObjects(kill_event ? 2 : 1, phSignals, FALSE, timeoutms);
// Overlapped structure required for async read.
this->can_rx_q[n_ptr].complete = CreateEvent(NULL, TRUE, TRUE, NULL);
memset(&this->can_rx_q[n_ptr].overlapped, sizeof(OVERLAPPED), 0);
this->can_rx_q[n_ptr].overlapped.hEvent = this->can_rx_q[n_ptr].complete;
this->can_rx_q[n_ptr].error = 0;
if (!WinUsb_ReadPipe(this->usbh, 0x81, this->can_rx_q[n_ptr].data, sizeof(this->can_rx_q[n_ptr].data), &this->can_rx_q[n_ptr].count, &this->can_rx_q[n_ptr].overlapped)) {
// An overlapped read will return true if done, or false with an
// error of ERROR_IO_PENDING if the transfer is still in process.
this->can_rx_q[n_ptr].error = GetLastError();
}
// Process the pipe read call from the previous invocation of this function
if (this->can_rx_q[w_ptr].error == ERROR_IO_PENDING) {
HANDLE phSignals[2] = { this->can_rx_q[w_ptr].complete, kill_event };
auto dwError = WaitForMultipleObjects(kill_event ? 2 : 1, phSignals, FALSE, timeoutms);
// Check if packet, timeout (nope), or break
if (dwError == WAIT_OBJECT_0) {
// Signal came from our usb object. Read the returned data.
if (!GetOverlappedResult(this->usbh, &m_overlappedData, (PULONG)&retcount, FALSE)) {
if (!GetOverlappedResult(this->usbh, &this->can_rx_q[w_ptr].overlapped, &this->can_rx_q[w_ptr].count, TRUE)) {
// TODO: handle other error cases better.
dwError = GetLastError();
printf("Got overlap error %d\n", dwError);
return TRUE;
continue;
}
} else {
}
else {
WinUsb_AbortPipe(this->usbh, 0x81);
// Return FALSE to show that the optional signal
@ -422,17 +437,39 @@ bool Panda::can_recv_async(HANDLE kill_event, std::vector<PANDA_CAN_MSG>& msg_bu
if (dwError == (WAIT_OBJECT_0 + 1)) {
return FALSE;
}
return TRUE;
continue;
}
} else { // ERROR_BAD_COMMAND happens when device is unplugged.
}
else if (this->can_rx_q[w_ptr].error != 0) { // ERROR_BAD_COMMAND happens when device is unplugged.
return FALSE;
}
this->w_ptr = n_ptr;
}
parse_can_recv(msg_buff, buff, retcount);
return TRUE;
}
void Panda::can_rx_q_pop(PANDA_CAN_MSG msg_out[], int &count) {
count = 0;
// No data left in queue
if (this->r_ptr == this->w_ptr) {
return;
}
auto r_ptr = this->r_ptr;
for (int i = 0; i < this->can_rx_q[r_ptr].count; i += sizeof(PANDA_CAN_MSG_INTERNAL)) {
auto in_msg_raw = (PANDA_CAN_MSG_INTERNAL *)(this->can_rx_q[r_ptr].data + i);
msg_out[count] = parse_can_recv(in_msg_raw);
++count;
}
// Advance read pointer (wrap around if needed)
++r_ptr;
this->r_ptr = (r_ptr == CAN_RX_QUEUE_LEN ? 0 : r_ptr);
}
std::vector<PANDA_CAN_MSG> Panda::can_recv() {
std::vector<PANDA_CAN_MSG> msg_recv;
int retcount;
@ -441,7 +478,11 @@ std::vector<PANDA_CAN_MSG> Panda::can_recv() {
if (this->bulk_read(0x81, buff, sizeof(buff), (PULONG)&retcount, 0) == FALSE)
return msg_recv;
parse_can_recv(msg_recv, buff, retcount);
for (int i = 0; i < retcount; i += sizeof(PANDA_CAN_MSG_INTERNAL)) {
PANDA_CAN_MSG_INTERNAL *in_msg_raw = (PANDA_CAN_MSG_INTERNAL *)(buff + i);
auto in_msg = parse_can_recv(in_msg_raw);
msg_recv.push_back(in_msg);
}
return msg_recv;
}

View File

@ -31,6 +31,8 @@
#endif
#define LIN_MSG_MAX_LEN 10
#define CAN_RX_QUEUE_LEN 10000
#define CAN_RX_MSG_LEN 1000
//template class __declspec(dllexport) std::basic_string<char>;
@ -139,6 +141,7 @@ namespace panda {
std::string get_usb_sn();
bool set_alt_setting(UCHAR alt_setting);
UCHAR get_current_alt_setting();
bool Panda::set_raw_io(bool val);
PANDA_HEALTH get_health();
bool enter_bootloader();
@ -160,9 +163,9 @@ namespace panda {
bool can_send_many(const std::vector<PANDA_CAN_MSG>& can_msgs);
bool can_send(uint32_t addr, bool addr_29b, const uint8_t *dat, uint8_t len, PANDA_CAN_PORT bus);
void parse_can_recv(std::vector<PANDA_CAN_MSG>& msg_recv, char *buff, int retcount);
bool can_recv_async(HANDLE kill_event, std::vector<PANDA_CAN_MSG>& msg_buff, DWORD timeoutms = INFINITE);
std::vector<PANDA_CAN_MSG> can_recv();
bool can_rx_q_push(HANDLE kill_event, DWORD timeoutms = INFINITE);
void can_rx_q_pop(PANDA_CAN_MSG msg_out[], int &count);
bool can_clear(PANDA_CAN_PORT_CLEAR bus);
std::string serial_read(PANDA_SERIAL_PORT port_number);
@ -202,6 +205,23 @@ namespace panda {
ULONG timeout
);
#pragma pack(1)
typedef struct _PANDA_CAN_MSG_INTERNAL {
uint32_t rir;
uint32_t f2;
uint8_t dat[8];
} PANDA_CAN_MSG_INTERNAL;
typedef struct _CAN_RX_PIPE_READ {
unsigned char data[sizeof(PANDA_CAN_MSG_INTERNAL) * CAN_RX_MSG_LEN];
unsigned long count;
OVERLAPPED overlapped;
HANDLE complete;
DWORD error;
} CAN_RX_PIPE_READ;
PANDA_CAN_MSG parse_can_recv(PANDA_CAN_MSG_INTERNAL *in_msg_raw);
WINUSB_INTERFACE_HANDLE usbh;
HANDLE devh;
tstring devPath;
@ -209,6 +229,9 @@ namespace panda {
bool loopback;
Timer runningTime;
CAN_RX_PIPE_READ can_rx_q[CAN_RX_QUEUE_LEN];
unsigned long w_ptr = 0;
unsigned long r_ptr = 0;
};
}

View File

@ -33,6 +33,7 @@ long J2534Connection::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMs
messageRxBuff_mutex.unlock();
if (Timeout == 0)
break;
Sleep(2);
continue;
}
@ -148,14 +149,33 @@ long J2534Connection::PassThruIoctl(unsigned long IoctlID, void *pInput, void *p
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() {
synchronized(messageRxBuff_mutex) {
this->messageRxBuff = {};
long J2534Connection::clearTXBuff() {
if (auto panda_ps = this->panda_dev.lock()) {
synchronized(staged_writes_lock) {
this->txbuff = {};
panda_ps->panda->can_clear(panda::PANDA_CAN1_TX);
}
}
return STATUS_NOERROR;
}
long J2534Connection::clearPeriodicMsgs() { return STATUS_NOERROR; }
long J2534Connection::clearRXBuff() {
if (auto panda_ps = this->panda_dev.lock()) {
synchronized(messageRxBuff_mutex) {
this->messageRxBuff = {};
panda_ps->panda->can_clear(panda::PANDA_CAN_RX);
}
}
return STATUS_NOERROR;
}
long J2534Connection::clearPeriodicMsgs() {
for (int i = 0; i < this->periodicMessages.size(); i++) {
if (periodicMessages[i] == nullptr) continue;
this->periodicMessages[i]->cancel();
this->periodicMessages[i] = nullptr;
}
return STATUS_NOERROR;
}
long J2534Connection::clearMsgFilters() {
for (auto& filter : this->filters) filter = nullptr;
return STATUS_NOERROR;

View File

@ -10,7 +10,7 @@ public:
J2534Frame(const panda::PANDA_CAN_MSG& msg_in) {
ProtocolID = CAN;
ExtraDataIndex = 0;
ExtraDataIndex = msg_in.len + 4;
Data.reserve(msg_in.len + 4);
Data += msg_in.addr >> 24;
Data += (msg_in.addr >> 16) & 0xFF;

View File

@ -95,7 +95,7 @@ BOOL MessageTx_ISO15765::checkTxReceipt(J2534Frame frame) {
J2534Frame outframe(ISO15765);
outframe.Timestamp = frame.Timestamp;
outframe.RxStatus = TX_INDICATION | (flags & (ISO15765_ADDR_TYPE | CAN_29BIT_ID));
outframe.RxStatus = TX_MSG_TYPE | TX_INDICATION | (flags & (ISO15765_ADDR_TYPE | CAN_29BIT_ID));
outframe.Data = frame.Data.substr(0, addressLength());
conn_sp->addMsgToRxQueue(outframe);

View File

@ -8,11 +8,15 @@ PandaJ2534Device::PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) : tx
this->panda->set_esp_power(FALSE);
this->panda->set_safety_mode(panda::SAFETY_ALLOUTPUT);
this->panda->set_can_loopback(FALSE);
this->panda->set_alt_setting(1);
this->panda->set_alt_setting(0);
this->thread_kill_event = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD canListenThreadID;
this->thread_kill_event = CreateEvent(NULL, TRUE, FALSE, NULL);
this->can_thread_handle = CreateThread(NULL, 0, _can_recv_threadBootstrap, (LPVOID)this, 0, &canListenThreadID);
this->can_recv_handle = CreateThread(NULL, 0, _can_recv_threadBootstrap, (LPVOID)this, 0, &canListenThreadID);
DWORD canProcessThreadID;
this->can_process_handle = CreateThread(NULL, 0, _can_process_threadBootstrap, (LPVOID)this, 0, &canProcessThreadID);
DWORD flowControlSendThreadID;
this->flow_control_wakeup_event = CreateEvent(NULL, TRUE, FALSE, NULL);
@ -21,8 +25,11 @@ PandaJ2534Device::PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) : tx
PandaJ2534Device::~PandaJ2534Device() {
SetEvent(this->thread_kill_event);
DWORD res = WaitForSingleObject(this->can_thread_handle, INFINITE);
CloseHandle(this->can_thread_handle);
DWORD res = WaitForSingleObject(this->can_recv_handle, INFINITE);
CloseHandle(this->can_recv_handle);
res = WaitForSingleObject(this->can_process_handle, INFINITE);
CloseHandle(this->can_process_handle);
res = WaitForSingleObject(this->flow_control_thread_handle, INFINITE);
CloseHandle(this->flow_control_thread_handle);
@ -67,11 +74,28 @@ DWORD PandaJ2534Device::addChannel(std::shared_ptr<J2534Connection>& conn, unsig
}
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->thread_kill_event, msg_recv);
for (auto msg_in : msg_recv) {
this->panda->can_clear(panda::PANDA_CAN_RX);
this->panda->can_rx_q_push(this->thread_kill_event);
return 0;
}
DWORD PandaJ2534Device::can_process_thread() {
panda::PANDA_CAN_MSG msg_recv[CAN_RX_MSG_LEN];
while (true) {
if (!WaitForSingleObject(this->thread_kill_event, 0)) {
break;
}
int count = 0;
this->panda->can_rx_q_pop(msg_recv, count);
if (count == 0) {
continue;
}
for (int i = 0; i < count; i++) {
auto msg_in = msg_recv[i];
J2534Frame msg_out(msg_in);
if (msg_in.is_receipt) {

View File

@ -55,12 +55,18 @@ public:
private:
HANDLE thread_kill_event;
HANDLE can_thread_handle;
HANDLE can_recv_handle;
static DWORD WINAPI _can_recv_threadBootstrap(LPVOID This) {
return ((PandaJ2534Device*)This)->can_recv_thread();
}
DWORD can_recv_thread();
HANDLE can_process_handle;
static DWORD WINAPI _can_process_threadBootstrap(LPVOID This) {
return ((PandaJ2534Device*)This)->can_process_thread();
}
DWORD can_process_thread();
HANDLE flow_control_wakeup_event;
HANDLE flow_control_thread_handle;
static DWORD WINAPI _msg_tx_threadBootstrap(LPVOID This) {