Skip to content

Commit

Permalink
fix HDS issues
Browse files Browse the repository at this point in the history
  • Loading branch information
gregjhogan committed Feb 18, 2018
1 parent 8203cc8 commit 2e99dbf
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 89 deletions.
10 changes: 8 additions & 2 deletions drivers/windows/panda.sln
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -87,4 +90,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8AF3826E-406A-4F1C-BA80-B4D7FD4B52E1}
EndGlobalSection
EndGlobal
177 changes: 109 additions & 68 deletions drivers/windows/panda/panda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
}

Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;

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);
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.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;
}

// Pause if there is not a slot available in the queue
if (n_ptr == this->r_ptr) {
printf("RX queue full!\n");
continue;
}

if (this->can_rx_q[n_ptr].complete) {
// TODO: is ResetEvent() faster?
CloseHandle(this->can_rx_q[n_ptr].complete);
}

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

HANDLE phSignals[2] = { m_hReadFinishedEvent, kill_event };
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();
}

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);
// 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
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down
27 changes: 25 additions & 2 deletions drivers/windows/panda/panda.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>;

Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand Down Expand Up @@ -202,13 +205,33 @@ 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;
std::string sn;
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;
};

}
28 changes: 24 additions & 4 deletions drivers/windows/pandaJ2534DLL/J2534Connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ long J2534Connection::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMs
messageRxBuff_mutex.unlock();
if (Timeout == 0)
break;
Sleep(2);
continue;
}

Expand Down Expand Up @@ -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::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::clearRXBuff() {
synchronized(messageRxBuff_mutex) {
this->messageRxBuff = {};
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::clearPeriodicMsgs() { return STATUS_NOERROR; }
long J2534Connection::clearMsgFilters() {
for (auto& filter : this->filters) filter = nullptr;
return STATUS_NOERROR;
Expand Down
Loading

0 comments on commit 2e99dbf

Please sign in to comment.