J2534_WIN: ECUsim supports ISO15765 extended addresses. With tests.

master
Jessy Diamond Exum 2017-09-21 02:32:54 -07:00
parent 353093a577
commit da1725dc27
5 changed files with 155 additions and 35 deletions

View File

@ -1,7 +1,8 @@
#include "stdafx.h"
#include "ECUsim.h"
ECUsim::ECUsim(std::string sn, unsigned long can_baud) : doloop(TRUE), verbose(TRUE), can11b_enabled(TRUE), can29b_enabled(TRUE){
ECUsim::ECUsim(std::string sn, unsigned long can_baud, bool ext_addr) :
doloop(TRUE), verbose(TRUE), can11b_enabled(TRUE), can29b_enabled(TRUE), ext_addr(ext_addr){
this->panda = panda::Panda::openPanda(sn);
this->panda->set_can_speed_cbps(panda::PANDA_CAN1, can_baud / 100); //Don't pass in baud where baud%100 != 0
this->panda->set_safety_mode(panda::SAFETY_ALLOUTPUT);
@ -10,8 +11,11 @@ ECUsim::ECUsim(std::string sn, unsigned long can_baud) : doloop(TRUE), verbose(T
DWORD threadid;
this->thread_can = CreateThread(NULL, 0, _canthreadBootstrap, (LPVOID)this, 0, &threadid);
}
return;
ECUsim::~ECUsim() {
this->stop();
this->join();
}
void ECUsim::stop() {
@ -52,10 +56,20 @@ DWORD ECUsim::can_recv_thread_function() {
}
BOOL ECUsim::_can_addr_matches(panda::PANDA_CAN_MSG& msg) {
if (this->can11b_enabled && !msg.addr_29b && (msg.addr == 0x7DF || (msg.addr & 0x7F8) == 0x7E0))
return TRUE;
if (this->can29b_enabled && msg.addr_29b && ((msg.addr & 0x1FFF00FF) == 0x18DB00F1 || (msg.addr & 0x1FFF00FF) == 0x18da00f1))
return TRUE;
if (this->can11b_enabled && !msg.addr_29b && (msg.addr == 0x7DF || (msg.addr & 0x7F8) == 0x7E0)) {
if (!this->ext_addr) {
return TRUE;
} else {
return msg.len >= 1 && msg.dat[0] == 0x13;//13 is an arbitrary address picked to test ext addresses
}
}
if (this->can29b_enabled && msg.addr_29b && ((msg.addr & 0x1FFF00FF) == 0x18DB00F1 || (msg.addr & 0x1FFF00FF) == 0x18da00f1)) {
if (!this->ext_addr) {
return TRUE;
} else {
return msg.len >= 1 && msg.dat[0] == 0x13;//13 is an arbitrary address picked to test ext addresses
}
}
return FALSE;
}
@ -66,7 +80,8 @@ void ECUsim::_CAN_process_msg(panda::PANDA_CAN_MSG& msg) {
bool doreply = FALSE;
if (this->_can_addr_matches(msg)) {// && msg.len == 8) {
if ((msg.dat[0] & 0xF0) == 0x10) {
uint8_t *dat = (this->ext_addr) ? &msg.dat[1] : &msg.dat[0];
if ((dat[0] & 0xF0) == 0x10) {
printf("Got a multiframe write request\n");
outaddr = (msg.addr_29b) ? 0x18DAF1EF : 0x7E8;
this->panda->can_send(outaddr, msg.addr_29b, (const uint8_t*)"\x30\x00\x00", 3, panda::PANDA_CAN1);
@ -74,30 +89,35 @@ void ECUsim::_CAN_process_msg(panda::PANDA_CAN_MSG& msg) {
}
/////////// Check if Flow Control Msg
if ((msg.dat[0] & 0xF0) == 0x30 && msg.len >= 3 && this->can_multipart_data.size() > 0) {
if ((dat[0] & 0xF0) == 0x30 && msg.len >= 3 && this->can_multipart_data.size() > 0) {
if (this->verbose) printf("More data requested\n");
uint8_t block_size = msg.dat[1], sep_time_min = msg.dat[2];
outaddr = (msg.addr == 0x7DF || msg.addr == 0x7E0) ? 0x7E8 : 0x18DAF1EF;
uint8_t block_size = dat[1], sep_time_min = dat[2];
outaddr = (msg.addr == 0x7DF || msg.addr == 0x7E0) ? 0x7E8 : 0x18DAF1EF; //ext addr 5th byte is just always 0x13 for simplicity
unsigned int msgnum = 1;
while (this->can_multipart_data.size()) {
unsigned int datalen = min(7, this->can_multipart_data.size());
unsigned int datalen = this->ext_addr ?
min(6, this->can_multipart_data.size()): //EXT ADDR VALUE
min(7, this->can_multipart_data.size()); //NORMAL ADDR VALUE
formatted_msg_buff[0] = 0x20 | msgnum;
unsigned int idx = 0;
if (this->ext_addr)
formatted_msg_buff[idx++] = 0x13; //EXT ADDR
formatted_msg_buff[idx++] = 0x20 | msgnum;
for (int i = 0; i < datalen; i++) {
formatted_msg_buff[i + 1] = this->can_multipart_data.front();
formatted_msg_buff[i + idx] = this->can_multipart_data.front();
this->can_multipart_data.pop();
}
for (int i = datalen + 1; i < sizeof(formatted_msg_buff); i++)
for (int i = datalen + idx; i < sizeof(formatted_msg_buff); i++)
formatted_msg_buff[i] = 0;
if (this->verbose) {
printf("Multipart reply to %X.\n ", outaddr);
for (int i = 0; i < datalen + 1; i++) printf("%02X ", formatted_msg_buff[i]);
for (int i = 0; i < datalen + idx; i++) printf("%02X ", formatted_msg_buff[i]);
printf("\n");
}
this->panda->can_send(outaddr, msg.addr_29b, formatted_msg_buff, datalen + 1, panda::PANDA_CAN1);
this->panda->can_send(outaddr, msg.addr_29b, formatted_msg_buff, datalen + idx, panda::PANDA_CAN1);
msgnum = (msgnum + 1) % 0x10;
Sleep(10);
}
@ -105,16 +125,19 @@ void ECUsim::_CAN_process_msg(panda::PANDA_CAN_MSG& msg) {
}
/////////// Normal message in
outmsg = this->process_obd_msg(msg.dat[1], msg.dat[2], doreply);
outmsg = this->process_obd_msg(dat[1], dat[2], doreply);
if (doreply) {
outaddr = (msg.addr_29b) ? 0x18DAF1EF : 0x7E8;
if (outmsg.size() <= 5) {
formatted_msg_buff[0] = outmsg.size() + 2;
formatted_msg_buff[1] = 0x40 | msg.dat[1];
formatted_msg_buff[2] = msg.dat[2]; //PID
memcpy_s(&formatted_msg_buff[3], sizeof(formatted_msg_buff) - 3, outmsg.c_str(), outmsg.size());
for (int i = 3 + outmsg.size(); i < 8; i++)
if (outmsg.size() <= (this->ext_addr ? 4 : 5)) {
unsigned int idx = 0;
if(this->ext_addr)
formatted_msg_buff[idx++] = 0x13; //EXT ADDR
formatted_msg_buff[idx++] = outmsg.size() + 2;
formatted_msg_buff[idx++] = 0x40 | dat[1];
formatted_msg_buff[idx++] = dat[2]; //PID
memcpy_s(&formatted_msg_buff[idx], sizeof(formatted_msg_buff) - idx, outmsg.c_str(), outmsg.size());
for (int i = idx + outmsg.size(); i < 8; i++)
formatted_msg_buff[i] = 0;
if (this->verbose) {
@ -125,15 +148,20 @@ void ECUsim::_CAN_process_msg(panda::PANDA_CAN_MSG& msg) {
this->panda->can_send(outaddr, msg.addr_29b, formatted_msg_buff, 8, panda::PANDA_CAN1); //outmsg.size() + 3
} else {
uint8_t first_msg_len = min(3, outmsg.size() % 7);
uint8_t first_msg_len = this->ext_addr ?
min(2, outmsg.size() % 7) : //EXT ADDR VALUES
min(3, outmsg.size() % 7); //NORMAL ADDR VALUES
uint8_t payload_len = outmsg.size() + 3;
formatted_msg_buff[0] = 0x10 | ((payload_len >> 8) & 0xF);
formatted_msg_buff[1] = payload_len & 0xFF;
formatted_msg_buff[2] = 0x40 | msg.dat[1];
formatted_msg_buff[3] = msg.dat[2]; //PID
formatted_msg_buff[4] = 1;
memcpy_s(&formatted_msg_buff[5], sizeof(formatted_msg_buff) - 3, outmsg.c_str(), first_msg_len);
unsigned int idx = 0;
if (this->ext_addr)
formatted_msg_buff[idx++] = 0x13; //EXT ADDR
formatted_msg_buff[idx++] = 0x10 | ((payload_len >> 8) & 0xF);
formatted_msg_buff[idx++] = payload_len & 0xFF;
formatted_msg_buff[idx++] = 0x40 | dat[1];
formatted_msg_buff[idx++] = dat[2]; //PID
formatted_msg_buff[idx++] = 1;
memcpy_s(&formatted_msg_buff[idx], sizeof(formatted_msg_buff) - idx, outmsg.c_str(), first_msg_len);
if (this->verbose) {
printf("Replying FIRST FRAME to %X.\n ", outaddr);
@ -159,7 +187,7 @@ std::string ECUsim::process_obd_msg(UCHAR mode, UCHAR pid, bool& return_data) {
case 0x00: //List supported things
return "\xff\xff\xff\xfe"; //b"\xBE\x1F\xB8\x10" #Bitfield, random features
case 0x01: // Monitor Status since DTC cleared
return "\x00\x00\x00\x00"; //Bitfield, random features
return std::string("\x00\x00\x00\x00", 4); //Bitfield, random features
case 0x04: // Calculated engine load
return "\x2f";
case 0x05: // Engine coolant temperature
@ -214,7 +242,7 @@ std::string ECUsim::process_obd_msg(UCHAR mode, UCHAR pid, bool& return_data) {
tmp.push_back(((i + 1) >> 8) & 0xFF);
tmp.push_back((i + 1) & 0xFF);
}
return "\xAA\x00\x00" + tmp;
return std::string("\xAA\x00\x00", 3) + tmp;
default:
return_data = FALSE;
return "";

View File

@ -19,15 +19,16 @@
// This class is exported from the ECUsim DLL.dll
class ECUSIMDLL_API ECUsim {
public:
ECUsim(std::string sn, unsigned long can_baud);
ECUsim(panda::Panda && p, unsigned long can_baud);
// TODO: add your methods here.
ECUsim(std::string sn, unsigned long can_baud, bool ext_addr = FALSE);
ECUsim(panda::Panda && p, unsigned long can_baud, bool ext_addr = FALSE);
~ECUsim();
void stop();
void join();
// Flag determines if verbose output is enabled
volatile bool verbose;
BOOL ext_addr;
private:
std::unique_ptr<panda::Panda> panda;

View File

@ -0,0 +1,87 @@
#include "stdafx.h"
#include "Loader4.h"
#include "pandaJ2534DLL/J2534_v0404.h"
#include "panda/panda.h"
#include "Timer.h"
#include "ECUsim DLL\ECUsim.h"
#include "TestHelpers.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace pandaWCUsimTest
{
TEST_CLASS(ECUsimTests)
{
public:
TEST_METHOD(ECUsim_ISO15765_SingleFrameTx_29bStandardAddrPad500k)
{
ECUsim sim("", 500000);
auto p = getPanda(500);
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x02\x01\x00", 3, panda::PANDA_CAN1);
auto msg_recv = panda_recv_loop(p, 2);
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x02\x01\x00", 3), LINE_INFO());
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x06\x41\x00\xff\xff\xff\xfe\x00", 8), LINE_INFO());
}
TEST_METHOD(ECUsim_ISO15765_SingleFrameTx_29bStandardAddrPad250k)
{
ECUsim sim("", 250000);
auto p = getPanda(250);
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x02\x01\x00", 3, panda::PANDA_CAN1);
auto msg_recv = panda_recv_loop(p, 2);
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x02\x01\x00", 3), LINE_INFO());
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x06""\x41\x00""\xff\xff\xff\xfe""\x00", 8), LINE_INFO());
}
TEST_METHOD(ECUsim_ISO15765_SingleFrameTx_29bExtAddrPad500k)
{
ECUsim sim("", 500000, TRUE);
auto p = getPanda(500);
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x13""\x02\x01\x00", 4, panda::PANDA_CAN1);
auto msg_recv = panda_recv_loop(p, 2);
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x13""\x02\x01\x00", 4), LINE_INFO());
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x06""\x41\x00""\xff\xff\xff\xfe", 8), LINE_INFO());
}
TEST_METHOD(ECUsim_ISO15765_MultiFrameTx_29bStandardAddrPad500k)
{
ECUsim sim("", 500000);
auto p = getPanda(500);
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x02\x09\x02", 3, panda::PANDA_CAN1);
auto msg_recv = panda_recv_loop(p, 2);
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x02\x09\x02", 3), LINE_INFO());
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x10\x14""\x49\x02\x01""1D4", 8), LINE_INFO());
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x30\x00\x00", 3, panda::PANDA_CAN1);
msg_recv = panda_recv_loop(p, 3);
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x30\x0\x0", 3), LINE_INFO());
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x21""GP00R55", 8), LINE_INFO());
check_panda_can_msg(msg_recv[2], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x22""B123456", 8), LINE_INFO());
}
TEST_METHOD(ECUsim_ISO15765_MultiFrameTx_29bExtAddrPad500k)
{
ECUsim sim("", 500000, TRUE);
auto p = getPanda(500);
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x13""\x02\x09\x02", 4, panda::PANDA_CAN1);
auto msg_recv = panda_recv_loop(p, 2);
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x13""\x02\x09\x02", 4), LINE_INFO());
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x10\x14""\x49\x02\x01""1D", 8), LINE_INFO());
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x13""\x30\x00\x00", 4, panda::PANDA_CAN1);
msg_recv = panda_recv_loop(p, 4);
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x13""\x30\x0\x0", 4), LINE_INFO());
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x21""4GP00R", 8), LINE_INFO());
check_panda_can_msg(msg_recv[2], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x22""55B123", 8), LINE_INFO());
check_panda_can_msg(msg_recv[3], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x23""456", 5), LINE_INFO());
}
};
}

View File

@ -96,6 +96,7 @@
<ClInclude Include="Timer.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ECUsim_tests.cpp" />
<ClCompile Include="Loader4.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>

View File

@ -53,5 +53,8 @@
<ClCompile Include="TestHelpers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ECUsim_tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>