LIN: Legacy API
parent
0fa7494eab
commit
63c81b1c3d
|
|
@ -73,6 +73,25 @@ static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t
|
|||
return false;
|
||||
|
||||
const neomessage_frame_t& frame = *reinterpret_cast<const neomessage_frame_t*>(&newmsg);
|
||||
|
||||
auto copyStatusData = [&]() {
|
||||
oldmsg.NetworkID = static_cast<uint8_t>(frame.netid); // Note: NetID remapping from the original API is not supported
|
||||
oldmsg.NetworkID2 = static_cast<uint8_t>(frame.netid >> 8);
|
||||
oldmsg.DescriptionID = frame.description;
|
||||
oldmsg.StatusBitField = frame.status.statusBitfield[0];
|
||||
oldmsg.StatusBitField2 = frame.status.statusBitfield[1];
|
||||
oldmsg.StatusBitField3 = frame.status.statusBitfield[2];
|
||||
oldmsg.StatusBitField4 = frame.status.statusBitfield[3];
|
||||
};
|
||||
|
||||
auto copyFrameData = [&]() {
|
||||
oldmsg.ExtraDataPtr = (void*)frame.data;
|
||||
oldmsg.ExtraDataPtrEnabled = frame.length > 8 ? 1 : 0;
|
||||
memcpy(oldmsg.Data, frame.data, std::min(frame.length, (size_t)8));
|
||||
oldmsg.ArbIDOrHeader = *reinterpret_cast<const uint32_t*>(frame.header);
|
||||
copyStatusData();
|
||||
};
|
||||
|
||||
switch (Network::Type(frame.type))
|
||||
{
|
||||
case Network::Type::CAN:
|
||||
|
|
@ -81,28 +100,42 @@ static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t
|
|||
oldmsg.Protocol = frame.status.canfdFDF ? SPY_PROTOCOL_CANFD : SPY_PROTOCOL_CAN;
|
||||
oldmsg.NumberBytesData = static_cast<uint8_t>(std::min(frame.length, (size_t)255));
|
||||
oldmsg.NumberBytesHeader = 4;
|
||||
copyFrameData();
|
||||
break;
|
||||
case Network::Type::Ethernet:
|
||||
oldmsg.Protocol = SPY_PROTOCOL_ETHERNET;
|
||||
oldmsg.NumberBytesData = static_cast<uint8_t>(frame.length & 0xFF);
|
||||
oldmsg.NumberBytesHeader = static_cast<uint8_t>(frame.length >> 8);
|
||||
copyFrameData();
|
||||
break;
|
||||
case Network::Type::LIN:
|
||||
{
|
||||
const neomessage_lin_t& linFrame = *reinterpret_cast<const neomessage_lin_t*>(&frame);
|
||||
icsSpyMessageJ1850& linSpyMsg = *reinterpret_cast<icsSpyMessageJ1850*>(&oldmsg);
|
||||
linSpyMsg.Protocol = SPY_PROTOCOL_LIN;
|
||||
linSpyMsg.NumberBytesHeader = static_cast<uint8_t>(std::min(linFrame.length, static_cast<size_t>(3)));
|
||||
linSpyMsg.NumberBytesData = static_cast<uint8_t>(linFrame.length - linSpyMsg.NumberBytesHeader);
|
||||
oldmsg.ArbIDOrHeader = *reinterpret_cast<const uint32_t*>(frame.header);
|
||||
copyStatusData();
|
||||
if ((2 < linFrame.length) && (linFrame.length <= 10)) {
|
||||
auto copyBytes = std::min(linSpyMsg.NumberBytesData, static_cast<uint8_t>(6));
|
||||
std::memcpy(oldmsg.Data, frame.data, copyBytes);
|
||||
oldmsg.Data[copyBytes] = linFrame.checksum;
|
||||
} else if (2 == linFrame.length) {
|
||||
std::memset(oldmsg.Data, 0, 8);
|
||||
linSpyMsg.Header[linSpyMsg.NumberBytesHeader] = linFrame.checksum;
|
||||
++linSpyMsg.NumberBytesHeader;
|
||||
} else {
|
||||
std::memset(oldmsg.Data, 0, 8);
|
||||
}
|
||||
if (linFrame.linStatus.txCommander)
|
||||
linSpyMsg.StatusBitField |= SPY_STATUS_INIT_MESSAGE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
oldmsg.ExtraDataPtr = (void*)frame.data;
|
||||
oldmsg.ExtraDataPtrEnabled = frame.length > 8 ? 1 : 0;
|
||||
memcpy(oldmsg.Data, frame.data, std::min(frame.length, (size_t)8));
|
||||
oldmsg.ArbIDOrHeader = *reinterpret_cast<const uint32_t*>(frame.header);
|
||||
oldmsg.NetworkID = static_cast<uint8_t>(frame.netid); // Note: NetID remapping from the original API is not supported
|
||||
oldmsg.NetworkID2 = static_cast<uint8_t>(frame.netid >> 8);
|
||||
oldmsg.DescriptionID = frame.description;
|
||||
oldmsg.StatusBitField = frame.status.statusBitfield[0];
|
||||
oldmsg.StatusBitField2 = frame.status.statusBitfield[1];
|
||||
oldmsg.StatusBitField3 = frame.status.statusBitfield[2];
|
||||
oldmsg.StatusBitField4 = frame.status.statusBitfield[3];
|
||||
|
||||
// Timestamp - epoch = 1/1/2007 - 25ns per tick most of the time
|
||||
uint64_t t = frame.timestamp;
|
||||
uint16_t res = 0;
|
||||
|
|
@ -127,6 +160,84 @@ static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool SpyMessageToNeoMessage(const icsSpyMessage& oldmsg, neomessage_frame_t& frame, unsigned int& lNetworkID)
|
||||
{
|
||||
frame.netid = static_cast<uint16_t>(lNetworkID);
|
||||
frame.description = oldmsg.DescriptionID;
|
||||
|
||||
frame.status.statusBitfield[0] = oldmsg.StatusBitField;
|
||||
frame.status.statusBitfield[1] = oldmsg.StatusBitField2;
|
||||
frame.status.statusBitfield[2] = oldmsg.StatusBitField3;
|
||||
frame.status.statusBitfield[3] = oldmsg.StatusBitField4;
|
||||
|
||||
auto copyFrameDataPtr = [&]() {
|
||||
memcpy(frame.header, &oldmsg.ArbIDOrHeader, sizeof(frame.header));
|
||||
if ((oldmsg.ExtraDataPtr != nullptr) && (oldmsg.ExtraDataPtrEnabled == 1))
|
||||
frame.data = reinterpret_cast<const uint8_t *>(oldmsg.ExtraDataPtr);
|
||||
else
|
||||
frame.data = oldmsg.Data;
|
||||
};
|
||||
|
||||
switch(oldmsg.Protocol)
|
||||
{
|
||||
case SPY_PROTOCOL_ETHERNET:
|
||||
{
|
||||
frame.length = ((oldmsg.NumberBytesHeader & 255) << 8) | (oldmsg.NumberBytesData & 255);
|
||||
copyFrameDataPtr();
|
||||
break;
|
||||
}
|
||||
case SPY_PROTOCOL_LIN:
|
||||
{
|
||||
neomessage_lin_t& linFrame = *reinterpret_cast<neomessage_lin_t*>(&frame);
|
||||
const uint8_t numberBytesHeader = std::min(oldmsg.NumberBytesHeader, static_cast<uint8_t>(3));
|
||||
const uint8_t numberBytesData = std::min(oldmsg.NumberBytesData, static_cast<uint8_t>(7));
|
||||
frame.length = numberBytesHeader + numberBytesData;
|
||||
linFrame.type = ICSNEO_NETWORK_TYPE_LIN;
|
||||
if (oldmsg.StatusBitField & SPY_STATUS_INIT_MESSAGE)
|
||||
linFrame.linStatus.txCommander = true;
|
||||
else
|
||||
linFrame.linStatus.txResponder = true;
|
||||
|
||||
copyFrameDataPtr();
|
||||
if (frame.length > 2) {
|
||||
size_t checksum = 0;
|
||||
uint8_t* lastByte = nullptr;
|
||||
for(size_t idx = 1; idx < (frame.length - 1); ++idx) {
|
||||
if (idx < oldmsg.NumberBytesHeader) {
|
||||
checksum += frame.header[idx];
|
||||
lastByte = (frame.header + idx + 1);
|
||||
} else {
|
||||
checksum += frame.data[idx-numberBytesHeader];
|
||||
lastByte = const_cast<uint8_t*>(frame.data) + idx - numberBytesHeader + 1;
|
||||
}
|
||||
if (checksum > 255) { checksum -= 255; }
|
||||
}
|
||||
size_t enhanced = frame.header[0] + checksum;
|
||||
if (enhanced > 255) { enhanced -= 255; }
|
||||
checksum ^= 0xff;
|
||||
enhanced ^= 0xff;
|
||||
|
||||
if ((lastByte != nullptr) && (*lastByte != checksum) && (*lastByte == enhanced))
|
||||
linFrame.linStatus.txChecksumEnhanced = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPY_PROTOCOL_CANFD:
|
||||
{
|
||||
frame.status.canfdFDF = true;
|
||||
copyFrameDataPtr();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
frame.length = oldmsg.NumberBytesData;
|
||||
copyFrameDataPtr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool Within(size_t value, size_t min, size_t max)
|
||||
{
|
||||
return ((min <= value) && (value < max));
|
||||
|
|
@ -396,25 +507,9 @@ int LegacyDLLExport icsneoTxMessagesEx(void* hObject, icsSpyMessage* pMsg, unsig
|
|||
*NumTxed = 0;
|
||||
for (unsigned int i = 0; i < lNumMessages; i++)
|
||||
{
|
||||
const icsSpyMessage& oldmsg = pMsg[i];
|
||||
newmsg = {};
|
||||
newmsg.netid = (uint16_t)lNetworkID;
|
||||
newmsg.description = oldmsg.DescriptionID;
|
||||
memcpy(newmsg.header, &oldmsg.ArbIDOrHeader, sizeof(newmsg.header));
|
||||
if (oldmsg.Protocol != SPY_PROTOCOL_ETHERNET)
|
||||
newmsg.length = oldmsg.NumberBytesData;
|
||||
else
|
||||
newmsg.length = ((oldmsg.NumberBytesHeader & 255) << 8) | (oldmsg.NumberBytesData & 255);
|
||||
if (oldmsg.ExtraDataPtr != nullptr && oldmsg.ExtraDataPtrEnabled == 1)
|
||||
newmsg.data = reinterpret_cast<const uint8_t *>(oldmsg.ExtraDataPtr);
|
||||
else
|
||||
newmsg.data = oldmsg.Data;
|
||||
newmsg.status.statusBitfield[0] = oldmsg.StatusBitField;
|
||||
newmsg.status.statusBitfield[1] = oldmsg.StatusBitField2;
|
||||
newmsg.status.statusBitfield[2] = oldmsg.StatusBitField3;
|
||||
newmsg.status.statusBitfield[3] = oldmsg.StatusBitField4;
|
||||
if (oldmsg.Protocol == SPY_PROTOCOL_CANFD)
|
||||
newmsg.status.canfdFDF = true;
|
||||
const icsSpyMessage& oldMsg = pMsg[i];
|
||||
SpyMessageToNeoMessage(oldMsg, newmsg, lNetworkID);
|
||||
if (icsneo_transmit(device, reinterpret_cast<neomessage_t*>(&newmsg)))
|
||||
(*NumTxed)++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,4 +19,12 @@ void LINMessage::calcChecksum(LINMessage& message) {
|
|||
message.checksum ^= 0xFFu;
|
||||
}
|
||||
|
||||
uint8_t LINMessage::calcProtectedID(uint8_t& id) {
|
||||
uint8_t protID = id;
|
||||
auto bit = [&](uint8_t pos)->uint8_t { return ((protID >> pos) & 0x1u); };
|
||||
protID |= (~(bit(1) ^ bit(3) ^ bit(4) ^ bit(5)) << 7);
|
||||
protID |= ((bit(0) ^ bit(1) ^ bit(2) ^ bit(4)) << 6);
|
||||
return protID;
|
||||
}
|
||||
|
||||
} //namespace icsneo
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#include "icsneo/communication/message/canmessage.h"
|
||||
#include "icsneo/communication/message/ethernetmessage.h"
|
||||
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||
#include "icsneo/communication/message/linmessage.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
|
|||
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
|
||||
auto framemsg = std::static_pointer_cast<Frame>(message);
|
||||
const auto netType = framemsg->network.getType();
|
||||
|
||||
frame.netid = (neonetid_t)framemsg->network.getNetID();
|
||||
frame.type = (neonettype_t)netType;
|
||||
frame.description = framemsg->description;
|
||||
|
|
@ -53,6 +55,47 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
|
|||
//eth.status.xyz = ethmsg->noPadding;
|
||||
break;
|
||||
}
|
||||
case Network::Type::LIN: {
|
||||
neomessage_lin_t& lin = *(neomessage_lin_t*)&neomsg;
|
||||
auto linmsg = std::static_pointer_cast<LINMessage>(message);
|
||||
if(!linmsg) { break; }
|
||||
const auto linHdrBytes = std::min(linmsg->data.size(), static_cast<size_t>(2));
|
||||
lin.header[0] = linmsg->protectedID;
|
||||
std::copy(linmsg->data.begin(), linmsg->data.begin() + linHdrBytes, lin.header + 1);
|
||||
linmsg->calcChecksum(*linmsg);
|
||||
lin.checksum = linmsg->checksum;
|
||||
lin.data = linmsg->data.data() + linHdrBytes;
|
||||
if(linmsg->isEnhancedChecksum != linmsg->statusFlags.TxChecksumEnhanced) {
|
||||
linmsg->isEnhancedChecksum = true;
|
||||
linmsg->statusFlags.TxChecksumEnhanced = true;
|
||||
}
|
||||
if(linmsg->data.size())
|
||||
lin.length = linmsg->data.size() + 2;
|
||||
else
|
||||
lin.length = 1;
|
||||
|
||||
lin.linStatus = {
|
||||
linmsg->statusFlags.TxChecksumEnhanced,
|
||||
linmsg->statusFlags.TxCommander,
|
||||
linmsg->statusFlags.TxResponder,
|
||||
linmsg->statusFlags.UpdateResponderOnce,
|
||||
linmsg->statusFlags.HasUpdatedResponderOnce,
|
||||
linmsg->statusFlags.BusRecovered,
|
||||
linmsg->statusFlags.BreakOnly
|
||||
};
|
||||
|
||||
lin.status.linJustBreakSync = linmsg->errFlags.ErrRxBreakSyncOnly;
|
||||
lin.status.linErrorTXRXMismatch = linmsg->errFlags.ErrTxRxMismatch;
|
||||
lin.status.linErrorRXBreakNotZero = linmsg->errFlags.ErrRxBreakNotZero;
|
||||
lin.status.linErrorRXBreakTooShort = linmsg->errFlags.ErrRxBreakTooShort;
|
||||
lin.status.linErrorRXSyncNot55 = linmsg->errFlags.ErrRxSyncNot55;
|
||||
lin.status.linErrorRXDataGreaterEight = linmsg->errFlags.ErrRxDataLenOver8;
|
||||
lin.status.linSyncFrameError = linmsg->errFlags.ErrFrameSync;
|
||||
lin.status.linIDFrameError = linmsg->errFlags.ErrFrameMessageID;
|
||||
lin.status.linSlaveByteError = linmsg->errFlags.ErrFrameResponderData;
|
||||
lin.status.checksumError = linmsg->errFlags.ErrChecksumMatch;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO Implement others
|
||||
break;
|
||||
|
|
@ -105,6 +148,53 @@ std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t*
|
|||
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
|
||||
return ethmsg;
|
||||
}
|
||||
case Network::Type::LIN: {
|
||||
neomessage_lin_t& lin = *(neomessage_lin_t*)neomessage;
|
||||
auto linmsg = std::make_shared<LINMessage>();
|
||||
linmsg->network = network;
|
||||
linmsg->description = lin.description;
|
||||
linmsg->protectedID = lin.header[0];
|
||||
linmsg->ID = linmsg->protectedID & 0x3F;
|
||||
linmsg->statusFlags = {
|
||||
static_cast<bool>(lin.linStatus.txChecksumEnhanced),
|
||||
static_cast<bool>(lin.linStatus.txCommander),
|
||||
static_cast<bool>(lin.linStatus.txResponder),
|
||||
static_cast<bool>(lin.linStatus.updateResponderOnce),
|
||||
static_cast<bool>(lin.linStatus.hasUpdatedResponderOnce),
|
||||
static_cast<bool>(lin.linStatus.busRecovered),
|
||||
static_cast<bool>(lin.linStatus.breakOnly)
|
||||
};
|
||||
linmsg->isEnhancedChecksum = linmsg->statusFlags.TxChecksumEnhanced;
|
||||
linmsg->errFlags = {
|
||||
static_cast<bool>(lin.linStatus.breakOnly),
|
||||
static_cast<bool>(lin.status.linJustBreakSync),
|
||||
static_cast<bool>(lin.status.linErrorTXRXMismatch),
|
||||
static_cast<bool>(lin.status.linErrorRXBreakNotZero),
|
||||
static_cast<bool>(lin.status.linErrorRXBreakTooShort),
|
||||
static_cast<bool>(lin.status.linErrorRXSyncNot55),
|
||||
static_cast<bool>(lin.status.linErrorRXDataGreaterEight),
|
||||
static_cast<bool>(lin.status.linSyncFrameError),
|
||||
static_cast<bool>(lin.status.linIDFrameError),
|
||||
static_cast<bool>(lin.status.linSlaveByteError),
|
||||
static_cast<bool>(lin.status.checksumError)
|
||||
};
|
||||
if(lin.length > 1) {
|
||||
auto numHeaderBytes = std::min(lin.length, static_cast<size_t>(3));
|
||||
linmsg->data.insert(linmsg->data.end(), (lin.header + 1), (lin.header + numHeaderBytes));
|
||||
linmsg->data.insert(linmsg->data.end(), lin.data, (lin.data + (lin.length - numHeaderBytes)));
|
||||
linmsg->checksum = linmsg->data.back();
|
||||
linmsg->data.pop_back();
|
||||
}
|
||||
if (linmsg->statusFlags.TxCommander) {
|
||||
if (linmsg->data.size())
|
||||
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
else
|
||||
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
|
||||
} else if (linmsg->statusFlags.TxResponder) {
|
||||
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
}
|
||||
return linmsg;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
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);
|
||||
|
|
@ -17,14 +16,13 @@ std::shared_ptr<Message> HardwareLINPacket::DecodeToMessage(const std::vector<ui
|
|||
if(numDataBytes)
|
||||
--numDataBytes; //If data is present, there will be a checksum included
|
||||
|
||||
auto msg = std::make_shared<LINMessage>(static_cast<uint8_t>(packet->CoreMiniBitsLIN.ID));
|
||||
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;
|
||||
msg->linMsgType = LINMessage::Type::LIN_ERROR;
|
||||
|
||||
auto dataStart = bytestream.begin() + numHeaderBytes;
|
||||
std::copy(dataStart, (dataStart+numDataBytes), std::back_inserter(msg->data));
|
||||
|
|
@ -78,16 +76,16 @@ std::shared_ptr<Message> HardwareLINPacket::DecodeToMessage(const std::vector<ui
|
|||
static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly)
|
||||
};
|
||||
if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder)
|
||||
msg->type = LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
else if(msg->statusFlags.BreakOnly)
|
||||
msg->type = LINMessage::Type::LIN_BREAK_ONLY;
|
||||
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->type = LINMessage::Type::LIN_ERROR; }
|
||||
{ msg->linMsgType = LINMessage::Type::LIN_ERROR; }
|
||||
|
||||
msg->timestamp = packet->timestamp;
|
||||
return msg;
|
||||
|
|
@ -97,7 +95,7 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
|
|||
{
|
||||
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) {
|
||||
switch(message.linMsgType) {
|
||||
case LINMessage::Type::LIN_HEADER_ONLY:
|
||||
case LINMessage::Type::LIN_COMMANDER_MSG:
|
||||
{
|
||||
|
|
@ -117,12 +115,7 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
|
|||
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);
|
||||
|
||||
message.calcProtectedID(message.ID);
|
||||
bytestream.insert(bytestream.end(),
|
||||
{
|
||||
static_cast<uint8_t>(0x00u),
|
||||
|
|
@ -132,7 +125,7 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
|
|||
static_cast<uint8_t>(message.protectedID)
|
||||
});
|
||||
|
||||
switch(message.type) {
|
||||
switch(message.linMsgType) {
|
||||
case(LINMessage::Type::LIN_COMMANDER_MSG):
|
||||
case(LINMessage::Type::LIN_UPDATE_RESPONDER):
|
||||
{
|
||||
|
|
@ -144,6 +137,7 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytestream.size() % 2)
|
||||
bytestream.push_back(0x41); //padding
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
option(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE "Build the command-line interactive C example." ON)
|
||||
option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
|
||||
option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
|
||||
|
|
@ -11,6 +13,14 @@ if(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE)
|
|||
add_subdirectory(c/interactive)
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE)
|
||||
add_subdirectory(c/simple)
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE)
|
||||
add_subdirectory(c/legacy)
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
|
||||
add_subdirectory(cpp/simple)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ add_executable(libicsneoc-interactive-example src/main.c)
|
|||
if(UNIX)
|
||||
target_link_libraries(libicsneoc-interactive-example ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
target_link_libraries(libicsneoc-interactive-example icsneoc)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Signal to dynamically load the library
|
||||
#define ICSNEOC_DYNAMICLOAD
|
||||
//#define ICSNEOC_DYNAMICLOAD
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -219,21 +219,21 @@ int main() {
|
|||
|
||||
// Attempt to initialize the library and access its functions
|
||||
// This call searches for icsneoc.dll according to the standard dynamic-link library search order
|
||||
int ret = icsneo_init();
|
||||
if(ret == 1) {
|
||||
printf("The library was already initialized!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(ret == 2) {
|
||||
printf("The library could not be found!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(ret == 3) {
|
||||
printf("The library is missing functions!\n");
|
||||
return ret;
|
||||
}
|
||||
//int ret = icsneo_init();
|
||||
//if(ret == 1) {
|
||||
// printf("The library was already initialized!\n");
|
||||
// return ret;
|
||||
//}
|
||||
//
|
||||
//if(ret == 2) {
|
||||
// printf("The library could not be found!\n");
|
||||
// return ret;
|
||||
//}
|
||||
//
|
||||
//if(ret == 3) {
|
||||
// printf("The library is missing functions!\n");
|
||||
// return ret;
|
||||
//}
|
||||
|
||||
neoversion_t ver = icsneo_getVersion();
|
||||
printf("ICS icsneoc.dll version %u.%u.%u\n\n", ver.major, ver.minor, ver.patch);
|
||||
|
|
@ -487,6 +487,31 @@ int main() {
|
|||
printf("(%"PRIu64")\n", canMsg->timestamp);
|
||||
break;
|
||||
}
|
||||
case ICSNEO_NETWORK_TYPE_LIN: {
|
||||
neomessage_lin_t* linMsg = (neomessage_lin_t*)frame;
|
||||
size_t frameLen = linMsg->length;
|
||||
size_t dataLen = (frameLen > 2) ? (frameLen - 2) : 0;
|
||||
size_t numberBytesHeader = (dataLen > 1) ? 3 : 1;
|
||||
size_t numberBytesData = frameLen - numberBytesHeader;
|
||||
if(linMsg->netid == ICSNEO_NETID_LIN) {
|
||||
printf("LIN 1 | ID: 0x%02x [%zu] ", linMsg->header[0], dataLen);
|
||||
}
|
||||
else if (linMsg->netid == ICSNEO_NETID_LIN2) {
|
||||
printf("LIN 2 | ID: 0x%02x [%zu] ", linMsg->header[0], dataLen);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < dataLen; ++i) {
|
||||
if (i < 2) {
|
||||
printf("%02x ", linMsg->header[i+1]);
|
||||
} else {
|
||||
printf("%02x ", linMsg->data[i-2]);
|
||||
}
|
||||
}
|
||||
if(numberBytesData > 0)
|
||||
printf("| Checksum: 0x%02x\n", linMsg->data[numberBytesData-1]);
|
||||
else
|
||||
printf("| Checksum: 0x%02x\n", linMsg->header[numberBytesHeader-1]);
|
||||
}
|
||||
default:
|
||||
printf("\tMessage on netid %d with length %zu\n", frame->netid, frame->length);
|
||||
break;
|
||||
|
|
@ -762,7 +787,7 @@ int main() {
|
|||
case 'X':
|
||||
case 'x':
|
||||
printf("Exiting program\n");
|
||||
return !icsneo_close();
|
||||
return 0;
|
||||
default:
|
||||
printf("Unexpected input, exiting!\n");
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneoc-legacy-lin-example VERSION 0.2.0)
|
||||
|
||||
add_executable(libicsneoc-legacy-lin-example lin/main.c)
|
||||
target_link_libraries(libicsneoc-legacy-lin-example icsneolegacy)
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
# libicsneo C Example
|
||||
|
||||
This is an example console application that uses the icsneoc library to control an Intrepid Control Systems hardware device.
|
||||
|
||||
## Cloning
|
||||
|
||||
This will create a copy of the repository on your local machine.
|
||||
|
||||
Run:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/intrepidcs/libicsneo-examples -b v0.2.0-dev --recursive
|
||||
```
|
||||
|
||||
Alternatively, if you cloned without the `--recursive` flag, you must enter the `libicsneo-examples` folder and run the following:
|
||||
|
||||
```shell
|
||||
git submodule update --recursive --init
|
||||
```
|
||||
|
||||
If you haven't done this, `third-party/libicsneo` will be empty and you won't be able to build!
|
||||
|
||||
## Windows using Visual Studio 2017+
|
||||
|
||||
### Building the DLL
|
||||
|
||||
First, we are going to build the icsneoc library into a .dll file that we can later use in order to access the library functions.
|
||||
|
||||
1. Launch Visual Studio and open the `libicsneo-examples` folder.
|
||||
2. Choose `File->Open->Cmake...`
|
||||
3. Navigate to `third-party/libicsneo` and select the `CMakeLists.txt` there.
|
||||
4. Visual Studio will process the CMake project.
|
||||
5. Select `Build->Rebuild All`
|
||||
6. Visual Studio will generate the `icsneoc.dll` file, which can then be found by selecting `Project->Cmake Cache (x64-Debug Only)->Open in Explorer`. If the file cannot be found, search in `libicsneo-examples/third-party/libicsneo/out/build/x64-Debug` and double-check that the build succeeded in step 5.
|
||||
7. Move the `icsneoc.dll` file to the `/C/Windows/System32` folder. This will allow it to be found by icsneo_init(), which loads all the library functions.
|
||||
* Alternatively, the `icsneoc.dll` file can be placed in the same directory as `libicsneoc-example.exe`, which is typically `libicsneo-examples/libicsneoc-example/out/build/x64-Debug`, although this is not recommended. For more information, refer to [the Microsoft documentation](https://docs.microsoft.com/en-us/windows/desktop/dlls/dynamic-link-library-search-order).
|
||||
|
||||
### Building the example program
|
||||
|
||||
Although the example program will build without successfully completing the steps above, it will exit immediately upon running due to a failure to load any library functions.
|
||||
|
||||
1. Choose `File->Open->Cmake...`
|
||||
2. Navigate to `libicsneo-examples/libicsneoc-example` and select the `CMakeLists.txt` there.
|
||||
3. Visual Studio will process the CMake project.
|
||||
4. Select `Build->Rebuild All`
|
||||
5. Click on the dropdown arrow attached to the green play button (labelled "Select Startup Item") and select `libicsneoc-example.exe`
|
||||
6. Click on the green play button to run the example.
|
||||
|
||||
## Ubuntu 18.04 LTS
|
||||
|
||||
### Building the .so
|
||||
|
||||
First, we are going to build the icsneoc library into a .so file that we can later use in order to access the library functions.
|
||||
|
||||
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
|
||||
2. Change directories to `libicsneo-examples/third-party/libicsneo` and create a build directory by running `mkdir -p build`
|
||||
3. Enter the build directory with `cd build`
|
||||
4. Run `cmake ..` to generate your Makefile.
|
||||
* Hint! Running `cmake -DCMAKE_BUILD_TYPE=Debug ..` will generate the proper scripts to build debug, and `cmake -DCMAKE_BUILD_TYPE=Release ..` will generate the proper scripts to build with all optimizations on.
|
||||
5. Run `make` to build the library.
|
||||
* Hint! Speed up your build by using multiple processors! Use `make -j#` where `#` is the number of cores/threads your system has plus one. For instance, on a standard 8 thread Intel i7, you might use `-j9` for an ~8x speedup.
|
||||
6. Run `sudo cp libicsneoc.so /usr/lib` so that it can be found via the default ubuntu .so search path. For more information, see the [ld.so.8 man page](http://man7.org/linux/man-pages/man8/ld.so.8.html).
|
||||
|
||||
### Building the example program
|
||||
|
||||
Although the example program will build without successfully completing the steps above, it will exit immediately upon running due to a failure to load any library functions.
|
||||
|
||||
1. Change directories to `libicsneo-examples/libicsneoc-example`
|
||||
2. Create a build directory by running `mkdir -p build`
|
||||
3. Enter the build directory with `cd build`
|
||||
4. Run `cmake ..` to generate your Makefile.
|
||||
* Hint! Running `cmake -DCMAKE_BUILD_TYPE=Debug ..` will generate the proper scripts to build debug, and `cmake -DCMAKE_BUILD_TYPE=Release ..` will generate the proper scripts to build with all optimizations on.
|
||||
5. Run `make` to build the library.
|
||||
* Hint! Speed up your build by using multiple processors! Use `make -j#` where `#` is the number of cores/threads your system has plus one. For instance, on a standard 8 thread Intel i7, you might use `-j9` for an ~8x speedup.
|
||||
6. Run `sudo ./libicsneoc-example` to run the example.
|
||||
* Hint! In order to run without sudo, you will need to set up the udev rules. Copy `libicsneo-examples/third-party/libicsneo/99-intrepidcs.rules` to `/etc/udev/rules.d`, then run `udevadm control --reload-rules && udevadm trigger` afterwards. While the program will still run without setting up these rules, it will fail to open any devices.
|
||||
|
||||
## macOS
|
||||
|
||||
Instructions coming soon™
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined _WIN32
|
||||
#include "icsneo/platform/windows.h"
|
||||
#define SLEEP(msecs) Sleep(msecs)
|
||||
#elif defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
|
||||
#include <time.h>
|
||||
#define SLEEP(msecs) do { \
|
||||
struct timespec ts; \
|
||||
ts.tv_sec = msecs/1000; \
|
||||
ts.tv_nsec = msecs%1000*1000; \
|
||||
nanosleep(&ts, NULL); \
|
||||
} while (0)
|
||||
#else
|
||||
#error "Platform unknown"
|
||||
#endif
|
||||
|
||||
// Get the PRIu64 macro for timestamps
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
// Include icsneo/icsneolegacy.h to access library functions
|
||||
#include "icsneo/icsneolegacy.h"
|
||||
|
||||
int main() {
|
||||
int ver = icsneoGetDLLVersion();
|
||||
printf("ICS icsneolegacy.dll version %u\n\n", ver);
|
||||
// Find and attempt to open device
|
||||
//legacy open device
|
||||
int numDevices = 10;
|
||||
NeoDevice devices[10];
|
||||
void* hObject; // holds a handle to the neoVI object
|
||||
int iRetVal = 0;
|
||||
int deviceTypes = 0;
|
||||
int iResult = 0;
|
||||
|
||||
iRetVal = icsneoFindNeoDevices(deviceTypes, devices, &numDevices);
|
||||
if(iRetVal) {
|
||||
// Attempt to open the selected device, enable message polling, and go online
|
||||
iRetVal = icsneoOpenNeoDevice(&devices[0], &hObject, NULL, 1, 0);
|
||||
if(iRetVal) {
|
||||
printf("Device found and opened!\n");
|
||||
} else {
|
||||
printf("Device found but failed to open!\n");
|
||||
}
|
||||
} else {
|
||||
printf("No new devices found!\n");
|
||||
}
|
||||
|
||||
// Send message LIN
|
||||
{
|
||||
//lin responder frame
|
||||
icsSpyMessageJ1850 msg1 = {0};
|
||||
int lNetworkID;
|
||||
msg1.Protocol = SPY_PROTOCOL_LIN;
|
||||
msg1.StatusBitField = 0;
|
||||
msg1.StatusBitField2 = 0;
|
||||
lNetworkID = NETID_LIN2;
|
||||
msg1.Header[0] = 0x11; //protected ID
|
||||
msg1.Header[1] = 0xaa;
|
||||
msg1.Header[2] = 0xbb;
|
||||
msg1.Data[0] = 0xcc;
|
||||
msg1.Data[1] = 0xdd;
|
||||
msg1.Data[2] = 0x11;
|
||||
msg1.Data[3] = 0x22;
|
||||
msg1.Data[4] = 0x33;
|
||||
msg1.Data[5] = 0x44;
|
||||
msg1.Data[6] = 0x44; //checksum 0x33 enhanced
|
||||
msg1.NumberBytesData = 7;
|
||||
msg1.NumberBytesHeader = 3;
|
||||
iRetVal = icsneoTxMessages(hObject, (icsSpyMessage*)&msg1, lNetworkID, 1);
|
||||
if(!iRetVal)
|
||||
printf("Device failed to transmit LIN responder update\n");
|
||||
else
|
||||
printf("Transmitted successfully!\n");
|
||||
|
||||
icsSpyMessageJ1850 msg2 = {0};
|
||||
msg2.Protocol = SPY_PROTOCOL_LIN;
|
||||
msg2.StatusBitField = SPY_STATUS_INIT_MESSAGE;
|
||||
lNetworkID = NETID_LIN;
|
||||
msg2.Header[0] = 0x11; //protected ID
|
||||
msg2.NumberBytesData = 0;
|
||||
msg2.NumberBytesHeader = 1;
|
||||
iRetVal = icsneoTxMessages(hObject, (icsSpyMessage*)&msg2, lNetworkID, 1);
|
||||
if(!iRetVal)
|
||||
printf("Device failed to transmit LIN commander header\n");
|
||||
else
|
||||
printf("Transmitted successfully!\n");
|
||||
|
||||
SLEEP(250);
|
||||
|
||||
icsSpyMessageJ1850 msg3 = {0};
|
||||
msg3.Protocol = SPY_PROTOCOL_LIN;
|
||||
msg3.StatusBitField = SPY_STATUS_INIT_MESSAGE;
|
||||
msg3.StatusBitField2 = 0;
|
||||
lNetworkID = NETID_LIN;
|
||||
msg3.Header[0] = 0xe2; //protected ID
|
||||
msg3.Header[1] = 0x44;
|
||||
msg3.Header[2] = 0x33;
|
||||
msg3.Data[0] = 0x22;
|
||||
msg3.Data[1] = 0x11;
|
||||
msg3.Data[2] = 0x11;
|
||||
msg3.Data[3] = 0x22;
|
||||
msg3.Data[4] = 0x33;
|
||||
msg3.Data[5] = 0x44;
|
||||
msg3.Data[6] = 0xc7; //checksum
|
||||
msg3.NumberBytesData = 7;
|
||||
msg3.NumberBytesHeader = 3;
|
||||
iRetVal = icsneoTxMessages(hObject, (icsSpyMessage*)&msg3, lNetworkID, 1);
|
||||
if(!iRetVal)
|
||||
printf("Device failed to transmit LIN commander message\n");
|
||||
else
|
||||
printf("Transmitted successfully!\n");
|
||||
}
|
||||
SLEEP(1000);
|
||||
// Get messages
|
||||
{
|
||||
static icsSpyMessage rxMsg[30000];
|
||||
int numMessages = 0;
|
||||
int numErrors = 0;
|
||||
iRetVal = icsneoGetMessages(hObject, rxMsg, &numMessages, &numErrors);
|
||||
if(!iRetVal)
|
||||
printf("Get Messages failed!\n");
|
||||
else
|
||||
for(int idx = 0; idx < numMessages; ++idx)
|
||||
{
|
||||
if(rxMsg[idx].Protocol == SPY_PROTOCOL_LIN) {
|
||||
const icsSpyMessageJ1850* linMsg = (icsSpyMessageJ1850*)&rxMsg[idx];
|
||||
size_t frameLen = (linMsg->NumberBytesHeader + linMsg->NumberBytesData);
|
||||
size_t dataLen = (frameLen > 2) ? (frameLen - 2) : 0;
|
||||
if(linMsg->NetworkID == NETID_LIN) {
|
||||
printf("LIN 1 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen);
|
||||
}
|
||||
else if (linMsg->NetworkID == NETID_LIN2) {
|
||||
printf("LIN 2 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < dataLen; ++i) {
|
||||
if (i < 2) {
|
||||
printf("%02x ", linMsg->Header[i+1]);
|
||||
} else {
|
||||
printf("%02x ", linMsg->Data[i-2]);
|
||||
}
|
||||
}
|
||||
if(linMsg->NumberBytesData > 0)
|
||||
printf("| Checksum: 0x%02x\n", linMsg->Data[linMsg->NumberBytesData-1]);
|
||||
else
|
||||
printf("| Checksum: 0x%02x\n", linMsg->Header[linMsg->NumberBytesHeader-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int iNumberOfErrors = 0;
|
||||
// Attempt to close the device
|
||||
{
|
||||
// Close Communication
|
||||
iResult = icsneoClosePort(hObject, &iNumberOfErrors);
|
||||
}
|
||||
printf("Exiting program\n");
|
||||
return iResult;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneoc-simple-lin-example VERSION 0.2.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Include libicsneo's include directory
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
|
||||
|
||||
if(UNIX)
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS)
|
||||
endif()
|
||||
|
||||
add_executable(libicsneoc-simple-lin-example lin/main.c)
|
||||
if(UNIX)
|
||||
target_link_libraries(libicsneoc-simple-lin-example ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
target_link_libraries(libicsneoc-simple-lin-example icsneoc)
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
# libicsneo C Example
|
||||
|
||||
This is an example console application that uses the icsneoc library to control an Intrepid Control Systems hardware device.
|
||||
|
||||
## Cloning
|
||||
|
||||
This will create a copy of the repository on your local machine.
|
||||
|
||||
Run:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/intrepidcs/libicsneo-examples -b v0.2.0-dev --recursive
|
||||
```
|
||||
|
||||
Alternatively, if you cloned without the `--recursive` flag, you must enter the `libicsneo-examples` folder and run the following:
|
||||
|
||||
```shell
|
||||
git submodule update --recursive --init
|
||||
```
|
||||
|
||||
If you haven't done this, `third-party/libicsneo` will be empty and you won't be able to build!
|
||||
|
||||
## Windows using Visual Studio 2017+
|
||||
|
||||
### Building the DLL
|
||||
|
||||
First, we are going to build the icsneoc library into a .dll file that we can later use in order to access the library functions.
|
||||
|
||||
1. Launch Visual Studio and open the `libicsneo-examples` folder.
|
||||
2. Choose `File->Open->Cmake...`
|
||||
3. Navigate to `third-party/libicsneo` and select the `CMakeLists.txt` there.
|
||||
4. Visual Studio will process the CMake project.
|
||||
5. Select `Build->Rebuild All`
|
||||
6. Visual Studio will generate the `icsneoc.dll` file, which can then be found by selecting `Project->Cmake Cache (x64-Debug Only)->Open in Explorer`. If the file cannot be found, search in `libicsneo-examples/third-party/libicsneo/out/build/x64-Debug` and double-check that the build succeeded in step 5.
|
||||
7. Move the `icsneoc.dll` file to the `/C/Windows/System32` folder. This will allow it to be found by icsneo_init(), which loads all the library functions.
|
||||
* Alternatively, the `icsneoc.dll` file can be placed in the same directory as `libicsneoc-example.exe`, which is typically `libicsneo-examples/libicsneoc-example/out/build/x64-Debug`, although this is not recommended. For more information, refer to [the Microsoft documentation](https://docs.microsoft.com/en-us/windows/desktop/dlls/dynamic-link-library-search-order).
|
||||
|
||||
### Building the example program
|
||||
|
||||
Although the example program will build without successfully completing the steps above, it will exit immediately upon running due to a failure to load any library functions.
|
||||
|
||||
1. Choose `File->Open->Cmake...`
|
||||
2. Navigate to `libicsneo-examples/libicsneoc-example` and select the `CMakeLists.txt` there.
|
||||
3. Visual Studio will process the CMake project.
|
||||
4. Select `Build->Rebuild All`
|
||||
5. Click on the dropdown arrow attached to the green play button (labelled "Select Startup Item") and select `libicsneoc-example.exe`
|
||||
6. Click on the green play button to run the example.
|
||||
|
||||
## Ubuntu 18.04 LTS
|
||||
|
||||
### Building the .so
|
||||
|
||||
First, we are going to build the icsneoc library into a .so file that we can later use in order to access the library functions.
|
||||
|
||||
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
|
||||
2. Change directories to `libicsneo-examples/third-party/libicsneo` and create a build directory by running `mkdir -p build`
|
||||
3. Enter the build directory with `cd build`
|
||||
4. Run `cmake ..` to generate your Makefile.
|
||||
* Hint! Running `cmake -DCMAKE_BUILD_TYPE=Debug ..` will generate the proper scripts to build debug, and `cmake -DCMAKE_BUILD_TYPE=Release ..` will generate the proper scripts to build with all optimizations on.
|
||||
5. Run `make` to build the library.
|
||||
* Hint! Speed up your build by using multiple processors! Use `make -j#` where `#` is the number of cores/threads your system has plus one. For instance, on a standard 8 thread Intel i7, you might use `-j9` for an ~8x speedup.
|
||||
6. Run `sudo cp libicsneoc.so /usr/lib` so that it can be found via the default ubuntu .so search path. For more information, see the [ld.so.8 man page](http://man7.org/linux/man-pages/man8/ld.so.8.html).
|
||||
|
||||
### Building the example program
|
||||
|
||||
Although the example program will build without successfully completing the steps above, it will exit immediately upon running due to a failure to load any library functions.
|
||||
|
||||
1. Change directories to `libicsneo-examples/libicsneoc-example`
|
||||
2. Create a build directory by running `mkdir -p build`
|
||||
3. Enter the build directory with `cd build`
|
||||
4. Run `cmake ..` to generate your Makefile.
|
||||
* Hint! Running `cmake -DCMAKE_BUILD_TYPE=Debug ..` will generate the proper scripts to build debug, and `cmake -DCMAKE_BUILD_TYPE=Release ..` will generate the proper scripts to build with all optimizations on.
|
||||
5. Run `make` to build the library.
|
||||
* Hint! Speed up your build by using multiple processors! Use `make -j#` where `#` is the number of cores/threads your system has plus one. For instance, on a standard 8 thread Intel i7, you might use `-j9` for an ~8x speedup.
|
||||
6. Run `sudo ./libicsneoc-example` to run the example.
|
||||
* Hint! In order to run without sudo, you will need to set up the udev rules. Copy `libicsneo-examples/third-party/libicsneo/99-intrepidcs.rules` to `/etc/udev/rules.d`, then run `udevadm control --reload-rules && udevadm trigger` afterwards. While the program will still run without setting up these rules, it will fail to open any devices.
|
||||
|
||||
## macOS
|
||||
|
||||
Instructions coming soon™
|
||||
|
|
@ -0,0 +1,427 @@
|
|||
// Signal to dynamically load the library
|
||||
//#define ICSNEOC_DYNAMICLOAD
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// Get the PRIu64 macro for timestamps
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
// Include icsneo/icsneoc.h to access library functions
|
||||
#include "icsneo/icsneoc.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SLEEP(msecs) Sleep(msecs)
|
||||
#elif defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
|
||||
#include <time.h>
|
||||
#define SLEEP(msecs) do { \
|
||||
struct timespec ts; \
|
||||
ts.tv_sec = msecs/1000; \
|
||||
ts.tv_nsec = msecs%1000*1000; \
|
||||
nanosleep(&ts, NULL); \
|
||||
} while (0)
|
||||
#else
|
||||
#error "Platform unknown"
|
||||
#endif
|
||||
|
||||
size_t msgLimit = 50000;
|
||||
size_t numDevices = 0;
|
||||
neodevice_t devices[99];
|
||||
const neodevice_t* selectedDevice = NULL;
|
||||
|
||||
/**
|
||||
* \brief Prints all current known devices to output in the following format:
|
||||
* [num] DeviceType SerialNum Connected: Yes/No Online: Yes/No Msg Polling: On/Off
|
||||
*
|
||||
* If any devices could not be described due to an error, they will appear in the following format:
|
||||
* Description for device num not available!
|
||||
*/
|
||||
void printAllDevices() {
|
||||
if(numDevices == 0) {
|
||||
printf("No devices found! Please scan for new devices.\n");
|
||||
}
|
||||
for(size_t i = 0; i < numDevices; i++) {
|
||||
char productDescription[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION] = { 0 };
|
||||
size_t descriptionLength = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
|
||||
|
||||
// Updates productDescription and descriptionLength for each device
|
||||
if(icsneo_describeDevice(devices + i, productDescription, &descriptionLength)) {
|
||||
printf("[%zd] %s\tConnected: ", i + 1, productDescription);
|
||||
if(icsneo_isOpen(devices + i)) {
|
||||
printf("Yes\t");
|
||||
} else printf("No\t");
|
||||
|
||||
printf("Online: ");
|
||||
if(icsneo_isOnline(devices + i)) {
|
||||
printf("Yes\t");
|
||||
} else printf("No\t");
|
||||
|
||||
printf("Msg Polling: ");
|
||||
if(icsneo_isMessagePollingEnabled(devices + i)) {
|
||||
printf("On\n");
|
||||
} else printf("Off\n");
|
||||
|
||||
} else {
|
||||
printf("Description for device %zd not available!\n", i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Scans for any new devices, adding them to devices and updating numDevices accordingly
|
||||
* A total of 99 devices may be stored at once
|
||||
*/
|
||||
size_t scanNewDevices() {
|
||||
neodevice_t newDevices[99];
|
||||
size_t numNewDevices = 99;
|
||||
icsneo_findAllDevices(newDevices, &numNewDevices);
|
||||
|
||||
for(size_t i = 0; i < numNewDevices; ++i) {
|
||||
devices[numDevices + i] = newDevices[i];
|
||||
}
|
||||
numDevices += numNewDevices;
|
||||
return numNewDevices;
|
||||
}
|
||||
void printLastError() {
|
||||
neoevent_t error;
|
||||
if(icsneo_getLastError(&error))
|
||||
printf("Error 0x%u: %s\n", error.eventNumber, error.description);
|
||||
else
|
||||
printf("No errors found!\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Gets all current API events and prints them to output
|
||||
* Flushes the API event cache, meaning future calls (barring any new events) will not detect any further API events
|
||||
*/
|
||||
void printAPIEvents() {
|
||||
neoevent_t events[99];
|
||||
size_t eventCount = 99;
|
||||
if(icsneo_getEvents(events, &eventCount)) {
|
||||
if(eventCount == 1) {
|
||||
printf("1 API event found!\n");
|
||||
printf("Event 0x%u: %s\n", events[0].eventNumber, events[0].description);
|
||||
} else {
|
||||
printf("%d API events found!\n", (int) eventCount);
|
||||
for(size_t i = 0; i < eventCount; ++i) {
|
||||
printf("Event 0x%u: %s\n", events[i].eventNumber, events[i].description);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Failed to get API events!\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Gets all current device events and prints them to output. If no device events were found, printAPIEvents() is called
|
||||
* Flushes the device event cache, meaning future calls (barring any new events) will not detect any further device events for this device
|
||||
*/
|
||||
void printDeviceEvents(neodevice_t* device) {
|
||||
neoevent_t events[99];
|
||||
size_t eventCount = 99;
|
||||
if(icsneo_getDeviceEvents(selectedDevice, events, &eventCount)) {
|
||||
if(eventCount == 1) {
|
||||
printf("1 device event found!\n");
|
||||
printf("Event 0x%x: %s\n", events[0].eventNumber, events[0].description);
|
||||
} else {
|
||||
printf("%d device events found!\n", (int) eventCount);
|
||||
for(size_t i = 0; i < eventCount; ++i) {
|
||||
printf("Event 0x%x: %s\n", events[i].eventNumber, events[i].description);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Used to check character inputs for correctness (if they are found in an expected list)
|
||||
* \param[in] numArgs the number of possible options for the expected character
|
||||
* \param[in] ... the possible options for the expected character
|
||||
* \returns the entered character
|
||||
*
|
||||
* This function repeatedly prompts the user for input until a matching input is entered
|
||||
* Example usage: char input = getCharInput(5, 'F', 'u', 'b', 'a', 'r');
|
||||
*/
|
||||
char getCharInput(int numArgs, ...) {
|
||||
// 99 chars shold be more than enough to catch any typos
|
||||
char input[99];
|
||||
bool found = false;
|
||||
|
||||
va_list vaList;
|
||||
va_start(vaList, numArgs);
|
||||
|
||||
char* list = (char*) calloc(numArgs, sizeof(char));
|
||||
for(int i = 0; i < numArgs; ++i) {
|
||||
*(list + i) = va_arg(vaList, int);
|
||||
}
|
||||
|
||||
va_end(vaList);
|
||||
|
||||
while(!found) {
|
||||
fgets(input, 99, stdin);
|
||||
if(strlen(input) == 2) {
|
||||
for(int i = 0; i < numArgs; ++i) {
|
||||
if(input[0] == *(list + i)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
printf("Input did not match expected options. Please try again.\n");
|
||||
}
|
||||
}
|
||||
|
||||
free(list);
|
||||
|
||||
return input[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Prompts the user to select a device from the list of currently known devices
|
||||
* \returns a pointer to the device in devices[] selected by the user
|
||||
* Requires an input from 1-9, so a maximum of 9 devices are supported
|
||||
*/
|
||||
const neodevice_t* selectDevice() {
|
||||
printf("Please select a device:\n");
|
||||
printAllDevices();
|
||||
printf("\n");
|
||||
|
||||
size_t selectedDeviceNum = 10;
|
||||
|
||||
while(selectedDeviceNum > numDevices) {
|
||||
char deviceSelection = getCharInput(9, '1', '2', '3', '4', '5', '6', '7', '8', '9');
|
||||
if(deviceSelection < '0') {
|
||||
printf("Selected device out of range!\n");
|
||||
continue;
|
||||
}
|
||||
selectedDeviceNum = deviceSelection - '0';
|
||||
if(selectedDeviceNum > numDevices) {
|
||||
printf("Selected device out of range!\n");
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return devices + selectedDeviceNum - 1;
|
||||
}
|
||||
|
||||
int main() {
|
||||
neoversion_t ver = icsneo_getVersion();
|
||||
printf("ICS icsneoc version %u.%u.%u\n\n", ver.major, ver.minor, ver.patch);
|
||||
// Find and attempt to open device
|
||||
size_t numNewDevices = scanNewDevices();
|
||||
if(numNewDevices == 1) {
|
||||
printf("1 new device found!\n");
|
||||
} else {
|
||||
printf("%d new devices found!\n", (int) numNewDevices);
|
||||
}
|
||||
printAllDevices();
|
||||
printf("\n");
|
||||
|
||||
// Select a device and get its description
|
||||
if(numDevices == 0) {
|
||||
printf("No devices found! Please scan for new devices.\n\n");
|
||||
return 1;
|
||||
}
|
||||
selectedDevice = &devices[0];
|
||||
|
||||
// Get the product description for the device
|
||||
char productDescription[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION] = { 0 };
|
||||
size_t descriptionLength = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
|
||||
icsneo_describeDevice(selectedDevice, productDescription, &descriptionLength);
|
||||
|
||||
// Attempt to open the selected device
|
||||
{
|
||||
if(icsneo_openDevice(selectedDevice)) {
|
||||
printf("%s successfully opened!\n\n", productDescription);
|
||||
} else {
|
||||
printf("%s failed to open!\n\n", productDescription);
|
||||
printLastError();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
// Attempt to go online
|
||||
{
|
||||
if(icsneo_goOnline(selectedDevice)) {
|
||||
printf("%s successfully went online!\n\n", productDescription);
|
||||
} else {
|
||||
printf("%s failed to go online!\n\n", productDescription);
|
||||
printLastError();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
// Attempt to enable message polling
|
||||
{
|
||||
if(icsneo_enableMessagePolling(selectedDevice)) {
|
||||
printf("Successfully enabled message polling for %s!\n\n", productDescription);
|
||||
} else {
|
||||
printf("Failed to enable message polling for %s!\n\n", productDescription);
|
||||
printLastError();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
// Send message LIN
|
||||
{
|
||||
// Start generating sample msg
|
||||
uint8_t sendMessageData[8];
|
||||
sendMessageData[0] = 0x33;
|
||||
sendMessageData[1] = 0x44;
|
||||
sendMessageData[2] = 0x55;
|
||||
sendMessageData[3] = 0x66;
|
||||
sendMessageData[4] = 0x77;
|
||||
sendMessageData[5] = 0x88;
|
||||
sendMessageData[6] = 0x88;
|
||||
|
||||
neomessage_lin_t msg = {0};
|
||||
|
||||
msg.header[0] = 0x11; //protected ID
|
||||
msg.header[1] = 0x11;
|
||||
msg.header[2] = 0x22;
|
||||
msg.length = 10;
|
||||
msg.netid = ICSNEO_NETID_LIN;
|
||||
msg.data = sendMessageData;
|
||||
msg.linStatus.txCommander = 1;
|
||||
msg.linStatus.txChecksumEnhanced = 1;
|
||||
msg.type = ICSNEO_NETWORK_TYPE_LIN;
|
||||
msg.checksum = 0x88;
|
||||
|
||||
// Attempt to transmit the sample msg
|
||||
if(icsneo_transmit(selectedDevice, (const neomessage_t*) &msg)) {
|
||||
printf("Message transmit successful!\n\n");
|
||||
} else {
|
||||
printf("Failed to transmit message to %s!\n\n", productDescription);
|
||||
printLastError();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
// Wait for a moment
|
||||
SLEEP(1000);
|
||||
// Get messages
|
||||
{
|
||||
// Prepare the array of neomessage_t ptrs for reading in the messages
|
||||
neomessage_t* msgs = (neomessage_t*) malloc(msgLimit * sizeof(neomessage_t));
|
||||
|
||||
// Get messages
|
||||
size_t msgCount = msgLimit;
|
||||
|
||||
// Attempt to get messages
|
||||
if(!icsneo_getMessages(selectedDevice, msgs, &msgCount, (uint64_t) 0)) {
|
||||
printf("Failed to get messages for %s!\n\n", productDescription);
|
||||
printLastError();
|
||||
free(msgs);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if(msgCount == 1) {
|
||||
printf("1 message received from %s!\n", productDescription);
|
||||
} else {
|
||||
printf("%d messages received from %s!\n", (int) msgCount, productDescription);
|
||||
}
|
||||
|
||||
// Print out the received messages
|
||||
for(size_t i = 0; i < msgCount; i++) {
|
||||
const neomessage_t* msg = &msgs[i];
|
||||
switch(msg->messageType) {
|
||||
case ICSNEO_MESSAGE_TYPE_FRAME: {
|
||||
const neomessage_frame_t* frame = (neomessage_frame_t*)msg;
|
||||
switch(frame->type) {
|
||||
case ICSNEO_NETWORK_TYPE_CAN: {
|
||||
neomessage_can_t* canMsg = (neomessage_can_t*)frame;
|
||||
printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length);
|
||||
for(size_t i = 0; i < canMsg->length; i++) {
|
||||
printf("%02x ", canMsg->data[i]);
|
||||
}
|
||||
if(canMsg->status.transmitMessage)
|
||||
printf("TX%s %04x ", canMsg->status.globalError ? " ERR" : "", canMsg->description);
|
||||
printf("(%"PRIu64")\n", canMsg->timestamp);
|
||||
break;
|
||||
}
|
||||
case ICSNEO_NETWORK_TYPE_LIN: {
|
||||
neomessage_lin_t* linMsg = (neomessage_lin_t*)frame;
|
||||
size_t frameLen = linMsg->length;
|
||||
size_t dataLen = (frameLen > 2) ? (frameLen - 2) : 0;
|
||||
size_t numberBytesHeader = (dataLen > 1) ? 3 : 1;
|
||||
size_t numberBytesData = frameLen - numberBytesHeader;
|
||||
if(linMsg->netid == ICSNEO_NETID_LIN) {
|
||||
printf("LIN 1 | ID: 0x%02x [%zu] ", linMsg->header[0], dataLen);
|
||||
}
|
||||
else if (linMsg->netid == ICSNEO_NETID_LIN2) {
|
||||
printf("LIN 2 | ID: 0x%02x [%zu] ", linMsg->header[0], dataLen);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < dataLen; ++i) {
|
||||
if (i < 2) {
|
||||
printf("%02x ", linMsg->header[i+1]);
|
||||
} else {
|
||||
printf("%02x ", linMsg->data[i-2]);
|
||||
}
|
||||
}
|
||||
printf("| Checksum: 0x%02x\n", linMsg->checksum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICSNEO_MESSAGE_TYPE_CAN_ERROR_COUNT: {
|
||||
const neomessage_can_error_t* cec = (neomessage_can_error_t*)msg;
|
||||
printf("\tCAN error counts changed, TEC=%d, REC=%d%s", cec->transmitErrorCount, cec->receiveErrorCount,
|
||||
cec->status.canBusOff ? " (Bus Off)" : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
free(msgs);
|
||||
}
|
||||
// Attempt to disable message polling
|
||||
{
|
||||
if(icsneo_disableMessagePolling(selectedDevice)) {
|
||||
printf("Successfully disabled message polling for %s!\n\n", productDescription);
|
||||
} else {
|
||||
printf("Failed to disable message polling limit for %s!\n\n", productDescription);
|
||||
printLastError();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
// Attempt to go offline
|
||||
{
|
||||
if(icsneo_goOffline(selectedDevice)) {
|
||||
printf("%s successfully went offline!\n\n", productDescription);
|
||||
} else {
|
||||
printf("%s failed to go offline!\n\n", productDescription);
|
||||
printLastError();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
// Attempt to close the device
|
||||
{
|
||||
if(icsneo_closeDevice(selectedDevice)) {
|
||||
numDevices--;
|
||||
printf("Successfully closed %s!\n\n", productDescription);
|
||||
|
||||
// Shifts everything after the removed device 1 index to the left
|
||||
bool startResizing = false;
|
||||
for(size_t i = 0; i < numDevices; ++i) {
|
||||
if(selectedDevice == devices + i)
|
||||
startResizing = true;
|
||||
if(startResizing)
|
||||
devices[i] = devices[i + 1];
|
||||
}
|
||||
|
||||
selectedDevice = NULL;
|
||||
} else {
|
||||
printf("Failed to close %s!\n\n", productDescription);
|
||||
printLastError();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
//exit
|
||||
printf("Exiting program\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ int main() {
|
|||
auto lin_r = std::make_shared<icsneo::LINMessage>();
|
||||
lin_r->network = icsneo::Network::NetID::LIN2;
|
||||
lin_r->ID = 0x11;
|
||||
lin_r->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
lin_r->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
lin_r->data = {0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22, 0x33, 0x44};
|
||||
ret = device->transmit(lin_r); // This will return false if the device does not support LIN
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
|
@ -108,7 +108,7 @@ int main() {
|
|||
auto lin_c = std::make_shared<icsneo::LINMessage>();
|
||||
lin_c->network = icsneo::Network::NetID::LIN;
|
||||
lin_c->ID = 0x11;
|
||||
lin_c->type = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
|
||||
lin_c->linMsgType = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
|
||||
ret = device->transmit(lin_c);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl << std::endl;
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ int main() {
|
|||
lin_d->network = icsneo::Network::NetID::LIN;
|
||||
lin_d->ID = 0x22;
|
||||
lin_d->isEnhancedChecksum = true;
|
||||
lin_d->type = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
lin_d->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
lin_d->data = {0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, 0xcc, 0xdd};
|
||||
ret = device->transmit(lin_d);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl << std::endl;
|
||||
|
|
|
|||
|
|
@ -36,10 +36,8 @@ struct LINStatusFlags {
|
|||
|
||||
class LINMessage : public Frame {
|
||||
public:
|
||||
static void calcChecksum(LINMessage& message);
|
||||
|
||||
enum class Type {
|
||||
NOT_SET,
|
||||
enum class Type : uint8_t {
|
||||
NOT_SET = 0,
|
||||
LIN_COMMANDER_MSG,
|
||||
LIN_HEADER_ONLY,
|
||||
LIN_BREAK_ONLY,
|
||||
|
|
@ -48,12 +46,17 @@ public:
|
|||
LIN_ERROR
|
||||
};
|
||||
|
||||
static void calcChecksum(LINMessage& message);
|
||||
uint8_t calcProtectedID(uint8_t& id);
|
||||
|
||||
LINMessage() {};
|
||||
LINMessage(uint8_t id) : ID(id & 0x3Fu), protectedID(calcProtectedID(ID)) {};
|
||||
|
||||
uint8_t ID = 0;
|
||||
uint8_t protectedID = 0;
|
||||
uint8_t checksum = 0;
|
||||
LINMessage::Type type = Type::NOT_SET;
|
||||
LINMessage::Type linMsgType = Type::NOT_SET;
|
||||
bool isEnhancedChecksum = false;
|
||||
bool isLINStd2x = true;
|
||||
LINErrorFlags errFlags;
|
||||
LINStatusFlags statusFlags;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -86,14 +86,24 @@ typedef union {
|
|||
// ethernetFrameTooShort
|
||||
// ethernetFCSAvailable
|
||||
// ~~~ End of bitfield 2 ~~~
|
||||
//uint32_t linJustBreakSync : 1;
|
||||
//uint32_t linSlaveDataTooShort : 1;
|
||||
//uint32_t linOnlyUpdateSlaveTableOnce : 1;
|
||||
union {
|
||||
uint32_t status3;
|
||||
struct {
|
||||
uint32_t canfdESI : 1;
|
||||
uint32_t canfdIDE : 1;
|
||||
uint32_t canfdRTR : 1;
|
||||
uint32_t canfdFDF : 1;
|
||||
uint32_t canfdBRS : 1;
|
||||
uint32_t : 27;
|
||||
};
|
||||
struct {
|
||||
uint32_t linJustBreakSync : 1;
|
||||
uint32_t linSlaveDataTooShort : 1;
|
||||
uint32_t linOnlyUpdateSlaveTableOnce : 1;
|
||||
uint32_t : 29;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
uint32_t statusBitfield[4];
|
||||
} neomessage_statusbitfield_t;
|
||||
|
|
@ -171,6 +181,33 @@ typedef struct {
|
|||
uint8_t _reserved1[12];
|
||||
} neomessage_eth_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t txChecksumEnhanced : 1;
|
||||
uint8_t txCommander : 1;
|
||||
uint8_t txResponder : 1;
|
||||
uint8_t txAborted : 1;
|
||||
uint8_t updateResponderOnce : 1;
|
||||
uint8_t hasUpdatedResponderOnce : 1;
|
||||
uint8_t busRecovered : 1;
|
||||
uint8_t breakOnly : 1;
|
||||
} neomessage_linstatus_t;
|
||||
|
||||
typedef struct {
|
||||
neomessage_statusbitfield_t status;
|
||||
uint64_t timestamp;
|
||||
uint64_t _reservedTimestamp;
|
||||
const uint8_t* data;
|
||||
size_t length;
|
||||
uint8_t header[4];
|
||||
neonetid_t netid;
|
||||
neonettype_t type;
|
||||
neomessage_linstatus_t linStatus;
|
||||
uint16_t description;
|
||||
neomessagetype_t messageType;
|
||||
uint8_t checksum;
|
||||
uint8_t _reserved1[11];
|
||||
} neomessage_lin_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -182,6 +219,7 @@ static_assert(sizeof(neomessage_frame_t) == sizeof(neomessage_t), "All types of
|
|||
static_assert(sizeof(neomessage_can_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN is not)");
|
||||
static_assert(sizeof(neomessage_can_error_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN error is not)");
|
||||
static_assert(sizeof(neomessage_eth_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Ethernet is not)");
|
||||
static_assert(sizeof(neomessage_lin_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (LIN is not)");
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
|
|
|
|||
|
|
@ -86,10 +86,9 @@ std::vector<uint8_t> testControllerWithData =
|
|||
|
||||
TEST_F(LINEncoderDecoderTest, ProtectedIDCalcTest) {
|
||||
std::vector<uint8_t> bytestream;
|
||||
auto message = std::make_shared<icsneo::LINMessage>();
|
||||
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||
message->network = icsneo::Network::NetID::LIN;
|
||||
message->ID = 0x22;
|
||||
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->isEnhancedChecksum = false;
|
||||
packetEncoder->encode(*packetizer, bytestream, message);
|
||||
EXPECT_EQ(message->protectedID, 0xE2);
|
||||
|
|
@ -97,10 +96,9 @@ TEST_F(LINEncoderDecoderTest, ProtectedIDCalcTest) {
|
|||
|
||||
TEST_F(LINEncoderDecoderTest, ChecksumCalcTestClassic) {
|
||||
std::vector<uint8_t> bytestream;
|
||||
auto message = std::make_shared<icsneo::LINMessage>();
|
||||
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||
message->network = icsneo::Network::NetID::LIN2;
|
||||
message->ID = 0x22;
|
||||
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->isEnhancedChecksum = false;
|
||||
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||
packetEncoder->encode(*packetizer, bytestream, message);
|
||||
|
|
@ -109,10 +107,9 @@ TEST_F(LINEncoderDecoderTest, ChecksumCalcTestClassic) {
|
|||
|
||||
TEST_F(LINEncoderDecoderTest, ChecksumCalcTestEnhanced) {
|
||||
std::vector<uint8_t> bytestream;
|
||||
auto message = std::make_shared<icsneo::LINMessage>();
|
||||
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||
message->network = icsneo::Network::NetID::LIN2;
|
||||
message->ID = 0x22;
|
||||
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->isEnhancedChecksum = true;
|
||||
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||
packetEncoder->encode(*packetizer, bytestream, message);
|
||||
|
|
@ -121,10 +118,9 @@ TEST_F(LINEncoderDecoderTest, ChecksumCalcTestEnhanced) {
|
|||
|
||||
TEST_F(LINEncoderDecoderTest, PacketEncoderResponderLoadTest) {
|
||||
std::vector<uint8_t> bytestream;
|
||||
auto message = std::make_shared<icsneo::LINMessage>();
|
||||
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||
message->network = icsneo::Network::NetID::LIN2;
|
||||
message->ID = 0x22;
|
||||
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||
message->isEnhancedChecksum = false;
|
||||
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||
packetEncoder->encode(*packetizer, bytestream, message);
|
||||
|
|
@ -133,10 +129,9 @@ TEST_F(LINEncoderDecoderTest, PacketEncoderResponderLoadTest) {
|
|||
|
||||
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerHeaderTest) {
|
||||
std::vector<uint8_t> bytestream;
|
||||
auto message = std::make_shared<icsneo::LINMessage>();
|
||||
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||
message->network = icsneo::Network::NetID::LIN;
|
||||
message->ID = 0x22;
|
||||
message->type = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
|
||||
message->linMsgType = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
|
||||
message->isEnhancedChecksum = false;
|
||||
packetEncoder->encode(*packetizer, bytestream, message);
|
||||
EXPECT_EQ(bytestream, testControllerHeaderOnly);
|
||||
|
|
@ -144,10 +139,9 @@ TEST_F(LINEncoderDecoderTest, PacketEncoderControllerHeaderTest) {
|
|||
|
||||
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWithDataTest) {
|
||||
std::vector<uint8_t> bytestream;
|
||||
auto message = std::make_shared<icsneo::LINMessage>();
|
||||
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x11u));
|
||||
message->network = icsneo::Network::NetID::LIN;
|
||||
message->ID = 0x11;
|
||||
message->type = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
message->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
message->isEnhancedChecksum = false;
|
||||
message->data = {0xaa, 0xbb, 0xcc};
|
||||
packetEncoder->encode(*packetizer, bytestream, message);
|
||||
|
|
@ -156,19 +150,17 @@ TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWithDataTest) {
|
|||
|
||||
TEST_F(LINEncoderDecoderTest, PacketDecoderTest) {
|
||||
std::shared_ptr<icsneo::Message> decodeMsg;
|
||||
auto msg1 = std::make_shared<icsneo::LINMessage>();
|
||||
auto msg2 = std::make_shared<icsneo::LINMessage>();
|
||||
|
||||
auto msg1 = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||
msg1->network = icsneo::Network::NetID::LIN2;
|
||||
msg1->ID = 0x22;
|
||||
msg1->type = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
msg1->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
msg1->isEnhancedChecksum = false;
|
||||
msg1->data = {0xaa, 0xbb, 0xcc};
|
||||
msg1->checksum = 0xcc;
|
||||
|
||||
auto msg2 = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||
msg2->network = icsneo::Network::NetID::LIN;
|
||||
msg2->ID = 0x22;
|
||||
msg2->type = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
msg2->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||
msg2->isEnhancedChecksum = false;
|
||||
msg2->data = {0xaa, 0xbb, 0xcc};
|
||||
msg2->checksum = 0xcc;
|
||||
|
|
|
|||
Loading…
Reference in New Issue