// 10BASE-T1S Symbol Decoding Example // Demonstrates T1S bus symbol decoding and analysis #include #include #include #include #include #include #include #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(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 symbolCount{0}; std::atomic beaconCount{0}; std::atomic wakeCount{0}; std::atomic burstCount{0}; std::atomic dataFrameCount{0}; std::map 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> 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(std::tolower(input[0])); return (c == 'y'); } return false; } bool configureT1SDecoding(std::shared_ptr& 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& device, icsneo::Network::NetID network, T1SStatistics& stats) { auto callback = std::make_shared( icsneo::MessageFilter(network), [&stats](std::shared_ptr message) { if (message->type != icsneo::Message::Type::Frame) return; auto frame = std::static_pointer_cast(message); auto netType = frame->network.getType(); if (netType != icsneo::Network::Type::Ethernet && netType != icsneo::Network::Type::AutomotiveEthernet) return; auto ethMsg = std::static_pointer_cast(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(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(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 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> 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; }