mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 01:18:36 +02:00
LIN: Network support
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "icsneo/communication/message/a2bmessage.h"
|
||||
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
||||
#include "icsneo/communication/message/i2cmessage.h"
|
||||
#include "icsneo/communication/message/linmessage.h"
|
||||
#include "icsneo/communication/command.h"
|
||||
#include "icsneo/device/device.h"
|
||||
#include "icsneo/communication/packet/canpacket.h"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "icsneo/communication/packet/wivicommandpacket.h"
|
||||
#include "icsneo/communication/packet/i2cpacket.h"
|
||||
#include "icsneo/communication/packet/scriptstatuspacket.h"
|
||||
#include "icsneo/communication/packet/linpacket.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace icsneo;
|
||||
@@ -362,6 +364,18 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||
msg.network = packet->network;
|
||||
return true;
|
||||
}
|
||||
case Network::Type::LIN: {
|
||||
result = HardwareLINPacket::DecodeToMessage(packet->data);
|
||||
|
||||
if(!result) {
|
||||
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||
return false; // A nullptr was returned, the packet was not long enough to decode
|
||||
}
|
||||
|
||||
LINMessage& msg = *static_cast<LINMessage*>(result.get());
|
||||
msg.network = packet->network;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// For the moment other types of messages will automatically be decoded as raw messages
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "icsneo/communication/packet/i2cpacket.h"
|
||||
#include "icsneo/communication/message/i2cmessage.h"
|
||||
#include "icsneo/communication/packet/a2bpacket.h"
|
||||
|
||||
#include "icsneo/communication/packet/linpacket.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
@@ -96,6 +96,18 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
|
||||
}
|
||||
break;
|
||||
} // End of Network::Type::I2C
|
||||
case Network::Type::LIN: {
|
||||
auto linmsg = std::dynamic_pointer_cast<LINMessage>(message);
|
||||
if(!linmsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
buffer = &result;
|
||||
if(!HardwareLINPacket::EncodeFromMessage(*linmsg, result, report)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
} // End of Network::Type::LIN
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return false;
|
||||
@@ -182,7 +194,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
|
||||
// Size for the host-to-device long format is the size of the entire packet + 1
|
||||
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
|
||||
// Then an extra +1, due to a firmware idiosyncrasy
|
||||
uint16_t size = uint16_t(buffer->size()) + 1 + 1 + 2 + 2 + 1;
|
||||
uint16_t size = static_cast<uint16_t>(buffer->size()) + 1 + 1 + 2 + 2 + 1;
|
||||
|
||||
buffer->insert(buffer->begin(), {
|
||||
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
||||
(uint8_t)size, // Size, little endian 16-bit
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "icsneo/communication/message/linmessage.h"
|
||||
#include <numeric>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
void LINMessage::calcChecksum(LINMessage& message) {
|
||||
uint16_t sum = 0;
|
||||
auto limitFunc = [](uint16_t x, uint16_t y) -> uint16_t {
|
||||
if ((x + y) > 0xFFu)
|
||||
return ((x + y) - 0xFFu);
|
||||
else
|
||||
return (x + y);
|
||||
};
|
||||
|
||||
message.checksum = static_cast<uint8_t>(std::accumulate(message.data.begin(), message.data.end(), sum, limitFunc));
|
||||
if(message.isEnhancedChecksum)
|
||||
message.checksum = static_cast<uint8_t>(limitFunc(message.checksum, message.protectedID));
|
||||
|
||||
message.checksum ^= 0xFFu;
|
||||
}
|
||||
|
||||
} //namespace icsneo
|
||||
@@ -0,0 +1,153 @@
|
||||
#include "icsneo/communication/packet/linpacket.h"
|
||||
#include "icsneo/communication/message/linmessage.h"
|
||||
#include "icsneo/communication/packetizer.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
std::shared_ptr<Message> HardwareLINPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
|
||||
auto msg = std::make_shared<LINMessage>();
|
||||
const HardwareLINPacket* packet = reinterpret_cast<const HardwareLINPacket*>(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
|
||||
|
||||
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
|
||||
msg->protectedID = packet->CoreMiniBitsLIN.ID;
|
||||
msg->ID = (packet->CoreMiniBitsLIN.ID & 0x3Fu);
|
||||
msg->isEnhancedChecksum = static_cast<bool>(packet->CoreMiniBitsLIN.TxChkSumEnhanced);
|
||||
|
||||
/* Minimum one responder byte and one checksum byte. */
|
||||
if(2u > packet->CoreMiniBitsLIN.len)
|
||||
msg->type = 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 true;
|
||||
|
||||
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<bool>(packet->CoreMiniBitsLIN.ErrRxOnlyBreak),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxOnlyBreakSync),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.ErrTxRxMismatch),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxBreakNotZero),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxBreakTooShort),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxSyncNot55),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxDataGreater8),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.SyncFerr),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.MidFerr),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.ResponderByteFerr),
|
||||
isChecksumInvalid(), /* ErrChecksumMatch */
|
||||
};
|
||||
|
||||
msg->statusFlags =
|
||||
{
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.TxChkSumEnhanced),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.TXCommander),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.TXResponder),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.TxAborted),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.UpdateResponderOnce),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.BusRecovered),
|
||||
static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly)
|
||||
};
|
||||
if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder)
|
||||
msg->type = LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
else if(msg->statusFlags.BreakOnly)
|
||||
msg->type = 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->type = LINMessage::Type::LIN_ERROR; }
|
||||
|
||||
msg->timestamp = packet->timestamp;
|
||||
return msg;
|
||||
}
|
||||
|
||||
bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
|
||||
{
|
||||
uint8_t size = ((std::min<size_t>(8ul, message.data.size()) + 3ul) & 0xFu);
|
||||
if(size > 3) { ++size; } // add a checksum byte if there's data
|
||||
switch(message.type) {
|
||||
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.ID;
|
||||
auto bit = [&](uint8_t pos)->uint8_t { return ((message.protectedID >> pos) & 0x1u); };
|
||||
message.protectedID |= (~(bit(1) ^ bit(3) ^ bit(4) ^ bit(5)) << 7);
|
||||
message.protectedID |= ((bit(0) ^ bit(1) ^ bit(2) ^ bit(4)) << 6);
|
||||
|
||||
bytestream.insert(bytestream.end(),
|
||||
{
|
||||
static_cast<uint8_t>(0x00u),
|
||||
static_cast<uint8_t>(size),
|
||||
static_cast<uint8_t>((message.description >> 8) & 0xFF),
|
||||
static_cast<uint8_t>(message.description & 0xFF),
|
||||
static_cast<uint8_t>(message.protectedID)
|
||||
});
|
||||
|
||||
switch(message.type) {
|
||||
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
|
||||
Reference in New Issue
Block a user