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.
 
 
 
 
 
 

180 lines
6.4 KiB

#include "stdafx.h"
#include "MessageTx_ISO15765.h"
#include "constants_ISO15765.h"
//in microseconsa
#define TIMEOUT_FC 250000 //Flow Control
#define TIMEOUT_CF 250000 //Consecutive Frames
MessageTx_ISO15765::MessageTx_ISO15765(
std::shared_ptr<J2534Connection> connection_in,
PASSTHRU_MSG& to_send,
std::shared_ptr<J2534MessageFilter> filter
) : MessageTxTimeoutable(connection_in, to_send), filter(filter), frames_sent(0),
consumed_count(0), txInFlight(FALSE), sendAll(FALSE), block_size(0), numWaitFrames(0), didtimeout(FALSE), issuspended(FALSE){
CANid = ((uint8_t)fullmsg.Data[0]) << 24 | ((uint8_t)fullmsg.Data[1]) << 16 |
((uint8_t)fullmsg.Data[2]) << 8 | ((uint8_t)fullmsg.Data[3]);
payload = fullmsg.Data.substr(addressLength());
if (check_bmask(fullmsg.TxFlags, ISO15765_ADDR_TYPE))
data_prefix = fullmsg.Data[4];
if (payload.size() <= (7 - data_prefix.size())) {
isMultipart = FALSE;
auto framepayload = data_prefix + std::string(1, (char)payload.size()) + payload;
if (check_bmask(this->fullmsg.TxFlags, ISO15765_FRAME_PAD))
framepayload += std::string(8 - framepayload.size(), '\x00');
framePayloads.push_back(framepayload);
} else {
isMultipart = TRUE;
unsigned long first_payload_len = 6 - data_prefix.size(); // 5 or 6
std::string framepayload = data_prefix +
(char)(0x10 | ((payload.size() >> 8) & 0xF)) +
(char)(payload.size() & 0xFF) +
payload.substr(0, first_payload_len);
framePayloads.push_back(framepayload);
unsigned int pktnum = 1;
uint8_t CFDatSize = 7 - data_prefix.size();
while (TRUE) {
framepayload = data_prefix + (char)(0x20 | (pktnum % 0x10)) +
payload.substr(first_payload_len + (CFDatSize * (pktnum-1)), CFDatSize);
if (check_bmask(this->fullmsg.TxFlags, ISO15765_FRAME_PAD))
framepayload += std::string(8 - framepayload.size(), '\x00');
framePayloads.push_back(framepayload);
if (first_payload_len + (CFDatSize * pktnum) >= payload.size()) break;
pktnum++;
}
}
};
unsigned int MessageTx_ISO15765::addressLength() {
return check_bmask(fullmsg.TxFlags, ISO15765_ADDR_TYPE) ? 5 : 4;
}
void MessageTx_ISO15765::execute() {
if (didtimeout || issuspended) return;
if (this->frames_sent >= this->framePayloads.size()) return;
if (block_size == 0 && !sendAll && this->frames_sent > 0) return;
if (block_size > 0 && !sendAll) block_size--;
if (auto conn_sp = this->connection.lock()) {
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
auto& outFramePayload = this->framePayloads[this->frames_sent];
if (panda_dev_sp->panda->can_send(this->CANid, check_bmask(this->fullmsg.TxFlags, CAN_29BIT_ID),
(const uint8_t*)outFramePayload.c_str(), (uint8_t)outFramePayload.size(), panda::PANDA_CAN1) == FALSE) {
return;
}
this->txInFlight = TRUE;
this->frames_sent++;
panda_dev_sp->txMsgsAwaitingEcho.push(shared_from_this());
}
}
}
//Returns TRUE if receipt is consumed by the msg, FALSE otherwise.
BOOL MessageTx_ISO15765::checkTxReceipt(J2534Frame frame) {
if (!txInFlight) return FALSE;
if (frame.Data.size() >= addressLength() + 1 && (frame.Data[addressLength()] & 0xF0) == FRAME_FLOWCTRL) return FALSE;
if (frame.Data == fullmsg.Data.substr(0, 4) + framePayloads[frames_sent - 1] &&
((this->fullmsg.TxFlags & CAN_29BIT_ID) == (frame.RxStatus & CAN_29BIT_ID))) { //Check receipt is expected
txInFlight = FALSE; //Received the expected receipt. Allow another msg to be sent.
if (this->recvCount == 0 && this->framePayloads.size() > 1)
scheduleTimeout(TIMEOUT_FC);
if (frames_sent == framePayloads.size()) { //Check message done
if (auto conn_sp = std::static_pointer_cast<J2534Connection_ISO15765>(this->connection.lock())) {
unsigned long flags = (filter == nullptr) ? fullmsg.TxFlags : this->filter->flags;
J2534Frame outframe(ISO15765);
outframe.Timestamp = frame.Timestamp;
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);
if (conn_sp->loopback) {
J2534Frame outframe(ISO15765);
outframe.Timestamp = frame.Timestamp;
outframe.RxStatus = TX_MSG_TYPE | (flags & (ISO15765_ADDR_TYPE | CAN_29BIT_ID));
outframe.Data = this->fullmsg.Data;
conn_sp->addMsgToRxQueue(outframe);
}
} //TODO what if fails
} else {
//Restart timeout if we are waiting for a flow control frame.
//FC frames are required when we are not sending all, the
//current block_size batch has not been sent, a FC message has
//already been received (differentiating from first frame), the
//message is not finished, and there is more than one frame in
//the message.
if (block_size == 0 && recvCount != 0 && !sendAll && !this->isFinished() && this->framePayloads.size() > 1)
scheduleTimeout(TIMEOUT_CF);
}
return TRUE;
}
return FALSE;
}
BOOL MessageTx_ISO15765::isFinished() {
return this->frames_sent == this->framePayloads.size() && !txInFlight;
}
BOOL MessageTx_ISO15765::txReady() {
return block_size > 0 || sendAll || this->frames_sent == 0;
}
void MessageTx_ISO15765::reset() {
frames_sent = 0;
consumed_count = 0;
block_size = 0;
txInFlight = FALSE;
sendAll = FALSE;
numWaitFrames = 0;
didtimeout = FALSE;
}
void MessageTx_ISO15765::onTimeout() {
didtimeout = TRUE;
if (auto conn_sp = std::static_pointer_cast<J2534Connection_ISO15765>(this->connection.lock())) {
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
panda_dev_sp->removeConnectionTopAction(conn_sp, shared_from_this());
}
}
}
void MessageTx_ISO15765::flowControlContinue(uint8_t block_size, std::chrono::microseconds separation_time) {
this->issuspended = FALSE;
this->block_size = block_size;
this->delay = separation_time;
this->sendAll = block_size == 0;
this->recvCount++;
}
void MessageTx_ISO15765::flowControlWait(unsigned long N_WFTmax) {
this->issuspended = TRUE;
this->recvCount++;
this->numWaitFrames++;
this->sendAll = FALSE;
this->block_size = block_size;
this->delay = std::chrono::microseconds(0);
//Docs are vague on if 0 means NO WAITS ALLOWED or NO LIMIT TO WAITS.
//It is less likely to cause issue if NO LIMIT is assumed.
if (N_WFTmax > 0 && this->numWaitFrames > N_WFTmax) {
this->onTimeout(); //Trigger self destruction of message.
} else {
scheduleTimeout(TIMEOUT_FC);
}
}
void MessageTx_ISO15765::flowControlAbort() {
this->recvCount++; //Invalidate future timeout actions.
this->onTimeout(); //Trigger self destruction of message.
}