Message: Create a type system so non-frame data can be represented

This change breaks existing code, hence the version bump, but it's
going to be much less error prone going forward.
v0.3.0-dev
Paul Hollinsky 2021-05-22 01:58:36 -04:00
parent 21e93d1f73
commit 21bc4eeff2
48 changed files with 853 additions and 527 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.2)
project(libicsneo VERSION 0.2.0) project(libicsneo VERSION 0.3.0)
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF) option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF) option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)

View File

@ -114,7 +114,7 @@ bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::mil
return false; return false;
} }
data = std::move(msg->data); data = std::move(gsmsg->data);
return true; return true;
} }
@ -145,7 +145,7 @@ optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersions
if(!ver) // Could not upcast for some reason if(!ver) // Could not upcast for some reason
return nullopt; return nullopt;
if(!ver->MainChip || ver->Versions.size() != 1) if(ver->ForChip != VersionMessage::MainChip || ver->Versions.size() != 1)
return nullopt; return nullopt;
ret.push_back(ver->Versions.front()); ret.push_back(ver->Versions.front());
@ -155,10 +155,9 @@ optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersions
}, Main51MessageFilter(Command::GetSecondaryVersions), timeout); }, Main51MessageFilter(Command::GetSecondaryVersions), timeout);
if(msg) { // This one is allowed to fail if(msg) { // This one is allowed to fail
ver = std::dynamic_pointer_cast<VersionMessage>(msg); ver = std::dynamic_pointer_cast<VersionMessage>(msg);
if(ver && !ver->MainChip) { if(ver && ver->ForChip != VersionMessage::MainChip)
ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end()); ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end());
} }
}
return ret; return ret;
} }

View File

