#include "icsneo/communication/packet/linpacket.h" #include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/packetizer.h" namespace icsneo { std::shared_ptr HardwareLINPacket::DecodeToMessage(const std::vector& bytestream) { const HardwareLINPacket* packet = reinterpret_cast(bytestream.data()); size_t numDataBytes = packet->CoreMiniBitsLIN.len; size_t numHeaderBytes = sizeof(HardwareLINPacket::CoreMiniBitsLIN); if( (sizeof(HardwareLINPacket) > bytestream.size()) || ((numDataBytes + numHeaderBytes) > bytestream.size()) ) return nullptr; if(numDataBytes) --numDataBytes; //If data is present, there will be a checksum included auto msg = std::make_shared(static_cast(packet->CoreMiniBitsLIN.ID)); msg->isEnhancedChecksum = static_cast(packet->CoreMiniBitsLIN.TxChkSumEnhanced); /* Minimum one responder byte and one checksum byte. */ if(2u > packet->CoreMiniBitsLIN.len) msg->linMsgType = LINMessage::Type::LIN_ERROR; auto dataStart = bytestream.begin() + numHeaderBytes; std::copy(dataStart, (dataStart+numDataBytes), std::back_inserter(msg->data)); /* If OK, validate the checksum*/ auto isChecksumInvalid = [&]() -> bool { /* messages with no data have no checksum (e.g. header only) */ if(!msg->data.size()) return false; uint8_t checkSum = (8 > numDataBytes) ? *(dataStart + numDataBytes) : packet->CoreMiniBitsLIN.LINByte9; LINMessage::calcChecksum(*msg); if(checkSum != msg->checksum) { msg->isEnhancedChecksum = true; LINMessage::calcChecksum(*msg); if(checkSum != msg->checksum) { msg->isEnhancedChecksum = false; msg->checksum = checkSum; return true; } } return false; }; /* if any of the status bits are set, then this is either a failed reception or a bus status update. */ msg->errFlags = { static_cast(packet->CoreMiniBitsLIN.ErrRxOnlyBreak), static_cast(packet->CoreMiniBitsLIN.ErrRxOnlyBreakSync), static_cast(packet->CoreMiniBitsLIN.ErrTxRxMismatch), static_cast(packet->CoreMiniBitsLIN.ErrRxBreakNotZero), static_cast(packet->CoreMiniBitsLIN.ErrRxBreakTooShort), static_cast(packet->CoreMiniBitsLIN.ErrRxSyncNot55), static_cast(packet->CoreMiniBitsLIN.ErrRxDataGreater8), static_cast(packet->CoreMiniBitsLIN.SyncFerr), static_cast(packet->CoreMiniBitsLIN.MidFerr), static_cast(packet->CoreMiniBitsLIN.ResponderByteFerr), isChecksumInvalid(), /* ErrChecksumMatch */ }; msg->statusFlags = { static_cast(packet->CoreMiniBitsLIN.TxChkSumEnhanced), static_cast(packet->CoreMiniBitsLIN.TXCommander), static_cast(packet->CoreMiniBitsLIN.TXResponder), static_cast(packet->CoreMiniBitsLIN.TxAborted), static_cast(packet->CoreMiniBitsLIN.UpdateResponderOnce), static_cast(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce), static_cast(packet->CoreMiniBitsLIN.BusRecovered), static_cast(packet->CoreMiniBitsLIN.BreakOnly) }; if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder) msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG; else if(msg->statusFlags.BreakOnly) msg->linMsgType = LINMessage::Type::LIN_BREAK_ONLY; if( msg->errFlags.ErrRxBreakOnly || msg->errFlags.ErrRxBreakSyncOnly || msg->errFlags.ErrTxRxMismatch || msg->errFlags.ErrRxBreakNotZero || msg->errFlags.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 || msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync || msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch || msg->errFlags.ErrFrameResponderData ) { msg->linMsgType = LINMessage::Type::LIN_ERROR; } msg->timestamp = packet->timestamp; return msg; } bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector& bytestream, const device_eventhandler_t& report) { uint8_t size = ((std::min(8ul, message.data.size()) + 3ul) & 0xFu); if(size > 3) { ++size; } // add a checksum byte if there's data switch(message.linMsgType) { case LINMessage::Type::LIN_HEADER_ONLY: case LINMessage::Type::LIN_COMMANDER_MSG: { size |= 0x80u; break; } case LINMessage::Type::LIN_BREAK_ONLY: { size |= 0x20u; break; } case LINMessage::Type::NOT_SET: { report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error); return false; } default: break; } message.protectedID = message.calcProtectedID(message.ID); bytestream.insert(bytestream.end(), { static_cast(0x00u), static_cast(size), static_cast((message.description >> 8) & 0xFF), static_cast(message.description & 0xFF), static_cast(message.protectedID) }); switch(message.linMsgType) { case(LINMessage::Type::LIN_COMMANDER_MSG): case(LINMessage::Type::LIN_UPDATE_RESPONDER): { std::copy(message.data.begin(), message.data.end(), std::back_inserter(bytestream)); LINMessage::calcChecksum(message); bytestream.push_back(message.checksum); break; } default: break; } if(bytestream.size() % 2) bytestream.push_back(0x41); //padding return true; } } //namespace icsneo