From 2ee54d61171ef1566ff804ddb2b013e8cdc0932b Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 11 Oct 2025 18:00:16 -0500 Subject: [PATCH 1/9] new branch --- photon/gpu/vulkanDevice.cpp | 4 +- photon/network/connecter.cpp | 18 ++++ photon/network/network.cpp | 178 ++++++++++++++++++++++++++++++++++- 3 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 photon/network/connecter.cpp diff --git a/photon/gpu/vulkanDevice.cpp b/photon/gpu/vulkanDevice.cpp index 7b55e6bc..7aa8e381 100644 --- a/photon/gpu/vulkanDevice.cpp +++ b/photon/gpu/vulkanDevice.cpp @@ -249,11 +249,11 @@ VkResult VulkanDevice::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPrope memAlloc.pNext = &allocFlagsInfo; } VK_CHECK(vkAllocateMemory(logicalDevice, &memAlloc, nullptr, &buffer->memory)); - +/* logs("[Buffer] size=" << size/1024 << "KB" << " | alloc=" << memAlloc.allocationSize/1024 << "KB" << " | flags=0x" << std::hex << usageFlags << std::dec); - +*/ buffer->alignment = memReqs.alignment; buffer->size = size; buffer->usageFlags = usageFlags; diff --git a/photon/network/connecter.cpp b/photon/network/connecter.cpp new file mode 100644 index 00000000..cfe77cca --- /dev/null +++ b/photon/network/connecter.cpp @@ -0,0 +1,18 @@ +// the purpose of this file is to connect DBC files to their respective CAN IDs. +// also im assuming (its not true) that the DBC file will be accessible like a dictionary +// and same for can IDs but im making it + +EXAMPLE INPUT : +canid_map order; + // Mapping values to keys + order[can1id] = vector info = {"ID", " Name", "DLC", "Transmitter"};; + order[can2id] = vector info = {"ID", " Name", "DLC", "Transmitter"};; + order[can3id] = vector info = {"ID", " Name", "DLC", "Transmitter"};; + +Can1idSG_map order; + + order[signalname1] = vector info = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; + order[signalname2] = vector info = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; + order[signalname2] = vector info = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; + +vector can1id = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; \ No newline at end of file diff --git a/photon/network/network.cpp b/photon/network/network.cpp index 6a20e239..dfefc7ca 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -55,8 +55,8 @@ void Network::parser(){ spscQueue.pop(); if (ch == 't') { - frame.clear(); - frame.push_back(ch); + frame.clear(); // clelaing the message frame + frame.push_back(ch); //appending the ch to the end collecting = true; continue; } @@ -77,13 +77,44 @@ void Network::parser(){ continue; } + if (!collecting && ch == 'B') { + frame.push_back(ch); + frame.push_back(ch); + frame.push_back(ch); + if (frame.size() >= 3 && frame.substr(frame.size() - 3) == "BO_") { + logs("[parser] Detected DBC message definition"); + frame.clear(); frame.push_back(ch); - } else { - std::this_thread::yield(); + collecting = true; + continue; } } + if (collecting && frame.size() >= 3 && frame[0] == 'B') { + // Detect if we just started a new SG_ inside a DBC message + size_t len = frame.size(); + if (len >= 3 && frame[len - 3] == 'S' && frame[len - 2] == 'G' && ch == '_') { + // Complete the "SG_" sequence + frame.push_back(ch); + + // Handle the previous BO_ frame before starting a new one + handleDBCframe(frame); + // example: store message ID for current context + // Sigid = canID; // if you have a signal–to–message mapping + + // Start collecting new SG_ line + frame.clear(); + frame.append("SG_"); + collecting = true; + continue; + } } + frame.push_back(ch); + } else { //doesnt this mean that we'll only get the packets if the queue is empty? + std::this_thread::yield(); + } + } + Network::sample& Network::ensureSample(uint16_t canId) { std::lock_guard guard(sampleMapMutex); auto it = sampleMap.find(canId); @@ -94,12 +125,36 @@ Network::sample& Network::ensureSample(uint16_t canId) { return *(it->second); } +Network::sample& Network::ensureDBC(uint16_t canId, uint64_t rest_of_stuff) { + std::lock_guard guard(sampleMapMutex); + auto it = sampleMap.find(canId); + if (it == sampleMap.end()) { + + auto inserted = (canId)Map.emplace(canId, std::make_unique()); + it = inserted.first; + } + return *(it->second); +} + void Network::writeSample(uint16_t canId, uint64_t value) { sample& entry = ensureSample(canId); std::lock_guard valueGuard(entry.lock); entry.point = value; } +void Network::writeDBC(uint16_t canId, uint64_t value) { + sample& entry = ensureSample(canId); + std::lock_guard valueGuard(entry.lock); + entry.point = value; +} + +void Network::writeSignal(uint16_t canId, uint64_t value) { + sample& entry = ensureSample(canId); + std::lock_guard valueGuard(entry.lock); + entry.point = value; +} + + bool Network::readSample(uint16_t canId, uint64_t& outValue) { std::unique_lock mapLock(sampleMapMutex); auto it = sampleMap.find(canId); @@ -126,6 +181,28 @@ void Network::handleFrame(const std::string& frame) { //logs("[parser] CAN 0x" << std::hex << canId << " value 0x" << value << std::dec); } +void Network::handleDBCframe(const std::string& frame) { + if (frame[0] == 'B') { + uint16t_t canID = 0; + uint64t_t rest_of_stuff = 0; + if (!decodeDBCFrame(frame, canID, value)) { + logs("[parser] Invalid DBC frame encountered"); + return; + writeDBC(canID, rest_of_stuff); + } + else if (frame[0] == 'S') { + uint16t_t canID = 0; + uint64t_t signal = 0; + if (!decodeSIGFrame(frame, canID, value)) { + logs("[parser] Invalid signal frame encountered"); + return; + writeSignal(canID, signal); + } + } + + +} + bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value) { if (frame.empty() || frame.front() != 't') { return false; @@ -173,5 +250,98 @@ bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& v value = (value << 8) | byte; } + + + return true; + +bool Network::decodeDBCFrame(const std::string& frame, uint16_t& canId, uint64_t& rest_of__stuff) { + if (frame.empty() || frame.front() != 'B') { + return false; + } + + // Example: frame = "BO_ 1234:5678" + // Index 1–4 contain CAN ID digits (e.g., 1234) + size_t index = 1; + canId = 0; + + // Ensure there are digits at position 1–4 + for (; index < frame.size() && std::isdigit(static_cast(frame[index])); ++index) { + canId = canId * 10 + (frame[index] - '0'); + } + + // Expect a colon next + if (index >= frame.size() || frame[index] != ':') { + return false; + } + ++index; // move past the colon + + // Parse value (up to the end or until a non-digit) + value = 0; + for (; index < frame.size(); ++index) { + char ch = frame[index]; + if (!std::isdigit(static_cast(ch))) { + return false; + } + value = value * 10 + (ch - '0'); + } + + return true; +} + + +bool Network::decodeSIGFrame(const std::string& frame, uint16_t& canId, uint64_t& signal) { + // minimal format validation, not full parse + if (frame.empty() || frame.rfind("SG_", 0) != 0) { + return false; + } + + // example structure: SG_ SignalName : 24|16@1+ (0.125,0) [0|8000] "rpm" Vector__XXX + for (size_t i = 0; i < frame.size(); ++i) { + char ch = frame[i]; + + // colon must have space before and after ( ...name : startbit... ) + if (ch == ':') { + if (i == 0 || i + 1 >= frame.size()) return false; + char before = frame[i - 1]; + char after = frame[i + 1]; + if (!std::isspace(static_cast(before)) || + !std::isspace(static_cast(after))) { + logs("[decodeSIGFrame] invalid spacing around ':'"); + return false; + } + } + + // '|' separates start bit and length => must have digits on both sides + else if (ch == '|') { + if (i == 0 || i + 1 >= frame.size()) return false; + char before = frame[i - 1]; + char after = frame[i + 1]; + if (!std::isdigit(static_cast(before)) || + !std::isdigit(static_cast(after))) { + logs("[decodeSIGFrame] '|' not surrounded by digits"); + return false; + } + } + + // '@' should be followed by '0' or '1' (byte order indicator) + else if (ch == '@') { + if (i + 1 >= frame.size()) return false; + char after = frame[i + 1]; + if (after != '0' && after != '1') { + logs("[decodeSIGFrame] '@' not followed by 0 or 1"); + return false; + } + } + } + + // if we reach here, the line looks structurally correct + // (you can later expand this to extract startBit/length/etc.) + canId = 0; // not encoded in SG_ line itself — usually inherited from BO_ + signal = 0; // placeholder until real parsing is implemented + return true; +} + + // new changes + } From 6840c0fbc1f074acd8e8dfc831fae4b464a07bf6 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 25 Oct 2025 11:25:26 -0500 Subject: [PATCH 2/9] this is my like final for network --- photon/network/network.cpp | 339 +++++++++++++++---------------------- 1 file changed, 135 insertions(+), 204 deletions(-) diff --git a/photon/network/network.cpp b/photon/network/network.cpp index dfefc7ca..42eb73f4 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -7,32 +7,25 @@ #include #include #include +#include #include "../engine/include.hpp" int hexValue(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - if (c >= 'a' && c <= 'f') { - return 10 + (c - 'a'); - } - if (c >= 'A' && c <= 'F') { - return 10 + (c - 'A'); - } + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); + if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); return -1; } #define QUEUE_CAPACITY 2048 -Network::Network() : spscQueue(QUEUE_CAPACITY){ - -} +Network::Network() : spscQueue(QUEUE_CAPACITY) {} #define BUFFER_CAPACITY 1024 -void Network::producer(){ +void Network::producer() { TcpSocket socket(IP, PORT); std::vector buffer(BUFFER_CAPACITY); - while(1){ + while (1) { auto bytesRead = socket.read(buffer.data(), buffer.size()); if (bytesRead > 0) { for (std::size_t i = 0; i < static_cast(bytesRead); ++i) { @@ -44,32 +37,43 @@ void Network::producer(){ } } -void Network::parser(){ +void Network::parser() { std::string frame; - frame.reserve(32); + frame.reserve(256); bool collecting = false; + std::string lookahead; // rolling buffer for pattern detection + lookahead.reserve(4); - while(1){ - if(auto* byte = spscQueue.front()){ + while (1) { + if (auto* byte = spscQueue.front()) { char ch = static_cast(*byte); spscQueue.pop(); + // detect start of standard CAN frame if (ch == 't') { - frame.clear(); // clelaing the message frame - frame.push_back(ch); //appending the ch to the end + frame.clear(); + frame.push_back(ch); collecting = true; continue; } - if (!collecting) { + // skip until collection begins + if (!collecting && ch != 'B' && ch != 'S') { continue; } + // handle end of a line if (ch == '\r') { - frame.push_back(ch); - handleFrame(frame); + if (!frame.empty()) { + // decide what kind of frame this is + if (frame.find("BO_") != std::string::npos || frame.find("SG_") != std::string::npos) + handleDBCframe(frame); + else + handleFrame(frame); + } frame.clear(); collecting = false; + lookahead.clear(); continue; } @@ -77,43 +81,40 @@ void Network::parser(){ continue; } - if (!collecting && ch == 'B') { - frame.push_back(ch); - frame.push_back(ch); - frame.push_back(ch); - if (frame.size() >= 3 && frame.substr(frame.size() - 3) == "BO_") { - logs("[parser] Detected DBC message definition"); - frame.clear(); frame.push_back(ch); - collecting = true; - continue; - } - } - if (collecting && frame.size() >= 3 && frame[0] == 'B') { - // Detect if we just started a new SG_ inside a DBC message - size_t len = frame.size(); - if (len >= 3 && frame[len - 3] == 'S' && frame[len - 2] == 'G' && ch == '_') { - // Complete the "SG_" sequence - frame.push_back(ch); - - // Handle the previous BO_ frame before starting a new one + lookahead.push_back(ch); + if (lookahead.size() > 3) lookahead.erase(0, lookahead.size() - 3); + + // detect new DBC message (BO_) + if (lookahead == "BO_") { + logs("[parser] Detected start of DBC message (BO_)"); + frame.clear(); + frame.append("BO_"); + collecting = true; + continue; + } + + // detect new DBC signal (SG_) + if (lookahead == "SG_") { + logs("[parser] Detected start of DBC signal (SG_)"); + + // flush previous BO_ message before collecting this new signal + if (!frame.empty() && frame.find("BO_") != std::string::npos) { handleDBCframe(frame); - // example: store message ID for current context - // Sigid = canID; // if you have a signal–to–message mapping - - // Start collecting new SG_ line - frame.clear(); - frame.append("SG_"); - collecting = true; - continue; } -} - frame.push_back(ch); - } else { //doesnt this mean that we'll only get the packets if the queue is empty? + frame.clear(); + frame.append("SG_"); + collecting = true; + continue; + } + + } else { std::this_thread::yield(); } } +} + Network::sample& Network::ensureSample(uint16_t canId) { std::lock_guard guard(sampleMapMutex); @@ -125,12 +126,11 @@ Network::sample& Network::ensureSample(uint16_t canId) { return *(it->second); } -Network::sample& Network::ensureDBC(uint16_t canId, uint64_t rest_of_stuff) { - std::lock_guard guard(sampleMapMutex); - auto it = sampleMap.find(canId); - if (it == sampleMap.end()) { - - auto inserted = (canId)Map.emplace(canId, std::make_unique()); +Network::DbcMessage& Network::ensureDBC(uint32_t canId) { + std::lock_guard guard(dbcMapMutex); + auto it = dbcMap.find(canId); + if (it == dbcMap.end()) { + auto inserted = dbcMap.emplace(canId, std::make_unique()); it = inserted.first; } return *(it->second); @@ -142,33 +142,33 @@ void Network::writeSample(uint16_t canId, uint64_t value) { entry.point = value; } -void Network::writeDBC(uint16_t canId, uint64_t value) { - sample& entry = ensureSample(canId); - std::lock_guard valueGuard(entry.lock); - entry.point = value; +void Network::writeDBC(uint32_t canId, const std::string& name, uint8_t dlc, const std::string& sender) { + DbcMessage& msg = ensureDBC(canId); + std::lock_guard guard(dbcMapMutex); + msg.name = name; + msg.dlc = dlc; + msg.sender = sender; } -void Network::writeSignal(uint16_t canId, uint64_t value) { - sample& entry = ensureSample(canId); - std::lock_guard valueGuard(entry.lock); - entry.point = value; +void Network::writeSignal(uint32_t canId, const DbcSignal& sig) { + DbcMessage& msg = ensureDBC(canId); + std::lock_guard guard(dbcMapMutex); + msg.signals.push_back(sig); } - bool Network::readSample(uint16_t canId, uint64_t& outValue) { std::unique_lock mapLock(sampleMapMutex); auto it = sampleMap.find(canId); - if (it == sampleMap.end()) { - return false; - } + if (it == sampleMap.end()) return false; sample* entry = it->second.get(); mapLock.unlock(); - std::lock_guard valueGuard(entry->lock); outValue = entry->point; return true; } +//FRAME HANDLING + void Network::handleFrame(const std::string& frame) { uint16_t canId = 0; uint64_t value = 0; @@ -176,66 +176,52 @@ void Network::handleFrame(const std::string& frame) { logs("[parser] Invalid SLCAN frame encountered"); return; } - writeSample(canId, value); - //logs("[parser] CAN 0x" << std::hex << canId << " value 0x" << value << std::dec); } +//DBC HANDLING + void Network::handleDBCframe(const std::string& frame) { - if (frame[0] == 'B') { - uint16t_t canID = 0; - uint64t_t rest_of_stuff = 0; - if (!decodeDBCFrame(frame, canID, value)) { - logs("[parser] Invalid DBC frame encountered"); + if (frame.rfind("BO_", 0) == 0) { + uint32_t canID = 0; std::string name, sender; uint8_t dlc = 0; + if (!decodeDBCFrame(frame, canID, name, dlc, sender)) { + logs("[parser] Invalid DBC BO_ frame encountered"); return; - writeDBC(canID, rest_of_stuff); + } + writeDBC(canID, name, dlc, sender); + currentCanId = canID; // Remember for SG_ lines + return; } - else if (frame[0] == 'S') { - uint16t_t canID = 0; - uint64t_t signal = 0; - if (!decodeSIGFrame(frame, canID, value)) { - logs("[parser] Invalid signal frame encountered"); + if (frame.rfind("SG_", 0) == 0) { + if (currentCanId == 0) { + logs("[parser] SG_ encountered before BO_"); + return; + } + DbcSignal sig; + if (!decodeSIGFrame(frame, currentCanId, sig)) { + logs("[parser] Invalid DBC SG_ frame encountered"); return; - writeSignal(canID, signal); } + writeSignal(currentCanId, sig); + return; } - - } bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value) { - if (frame.empty() || frame.front() != 't') { - return false; - } - if (frame.back() != '\r') { - return false; - } - - if (frame.size() < 5) { - return false; - } - - const std::size_t payloadLength = frame.size() - 1; - if (payloadLength < 5) { - return false; - } + if (frame.empty() || frame.front() != 't') return false; + if (frame.back() != '\r') return false; + if (frame.size() < 5) return false; int dataLength = hexValue(frame[4]); - if (dataLength < 0 || dataLength > 8) { - return false; - } + if (dataLength < 0 || dataLength > 8) return false; const std::size_t expectedLength = 5 + static_cast(dataLength) * 2; - if (payloadLength != expectedLength) { - return false; - } + if (frame.size() - 1 != expectedLength) return false; canId = 0; for (std::size_t i = 1; i <= 3; ++i) { int nibble = hexValue(frame[i]); - if (nibble < 0) { - return false; - } + if (nibble < 0) return false; canId = static_cast((canId << 4) | static_cast(nibble)); } @@ -243,105 +229,50 @@ bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& v for (int i = 0; i < dataLength; ++i) { int hi = hexValue(frame[5 + i * 2]); int lo = hexValue(frame[6 + i * 2]); - if (hi < 0 || lo < 0) { - return false; - } + if (hi < 0 || lo < 0) return false; uint8_t byte = static_cast((hi << 4) | lo); value = (value << 8) | byte; } - - - - return true; - -bool Network::decodeDBCFrame(const std::string& frame, uint16_t& canId, uint64_t& rest_of__stuff) { - if (frame.empty() || frame.front() != 'B') { - return false; - } - - // Example: frame = "BO_ 1234:5678" - // Index 1–4 contain CAN ID digits (e.g., 1234) - size_t index = 1; - canId = 0; - - // Ensure there are digits at position 1–4 - for (; index < frame.size() && std::isdigit(static_cast(frame[index])); ++index) { - canId = canId * 10 + (frame[index] - '0'); - } - - // Expect a colon next - if (index >= frame.size() || frame[index] != ':') { - return false; - } - ++index; // move past the colon - - // Parse value (up to the end or until a non-digit) - value = 0; - for (; index < frame.size(); ++index) { - char ch = frame[index]; - if (!std::isdigit(static_cast(ch))) { - return false; - } - value = value * 10 + (ch - '0'); - } - return true; } - -bool Network::decodeSIGFrame(const std::string& frame, uint16_t& canId, uint64_t& signal) { - // minimal format validation, not full parse - if (frame.empty() || frame.rfind("SG_", 0) != 0) { - return false; - } - - // example structure: SG_ SignalName : 24|16@1+ (0.125,0) [0|8000] "rpm" Vector__XXX - for (size_t i = 0; i < frame.size(); ++i) { - char ch = frame[i]; - - // colon must have space before and after ( ...name : startbit... ) - if (ch == ':') { - if (i == 0 || i + 1 >= frame.size()) return false; - char before = frame[i - 1]; - char after = frame[i + 1]; - if (!std::isspace(static_cast(before)) || - !std::isspace(static_cast(after))) { - logs("[decodeSIGFrame] invalid spacing around ':'"); - return false; - } - } - - // '|' separates start bit and length => must have digits on both sides - else if (ch == '|') { - if (i == 0 || i + 1 >= frame.size()) return false; - char before = frame[i - 1]; - char after = frame[i + 1]; - if (!std::isdigit(static_cast(before)) || - !std::isdigit(static_cast(after))) { - logs("[decodeSIGFrame] '|' not surrounded by digits"); - return false; - } - } - - // '@' should be followed by '0' or '1' (byte order indicator) - else if (ch == '@') { - if (i + 1 >= frame.size()) return false; - char after = frame[i + 1]; - if (after != '0' && after != '1') { - logs("[decodeSIGFrame] '@' not followed by 0 or 1"); - return false; - } - } - } - - // if we reach here, the line looks structurally correct - // (you can later expand this to extract startBit/length/etc.) - canId = 0; // not encoded in SG_ line itself — usually inherited from BO_ - signal = 0; // placeholder until real parsing is implemented - +bool Network::decodeDBCFrame(const std::string& frame, + uint32_t& canId, + std::string& name, + uint8_t& dlc, + std::string& sender) { + if (frame.empty() || frame.rfind("BO_", 0) != 0) return false; + std::istringstream iss(frame); + std::string tag; + iss >> tag; // BO_ + iss >> canId; + std::string temp; + iss >> temp; // name: + auto colon = temp.find(':'); + if (colon == std::string::npos) return false; + name = temp.substr(0, colon); + std::string dlcStr; + iss >> dlcStr; + dlc = static_cast(std::stoi(dlcStr)); + iss >> sender; return true; } - // new changes - +bool Network::decodeSIGFrame(const std::string& frame, + uint32_t& canId, + DbcSignal& sig) { + if (frame.empty() || frame.rfind("SG_", 0) != 0) return false; + + std::istringstream iss(frame); + std::string tag; iss >> tag; // SG_ + iss >> sig.name; // EngineSpeed + char colon; iss >> colon; // : + iss >> sig.startBit; // 24 + iss.ignore(1, '|'); + iss >> sig.length; // 16 + char at; iss >> at; // @ + iss >> sig.byteOrder; // 1 + char sign; iss >> sign; // + + sig.isSigned = (sign == '-'); + return true; } From 4cfd3a28ffa0533a251947d00a2cd5a120fddb72 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 25 Oct 2025 11:35:30 -0500 Subject: [PATCH 3/9] connector+network patch --- photon/network/connecter.cpp | 99 +++++++++++++++++++++---- photon/network/network.cpp | 140 ++++++++++++++++++----------------- 2 files changed, 159 insertions(+), 80 deletions(-) diff --git a/photon/network/connecter.cpp b/photon/network/connecter.cpp index cfe77cca..8395ecf5 100644 --- a/photon/network/connecter.cpp +++ b/photon/network/connecter.cpp @@ -1,18 +1,89 @@ -// the purpose of this file is to connect DBC files to their respective CAN IDs. -// also im assuming (its not true) that the DBC file will be accessible like a dictionary -// and same for can IDs but im making it +/* [ξ] DBC Connector Interface + Connects parsed DBC definitions to their respective CAN IDs. + Acts like a runtime dictionary for DBC → CAN lookup. +*/ -EXAMPLE INPUT : -canid_map order; - // Mapping values to keys - order[can1id] = vector info = {"ID", " Name", "DLC", "Transmitter"};; - order[can2id] = vector info = {"ID", " Name", "DLC", "Transmitter"};; - order[can3id] = vector info = {"ID", " Name", "DLC", "Transmitter"};; +#include +#include +#include +#include +#include -Can1idSG_map order; +struct DbcSignalInfo { + int startBit; + int length; + int endianness; // 1 = little, 0 = big + bool isSigned; + double factor; + double offset; + double minVal; + double maxVal; +}; - order[signalname1] = vector info = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; - order[signalname2] = vector info = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; - order[signalname2] = vector info = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; +struct DbcMessageInfo { + int canId; + std::string name; + int dlc; + std::string transmitter; -vector can1id = {"startbit", " length", "endianness", "signedness", "factor", "Offset" , "min" Max"};; \ No newline at end of file + // Each message holds multiple signal definitions + std::unordered_map signals; +}; + +class DbcConnector { +public: + // Top-level: map CAN IDs → DBC message info + std::unordered_map> dbcMap; + + // Register a new CAN message (BO_ line) + void registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter) { + auto msg = std::make_shared(); + msg->canId = canId; + msg->name = name; + msg->dlc = dlc; + msg->transmitter = transmitter; + dbcMap[canId] = msg; + } + + // Register a new signal for a given CAN ID (SG_ line) + void registerSignal(int canId, + const std::string& signalName, + int startBit, + int length, + int endianness, + bool isSigned, + double factor, + double offset, + double minVal, + double maxVal) { + if (dbcMap.find(canId) == dbcMap.end()) { + std::cerr << "[Connector] Error: CAN ID " << canId << " not registered before SG_ line\n"; + return; + } + + DbcSignalInfo sig{ startBit, length, endianness, isSigned, factor, offset, minVal, maxVal }; + dbcMap[canId]->signals[signalName] = sig; + } + + // Print all stored mappings for debugging + void dump() const { + for (const auto& [id, msg] : dbcMap) { + std::cout << "CAN ID: " << id << " | Name: " << msg->name + << " | DLC: " << msg->dlc + << " | Transmitter: " << msg->transmitter << "\n"; + + for (const auto& [sigName, sig] : msg->signals) { + std::cout << " └─ Signal: " << sigName + << " (StartBit: " << sig.startBit + << ", Len: " << sig.length + << ", Endian: " << sig.endianness + << ", Signed: " << sig.isSigned + << ", Factor: " << sig.factor + << ", Offset: " << sig.offset + << ", Min: " << sig.minVal + << ", Max: " << sig.maxVal + << ")\n"; + } + } + } +}; diff --git a/photon/network/network.cpp b/photon/network/network.cpp index 42eb73f4..a27a1ed8 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -1,4 +1,3 @@ -/*[ξ] the photon network interface*/ #include "network.hpp" #include "tcp.hpp" #include "spsc.hpp" @@ -8,6 +7,8 @@ #include #include #include +#include +#include #include "../engine/include.hpp" int hexValue(char c) { @@ -17,6 +18,56 @@ int hexValue(char c) { return -1; } +struct DbcSignalInfo { + int startBit; + int length; + int endianness; + bool isSigned; + double factor; + double offset; + double minVal; + double maxVal; +}; + +struct DbcMessageInfo { + int canId; + std::string name; + int dlc; + std::string transmitter; + std::unordered_map signals; +}; + +class DbcConnector { +public: + std::unordered_map> dbcMap; + + void registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter) { + auto msg = std::make_shared(); + msg->canId = canId; + msg->name = name; + msg->dlc = dlc; + msg->transmitter = transmitter; + dbcMap[canId] = msg; + } + + void registerSignal(int canId, + const std::string& signalName, + int startBit, + int length, + int endianness, + bool isSigned, + double factor, + double offset, + double minVal, + double maxVal) { + if (dbcMap.find(canId) == dbcMap.end()) return; + DbcSignalInfo sig{ startBit, length, endianness, isSigned, factor, offset, minVal, maxVal }; + dbcMap[canId]->signals[signalName] = sig; + } +}; + +static DbcConnector dbcConnector; + #define QUEUE_CAPACITY 2048 Network::Network() : spscQueue(QUEUE_CAPACITY) {} @@ -24,14 +75,11 @@ Network::Network() : spscQueue(QUEUE_CAPACITY) {} void Network::producer() { TcpSocket socket(IP, PORT); std::vector buffer(BUFFER_CAPACITY); - while (1) { auto bytesRead = socket.read(buffer.data(), buffer.size()); if (bytesRead > 0) { for (std::size_t i = 0; i < static_cast(bytesRead); ++i) { - while (!spscQueue.try_push(buffer[i])) { - std::this_thread::yield(); - } + while (!spscQueue.try_push(buffer[i])) std::this_thread::yield(); } } } @@ -41,31 +89,21 @@ void Network::parser() { std::string frame; frame.reserve(256); bool collecting = false; - std::string lookahead; // rolling buffer for pattern detection + std::string lookahead; lookahead.reserve(4); - while (1) { if (auto* byte = spscQueue.front()) { char ch = static_cast(*byte); spscQueue.pop(); - - // detect start of standard CAN frame if (ch == 't') { frame.clear(); frame.push_back(ch); collecting = true; continue; } - - // skip until collection begins - if (!collecting && ch != 'B' && ch != 'S') { - continue; - } - - // handle end of a line + if (!collecting && ch != 'B' && ch != 'S') continue; if (ch == '\r') { if (!frame.empty()) { - // decide what kind of frame this is if (frame.find("BO_") != std::string::npos || frame.find("SG_") != std::string::npos) handleDBCframe(frame); else @@ -76,16 +114,10 @@ void Network::parser() { lookahead.clear(); continue; } - - if (ch == '\n') { - continue; - } - + if (ch == '\n') continue; frame.push_back(ch); lookahead.push_back(ch); if (lookahead.size() > 3) lookahead.erase(0, lookahead.size() - 3); - - // detect new DBC message (BO_) if (lookahead == "BO_") { logs("[parser] Detected start of DBC message (BO_)"); frame.clear(); @@ -93,29 +125,18 @@ void Network::parser() { collecting = true; continue; } - - // detect new DBC signal (SG_) if (lookahead == "SG_") { logs("[parser] Detected start of DBC signal (SG_)"); - - // flush previous BO_ message before collecting this new signal - if (!frame.empty() && frame.find("BO_") != std::string::npos) { - handleDBCframe(frame); - } - + if (!frame.empty() && frame.find("BO_") != std::string::npos) handleDBCframe(frame); frame.clear(); frame.append("SG_"); collecting = true; continue; } - - } else { - std::this_thread::yield(); - } + } else std::this_thread::yield(); } } - Network::sample& Network::ensureSample(uint16_t canId) { std::lock_guard guard(sampleMapMutex); auto it = sampleMap.find(canId); @@ -148,12 +169,14 @@ void Network::writeDBC(uint32_t canId, const std::string& name, uint8_t dlc, con msg.name = name; msg.dlc = dlc; msg.sender = sender; + dbcConnector.registerMessage(canId, name, dlc, sender); } void Network::writeSignal(uint32_t canId, const DbcSignal& sig) { DbcMessage& msg = ensureDBC(canId); std::lock_guard guard(dbcMapMutex); msg.signals.push_back(sig); + dbcConnector.registerSignal(canId, sig.name, sig.startBit, sig.length, sig.byteOrder, sig.isSigned, sig.scale, sig.offset, sig.minVal, sig.maxVal); } bool Network::readSample(uint16_t canId, uint64_t& outValue) { @@ -167,8 +190,6 @@ bool Network::readSample(uint16_t canId, uint64_t& outValue) { return true; } -//FRAME HANDLING - void Network::handleFrame(const std::string& frame) { uint16_t canId = 0; uint64_t value = 0; @@ -179,8 +200,6 @@ void Network::handleFrame(const std::string& frame) { writeSample(canId, value); } -//DBC HANDLING - void Network::handleDBCframe(const std::string& frame) { if (frame.rfind("BO_", 0) == 0) { uint32_t canID = 0; std::string name, sender; uint8_t dlc = 0; @@ -189,7 +208,7 @@ void Network::handleDBCframe(const std::string& frame) { return; } writeDBC(canID, name, dlc, sender); - currentCanId = canID; // Remember for SG_ lines + currentCanId = canID; return; } if (frame.rfind("SG_", 0) == 0) { @@ -211,20 +230,16 @@ bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& v if (frame.empty() || frame.front() != 't') return false; if (frame.back() != '\r') return false; if (frame.size() < 5) return false; - int dataLength = hexValue(frame[4]); if (dataLength < 0 || dataLength > 8) return false; - const std::size_t expectedLength = 5 + static_cast(dataLength) * 2; if (frame.size() - 1 != expectedLength) return false; - canId = 0; for (std::size_t i = 1; i <= 3; ++i) { int nibble = hexValue(frame[i]); if (nibble < 0) return false; canId = static_cast((canId << 4) | static_cast(nibble)); } - value = 0; for (int i = 0; i < dataLength; ++i) { int hi = hexValue(frame[5 + i * 2]); @@ -236,18 +251,14 @@ bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& v return true; } -bool Network::decodeDBCFrame(const std::string& frame, - uint32_t& canId, - std::string& name, - uint8_t& dlc, - std::string& sender) { +bool Network::decodeDBCFrame(const std::string& frame, uint32_t& canId, std::string& name, uint8_t& dlc, std::string& sender) { if (frame.empty() || frame.rfind("BO_", 0) != 0) return false; std::istringstream iss(frame); std::string tag; - iss >> tag; // BO_ + iss >> tag; iss >> canId; std::string temp; - iss >> temp; // name: + iss >> temp; auto colon = temp.find(':'); if (colon == std::string::npos) return false; name = temp.substr(0, colon); @@ -258,21 +269,18 @@ bool Network::decodeDBCFrame(const std::string& frame, return true; } -bool Network::decodeSIGFrame(const std::string& frame, - uint32_t& canId, - DbcSignal& sig) { +bool Network::decodeSIGFrame(const std::string& frame, uint32_t& canId, DbcSignal& sig) { if (frame.empty() || frame.rfind("SG_", 0) != 0) return false; - std::istringstream iss(frame); - std::string tag; iss >> tag; // SG_ - iss >> sig.name; // EngineSpeed - char colon; iss >> colon; // : - iss >> sig.startBit; // 24 + std::string tag; iss >> tag; + iss >> sig.name; + char colon; iss >> colon; + iss >> sig.startBit; iss.ignore(1, '|'); - iss >> sig.length; // 16 - char at; iss >> at; // @ - iss >> sig.byteOrder; // 1 - char sign; iss >> sign; // + + iss >> sig.length; + char at; iss >> at; + iss >> sig.byteOrder; + char sign; iss >> sign; sig.isSigned = (sign == '-'); return true; -} +} \ No newline at end of file From 32b54fe1f6d64a959c3ebd22341d92e2d785da13 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 25 Oct 2025 11:43:47 -0500 Subject: [PATCH 4/9] seeing whats wrong --- photon/network/network.cpp | 2 +- photon/network/network.hpp | 59 ++++++++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/photon/network/network.cpp b/photon/network/network.cpp index a27a1ed8..dca28041 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -194,7 +194,7 @@ void Network::handleFrame(const std::string& frame) { uint16_t canId = 0; uint64_t value = 0; if (!decodeFrame(frame, canId, value)) { - logs("[parser] Invalid SLCAN frame encountered"); + logs("[parser] Invalid SLCAN frame encountered → \"" + frame + "\""); return; } writeSample(canId, value); diff --git a/photon/network/network.hpp b/photon/network/network.hpp index 30ff3acb..4a3bfbc6 100644 --- a/photon/network/network.hpp +++ b/photon/network/network.hpp @@ -6,10 +6,40 @@ #include #include #include +#include #include "spsc.hpp" -class Network{ +class Network { private: + struct sample { + sample() = default; + sample(const sample&) = delete; + sample& operator=(const sample&) = delete; + sample(sample&&) = delete; + sample& operator=(sample&&) = delete; + + std::mutex lock; + uint64_t point = 0; + }; + + struct DbcSignal { + std::string name; + int startBit = 0; + int length = 0; + int byteOrder = 0; + bool isSigned = false; + double scale = 1.0; + double offset = 0.0; + double minVal = 0.0; + double maxVal = 0.0; + }; + + struct DbcMessage { + std::string name; + uint8_t dlc = 0; + std::string sender; + std::vector signals; + }; public: Network(); @@ -20,28 +50,27 @@ class Network{ void writeSample(uint16_t canId, uint64_t value); SPSCQueue spscQueue; - std::string IP ="3.141.38.115"; + std::string IP = "3.141.38.115"; unsigned PORT = 8187; - private: - struct sample { - sample() = default; - sample(const sample&) = delete; - sample& operator=(const sample&) = delete; - sample(sample&&) = delete; - sample& operator=(sample&&) = delete; - - std::mutex lock; - uint64_t point = 0; - }; - sample& ensureSample(uint16_t canId); bool decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value); void handleFrame(const std::string& frame); + // DBC system + DbcMessage& ensureDBC(uint32_t canId); + void writeDBC(uint32_t canId, const std::string& name, uint8_t dlc, const std::string& sender); + void writeSignal(uint32_t canId, const DbcSignal& sig); + void handleDBCframe(const std::string& frame); + bool decodeDBCFrame(const std::string& frame, uint32_t& canId, std::string& name, uint8_t& dlc, std::string& sender); + bool decodeSIGFrame(const std::string& frame, uint32_t& canId, DbcSignal& sig); + std::mutex sampleMapMutex; std::unordered_map> sampleMap; -/* end of network class */ + std::mutex dbcMapMutex; + std::unordered_map> dbcMap; + + uint32_t currentCanId = 0; }; From 1f9ddfff2f90f41c2100446a1562ca54ba71a323 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 25 Oct 2025 12:44:31 -0500 Subject: [PATCH 5/9] fixedpush --- photon/network/network.cpp | 68 +++++++++++++++++++++++++++++++++----- photon/network/network.hpp | 4 ++- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/photon/network/network.cpp b/photon/network/network.cpp index dca28041..f985a5cf 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -75,12 +75,12 @@ Network::Network() : spscQueue(QUEUE_CAPACITY) {} void Network::producer() { TcpSocket socket(IP, PORT); std::vector buffer(BUFFER_CAPACITY); - while (1) { + while (1){ auto bytesRead = socket.read(buffer.data(), buffer.size()); if (bytesRead > 0) { for (std::size_t i = 0; i < static_cast(bytesRead); ++i) { while (!spscQueue.try_push(buffer[i])) std::this_thread::yield(); - } +} } } } @@ -202,38 +202,50 @@ void Network::handleFrame(const std::string& frame) { void Network::handleDBCframe(const std::string& frame) { if (frame.rfind("BO_", 0) == 0) { - uint32_t canID = 0; std::string name, sender; uint8_t dlc = 0; + uint32_t canID = 0; + std::string name, sender; + uint8_t dlc = 0; + if (!decodeDBCFrame(frame, canID, name, dlc, sender)) { - logs("[parser] Invalid DBC BO_ frame encountered"); + logs("[parser] Invalid DBC BO_ frame encountered → " + frame); return; } + writeDBC(canID, name, dlc, sender); currentCanId = canID; + logs("[parser] Registered BO_ " + name + " (CAN ID: " + std::to_string(canID) + ")"); + printDBCMap(); // ✅ print here after adding new BO_ return; } + if (frame.rfind("SG_", 0) == 0) { if (currentCanId == 0) { - logs("[parser] SG_ encountered before BO_"); + logs("[parser] SG_ encountered before BO_ → " + frame); return; } + DbcSignal sig; if (!decodeSIGFrame(frame, currentCanId, sig)) { - logs("[parser] Invalid DBC SG_ frame encountered"); + logs("[parser] Invalid DBC SG_ frame encountered → " + frame); return; } + writeSignal(currentCanId, sig); + logs("[parser] Registered SG_ " + sig.name + " for CAN ID " + std::to_string(currentCanId)); + printDBCMap(); // ✅ print here after adding new SG_ return; } } bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value) { if (frame.empty() || frame.front() != 't') return false; - if (frame.back() != '\r') return false; + // if (frame.back() != '\r') return false; if (frame.size() < 5) return false; int dataLength = hexValue(frame[4]); if (dataLength < 0 || dataLength > 8) return false; const std::size_t expectedLength = 5 + static_cast(dataLength) * 2; - if (frame.size() - 1 != expectedLength) return false; + if (frame.size() != expectedLength) return false; + // logs(std::to_string(frame.size()) + " vs " + std::to_string(expectedLength)); canId = 0; for (std::size_t i = 1; i <= 3; ++i) { int nibble = hexValue(frame[i]); @@ -283,4 +295,42 @@ bool Network::decodeSIGFrame(const std::string& frame, uint32_t& canId, DbcSigna char sign; iss >> sign; sig.isSigned = (sign == '-'); return true; -} \ No newline at end of file +} + +void Network::printDBCMap() { + std::lock_guard guard(dbcMapMutex); + + if (dbcMap.empty()) { + logs("[DBC] No DBC messages stored yet."); + return; + } + + logs("========== DBC MAP =========="); + for (const auto& [canId, msgPtr] : dbcMap) { + const auto& msg = *msgPtr; + std::ostringstream oss; + oss << "[DBC] CAN ID: " << canId + << " | Name: " << msg.name + << " | DLC: " << (int)msg.dlc + << " | Sender: " << msg.sender; + logs(oss.str()); + + if (msg.signals.empty()) { + logs(" (No signals found for this message)"); + } else { + for (const auto& sig : msg.signals) { + std::ostringstream sigoss; + sigoss << " SG_ " << sig.name + << " : start=" << sig.startBit + << " len=" << sig.length + << " @byteOrder=" << sig.byteOrder + << (sig.isSigned ? " signed" : " unsigned") + << " scale=" << sig.scale + << " offset=" << sig.offset + << " [" << sig.minVal << "|" << sig.maxVal << "]"; + logs(sigoss.str()); + } + } + } + logs("============================="); +} diff --git a/photon/network/network.hpp b/photon/network/network.hpp index 4a3bfbc6..85c932d1 100644 --- a/photon/network/network.hpp +++ b/photon/network/network.hpp @@ -44,13 +44,14 @@ class Network { public: Network(); void producer(); + void printDBCMap(); void parser(); bool readSample(uint16_t canId, uint64_t& outValue); void writeSample(uint16_t canId, uint64_t value); SPSCQueue spscQueue; - std::string IP = "3.141.38.115"; + std::string IP = "172.0.0.1"; //"3.141.38.115"; unsigned PORT = 8187; private: @@ -74,3 +75,4 @@ class Network { uint32_t currentCanId = 0; }; + From dd6e9ecff6fc072d696f534b69db4a692800b666 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 25 Oct 2025 15:56:12 -0500 Subject: [PATCH 6/9] WORKING NETWORK QUEUE LFGG --- photon/network/network.cpp | 75 ++++++++++++++++---------------------- photon/network/network.hpp | 2 +- 2 files changed, 32 insertions(+), 45 deletions(-) diff --git a/photon/network/network.cpp b/photon/network/network.cpp index f985a5cf..17658121 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -77,6 +77,7 @@ void Network::producer() { std::vector buffer(BUFFER_CAPACITY); while (1){ auto bytesRead = socket.read(buffer.data(), buffer.size()); + printDBCMap(); if (bytesRead > 0) { for (std::size_t i = 0; i < static_cast(bytesRead); ++i) { while (!spscQueue.try_push(buffer[i])) std::this_thread::yield(); @@ -89,54 +90,51 @@ void Network::parser() { std::string frame; frame.reserve(256); bool collecting = false; - std::string lookahead; - lookahead.reserve(4); + while (1) { if (auto* byte = spscQueue.front()) { char ch = static_cast(*byte); spscQueue.pop(); - if (ch == 't') { - frame.clear(); - frame.push_back(ch); + + // Begin collection + if (!collecting && (std::isprint(ch) || ch == '\r')) collecting = true; + + if (!collecting) continue; - } - if (!collecting && ch != 'B' && ch != 'S') continue; + + // End of line (your Python stream uses '\r') if (ch == '\r') { if (!frame.empty()) { - if (frame.find("BO_") != std::string::npos || frame.find("SG_") != std::string::npos) + // Remove leftover whitespace + while (!frame.empty() && (frame.back() == '\r' || frame.back() == '\n')) + frame.pop_back(); + + // Detect and handle DBC vs CAN + if (frame.rfind("BO_", 0) == 0 || frame.rfind("SG_", 0) == 0) { + logs("[parser] Detected DBC line → " + frame); handleDBCframe(frame); - else + } else if (frame.rfind("t", 0) == 0) { handleFrame(frame); + } else { + logs("[parser] Skipped line → " + frame); + } } + frame.clear(); collecting = false; - lookahead.clear(); continue; } - if (ch == '\n') continue; + + // Build current frame frame.push_back(ch); - lookahead.push_back(ch); - if (lookahead.size() > 3) lookahead.erase(0, lookahead.size() - 3); - if (lookahead == "BO_") { - logs("[parser] Detected start of DBC message (BO_)"); - frame.clear(); - frame.append("BO_"); - collecting = true; - continue; - } - if (lookahead == "SG_") { - logs("[parser] Detected start of DBC signal (SG_)"); - if (!frame.empty() && frame.find("BO_") != std::string::npos) handleDBCframe(frame); - frame.clear(); - frame.append("SG_"); - collecting = true; - continue; - } - } else std::this_thread::yield(); + } else { + std::this_thread::yield(); + } } } + Network::sample& Network::ensureSample(uint16_t canId) { std::lock_guard guard(sampleMapMutex); auto it = sampleMap.find(canId); @@ -202,37 +200,26 @@ void Network::handleFrame(const std::string& frame) { void Network::handleDBCframe(const std::string& frame) { if (frame.rfind("BO_", 0) == 0) { - uint32_t canID = 0; - std::string name, sender; - uint8_t dlc = 0; - + uint32_t canID = 0; std::string name, sender; uint8_t dlc = 0; if (!decodeDBCFrame(frame, canID, name, dlc, sender)) { - logs("[parser] Invalid DBC BO_ frame encountered → " + frame); + logs("[parser] Invalid DBC BO_ frame encountered"); return; } - writeDBC(canID, name, dlc, sender); currentCanId = canID; - logs("[parser] Registered BO_ " + name + " (CAN ID: " + std::to_string(canID) + ")"); - printDBCMap(); // ✅ print here after adding new BO_ return; } - if (frame.rfind("SG_", 0) == 0) { if (currentCanId == 0) { - logs("[parser] SG_ encountered before BO_ → " + frame); + logs("[parser] SG_ encountered before BO_"); return; } - DbcSignal sig; if (!decodeSIGFrame(frame, currentCanId, sig)) { - logs("[parser] Invalid DBC SG_ frame encountered → " + frame); + logs("[parser] Invalid DBC SG_ frame encountered"); return; } - writeSignal(currentCanId, sig); - logs("[parser] Registered SG_ " + sig.name + " for CAN ID " + std::to_string(currentCanId)); - printDBCMap(); // ✅ print here after adding new SG_ return; } } diff --git a/photon/network/network.hpp b/photon/network/network.hpp index 85c932d1..a288e220 100644 --- a/photon/network/network.hpp +++ b/photon/network/network.hpp @@ -51,7 +51,7 @@ class Network { void writeSample(uint16_t canId, uint64_t value); SPSCQueue spscQueue; - std::string IP = "172.0.0.1"; //"3.141.38.115"; + std::string IP = "127.0.0.1"; //"3.141.38.115"; unsigned PORT = 8187; private: From db93ec35165dd29c3807783b7ef91c520ec64443 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 1 Nov 2025 16:17:01 -0500 Subject: [PATCH 7/9] seperate DBC parser and fixed server issue --- photon/network/connecter.cpp | 138 ++++++-------- photon/network/dbc_connector.hpp | 34 ++++ photon/network/dbc_loader.cpp | 55 ++++++ photon/network/dbc_loader.hpp | 9 + photon/network/dbc_watcher.cpp | 56 ++++++ photon/network/dbc_watcher.hpp | 31 +++ photon/network/network.cpp | 315 +++++++------------------------ photon/network/network.hpp | 74 ++++---- 8 files changed, 345 insertions(+), 367 deletions(-) create mode 100644 photon/network/dbc_connector.hpp create mode 100644 photon/network/dbc_loader.cpp create mode 100644 photon/network/dbc_loader.hpp create mode 100644 photon/network/dbc_watcher.cpp create mode 100644 photon/network/dbc_watcher.hpp diff --git a/photon/network/connecter.cpp b/photon/network/connecter.cpp index 8395ecf5..82061bb0 100644 --- a/photon/network/connecter.cpp +++ b/photon/network/connecter.cpp @@ -1,89 +1,59 @@ -/* [ξ] DBC Connector Interface - Connects parsed DBC definitions to their respective CAN IDs. - Acts like a runtime dictionary for DBC → CAN lookup. -*/ - -#include -#include -#include -#include -#include - -struct DbcSignalInfo { - int startBit; - int length; - int endianness; // 1 = little, 0 = big - bool isSigned; - double factor; - double offset; - double minVal; - double maxVal; -}; - -struct DbcMessageInfo { - int canId; - std::string name; - int dlc; - std::string transmitter; - - // Each message holds multiple signal definitions - std::unordered_map signals; -}; - -class DbcConnector { -public: - // Top-level: map CAN IDs → DBC message info - std::unordered_map> dbcMap; - - // Register a new CAN message (BO_ line) - void registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter) { - auto msg = std::make_shared(); - msg->canId = canId; - msg->name = name; - msg->dlc = dlc; - msg->transmitter = transmitter; - dbcMap[canId] = msg; +#include "dbc_connector.hpp" + +void DbcConnector::registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter) { + DbcMessageInfo& msg = dbcMap[canId]; + msg.canId = canId; + msg.name = name; + msg.dlc = dlc; + msg.transmitter = transmitter; + msg.signals.clear(); + + std::cerr << "[DBC] Registered new message: " << name + << " (CAN ID " << canId << ")\n"; +} + +void DbcConnector::registerSignal(int canId, + const std::string& signalName, + int startBit, int length, + int endianness, bool isSigned, + double factor, double offset, + double minVal, double maxVal) { + auto it = dbcMap.find(canId); + if (it == dbcMap.end()) { + std::cerr << "[DBC] Error: SG_ before BO_ for CAN ID " << canId << "\n"; + return; } - // Register a new signal for a given CAN ID (SG_ line) - void registerSignal(int canId, - const std::string& signalName, - int startBit, - int length, - int endianness, - bool isSigned, - double factor, - double offset, - double minVal, - double maxVal) { - if (dbcMap.find(canId) == dbcMap.end()) { - std::cerr << "[Connector] Error: CAN ID " << canId << " not registered before SG_ line\n"; - return; - } - - DbcSignalInfo sig{ startBit, length, endianness, isSigned, factor, offset, minVal, maxVal }; - dbcMap[canId]->signals[signalName] = sig; - } - - // Print all stored mappings for debugging - void dump() const { - for (const auto& [id, msg] : dbcMap) { - std::cout << "CAN ID: " << id << " | Name: " << msg->name - << " | DLC: " << msg->dlc - << " | Transmitter: " << msg->transmitter << "\n"; - - for (const auto& [sigName, sig] : msg->signals) { - std::cout << " └─ Signal: " << sigName - << " (StartBit: " << sig.startBit - << ", Len: " << sig.length - << ", Endian: " << sig.endianness - << ", Signed: " << sig.isSigned - << ", Factor: " << sig.factor - << ", Offset: " << sig.offset - << ", Min: " << sig.minVal - << ", Max: " << sig.maxVal - << ")\n"; + DbcSignalInfo sig{ startBit, length, endianness, isSigned, factor, offset, minVal, maxVal }; + it->second.signals[signalName] = sig; + + std::cerr << "[DBC] Registered SG_ " << signalName + << " (CAN ID " << canId << ")\n"; +} + +void DbcConnector::dump() const { + std::cout << "========== DBC MAP ==========\n"; + for (const auto& [id, msg] : dbcMap) { + std::cout << "[DBC] CAN ID: " << id + << " | Name: " << msg.name + << " | DLC: " << msg.dlc + << " | Sender: " << msg.transmitter << "\n"; + + if (msg.signals.empty()) { + std::cout << " (No signals)\n"; + } else { + for (const auto& [sigName, sig] : msg.signals) { + std::cout << " SG_ " << sigName + << " : start=" << sig.startBit + << " len=" << sig.length + << " endian=" << sig.endianness + << (sig.isSigned ? " signed" : " unsigned") + << " scale=" << sig.factor + << " offset=" << sig.offset + << " [" << sig.minVal << "|" << sig.maxVal << "]\n"; } } } -}; + std::cout << "=============================\n"; +} + diff --git a/photon/network/dbc_connector.hpp b/photon/network/dbc_connector.hpp new file mode 100644 index 00000000..9653f95f --- /dev/null +++ b/photon/network/dbc_connector.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include +#include + +struct DbcSignalInfo { + int startBit = 0; + int length = 0; + int endianness = 1; // 1 = little + bool isSigned = false; + double factor = 1.0; + double offset = 0.0; + double minVal = 0.0; + double maxVal = 0.0; +}; + +struct DbcMessageInfo { + int canId = 0; + std::string name; + int dlc = 0; + std::string transmitter; + std::unordered_map signals; +}; + +class DbcConnector { +public: + std::unordered_map dbcMap; + + void registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter); + void registerSignal(int canId, const std::string& signalName, + int startBit, int length, int endianness, bool isSigned, + double factor, double offset, double minVal, double maxVal); + void dump() const; +}; diff --git a/photon/network/dbc_loader.cpp b/photon/network/dbc_loader.cpp new file mode 100644 index 00000000..aebdcf07 --- /dev/null +++ b/photon/network/dbc_loader.cpp @@ -0,0 +1,55 @@ +#include "dbc_loader.hpp" +#include +#include +#include + +bool DbcLoader::loadFromFile(const std::string& path, DbcConnector& connector) { + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "[DBC Loader] Failed to open " << path << "\n"; + return false; + } + + std::string line; + uint32_t currentId = 0; + + while (std::getline(file, line)) { + if (line.rfind("BO_", 0) == 0) { + uint32_t canId = 0; + std::string name, sender; + uint8_t dlc = 0; + + std::istringstream iss(line); + std::string tag; iss >> tag >> canId; + std::string tmp; iss >> tmp; + auto colon = tmp.find(':'); + if (colon == std::string::npos) continue; + name = tmp.substr(0, colon); + + std::string dlcStr; iss >> dlcStr; + dlc = static_cast(std::stoi(dlcStr)); + iss >> sender; + + connector.registerMessage(canId, name, dlc, sender); + currentId = canId; + } + else if (line.rfind("SG_", 0) == 0 && currentId != 0) { + DbcSignalInfo sig{}; + std::istringstream iss(line); + std::string tag, sigName; iss >> tag >> sigName; + char colon; iss >> colon; + iss >> sig.startBit; + iss.ignore(1, '|'); + iss >> sig.length; + char at; iss >> at; + iss >> sig.endianness; + char sign; iss >> sign; + sig.isSigned = (sign == '-'); + connector.registerSignal(currentId, sigName, sig.startBit, sig.length, + sig.endianness, sig.isSigned, 1.0, 0.0, 0.0, 0.0); + } + } + + std::cerr << "[DBC Loader] Successfully loaded: " << path << "\n"; + return true; +} diff --git a/photon/network/dbc_loader.hpp b/photon/network/dbc_loader.hpp new file mode 100644 index 00000000..479254fb --- /dev/null +++ b/photon/network/dbc_loader.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include "dbc_connector.hpp" + +class DbcLoader { +public: + // Parse a .dbc file and populate the given connector + static bool loadFromFile(const std::string& path, DbcConnector& connector); +}; diff --git a/photon/network/dbc_watcher.cpp b/photon/network/dbc_watcher.cpp new file mode 100644 index 00000000..274d8d5f --- /dev/null +++ b/photon/network/dbc_watcher.cpp @@ -0,0 +1,56 @@ +#include "dbc_watcher.hpp" +#include + +DbcWatcher::DbcWatcher(Network& net, const std::string& directory, int intervalSeconds) + : network(net), directoryPath(directory), pollInterval(intervalSeconds), running(false) {} + +DbcWatcher::~DbcWatcher() { + stop(); +} + +void DbcWatcher::start() { + if (running.load()) return; + running.store(true); + workerThread = std::thread(&DbcWatcher::monitorLoop, this); + std::cerr << "[DBC Watcher] Monitoring started on: " << directoryPath << "\n"; +} + +void DbcWatcher::stop() { + running.store(false); + if (workerThread.joinable()) + workerThread.join(); + std::cerr << "[DBC Watcher] Monitoring stopped.\n"; +} + +void DbcWatcher::monitorLoop() { + using namespace std::chrono_literals; + + while (running.load()) { + try { + for (const auto& entry : fs::directory_iterator(directoryPath)) { + if (!entry.is_regular_file()) continue; + + std::string path = entry.path().string(); + if (entry.path().extension() != ".dbc") continue; + + auto lastWrite = fs::last_write_time(entry.path()); + + // ✅ replaced .contains with .find for C++17 compatibility + if (fileTimestamps.find(path) == fileTimestamps.end() || fileTimestamps[path] != lastWrite) { + fileTimestamps[path] = lastWrite; + std::cerr << "[DBC Watcher] Detected new or modified file: " << path << "\n"; + + if (network.loadDBC(path)) { + std::cerr << "[DBC Watcher] Loaded DBC: " << path << "\n"; + } else { + std::cerr << "[DBC Watcher] Failed to load DBC: " << path << "\n"; + } + } + } + } catch (const std::exception& e) { + std::cerr << "[DBC Watcher] Error: " << e.what() << "\n"; + } + + std::this_thread::sleep_for(std::chrono::seconds(pollInterval)); + } +} diff --git a/photon/network/dbc_watcher.hpp b/photon/network/dbc_watcher.hpp new file mode 100644 index 00000000..48df82ba --- /dev/null +++ b/photon/network/dbc_watcher.hpp @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "network.hpp" + +namespace fs = std::filesystem; + +class DbcWatcher { +public: + DbcWatcher(Network& net, const std::string& directory, int intervalSeconds = 5); + ~DbcWatcher(); + + void start(); + void stop(); + +private: + void monitorLoop(); + + Network& network; + std::string directoryPath; + int pollInterval; + std::atomic running; + std::thread workerThread; + + // Keep track of last modification times + std::unordered_map fileTimestamps; +}; diff --git a/photon/network/network.cpp b/photon/network/network.cpp index 17658121..769e442c 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -1,88 +1,39 @@ #include "network.hpp" #include "tcp.hpp" -#include "spsc.hpp" -#include -#include +#include "dbc_loader.hpp" +#include "dbc_connector.hpp" #include -#include #include #include -#include -#include -#include "../engine/include.hpp" +#include -int hexValue(char c) { +#define QUEUE_CAPACITY 2048 +#define BUFFER_CAPACITY 1024 + +static int hexValue(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); return -1; } -struct DbcSignalInfo { - int startBit; - int length; - int endianness; - bool isSigned; - double factor; - double offset; - double minVal; - double maxVal; -}; - -struct DbcMessageInfo { - int canId; - std::string name; - int dlc; - std::string transmitter; - std::unordered_map signals; -}; - -class DbcConnector { -public: - std::unordered_map> dbcMap; - - void registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter) { - auto msg = std::make_shared(); - msg->canId = canId; - msg->name = name; - msg->dlc = dlc; - msg->transmitter = transmitter; - dbcMap[canId] = msg; - } - - void registerSignal(int canId, - const std::string& signalName, - int startBit, - int length, - int endianness, - bool isSigned, - double factor, - double offset, - double minVal, - double maxVal) { - if (dbcMap.find(canId) == dbcMap.end()) return; - DbcSignalInfo sig{ startBit, length, endianness, isSigned, factor, offset, minVal, maxVal }; - dbcMap[canId]->signals[signalName] = sig; - } -}; - -static DbcConnector dbcConnector; - -#define QUEUE_CAPACITY 2048 Network::Network() : spscQueue(QUEUE_CAPACITY) {} -#define BUFFER_CAPACITY 1024 void Network::producer() { + std::cerr << "[DEBUG] Using IP=" << IP << " PORT=" << PORT << "\n"; TcpSocket socket(IP, PORT); std::vector buffer(BUFFER_CAPACITY); - while (1){ + + std::cerr << "[+] Attempting connection to " << IP << ":" << PORT << "...\n"; + std::cerr << "[+] Connected (TcpSocket constructor succeeded).\n"; + + + while (true) { auto bytesRead = socket.read(buffer.data(), buffer.size()); - printDBCMap(); if (bytesRead > 0) { - for (std::size_t i = 0; i < static_cast(bytesRead); ++i) { + for (size_t i = 0; i < (size_t)bytesRead; ++i) while (!spscQueue.try_push(buffer[i])) std::this_thread::yield(); -} - } + } else std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } @@ -91,233 +42,105 @@ void Network::parser() { frame.reserve(256); bool collecting = false; - while (1) { + while (true) { if (auto* byte = spscQueue.front()) { char ch = static_cast(*byte); spscQueue.pop(); - // Begin collection if (!collecting && (std::isprint(ch) || ch == '\r')) collecting = true; + if (!collecting) continue; - if (!collecting) - continue; - - // End of line (your Python stream uses '\r') if (ch == '\r') { if (!frame.empty()) { - // Remove leftover whitespace while (!frame.empty() && (frame.back() == '\r' || frame.back() == '\n')) frame.pop_back(); - // Detect and handle DBC vs CAN - if (frame.rfind("BO_", 0) == 0 || frame.rfind("SG_", 0) == 0) { - logs("[parser] Detected DBC line → " + frame); - handleDBCframe(frame); - } else if (frame.rfind("t", 0) == 0) { - handleFrame(frame); - } else { - logs("[parser] Skipped line → " + frame); - } + if (frame.rfind("t", 0) == 0) handleFrame(frame); } - frame.clear(); collecting = false; continue; } - // Build current frame frame.push_back(ch); - } else { - std::this_thread::yield(); - } - } -} - - -Network::sample& Network::ensureSample(uint16_t canId) { - std::lock_guard guard(sampleMapMutex); - auto it = sampleMap.find(canId); - if (it == sampleMap.end()) { - auto inserted = sampleMap.emplace(canId, std::make_unique()); - it = inserted.first; - } - return *(it->second); -} - -Network::DbcMessage& Network::ensureDBC(uint32_t canId) { - std::lock_guard guard(dbcMapMutex); - auto it = dbcMap.find(canId); - if (it == dbcMap.end()) { - auto inserted = dbcMap.emplace(canId, std::make_unique()); - it = inserted.first; - } - return *(it->second); -} - -void Network::writeSample(uint16_t canId, uint64_t value) { - sample& entry = ensureSample(canId); - std::lock_guard valueGuard(entry.lock); - entry.point = value; -} - -void Network::writeDBC(uint32_t canId, const std::string& name, uint8_t dlc, const std::string& sender) { - DbcMessage& msg = ensureDBC(canId); - std::lock_guard guard(dbcMapMutex); - msg.name = name; - msg.dlc = dlc; - msg.sender = sender; - dbcConnector.registerMessage(canId, name, dlc, sender); -} - -void Network::writeSignal(uint32_t canId, const DbcSignal& sig) { - DbcMessage& msg = ensureDBC(canId); - std::lock_guard guard(dbcMapMutex); - msg.signals.push_back(sig); - dbcConnector.registerSignal(canId, sig.name, sig.startBit, sig.length, sig.byteOrder, sig.isSigned, sig.scale, sig.offset, sig.minVal, sig.maxVal); -} - -bool Network::readSample(uint16_t canId, uint64_t& outValue) { - std::unique_lock mapLock(sampleMapMutex); - auto it = sampleMap.find(canId); - if (it == sampleMap.end()) return false; - sample* entry = it->second.get(); - mapLock.unlock(); - std::lock_guard valueGuard(entry->lock); - outValue = entry->point; - return true; -} - -void Network::handleFrame(const std::string& frame) { - uint16_t canId = 0; - uint64_t value = 0; - if (!decodeFrame(frame, canId, value)) { - logs("[parser] Invalid SLCAN frame encountered → \"" + frame + "\""); - return; - } - writeSample(canId, value); -} - -void Network::handleDBCframe(const std::string& frame) { - if (frame.rfind("BO_", 0) == 0) { - uint32_t canID = 0; std::string name, sender; uint8_t dlc = 0; - if (!decodeDBCFrame(frame, canID, name, dlc, sender)) { - logs("[parser] Invalid DBC BO_ frame encountered"); - return; - } - writeDBC(canID, name, dlc, sender); - currentCanId = canID; - return; - } - if (frame.rfind("SG_", 0) == 0) { - if (currentCanId == 0) { - logs("[parser] SG_ encountered before BO_"); - return; - } - DbcSignal sig; - if (!decodeSIGFrame(frame, currentCanId, sig)) { - logs("[parser] Invalid DBC SG_ frame encountered"); - return; - } - writeSignal(currentCanId, sig); - return; + } else std::this_thread::yield(); } } bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value) { - if (frame.empty() || frame.front() != 't') return false; - // if (frame.back() != '\r') return false; - if (frame.size() < 5) return false; + if (frame.empty() || frame.front() != 't' || frame.size() < 5) return false; int dataLength = hexValue(frame[4]); if (dataLength < 0 || dataLength > 8) return false; - const std::size_t expectedLength = 5 + static_cast(dataLength) * 2; + + const size_t expectedLength = 5 + (size_t)dataLength * 2; if (frame.size() != expectedLength) return false; - // logs(std::to_string(frame.size()) + " vs " + std::to_string(expectedLength)); + canId = 0; - for (std::size_t i = 1; i <= 3; ++i) { + for (size_t i = 1; i <= 3; ++i) { int nibble = hexValue(frame[i]); if (nibble < 0) return false; - canId = static_cast((canId << 4) | static_cast(nibble)); + canId = (uint16_t)((canId << 4) | nibble); } + value = 0; for (int i = 0; i < dataLength; ++i) { int hi = hexValue(frame[5 + i * 2]); int lo = hexValue(frame[6 + i * 2]); if (hi < 0 || lo < 0) return false; - uint8_t byte = static_cast((hi << 4) | lo); + uint8_t byte = (uint8_t)((hi << 4) | lo); value = (value << 8) | byte; } return true; } -bool Network::decodeDBCFrame(const std::string& frame, uint32_t& canId, std::string& name, uint8_t& dlc, std::string& sender) { - if (frame.empty() || frame.rfind("BO_", 0) != 0) return false; - std::istringstream iss(frame); - std::string tag; - iss >> tag; - iss >> canId; - std::string temp; - iss >> temp; - auto colon = temp.find(':'); - if (colon == std::string::npos) return false; - name = temp.substr(0, colon); - std::string dlcStr; - iss >> dlcStr; - dlc = static_cast(std::stoi(dlcStr)); - iss >> sender; - return true; +void Network::handleFrame(const std::string& frame) { + uint16_t canId; + uint64_t value; + if (!decodeFrame(frame, canId, value)) { + std::cerr << "[parser] Invalid SLCAN frame → " << frame << "\n"; + return; + } + + std::lock_guard lock(sampleMapMutex); + auto& entry = sampleMap[canId]; + std::lock_guard entryLock(entry.lock); + entry.point = value; + + std::cerr << "[SLCAN] ID=" << canId << " Value=" << std::hex << value << std::dec << "\n"; } -bool Network::decodeSIGFrame(const std::string& frame, uint32_t& canId, DbcSignal& sig) { - if (frame.empty() || frame.rfind("SG_", 0) != 0) return false; - std::istringstream iss(frame); - std::string tag; iss >> tag; - iss >> sig.name; - char colon; iss >> colon; - iss >> sig.startBit; - iss.ignore(1, '|'); - iss >> sig.length; - char at; iss >> at; - iss >> sig.byteOrder; - char sign; iss >> sign; - sig.isSigned = (sign == '-'); - return true; +Network::sample& Network::ensureSample(uint16_t canId) { + std::lock_guard guard(sampleMapMutex); + return sampleMap[canId]; } -void Network::printDBCMap() { - std::lock_guard guard(dbcMapMutex); +bool Network::readSample(uint16_t canId, uint64_t& outValue) { + std::lock_guard guard(sampleMapMutex); + auto it = sampleMap.find(canId); + if (it == sampleMap.end()) return false; + std::lock_guard lock(it->second.lock); + outValue = it->second.point; + return true; +} - if (dbcMap.empty()) { - logs("[DBC] No DBC messages stored yet."); - return; - } +void Network::writeSample(uint16_t canId, uint64_t value) { + std::lock_guard guard(sampleMapMutex); + auto& s = sampleMap[canId]; + std::lock_guard lock(s.lock); + s.point = value; +} - logs("========== DBC MAP =========="); - for (const auto& [canId, msgPtr] : dbcMap) { - const auto& msg = *msgPtr; - std::ostringstream oss; - oss << "[DBC] CAN ID: " << canId - << " | Name: " << msg.name - << " | DLC: " << (int)msg.dlc - << " | Sender: " << msg.sender; - logs(oss.str()); +bool Network::loadDBC(const std::string& path) { + std::cerr << "[DBC Loader] Loading DBC from " << path << "\n"; + DbcConnector connector; + return DbcLoader::loadFromFile(path, connector); +} - if (msg.signals.empty()) { - logs(" (No signals found for this message)"); - } else { - for (const auto& sig : msg.signals) { - std::ostringstream sigoss; - sigoss << " SG_ " << sig.name - << " : start=" << sig.startBit - << " len=" << sig.length - << " @byteOrder=" << sig.byteOrder - << (sig.isSigned ? " signed" : " unsigned") - << " scale=" << sig.scale - << " offset=" << sig.offset - << " [" << sig.minVal << "|" << sig.maxVal << "]"; - logs(sigoss.str()); - } - } +void Network::printDBCMap() { + std::cerr << "[DBC] Dump of loaded messages:\n"; + for (const auto& [id, msg] : dbcMap) { + std::cerr << "CAN ID: " << id << " Name: " << msg.name + << " DLC: " << (int)msg.dlc << " Sender: " << msg.sender << "\n"; } - logs("============================="); } diff --git a/photon/network/network.hpp b/photon/network/network.hpp index a288e220..cec3946b 100644 --- a/photon/network/network.hpp +++ b/photon/network/network.hpp @@ -1,23 +1,44 @@ -/*[ξ] the photon network interface*/ +/* [ξ] Photon Network Interface + Handles real-time SLCAN (CAN over TCP) parsing and DBC mapping. + Designed for thread-safe CAN streaming and modular DBC integration. +*/ + #pragma once #include -#include +#include #include #include #include -#include #include #include "spsc.hpp" +// forward declaration +class TcpSocket; +class DbcConnector; + class Network { +public: + Network(); + + // --- Threads --- + void producer(); + void parser(); + + // --- Debug / DBC --- + void printDBCMap(); + bool loadDBC(const std::string& path); + + // --- CAN sample interface --- + bool readSample(uint16_t canId, uint64_t& outValue); + void writeSample(uint16_t canId, uint64_t value); + + // --- Network configuration --- + std::string IP = "3.141.38.115"; + unsigned PORT = 8187; + SPSCQueue spscQueue; + private: struct sample { - sample() = default; - sample(const sample&) = delete; - sample& operator=(const sample&) = delete; - sample(sample&&) = delete; - sample& operator=(sample&&) = delete; - std::mutex lock; uint64_t point = 0; }; @@ -41,38 +62,17 @@ class Network { std::vector signals; }; -public: - Network(); - void producer(); - void printDBCMap(); - void parser(); + // --- Maps --- + std::unordered_map sampleMap; + std::unordered_map dbcMap; - bool readSample(uint16_t canId, uint64_t& outValue); - void writeSample(uint16_t canId, uint64_t value); + std::mutex sampleMapMutex; + std::mutex dbcMapMutex; - SPSCQueue spscQueue; - std::string IP = "127.0.0.1"; //"3.141.38.115"; - unsigned PORT = 8187; + uint32_t currentCanId = 0; -private: + // --- Helpers --- sample& ensureSample(uint16_t canId); bool decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value); void handleFrame(const std::string& frame); - - // DBC system - DbcMessage& ensureDBC(uint32_t canId); - void writeDBC(uint32_t canId, const std::string& name, uint8_t dlc, const std::string& sender); - void writeSignal(uint32_t canId, const DbcSignal& sig); - void handleDBCframe(const std::string& frame); - bool decodeDBCFrame(const std::string& frame, uint32_t& canId, std::string& name, uint8_t& dlc, std::string& sender); - bool decodeSIGFrame(const std::string& frame, uint32_t& canId, DbcSignal& sig); - - std::mutex sampleMapMutex; - std::unordered_map> sampleMap; - - std::mutex dbcMapMutex; - std::unordered_map> dbcMap; - - uint32_t currentCanId = 0; }; - From 8e4b10ad9db0169c1fc10e5b520df0d94a0f7aa1 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 15 Nov 2025 15:10:47 -0600 Subject: [PATCH 8/9] =?UTF-8?q?all=20DBC=20files=20in=20a=20cpp=20and=20he?= =?UTF-8?q?ader,=20made=20window=20for=20SLCAN=20Tracker.=F0=9F=AB=A1?= =?UTF-8?q?=F0=9F=92=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- photon/engine/photon.cpp | 3 + photon/gui/ui.cpp | 57 +++++++ photon/gui/ui.hpp | 1 + photon/network/connecter.cpp | 59 -------- photon/network/dbc_connector.hpp | 34 ----- photon/network/dbc_loader.cpp | 55 ------- photon/network/dbc_loader.hpp | 9 -- photon/network/dbc_manager.cpp | 248 +++++++++++++++++++++++++++++++ photon/network/dbc_manager.hpp | 70 +++++++++ photon/network/dbc_watcher.cpp | 56 ------- photon/network/dbc_watcher.hpp | 31 ---- photon/network/network.cpp | 189 ++++++++++++++++++----- photon/network/network.hpp | 54 +++---- 13 files changed, 555 insertions(+), 311 deletions(-) delete mode 100644 photon/network/connecter.cpp delete mode 100644 photon/network/dbc_connector.hpp delete mode 100644 photon/network/dbc_loader.cpp delete mode 100644 photon/network/dbc_loader.hpp create mode 100644 photon/network/dbc_manager.cpp create mode 100644 photon/network/dbc_manager.hpp delete mode 100644 photon/network/dbc_watcher.cpp delete mode 100644 photon/network/dbc_watcher.hpp diff --git a/photon/engine/photon.cpp b/photon/engine/photon.cpp index 0fb933d0..e2ee8f9a 100644 --- a/photon/engine/photon.cpp +++ b/photon/engine/photon.cpp @@ -54,6 +54,9 @@ void Photon::initThreads(){ logs("[?] Cache line size (constructive): " << std::hardware_constructive_interference_size); logs("[?] Usable Hardware Threads: " << std::thread::hardware_concurrency()); #endif + DbcWatcher watcher(network.getDbcManager(), "dbc", 3); + watcher.start(); + network.printDBCMap(); std::thread producer_t(&Network::producer, &network); producer_t.detach(); std::thread parser_t(&Network::parser, &network); diff --git a/photon/gui/ui.cpp b/photon/gui/ui.cpp index 2b917723..e0eb8175 100644 --- a/photon/gui/ui.cpp +++ b/photon/gui/ui.cpp @@ -11,6 +11,7 @@ void UI::build(){ ImPlot::ShowDemoWindow(); ImPlot3D::ShowDemoWindow(); fpsWindow(); + slcanWindow(); customShaderWindow(); showVideoDisplay(); networkSamplePlot(); @@ -231,6 +232,62 @@ void UI::networkSamplePlot(){ ImGui::End(); } +void UI::slcanWindow() { + ImGui::SetNextWindowSize(ImVec2(460.0f, 300.0f), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("SLCAN Monitor")) { + ImGui::End(); + return; + } + + if (!networkINTF) { + ImGui::Text("Network not connected."); + ImGui::End(); + return; + } + + auto& net = *networkINTF; + + if (ImGui::BeginTable("slcan_table", 3, + ImGuiTableFlags_ScrollY | + ImGuiTableFlags_Borders | + ImGuiTableFlags_RowBg)) { + + ImGui::TableSetupColumn("CAN ID"); + ImGui::TableSetupColumn("Raw"); + ImGui::TableSetupColumn("Interpretation"); + ImGui::TableHeadersRow(); + + std::lock_guard lock(net.decodedHistoryMutex); + + for (const auto& entry : net.decodedHistory) { + + ImGui::TableNextRow(); + + // CAN ID + ImGui::TableSetColumnIndex(0); + ImGui::Text("0x%03X", entry.canId); + + // Raw Value + ImGui::TableSetColumnIndex(1); + ImGui::Text("0x%016llX", + (unsigned long long)entry.rawValue); + + // Interpretation (multiline) + ImGui::TableSetColumnIndex(2); + for (const std::string& line : entry.lines) { + ImGui::TextUnformatted(line.c_str()); + } + } + + ImGui::EndTable(); + } + + ImGui::End(); +} + + + + void UI::customBackground(){ ImGuiIO &io = ImGui::GetIO(); ImVec2 displaySize = io.DisplaySize; diff --git a/photon/gui/ui.hpp b/photon/gui/ui.hpp index acc67748..3d1ac1c1 100644 --- a/photon/gui/ui.hpp +++ b/photon/gui/ui.hpp @@ -56,4 +56,5 @@ struct UI{ void showVideoDisplay(); void customBackground(); void networkSamplePlot(); + void slcanWindow(); }; diff --git a/photon/network/connecter.cpp b/photon/network/connecter.cpp deleted file mode 100644 index 82061bb0..00000000 --- a/photon/network/connecter.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "dbc_connector.hpp" - -void DbcConnector::registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter) { - DbcMessageInfo& msg = dbcMap[canId]; - msg.canId = canId; - msg.name = name; - msg.dlc = dlc; - msg.transmitter = transmitter; - msg.signals.clear(); - - std::cerr << "[DBC] Registered new message: " << name - << " (CAN ID " << canId << ")\n"; -} - -void DbcConnector::registerSignal(int canId, - const std::string& signalName, - int startBit, int length, - int endianness, bool isSigned, - double factor, double offset, - double minVal, double maxVal) { - auto it = dbcMap.find(canId); - if (it == dbcMap.end()) { - std::cerr << "[DBC] Error: SG_ before BO_ for CAN ID " << canId << "\n"; - return; - } - - DbcSignalInfo sig{ startBit, length, endianness, isSigned, factor, offset, minVal, maxVal }; - it->second.signals[signalName] = sig; - - std::cerr << "[DBC] Registered SG_ " << signalName - << " (CAN ID " << canId << ")\n"; -} - -void DbcConnector::dump() const { - std::cout << "========== DBC MAP ==========\n"; - for (const auto& [id, msg] : dbcMap) { - std::cout << "[DBC] CAN ID: " << id - << " | Name: " << msg.name - << " | DLC: " << msg.dlc - << " | Sender: " << msg.transmitter << "\n"; - - if (msg.signals.empty()) { - std::cout << " (No signals)\n"; - } else { - for (const auto& [sigName, sig] : msg.signals) { - std::cout << " SG_ " << sigName - << " : start=" << sig.startBit - << " len=" << sig.length - << " endian=" << sig.endianness - << (sig.isSigned ? " signed" : " unsigned") - << " scale=" << sig.factor - << " offset=" << sig.offset - << " [" << sig.minVal << "|" << sig.maxVal << "]\n"; - } - } - } - std::cout << "=============================\n"; -} - diff --git a/photon/network/dbc_connector.hpp b/photon/network/dbc_connector.hpp deleted file mode 100644 index 9653f95f..00000000 --- a/photon/network/dbc_connector.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include -#include -#include - -struct DbcSignalInfo { - int startBit = 0; - int length = 0; - int endianness = 1; // 1 = little - bool isSigned = false; - double factor = 1.0; - double offset = 0.0; - double minVal = 0.0; - double maxVal = 0.0; -}; - -struct DbcMessageInfo { - int canId = 0; - std::string name; - int dlc = 0; - std::string transmitter; - std::unordered_map signals; -}; - -class DbcConnector { -public: - std::unordered_map dbcMap; - - void registerMessage(int canId, const std::string& name, int dlc, const std::string& transmitter); - void registerSignal(int canId, const std::string& signalName, - int startBit, int length, int endianness, bool isSigned, - double factor, double offset, double minVal, double maxVal); - void dump() const; -}; diff --git a/photon/network/dbc_loader.cpp b/photon/network/dbc_loader.cpp deleted file mode 100644 index aebdcf07..00000000 --- a/photon/network/dbc_loader.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "dbc_loader.hpp" -#include -#include -#include - -bool DbcLoader::loadFromFile(const std::string& path, DbcConnector& connector) { - std::ifstream file(path); - if (!file.is_open()) { - std::cerr << "[DBC Loader] Failed to open " << path << "\n"; - return false; - } - - std::string line; - uint32_t currentId = 0; - - while (std::getline(file, line)) { - if (line.rfind("BO_", 0) == 0) { - uint32_t canId = 0; - std::string name, sender; - uint8_t dlc = 0; - - std::istringstream iss(line); - std::string tag; iss >> tag >> canId; - std::string tmp; iss >> tmp; - auto colon = tmp.find(':'); - if (colon == std::string::npos) continue; - name = tmp.substr(0, colon); - - std::string dlcStr; iss >> dlcStr; - dlc = static_cast(std::stoi(dlcStr)); - iss >> sender; - - connector.registerMessage(canId, name, dlc, sender); - currentId = canId; - } - else if (line.rfind("SG_", 0) == 0 && currentId != 0) { - DbcSignalInfo sig{}; - std::istringstream iss(line); - std::string tag, sigName; iss >> tag >> sigName; - char colon; iss >> colon; - iss >> sig.startBit; - iss.ignore(1, '|'); - iss >> sig.length; - char at; iss >> at; - iss >> sig.endianness; - char sign; iss >> sign; - sig.isSigned = (sign == '-'); - connector.registerSignal(currentId, sigName, sig.startBit, sig.length, - sig.endianness, sig.isSigned, 1.0, 0.0, 0.0, 0.0); - } - } - - std::cerr << "[DBC Loader] Successfully loaded: " << path << "\n"; - return true; -} diff --git a/photon/network/dbc_loader.hpp b/photon/network/dbc_loader.hpp deleted file mode 100644 index 479254fb..00000000 --- a/photon/network/dbc_loader.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include -#include "dbc_connector.hpp" - -class DbcLoader { -public: - // Parse a .dbc file and populate the given connector - static bool loadFromFile(const std::string& path, DbcConnector& connector); -}; diff --git a/photon/network/dbc_manager.cpp b/photon/network/dbc_manager.cpp new file mode 100644 index 00000000..575c5710 --- /dev/null +++ b/photon/network/dbc_manager.cpp @@ -0,0 +1,248 @@ +#include "dbc_manager.hpp" +#include +#include +#include + +// ---------- DbcManager Implementation ---------- + +bool DbcManager::loadFromFile(const std::string& path) { + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "[DBC Loader] Failed to open " << path << "\n"; + return false; + } + + std::string line; + uint32_t currentId = 0; + int messageCountLocal = 0; + int signalCountLocal = 0; + + // === Main parsing loop === + while (std::getline(file, line)) { + // trim leading spaces/tabs + line.erase(0, line.find_first_not_of(" \t\r\n")); + if (line.empty()) continue; + + // --- Parse BO_ lines --- + if (line.rfind("BO_", 0) == 0) { + uint32_t canId = 0; + std::string name, sender; + uint8_t dlc = 0; + + std::istringstream iss(line); + std::string tag; + iss >> tag >> canId; + + std::string tmp; + iss >> tmp; + auto colon = tmp.find(':'); + if (colon == std::string::npos) + continue; + name = tmp.substr(0, colon); + + std::string dlcStr; + iss >> dlcStr; + try { + dlc = static_cast(std::stoi(dlcStr)); + } catch (...) { + continue; + } + + iss >> sender; + + { + std::lock_guard lock(mapMutex); + DbcMessage& msg = dbcMap[static_cast(canId)]; + msg.canId = static_cast(canId); + msg.name = name; + msg.dlc = dlc; + msg.transmitter = sender; + msg.signals.clear(); + } + + currentId = canId; + messageCountLocal++; + std::cerr << "[DBC] Registered message: " << name + << " (ID=" << canId << ")\n"; + } + + // --- Parse SG_ lines --- + else if (line.find("SG_") != std::string::npos && currentId != 0) { + std::istringstream iss(line); + std::string tag, sigName; + iss >> tag >> sigName; // SG_ + + DbcSignal sig{}; + char c = 0; + + // find the colon + while (iss >> c) { + if (c == ':') break; + } + if (c != ':') continue; + + // parse 0|32@1+ + iss >> sig.startBit; + iss.ignore(1, '|'); + iss >> sig.length; + iss.ignore(1, '@'); + iss >> sig.endianness; + iss >> c; + sig.isSigned = (c == '-'); + + // parse (scale,offset) + if (iss >> c && c == '(') { + iss >> sig.scale; + iss.ignore(1, ','); + iss >> sig.offset; + iss.ignore(1, ')'); + } + + // parse [min|max] + if (iss >> c && c == '[') { + iss >> sig.min; + iss.ignore(1, '|'); + iss >> sig.max; + iss.ignore(1, ']'); + } + + // parse "unit" + if (iss >> std::ws && iss.peek() == '"') { + iss.get(); // consume " + std::getline(iss, sig.unit, '"'); + } + + // receiver (may or may not be in brackets) + std::string receiver; + if (iss >> std::ws) { + if (iss.peek() == '[') { + iss.get(); // [ + std::getline(iss, receiver, ']'); + } else { + iss >> receiver; // plain token (Vector__XXX) + } + sig.receiver = receiver; + } + + { + std::lock_guard lock(mapMutex); + auto it = dbcMap.find(static_cast(currentId)); + if (it != dbcMap.end()) + it->second.signals[sigName] = sig; + } + + signalCountLocal++; + std::cerr << "[DBC] Registered signal: " << sigName + << " (ID=" << currentId << ")\n"; + } + } + + // --- Summary + dump --- + { + std::lock_guard lock(mapMutex); + std::cerr << "[DBC Loader] Parsed " << messageCountLocal + << " messages and " << signalCountLocal + << " signals from " << path << "\n"; + std::cerr << "[DBC Loader] Current total messages in map: " + << dbcMap.size() << "\n"; + } + + dump(); + return (messageCountLocal > 0); +} + +// ---------- Utility Methods ---------- + +bool DbcManager::hasMessages() { + std::lock_guard lock(mapMutex); + return !dbcMap.empty(); +} + +size_t DbcManager::messageCount() { + std::lock_guard lock(mapMutex); + return dbcMap.size(); +} + +void DbcManager::dump() { + std::lock_guard lock(mapMutex); + std::cout << "========== DBC MAP ==========\n"; + for (const auto& [id, msg] : dbcMap) { + std::cout << "CAN ID: " << id + << " | Name: " << msg.name + << " | DLC: " << msg.dlc + << " | Sender: " << msg.transmitter << "\n"; + for (const auto& [sigName, s] : msg.signals) { + std::cout << " SG_ " << sigName + << " start=" << s.startBit + << " len=" << s.length + << " endian=" << s.endianness + << (s.isSigned ? " signed" : " unsigned") + << "\n"; + } + } + std::cout << "=============================\n"; +} + +// ---------- DbcWatcher Implementation ---------- + +DbcWatcher::DbcWatcher(DbcManager& manager, + const std::string& directory, + int intervalSeconds) + : dbcManager(manager), + directoryPath(directory), + pollInterval(intervalSeconds), + running(false) {} + +DbcWatcher::~DbcWatcher() { + stop(); +} + +void DbcWatcher::start() { + if (running.load()) return; + running.store(true); + workerThread = std::thread(&DbcWatcher::monitorLoop, this); + std::cerr << "[DBC Watcher] Monitoring started on: " + << directoryPath << "\n"; +} + +void DbcWatcher::stop() { + running.store(false); + if (workerThread.joinable()) + workerThread.join(); + std::cerr << "[DBC Watcher] Monitoring stopped.\n"; +} + +void DbcWatcher::monitorLoop() { + using namespace std::chrono_literals; + + while (running.load()) { + try { + for (const auto& entry : fs::directory_iterator(directoryPath)) { + if (!entry.is_regular_file()) continue; + if (entry.path().extension() != ".dbc") continue; + + std::string path = entry.path().string(); + auto lastWrite = fs::last_write_time(entry.path()); + + if (fileTimestamps.find(path) == fileTimestamps.end() + || fileTimestamps[path] != lastWrite) { + + fileTimestamps[path] = lastWrite; + std::cerr << "[DBC Watcher] Detected new/modified: " + << path << "\n"; + + if (dbcManager.loadFromFile(path)) + std::cerr << "[DBC Watcher] Loaded DBC: " + << path << "\n"; + else + std::cerr << "[DBC Watcher] Failed to load: " + << path << "\n"; + } + } + } catch (const std::exception& e) { + std::cerr << "[DBC Watcher] Error: " << e.what() << "\n"; + } + + std::this_thread::sleep_for(std::chrono::seconds(pollInterval)); + } +} diff --git a/photon/network/dbc_manager.hpp b/photon/network/dbc_manager.hpp new file mode 100644 index 00000000..02ebcb35 --- /dev/null +++ b/photon/network/dbc_manager.hpp @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +// ---------- DBC data structures ---------- + +struct DbcSignal { + int startBit = 0; + int length = 0; + int endianness = 0; + bool isSigned = false; + double scale = 1.0; + double offset = 0.0; + double min = 0.0; + double max = 0.0; + std::string unit; + std::string receiver; +}; + + +struct DbcMessage { + int canId = 0; + std::string name; + int dlc = 0; + std::string transmitter; + std::unordered_map signals; +}; + +// ---------- DbcManager ---------- + +class DbcManager { +public: + bool loadFromFile(const std::string& path); + void dump(); + + bool hasMessages(); + size_t messageCount(); + + // Exposed for direct access if needed + std::unordered_map dbcMap; + std::mutex mapMutex; +}; + +// ---------- DbcWatcher ---------- + +class DbcWatcher { +public: + DbcWatcher(DbcManager& manager, const std::string& directory, int intervalSeconds = 5); + ~DbcWatcher(); + + void start(); + void stop(); + +private: + void monitorLoop(); + + DbcManager& dbcManager; + std::string directoryPath; + int pollInterval; + std::atomic running; + std::thread workerThread; + std::unordered_map fileTimestamps; +}; diff --git a/photon/network/dbc_watcher.cpp b/photon/network/dbc_watcher.cpp deleted file mode 100644 index 274d8d5f..00000000 --- a/photon/network/dbc_watcher.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "dbc_watcher.hpp" -#include - -DbcWatcher::DbcWatcher(Network& net, const std::string& directory, int intervalSeconds) - : network(net), directoryPath(directory), pollInterval(intervalSeconds), running(false) {} - -DbcWatcher::~DbcWatcher() { - stop(); -} - -void DbcWatcher::start() { - if (running.load()) return; - running.store(true); - workerThread = std::thread(&DbcWatcher::monitorLoop, this); - std::cerr << "[DBC Watcher] Monitoring started on: " << directoryPath << "\n"; -} - -void DbcWatcher::stop() { - running.store(false); - if (workerThread.joinable()) - workerThread.join(); - std::cerr << "[DBC Watcher] Monitoring stopped.\n"; -} - -void DbcWatcher::monitorLoop() { - using namespace std::chrono_literals; - - while (running.load()) { - try { - for (const auto& entry : fs::directory_iterator(directoryPath)) { - if (!entry.is_regular_file()) continue; - - std::string path = entry.path().string(); - if (entry.path().extension() != ".dbc") continue; - - auto lastWrite = fs::last_write_time(entry.path()); - - // ✅ replaced .contains with .find for C++17 compatibility - if (fileTimestamps.find(path) == fileTimestamps.end() || fileTimestamps[path] != lastWrite) { - fileTimestamps[path] = lastWrite; - std::cerr << "[DBC Watcher] Detected new or modified file: " << path << "\n"; - - if (network.loadDBC(path)) { - std::cerr << "[DBC Watcher] Loaded DBC: " << path << "\n"; - } else { - std::cerr << "[DBC Watcher] Failed to load DBC: " << path << "\n"; - } - } - } - } catch (const std::exception& e) { - std::cerr << "[DBC Watcher] Error: " << e.what() << "\n"; - } - - std::this_thread::sleep_for(std::chrono::seconds(pollInterval)); - } -} diff --git a/photon/network/dbc_watcher.hpp b/photon/network/dbc_watcher.hpp deleted file mode 100644 index 48df82ba..00000000 --- a/photon/network/dbc_watcher.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include "network.hpp" - -namespace fs = std::filesystem; - -class DbcWatcher { -public: - DbcWatcher(Network& net, const std::string& directory, int intervalSeconds = 5); - ~DbcWatcher(); - - void start(); - void stop(); - -private: - void monitorLoop(); - - Network& network; - std::string directoryPath; - int pollInterval; - std::atomic running; - std::thread workerThread; - - // Keep track of last modification times - std::unordered_map fileTimestamps; -}; diff --git a/photon/network/network.cpp b/photon/network/network.cpp index 769e442c..7bdd7a78 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -1,7 +1,8 @@ +#include +#define NOMINMAX +#include #include "network.hpp" #include "tcp.hpp" -#include "dbc_loader.hpp" -#include "dbc_connector.hpp" #include #include #include @@ -17,26 +18,38 @@ static int hexValue(char c) { return -1; } -Network::Network() : spscQueue(QUEUE_CAPACITY) {} +Network::Network() + : spscQueue(QUEUE_CAPACITY) {} + +// ---------------------- producer ---------------------- void Network::producer() { - std::cerr << "[DEBUG] Using IP=" << IP << " PORT=" << PORT << "\n"; + std::cerr << "[DEBUG] Using IP=" << IP + << " PORT=" << PORT << "\n"; + TcpSocket socket(IP, PORT); std::vector buffer(BUFFER_CAPACITY); - std::cerr << "[+] Attempting connection to " << IP << ":" << PORT << "...\n"; + std::cerr << "[+] Attempting connection to " + << IP << ":" << PORT << "...\n"; std::cerr << "[+] Connected (TcpSocket constructor succeeded).\n"; - while (true) { auto bytesRead = socket.read(buffer.data(), buffer.size()); if (bytesRead > 0) { - for (size_t i = 0; i < (size_t)bytesRead; ++i) - while (!spscQueue.try_push(buffer[i])) std::this_thread::yield(); - } else std::this_thread::sleep_for(std::chrono::milliseconds(100)); + for (size_t i = 0; i < (size_t)bytesRead; ++i) { + while (!spscQueue.try_push(buffer[i])) + std::this_thread::yield(); + } + } else { + std::this_thread::sleep_for( + std::chrono::milliseconds(100)); + } } } +// ---------------------- parser ---------------------- + void Network::parser() { std::string frame; frame.reserve(256); @@ -49,14 +62,21 @@ void Network::parser() { if (!collecting && (std::isprint(ch) || ch == '\r')) collecting = true; - if (!collecting) continue; + if (!collecting) + continue; if (ch == '\r') { if (!frame.empty()) { - while (!frame.empty() && (frame.back() == '\r' || frame.back() == '\n')) + while (!frame.empty() && + (frame.back() == '\r' || + frame.back() == '\n')) { frame.pop_back(); + } - if (frame.rfind("t", 0) == 0) handleFrame(frame); + if (!frame.empty() && + frame.rfind("t", 0) == 0) { + handleFrame(frame); + } } frame.clear(); collecting = false; @@ -64,23 +84,35 @@ void Network::parser() { } frame.push_back(ch); - } else std::this_thread::yield(); + } else { + std::this_thread::yield(); + } } } -bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value) { - if (frame.empty() || frame.front() != 't' || frame.size() < 5) return false; +// ---------------------- decodeFrame ---------------------- + +bool Network::decodeFrame(const std::string& frame, + uint16_t& canId, + uint64_t& value) { + if (frame.empty() || frame.front() != 't' + || frame.size() < 5) + return false; + int dataLength = hexValue(frame[4]); - if (dataLength < 0 || dataLength > 8) return false; + if (dataLength < 0 || dataLength > 8) + return false; - const size_t expectedLength = 5 + (size_t)dataLength * 2; - if (frame.size() != expectedLength) return false; + const size_t expectedLength = + 5 + static_cast(dataLength) * 2; + if (frame.size() != expectedLength) + return false; canId = 0; for (size_t i = 1; i <= 3; ++i) { int nibble = hexValue(frame[i]); if (nibble < 0) return false; - canId = (uint16_t)((canId << 4) | nibble); + canId = static_cast((canId << 4) | nibble); } value = 0; @@ -88,28 +120,47 @@ bool Network::decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& v int hi = hexValue(frame[5 + i * 2]); int lo = hexValue(frame[6 + i * 2]); if (hi < 0 || lo < 0) return false; - uint8_t byte = (uint8_t)((hi << 4) | lo); + uint8_t byte = static_cast((hi << 4) | lo); value = (value << 8) | byte; } + return true; } +// ---------------------- handleFrame ---------------------- + void Network::handleFrame(const std::string& frame) { uint16_t canId; uint64_t value; + if (!decodeFrame(frame, canId, value)) { - std::cerr << "[parser] Invalid SLCAN frame → " << frame << "\n"; + std::cerr << "[parser] Invalid SLCAN frame → " + << frame << "\n"; return; } - std::lock_guard lock(sampleMapMutex); - auto& entry = sampleMap[canId]; - std::lock_guard entryLock(entry.lock); - entry.point = value; + { + std::lock_guard guard(sampleMapMutex); + auto& entry = sampleMap[canId]; + std::lock_guard entryLock(entry.lock); + entry.point = value; + } + + std::cerr << "[SLCAN] ID=" << canId + << " Value=0x" << std::hex << value + << std::dec << "\n"; + + // Interpret using DBC if available + if (dbcManager.hasMessages()) { + interpretDBCFrame(canId, value, frame[4] - '0'); // DLC from frame[4] + } else { + std::cerr << "[DBC] Map is empty.\n"; + } - std::cerr << "[SLCAN] ID=" << canId << " Value=" << std::hex << value << std::dec << "\n"; } +// ---------------------- sample helpers ---------------------- + Network::sample& Network::ensureSample(uint16_t canId) { std::lock_guard guard(sampleMapMutex); return sampleMap[canId]; @@ -118,12 +169,84 @@ Network::sample& Network::ensureSample(uint16_t canId) { bool Network::readSample(uint16_t canId, uint64_t& outValue) { std::lock_guard guard(sampleMapMutex); auto it = sampleMap.find(canId); - if (it == sampleMap.end()) return false; + if (it == sampleMap.end()) + return false; + std::lock_guard lock(it->second.lock); outValue = it->second.point; return true; } +// --------------------------------------------------------- +// Decode raw CAN payload using the DBC map +// --------------------------------------------------------- +void Network::interpretDBCFrame(uint16_t canId, uint64_t rawValue, int dlc) { + std::lock_guard lock(dbcManager.mapMutex); + + auto it = dbcManager.dbcMap.find(canId); + if (it == dbcManager.dbcMap.end()) { + std::cerr << "[DBC Decode] No DBC entry for CAN ID " << canId << "\n"; + return; + } + + const DbcMessage& msg = it->second; + + // ---- COLLECT INTO A VECTOR ---- + std::vector collected; + collected.push_back(msg.name); + + // Convert rawValue → bytes + uint8_t bytes[8] = {0}; + uint64_t tmp = rawValue; + for (int i = dlc - 1; i >= 0; --i) { + bytes[i] = static_cast(tmp & 0xFF); + tmp >>= 8; + } + + // Iterate signals + for (const auto& [sigName, sig] : msg.signals) { + + uint64_t rawSignal = 0; + int byteIndex = sig.startBit / 8; + int bitOffset = sig.startBit % 8; + int bitsLeft = sig.length; + int dstPos = 0; + + while (bitsLeft > 0 && byteIndex < dlc) { + int bitsInByte = std::min(8 - bitOffset, bitsLeft); + uint8_t mask = ((1 << bitsInByte) - 1) << bitOffset; + uint8_t extracted = (bytes[byteIndex] & mask) >> bitOffset; + rawSignal |= (uint64_t(extracted) << dstPos); + + bitsLeft -= bitsInByte; + dstPos += bitsInByte; + byteIndex++; + bitOffset = 0; + } + + double physValue = sig.scale * rawSignal + sig.offset; + + // ---- MAKE A STRING FOR THIS SIGNAL ---- + std::ostringstream ss; + ss << sigName << " = " << physValue; + if (!sig.unit.empty()) + ss << " " << sig.unit; + + collected.push_back(ss.str()); + + // ---- Print OUT (original behavior) ---- + std::cerr << " " << ss.str() << "\n"; + } + + // ---- STORE IN HISTORY ---- + { + std::lock_guard histLock(decodedHistoryMutex); + decodedHistory.push_back({canId, rawValue, collected}); + if (decodedHistory.size() > MAX_HISTORY) + decodedHistory.pop_front(); + } +} + void Network::writeSample(uint16_t canId, uint64_t value) { std::lock_guard guard(sampleMapMutex); auto& s = sampleMap[canId]; @@ -131,16 +254,12 @@ void Network::writeSample(uint16_t canId, uint64_t value) { s.point = value; } +// ---------------------- DBC wrappers ---------------------- + bool Network::loadDBC(const std::string& path) { - std::cerr << "[DBC Loader] Loading DBC from " << path << "\n"; - DbcConnector connector; - return DbcLoader::loadFromFile(path, connector); + return dbcManager.loadFromFile(path); } void Network::printDBCMap() { - std::cerr << "[DBC] Dump of loaded messages:\n"; - for (const auto& [id, msg] : dbcMap) { - std::cerr << "CAN ID: " << id << " Name: " << msg.name - << " DLC: " << (int)msg.dlc << " Sender: " << msg.sender << "\n"; - } + dbcManager.dump(); } diff --git a/photon/network/network.hpp b/photon/network/network.hpp index cec3946b..5162428a 100644 --- a/photon/network/network.hpp +++ b/photon/network/network.hpp @@ -1,9 +1,5 @@ -/* [ξ] Photon Network Interface - Handles real-time SLCAN (CAN over TCP) parsing and DBC mapping. - Designed for thread-safe CAN streaming and modular DBC integration. -*/ - #pragma once + #include #include #include @@ -11,10 +7,11 @@ #include #include #include "spsc.hpp" +#include "dbc_manager.hpp" +#include // forward declaration class TcpSocket; -class DbcConnector; class Network { public: @@ -26,6 +23,8 @@ class Network { // --- Debug / DBC --- void printDBCMap(); + DbcManager dbcManager; + DbcManager& getDbcManager() { return dbcManager; } bool loadDBC(const std::string& path); // --- CAN sample interface --- @@ -33,46 +32,37 @@ class Network { void writeSample(uint16_t canId, uint64_t value); // --- Network configuration --- - std::string IP = "3.141.38.115"; + std::string IP = "127.0.0.1"; unsigned PORT = 8187; SPSCQueue spscQueue; + struct DecodedEntry { + uint16_t canId; + uint64_t rawValue; + std::vector lines; // e.g. "Temp=25°C, Mode=3, Enabled=1" + }; + + static constexpr size_t MAX_HISTORY = 100; + std::mutex decodedHistoryMutex; + std::deque decodedHistory; + private: struct sample { std::mutex lock; uint64_t point = 0; }; - struct DbcSignal { - std::string name; - int startBit = 0; - int length = 0; - int byteOrder = 0; - bool isSigned = false; - double scale = 1.0; - double offset = 0.0; - double minVal = 0.0; - double maxVal = 0.0; - }; - struct DbcMessage { - std::string name; - uint8_t dlc = 0; - std::string sender; - std::vector signals; - }; + // --- Maps --- std::unordered_map sampleMap; - std::unordered_map dbcMap; - - std::mutex sampleMapMutex; - std::mutex dbcMapMutex; - - uint32_t currentCanId = 0; - + std::mutex sampleMapMutex;; // --- Helpers --- sample& ensureSample(uint16_t canId); - bool decodeFrame(const std::string& frame, uint16_t& canId, uint64_t& value); + bool decodeFrame(const std::string& frame, + uint16_t& canId, + uint64_t& value); void handleFrame(const std::string& frame); + void interpretDBCFrame(uint16_t canId, uint64_t rawValue, int dlc); }; From b34956dd57b1649a5a03d9923a0196d664206631 Mon Sep 17 00:00:00 2001 From: Ali Date: Sat, 15 Nov 2025 15:38:42 -0600 Subject: [PATCH 9/9] made it so you could see hexa and decimal inside of the monitor. --- photon/gui/ui.cpp | 2 +- photon/network/network.cpp | 9 ++++++--- photon/network/network.hpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/photon/gui/ui.cpp b/photon/gui/ui.cpp index e0eb8175..35830a8b 100644 --- a/photon/gui/ui.cpp +++ b/photon/gui/ui.cpp @@ -265,7 +265,7 @@ void UI::slcanWindow() { // CAN ID ImGui::TableSetColumnIndex(0); - ImGui::Text("0x%03X", entry.canId); + ImGui::Text("%u (0x%X)", entry.canId, entry.canId); // Raw Value ImGui::TableSetColumnIndex(1); diff --git a/photon/network/network.cpp b/photon/network/network.cpp index 7bdd7a78..b714540f 100644 --- a/photon/network/network.cpp +++ b/photon/network/network.cpp @@ -146,9 +146,12 @@ void Network::handleFrame(const std::string& frame) { entry.point = value; } - std::cerr << "[SLCAN] ID=" << canId - << " Value=0x" << std::hex << value - << std::dec << "\n"; + std::cerr << "[SLCAN] CAN ID = " << canId + << " (0x" << std::uppercase << std::hex << canId << std::dec << ")" + << " | DLC = " << int(frame[4] - '0') + << " | DATA = 0x" << std::uppercase << std::hex << value << std::dec + << "\n"; + // Interpret using DBC if available if (dbcManager.hasMessages()) { diff --git a/photon/network/network.hpp b/photon/network/network.hpp index 5162428a..304a3e54 100644 --- a/photon/network/network.hpp +++ b/photon/network/network.hpp @@ -32,7 +32,7 @@ class Network { void writeSample(uint16_t canId, uint64_t value); // --- Network configuration --- - std::string IP = "127.0.0.1"; + std::string IP = "127.0.0.1";//"3.141.38.115"; unsigned PORT = 8187; SPSCQueue spscQueue;