You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
8.5 KiB
284 lines
8.5 KiB
7 years ago
|
#include "stdafx.h"
|
||
|
#include "J2534Connection.h"
|
||
|
#include "Timer.h"
|
||
|
|
||
|
J2534Connection::J2534Connection(
|
||
|
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||
|
unsigned long ProtocolID,
|
||
|
unsigned long Flags,
|
||
|
unsigned long BaudRate
|
||
|
) : panda_dev(panda_dev), ProtocolID(ProtocolID), Flags(Flags), BaudRate(BaudRate), port(0) { }
|
||
|
|
||
|
unsigned long J2534Connection::validateTxMsg(PASSTHRU_MSG* msg) {
|
||
|
if (msg->DataSize < this->getMinMsgLen() || msg->DataSize > this->getMaxMsgLen())
|
||
|
return ERR_INVALID_MSG;
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
|
|
||
|
long J2534Connection::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
|
||
|
//Timeout of 0 means return immediately. Non zero means WAIT for that time then return. Dafuk.
|
||
|
long err_code = STATUS_NOERROR;
|
||
|
Timer t = Timer();
|
||
|
|
||
|
unsigned long msgnum = 0;
|
||
|
while (msgnum < *pNumMsgs) {
|
||
|
if (Timeout > 0 && t.getTimePassed() >= Timeout) {
|
||
|
err_code = ERR_TIMEOUT;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//Synchronized won't work where we have to break out of a loop
|
||
|
messageRxBuff_mutex.lock();
|
||
|
if (this->messageRxBuff.empty()) {
|
||
|
messageRxBuff_mutex.unlock();
|
||
|
if (Timeout == 0)
|
||
|
break;
|
||
7 years ago
|
Sleep(2);
|
||
7 years ago
|
continue;
|
||
|
}
|
||
|
|
||
|
auto msg_in = this->messageRxBuff.front();
|
||
|
this->messageRxBuff.pop();
|
||
|
messageRxBuff_mutex.unlock();
|
||
|
|
||
|
PASSTHRU_MSG *msg_out = &pMsg[msgnum++];
|
||
|
msg_out->ProtocolID = this->ProtocolID;
|
||
|
msg_out->DataSize = msg_in.Data.size();
|
||
|
memcpy(msg_out->Data, msg_in.Data.c_str(), msg_in.Data.size());
|
||
|
msg_out->Timestamp = msg_in.Timestamp;
|
||
|
msg_out->RxStatus = msg_in.RxStatus;
|
||
|
msg_out->ExtraDataIndex = msg_in.ExtraDataIndex;
|
||
|
msg_out->TxFlags = 0;
|
||
|
if (msgnum == *pNumMsgs) break;
|
||
|
}
|
||
|
|
||
|
if (msgnum == 0)
|
||
|
err_code = ERR_BUFFER_EMPTY;
|
||
|
*pNumMsgs = msgnum;
|
||
|
return err_code;
|
||
|
}
|
||
|
|
||
|
long J2534Connection::PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
|
||
|
//There doesn't seem to be much reason to implement the timeout here.
|
||
|
for (int msgnum = 0; msgnum < *pNumMsgs; msgnum++) {
|
||
|
PASSTHRU_MSG* msg = &pMsg[msgnum];
|
||
|
if (msg->ProtocolID != this->ProtocolID) {
|
||
|
*pNumMsgs = msgnum;
|
||
|
return ERR_MSG_PROTOCOL_ID;
|
||
|
}
|
||
|
|
||
|
auto retcode = this->validateTxMsg(msg);
|
||
|
if (retcode != STATUS_NOERROR) {
|
||
|
*pNumMsgs = msgnum;
|
||
|
return retcode;
|
||
|
}
|
||
|
|
||
|
auto msgtx = this->parseMessageTx(*pMsg);
|
||
|
if (msgtx != nullptr) //Nullptr is supported for unimplemented connection types.
|
||
|
this->schedultMsgTx(std::dynamic_pointer_cast<Action>(msgtx));
|
||
|
}
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
|
|
||
|
//The docs say that a device has to support 10 periodic messages, though more is ok.
|
||
|
//It is easier to store them on the connection, so 10 per connection it is.
|
||
|
long J2534Connection::PassThruStartPeriodicMsg(PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval) {
|
||
|
if (pMsg->DataSize < getMinMsgLen() || pMsg->DataSize > getMaxMsgSingleFrameLen()) return ERR_INVALID_MSG;
|
||
|
if (pMsg->ProtocolID != this->ProtocolID) return ERR_MSG_PROTOCOL_ID;
|
||
|
if (TimeInterval < 5 || TimeInterval > 65535) return ERR_INVALID_TIME_INTERVAL;
|
||
|
|
||
|
for (int i = 0; i < this->periodicMessages.size(); i++) {
|
||
|
if (periodicMessages[i] != nullptr) continue;
|
||
|
|
||
|
*pMsgID = i;
|
||
|
auto msgtx = this->parseMessageTx(*pMsg);
|
||
|
if (msgtx != nullptr) {
|
||
|
periodicMessages[i] = std::make_shared<MessagePeriodic>(std::chrono::microseconds(TimeInterval*1000), msgtx);
|
||
|
periodicMessages[i]->scheduleImmediate();
|
||
|
if (auto panda_dev = this->getPandaDev()) {
|
||
|
panda_dev->insertActionIntoTaskList(periodicMessages[i]);
|
||
|
}
|
||
|
}
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
|
return ERR_EXCEEDED_LIMIT;
|
||
|
}
|
||
|
|
||
|
long J2534Connection::PassThruStopPeriodicMsg(unsigned long MsgID) {
|
||
|
if (MsgID >= this->periodicMessages.size() || this->periodicMessages[MsgID] == nullptr)
|
||
|
return ERR_INVALID_MSG_ID;
|
||
|
this->periodicMessages[MsgID]->cancel();
|
||
|
this->periodicMessages[MsgID] = nullptr;
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
|
|
||
|
long J2534Connection::PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
|
||
|
PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID) {
|
||
|
for (int i = 0; i < this->filters.size(); i++) {
|
||
|
if (filters[i] == nullptr) {
|
||
|
try {
|
||
|
auto newfilter = std::make_shared<J2534MessageFilter>(this, FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg);
|
||
|
for (int check_idx = 0; check_idx < filters.size(); check_idx++) {
|
||
|
if (filters[check_idx] == nullptr) continue;
|
||
|
if (filters[check_idx] == newfilter) {
|
||
|
filters[i] = nullptr;
|
||
|
return ERR_NOT_UNIQUE;
|
||
|
}
|
||
|
}
|
||
|
*pFilterID = i;
|
||
|
filters[i] = newfilter;
|
||
|
return STATUS_NOERROR;
|
||
|
} catch (int e) {
|
||
|
return e;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ERR_EXCEEDED_LIMIT;
|
||
|
}
|
||
|
|
||
|
long J2534Connection::PassThruStopMsgFilter(unsigned long FilterID) {
|
||
|
if (FilterID >= this->filters.size() || this->filters[FilterID] == nullptr)
|
||
|
return ERR_INVALID_FILTER_ID;
|
||
|
this->filters[FilterID] = nullptr;
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
|
|
||
|
long J2534Connection::PassThruIoctl(unsigned long IoctlID, void *pInput, void *pOutput) {
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
|
|
||
7 years ago
|
long J2534Connection::init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) { return ERR_FAILED; }
|
||
|
long J2534Connection::initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput) { return ERR_FAILED; }
|
||
|
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;
|
||
|
}
|
||
7 years ago
|
long J2534Connection::clearRXBuff() {
|
||
7 years ago
|
if (auto panda_ps = this->panda_dev.lock()) {
|
||
|
synchronized(messageRxBuff_mutex) {
|
||
|
this->messageRxBuff = {};
|
||
|
panda_ps->panda->can_clear(panda::PANDA_CAN_RX);
|
||
|
}
|
||
7 years ago
|
}
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
7 years ago
|
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;
|
||
|
}
|
||
7 years ago
|
long J2534Connection::clearMsgFilters() {
|
||
|
for (auto& filter : this->filters) filter = nullptr;
|
||
|
return STATUS_NOERROR;
|
||
|
}
|
||
|
|
||
|
void J2534Connection::setBaud(unsigned long baud) {
|
||
|
this->BaudRate = baud;
|
||
|
}
|
||
|
|
||
|
void J2534Connection::schedultMsgTx(std::shared_ptr<Action> msgout) {
|
||
|
if (auto panda_ps = this->panda_dev.lock()) {
|
||
|
synchronized(staged_writes_lock) {
|
||
|
this->txbuff.push(msgout);
|
||
|
panda_ps->registerConnectionTx(shared_from_this());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void J2534Connection::rescheduleExistingTxMsgs() {
|
||
|
if (auto panda_ps = this->panda_dev.lock()) {
|
||
|
synchronized(staged_writes_lock) {
|
||
|
panda_ps->unstallConnectionTx(shared_from_this());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Works well as long as the protocol doesn't support flow control.
|
||
|
void J2534Connection::processMessage(const J2534Frame& msg) {
|
||
|
FILTER_RESULT filter_res = FILTER_RESULT_NEUTRAL;
|
||
|
|
||
|
for (auto filter : this->filters) {
|
||
|
if (filter == nullptr) continue;
|
||
|
FILTER_RESULT current_check_res = filter->check(msg);
|
||
|
if (current_check_res == FILTER_RESULT_BLOCK) return;
|
||
|
if (current_check_res == FILTER_RESULT_PASS) filter_res = FILTER_RESULT_PASS;
|
||
|
}
|
||
|
|
||
|
if (filter_res == FILTER_RESULT_PASS) {
|
||
|
addMsgToRxQueue(msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void J2534Connection::processIOCTLSetConfig(unsigned long Parameter, unsigned long Value) {
|
||
|
switch (Parameter) {
|
||
|
case DATA_RATE: // 5-500000
|
||
|
this->setBaud(Value);
|
||
7 years ago
|
break;
|
||
7 years ago
|
case LOOPBACK: // 0 (OFF), 1 (ON) [0]
|
||
|
this->loopback = (Value != 0);
|
||
|
break;
|
||
|
case ISO15765_WFT_MAX:
|
||
|
break;
|
||
|
case NODE_ADDRESS: // J1850PWM Related (Not supported by panda). HDS requires these to 'work'.
|
||
|
case NETWORK_LINE:
|
||
|
case P1_MIN: // A bunch of stuff relating to ISO9141 and ISO14230 that the panda
|
||
|
case P1_MAX: // currently doesn't support. Don't let HDS know we can't use these.
|
||
|
case P2_MIN:
|
||
|
case P2_MAX:
|
||
|
case P3_MIN:
|
||
|
case P3_MAX:
|
||
|
case P4_MIN:
|
||
|
case P4_MAX:
|
||
|
case W0:
|
||
|
case W1:
|
||
|
case W2:
|
||
|
case W3:
|
||
|
case W4:
|
||
|
case W5:
|
||
|
case TIDLE:
|
||
|
case TINIL:
|
||
|
case TWUP:
|
||
|
case PARITY:
|
||
|
case T1_MAX: // SCI related options. The panda does not appear to support this
|
||
|
case T2_MAX:
|
||
|
case T3_MAX:
|
||
|
case T4_MAX:
|
||
|
case T5_MAX:
|
||
|
break; // Just smile and nod.
|
||
|
default:
|
||
|
printf("Got unknown SET code %X\n", Parameter);
|
||
|
}
|
||
7 years ago
|
|
||
|
// reserved parameters usually mean special equiptment is required
|
||
|
if (Parameter >= 0x20) {
|
||
|
throw ERR_NOT_SUPPORTED;
|
||
|
}
|
||
7 years ago
|
}
|
||
|
|
||
|
unsigned long J2534Connection::processIOCTLGetConfig(unsigned long Parameter) {
|
||
|
switch (Parameter) {
|
||
|
case DATA_RATE:
|
||
|
return this->getBaud();
|
||
|
case LOOPBACK:
|
||
|
return this->loopback;
|
||
|
break;
|
||
|
case BIT_SAMPLE_POINT:
|
||
|
return 80;
|
||
|
case SYNC_JUMP_WIDTH:
|
||
|
return 15;
|
||
|
default:
|
||
|
// HDS rarely reads off values through ioctl GET_CONFIG, but it often
|
||
|
// just wants the call to pass without erroring, so just don't do anything.
|
||
|
printf("Got unknown code %X\n", Parameter);
|
||
|
}
|
||
|
}
|