libicsneo/examples/cpp/t1s/src/T1SSymbolDecodingExample.cpp

360 lines
12 KiB
C++

// 10BASE-T1S Symbol Decoding Example
// Demonstrates T1S bus symbol decoding and analysis
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
#include <map>
#include <string>
#include <atomic>
#include "icsneo/icsneocpp.h"
enum class T1SSymbol : uint8_t {
SSD = 0x04,
ESDOK = 0x07,
BEACON = 0x08,
ESD = 0x0D,
ESDERR = 0x11,
SYNC = 0x18,
ESDJAB = 0x19,
SILENCE = 0x1F
};
std::string getSymbolName(uint8_t value) {
switch(static_cast<T1SSymbol>(value)) {
case T1SSymbol::SSD: return "SSD";
case T1SSymbol::ESDOK: return "ESDOK";
case T1SSymbol::BEACON: return "BEACON";
case T1SSymbol::ESD: return "ESD";
case T1SSymbol::ESDERR: return "ESDERR";
case T1SSymbol::SYNC: return "SYNC";
case T1SSymbol::ESDJAB: return "ESDJAB";
case T1SSymbol::SILENCE: return "SILENCE";
default:
if (value <= 0x0F) {
std::stringstream ss;
ss << "DATA(0x" << std::hex << std::uppercase << (int)value << ")";
return ss.str();
}
std::stringstream ss;
ss << "UNKNOWN(0x" << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)value << std::setfill(' ') << ")";
return ss.str();
}
}
struct T1SStatistics {
std::atomic<uint64_t> symbolCount{0};
std::atomic<uint64_t> beaconCount{0};
std::atomic<uint64_t> wakeCount{0};
std::atomic<uint64_t> burstCount{0};
std::atomic<uint64_t> dataFrameCount{0};
std::map<std::string, uint64_t> symbolStats;
void reset() {
symbolCount = 0;
beaconCount = 0;
wakeCount = 0;
burstCount = 0;
dataFrameCount = 0;
symbolStats.clear();
}
void print() const {
std::cout << std::setfill(' ');
std::cout << "\n" << std::string(70, '=') << std::endl;
std::cout << "T1S SYMBOL DECODING STATISTICS" << std::endl;
std::cout << std::string(70, '=') << std::endl;
std::cout << "Total Symbols: " << symbolCount << std::endl;
std::cout << "Total Beacons: " << beaconCount << std::endl;
std::cout << "Total Wake Signals: " << wakeCount << std::endl;
std::cout << "Total Bursts: " << burstCount << std::endl;
std::cout << "Total Data Frames: " << dataFrameCount << std::endl;
if (!symbolStats.empty()) {
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Symbol Type Breakdown:" << std::endl;
std::cout << std::string(70, '-') << std::endl;
std::vector<std::pair<std::string, uint64_t>> sortedStats(
symbolStats.begin(), symbolStats.end());
std::sort(sortedStats.begin(), sortedStats.end(),
[](const auto& a, const auto& b) { return a.second > b.second; });
for (const auto& [name, count] : sortedStats) {
std::cout << " " << std::left << std::setw(20) << name
<< std::right << std::setw(10) << count << std::endl;
}
}
std::cout << std::string(70, '=') << std::endl;
}
};
bool getUserConfirmation(const std::string& prompt) {
std::string input;
std::cout << prompt << " (y/n): " << std::flush;
std::getline(std::cin, input);
if (!input.empty()) {
char c = static_cast<char>(std::tolower(input[0]));
return (c == 'y');
}
return false;
}
bool configureT1SDecoding(std::shared_ptr<icsneo::Device>& device, icsneo::Network::NetID network,
bool enableSymbols, bool enableBeacons) {
std::cout << "\nConfiguring T1S decoding on network " << icsneo::Network(network) << "..." << std::endl;
if (!device->settings->setT1SBusDecodingAllFor(network, enableSymbols)) {
std::cerr << " ✗ Failed to set T1S symbol decoding" << std::endl;
return false;
}
if (enableSymbols) {
std::cout << " ✓ Enabled decoding of all T1S symbols" << std::endl;
} else {
std::cout << " • T1S symbol decoding disabled" << std::endl;
}
if (!device->settings->setT1SBusDecodingBeaconsFor(network, enableBeacons)) {
std::cerr << " ✗ Failed to set T1S beacon decoding" << std::endl;
return false;
}
if (enableBeacons) {
std::cout << " ✓ Enabled T1S beacon decoding" << std::endl;
} else {
std::cout << " • T1S beacon decoding disabled" << std::endl;
}
if (!device->settings->apply(true)) {
std::cerr << " ✗ Failed to apply settings to device" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
return false;
}
std::cout << " ✓ Settings applied successfully" << std::endl;
return true;
}
void setupSymbolMonitoring(std::shared_ptr<icsneo::Device>& device,
icsneo::Network::NetID network,
T1SStatistics& stats) {
auto callback = std::make_shared<icsneo::MessageCallback>(
icsneo::MessageFilter(network),
[&stats](std::shared_ptr<icsneo::Message> message) {
if (message->type != icsneo::Message::Type::Frame)
return;
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
auto netType = frame->network.getType();
if (netType != icsneo::Network::Type::Ethernet && netType != icsneo::Network::Type::AutomotiveEthernet)
return;
auto ethMsg = std::static_pointer_cast<icsneo::EthernetMessage>(frame);
if (!ethMsg->t1s)
return;
double timestamp_ms = ethMsg->timestamp / 1000000.0;
if (ethMsg->t1s->isSymbol) {
size_t numSymbols = ethMsg->data.size();
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "T1S Symbols";
if (numSymbols > 0) {
std::cout << " (" << numSymbols << " symbol" << (numSymbols > 1 ? "s" : "") << ")";
}
std::cout << " | Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
for (size_t i = 0; i < numSymbols; i++) {
uint8_t symbolValue = ethMsg->data[i];
std::string symbolName = getSymbolName(symbolValue);
stats.symbolCount++;
stats.symbolStats[symbolName]++;
if (symbolValue == static_cast<uint8_t>(T1SSymbol::BEACON)) {
stats.beaconCount++;
}
std::cout << " [" << i << "] " << std::left << std::setw(10) << symbolName << std::right
<< " = 0x" << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)symbolValue << std::setfill(' ')
<< std::dec << std::endl;
}
if (numSymbols == 0 && ethMsg->t1s->symbolType != 0) {
uint8_t symbolValue = ethMsg->t1s->symbolType;
std::string symbolName = getSymbolName(symbolValue);
stats.symbolCount++;
stats.symbolStats[symbolName]++;
if (symbolValue == static_cast<uint8_t>(T1SSymbol::BEACON)) {
stats.beaconCount++;
}
std::cout << " " << std::left << std::setw(10) << symbolName << std::right
<< " = 0x" << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)symbolValue << std::setfill(' ')
<< std::dec << " (from t1sSymbolType field)" << std::endl;
}
}
else if (ethMsg->t1s->isBurst) {
stats.burstCount++;
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "BURST | "
<< "Node ID: " << (int)ethMsg->t1s->nodeId << " | "
<< "Burst Count: " << (int)ethMsg->t1s->burstCount << std::endl;
}
else if (ethMsg->t1s->isWake) {
stats.wakeCount++;
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "WAKE signal detected | "
<< "Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
}
else {
stats.dataFrameCount++;
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "T1S Data Frame | "
<< "Length: " << ethMsg->data.size() << " bytes | "
<< "Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
if (!ethMsg->data.empty()) {
std::cout << " Data: ";
size_t preview_len = std::min(ethMsg->data.size(), size_t(16));
for (size_t i = 0; i < preview_len; i++) {
std::cout << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)ethMsg->data[i] << " ";
}
if (ethMsg->data.size() > 16)
std::cout << "...";
std::cout << std::setfill(' ') << std::dec << std::endl;
}
}
}
);
device->addMessageCallback(callback);
}
int main() {
const icsneo::Network::NetID MONITOR_NETWORK = icsneo::Network::NetID::AE_02;
const int MONITOR_DURATION_SECONDS = 30;
std::cout << "\n" << std::string(70, '=') << std::endl;
std::cout << "10BASE-T1S SYMBOL DECODING EXAMPLE" << std::endl;
std::cout << std::string(70, '=') << std::endl;
std::cout << "libicsneo " << icsneo::GetVersion() << std::endl;
std::cout << std::string(70, '=') << std::endl;
std::cout << "\nFinding devices... " << std::flush;
auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return 1;
}
// List devices
for (const auto& device : devices) {
std::cout << " " << device->describe() << std::endl;
}
std::shared_ptr<icsneo::Device> device;
for (auto& dev : devices) {
if (dev->getType() == icsneo::DeviceType::RADComet3) {
device = dev;
break;
}
}
if (!device && !devices.empty())
device = devices[0];
if (!device) {
std::cerr << "No suitable device found!" << std::endl;
return 1;
}
std::cout << "\nSelected device: " << device->describe() << std::endl;
std::cout << "Serial: " << device->getSerial() << std::endl;
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "T1S DECODING CONFIGURATION" << std::endl;
std::cout << std::string(70, '-') << std::endl;
bool enableSymbols = getUserConfirmation("Enable T1S symbol decoding (all symbols)");
bool enableBeacons = getUserConfirmation("Enable T1S beacon decoding");
std::cout << std::string(70, '-') << std::endl;
std::cout << "\nOpening device... " << std::flush;
if (!device->open()) {
std::cerr << "✗ Failed" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
return 1;
}
std::cout << "" << std::endl;
std::cout << "Enabling message polling... " << std::flush;
if (!device->enableMessagePolling()) {
std::cerr << "✗ Failed" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
device->close();
return 1;
}
device->setPollingMessageLimit(100000);
std::cout << "" << std::endl;
if (!configureT1SDecoding(device, MONITOR_NETWORK, enableSymbols, enableBeacons)) {
device->close();
return 1;
}
std::cout << "Going online... " << std::flush;
if (!device->goOnline()) {
std::cerr << "✗ Failed" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
device->close();
return 1;
}
std::cout << "" << std::endl;
T1SStatistics stats;
setupSymbolMonitoring(device, MONITOR_NETWORK, stats);
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Monitoring T1S traffic for " << MONITOR_DURATION_SECONDS << " seconds..." << std::endl;
std::cout << std::string(70, '-') << std::endl;
auto startTime = std::chrono::steady_clock::now();
std::vector<std::shared_ptr<icsneo::Message>> messages;
messages.reserve(10000);
while (std::chrono::steady_clock::now() - startTime < std::chrono::seconds(MONITOR_DURATION_SECONDS)) {
device->getMessages(messages);
messages.clear();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Closing device... " << std::flush;
device->close();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "" << std::endl;
stats.print();
return 0;
}