openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
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.
 
 
 
 
 
 

283 lines
8.5 KiB

#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;
Sleep(2);
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;
}
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;
}
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;
}
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);
break;
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);
}
// reserved parameters usually mean special equiptment is required
if (Parameter >= 0x20) {
throw ERR_NOT_SUPPORTED;
}
}
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);
}
}