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.
181 lines
6.4 KiB
181 lines
6.4 KiB
7 years ago
|
#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;
|
||
7 years ago
|
outframe.RxStatus = TX_MSG_TYPE | TX_INDICATION | (flags & (ISO15765_ADDR_TYPE | CAN_29BIT_ID));
|
||
7 years ago
|
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.
|
||
|
}
|