#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 connection_in, PASSTHRU_MSG& to_send, std::shared_ptr 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(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(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. }