Support Ethernet and Broad-R Reach TX and RX

pull/4/head
Paul Hollinsky 2018-12-21 20:32:27 -05:00
parent 603d532d2d
commit d37d5bb23e
14 changed files with 490 additions and 209 deletions

View File

@ -94,6 +94,8 @@ endif()
set(COMMON_SRC
communication/message/neomessage.cpp
communication/packet/canpacket.cpp
communication/packet/ethernetpacket.cpp
communication/decoder.cpp
communication/encoder.cpp
communication/packetizer.cpp

View File

@ -5,6 +5,8 @@
#include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include <iostream>
using namespace icsneo;
@ -18,82 +20,28 @@ uint64_t Decoder::GetUInt64FromLEBytes(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:
result = HardwareEthernetPacket::DecodeToMessage(packet->data);
if(!result)
return false; // A nullptr was returned, the packet was not long enough to decode
// Timestamps are in (multiplier) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution (multiplier) depends on the device
result->timestamp *= timestampMultiplier;
result->network = packet->network;
return true;
case Network::Type::CAN: {
if(packet->data.size() < 24)
return false;
HardwareCANPacket* data = (HardwareCANPacket*)packet->data.data();
auto msg = std::make_shared<CANMessage>();
msg->network = packet->network;
result = HardwareCANPacket::DecodeToMessage(packet->data);
if(!result)
return false; // A nullptr was returned, the packet was malformed
// Timestamp calculation
msg->timestamp = data->timestamp.TS * 25; // Timestamps are in 25ns increments since 1/1/2007 GMT 00:00:00.0000
// 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;
}
// 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
if(length > 8) {
switch(length) { // CAN FD Length Decoding
case 0x9:
length = 12;
break;
case 0xa:
length = 16;
break;
case 0xb:
length = 20;
break;
case 0xc:
length = 24;
break;
case 0xd:
length = 32;
break;
case 0xe:
length = 48;
break;
case 0xf:
length = 64;
break;
default:
return false;
}
}
} 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
uint8_t* extraDataStart = packet->data.data() + sizeof(HardwareCANPacket) + 2 + 2;
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
}
}
result = msg;
// Timestamps are in (multiplier) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution (multiplier) depends on the device
result->timestamp *= timestampMultiplier;
result->network = packet->network;
return true;
}
case Network::Type::Internal: {

View File

@ -1,4 +1,7 @@
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/canpacket.h"
using namespace icsneo;
@ -8,9 +11,18 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
result.clear();
switch(message->network.getType()) {
case Network::Type::CAN: {
useResultAsBuffer = true;
case Network::Type::Ethernet: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg)
return false; // The message was not a properly formed EthernetMessage
useResultAsBuffer = true;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result))
return false;
break;
} // End of Network::Type::Ethernet
case Network::Type::CAN: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(!canmsg)
return false; // The message was not a properly formed CANMessage
@ -18,88 +30,10 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
if(!supportCANFD && canmsg->isCANFD)
return false; // This device does not support CAN FD
if(canmsg->isCANFD && canmsg->isRemote)
return false; // RTR frames can not be used with CAN FD
useResultAsBuffer = true;
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result))
return false; // The CANMessage was malformed
const size_t dataSize = canmsg->data.size();
if(dataSize > 64 || (dataSize > 8 && !canmsg->isCANFD))
return false; // Too much data for the protocol
uint8_t lengthNibble = uint8_t(canmsg->data.size());
if(lengthNibble > 8) {
switch(lengthNibble) {
case 12:
lengthNibble = 0x9;
break;
case 16:
lengthNibble = 0xA;
break;
case 20:
lengthNibble = 0xB;
break;
case 24:
lengthNibble = 0xC;
break;
case 32:
lengthNibble = 0xD;
break;
case 48:
lengthNibble = 0xE;
break;
case 64:
lengthNibble = 0xF;
break;
default:
return false; // CAN FD frame may have had an incorrect byte count
}
}
// Pre-allocate as much memory as we will possibly need for speed
result.reserve(17 + dataSize);
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(canmsg->network.getNetID()) & 0xF));
result.insert(result.end(), {0,0}); // Two bytes for Description ID, big endian, not used in API currently
// Next 2-4 bytes are ArbID
if(canmsg->isExtended) {
if(canmsg->arbid >= 0x20000000) // Extended messages use 29-bit arb IDs
return false;
result.insert(result.end(), {
(uint8_t)(canmsg->arbid >> 21),
(uint8_t)(((((canmsg->arbid & 0x001C0000) >> 13) & 0xFF) + (((canmsg->arbid & 0x00030000) >> 16) & 0xFF)) | 8),
(uint8_t)(canmsg->arbid >> 8),
(uint8_t)canmsg->arbid
});
} else {
if(canmsg->arbid >= 0x800) // Standard messages use 11-bit arb IDs
return false;
result.insert(result.end(), {
(uint8_t)(canmsg->arbid >> 3),
(uint8_t)((canmsg->arbid & 0x7) << 5)
});
}
// Status and DLC bits
if(canmsg->isCANFD) {
result.push_back(0x0F); // FD Frame
uint8_t fdStatusByte = lengthNibble;
if(canmsg->baudrateSwitch)
fdStatusByte |= 0x80; // BRS status bit
result.push_back(fdStatusByte);
} else {
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
uint8_t statusNibble = canmsg->isRemote ? 0x4 : 0x0;
result.push_back((statusNibble << 4) | lengthNibble);
}
// Now finally the payload
result.insert(result.end(), canmsg->data.begin(), canmsg->data.end());
result.push_back(0);
// Fill in the length byte from earlier
result[0] |= result.size() << 4;
break;
} // End of Network::Type::CAN
default:

