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:
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-interactive-example VERSION 0.2.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
@@ -182,6 +182,102 @@ std::shared_ptr<icsneo::Device> selectDevice(const std::vector<std::shared_ptr<i
|
||||
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() {
|
||||
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl << std::endl;
|
||||
|
||||
@@ -237,7 +333,7 @@ int main() {
|
||||
std::cout << "[1] Open" << std::endl << "[2] Close" << std::endl << "[3] Cancel" << std::endl << std::endl;
|
||||
char selection = getCharInput(std::vector<char> {'1', '2', '3'});
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
switch(selection) {
|
||||
case '1':
|
||||
if(selectedDevice->open()) {
|
||||
@@ -247,7 +343,7 @@ int main() {
|
||||
std::cout << icsneo::GetLastError() << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case '2':
|
||||
// Attempt to close the device
|
||||
@@ -259,7 +355,7 @@ int main() {
|
||||
std::cout << icsneo::GetLastError() << std::endl;;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
default:
|
||||
std::cout << "Canceling!" << std::endl << std::endl;
|
||||
@@ -360,7 +456,7 @@ int main() {
|
||||
default:
|
||||
std::cout << "Canceling!" << std::endl << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Get messages
|
||||
@@ -392,29 +488,9 @@ int main() {
|
||||
}
|
||||
|
||||
// Print out the received messages
|
||||
for(auto msg : msgs) {
|
||||
switch(msg->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 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;
|
||||
}
|
||||
for(const auto& msg : msgs)
|
||||
printMessage(msg);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -445,7 +521,7 @@ int main() {
|
||||
std::cout << "Failed to transmit message to " << selectedDevice->describe() << "!" << std::endl << std::endl;
|
||||
std::cout << icsneo::GetLastError() << std::endl;;
|
||||
}
|
||||
|
||||
|
||||
/** Example of CAN FD
|
||||
std::cout << "Transmitting an extended CAN FD frame... " << std::endl;
|
||||
auto txMessage = std::make_shared<icsneo::CANMessage>();
|
||||
@@ -538,28 +614,8 @@ int main() {
|
||||
switch(selection) {
|
||||
case '1':
|
||||
{
|
||||
// Shameless copy-paste from get messages above, demonstrating a callback
|
||||
int callbackID = selectedDevice->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> msg){
|
||||
switch(msg->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 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;
|
||||
}
|
||||
printMessage(msg);
|
||||
}));
|
||||
|
||||
if(callbackID != -1) {
|
||||
@@ -578,7 +634,7 @@ int main() {
|
||||
break;
|
||||
} else {
|
||||
std::vector<char> allowed;
|
||||
|
||||
|
||||
std::cout << "Which id would you like to remove?" << std::endl;
|
||||
for(int id : callbacks.find(selectedDevice)->second) {
|
||||
allowed.push_back(static_cast<char>(id) + '0');
|
||||
@@ -595,7 +651,7 @@ int main() {
|
||||
} else {
|
||||
std::cout << "Failed to remove message callback id " << removeID << " from " << selectedDevice->describe() << "!" << std::endl << std::endl;
|
||||
std::cout << icsneo::GetLastError() << std::endl;;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-simple-example VERSION 0.2.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
int main() {
|
||||
// Print version
|
||||
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
|
||||
|
||||
|
||||
std::cout<< "Supported devices:" << std::endl;
|
||||
for(auto& dev : icsneo::GetSupportedDevices())
|
||||
std::cout << '\t' << dev.getGenericProductName() << std::endl;
|
||||
@@ -85,7 +85,7 @@ int main() {
|
||||
std::cout << "FAIL" << std::endl;
|
||||
else
|
||||
std::cout << "OK, " << (baud/1000) << "kbit/s" << std::endl;
|
||||
|
||||
|
||||
std::cout << "\tGetting HSCANFD Baudrate... ";
|
||||
baud = device->settings->getFDBaudrateFor(icsneo::Network::NetID::HSCAN);
|
||||
if(baud < 0)
|
||||
@@ -126,82 +126,118 @@ int main() {
|
||||
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!
|
||||
|
||||
// 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
|
||||
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
|
||||
auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) {
|
||||
switch(message->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\tCAN ";
|
||||
if(canMessage->isCANFD) {
|
||||
std::cout << "FD ";
|
||||
if(!canMessage->baudrateSwitch)
|
||||
std::cout << "(No BRS) ";
|
||||
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;
|
||||
}
|
||||
|
||||
// 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] << ' ';
|
||||
}
|
||||
} // 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 << 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 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 << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
|
||||
std::cout << std::dec << '(' << cec->timestamp << " ns since 1/1/2007)\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Ignoring non-network messages
|
||||
// Ignoring other types of messages
|
||||
break;
|
||||
}
|
||||
}));
|
||||
@@ -278,7 +314,7 @@ int main() {
|
||||
ret = device->close();
|
||||
std::cout << (ret ? "OK\n" : "FAIL\n") << std::endl;
|
||||
}
|
||||
|
||||
|
||||
std::cout << "Press any key to continue..." << std::endl;
|
||||
std::cin.get();
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user