@ -3,6 +3,7 @@
#include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h" #include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
@ -24,7 +25,7 @@ uint64_t Decoder::GetUInt64FromLEBytes(const uint8_t* bytes) {
bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) { bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) {
switch(packet->network.getType()) { switch(packet->network.getType()) {
case Network::Type::Ethernet: case Network::Type::Ethernet: {
result = HardwareEthernetPacket::DecodeToMessage(packet->data, report); result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
if(!result) { if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
@ -33,9 +34,11 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; EthernetMessage& eth = *static_cast<EthernetMessage*>(result.get());
result->network = packet->network; eth.timestamp *= timestampResolution;
eth.network = packet->network;
return true; return true;
}
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: { case Network::Type::LSFTCAN: {
@ -49,10 +52,28 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false; // A nullptr was returned, the packet was malformed
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; result->timestamp *= timestampResolution;
result->network = packet->network;
switch(result->type) {
case Message::Type::Frame: {
CANMessage& can = *static_cast<CANMessage*>(result.get());
can.network = packet->network;
break;
}
case Message::Type::CANErrorCount: {
CANErrorCountMessage& can = *static_cast<CANErrorCountMessage*>(result.get());
can.network = packet->network;
break;
}
default: {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // An unknown type was returned, the packet was malformed
}
}
return true; return true;
} }
case Network::Type::FlexRay: { case Network::Type::FlexRay: {
@ -66,10 +87,12 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false; // A nullptr was returned, the packet was malformed
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; FlexRayMessage& fr = *static_cast<FlexRayMessage*>(result.get());
result->network = packet->network; fr.timestamp *= timestampResolution;
fr.network = packet->network;
return true; return true;
} }
case Network::Type::ISO9141: { case Network::Type::ISO9141: {
@ -84,8 +107,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; ISO9141Message& iso = *static_cast<ISO9141Message*>(result.get());
result->network = packet->network; iso.timestamp *= timestampResolution;
iso.network = packet->network;
return true; return true;
} }
case Network::Type::Internal: { case Network::Type::Internal: {
@ -98,7 +122,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data(); HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data();
auto msg = std::make_shared<ResetStatusMessage>(); auto msg = std::make_shared<ResetStatusMessage>();
msg->network = packet->network;
msg->mainLoopTime = data->main_loop_time_25ns * 25; msg->mainLoopTime = data->main_loop_time_25ns * 25;
msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25; msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25;
msg->busVoltage = data->busVoltage; msg->busVoltage = data->busVoltage;
@ -124,9 +147,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// They come in as CAN but we will handle them in the device rather than // They come in as CAN but we will handle them in the device rather than
// passing them onto the user. // passing them onto the user.
if(packet->data.size() < 24) { if(packet->data.size() < 24) {
result = std::make_shared<Message>(); auto rawmsg = std::make_shared<RawMessage>(Network::NetID::Device);
result->network = packet->network; result = rawmsg;
result->data = packet->data; rawmsg->data = packet->data;
return true; return true;
} }
@ -135,17 +158,21 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false; // A nullptr was returned, the packet was malformed
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; auto* raw = dynamic_cast<RawMessage*>(result.get());
result->network = packet->network; if(raw == nullptr) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
raw->timestamp *= timestampResolution;
raw->network = packet->network;
return true; return true;
} }
case Network::NetID::DeviceStatus: { case Network::NetID::DeviceStatus: {
result = std::make_shared<Message>();
result->network = packet->network;
// Just pass along the data, the device needs to handle this itself // Just pass along the data, the device needs to handle this itself
result->data = packet->data; result = std::make_shared<RawMessage>(packet->network, packet->data);
return true; return true;
} }
case Network::NetID::FlexRayControl: { case Network::NetID::FlexRayControl: {
@ -161,7 +188,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
switch((Command)packet->data[0]) { switch((Command)packet->data[0]) {
case Command::RequestSerialNumber: { case Command::RequestSerialNumber: {
auto msg = std::make_shared<SerialNumberMessage>(); auto msg = std::make_shared<SerialNumberMessage>();
msg->network = packet->network;
uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1); uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1);
// The device sends 64-bits of serial number, but we never use more than 32-bits. // The device sends 64-bits of serial number, but we never use more than 32-bits.
msg->deviceSerial = Device::SerialNumToString((uint32_t)serial); msg->deviceSerial = Device::SerialNumToString((uint32_t)serial);
@ -194,7 +220,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
default: default:
auto msg = std::make_shared<Main51Message>(); auto msg = std::make_shared<Main51Message>();
msg->network = packet->network;
msg->command = Command(packet->data[0]); msg->command = Command(packet->data[0]);
msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end()); msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end());
result = msg; result = msg;
@ -218,7 +243,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
case Network::NetID::ReadSettings: { case Network::NetID::ReadSettings: {
auto msg = std::make_shared<ReadSettingsMessage>(); auto msg = std::make_shared<ReadSettingsMessage>();
msg->network = packet->network;
msg->response = ReadSettingsMessage::Response(packet->data[0]); msg->response = ReadSettingsMessage::Response(packet->data[0]);
if(msg->response == ReadSettingsMessage::Response::OK) { if(msg->response == ReadSettingsMessage::Response::OK) {
@ -243,9 +267,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
// 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
auto msg = std::make_shared<Message>(); result = std::make_shared<RawMessage>(packet->network, packet->data);
msg->network = packet->network;
msg->data = packet->data;
result = msg;
return true; return true;
} }

View File

@ -9,10 +9,19 @@ using namespace icsneo;
bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) { bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
bool shortFormat = false; bool shortFormat = false;
bool useResultAsBuffer = false; // Otherwise it's expected that we use message->data std::vector<uint8_t>* buffer = &result;
uint16_t netid = 0;
result.clear(); result.clear();
switch(message->network.getType()) { switch(message->type) {
case Message::Type::Frame: {
auto frame = std::dynamic_pointer_cast<Frame>(message);
// Frame uses frame->data as the buffer unless directed otherwise
buffer = &frame->data;
netid = uint16_t(frame->network.getNetID());
switch(frame->network.getType()) {
case Network::Type::Ethernet: { case Network::Type::Ethernet: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message); auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg) { if(!ethmsg) {
@ -20,7 +29,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
return false; // The message was not a properly formed EthernetMessage return false; // The message was not a properly formed EthernetMessage
} }
useResultAsBuffer = true; buffer = &result;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report)) if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
return false; return false;
@ -40,7 +49,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
return false; // This device does not support CAN FD return false; // This device does not support CAN FD
} }
useResultAsBuffer = true; buffer = &result;
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report)) if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
return false; // The CANMessage was malformed return false; // The CANMessage was malformed
@ -58,70 +67,86 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer); return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
} // End of Network::Type::ISO9141 } // End of Network::Type::ISO9141
default: default:
switch(message->network.getNetID()) { report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
break;
}
case Message::Type::RawMessage: {
auto raw = std::dynamic_pointer_cast<RawMessage>(message);
// Raw message uses raw->data as the buffer unless directed otherwise
buffer = &raw->data;
netid = uint16_t(raw->network.getNetID());
switch(raw->network.getNetID()) {
case Network::NetID::Device: case Network::NetID::Device:
shortFormat = true; shortFormat = true;
break; break;
case Network::NetID::Main51: {
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
if(!m51msg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Main51Message
}
if(!m51msg->forceShortFormat) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(message->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
size += 1; // Main51 Command
message->data.insert(message->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8),
(uint8_t)m51msg->command
});
result = packetizer.packetWrap(message->data, shortFormat);
return true;
} else {
message->data.insert(message->data.begin(), { uint8_t(m51msg->command) });
shortFormat = true;
}
break;
}
case Network::NetID::RED_OLDFORMAT: { case Network::NetID::RED_OLDFORMAT: {
// See the decoder for an explanation // See the decoder for an explanation
// We expect the network byte to be populated already in data, but not the length // We expect the network byte to be populated already in data, but not the length
uint16_t length = uint16_t(message->data.size()) - 1; uint16_t length = uint16_t(raw->data.size()) - 1;
message->data.insert(message->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)}); raw->data.insert(raw->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
break; break;
} }
default: default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error); report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false; return false;
} }
break;
}
case Message::Type::Main51: {
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
if(!m51msg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Main51Message
}
buffer = &m51msg->data;
netid = uint16_t(Network::NetID::Main51);
if(!m51msg->forceShortFormat) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(m51msg->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
size += 1; // Main51 Command
m51msg->data.insert(m51msg->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8),
(uint8_t)m51msg->command
});
result = packetizer.packetWrap(m51msg->data, shortFormat);
return true;
} else {
m51msg->data.insert(m51msg->data.begin(), { uint8_t(m51msg->command) });
shortFormat = true;
}
}
break;
} }
// Early returns may mean we don't reach this far, check the type you're concerned with // Early returns may mean we don't reach this far, check the type you're concerned with
auto& buffer = useResultAsBuffer ? result : message->data;
if(shortFormat) { if(shortFormat) {
buffer.insert(buffer.begin(), (uint8_t(buffer.size()) << 4) | uint8_t(message->network.getNetID())); buffer->insert(buffer->begin(), (uint8_t(buffer->size()) << 4) | uint8_t(netid));
} else { } else {
// Size in long format is the size of the entire packet // Size in long format is the size of the entire packet
// 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
uint16_t size = uint16_t(buffer.size()) + 1 + 1 + 2 + 2; uint16_t size = uint16_t(buffer->size()) + 1 + 1 + 2 + 2;
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
(uint8_t)(size >> 8), (uint8_t)(size >> 8),
(uint8_t)message->network.getNetID(), // NetID, little endian 16-bit (uint8_t)netid, // NetID, little endian 16-bit
(uint8_t)(uint16_t(message->network.getNetID()) >> 8) (uint8_t)(netid >> 8)
}); });
} }
result = packetizer.packetWrap(buffer, shortFormat); result = packetizer.packetWrap(*buffer, shortFormat);
return true; return true;
} }
@ -133,20 +158,19 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
* In this case, command 0x06 is SetLEDState. * In this case, command 0x06 is SetLEDState.
* This old command type is not really used anywhere else. * This old command type is not really used anywhere else.
*/ */
msg = std::make_shared<Message>(); auto canmsg = std::make_shared<RawMessage>(Network::NetID::Device);
msg = canmsg;
if(arguments.empty()) { if(arguments.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error); report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; return false;
} }
msg->network = Network::NetID::Device; canmsg->data.reserve(3);
msg->data.reserve(3); canmsg->data.push_back(0x00);
msg->data.push_back(0x00); canmsg->data.push_back(0x06); // SetLEDState
msg->data.push_back(0x06); // SetLEDState canmsg->data.push_back(arguments.at(0)); // See Device::LEDState
msg->data.push_back(arguments.at(0)); // See Device::LEDState
} else { } else {
auto m51msg = std::make_shared<Main51Message>(); auto m51msg = std::make_shared<Main51Message>();
msg = m51msg; msg = m51msg;
msg->network = Network::NetID::Main51;
m51msg->command = cmd; m51msg->command = cmd;
switch(cmd) { switch(cmd) {
case Command::ReadSettings: case Command::ReadSettings:
@ -161,7 +185,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
default: default:
break; break;
} }
msg->data.insert(msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end())); m51msg->data.insert(m51msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
} }
return encode(packetizer, result, msg); return encode(packetizer, result, msg);

View File