View File

@ -1,5 +1,6 @@
#include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
using namespace icsneo;
@ -13,6 +14,8 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
neomsg.length = message->data.size();
neomsg.data = message->data.data();
neomsg.timestamp = message->timestamp;
neomsg.status.globalError = message->error;
neomsg.status.transmitMessage = message->transmitted;
switch(type) {
case Network::Type::CAN: {
@ -27,6 +30,17 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
can.status.canfdBRS = canmsg->baudrateSwitch;
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;

View File

@ -0,0 +1,164 @@
#include "icsneo/communication/packet/canpacket.h"
using namespace icsneo;
std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
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;
}
// 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
if(length > 8) {
switch(length) { // CAN FD Length Decoding
case 0x9:
length = 12;
break;
case 0xa:
length = 16;
break;
case 0xb:
length = 20;
break;
case 0xc:
length = 24;
break;
case 0xd:
length = 32;
break;
case 0xe:
length = 48;
break;
case 0xf:
length = 64;
break;
default:
return nullptr;
}
}
} 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));
}
}
return msg;
}
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result) {
if(message.isCANFD && message.isRemote)
return false; // RTR frames can not be used with CAN FD
const size_t dataSize = message.data.size();
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD))
return false; // Too much data for the protocol
uint8_t lengthNibble = uint8_t(message.data.size());
if(lengthNibble > 8) {
switch(lengthNibble) {
case 12:
lengthNibble = 0x9;
break;
case 16:
lengthNibble = 0xA;
break;
case 20:
lengthNibble = 0xB;
break;
case 24:
lengthNibble = 0xC;
break;
case 32:
lengthNibble = 0xD;
break;
case 48:
lengthNibble = 0xE;
break;
case 64:
lengthNibble = 0xF;
break;
default:
return false; // CAN FD frame may have had an incorrect byte count
}
}
// Pre-allocate as much memory as we will possibly need for speed
result.reserve(17 + dataSize);
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF));
// Two bytes for Description ID, big endian
result.insert(result.end(), { uint8_t(message.description >> 8), uint8_t(message.description) });
// Next 2-4 bytes are ArbID
if(message.isExtended) {
if(message.arbid >= 0x20000000) // Extended messages use 29-bit arb IDs
return false;
result.insert(result.end(), {
(uint8_t)(message.arbid >> 21),
(uint8_t)(((((message.arbid & 0x001C0000) >> 13) & 0xFF) + (((message.arbid & 0x00030000) >> 16) & 0xFF)) | 8),
(uint8_t)(message.arbid >> 8),
(uint8_t)message.arbid
});
} else {
if(message.arbid >= 0x800) // Standard messages use 11-bit arb IDs
return false;
result.insert(result.end(), {
(uint8_t)(message.arbid >> 3),
(uint8_t)((message.arbid & 0x7) << 5)
});
}
// Status and DLC bits
if(message.isCANFD) {
result.push_back(0x0F); // FD Frame
uint8_t fdStatusByte = lengthNibble;
if(message.baudrateSwitch)
fdStatusByte |= 0x80; // BRS status bit
result.push_back(fdStatusByte);
} else {
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
uint8_t statusNibble = message.isRemote ? 0x4 : 0x0;
result.push_back((statusNibble << 4) | lengthNibble);
}
// Now finally the payload
result.insert(result.end(), message.data.begin(), message.data.end());
result.push_back(0);
// Fill in the length byte from earlier
result[0] |= result.size() << 4;
return true;
}

View File

@ -0,0 +1,86 @@
#include "icsneo/communication/packet/ethernetpacket.h"
#include <cstring> // memcpy
#include <iostream>
using namespace icsneo;
std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareEthernetPacket* packet = (const HardwareEthernetPacket*)((const void*)bytestream.data());
const uint16_t* rawWords = (const uint16_t*)bytestream.data();
// Make sure we have enough to read the packet length first
if(bytestream.size() < sizeof(HardwareEthernetPacket))
return nullptr;
// packet->Length will also encompass the two uint16_t's at the end of the struct, make sure that at least they are here
if(packet->Length < 4)
return nullptr;
size_t bytesOnWire = packet->Length - (sizeof(uint16_t) * 2);
if(bytestream.size() < sizeof(HardwareEthernetPacket) + bytesOnWire)
return nullptr;
if(bytestream.size() > sizeof(HardwareEthernetPacket) + bytesOnWire)
std::cout << "There is an extra " << (sizeof(HardwareEthernetPacket) + bytesOnWire) << " bytes at the end" << std::endl;
auto messagePtr = std::make_shared<EthernetMessage>();
EthernetMessage& message = *messagePtr;
message.transmitted = packet->eid.TXMSG;
if(message.transmitted)
message.description = packet->stats;
message.preemptionEnabled = packet->header.PREEMPTION_ENABLED;
if(message.preemptionEnabled)
message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4);
message.fcsAvailable = packet->header.FCS_AVAIL;
message.frameTooShort = packet->header.RUNT_FRAME;
if(message.frameTooShort)
message.error = true;
// This timestamp is raw off the device (in timestampMultiplier increments)
// Decoder will fix as it has information about the timestampMultiplier increments
message.timestamp = packet->timestamp.TS;
// Network ID is also not set, this will be fixed in the Decoder as well
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + (sizeof(HardwareEthernetPacket) - (sizeof(uint16_t) * 2));
const std::vector<uint8_t>::const_iterator dataend = databegin + bytesOnWire;
message.data.insert(message.data.begin(), databegin, dataend);
return messagePtr;
}
bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream) {
const size_t unpaddedSize = message.data.size();
size_t paddedSize = unpaddedSize;
if(!message.noPadding && unpaddedSize < 60)
paddedSize = 60; // Pad out short messages
size_t sizeWithHeader = paddedSize + 5; // DescriptionID and Premption Flags
bytestream.reserve(sizeWithHeader + 8); // Also reserve space for the bytes we'll use later on
bytestream.resize(sizeWithHeader);
size_t index = 0;
// Padded size, little endian
bytestream[index++] = uint8_t(paddedSize);
bytestream[index++] = uint8_t(paddedSize >> 8);
// Description ID, big endian
bytestream[index++] = uint8_t(message.description >> 8);
bytestream[index++] = uint8_t(message.description);
// Yes, we reserved and allocated space for the preemption flags even if we're not putting them there
// And yes, the data is intended to move over one byte
if(message.preemptionEnabled)
bytestream[index++] = message.preemptionFlags;
// We only copy in the unpadded size, the rest will be 0
memcpy(bytestream.data() + index, message.data.data(), unpaddedSize);
return true;
}

View File

@ -10,8 +10,6 @@
#include <vector>
#include <memory>
#pragma pack(push, 1)
namespace icsneo {
class Decoder {
@ -20,44 +18,13 @@ public:
Decoder(device_errorhandler_t err) : err(err) {}
bool decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet);
int timestampMultiplier = 25;
private:
device_errorhandler_t err;
typedef uint16_t icscm_bitfield;
struct HardwareCANPacket {
struct {
icscm_bitfield IDE : 1;
icscm_bitfield SRR : 1;
icscm_bitfield SID : 11;
icscm_bitfield EDL : 1;
icscm_bitfield BRS : 1;
icscm_bitfield ESI : 1;
} header;
struct {
icscm_bitfield EID : 12;
icscm_bitfield TXMSG : 1;
icscm_bitfield TXAborted : 1;
icscm_bitfield TXLostArb : 1;
icscm_bitfield TXError : 1;
} eid;
struct {
icscm_bitfield DLC : 4;
icscm_bitfield RB0 : 1;
icscm_bitfield IVRIF : 1;
icscm_bitfield HVEnable : 1;// must be cleared before passing into CAN driver
icscm_bitfield ExtendedNetworkIndexBit : 1;//DO NOT CLOBBER THIS
icscm_bitfield RB1 : 1;
icscm_bitfield RTR : 1;
icscm_bitfield EID2 : 6;
} dlc;
unsigned char data[8];
uint16_t stats;
struct {
uint64_t TS : 60;
uint64_t : 3; // Reserved for future status bits
uint64_t IsExtended : 1;
} timestamp;
};
#pragma pack(push, 1)
#ifdef _MSC_VER
#pragma warning(push)
@ -99,10 +66,9 @@ private:
uint16_t busVoltage;
uint16_t deviceTemperature;
};
#pragma pack(pop)
};
}
#pragma pack(pop)
#endif

View File

@ -0,0 +1,48 @@
#ifndef __ETHERNETMESSAGE_H_
#define __ETHERNETMESSAGE_H_
#include "icsneo/communication/message/message.h"
// Used for MACAddress.toString() only
#include <sstream>
#include <iomanip>
namespace icsneo {
struct MACAddress {
uint8_t data[6];
// Helpers
std::string toString() const {
std::stringstream ss;
for(size_t i = 0; i < 6; i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];
if(i != 5)
ss << ':';
}
return ss.str();
}
friend std::ostream& operator<<(std::ostream& os, const MACAddress& mac) {
os << mac.toString();
return os;
}
};
class EthernetMessage : public Message {
public:
bool preemptionEnabled = false;
uint8_t preemptionFlags = 0;
bool fcsAvailable = false;
bool frameTooShort = false;
bool noPadding = false;
// Accessors
const MACAddress& getDestinationMAC() const { return *(const MACAddress*)(data.data() + 0); }
const MACAddress& getSourceMAC() const { return *(const MACAddress*)(data.data() + 6); }
uint16_t getEtherType() const { return (data[12] << 8) | data[13]; }
};
}
#endif

View File

@ -11,7 +11,10 @@ public:
virtual ~Message() = default;
Network network;
std::vector<uint8_t> data;
uint64_t timestamp;
uint64_t timestamp = 0;
uint16_t description = 0;
bool transmitted = false;
bool error = false;
};
}

View File

@ -102,18 +102,20 @@ typedef union {
typedef struct {
neomessage_statusbitfield_t status;
uint64_t timestamp;
uint64_t timestampReserved;
const uint8_t* data;
size_t length;
uint8_t header[4];
uint16_t netid;
uint8_t type;
uint8_t reserved[17];
} neomessage_t; // 64 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!
typedef struct {
neomessage_statusbitfield_t status;
uint64_t timestamp;
uint64_t timestampReserved;
const uint8_t* data;
size_t length;
uint32_t arbid;
@ -123,13 +125,28 @@ typedef struct {
uint8_t reserved[16];
} neomessage_can_t;
typedef struct {
neomessage_statusbitfield_t status;
uint64_t timestamp;
uint64_t timestampReserved;
const uint8_t* data;
size_t length;
uint8_t preemptionFlags;
uint8_t reservedHeader[3];
uint16_t netid;
uint8_t type;
uint8_t reserved[17];
} neomessage_eth_t;
#pragma pack(pop)
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include <memory>
static_assert(sizeof(neomessage_can_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size!");
static_assert(sizeof(neomessage_t) == 72, "neomessage_t may not change size from 72 bytes!");
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_eth_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Ethernet is not)");
namespace icsneo {

View File

@ -245,11 +245,11 @@ public:
case NetID::LIN:
return "LIN";
case NetID::OP_Ethernet1:
return "Ethernet 1";
return "OP (BR) Ethernet 1";
case NetID::OP_Ethernet2:
return "Ethernet 2";
return "OP (BR) Ethernet 2";
case NetID::OP_Ethernet3:
return "Ethernet 3";
return "OP (BR) Ethernet 3";
case NetID::RED_EXT_MEMORYREAD:
return "RED_EXT_MEMORYREAD";
case NetID::RED_INT_MEMORYREAD:
@ -299,9 +299,9 @@ public:
case NetID::HSCAN3:
return "HSCAN 3";
case NetID::OP_Ethernet4:
return "Ethernet 4";
return "OP (BR) Ethernet 4";
case NetID::OP_Ethernet5:
return "Ethernet 5";
return "OP (BR) Ethernet 5";
case NetID::ISO4:
return "ISO 4";
case NetID::LIN2:
@ -351,19 +351,19 @@ public:
case NetID::TextAPI_To_Host:
return "TextAPI To Host";
case NetID::OP_Ethernet6:
return "Ethernet 6";
return "OP (BR) Ethernet 6";
case NetID::Red_VBat:
return "Red VBat";
case NetID::OP_Ethernet7:
return "Ethernet 7";
return "OP (BR) Ethernet 7";
case NetID::OP_Ethernet8:
return "Ethernet 8";
return "OP (BR) Ethernet 8";
case NetID::OP_Ethernet9:
return "Ethernet 9";
return "OP (BR) Ethernet 9";
case NetID::OP_Ethernet10:
return "Ethernet 10";
return "OP (BR) Ethernet 10";
case NetID::OP_Ethernet11:
return "Ethernet 11";
return "OP (BR) Ethernet 11";
case NetID::FlexRay1a:
return "FlexRay 1a";
case NetID::FlexRay1b:
@ -379,7 +379,7 @@ public:
case NetID::FlexRay2:
return "FlexRay 2";
case NetID::OP_Ethernet12:
return "Ethernet 12";
return "OP (BR) Ethernet 12";
case NetID::MOST25:
return "MOST25";
case NetID::MOST50:

View File

@ -0,0 +1,52 @@
#ifndef __CANPACKET_H__
#define __CANPACKET_H__
#include "icsneo/communication/message/canmessage.h"
#include <cstdint>
#include <memory>
namespace icsneo {
typedef uint16_t icscm_bitfield;
struct HardwareCANPacket {
static std::shared_ptr<CANMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream);
struct {
icscm_bitfield IDE : 1;
icscm_bitfield SRR : 1;
icscm_bitfield SID : 11;
icscm_bitfield EDL : 1;
icscm_bitfield BRS : 1;
icscm_bitfield ESI : 1;
} header;
struct {
icscm_bitfield EID : 12;
icscm_bitfield TXMSG : 1;
icscm_bitfield TXAborted : 1;
icscm_bitfield TXLostArb : 1;
icscm_bitfield TXError : 1;
} eid;
struct {
icscm_bitfield DLC : 4;
icscm_bitfield RB0 : 1;
icscm_bitfield IVRIF : 1;
icscm_bitfield HVEnable : 1;// must be cleared before passing into CAN driver
icscm_bitfield ExtendedNetworkIndexBit : 1;//DO NOT CLOBBER THIS
icscm_bitfield RB1 : 1;
icscm_bitfield RTR : 1;
icscm_bitfield EID2 : 6;
} dlc;
unsigned char data[8];
uint16_t stats;
struct {
uint64_t TS : 60;
uint64_t : 3; // Reserved for future status bits
uint64_t IsExtended : 1;
} timestamp;
};
}
#endif

View File

@ -0,0 +1,44 @@
#ifndef __ETHERNETPACKET_H__
#define __ETHERNETPACKET_H__
#include "icsneo/communication/message/ethernetmessage.h"
#include <cstdint>
#include <memory>
namespace icsneo {
typedef uint16_t icscm_bitfield;
struct HardwareEthernetPacket {
static std::shared_ptr<EthernetMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream);
struct {
icscm_bitfield FCS_AVAIL : 1;
icscm_bitfield RUNT_FRAME : 1;
icscm_bitfield DISABLE_PADDING : 1;
icscm_bitfield PREEMPTION_ENABLED : 1;
icscm_bitfield MPACKET_TYPE : 4;
icscm_bitfield MPACKET_FRAG_CNT : 2;
icscm_bitfield : 6;
} header;
struct {
icscm_bitfield txlen : 12;
icscm_bitfield TXMSG : 1;
icscm_bitfield : 3;
} eid;
icscm_bitfield reserved;
unsigned char data[8];
uint16_t stats;
struct {
uint64_t TS : 60;
uint64_t : 3; // Reserved for future status bits
uint64_t IsExtended : 1;
} timestamp;
uint16_t NetworkID;
uint16_t Length;
};
}
#endif

View File

@ -8,6 +8,9 @@
#include "icsneo/api/version.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
namespace icsneo {
std::vector<std::shared_ptr<Device>> FindAllDevices();