mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 01:18:36 +02:00
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.
This commit is contained in:
@@ -29,7 +29,7 @@ bool Communication::open() {
|
||||
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if(!driver->open())
|
||||
return false;
|
||||
spawnThreads();
|
||||
@@ -114,7 +114,7 @@ bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::mil
|
||||
return false;
|
||||
}
|
||||
|
||||
data = std::move(msg->data);
|
||||
data = std::move(gsmsg->data);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chr
|
||||
auto m51 = std::dynamic_pointer_cast<Main51Message>(msg);
|
||||
if(!m51) // Could not upcast for some reason
|
||||
return std::shared_ptr<SerialNumberMessage>();
|
||||
|
||||
|
||||
return std::dynamic_pointer_cast<SerialNumberMessage>(m51);
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersions
|
||||
if(!ver) // Could not upcast for some reason
|
||||
return nullopt;
|
||||
|
||||
if(!ver->MainChip || ver->Versions.size() != 1)
|
||||
if(ver->ForChip != VersionMessage::MainChip || ver->Versions.size() != 1)
|
||||
return nullopt;
|
||||
|
||||
ret.push_back(ver->Versions.front());
|
||||
@@ -155,9 +155,8 @@ optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersions
|
||||
}, Main51MessageFilter(Command::GetSecondaryVersions), timeout);
|
||||
if(msg) { // This one is allowed to fail
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -231,7 +230,7 @@ void Communication::readTask() {
|
||||
std::vector<uint8_t> readBytes;
|
||||
|
||||
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||
|
||||
|
||||
while(!closing) {
|
||||
readBytes.clear();
|
||||
if(driver->readWait(readBytes)) {
|
||||
|
||||
+46
-25
@@ -3,6 +3,7 @@
|
||||
#include "icsneo/communication/message/serialnumbermessage.h"
|
||||
#include "icsneo/communication/message/resetstatusmessage.h"
|
||||
#include "icsneo/communication/message/readsettingsmessage.h"
|
||||
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
||||
#include "icsneo/communication/command.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) {
|
||||
switch(packet->network.getType()) {
|
||||
case Network::Type::Ethernet:
|
||||
case Network::Type::Ethernet: {
|
||||
result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
|
||||
if(!result) {
|
||||
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
|
||||
// The resolution depends on the device
|
||||
result->timestamp *= timestampResolution;
|
||||
result->network = packet->network;
|
||||
EthernetMessage& eth = *static_cast<EthernetMessage*>(result.get());
|
||||
eth.timestamp *= timestampResolution;
|
||||
eth.network = packet->network;
|
||||
return true;
|
||||
}
|
||||
case Network::Type::CAN:
|
||||
case Network::Type::SWCAN:
|
||||
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);
|
||||
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
|
||||
// The resolution depends on the device
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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
|
||||
// The resolution depends on the device
|
||||
result->timestamp *= timestampResolution;
|
||||
result->network = packet->network;
|
||||
FlexRayMessage& fr = *static_cast<FlexRayMessage*>(result.get());
|
||||
fr.timestamp *= timestampResolution;
|
||||
fr.network = packet->network;
|
||||
return true;
|
||||
}
|
||||
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
|
||||
// The resolution depends on the device
|
||||
result->timestamp *= timestampResolution;
|
||||
result->network = packet->network;
|
||||
ISO9141Message& iso = *static_cast<ISO9141Message*>(result.get());
|
||||
iso.timestamp *= timestampResolution;
|
||||
iso.network = packet->network;
|
||||
return true;
|
||||
}
|
||||
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();
|
||||
auto msg = std::make_shared<ResetStatusMessage>();
|
||||
msg->network = packet->network;
|
||||
msg->mainLoopTime = data->main_loop_time_25ns * 25;
|
||||
msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25;
|
||||
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
|
||||
// passing them onto the user.
|
||||
if(packet->data.size() < 24) {
|
||||
result = std::make_shared<Message>();
|
||||
result->network = packet->network;
|
||||
result->data = packet->data;
|
||||
auto rawmsg = std::make_shared<RawMessage>(Network::NetID::Device);
|
||||
result = rawmsg;
|
||||
rawmsg->data = packet->data;
|
||||
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);
|
||||
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
|
||||
// The resolution depends on the device
|
||||
result->timestamp *= timestampResolution;
|
||||
result->network = packet->network;
|
||||
auto* raw = dynamic_cast<RawMessage*>(result.get());
|
||||
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;
|
||||
}
|
||||
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
|
||||
result->data = packet->data;
|
||||
result = std::make_shared<RawMessage>(packet->network, packet->data);
|
||||
return true;
|
||||
}
|
||||
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]) {
|
||||
case Command::RequestSerialNumber: {
|
||||
auto msg = std::make_shared<SerialNumberMessage>();
|
||||
msg->network = packet->network;
|
||||
uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1);
|
||||
// The device sends 64-bits of serial number, but we never use more than 32-bits.
|
||||
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:
|
||||
auto msg = std::make_shared<Main51Message>();
|
||||
msg->network = packet->network;
|
||||
msg->command = Command(packet->data[0]);
|
||||
msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end());
|
||||
result = msg;
|
||||
@@ -218,9 +243,8 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||
}
|
||||
case Network::NetID::ReadSettings: {
|
||||
auto msg = std::make_shared<ReadSettingsMessage>();
|
||||
msg->network = packet->network;
|
||||
msg->response = ReadSettingsMessage::Response(packet->data[0]);
|
||||
|
||||
|
||||
if(msg->response == ReadSettingsMessage::Response::OK) {
|
||||
// The global settings structure is the payload of the message in this case
|
||||
msg->data.insert(msg->data.begin(), packet->data.begin() + 10, packet->data.end());
|
||||
@@ -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
|
||||
auto msg = std::make_shared<Message>();
|
||||
msg->network = packet->network;
|
||||
msg->data = packet->data;
|
||||
result = msg;
|
||||
result = std::make_shared<RawMessage>(packet->network, packet->data);
|
||||
return true;
|
||||
}
|
||||
+114
-90
@@ -9,119 +9,144 @@ using namespace icsneo;
|
||||
|
||||
bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
|
||||
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();
|
||||
|
||||
switch(message->network.getType()) {
|
||||
case Network::Type::Ethernet: {
|
||||
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
|
||||
if(!ethmsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false; // The message was not a properly formed EthernetMessage
|
||||
}
|
||||
switch(message->type) {
|
||||
case Message::Type::Frame: {
|
||||
auto frame = std::dynamic_pointer_cast<Frame>(message);
|
||||
|
||||
useResultAsBuffer = true;
|
||||
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
|
||||
return false;
|
||||
// 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: {
|
||||
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
|
||||
if(!ethmsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false; // The message was not a properly formed EthernetMessage
|
||||
}
|
||||
|
||||
buffer = &result;
|
||||
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
|
||||
return false;
|
||||
|
||||
break;
|
||||
} // End of Network::Type::Ethernet
|
||||
case Network::Type::CAN:
|
||||
case Network::Type::SWCAN:
|
||||
case Network::Type::LSFTCAN: {
|
||||
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
|
||||
if(!canmsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false; // The message was not a properly formed CANMessage
|
||||
}
|
||||
|
||||
if(!supportCANFD && canmsg->isCANFD) {
|
||||
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
|
||||
return false; // This device does not support CAN FD
|
||||
}
|
||||
|
||||
buffer = &result;
|
||||
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
|
||||
return false; // The CANMessage was malformed
|
||||
|
||||
break;
|
||||
} // End of Network::Type::CAN
|
||||
case Network::Type::ISO9141: {
|
||||
auto isomsg = std::dynamic_pointer_cast<ISO9141Message>(message);
|
||||
if(!isomsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false; // The message was not a properly formed ISO9141Message
|
||||
}
|
||||
|
||||
// Skip the normal message wrapping at the bottom since we need to send multiple
|
||||
// packets to the device. This function just encodes them back to back into `result`
|
||||
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
|
||||
} // End of Network::Type::ISO9141
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
} // End of Network::Type::Ethernet
|
||||
case Network::Type::CAN:
|
||||
case Network::Type::SWCAN:
|
||||
case Network::Type::LSFTCAN: {
|
||||
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
|
||||
if(!canmsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false; // The message was not a properly formed CANMessage
|
||||
}
|
||||
}
|
||||
case Message::Type::RawMessage: {
|
||||
auto raw = std::dynamic_pointer_cast<RawMessage>(message);
|
||||
|
||||
if(!supportCANFD && canmsg->isCANFD) {
|
||||
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
|
||||
return false; // This device does not support CAN FD
|
||||
}
|
||||
|
||||
useResultAsBuffer = true;
|
||||
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
|
||||
return false; // The CANMessage was malformed
|
||||
// Raw message uses raw->data as the buffer unless directed otherwise
|
||||
buffer = &raw->data;
|
||||
netid = uint16_t(raw->network.getNetID());
|
||||
|
||||
break;
|
||||
} // End of Network::Type::CAN
|
||||
case Network::Type::ISO9141: {
|
||||
auto isomsg = std::dynamic_pointer_cast<ISO9141Message>(message);
|
||||
if(!isomsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false; // The message was not a properly formed ISO9141Message
|
||||
}
|
||||
|
||||
// Skip the normal message wrapping at the bottom since we need to send multiple
|
||||
// packets to the device. This function just encodes them back to back into `result`
|
||||
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
|
||||
} // End of Network::Type::ISO9141
|
||||
default:
|
||||
switch(message->network.getNetID()) {
|
||||
switch(raw->network.getNetID()) {
|
||||
case Network::NetID::Device:
|
||||
shortFormat = true;
|
||||
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: {
|
||||
// See the decoder for an explanation
|
||||
// We expect the network byte to be populated already in data, but not the length
|
||||
uint16_t length = uint16_t(message->data.size()) - 1;
|
||||
message->data.insert(message->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
|
||||
uint16_t length = uint16_t(raw->data.size()) - 1;
|
||||
raw->data.insert(raw->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
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
|
||||
auto& buffer = useResultAsBuffer ? result : message->data;
|
||||
|
||||
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 {
|
||||
// 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
|
||||
uint16_t size = uint16_t(buffer.size()) + 1 + 1 + 2 + 2;
|
||||
buffer.insert(buffer.begin(), {
|
||||
uint16_t size = uint16_t(buffer->size()) + 1 + 1 + 2 + 2;
|
||||
buffer->insert(buffer->begin(), {
|
||||
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
||||
(uint8_t)size, // Size, little endian 16-bit
|
||||
(uint8_t)(size >> 8),
|
||||
(uint8_t)message->network.getNetID(), // NetID, little endian 16-bit
|
||||
(uint8_t)(uint16_t(message->network.getNetID()) >> 8)
|
||||
(uint8_t)netid, // NetID, little endian 16-bit
|
||||
(uint8_t)(netid >> 8)
|
||||
});
|
||||
}
|
||||
|
||||
result = packetizer.packetWrap(buffer, shortFormat);
|
||||
result = packetizer.packetWrap(*buffer, shortFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -133,20 +158,19 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
|
||||
* In this case, command 0x06 is SetLEDState.
|
||||
* 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()) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
msg->network = Network::NetID::Device;
|
||||
msg->data.reserve(3);
|
||||
msg->data.push_back(0x00);
|
||||
msg->data.push_back(0x06); // SetLEDState
|
||||
msg->data.push_back(arguments.at(0)); // See Device::LEDState
|
||||
canmsg->data.reserve(3);
|
||||
canmsg->data.push_back(0x00);
|
||||
canmsg->data.push_back(0x06); // SetLEDState
|
||||
canmsg->data.push_back(arguments.at(0)); // See Device::LEDState
|
||||
} else {
|
||||
auto m51msg = std::make_shared<Main51Message>();
|
||||
msg = m51msg;
|
||||
msg->network = Network::NetID::Main51;
|
||||
m51msg->command = cmd;
|
||||
switch(cmd) {
|
||||
case Command::ReadSettings:
|
||||
@@ -161,8 +185,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
|
||||
default:
|
||||
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);
|
||||
}
|
||||
@@ -64,9 +64,7 @@ std::vector<uint8_t> FlexRayControlMessage::BuildWriteMessageBufferArgs(
|
||||
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args);
|
||||
}
|
||||
|
||||
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message() {
|
||||
network = Network::NetID::FlexRayControl;
|
||||
|
||||
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message(Message::Type::FlexRayControl) {
|
||||
if(packet.data.size() < 2)
|
||||
return; // huh?
|
||||
controller = packet.data[0];
|
||||
@@ -77,7 +75,7 @@ FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message() {
|
||||
opcode = FlexRay::Opcode(packet.data[1]);
|
||||
if(opcode != FlexRay::Opcode::ReadCCRegs && opcode != FlexRay::Opcode::ReadCCStatus)
|
||||
return;
|
||||
|
||||
|
||||
// Read out registers
|
||||
size_t bytes = packet.data.size() - 2;
|
||||
const size_t count = bytes / sizeof(uint32_t);
|
||||
|
||||
@@ -1,87 +1,116 @@
|
||||
#include "icsneo/communication/message/neomessage.h"
|
||||
#include "icsneo/communication/message/canmessage.h"
|
||||
#include "icsneo/communication/message/ethernetmessage.h"
|
||||
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
|
||||
// This function is not responsible for storing the message!
|
||||
// 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
|
||||
neomsg.netid = (uint32_t)message->network.getNetID();
|
||||
neomsg.type = (uint8_t)type;
|
||||
neomsg.description = message->description;
|
||||
neomsg.length = message->data.size();
|
||||
neomsg.data = message->data.data();
|
||||
neomsg.messageType = (neomessagetype_t)message->type;
|
||||
neomsg.timestamp = message->timestamp;
|
||||
neomsg.status.globalError = message->error;
|
||||
neomsg.status.transmitMessage = message->transmitted;
|
||||
switch (message->type)
|
||||
{
|
||||
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) {
|
||||
case Network::Type::CAN:
|
||||
case Network::Type::SWCAN:
|
||||
case Network::Type::LSFTCAN: {
|
||||
neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
|
||||
auto canmsg = std::static_pointer_cast<CANMessage>(message);
|
||||
can.arbid = canmsg->arbid;
|
||||
can.dlcOnWire = canmsg->dlcOnWire;
|
||||
can.status.extendedFrame = canmsg->isExtended;
|
||||
can.status.remoteFrame = canmsg->isRemote;
|
||||
can.status.canfdRTR = canmsg->isRemote;
|
||||
can.status.canfdFDF = canmsg->isCANFD;
|
||||
can.status.canfdBRS = canmsg->baudrateSwitch;
|
||||
can.status.canfdESI = canmsg->errorStateIndicator;
|
||||
break;
|
||||
switch(netType) {
|
||||
case Network::Type::CAN:
|
||||
case Network::Type::SWCAN:
|
||||
case Network::Type::LSFTCAN: {
|
||||
neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
|
||||
auto canmsg = std::static_pointer_cast<CANMessage>(message);
|
||||
can.arbid = canmsg->arbid;
|
||||
can.dlcOnWire = canmsg->dlcOnWire;
|
||||
can.status.extendedFrame = canmsg->isExtended;
|
||||
can.status.remoteFrame = canmsg->isRemote;
|
||||
can.status.canfdRTR = canmsg->isRemote;
|
||||
can.status.canfdFDF = canmsg->isCANFD;
|
||||
can.status.canfdBRS = canmsg->baudrateSwitch;
|
||||
can.status.canfdESI = canmsg->errorStateIndicator;
|
||||
break;
|
||||
}
|
||||
case Network::Type::Ethernet: {
|
||||
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
|
||||
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
|
||||
eth.preemptionFlags = ethmsg->preemptionFlags;
|
||||
eth.status.incompleteFrame = ethmsg->frameTooShort;
|
||||
// TODO Fill in extra status bits
|
||||
//eth.status.xyz = ethmsg->preemptionEnabled;
|
||||
//eth.status.xyz = ethmsg->fcsAvailable;
|
||||
//eth.status.xyz = ethmsg->noPadding;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO Implement others
|
||||
break;
|
||||
}
|
||||
case Network::Type::Ethernet: {
|
||||
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
|
||||
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
|
||||
eth.preemptionFlags = ethmsg->preemptionFlags;
|
||||
eth.status.incompleteFrame = ethmsg->frameTooShort;
|
||||
// TODO Fill in extra status bits
|
||||
//eth.status.xyz = ethmsg->preemptionEnabled;
|
||||
//eth.status.xyz = ethmsg->fcsAvailable;
|
||||
//eth.status.xyz = ethmsg->noPadding;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO Implement others
|
||||
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;
|
||||
}
|
||||
|
||||
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
|
||||
const Network network = neomessage->netid;
|
||||
switch(network.getType()) {
|
||||
case Network::Type::CAN:
|
||||
case Network::Type::SWCAN:
|
||||
case Network::Type::LSFTCAN: {
|
||||
neomessage_can_t& can = *(neomessage_can_t*)neomessage;
|
||||
auto canmsg = std::make_shared<CANMessage>();
|
||||
canmsg->network = network;
|
||||
canmsg->description = can.description;
|
||||
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
|
||||
canmsg->arbid = can.arbid;
|
||||
canmsg->isExtended = can.status.extendedFrame;
|
||||
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
|
||||
canmsg->isCANFD = can.status.canfdFDF;
|
||||
canmsg->baudrateSwitch = can.status.canfdBRS;
|
||||
canmsg->errorStateIndicator = can.status.canfdESI;
|
||||
return canmsg;
|
||||
switch((Message::Type)neomessage->messageType) {
|
||||
case Message::Type::Frame: {
|
||||
const Network network = ((neomessage_frame_t*)neomessage)->netid;
|
||||
switch(network.getType()) {
|
||||
case Network::Type::CAN:
|
||||
case Network::Type::SWCAN:
|
||||
case Network::Type::LSFTCAN: {
|
||||
neomessage_can_t& can = *(neomessage_can_t*)neomessage;
|
||||
auto canmsg = std::make_shared<CANMessage>();
|
||||
canmsg->network = network;
|
||||
canmsg->description = can.description;
|
||||
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
|
||||
canmsg->arbid = can.arbid;
|
||||
canmsg->dlcOnWire = can.dlcOnWire;
|
||||
canmsg->isExtended = can.status.extendedFrame;
|
||||
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
|
||||
canmsg->isCANFD = can.status.canfdFDF;
|
||||
canmsg->baudrateSwitch = can.status.canfdBRS;
|
||||
canmsg->errorStateIndicator = can.status.canfdESI;
|
||||
return canmsg;
|
||||
}
|
||||
case Network::Type::Ethernet: {
|
||||
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
|
||||
auto ethmsg = std::make_shared<EthernetMessage>();
|
||||
ethmsg->network = network;
|
||||
ethmsg->description = eth.description;
|
||||
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
|
||||
return ethmsg;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Network::Type::Ethernet: {
|
||||
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
|
||||
auto ethmsg = std::make_shared<EthernetMessage>();
|
||||
ethmsg->network = network;
|
||||
ethmsg->description = eth.description;
|
||||
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
|
||||
return ethmsg;
|
||||
}
|
||||
default:
|
||||
// TODO Implement others
|
||||
return std::shared_ptr<Message>();
|
||||
default: break;
|
||||
}
|
||||
return std::shared_ptr<Message>();
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "icsneo/communication/packet/canpacket.h"
|
||||
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||
#include "icsneo/platform/optional.h"
|
||||
|
||||
using namespace icsneo;
|
||||
@@ -6,7 +7,7 @@ using namespace icsneo;
|
||||
static optional<uint8_t> CANFD_DLCToLength(uint8_t length) {
|
||||
if (length < 8)
|
||||
return length;
|
||||
|
||||
|
||||
switch(length) {
|
||||
case 0x9:
|
||||
return 12;
|
||||
@@ -26,61 +27,75 @@ static optional<uint8_t> CANFD_DLCToLength(uint8_t length) {
|
||||
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();
|
||||
|
||||
auto msg = std::make_shared<CANMessage>();
|
||||
if(data->dlc.RB1) { // Change counts reporting
|
||||
|
||||
// Arb ID
|
||||
if(data->header.IDE) { // Extended 29-bit ID
|
||||
msg->arbid = (data->header.SID & 0x7ff) << 18;
|
||||
msg->arbid |= (data->eid.EID & 0xfff) << 6;
|
||||
msg->arbid |= (data->dlc.EID2 & 0x3f);
|
||||
msg->isExtended = true;
|
||||
} else { // Standard 11-bit ID
|
||||
msg->arbid = data->header.SID;
|
||||
}
|
||||
const bool busOff = data->data[0] & 0b00100000;
|
||||
|
||||
// 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;
|
||||
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff);
|
||||
|
||||
// DLC
|
||||
uint8_t length = data->dlc.DLC;
|
||||
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
|
||||
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
|
||||
msg->isCANFD = true;
|
||||
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
|
||||
msg->errorStateIndicator = data->header.ESI;
|
||||
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(length);
|
||||
if (lenFromDLC)
|
||||
length = *lenFromDLC;
|
||||
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
|
||||
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
|
||||
// We don't want to overread our buffer, though, so make sure we cap the length
|
||||
length = 8;
|
||||
}
|
||||
|
||||
// Data
|
||||
// The first 8 bytes are always in the standard place
|
||||
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
|
||||
msg->data.resize(length); // This data will be all zeros, but the length will be set
|
||||
msg->isRemote = true;
|
||||
} else {
|
||||
msg->data.reserve(length);
|
||||
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
|
||||
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
|
||||
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
|
||||
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
|
||||
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
|
||||
// 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>();
|
||||
|
||||
// Arb ID
|
||||
if(data->header.IDE) { // Extended 29-bit ID
|
||||
msg->arbid = (data->header.SID & 0x7ff) << 18;
|
||||
msg->arbid |= (data->eid.EID & 0xfff) << 6;
|
||||
msg->arbid |= (data->dlc.EID2 & 0x3f);
|
||||
msg->isExtended = true;
|
||||
} else { // Standard 11-bit ID
|
||||
msg->arbid = data->header.SID;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// DLC
|
||||
uint8_t length = data->dlc.DLC;
|
||||
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
|
||||
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
|
||||
msg->isCANFD = true;
|
||||
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
|
||||
msg->errorStateIndicator = data->header.ESI;
|
||||
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(length);
|
||||
if (lenFromDLC)
|
||||
length = *lenFromDLC;
|
||||
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
|
||||
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
|
||||
// We don't want to overread our buffer, though, so make sure we cap the length
|
||||
length = 8;
|
||||
}
|
||||
|
||||
// Data
|
||||
// The first 8 bytes are always in the standard place
|
||||
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
|
||||
msg->data.resize(length); // This data will be all zeros, but the length will be set
|
||||
msg->isRemote = true;
|
||||
} else {
|
||||
msg->data.reserve(length);
|
||||
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
|
||||
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
|
||||
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
|
||||
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
|
||||
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
|
||||
}
|
||||
}
|
||||
|
||||
msg->transmitted = data->eid.TXMSG;
|
||||
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
|
||||
msg->description = data->stats;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg->transmitted = data->eid.TXMSG;
|
||||
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
|
||||
msg->description = data->stats;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
|
||||
|
||||
@@ -6,7 +6,7 @@ std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const
|
||||
if(bytestream.size() < 3) // Not enough bytes to decode
|
||||
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();
|
||||
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) {
|
||||
auto msg = std::make_shared<VersionMessage>(false);
|
||||
auto msg = std::make_shared<VersionMessage>(VersionMessage::SecondaryChips);
|
||||
|
||||
size_t bytesLeft = bytestream.size();
|
||||
if(bytesLeft)
|
||||
|
||||
Reference in New Issue
Block a user