@ -64,9 +64,7 @@ std::vector<uint8_t> FlexRayControlMessage::BuildWriteMessageBufferArgs(
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args); return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args);
} }
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message() { FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message(Message::Type::FlexRayControl) {
network = Network::NetID::FlexRayControl;
if(packet.data.size() < 2) if(packet.data.size() < 2)
return; // huh? return; // huh?
controller = packet.data[0]; controller = packet.data[0];

View File

@ -1,24 +1,32 @@
#include "icsneo/communication/message/neomessage.h" #include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
using namespace icsneo; using namespace icsneo;
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) { neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
// This function is not responsible for storing the message! // This function is not responsible for storing the message!
// Keep the shared_ptr around for the lifetime of the data access // Keep the shared_ptr around for the lifetime of the data access
const auto type = message->network.getType();
neomessage_t neomsg = {}; // Clear out the memory neomessage_t neomsg = {}; // Clear out the memory
neomsg.netid = (uint32_t)message->network.getNetID(); neomsg.messageType = (neomessagetype_t)message->type;
neomsg.type = (uint8_t)type;
neomsg.description = message->description;
neomsg.length = message->data.size();
neomsg.data = message->data.data();
neomsg.timestamp = message->timestamp; neomsg.timestamp = message->timestamp;
neomsg.status.globalError = message->error; switch (message->type)
neomsg.status.transmitMessage = message->transmitted; {
case Message::Type::Frame: {
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;
frame.length = framemsg->data.size();
frame.data = framemsg->data.data();
frame.timestamp = framemsg->timestamp;
frame.status.globalError = framemsg->error;
frame.status.transmitMessage = framemsg->transmitted;
switch(type) { switch(netType) {
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: { case Network::Type::LSFTCAN: {
@ -49,12 +57,28 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
// TODO Implement others // TODO Implement others
break; break;
} }
break;
}
case Message::Type::CANErrorCount: {
neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message);
canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
canerror.status.canBusOff = canerrormsg->busOff;
canerror.netid = (neonetid_t)canerrormsg->network.getNetID();
canerror.type = (neonettype_t)canerrormsg->network.getType();
break;
}
default:
break;
}
return neomsg; return neomsg;
} }
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) { std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
const Network network = neomessage->netid; switch((Message::Type)neomessage->messageType) {
case Message::Type::Frame: {
const Network network = ((neomessage_frame_t*)neomessage)->netid;
switch(network.getType()) { switch(network.getType()) {
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
@ -65,6 +89,7 @@ std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t*
canmsg->description = can.description; canmsg->description = can.description;
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length); canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
canmsg->arbid = can.arbid; canmsg->arbid = can.arbid;
canmsg->dlcOnWire = can.dlcOnWire;
canmsg->isExtended = can.status.extendedFrame; canmsg->isExtended = can.status.extendedFrame;
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR; canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
canmsg->isCANFD = can.status.canfdFDF; canmsg->isCANFD = can.status.canfdFDF;
@ -80,8 +105,12 @@ std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t*
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length); ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
return ethmsg; return ethmsg;
} }
default: default: break;
// TODO Implement others }
break;
}
default: break;
}
return std::shared_ptr<Message>(); return std::shared_ptr<Message>();
}
} }

View File

@ -1,4 +1,5 @@
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/platform/optional.h" #include "icsneo/platform/optional.h"
using namespace icsneo; using namespace icsneo;
@ -26,9 +27,22 @@ static optional<uint8_t> CANFD_DLCToLength(uint8_t length) {
return nullopt; return nullopt;
} }
std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data(); const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
if(data->dlc.RB1) { // Change counts reporting
const bool busOff = data->data[0] & 0b00100000;
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff);
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
return msg;
} else { // CAN Frame
auto msg = std::make_shared<CANMessage>(); auto msg = std::make_shared<CANMessage>();
// Arb ID // Arb ID
@ -82,6 +96,7 @@ std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector
return msg; return msg;
} }
}
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) { bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
if(message.isCANFD && message.isRemote) { if(message.isCANFD && message.isRemote) {

View File

@ -6,7 +6,7 @@ std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const
if(bytestream.size() < 3) // Not enough bytes to decode if(bytestream.size() < 3) // Not enough bytes to decode
return std::shared_ptr<VersionMessage>(); return std::shared_ptr<VersionMessage>();
auto msg = std::make_shared<VersionMessage>(true); auto msg = std::make_shared<VersionMessage>(VersionMessage::MainChip);
optional<DeviceAppVersion>& version = msg->Versions.emplace_back(); optional<DeviceAppVersion>& version = msg->Versions.emplace_back();
version.emplace(); version.emplace();
@ -17,7 +17,7 @@ std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const
} }
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) {
auto msg = std::make_shared<VersionMessage>(false); auto msg = std::make_shared<VersionMessage>(VersionMessage::SecondaryChips);
size_t bytesLeft = bytestream.size(); size_t bytesLeft = bytestream.size();
if(bytesLeft) if(bytesLeft)

View File

@ -117,19 +117,16 @@ std::pair<std::vector<std::shared_ptr<Message>>, bool> Device::getMessages() {
} }
bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit, std::chrono::milliseconds timeout) { bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit, std::chrono::milliseconds timeout) {
// not open
if(!isOpen()) { if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false; return false;
} }
// not online
if(!isOnline()) { if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return false; return false;
} }
// not currently polling, throw error
if(!isMessagePollingEnabled()) { if(!isMessagePollingEnabled()) {
report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error); report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error);
return false; return false;
@ -395,20 +392,18 @@ bool Device::goOffline() {
return true; return true;
} }
bool Device::transmit(std::shared_ptr<Message> message) { bool Device::transmit(std::shared_ptr<Frame> frame) {
// not open
if(!isOpen()) { if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false; return false;
} }
// not online
if(!isOnline()) { if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return false; return false;
} }
if(!isSupportedTXNetwork(message->network)) { if(!isSupportedTXNetwork(frame->network)) {
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error); report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
return false; return false;
} }
@ -416,7 +411,7 @@ bool Device::transmit(std::shared_ptr<Message> message) {
bool extensionHookedTransmit = false; bool extensionHookedTransmit = false;
bool transmitStatusFromExtension = false; bool transmitStatusFromExtension = false;
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) { forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
if(!ext->transmitHook(message, transmitStatusFromExtension)) if(!ext->transmitHook(frame, transmitStatusFromExtension))
extensionHookedTransmit = true; extensionHookedTransmit = true;
return !extensionHookedTransmit; // false breaks out of the loop early return !extensionHookedTransmit; // false breaks out of the loop early
}); });
@ -424,15 +419,15 @@ bool Device::transmit(std::shared_ptr<Message> message) {
return transmitStatusFromExtension; return transmitStatusFromExtension;
std::vector<uint8_t> packet; std::vector<uint8_t> packet;
if(!com->encoder->encode(*com->packetizer, packet, message)) if(!com->encoder->encode(*com->packetizer, packet, frame))
return false; return false;
return com->sendPacket(packet); return com->sendPacket(packet);
} }
bool Device::transmit(std::vector<std::shared_ptr<Message>> messages) { bool Device::transmit(std::vector<std::shared_ptr<Frame>> frames) {
for(auto& message : messages) { for(auto& frame : frames) {
if(!transmit(message)) if(!transmit(frame))
return false; return false;
} }
return true; return true;
@ -692,11 +687,17 @@ void Device::forEachExtension(std::function<bool(const std::shared_ptr<DeviceExt
} }
void Device::handleInternalMessage(std::shared_ptr<Message> message) { void Device::handleInternalMessage(std::shared_ptr<Message> message) {
switch(message->network.getNetID()) { switch(message->type) {
case Network::NetID::Reset_Status: case Message::Type::ResetStatus:
latestResetStatus = std::dynamic_pointer_cast<ResetStatusMessage>(message); latestResetStatus = std::static_pointer_cast<ResetStatusMessage>(message);
break; break;
case Message::Type::RawMessage: {
auto rawMessage = std::static_pointer_cast<RawMessage>(message);
switch(rawMessage->network.getNetID()) {
case Network::NetID::Device: { case Network::NetID::Device: {
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
// if it couldn't be decoded to a CANMessage. We only care about the
// CANMessage decoding right now.
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message); auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg) if(canmsg)
handleNeoVIMessage(std::move(canmsg)); handleNeoVIMessage(std::move(canmsg));
@ -704,11 +705,15 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
} }
case Network::NetID::DeviceStatus: case Network::NetID::DeviceStatus:
// Device Status format is unique per device, so the devices need to decode it themselves // Device Status format is unique per device, so the devices need to decode it themselves
handleDeviceStatus(message); handleDeviceStatus(rawMessage);
break; break;
default: default:
break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl; break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl;
} }
break;
}
default: break;
}
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) { forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
ext->handleMessage(message); ext->handleMessage(message);
return true; // false breaks out early return true; // false breaks out early

View File

@ -26,18 +26,16 @@ void FlexRay::Extension::onGoOffline() {
} }
void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) { void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) {
switch(message->network.getNetID()) { switch(message->type) {
case Network::NetID::FlexRayControl: { case Message::Type::FlexRayControl: {
auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message); auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message);
if(!msg || !msg->decoded) if(!msg || !msg->decoded)
return; return;
switch(msg->opcode) { switch(msg->opcode) {
case FlexRay::Opcode::ReadCCStatus: case FlexRay::Opcode::ReadCCStatus:
if(auto status = std::dynamic_pointer_cast<FlexRayControlMessage>(message)) { // TODO else report error? if(msg->controller >= controllers.size())
if(status->controller >= controllers.size())
return; // TODO error return; // TODO error
controllers[status->controller]->_setStatus(status); controllers[msg->controller]->_setStatus(msg);
}
break; break;
} }
break; break;
@ -47,18 +45,18 @@ void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message)
} }
} }
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Message>& message, bool& success) { bool FlexRay::Extension::transmitHook(const std::shared_ptr<Frame>& frame, bool& success) {
if(!message || message->network.getType() != Network::Type::FlexRay) if(!frame || frame->network.getType() != Network::Type::FlexRay)
return true; // Don't hook non-FlexRay messages return true; // Don't hook non-FlexRay messages
success = false; success = false;
std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(message); std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(frame);
if(!frmsg) if(!frmsg)
return false; return false;
for(auto& controller : controllers) { for(auto& controller : controllers) {
if(controller->getNetwork() != message->network) if(controller->getNetwork() != frame->network)
continue; continue;
success |= controller->transmit(frmsg); success |= controller->transmit(frmsg);
} }

View File

@ -228,9 +228,9 @@ bool IDeviceSettings::apply(bool temporary) {
// Pause I/O with the device while the settings are applied // Pause I/O with the device while the settings are applied
applyingSettings = true; applyingSettings = true;
std::shared_ptr<Message> msg = com->waitForMessageSync([this, &bytestream]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)); }, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { // We did not receive a response if(!msg || msg->data[0] != 1) { // We did not receive a response
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@ -254,9 +254,9 @@ bool IDeviceSettings::apply(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)); }, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@ -267,9 +267,9 @@ bool IDeviceSettings::apply(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return com->sendCommand(Command::SaveSettings);
}, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000)); }, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; applyingSettings = false;
@ -296,9 +296,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
applyingSettings = true; applyingSettings = true;
std::shared_ptr<Message> msg = com->waitForMessageSync([this]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SetDefaultSettings); return com->sendCommand(Command::SetDefaultSettings);
}, Main51MessageFilter(Command::SetDefaultSettings), std::chrono::milliseconds(1000)); }, Main51MessageFilter(Command::SetDefaultSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@ -331,9 +331,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)); }, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@ -344,9 +344,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return com->sendCommand(Command::SaveSettings);
}, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000)); }, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; applyingSettings = false;

View File

@ -467,11 +467,13 @@ int main() {
// Print out the received messages // Print out the received messages
for(size_t i = 0; i < msgCount; i++) { for(size_t i = 0; i < msgCount; i++) {
neomessage_t* msg = &msgs[i]; const neomessage_t* msg = &msgs[i];
switch(msg->type) { switch(msg->messageType) {
case ICSNEO_NETWORK_TYPE_CAN: // CAN case ICSNEO_MESSAGE_TYPE_FRAME: {
{ const neomessage_frame_t* frame = (neomessage_frame_t*)msg;
neomessage_can_t* canMsg = (neomessage_can_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); printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length);
for(size_t i = 0; i < canMsg->length; i++) { for(size_t i = 0; i < canMsg->length; i++) {
printf("%02x ", canMsg->data[i]); printf("%02x ", canMsg->data[i]);
@ -482,10 +484,18 @@ int main() {
break; break;
} }
default: default:
if(msg->netid != 0) printf("\tMessage on netid %d with length %zu\n", frame->netid, frame->length);
printf("\tMessage on netid %d with length %zu\n", msg->netid, msg->length);
break; 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"); printf("\n");

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.2)
project(libicsneocpp-interactive-example VERSION 0.2.0) project(libicsneocpp-interactive-example VERSION 0.2.0)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED 11)
include(GNUInstallDirs) include(GNUInstallDirs)

View File

@ -182,6 +182,102 @@ std::shared_ptr<icsneo::Device> selectDevice(const std::vector<std::shared_ptr<i
return from.at(selectedDeviceNum - 1); return from.at(selectedDeviceNum - 1);
} }
void printMessage(const std::shared_ptr<icsneo::Message>& message) {
switch(message->type) {
case icsneo::Message::Type::Frame: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
std::cout << "\t\t" << frame->network << ' ';
if(canMessage->isCANFD) {
std::cout << "FD ";
if(!canMessage->baudrateSwitch)
std::cout << "(No BRS) ";
}
// Print the Arbitration ID
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3)
<< std::setfill('0') << canMessage->arbid;
// Print the DLC
std::cout << std::dec << " [" << canMessage->data.size() << "] ";
// Print the data
for(auto& databyte : canMessage->data)
std::cout << std::hex << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp
std::cout << std::dec << '(' << canMessage->timestamp << " ns since 1/1/2007)\n";
break;
}
case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
<< ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
// Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) {
if(i % 8 == 0)
std::cout << "\n\t\t " << std::hex << std::setw(4) << std::setfill('0') << i << '\t';
std::cout << std::hex << std::setw(2) << (uint32_t)ethMessage->data[i] << ' ';
}
std::cout << std::dec << std::endl;
break;
}
case icsneo::Network::Type::ISO9141: {
// Note that the default settings on some devices have ISO9141 disabled by default in favor of LIN
// and that this example loads the device defaults at the very end.
// A message of type ISO9414 is guaranteed to be an ISO9141Message, so we can static cast safely
auto isoMessage = std::static_pointer_cast<icsneo::ISO9141Message>(message);
std::cout << "\t\t" << isoMessage->network << ' ';
// Print the header bytes
std::cout << '(' << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[0] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[1] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[2] << ") ";
// Print the data length
std::cout << std::dec << " [" << isoMessage->data.size() << "] ";
// Print the data
for(auto& databyte : isoMessage->data)
std::cout << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp
std::cout << std::dec << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
break;
}
default:
// Ignoring non-network messages
break;
}
break;
} // end of icsneo::Message::Type::Frame
case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message);
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << cec->receiveErrorCount
<< " TEC=" << cec->transmitErrorCount << " (" << (cec->busOff ? "" : "Not ") << "Bus Off)" << std::endl;
break;
}
default:
// Ignoring other types of messages
break;
}
}
int main() { int main() {
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl << std::endl; std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl << std::endl;
@ -392,28 +488,8 @@ int main() {
} }
// Print out the received messages // Print out the received messages
for(auto msg : msgs) { for(const auto& msg : msgs)
switch(msg->network.getType()) { printMessage(msg);
case icsneo::Network::Type::CAN:
{
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
std::cout << "\t0x" << std::setfill('0') << std::setw(3) << std::hex << (int) canMsg->arbid << " [" << canMsg->data.size() << "] " << std::dec;
for(auto data : canMsg->data) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int) data << " " << std::dec;
}
std::cout << canMsg->timestamp << std::endl;
break;
}
default:
if(msg->network.getNetID() != icsneo::Network::NetID::Device) {
std::cout << "\tMessage on netid " << msg->network.GetNetIDString(msg->network.getNetID()) << " with length " << msg->data.size() << std::endl;
}
break;
}
}
std::cout << std::endl; std::cout << std::endl;
} }
@ -538,28 +614,8 @@ int main() {
switch(selection) { switch(selection) {
case '1': case '1':
{ {
// Shameless copy-paste from get messages above, demonstrating a callback
int callbackID = selectedDevice->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> msg){ int callbackID = selectedDevice->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> msg){
switch(msg->network.getType()) { printMessage(msg);
case icsneo::Network::Type::CAN:
{
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
std::cout << "\t0x" << std::setfill('0') << std::setw(3) << std::hex << (int) canMsg->arbid << " [" << canMsg->data.size() << "] " << std::dec;
for(auto data : canMsg->data) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int) data << " " << std::dec;
}
std::cout << canMsg->timestamp << std::endl;
break;
}
default:
if(msg->network.getNetID() != icsneo::Network::NetID::Device) {
std::cout << "\tMessage on netid " << msg->network.GetNetIDString(msg->network.getNetID()) << " with length " << msg->data.size() << std::endl;
}
break;
}
})); }));
if(callbackID != -1) { if(callbackID != -1) {

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.2)
project(libicsneocpp-simple-example VERSION 0.2.0) project(libicsneocpp-simple-example VERSION 0.2.0)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED 11)
include(GNUInstallDirs) include(GNUInstallDirs)

View File

@ -126,16 +126,32 @@ int main() {
device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k
// Keep in mind that 20k messages comes quickly at high bus loads! // Keep in mind that 20k messages comes quickly at high bus loads!
// We can transmit messages
std::cout << "\tTransmitting an extended CAN FD frame... ";
auto txMessage5 = std::make_shared<icsneo::CANMessage>();
txMessage5->network = icsneo::Network::NetID::HSCAN;
txMessage5->arbid = 0x1C5001C5;
txMessage5->data.insert(txMessage5->data.end(), {0xaa, 0xbb, 0xcc});
// The DLC will come from the length of the data vector
txMessage5->isExtended = true;
txMessage5->isCANFD = true;
ret = device->transmit(txMessage5); // This will return false if the device does not support CAN FD, or does not have HSCAN
std::cout << (ret ? "OK" : "FAIL") << std::endl;
// We can also register a handler // We can also register a handler
std::cout << "\tStreaming messages in for 3 seconds... " << std::endl; std::cout << "\tStreaming messages in for 3 seconds... " << std::endl;
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation // MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) { auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) {
switch(message->network.getType()) { switch(message->type) {
case icsneo::Message::Type::Frame: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: { case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely // A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message); auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
std::cout << "\t\tCAN "; std::cout << "\t\t" << frame->network << ' ';
if(canMessage->isCANFD) { if(canMessage->isCANFD) {
std::cout << "FD "; std::cout << "FD ";
if(!canMessage->baudrateSwitch) if(!canMessage->baudrateSwitch)
@ -143,7 +159,8 @@ int main() {
} }
// Print the Arbitration ID // Print the Arbitration ID
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3) << std::setfill('0') << canMessage->arbid; std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3)
<< std::setfill('0') << canMessage->arbid;
// Print the DLC // Print the DLC
std::cout << std::dec << " [" << canMessage->data.size() << "] "; std::cout << std::dec << " [" << canMessage->data.size() << "] ";
@ -159,7 +176,8 @@ int main() {
case icsneo::Network::Type::Ethernet: { case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message); auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec << ethMessage->data.size() << " bytes on wire\n"; std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
<< ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n"; std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member // The MACAddress may be printed directly or accessed with the `data` member
@ -204,6 +222,24 @@ int main() {
// Ignoring non-network messages // Ignoring non-network messages
break; break;
} }
break;
} // end of icsneo::Message::Type::Frame
case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message);
// Print the error counts
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount)
<< " TEC=" << std::to_string(cec->transmitErrorCount) << " (" << (cec->busOff ? "" : "Not ") << "Bus Off) ";
// Print the timestamp
std::cout << std::dec << '(' << cec->timestamp << " ns since 1/1/2007)\n";
break;
}
default:
// Ignoring other types of messages
break;
}
})); }));
std::this_thread::sleep_for(std::chrono::seconds(3)); std::this_thread::sleep_for(std::chrono::seconds(3));
device->removeMessageCallback(handler); // Removing the callback means it will not be called anymore device->removeMessageCallback(handler); // Removing the callback means it will not be called anymore

View File

@ -0,0 +1,25 @@
#ifndef __CANERRORCOUNTMESSAGE_H_
#define __CANERRORCOUNTMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
namespace icsneo {
class CANErrorCountMessage : public Message {
public:
CANErrorCountMessage(uint8_t tec, uint8_t rec, bool busOffFlag)
: Message(Message::Type::CANErrorCount), transmitErrorCount(tec), receiveErrorCount(rec), busOff(busOffFlag){}
Network network;
uint8_t transmitErrorCount;
uint8_t receiveErrorCount;
bool busOff;
};
}
#endif // __cplusplus
#endif

View File

@ -7,7 +7,7 @@
namespace icsneo { namespace icsneo {
class CANMessage : public Message { class CANMessage : public Frame {
public: public:
uint32_t arbid; uint32_t arbid;
uint8_t dlcOnWire; uint8_t dlcOnWire;

View File

@ -31,7 +31,7 @@ struct MACAddress {
} }
}; };
class EthernetMessage : public Message { class EthernetMessage : public Frame {
public: public:
bool preemptionEnabled = false; bool preemptionEnabled = false;
uint8_t preemptionFlags = 0; uint8_t preemptionFlags = 0;

View File

@ -13,8 +13,8 @@ namespace icsneo {
class CANMessageFilter : public MessageFilter { class CANMessageFilter : public MessageFilter {
public: public:
CANMessageFilter() : MessageFilter(Network::Type::CAN), arbid(INVALID_ARBID) {} CANMessageFilter() : MessageFilter(Network::Type::CAN), arbid(INVALID_ARBID) { messageType = Message::Type::Frame; }
CANMessageFilter(uint32_t arbid) : MessageFilter(Network::Type::CAN), arbid(arbid) {} CANMessageFilter(uint32_t arbid) : MessageFilter(Network::Type::CAN), arbid(arbid) { messageType = Message::Type::Frame; }
bool match(const std::shared_ptr<Message>& message) const { bool match(const std::shared_ptr<Message>& message) const {
if(!MessageFilter::match(message)) if(!MessageFilter::match(message))

View File

@ -14,8 +14,10 @@ namespace icsneo {
class Main51MessageFilter : public MessageFilter { class Main51MessageFilter : public MessageFilter {
public: public:
Main51MessageFilter() : MessageFilter(Network::NetID::Main51), command(INVALID_COMMAND) {} Main51MessageFilter() : MessageFilter(Message::Type::Main51), command(INVALID_COMMAND) {}
Main51MessageFilter(Command command) : MessageFilter(Network::NetID::Main51), command(command) {} // Don't filter on Type::Main51 for Command as some Commands have their own type
// We still guarantee it's a Main51Message if it matches because of the dynamic_pointer_cast below
Main51MessageFilter(Command command) : command(command) { includeInternalInAny = true; }
bool match(const std::shared_ptr<Message>& message) const { bool match(const std::shared_ptr<Message>& message) const {
if(!MessageFilter::match(message)) { if(!MessageFilter::match(message)) {

View File

@ -12,26 +12,44 @@ namespace icsneo {
class MessageFilter { class MessageFilter {
public: public:
MessageFilter() {} MessageFilter() {}
MessageFilter(Network::Type type) : type(type) {} MessageFilter(Message::Type type) : includeInternalInAny(neomessagetype_t(type) & 0x8000), messageType(type) {}
MessageFilter(Network::NetID netid) : type(Network::GetTypeOfNetID(netid)), netid(netid) {} MessageFilter(Network::NetID netid) : MessageFilter(Network::GetTypeOfNetID(netid), netid) {}
virtual ~MessageFilter() {} MessageFilter(Network::Type type, Network::NetID net = Network::NetID::Any) : networkType(type), netid(net) {
// If a Network::Type::Internal is used, we want to also get internal Message::Types
// The NetID we want may be in there
includeInternalInAny = (networkType == Network::Type::Internal);
}
virtual ~MessageFilter() = default;
// When getting "all" types of messages, include the ones marked as "internal only" // When getting "all" types of messages, include the ones marked as "internal only"
bool includeInternalInAny = false; bool includeInternalInAny = false;
virtual bool match(const std::shared_ptr<Message>& message) const { virtual bool match(const std::shared_ptr<Message>& message) const {
if(!matchType(message->network.getType())) if(!matchMessageType(message->type))
return false; return false;
if(!matchNetID(message->network.getNetID()))
if(message->type == Message::Type::Frame) {
Frame& frame = *static_cast<Frame*>(message.get());
if(!matchNetworkType(frame.network.getType()))
return false; return false;
if(!matchNetID(frame.network.getNetID()))
return false;
}
return true; return true;
} }
private: protected:
Network::Type type = Network::Type::Any; Message::Type messageType = Message::Type::Invalid; // Used here for "any"
bool matchType(Network::Type mtype) const { bool matchMessageType(Message::Type mtype) const {
if(type == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny)) if(messageType == Message::Type::Invalid && ((neomessagetype_t(mtype) & 0x8000) == 0 || includeInternalInAny))
return true; return true;
return type == mtype; return messageType == mtype;
}
Network::Type networkType = Network::Type::Any;
bool matchNetworkType(Network::Type mtype) const {
if(networkType == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny))
return true;
return networkType == mtype;
} }
Network::NetID netid = Network::NetID::Any; Network::NetID netid = Network::NetID::Any;

View File

@ -23,7 +23,7 @@ public:
uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize); uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize);
FlexRayControlMessage(const Packet& packet); FlexRayControlMessage(const Packet& packet);
virtual ~FlexRayControlMessage() = default;
bool decoded = false; bool decoded = false;
uint8_t controller = 0xff; // Controller index, either 0 or 1 uint8_t controller = 0xff; // Controller index, either 0 or 1
FlexRay::Opcode opcode = FlexRay::Opcode::Unknown; FlexRay::Opcode opcode = FlexRay::Opcode::Unknown;

View File

@ -10,7 +10,7 @@
namespace icsneo { namespace icsneo {
class FlexRayMessage : public Message { class FlexRayMessage : public Frame {
public: public:
uint16_t slotid = 0; uint16_t slotid = 0;
double tsslen = 0; double tsslen = 0;

View File

@ -8,7 +8,7 @@
namespace icsneo { namespace icsneo {
class ISO9141Message : public Message { class ISO9141Message : public Frame {
public: public:
std::array<uint8_t, 3> header; std::array<uint8_t, 3> header;
bool isInit = false; bool isInit = false;

View File

@ -8,9 +8,9 @@
namespace icsneo { namespace icsneo {
class Main51Message : public Message { class Main51Message : public RawMessage {
public: public:
virtual ~Main51Message() = default; Main51Message() : RawMessage(Message::Type::Main51, Network::NetID::Main51) {}
Command command = Command(0); Command command = Command(0);
bool forceShortFormat = false; // Necessary for EnableNetworkCom and EnableNetworkComEx bool forceShortFormat = false; // Necessary for EnableNetworkCom and EnableNetworkComEx
}; };

View File

@ -1,6 +1,9 @@
#ifndef __MESSAGE_H_ #ifndef __MESSAGE_H_
#define __MESSAGE_H_ #define __MESSAGE_H_
#include <stdint.h>
typedef uint16_t neomessagetype_t;
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/network.h" #include "icsneo/communication/network.h"
@ -10,10 +13,42 @@ namespace icsneo {
class Message { class Message {
public: public:
enum class Type : neomessagetype_t {
Frame = 0,
CANErrorCount = 0x100,
// Past 0x8000 are all for internal use only
Invalid = 0x8000,
RawMessage = 0x8001,
ReadSettings = 0x8002,
ResetStatus = 0x8003,
DeviceVersion = 0x8004,
Main51 = 0x8005,
FlexRayControl = 0x8006,
};
Message(Type t) : type(t) {}
virtual ~Message() = default; virtual ~Message() = default;
const Type type;
uint64_t timestamp = 0;
};
class RawMessage : public Message {
public:
RawMessage(Message::Type type = Message::Type::RawMessage) : Message(type) {}
RawMessage(Message::Type type, Network net) : Message(type), network(net) {}
RawMessage(Network net) : Message(Message::Type::RawMessage), network(net) {}
RawMessage(Network net, std::vector<uint8_t> d) : Message(Message::Type::RawMessage), network(net), data(d) {}
Network network; Network network;
std::vector<uint8_t> data; std::vector<uint8_t> data;
uint64_t timestamp = 0; };
class Frame : public RawMessage {
public:
Frame() : RawMessage(Message::Type::Frame) {}
uint16_t description = 0; uint16_t description = 0;
bool transmitted = false; bool transmitted = false;
bool error = false; bool error = false;
@ -23,4 +58,18 @@ public:
#endif // __cplusplus #endif // __cplusplus
#ifdef __ICSNEOC_H_
#define ICSNEO_MESSAGE_TYPE_FRAME (0x0)
#define ICSNEO_MESSAGE_TYPE_CAN_ERROR_COUNT (0x100)
#define ICSNEO_MESSAGE_TYPE_INVALID (0x8000)
#define ICSNEO_MESSAGE_TYPE_RAW_MESSAGE (0x8001)
#define ICSNEO_MESSAGE_TYPE_READ_SETTINGS (0x8002)
#define ICSNEO_MESSAGE_TYPE_RESET_STATUS (0x8003)
#define ICSNEO_MESSAGE_TYPE_DEVICE_VERSION (0x8004)
#define ICSNEO_MESSAGE_TYPE_MAIN51 (0x8005)
#define ICSNEO_MESSAGE_TYPE_FLEXRAY_CONTROL (0x8006)
#endif // __ICSNEOC_H_
#endif #endif

View File

@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "icsneo/communication/network.h" #include "icsneo/communication/network.h"
#include "icsneo/communication/message/message.h"
#pragma pack(push, 1) #pragma pack(push, 1)
@ -18,12 +19,12 @@ typedef union {
uint32_t extendedFrame : 1; uint32_t extendedFrame : 1;
uint32_t remoteFrame : 1; uint32_t remoteFrame : 1;
uint32_t crcError : 1; uint32_t crcError : 1;
uint32_t canErrorPassive : 1; uint32_t canErrorPassive : 1; // Occupies the same space as headerCRCError
uint32_t incompleteFrame : 1; uint32_t incompleteFrame : 1;
uint32_t lostArbitration : 1; uint32_t lostArbitration : 1;
uint32_t undefinedError : 1; uint32_t undefinedError : 1;
uint32_t canBusOff : 1; uint32_t canBusOff : 1;
uint32_t canErrorWarning : 1; uint32_t canBusRecovered : 1;
uint32_t canBusShortedPlus : 1; uint32_t canBusShortedPlus : 1;
uint32_t canBusShortedGround : 1; uint32_t canBusShortedGround : 1;
uint32_t checksumError : 1; uint32_t checksumError : 1;
@ -101,24 +102,34 @@ typedef union {
#endif #endif
typedef struct { typedef struct {
neomessage_statusbitfield_t status; uint8_t _reserved1[16];
uint64_t timestamp; uint64_t timestamp;
uint64_t timestampReserved; uint64_t _reservedTimestamp;
const uint8_t* data; uint8_t _reserved2[sizeof(size_t) * 2 + 7 + sizeof(neonetid_t) + sizeof(neonettype_t)];
size_t length; neomessagetype_t messageType;
uint8_t header[4]; uint8_t _reserved3[12];
neonetid_t netid;
neonettype_t type;
uint8_t reserved0;
uint16_t description;
uint8_t reserved1[14];
} neomessage_t; // 72 bytes total } neomessage_t; // 72 bytes total
// Any time you add another neomessage_*_t type, make sure to add it to the static_asserts below! // Any time you add another neomessage_*_t type, make sure to add it to the static_asserts below!
typedef struct { typedef struct {
neomessage_statusbitfield_t status; neomessage_statusbitfield_t status;
uint64_t timestamp; uint64_t timestamp;
uint64_t timestampReserved; uint64_t _reservedTimestamp;
const uint8_t* data;
size_t length;
uint8_t header[4];
neonetid_t netid;
neonettype_t type;
uint8_t _reserved0;
uint16_t description;
neomessagetype_t messageType;
uint8_t _reserved1[12];
} neomessage_frame_t;
typedef struct {
neomessage_statusbitfield_t status;
uint64_t timestamp;
uint64_t _reservedTimestamp;
const uint8_t* data; const uint8_t* data;
size_t length; size_t length;
uint32_t arbid; uint32_t arbid;
@ -126,22 +137,38 @@ typedef struct {
neonettype_t type; neonettype_t type;
uint8_t dlcOnWire; uint8_t dlcOnWire;
uint16_t description; uint16_t description;
uint8_t reserved[14]; neomessagetype_t messageType;
uint8_t _reserved1[12];
} neomessage_can_t; } neomessage_can_t;
typedef struct { typedef struct {
neomessage_statusbitfield_t status; neomessage_statusbitfield_t status;
uint64_t timestamp; uint64_t timestamp;
uint64_t timestampReserved; uint64_t _reservedTimestamp;
size_t _reserved2[2];
uint8_t transmitErrorCount;
uint8_t receiveErrorCount;
uint8_t _reserved3[5];
neonetid_t netid;
neonettype_t type;
neomessagetype_t messageType;
uint8_t _reserved4[12];
} neomessage_can_error_t;
typedef struct {
neomessage_statusbitfield_t status;
uint64_t timestamp;
uint64_t _reservedTimestamp;
const uint8_t* data; const uint8_t* data;
size_t length; size_t length;
uint8_t preemptionFlags; uint8_t preemptionFlags;
uint8_t reservedHeader[3]; uint8_t _reservedHeader[3];
neonetid_t netid; neonetid_t netid;
neonettype_t type; neonettype_t type;
uint8_t reserved0; uint8_t _reserved0;
uint16_t description; uint16_t description;
uint8_t reserved1[14]; neomessagetype_t messageType;
uint8_t _reserved1[12];
} neomessage_eth_t; } neomessage_eth_t;
#pragma pack(pop) #pragma pack(pop)
@ -151,7 +178,9 @@ typedef struct {
#include <memory> #include <memory>
static_assert(sizeof(neomessage_t) == (56 + sizeof(void*) + sizeof(size_t)), "neomessage_t size is incorrect! Changing size will break compatibility with existing C API programs."); static_assert(sizeof(neomessage_t) == (56 + sizeof(void*) + sizeof(size_t)), "neomessage_t size is incorrect! Changing size will break compatibility with existing C API programs.");
static_assert(sizeof(neomessage_frame_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Base frame is not)");
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_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_eth_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Ethernet is not)");
namespace icsneo { namespace icsneo {

View File

@ -8,9 +8,9 @@
namespace icsneo { namespace icsneo {
class ReadSettingsMessage : public Message { class ReadSettingsMessage : public RawMessage {
public: public:
virtual ~ReadSettingsMessage() = default; ReadSettingsMessage() : RawMessage(Message::Type::ReadSettings, Network::NetID::ReadSettings) {}
enum class Response : uint8_t { enum class Response : uint8_t {
OK = 0, OK = 0,

View File

@ -11,8 +11,8 @@ namespace icsneo {
class ResetStatusMessage : public Message { class ResetStatusMessage : public Message {
public: public:
ResetStatusMessage() : Message() {} ResetStatusMessage() : Message(Message::Type::ResetStatus) {}
virtual ~ResetStatusMessage() = default;
uint16_t mainLoopTime; uint16_t mainLoopTime;
uint16_t maxMainLoopTime; uint16_t maxMainLoopTime;
bool justReset; bool justReset;

View File

@ -11,13 +11,18 @@ namespace icsneo {
class VersionMessage : public Message { class VersionMessage : public Message {
public: public:
VersionMessage(bool main) : MainChip(main) { network = Network::NetID::Main51; } enum Chip : uint8_t {
MainChip,
SecondaryChips
};
// If true, the included version is for the main chip VersionMessage(Chip chip) : Message(Message::Type::DeviceVersion), ForChip(chip) {}
const bool MainChip;
// nullopt here indicates invalid // nullopt here indicates invalid
std::vector< optional<DeviceAppVersion> > Versions; std::vector< optional<DeviceAppVersion> > Versions;
// What chips the versions are for
const Chip ForChip;
}; };
} }

View File

@ -13,7 +13,7 @@ namespace icsneo {
typedef uint16_t icscm_bitfield; typedef uint16_t icscm_bitfield;
struct HardwareCANPacket { struct HardwareCANPacket {
static std::shared_ptr<CANMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream); static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report); static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
struct { struct {

View File

@ -121,8 +121,8 @@ public:
int addMessageCallback(const MessageCallback& cb) { return com->addMessageCallback(cb); } int addMessageCallback(const MessageCallback& cb) { return com->addMessageCallback(cb); }
bool removeMessageCallback(int id) { return com->removeMessageCallback(id); } bool removeMessageCallback(int id) { return com->removeMessageCallback(id); }
bool transmit(std::shared_ptr<Message> message); bool transmit(std::shared_ptr<Frame> frame);
bool transmit(std::vector<std::shared_ptr<Message>> messages); bool transmit(std::vector<std::shared_ptr<Frame>> frames);
void setWriteBlocks(bool blocks); void setWriteBlocks(bool blocks);
@ -328,7 +328,7 @@ protected:
void handleInternalMessage(std::shared_ptr<Message> message); void handleInternalMessage(std::shared_ptr<Message> message);
virtual void handleDeviceStatus(const std::shared_ptr<Message>&) {} virtual void handleDeviceStatus(const std::shared_ptr<RawMessage>&) {}
neodevice_t& getWritableNeoDevice() { return data; } neodevice_t& getWritableNeoDevice() { return data; }

View File

@ -33,7 +33,7 @@ public:
virtual void handleMessage(const std::shared_ptr<Message>&) {} virtual void handleMessage(const std::shared_ptr<Message>&) {}
// Return true to continue transmitting, success should be written to if false is returned // Return true to continue transmitting, success should be written to if false is returned
virtual bool transmitHook(const std::shared_ptr<Message>& message, bool& success) { (void)message; (void)success; return true; } virtual bool transmitHook(const std::shared_ptr<Frame>& frame, bool& success) { (void)frame; (void)success; return true; }
protected: protected:
Device& device; Device& device;

View File

@ -25,7 +25,7 @@ public:
void onGoOffline() override; void onGoOffline() override;
void handleMessage(const std::shared_ptr<Message>& message) override; void handleMessage(const std::shared_ptr<Message>& message) override;
bool transmitHook(const std::shared_ptr<Message>& message, bool& success) override; bool transmitHook(const std::shared_ptr<Frame>& frame, bool& success) override;
std::shared_ptr<Controller> getController(uint8_t index) const { std::shared_ptr<Controller> getController(uint8_t index) const {
if(index >= controllers.size()) if(index >= controllers.size())

View File

@ -104,11 +104,12 @@ protected:
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(neovifire2_status_t)) const auto& data = message->data;
if(data.size() < sizeof(neovifire2_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const neovifire2_status_t* status = reinterpret_cast<const neovifire2_status_t*>(message->data.data()); const neovifire2_status_t* status = reinterpret_cast<const neovifire2_status_t*>(data.data());
backupPowerEnabled = status->backupPowerEnabled; backupPowerEnabled = status->backupPowerEnabled;
backupPowerGood = status->backupPowerGood; backupPowerGood = status->backupPowerGood;
ethActivationStatus = status->ethernetActivationLineEnabled; ethActivationStatus = status->ethernetActivationLineEnabled;

View File

@ -24,7 +24,7 @@ public:
if (!fakedev->com->decoder->decode(msg, packet)) if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51) if(!msg || msg->type != Message::Type::Main51)
continue; // Not a message we care about continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg); auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn) if(!sn)

View File

@ -80,11 +80,12 @@ protected:
return ret; return ret;
} }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(fire2vnet_status_t)) const auto& data = message->data;
if(data.size() < sizeof(fire2vnet_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const fire2vnet_status_t* status = reinterpret_cast<const fire2vnet_status_t*>(message->data.data()); const fire2vnet_status_t* status = reinterpret_cast<const fire2vnet_status_t*>(data.data());
ethActivationStatus = status->ethernetActivationLineEnabled; ethActivationStatus = status->ethernetActivationLineEnabled;
} }

View File

@ -30,7 +30,7 @@ public:
if(!fakedev->com->decoder->decode(msg, packet)) if(!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51) if(!msg || msg->type != Message::Type::Main51)
continue; // Not a message we care about continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg); auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn) if(!sn)
@ -118,11 +118,12 @@ protected:
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(radgalaxy_status_t)) const auto& data = message->data;
if(data.size() < sizeof(radgalaxy_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const radgalaxy_status_t* status = reinterpret_cast<const radgalaxy_status_t*>(message->data.data()); const radgalaxy_status_t* status = reinterpret_cast<const radgalaxy_status_t*>(data.data());
ethActivationStatus = status->ethernetActivationLineEnabled; ethActivationStatus = status->ethernetActivationLineEnabled;
} }
}; };

View File

@ -77,11 +77,12 @@ protected:
txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end()); txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end());
} }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(radgigalog_status_t)) const auto& data = message->data;
if(data.size() < sizeof(radgigalog_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const radgigalog_status_t* status = reinterpret_cast<const radgigalog_status_t*>(message->data.data()); const radgigalog_status_t* status = reinterpret_cast<const radgigalog_status_t*>(data.data());
ethActivationStatus = status->ethernetActivationLineEnabled; ethActivationStatus = status->ethernetActivationLineEnabled;
} }
}; };

View File

@ -23,7 +23,7 @@ public:
if (!fakedev->com->decoder->decode(msg, packet)) if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51) if(!msg || msg->type != Message::Type::Main51)
continue; // Not a message we care about continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg); auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn) if(!sn)

View File

@ -81,11 +81,12 @@ protected:
txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end()); txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end());
} }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(radgigastar_status_t)) const auto& data = message->data;
if(data.size() < sizeof(radgigastar_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const radgigastar_status_t* status = reinterpret_cast<const radgigastar_status_t*>(message->data.data()); const radgigastar_status_t* status = reinterpret_cast<const radgigastar_status_t*>(data.data());
ethActivationStatus = status->ethernetActivationLineEnabled; ethActivationStatus = status->ethernetActivationLineEnabled;
} }
}; };

View File

@ -23,7 +23,7 @@ public:
if (!fakedev->com->decoder->decode(msg, packet)) if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51) if(!msg || msg->type != Message::Type::Main51)
continue; // Not a message we care about continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg); auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn) if(!sn)

View File

@ -25,7 +25,7 @@ public:
if(!fakedev->com->decoder->decode(msg, packet)) if(!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51) if(!msg || msg->type != Message::Type::Main51)
continue; // Not a message we care about continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg); auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn) if(!sn)

View File

@ -73,11 +73,12 @@ protected:
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(valuecan4_2el_status_t)) const auto& data = message->data;
if(data.size() < sizeof(valuecan4_2el_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const valuecan4_2el_status_t* status = reinterpret_cast<const valuecan4_2el_status_t*>(message->data.data()); const valuecan4_2el_status_t* status = reinterpret_cast<const valuecan4_2el_status_t*>(data.data());
ethActivationStatus = status->ethernetActivationLineEnabled; ethActivationStatus = status->ethernetActivationLineEnabled;
} }
}; };

View File

@ -25,7 +25,7 @@ public:
if (!fakedev->com->decoder->decode(msg, packet)) if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51) if(!msg || msg->type != Message::Type::Main51)
continue; // Not a message we care about continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg); auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn) if(!sn)

View File

@ -25,7 +25,7 @@ public:
if (!fakedev->com->decoder->decode(msg, packet)) if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51) if(!msg || msg->type != Message::Type::Main51)
continue; // Not a message we care about continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg); auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn) if(!sn)

View File

@ -14,6 +14,7 @@
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/flexray/flexraymessage.h" #include "icsneo/communication/message/flexray/flexraymessage.h"
#include "icsneo/communication/message/iso9141message.h" #include "icsneo/communication/message/iso9141message.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
namespace icsneo { namespace icsneo {