CAN and CAN FD transmit implemented

This commit is contained in:
Paul Hollinsky
2018-10-18 17:39:37 -04:00
parent dd99f82324
commit d037709963
8 changed files with 213 additions and 82 deletions
+33 -42
View File
@@ -43,40 +43,32 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
switch(length) { // CAN FD Length Decoding
case 0x0:
case 0x1:
case 0x2:
case 0x3:
case 0x4:
case 0x5:
case 0x6:
case 0x7:
case 0x8:
break; // The length is already correct
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;
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;
}
}
}
@@ -128,7 +120,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true;
}
default:
return false;
break;//return false;
}
}
default:
@@ -177,11 +169,10 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
}
}
return false;
// auto msg = std::make_shared<Message>();
// msg->network = packet->network;
// msg->data = packet->data;
// result = msg;
// return true;
// 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;
return true;
}
+92 -18
View File
@@ -4,26 +4,98 @@ using namespace icsneo;
bool Encoder::encode(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
result.clear();
switch(message->network.getType()) {
// case Network::Type::CAN: {
// if(message->data.size() < 24)
// break; // We would read garbage when interpereting the data
case Network::Type::CAN: {
useResultAsBuffer = true;
// HardwareCANPacket* data = (HardwareCANPacket*)message->data.data();
// auto msg = std::make_shared<CANMessage>();
// msg->network = message->network;
// msg->arbid = data->header.SID;
// msg->data.reserve(data->dlc.DLC);
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(!canmsg)
return false; // The message was not a properly formed CANMessage
// // Timestamp calculation
// msg->timestamp = data->timestamp.TS * 25; // Timestamps are in 25ns increments since 1/1/2007 GMT 00:00:00.0000
if(canmsg->isCANFD && canmsg->isRemote)
return false; // RTR frames can not be used with CAN FD
// for(auto i = 0; i < data->dlc.DLC; i++)
// msg->data.push_back(data->data[i]);
// return msg;
// }
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
}
}
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;
}
default:
switch(message->network.getNetID()) {
case Network::NetID::Device:
@@ -59,13 +131,15 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
}
}
auto& buffer = useResultAsBuffer ? result : message->data;
if(shortFormat) {
message->data.insert(message->data.begin(), (uint8_t(message->data.size()) << 4) | uint8_t(message->network.getNetID()));
buffer.insert(buffer.begin(), (uint8_t(buffer.size()) << 4) | uint8_t(message->network.getNetID()));
} 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(message->data.size()) + 1 + 1 + 2 + 2;
message->data.insert(message->data.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),
@@ -74,7 +148,7 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
});
}
result = packetizer->packetWrap(message->data, shortFormat);
result = packetizer->packetWrap(buffer, shortFormat);
return true;
}
+3 -1
View File
@@ -119,12 +119,14 @@ typedef struct {
#ifdef __cplusplus
#include "communication/message/include/message.h"
#include <memory>
static_assert(sizeof(neomessage_can_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size!");
namespace icsneo {
neomessage_t CreateNeoMessage(const Message& message);
neomessage_t CreateNeoMessage(const std::shared_ptr<Message> message);
std::shared_ptr<Message> CreateMessageFromNeoMessage(const neomessage_t* neomessage);
}
#endif
+34 -13
View File
@@ -3,27 +3,27 @@
using namespace icsneo;
neomessage_t icsneo::CreateNeoMessage(const Message& message) {
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();
const auto type = message->network.getType();
neomessage_t neomsg = {}; // Clear out the memory
neomsg.netid = (uint32_t)message.network.getNetID();
neomsg.netid = (uint32_t)message->network.getNetID();
neomsg.type = (uint8_t)type;
neomsg.length = message.data.size();
neomsg.data = message.data.data();
neomsg.timestamp = message.timestamp;
neomsg.length = message->data.size();
neomsg.data = message->data.data();
neomsg.timestamp = message->timestamp;
switch(type) {
case Network::Type::CAN: {
neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
const CANMessage& canmsg = *(const CANMessage*)&message;
can.arbid = canmsg.arbid;
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;
auto canmsg = std::static_pointer_cast<CANMessage>(message);
can.arbid = canmsg->arbid;
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;
break;
}
default:
@@ -32,4 +32,25 @@ neomessage_t icsneo::CreateNeoMessage(const Message& message) {
}
return neomsg;
}
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
const Network network = neomessage->netid;
switch(network.getType()) {
case Network::Type::CAN: {
neomessage_can_t& can = *(neomessage_can_t*)neomessage;
auto canmsg = std::make_shared<CANMessage>();
canmsg->network = network;
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;
return canmsg;
}
default:
// TODO Implement others
return std::shared_ptr<Message>();
}
}