LIN: Network support
parent
4229d8b66a
commit
539cfa511b
|
|
@ -174,6 +174,7 @@ set(SRC_FILES
|
||||||
communication/message/callback/streamoutput/a2bwavoutput.cpp
|
communication/message/callback/streamoutput/a2bwavoutput.cpp
|
||||||
communication/message/neomessage.cpp
|
communication/message/neomessage.cpp
|
||||||
communication/message/ethphymessage.cpp
|
communication/message/ethphymessage.cpp
|
||||||
|
communication/message/linmessage.cpp
|
||||||
communication/packet/flexraypacket.cpp
|
communication/packet/flexraypacket.cpp
|
||||||
communication/packet/canpacket.cpp
|
communication/packet/canpacket.cpp
|
||||||
communication/packet/a2bpacket.cpp
|
communication/packet/a2bpacket.cpp
|
||||||
|
|
@ -184,6 +185,7 @@ set(SRC_FILES
|
||||||
communication/packet/logicaldiskinfopacket.cpp
|
communication/packet/logicaldiskinfopacket.cpp
|
||||||
communication/packet/wivicommandpacket.cpp
|
communication/packet/wivicommandpacket.cpp
|
||||||
communication/packet/i2cpacket.cpp
|
communication/packet/i2cpacket.cpp
|
||||||
|
communication/packet/linpacket.cpp
|
||||||
communication/packet/scriptstatuspacket.cpp
|
communication/packet/scriptstatuspacket.cpp
|
||||||
communication/decoder.cpp
|
communication/decoder.cpp
|
||||||
communication/encoder.cpp
|
communication/encoder.cpp
|
||||||
|
|
@ -394,6 +396,7 @@ if(LIBICSNEO_BUILD_TESTS)
|
||||||
test/eventmanagertest.cpp
|
test/eventmanagertest.cpp
|
||||||
test/ethernetpacketizertest.cpp
|
test/ethernetpacketizertest.cpp
|
||||||
test/i2cencoderdecodertest.cpp
|
test/i2cencoderdecodertest.cpp
|
||||||
|
test/linencoderdecodertest.cpp
|
||||||
test/a2bencoderdecodertest.cpp
|
test/a2bencoderdecodertest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "icsneo/communication/message/a2bmessage.h"
|
#include "icsneo/communication/message/a2bmessage.h"
|
||||||
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
||||||
#include "icsneo/communication/message/i2cmessage.h"
|
#include "icsneo/communication/message/i2cmessage.h"
|
||||||
|
#include "icsneo/communication/message/linmessage.h"
|
||||||
#include "icsneo/communication/command.h"
|
#include "icsneo/communication/command.h"
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/communication/packet/canpacket.h"
|
#include "icsneo/communication/packet/canpacket.h"
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
#include "icsneo/communication/packet/wivicommandpacket.h"
|
#include "icsneo/communication/packet/wivicommandpacket.h"
|
||||||
#include "icsneo/communication/packet/i2cpacket.h"
|
#include "icsneo/communication/packet/i2cpacket.h"
|
||||||
#include "icsneo/communication/packet/scriptstatuspacket.h"
|
#include "icsneo/communication/packet/scriptstatuspacket.h"
|
||||||
|
#include "icsneo/communication/packet/linpacket.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
@ -362,6 +364,18 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
msg.network = packet->network;
|
msg.network = packet->network;
|
||||||
return true;
|
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
|
// 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/packet/i2cpacket.h"
|
||||||
#include "icsneo/communication/message/i2cmessage.h"
|
#include "icsneo/communication/message/i2cmessage.h"
|
||||||
#include "icsneo/communication/packet/a2bpacket.h"
|
#include "icsneo/communication/packet/a2bpacket.h"
|
||||||
|
#include "icsneo/communication/packet/linpacket.h"
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
|
|
@ -96,6 +96,18 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} // End of Network::Type::I2C
|
} // 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:
|
default:
|
||||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||||
return false;
|
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
|
// 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
|
// 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
|
// 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(), {
|
buffer->insert(buffer->begin(), {
|
||||||
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
||||||
(uint8_t)size, // Size, little endian 16-bit
|
(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
|
||||||
|
|
@ -2,8 +2,7 @@ option(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE "Build the command-line interactive
|
||||||
option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the 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_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
|
||||||
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
|
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
|
||||||
|
option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON)
|
||||||
|
|
||||||
# Disabled until we properly build these in-tree
|
# Disabled until we properly build these in-tree
|
||||||
# option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF)
|
# option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF)
|
||||||
# option(LIBICSNEO_BUILD_JAVA_INTERACTIVE_EXAMPLE "Build the command-line interactive Java example." OFF)
|
# option(LIBICSNEO_BUILD_JAVA_INTERACTIVE_EXAMPLE "Build the command-line interactive Java example." OFF)
|
||||||
|
|
@ -24,6 +23,9 @@ if(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE)
|
||||||
add_subdirectory(cpp/a2b)
|
add_subdirectory(cpp/a2b)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE)
|
||||||
|
add_subdirectory(cpp/lin)
|
||||||
|
endif()
|
||||||
# if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE)
|
# if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE)
|
||||||
# add_subdirectory(csharp)
|
# add_subdirectory(csharp)
|
||||||
# endif()
|
# endif()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
project(libicsneocpp-lin VERSION 0.1.0)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
# Add an include directory like so if desired
|
||||||
|
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
# Enable Warnings
|
||||||
|
if(MSVC)
|
||||||
|
# Force to always compile with W4
|
||||||
|
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||||
|
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||||
|
endif()
|
||||||
|
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add libicsneo, usually a git submodule within your project works well
|
||||||
|
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||||
|
|
||||||
|
add_executable(libicsneocpp-lin src/LINExample.cpp)
|
||||||
|
target_link_libraries(libicsneocpp-lin icsneocpp)
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "icsneo/icsneocpp.h"
|
||||||
|
#include "icsneo/communication/message/linmessage.h"
|
||||||
|
|
||||||
|
/* Note: This example requires LIN 1 and LIN 2 channels to be connected on the device */
|
||||||
|
|
||||||
|
char getCharInput(std::vector<char> allowed) {
|
||||||
|
bool found = false;
|
||||||
|
std::string input;
|
||||||
|
|
||||||
|
while(!found) {
|
||||||
|
std::cin >> input;
|
||||||
|
|
||||||
|
if(input.length() == 1) {
|
||||||
|
for(char compare : allowed) {
|
||||||
|
if(compare == input.c_str()[0]) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found) {
|
||||||
|
std::cout << "Input did not match expected options. Please try again." << std::endl;
|
||||||
|
std::cout << "<X or x to quit>" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.c_str()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Print version
|
||||||
|
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
|
||||||
|
std::cout << "\nFinding devices... " << std::flush;
|
||||||
|
auto devices = icsneo::FindAllDevices(); // This is type std::vector<std::shared_ptr<icsneo::Device>>
|
||||||
|
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
|
||||||
|
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
|
||||||
|
|
||||||
|
// List off the devices
|
||||||
|
for(auto& device : devices)
|
||||||
|
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
for(auto& device : devices) {
|
||||||
|
std::cout << "Connecting to " << device->describe() << "... ";
|
||||||
|
bool ret = device->open();
|
||||||
|
if(!ret) { // Failed to open
|
||||||
|
std::cout << "FAIL" << std::endl;
|
||||||
|
std::cout << icsneo::GetLastError() << std::endl << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
|
||||||
|
// The concept of going "online" tells the connected device to start listening, i.e. ACKing traffic and giving it to us
|
||||||
|
std::cout << "\tGoing online... ";
|
||||||
|
ret = device->goOnline();
|
||||||
|
if(!ret) {
|
||||||
|
std::cout << "FAIL" << std::endl;
|
||||||
|
device->close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
|
||||||
|
// A real application would just check the result of icsneo_goOnline() rather than calling this
|
||||||
|
// This function is intended to be called later on if needed
|
||||||
|
std::cout << "\tChecking online status... ";
|
||||||
|
ret = device->isOnline();
|
||||||
|
if(!ret) {
|
||||||
|
std::cout << "FAIL\n" << std::endl;
|
||||||
|
device->close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
|
||||||
|
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message) {
|
||||||
|
if(icsneo::Message::Type::Frame == message->type) {
|
||||||
|
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
|
||||||
|
if(icsneo::Network::Type::LIN == frame->network.getType()) {
|
||||||
|
auto msg = std::static_pointer_cast<icsneo::LINMessage>(message);
|
||||||
|
std::cout << msg->network << " RX frame | ID: 0x" << std::hex << static_cast<int>(msg->ID) << " | ";
|
||||||
|
std::cout << "Protected ID: 0x" << static_cast<int>(msg->protectedID) << "\n" << "Data: ";
|
||||||
|
for(uint8_t& each : msg->data) {
|
||||||
|
std::cout << "0x" << static_cast<int>(each) << " ";
|
||||||
|
}
|
||||||
|
std::cout << "\nChecksum type: " << (msg->isEnhancedChecksum ? "Enhanced" : "Classic");
|
||||||
|
std::cout << "\nChecksum: 0x" << static_cast<int>(msg->checksum) << "\n";
|
||||||
|
std::cout << "Is checksum valid: " << ((!msg->errFlags.ErrChecksumMatch) ? "yes" : "no") << "\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// We can transmit messages
|
||||||
|
std::cout << "\tTransmitting a LIN responder data frame... ";
|
||||||
|
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->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;
|
||||||
|
|
||||||
|
std::cout << "\tTransmitting a LIN commander frame... ";
|
||||||
|
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;
|
||||||
|
ret = device->transmit(lin_c);
|
||||||
|
std::cout << (ret ? "OK" : "FAIL") << std::endl << std::endl;
|
||||||
|
|
||||||
|
std::cout << "\tTransmitting a LIN commander frame with responder data... ";
|
||||||
|
auto lin_d = std::make_shared<icsneo::LINMessage>();
|
||||||
|
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->data = {0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, 0xcc, 0xdd};
|
||||||
|
ret = device->transmit(lin_d);
|
||||||
|
std::cout << (ret ? "OK" : "FAIL") << std::endl << std::endl;
|
||||||
|
std::cout << "<X or x to quit>\n\n";
|
||||||
|
|
||||||
|
// Go offline, stop sending and receiving traffic
|
||||||
|
auto shutdown = [&](){
|
||||||
|
device->removeMessageCallback(handler);
|
||||||
|
std::cout << "\tGoing offline... ";
|
||||||
|
ret = device->goOffline();
|
||||||
|
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||||
|
std::cout << "\tDisconnecting... ";
|
||||||
|
ret = device->close();
|
||||||
|
std::cout << (ret ? "OK\n" : "FAIL\n") << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
char input = getCharInput(std::vector<char> {'X', 'x'});
|
||||||
|
switch(input) {
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
shutdown();
|
||||||
|
printf("Exiting program\n");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef __LINMESSAGE_H_
|
||||||
|
#define __LINMESSAGE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
#include "icsneo/communication/network.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
struct LINErrorFlags {
|
||||||
|
bool ErrRxBreakOnly = false;
|
||||||
|
bool ErrRxBreakSyncOnly = false;
|
||||||
|
bool ErrTxRxMismatch = false;
|
||||||
|
bool ErrRxBreakNotZero = false;
|
||||||
|
bool ErrRxBreakTooShort = false;
|
||||||
|
bool ErrRxSyncNot55 = false;
|
||||||
|
bool ErrRxDataLenOver8 = false;
|
||||||
|
bool ErrFrameSync = false;
|
||||||
|
bool ErrFrameMessageID = false;
|
||||||
|
bool ErrFrameResponderData = false;
|
||||||
|
bool ErrChecksumMatch = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LINStatusFlags {
|
||||||
|
bool TxChecksumEnhanced = false;
|
||||||
|
bool TxCommander = false;
|
||||||
|
bool TxResponder = false;
|
||||||
|
bool TxAborted = false;
|
||||||
|
bool UpdateResponderOnce = false;
|
||||||
|
bool HasUpdatedResponderOnce = false;
|
||||||
|
bool BusRecovered = false;
|
||||||
|
bool BreakOnly = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LINMessage : public Frame {
|
||||||
|
public:
|
||||||
|
static void calcChecksum(LINMessage& message);
|
||||||
|
|
||||||
|
enum class Type {
|
||||||
|
NOT_SET,
|
||||||
|
LIN_COMMANDER_MSG,
|
||||||
|
LIN_HEADER_ONLY,
|
||||||
|
LIN_BREAK_ONLY,
|
||||||
|
LIN_SYNC_ONLY,
|
||||||
|
LIN_UPDATE_RESPONDER,
|
||||||
|
LIN_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t ID = 0;
|
||||||
|
uint8_t protectedID = 0;
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
LINMessage::Type type = Type::NOT_SET;
|
||||||
|
bool isEnhancedChecksum = false;
|
||||||
|
bool isLINStd2x = true;
|
||||||
|
LINErrorFlags errFlags;
|
||||||
|
LINStatusFlags statusFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -18,6 +18,9 @@ public:
|
||||||
|
|
||||||
CANErrorCount = 0x100,
|
CANErrorCount = 0x100,
|
||||||
|
|
||||||
|
LINHeaderOnly = 0x200,
|
||||||
|
LINBreak = 0x201,
|
||||||
|
|
||||||
// Past 0x8000 are all for internal use only
|
// Past 0x8000 are all for internal use only
|
||||||
Invalid = 0x8000,
|
Invalid = 0x8000,
|
||||||
RawMessage = 0x8001,
|
RawMessage = 0x8001,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef __LINPACKET_H__
|
||||||
|
#define __LINPACKET_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/message/linmessage.h"
|
||||||
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
#include "icsneo/communication/packetizer.h"
|
||||||
|
#include "icsneo/communication/network.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
#pragma pack(push, 2)
|
||||||
|
|
||||||
|
struct HardwareLINPacket {
|
||||||
|
static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
||||||
|
static bool EncodeFromMessage(LINMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
|
||||||
|
struct {
|
||||||
|
//CxLIN3
|
||||||
|
uint16_t ErrRxOnlyBreak : 1;
|
||||||
|
uint16_t ErrRxOnlyBreakSync : 1;
|
||||||
|
uint16_t ID : 11;
|
||||||
|
uint16_t NETWORKINDEX : 3;//DO NOT CLOBBER THIS
|
||||||
|
|
||||||
|
// CxLIN
|
||||||
|
uint8_t LINByte9;
|
||||||
|
uint8_t ErrTxRxMismatch : 1;
|
||||||
|
uint8_t TxChkSumEnhanced : 1;
|
||||||
|
uint8_t TXCommander : 1;
|
||||||
|
uint8_t TXResponder : 1;
|
||||||
|
uint8_t ErrRxBreakNotZero : 1;
|
||||||
|
uint8_t ErrRxBreakTooShort : 1;
|
||||||
|
uint8_t ErrRxSyncNot55 : 1;
|
||||||
|
uint8_t ErrRxDataGreater8 : 1;
|
||||||
|
|
||||||
|
// CxLIN2
|
||||||
|
uint16_t len : 4;
|
||||||
|
uint16_t ExtendedNetworkIndexBit2 : 1;//DO NOT CLOBBER THIS
|
||||||
|
uint16_t UpdateResponderOnce : 1;
|
||||||
|
uint16_t HasUpdatedResponderOnce : 1;
|
||||||
|
uint16_t ExtendedNetworkIndexBit : 1;//DO NOT CLOBBER THIS
|
||||||
|
uint16_t BusRecovered : 1;
|
||||||
|
uint16_t SyncFerr : 1; //Framing error in sync byte
|
||||||
|
uint16_t MidFerr : 1; // Framing error in message id
|
||||||
|
uint16_t ResponderByteFerr : 1; //Framing error in one of our responder bytes.
|
||||||
|
uint16_t TxAborted : 1;//!< This transmit was aborted.
|
||||||
|
uint16_t BreakOnly : 1;
|
||||||
|
uint16_t : 2;
|
||||||
|
} CoreMiniBitsLIN;
|
||||||
|
|
||||||
|
uint8_t data[8];
|
||||||
|
|
||||||
|
uint16_t stats; //CxTRB0STAT
|
||||||
|
uint64_t timestamp; //Large timestamp
|
||||||
|
//CoreMiniMsgExtendedHdr
|
||||||
|
uint16_t networkID;
|
||||||
|
uint16_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
} //namespace libicsneo
|
||||||
|
#endif //_cplusplus
|
||||||
|
#endif
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "icsneo/communication/message/ethphymessage.h"
|
#include "icsneo/communication/message/ethphymessage.h"
|
||||||
#include "icsneo/communication/message/i2cmessage.h"
|
#include "icsneo/communication/message/i2cmessage.h"
|
||||||
#include "icsneo/communication/message/a2bmessage.h"
|
#include "icsneo/communication/message/a2bmessage.h"
|
||||||
|
#include "icsneo/communication/message/linmessage.h"
|
||||||
|
|
||||||
#include "icsneo/communication/message/callback/streamoutput/a2bwavoutput.h"
|
#include "icsneo/communication/message/callback/streamoutput/a2bwavoutput.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
#include "icsneo/icsneocpp.h"
|
||||||
|
#include "icsneo/communication/encoder.h"
|
||||||
|
#include "icsneo/communication/packet/linpacket.h"
|
||||||
|
#include "icsneo/communication/message/linmessage.h"
|
||||||
|
#include "icsneo/communication/packetizer.h"
|
||||||
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
|
||||||
|
class LINEncoderDecoderTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
report = [](APIEvent::Type, APIEvent::Severity) {
|
||||||
|
// Unless caught by the test, the packetizer should not throw errors
|
||||||
|
EXPECT_TRUE(false);
|
||||||
|
};
|
||||||
|
packetizer.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
|
||||||
|
report(t, s);
|
||||||
|
});
|
||||||
|
packetEncoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
|
||||||
|
report(t, s);
|
||||||
|
});
|
||||||
|
packetDecoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
|
||||||
|
report(t, s);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
device_eventhandler_t report;
|
||||||
|
std::optional<Encoder> packetEncoder;
|
||||||
|
std::optional<Packetizer> packetizer;
|
||||||
|
std::optional<Decoder> packetDecoder;
|
||||||
|
//Responder load data before response LIN 2
|
||||||
|
// ID 0x22 pID 0xE2 length 8
|
||||||
|
std::vector<uint8_t> testRespData =
|
||||||
|
{0xaa, 0x0c,
|
||||||
|
0x15, 0x00,
|
||||||
|
0x30, 0x00,
|
||||||
|
0x00, 0x0c,
|
||||||
|
0x00, 0x00,
|
||||||
|
0xe2,
|
||||||
|
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
||||||
|
0x99};
|
||||||
|
|
||||||
|
//Controller header LIN 1
|
||||||
|
// ID 0x22 pID 0xE2 length 8
|
||||||
|
std::vector<uint8_t> testControllerHeaderOnly =
|
||||||
|
{0xaa, 0x0c,
|
||||||
|
0x0d, 0x00,
|
||||||
|
0x10, 0x00,
|
||||||
|
0x00, 0x83,
|
||||||
|
0x00, 0x00,
|
||||||
|
0xE2, 0x41};
|
||||||
|
|
||||||
|
std::vector<uint8_t> recvBytes =
|
||||||
|
{0xaa, 0x0c, 0x22, 0x00,
|
||||||
|
0x10, 0x00, 0x88, 0x03,
|
||||||
|
0x00, 0x08, 0x04, 0x00,
|
||||||
|
0xaa, 0xbb, 0xcc, 0xcc,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xb3, 0x34,
|
||||||
|
0xa8, 0x10, 0x29, 0x13,
|
||||||
|
0x48, 0x00, 0x02, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0xaa, 0x0c, 0x22, 0x00,
|
||||||
|
0x30, 0x00, 0x88, 0x03,
|
||||||
|
0x00, 0x04, 0x04, 0x00,
|
||||||
|
0xaa, 0xbb, 0xcc, 0xcc,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xb4, 0x34,
|
||||||
|
0xa8, 0x10, 0x29, 0x13,
|
||||||
|
0x48, 0x00, 0x03, 0x00,
|
||||||
|
0x00, 0x00};
|
||||||
|
|
||||||
|
std::vector<uint8_t> testControllerWithData =
|
||||||
|
{0xaa, 0x0c,
|
||||||
|
0x11, 0x00,
|
||||||
|
0x10, 0x00,
|
||||||
|
0x00, 0x87,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x11, 0xaa,
|
||||||
|
0xbb, 0xcc,
|
||||||
|
0xcc, 0x41};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, ProtectedIDCalcTest) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>();
|
||||||
|
message->network = icsneo::Network::NetID::LIN;
|
||||||
|
message->ID = 0x22;
|
||||||
|
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||||
|
message->isEnhancedChecksum = false;
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(message->protectedID, 0xE2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, ChecksumCalcTestClassic) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>();
|
||||||
|
message->network = icsneo::Network::NetID::LIN2;
|
||||||
|
message->ID = 0x22;
|
||||||
|
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||||
|
message->isEnhancedChecksum = false;
|
||||||
|
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(message->checksum, 0x99);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, ChecksumCalcTestEnhanced) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>();
|
||||||
|
message->network = icsneo::Network::NetID::LIN2;
|
||||||
|
message->ID = 0x22;
|
||||||
|
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||||
|
message->isEnhancedChecksum = true;
|
||||||
|
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(message->checksum, 0xB6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, PacketEncoderResponderLoadTest) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>();
|
||||||
|
message->network = icsneo::Network::NetID::LIN2;
|
||||||
|
message->ID = 0x22;
|
||||||
|
message->type = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
|
||||||
|
message->isEnhancedChecksum = false;
|
||||||
|
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(bytestream, testRespData);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerHeaderTest) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>();
|
||||||
|
message->network = icsneo::Network::NetID::LIN;
|
||||||
|
message->ID = 0x22;
|
||||||
|
message->type = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
|
||||||
|
message->isEnhancedChecksum = false;
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(bytestream, testControllerHeaderOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWithDataTest) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>();
|
||||||
|
message->network = icsneo::Network::NetID::LIN;
|
||||||
|
message->ID = 0x11;
|
||||||
|
message->type = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||||
|
message->isEnhancedChecksum = false;
|
||||||
|
message->data = {0xaa, 0xbb, 0xcc};
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(bytestream, testControllerWithData);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, PacketDecoderTest) {
|
||||||
|
std::shared_ptr<icsneo::Message> decodeMsg;
|
||||||
|
auto msg1 = std::make_shared<icsneo::LINMessage>();
|
||||||
|
auto msg2 = std::make_shared<icsneo::LINMessage>();
|
||||||
|
|
||||||
|
msg1->network = icsneo::Network::NetID::LIN2;
|
||||||
|
msg1->ID = 0x22;
|
||||||
|
msg1->type = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||||
|
msg1->isEnhancedChecksum = false;
|
||||||
|
msg1->data = {0xaa, 0xbb, 0xcc};
|
||||||
|
msg1->checksum = 0xcc;
|
||||||
|
|
||||||
|
msg2->network = icsneo::Network::NetID::LIN;
|
||||||
|
msg2->ID = 0x22;
|
||||||
|
msg2->type = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
|
||||||
|
msg2->isEnhancedChecksum = false;
|
||||||
|
msg2->data = {0xaa, 0xbb, 0xcc};
|
||||||
|
msg2->checksum = 0xcc;
|
||||||
|
|
||||||
|
EXPECT_TRUE(packetizer->input(recvBytes));
|
||||||
|
auto packets = packetizer->output();
|
||||||
|
if(packets.size() != 2) { EXPECT_TRUE(false); }
|
||||||
|
//LIN2 frame from device
|
||||||
|
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
|
||||||
|
auto testMessage = std::dynamic_pointer_cast<icsneo::LINMessage>(decodeMsg);
|
||||||
|
EXPECT_EQ(msg1->network, testMessage->network);
|
||||||
|
EXPECT_EQ(msg1->ID, testMessage->ID);
|
||||||
|
EXPECT_EQ(msg1->type, testMessage->type);
|
||||||
|
EXPECT_EQ(msg1->isEnhancedChecksum, testMessage->isEnhancedChecksum);
|
||||||
|
EXPECT_EQ(msg1->data, testMessage->data);
|
||||||
|
EXPECT_EQ(msg1->checksum, testMessage->checksum);
|
||||||
|
packets.pop_back();
|
||||||
|
|
||||||
|
//LIN1 frame from device
|
||||||
|
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
|
||||||
|
auto testMessage2 = std::dynamic_pointer_cast<icsneo::LINMessage>(decodeMsg);
|
||||||
|
EXPECT_EQ(msg2->network, testMessage2->network);
|
||||||
|
EXPECT_EQ(msg2->ID, testMessage2->ID);
|
||||||
|
EXPECT_EQ(msg2->type, testMessage2->type);
|
||||||
|
EXPECT_EQ(msg2->isEnhancedChecksum, testMessage2->isEnhancedChecksum);
|
||||||
|
EXPECT_EQ(msg2->data, testMessage2->data);
|
||||||
|
EXPECT_EQ(msg2->checksum, testMessage2->checksum);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue