From a89fceaf3901eb9f274d3ebf278074b1704f86cb Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 14 Jul 2025 14:42:18 -0300 Subject: [PATCH 1/7] feat(openthread): native API extension --- .../LeaderNode/LeaderNode.ino | 94 +++++- .../RouterNode/RouterNode.ino | 59 +++- libraries/OpenThread/keywords.txt | 20 +- libraries/OpenThread/src/OThread.cpp | 290 ++++++++++++++++++ libraries/OpenThread/src/OThread.h | 60 ++++ 5 files changed, 516 insertions(+), 7 deletions(-) diff --git a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino index dfea9776838..6a90a5eab90 100644 --- a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino +++ b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino @@ -3,6 +3,9 @@ OpenThread threadLeaderNode; DataSet dataset; +// Track last known device role for state change detection +ot_device_role_t lastKnownRole = OT_ROLE_DISABLED; + void setup() { Serial.begin(115200); @@ -27,8 +30,93 @@ void setup() { } void loop() { - // Print network information every 5 seconds - Serial.println("=============================================="); - threadLeaderNode.otPrintNetworkInformation(Serial); + // Get current device role + ot_device_role_t currentRole = threadLeaderNode.otGetDeviceRole(); + + // Only print network information when not detached + if (currentRole != OT_ROLE_DETACHED && currentRole != OT_ROLE_DISABLED) { + Serial.println("=============================================="); + Serial.println("OpenThread Network Information:"); + + // Basic network information + Serial.printf("Role: %s\n", threadLeaderNode.otGetStringDeviceRole()); + Serial.printf("RLOC16: 0x%04x\n", threadLeaderNode.getRloc16()); + Serial.printf("Network Name: %s\n", threadLeaderNode.getNetworkName().c_str()); + Serial.printf("Channel: %d\n", threadLeaderNode.getChannel()); + Serial.printf("PAN ID: 0x%04x\n", threadLeaderNode.getPanId()); + + // Extended PAN ID + const uint8_t *extPanId = threadLeaderNode.getExtendedPanId(); + if (extPanId) { + Serial.print("Extended PAN ID: "); + for (int i = 0; i < OT_EXT_PAN_ID_SIZE; i++) { + Serial.printf("%02x", extPanId[i]); + } + Serial.println(); + } + + // Network Key + const uint8_t *networkKey = threadLeaderNode.getNetworkKey(); + if (networkKey) { + Serial.print("Network Key: "); + for (int i = 0; i < OT_NETWORK_KEY_SIZE; i++) { + Serial.printf("%02x", networkKey[i]); + } + Serial.println(); + } + + // Mesh Local EID + IPAddress meshLocalEid = threadLeaderNode.getMeshLocalEid(); + Serial.printf("Mesh Local EID: %s\n", meshLocalEid.toString().c_str()); + + // Leader RLOC + IPAddress leaderRloc = threadLeaderNode.getLeaderRloc(); + Serial.printf("Leader RLOC: %s\n", leaderRloc.toString().c_str()); + + // Node RLOC + IPAddress nodeRloc = threadLeaderNode.getRloc(); + Serial.printf("Node RLOC: %s\n", nodeRloc.toString().c_str()); + + // Demonstrate address listing with two different methods: + // Method 1: Unicast addresses using counting API (individual access) + Serial.println("\n--- Unicast Addresses (Using Count + Index API) ---"); + size_t unicastCount = threadLeaderNode.getUnicastAddressCount(); + for (size_t i = 0; i < unicastCount; i++) { + IPAddress addr = threadLeaderNode.getUnicastAddress(i); + Serial.printf(" [%zu]: %s\n", i, addr.toString().c_str()); + } + + // Method 2: Multicast addresses using std::vector (bulk access) + Serial.println("\n--- Multicast Addresses (Using std::vector API) ---"); + std::vector allMulticast = threadLeaderNode.getAllMulticastAddresses(); + for (size_t i = 0; i < allMulticast.size(); i++) { + Serial.printf(" [%zu]: %s\n", i, allMulticast[i].toString().c_str()); + } + + // Cache management information + Serial.println("\n--- Address Access Methods ---"); + Serial.println("Two ways to access addresses:"); + Serial.println("1. Count + Index: getUnicastAddressCount() + getUnicastAddress(index)"); + Serial.println("2. Vector: getAllUnicastAddresses() or getAllMulticastAddresses()"); + Serial.println("Cache is automatically populated when empty"); + + Serial.println("==============================================\n"); + + // Check for role change and clear cache if needed (only when active) + if (currentRole != lastKnownRole) { + Serial.printf("Role changed from %s to %s - clearing address cache\n", + (lastKnownRole < 5) ? otRoleString[lastKnownRole] : "Unknown", + threadLeaderNode.otGetStringDeviceRole()); + threadLeaderNode.clearAllAddressCache(); + lastKnownRole = currentRole; + } + } else { + Serial.printf("Thread Node Status: %s - Waiting for network connection...\n", + threadLeaderNode.otGetStringDeviceRole()); + + // Update role tracking even when detached/disabled, but don't clear cache + lastKnownRole = currentRole; + } + delay(5000); } diff --git a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino index 5ffa535ad51..a4f4a67a76d 100644 --- a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino +++ b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino @@ -22,8 +22,61 @@ void setup() { } void loop() { - // Print network information every 5 seconds - Serial.println("=============================================="); - threadChildNode.otPrintNetworkInformation(Serial); + // Get current device role + ot_device_role_t currentRole = threadChildNode.otGetDeviceRole(); + + // Only print detailed network information when node is active + if (currentRole != OT_ROLE_DETACHED && currentRole != OT_ROLE_DISABLED) { + Serial.println("=============================================="); + Serial.println("OpenThread Network Information (Active Dataset):"); + + // Get and display the current active dataset + const DataSet &activeDataset = threadChildNode.getCurrentDataSet(); + + Serial.printf("Role: %s\n", threadChildNode.otGetStringDeviceRole()); + Serial.printf("RLOC16: 0x%04x\n", threadChildNode.getRloc16()); + + // Dataset information + Serial.printf("Network Name: %s\n", activeDataset.getNetworkName()); + Serial.printf("Channel: %d\n", activeDataset.getChannel()); + Serial.printf("PAN ID: 0x%04x\n", activeDataset.getPanId()); + + // Extended PAN ID from dataset + const uint8_t *extPanId = activeDataset.getExtendedPanId(); + if (extPanId) { + Serial.print("Extended PAN ID: "); + for (int i = 0; i < OT_EXT_PAN_ID_SIZE; i++) { + Serial.printf("%02x", extPanId[i]); + } + Serial.println(); + } + + // Network Key from dataset + const uint8_t *networkKey = activeDataset.getNetworkKey(); + if (networkKey) { + Serial.print("Network Key: "); + for (int i = 0; i < OT_NETWORK_KEY_SIZE; i++) { + Serial.printf("%02x", networkKey[i]); + } + Serial.println(); + } + + // Additional runtime information + IPAddress meshLocalEid = threadChildNode.getMeshLocalEid(); + Serial.printf("Mesh Local EID: %s\n", meshLocalEid.toString().c_str()); + + IPAddress nodeRloc = threadChildNode.getRloc(); + Serial.printf("Node RLOC: %s\n", nodeRloc.toString().c_str()); + + Serial.println(); + + } else { + Serial.println("=============================================="); + Serial.printf("Thread Node Status: %s - Waiting for network connection...\n", + threadChildNode.otGetStringDeviceRole()); + + Serial.println(); + } + delay(5000); } diff --git a/libraries/OpenThread/keywords.txt b/libraries/OpenThread/keywords.txt index b62c2c23ddc..b34f67276f6 100644 --- a/libraries/OpenThread/keywords.txt +++ b/libraries/OpenThread/keywords.txt @@ -1,4 +1,4 @@ -####################################### +check ####################################### # Syntax Coloring Map For OpenThread ####################################### @@ -13,6 +13,7 @@ OpenThread KEYWORD1 DataSet KEYWORD1 ot_cmd_return_t KEYWORD1 ot_device_role_t KEYWORD1 +OnReceiveCb_t KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -59,6 +60,23 @@ stop KEYWORD2 networkInterfaceUp KEYWORD2 networkInterfaceDown KEYWORD2 commitDataSet KEYWORD2 +getInstance KEYWORD2 +getCurrentDataSet KEYWORD2 +getMeshLocalPrefix KEYWORD2 +getMeshLocalEid KEYWORD2 +getLeaderRloc KEYWORD2 +getRloc KEYWORD2 +getRloc16 KEYWORD2 +getUnicastAddressCount KEYWORD2 +getUnicastAddress KEYWORD2 +getAllUnicastAddresses KEYWORD2 +getMulticastAddressCount KEYWORD2 +getMulticastAddress KEYWORD2 +getAllMulticastAddresses KEYWORD2 +clearUnicastAddressCache KEYWORD2 +clearMulticastAddressCache KEYWORD2 +clearAllAddressCache KEYWORD2 +end KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/libraries/OpenThread/src/OThread.cpp b/libraries/OpenThread/src/OThread.cpp index 7714d870cce..6ae1c7ff775 100644 --- a/libraries/OpenThread/src/OThread.cpp +++ b/libraries/OpenThread/src/OThread.cpp @@ -2,6 +2,8 @@ #if SOC_IEEE802154_SUPPORTED #if CONFIG_OPENTHREAD_ENABLED +#include "IPAddress.h" +#include #include "esp_err.h" #include "esp_event.h" #include "esp_netif.h" @@ -262,6 +264,7 @@ void OpenThread::start() { log_w("Error: OpenThread instance not initialized"); return; } + clearAllAddressCache(); // Clear cache when starting network otThreadSetEnabled(mInstance, true); log_d("Thread network started"); } @@ -271,6 +274,7 @@ void OpenThread::stop() { log_w("Error: OpenThread instance not initialized"); return; } + clearAllAddressCache(); // Clear cache when stopping network otThreadSetEnabled(mInstance, false); log_d("Thread network stopped"); } @@ -285,6 +289,7 @@ void OpenThread::networkInterfaceUp() { if (error != OT_ERROR_NONE) { log_e("Error: Failed to enable Thread interface (error code: %d)\n", error); } + clearAllAddressCache(); // Clear cache when interface comes up log_d("OpenThread Network Interface is up"); } @@ -312,6 +317,7 @@ void OpenThread::commitDataSet(const DataSet &dataset) { log_e("Error: Failed to commit dataset (error code: %d)\n", error); return; } + clearAllAddressCache(); // Clear cache when dataset changes log_d("Dataset committed successfully"); } @@ -360,6 +366,290 @@ void OpenThread::otPrintNetworkInformation(Stream &output) { output.println(); } +// Get the Node Network Name +String OpenThread::getNetworkName() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return String(); // Return empty String, not nullptr + } + const char* networkName = otThreadGetNetworkName(mInstance); + return networkName ? String(networkName) : String(); +} + +// Get the Node Extended PAN ID +const uint8_t *OpenThread::getExtendedPanId() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return nullptr; + } + const otExtendedPanId *extPanId = otThreadGetExtendedPanId(mInstance); + return extPanId ? extPanId->m8 : nullptr; +} + +// Get the Node Network Key +const uint8_t *OpenThread::getNetworkKey() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return nullptr; + } + static otNetworkKey networkKey; // Static storage to persist after function return + otError error = otThreadGetNetworkKey(mInstance, &networkKey); + return (error == OT_ERROR_NONE) ? networkKey.m8 : nullptr; +} + +// Get the Node Channel +uint8_t OpenThread::getChannel() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return 0; + } + return otLinkGetChannel(mInstance); +} + +// Get the Node PAN ID +uint16_t OpenThread::getPanId() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return 0; + } + return otLinkGetPanId(mInstance); +} + +// Get the OpenThread instance +otInstance *OpenThread::getInstance() { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return nullptr; + } + return mInstance; +} + +// Get the current dataset +const DataSet &OpenThread::getCurrentDataSet() const { + static DataSet currentDataset; + + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + currentDataset.clear(); + return currentDataset; + } + + otOperationalDataset dataset; + otError error = otDatasetGetActive(mInstance, &dataset); + + if (error == OT_ERROR_NONE) { + currentDataset.clear(); + + if (dataset.mComponents.mIsNetworkNamePresent) { + currentDataset.setNetworkName(dataset.mNetworkName.m8); + } + if (dataset.mComponents.mIsExtendedPanIdPresent) { + currentDataset.setExtendedPanId(dataset.mExtendedPanId.m8); + } + if (dataset.mComponents.mIsNetworkKeyPresent) { + currentDataset.setNetworkKey(dataset.mNetworkKey.m8); + } + if (dataset.mComponents.mIsChannelPresent) { + currentDataset.setChannel(dataset.mChannel); + } + if (dataset.mComponents.mIsPanIdPresent) { + currentDataset.setPanId(dataset.mPanId); + } + } else { + log_w("Failed to get active dataset (error: %d)", error); + currentDataset.clear(); + } + + return currentDataset; +} + +// Get the Mesh Local Prefix +const otMeshLocalPrefix *OpenThread::getMeshLocalPrefix() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return nullptr; + } + return otThreadGetMeshLocalPrefix(mInstance); +} + +// Get the Mesh-Local EID +IPAddress OpenThread::getMeshLocalEid() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return IPAddress(IPv6); // Return empty IPv6 address + } + const otIp6Address *otAddr = otThreadGetMeshLocalEid(mInstance); + if (!otAddr) { + log_w("Failed to get Mesh Local EID"); + return IPAddress(IPv6); + } + return IPAddress(IPv6, otAddr->mFields.m8); +} + +// Get the Thread Leader RLOC +IPAddress OpenThread::getLeaderRloc() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return IPAddress(IPv6); // Return empty IPv6 address + } + const otIp6Address *otAddr = otThreadGetLeaderRloc(mInstance); + if (!otAddr) { + log_w("Failed to get Leader RLOC"); + return IPAddress(IPv6); + } + return IPAddress(IPv6, otAddr->mFields.m8); +} + +// Get the Node RLOC +IPAddress OpenThread::getRloc() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return IPAddress(IPv6); // Return empty IPv6 address + } + const otIp6Address *otAddr = otThreadGetRloc(mInstance); + if (!otAddr) { + log_w("Failed to get Node RLOC"); + return IPAddress(IPv6); + } + return IPAddress(IPv6, otAddr->mFields.m8); +} + +// Get the RLOC16 ID +uint16_t OpenThread::getRloc16() const { + if (!mInstance) { + log_w("Error: OpenThread instance not initialized"); + return 0; + } + return otThreadGetRloc16(mInstance); +} + +// Populate unicast address cache from OpenThread +void OpenThread::populateUnicastAddressCache() const { + if (!mInstance) { + return; + } + + // Clear existing cache + mCachedUnicastAddresses.clear(); + + // Populate unicast addresses cache + const otNetifAddress *addr = otIp6GetUnicastAddresses(mInstance); + while (addr != nullptr) { + mCachedUnicastAddresses.push_back(IPAddress(IPv6, addr->mAddress.mFields.m8)); + addr = addr->mNext; + } + + log_d("Populated unicast address cache with %d addresses", mCachedUnicastAddresses.size()); +} + +// Populate multicast address cache from OpenThread +void OpenThread::populateMulticastAddressCache() const { + if (!mInstance) { + return; + } + + // Clear existing cache + mCachedMulticastAddresses.clear(); + + // Populate multicast addresses cache + const otNetifMulticastAddress *mAddr = otIp6GetMulticastAddresses(mInstance); + while (mAddr != nullptr) { + mCachedMulticastAddresses.push_back(IPAddress(IPv6, mAddr->mAddress.mFields.m8)); + mAddr = mAddr->mNext; + } + + log_d("Populated multicast address cache with %d addresses", mCachedMulticastAddresses.size()); +} + +// Clear unicast address cache +void OpenThread::clearUnicastAddressCache() const { + mCachedUnicastAddresses.clear(); + log_d("Cleared unicast address cache"); +} + +// Clear multicast address cache +void OpenThread::clearMulticastAddressCache() const { + mCachedMulticastAddresses.clear(); + log_d("Cleared multicast address cache"); +} + +// Clear all address caches +void OpenThread::clearAllAddressCache() const { + mCachedUnicastAddresses.clear(); + mCachedMulticastAddresses.clear(); + log_d("Cleared all address caches"); +} + +// Get count of unicast addresses +size_t OpenThread::getUnicastAddressCount() const { + // Populate cache if empty + if (mCachedUnicastAddresses.empty()) { + populateUnicastAddressCache(); + } + + return mCachedUnicastAddresses.size(); +} + +// Get unicast address by index +IPAddress OpenThread::getUnicastAddress(size_t index) const { + // Populate cache if empty + if (mCachedUnicastAddresses.empty()) { + populateUnicastAddressCache(); + } + + if (index >= mCachedUnicastAddresses.size()) { + log_w("Unicast address index %zu out of range (max: %zu)", index, mCachedUnicastAddresses.size()); + return IPAddress(IPv6); + } + + return mCachedUnicastAddresses[index]; +} + +// Get all unicast addresses +std::vector OpenThread::getAllUnicastAddresses() const { + // Populate cache if empty + if (mCachedUnicastAddresses.empty()) { + populateUnicastAddressCache(); + } + + return mCachedUnicastAddresses; // Return copy of cached vector +} + +// Get count of multicast addresses +size_t OpenThread::getMulticastAddressCount() const { + // Populate cache if empty + if (mCachedMulticastAddresses.empty()) { + populateMulticastAddressCache(); + } + + return mCachedMulticastAddresses.size(); +} + +// Get multicast address by index +IPAddress OpenThread::getMulticastAddress(size_t index) const { + // Populate cache if empty + if (mCachedMulticastAddresses.empty()) { + populateMulticastAddressCache(); + } + + if (index >= mCachedMulticastAddresses.size()) { + log_w("Multicast address index %zu out of range (max: %zu)", index, mCachedMulticastAddresses.size()); + return IPAddress(IPv6); + } + + return mCachedMulticastAddresses[index]; +} + +// Get all multicast addresses +std::vector OpenThread::getAllMulticastAddresses() const { + // Populate cache if empty + if (mCachedMulticastAddresses.empty()) { + populateMulticastAddressCache(); + } + + return mCachedMulticastAddresses; // Return copy of cached vector +} + OpenThread OThread; #endif /* CONFIG_OPENTHREAD_ENABLED */ diff --git a/libraries/OpenThread/src/OThread.h b/libraries/OpenThread/src/OThread.h index 359d581bb9d..e20b278698e 100644 --- a/libraries/OpenThread/src/OThread.h +++ b/libraries/OpenThread/src/OThread.h @@ -25,6 +25,8 @@ #include #include #include +#include "IPAddress.h" +#include typedef enum { OT_ROLE_DISABLED = 0, ///< The Thread stack is disabled. @@ -96,9 +98,67 @@ class OpenThread { // Set the dataset void commitDataSet(const DataSet &dataset); + // Get the Node Network Name + String getNetworkName() const; + + // Get the Node Extended PAN ID + const uint8_t *getExtendedPanId() const; + + // Get the Node Network Key + const uint8_t *getNetworkKey() const; + + // Get the Node Channel + uint8_t getChannel() const; + + // Get the Node PAN ID + uint16_t getPanId() const; + + // Get the OpenThread instance + otInstance *getInstance(); + + // Get the current dataset + const DataSet &getCurrentDataSet() const; + + // Get the Mesh Local Prefix + const otMeshLocalPrefix *getMeshLocalPrefix() const; + + // Get the Mesh-Local EID + IPAddress getMeshLocalEid() const; + + // Get the Thread Leader RLOC + IPAddress getLeaderRloc() const; + + // Get the Node RLOC + IPAddress getRloc() const; + + // Get the RLOC16 ID + uint16_t getRloc16() const; + + // Address management with caching + size_t getUnicastAddressCount() const; + IPAddress getUnicastAddress(size_t index) const; + std::vector getAllUnicastAddresses() const; + + size_t getMulticastAddressCount() const; + IPAddress getMulticastAddress(size_t index) const; + std::vector getAllMulticastAddresses() const; + + // Cache management + void clearUnicastAddressCache() const; + void clearMulticastAddressCache() const; + void clearAllAddressCache() const; + private: static otInstance *mInstance; DataSet mCurrentDataSet; + + // Address caching for performance (user-controlled) + mutable std::vector mCachedUnicastAddresses; + mutable std::vector mCachedMulticastAddresses; + + // Internal cache management + void populateUnicastAddressCache() const; + void populateMulticastAddressCache() const; }; extern OpenThread OThread; From dcb09f358b33cd9fb4b7fbfe14d3264b0bb00e2d Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 14 Jul 2025 15:10:48 -0300 Subject: [PATCH 2/7] fix(openthread): wrong return type and parameter --- libraries/OpenThread/keywords.txt | 2 +- libraries/OpenThread/src/OThread.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/OpenThread/keywords.txt b/libraries/OpenThread/keywords.txt index b34f67276f6..99821ce401c 100644 --- a/libraries/OpenThread/keywords.txt +++ b/libraries/OpenThread/keywords.txt @@ -1,4 +1,4 @@ -check ####################################### +####################################### # Syntax Coloring Map For OpenThread ####################################### diff --git a/libraries/OpenThread/src/OThread.cpp b/libraries/OpenThread/src/OThread.cpp index 6ae1c7ff775..bc739331452 100644 --- a/libraries/OpenThread/src/OThread.cpp +++ b/libraries/OpenThread/src/OThread.cpp @@ -393,8 +393,8 @@ const uint8_t *OpenThread::getNetworkKey() const { return nullptr; } static otNetworkKey networkKey; // Static storage to persist after function return - otError error = otThreadGetNetworkKey(mInstance, &networkKey); - return (error == OT_ERROR_NONE) ? networkKey.m8 : nullptr; + otThreadGetNetworkKey(mInstance, &networkKey); + return networkKey.m8; } // Get the Node Channel @@ -492,8 +492,9 @@ IPAddress OpenThread::getLeaderRloc() const { log_w("Error: OpenThread instance not initialized"); return IPAddress(IPv6); // Return empty IPv6 address } - const otIp6Address *otAddr = otThreadGetLeaderRloc(mInstance); - if (!otAddr) { + otIp6Address otAddr; + otError error = otThreadGetLeaderRloc(mInstance, &otAddr); + if (error != OT_ERROR_NONE) { log_w("Failed to get Leader RLOC"); return IPAddress(IPv6); } From 637402fec5d5dae348920205637bdafce68deeae Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 14 Jul 2025 15:15:25 -0300 Subject: [PATCH 3/7] fix(openthread): wrong field reference --- libraries/OpenThread/src/OThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/OpenThread/src/OThread.cpp b/libraries/OpenThread/src/OThread.cpp index bc739331452..baddc5d3d68 100644 --- a/libraries/OpenThread/src/OThread.cpp +++ b/libraries/OpenThread/src/OThread.cpp @@ -498,7 +498,7 @@ IPAddress OpenThread::getLeaderRloc() const { log_w("Failed to get Leader RLOC"); return IPAddress(IPv6); } - return IPAddress(IPv6, otAddr->mFields.m8); + return IPAddress(IPv6, otAddr.mFields.m8); } // Get the Node RLOC From a48f3988de30df5cac993a33af9775378c8b546f Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 14 Jul 2025 16:16:36 -0300 Subject: [PATCH 4/7] fix(openthread): CR/LF fix --- .../LeaderNode/LeaderNode.ino | 39 +++++++------------ .../RouterNode/RouterNode.ino | 16 ++++---- libraries/OpenThread/src/OThread.cpp | 1 + 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino index 6a90a5eab90..e612d9728d3 100644 --- a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino +++ b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino @@ -39,11 +39,11 @@ void loop() { Serial.println("OpenThread Network Information:"); // Basic network information - Serial.printf("Role: %s\n", threadLeaderNode.otGetStringDeviceRole()); - Serial.printf("RLOC16: 0x%04x\n", threadLeaderNode.getRloc16()); - Serial.printf("Network Name: %s\n", threadLeaderNode.getNetworkName().c_str()); - Serial.printf("Channel: %d\n", threadLeaderNode.getChannel()); - Serial.printf("PAN ID: 0x%04x\n", threadLeaderNode.getPanId()); + Serial.printf("Role: %s\r\n", threadLeaderNode.otGetStringDeviceRole()); + Serial.printf("RLOC16: 0x%04x\r\n", threadLeaderNode.getRloc16()); + Serial.printf("Network Name: %s\r\n", threadLeaderNode.getNetworkName().c_str()); + Serial.printf("Channel: %d\r\n", threadLeaderNode.getChannel()); + Serial.printf("PAN ID: 0x%04x\r\n", threadLeaderNode.getPanId()); // Extended PAN ID const uint8_t *extPanId = threadLeaderNode.getExtendedPanId(); @@ -67,51 +67,42 @@ void loop() { // Mesh Local EID IPAddress meshLocalEid = threadLeaderNode.getMeshLocalEid(); - Serial.printf("Mesh Local EID: %s\n", meshLocalEid.toString().c_str()); + Serial.printf("Mesh Local EID: %s\r\n", meshLocalEid.toString().c_str()); // Leader RLOC IPAddress leaderRloc = threadLeaderNode.getLeaderRloc(); - Serial.printf("Leader RLOC: %s\n", leaderRloc.toString().c_str()); + Serial.printf("Leader RLOC: %s\r\n", leaderRloc.toString().c_str()); // Node RLOC IPAddress nodeRloc = threadLeaderNode.getRloc(); - Serial.printf("Node RLOC: %s\n", nodeRloc.toString().c_str()); + Serial.printf("Node RLOC: %s\r\n", nodeRloc.toString().c_str()); // Demonstrate address listing with two different methods: // Method 1: Unicast addresses using counting API (individual access) - Serial.println("\n--- Unicast Addresses (Using Count + Index API) ---"); + Serial.println("\r\n--- Unicast Addresses (Using Count + Index API) ---"); size_t unicastCount = threadLeaderNode.getUnicastAddressCount(); for (size_t i = 0; i < unicastCount; i++) { IPAddress addr = threadLeaderNode.getUnicastAddress(i); - Serial.printf(" [%zu]: %s\n", i, addr.toString().c_str()); + Serial.printf(" [%zu]: %s\r\n", i, addr.toString().c_str()); } // Method 2: Multicast addresses using std::vector (bulk access) - Serial.println("\n--- Multicast Addresses (Using std::vector API) ---"); + Serial.println("\r\n--- Multicast Addresses (Using std::vector API) ---"); std::vector allMulticast = threadLeaderNode.getAllMulticastAddresses(); for (size_t i = 0; i < allMulticast.size(); i++) { - Serial.printf(" [%zu]: %s\n", i, allMulticast[i].toString().c_str()); + Serial.printf(" [%zu]: %s\r\n", i, allMulticast[i].toString().c_str()); } - - // Cache management information - Serial.println("\n--- Address Access Methods ---"); - Serial.println("Two ways to access addresses:"); - Serial.println("1. Count + Index: getUnicastAddressCount() + getUnicastAddress(index)"); - Serial.println("2. Vector: getAllUnicastAddresses() or getAllMulticastAddresses()"); - Serial.println("Cache is automatically populated when empty"); - - Serial.println("==============================================\n"); - + // Check for role change and clear cache if needed (only when active) if (currentRole != lastKnownRole) { - Serial.printf("Role changed from %s to %s - clearing address cache\n", + Serial.printf("Role changed from %s to %s - clearing address cache\r\n", (lastKnownRole < 5) ? otRoleString[lastKnownRole] : "Unknown", threadLeaderNode.otGetStringDeviceRole()); threadLeaderNode.clearAllAddressCache(); lastKnownRole = currentRole; } } else { - Serial.printf("Thread Node Status: %s - Waiting for network connection...\n", + Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", threadLeaderNode.otGetStringDeviceRole()); // Update role tracking even when detached/disabled, but don't clear cache diff --git a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino index a4f4a67a76d..67101bd41be 100644 --- a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino +++ b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino @@ -33,13 +33,13 @@ void loop() { // Get and display the current active dataset const DataSet &activeDataset = threadChildNode.getCurrentDataSet(); - Serial.printf("Role: %s\n", threadChildNode.otGetStringDeviceRole()); - Serial.printf("RLOC16: 0x%04x\n", threadChildNode.getRloc16()); + Serial.printf("Role: %s\r\n", threadChildNode.otGetStringDeviceRole()); + Serial.printf("RLOC16: 0x%04x\r\n", threadChildNode.getRloc16()); // Dataset information - Serial.printf("Network Name: %s\n", activeDataset.getNetworkName()); - Serial.printf("Channel: %d\n", activeDataset.getChannel()); - Serial.printf("PAN ID: 0x%04x\n", activeDataset.getPanId()); + Serial.printf("Network Name: %s\r\n", activeDataset.getNetworkName()); + Serial.printf("Channel: %d\r\n", activeDataset.getChannel()); + Serial.printf("PAN ID: 0x%04x\r\n", activeDataset.getPanId()); // Extended PAN ID from dataset const uint8_t *extPanId = activeDataset.getExtendedPanId(); @@ -63,16 +63,16 @@ void loop() { // Additional runtime information IPAddress meshLocalEid = threadChildNode.getMeshLocalEid(); - Serial.printf("Mesh Local EID: %s\n", meshLocalEid.toString().c_str()); + Serial.printf("Mesh Local EID: %s\r\n", meshLocalEid.toString().c_str()); IPAddress nodeRloc = threadChildNode.getRloc(); - Serial.printf("Node RLOC: %s\n", nodeRloc.toString().c_str()); + Serial.printf("Node RLOC: %s\r\n", nodeRloc.toString().c_str()); Serial.println(); } else { Serial.println("=============================================="); - Serial.printf("Thread Node Status: %s - Waiting for network connection...\n", + Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", threadChildNode.otGetStringDeviceRole()); Serial.println(); diff --git a/libraries/OpenThread/src/OThread.cpp b/libraries/OpenThread/src/OThread.cpp index baddc5d3d68..6fb7de2c3bd 100644 --- a/libraries/OpenThread/src/OThread.cpp +++ b/libraries/OpenThread/src/OThread.cpp @@ -240,6 +240,7 @@ void OpenThread::begin(bool OThreadAutoStart) { log_i("AUTO start OpenThread done"); } } + delay(500); // Give some time for the OpenThread tasks to initialize otStarted = true; } From c336d93f8aa4c9ef585b6d7e8fa91d3e11492c68 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 14 Jul 2025 16:25:37 -0300 Subject: [PATCH 5/7] feat(openthread): print leader RLOC information --- .../Native/SimpleThreadNetwork/RouterNode/RouterNode.ino | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino index 67101bd41be..4725124bdfc 100644 --- a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino +++ b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino @@ -67,7 +67,10 @@ void loop() { IPAddress nodeRloc = threadChildNode.getRloc(); Serial.printf("Node RLOC: %s\r\n", nodeRloc.toString().c_str()); - + + IPAddress leaderRloc = threadChildNode.getLeaderRloc(); + Serial.printf("Leader RLOC: %s\r\n", leaderRloc.toString().c_str()); + Serial.println(); } else { From 0ae4855cfbfd71d415d6e2d5361cc2f4b4edc159 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 14 Jul 2025 22:54:54 -0300 Subject: [PATCH 6/7] feat(openthread): code improvements --- libraries/OpenThread/src/OThread.cpp | 105 ++++++++++++++++++--------- libraries/OpenThread/src/OThread.h | 3 +- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/libraries/OpenThread/src/OThread.cpp b/libraries/OpenThread/src/OThread.cpp index 6fb7de2c3bd..605fe874165 100644 --- a/libraries/OpenThread/src/OThread.cpp +++ b/libraries/OpenThread/src/OThread.cpp @@ -134,16 +134,29 @@ const otOperationalDataset &DataSet::getDataset() const { } void DataSet::setNetworkName(const char *name) { - strncpy(mDataset.mNetworkName.m8, name, sizeof(mDataset.mNetworkName.m8)); + if (!name) { + log_w("Network name is null"); + return; + } + // char m8[OT_NETWORK_KEY_SIZE + 1] bytes space by definition + strncpy(mDataset.mNetworkName.m8, name, OT_NETWORK_KEY_SIZE); mDataset.mComponents.mIsNetworkNamePresent = true; } void DataSet::setExtendedPanId(const uint8_t *extPanId) { + if (!extPanId) { + log_w("Extended PAN ID is null"); + return; + } memcpy(mDataset.mExtendedPanId.m8, extPanId, OT_EXT_PAN_ID_SIZE); mDataset.mComponents.mIsExtendedPanIdPresent = true; } void DataSet::setNetworkKey(const uint8_t *key) { + if (!key) { + log_w("Network key is null"); + return; + } memcpy(mDataset.mNetworkKey.m8, key, OT_NETWORK_KEY_SIZE); mDataset.mComponents.mIsNetworkKeyPresent = true; } @@ -183,10 +196,18 @@ void DataSet::apply(otInstance *instance) { } // OpenThread Implementation -bool OpenThread::otStarted = false; +bool OpenThread::otStarted; +otInstance *OpenThread::mInstance; +DataSet OpenThread::mCurrentDataset; +otNetworkKey OpenThread::mNetworkKey; -otInstance *OpenThread::mInstance = nullptr; -OpenThread::OpenThread() {} +OpenThread::OpenThread() { + // static initialization (node data and stack starting information) + otStarted = false; + mCurrentDataset.clear(); // Initialize the current dataset + memset(&mNetworkKey, 0, sizeof(mNetworkKey)); // Initialize the network key + mInstance = nullptr; +} OpenThread::~OpenThread() { end(); @@ -216,13 +237,7 @@ void OpenThread::begin(bool OThreadAutoStart) { return; } log_d("OpenThread task created successfully"); - // get the OpenThread instance that will be used for all operations - mInstance = esp_openthread_get_instance(); - if (!mInstance) { - log_e("Error: Failed to initialize OpenThread instance"); - end(); - return; - } + // starts Thread with default dataset from NVS or from IDF default settings if (OThreadAutoStart) { otOperationalDatasetTlvs dataset; @@ -240,24 +255,46 @@ void OpenThread::begin(bool OThreadAutoStart) { log_i("AUTO start OpenThread done"); } } - delay(500); // Give some time for the OpenThread tasks to initialize + + // get the OpenThread instance that will be used for all operations + mInstance = esp_openthread_get_instance(); + if (!mInstance) { + log_e("Error: Failed to initialize OpenThread instance"); + end(); + return; + } + otStarted = true; } void OpenThread::end() { + if (!otStarted) { + log_w("OpenThread already stopped"); + return; + } + if (s_ot_task != NULL) { vTaskDelete(s_ot_task); s_ot_task = NULL; - // Clean up - esp_openthread_deinit(); - esp_openthread_netif_glue_deinit(); -#if CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM - ot_lwip_netif = NULL; -#endif + } + + // Clean up in reverse order of initialization + if (openthread_netif != NULL) { esp_netif_destroy(openthread_netif); - esp_vfs_eventfd_unregister(); + openthread_netif = NULL; } + + esp_openthread_netif_glue_deinit(); + esp_openthread_deinit(); + esp_vfs_eventfd_unregister(); + +#if CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM + ot_lwip_netif = NULL; +#endif + + mInstance = nullptr; otStarted = false; + log_d("OpenThread ended successfully"); } void OpenThread::start() { @@ -393,9 +430,8 @@ const uint8_t *OpenThread::getNetworkKey() const { log_w("Error: OpenThread instance not initialized"); return nullptr; } - static otNetworkKey networkKey; // Static storage to persist after function return - otThreadGetNetworkKey(mInstance, &networkKey); - return networkKey.m8; + otThreadGetNetworkKey(mInstance, &mNetworkKey); + return mNetworkKey.m8; } // Get the Node Channel @@ -427,41 +463,40 @@ otInstance *OpenThread::getInstance() { // Get the current dataset const DataSet &OpenThread::getCurrentDataSet() const { - static DataSet currentDataset; if (!mInstance) { log_w("Error: OpenThread instance not initialized"); - currentDataset.clear(); - return currentDataset; + mCurrentDataset.clear(); + return mCurrentDataset; } otOperationalDataset dataset; otError error = otDatasetGetActive(mInstance, &dataset); if (error == OT_ERROR_NONE) { - currentDataset.clear(); + mCurrentDataset.clear(); if (dataset.mComponents.mIsNetworkNamePresent) { - currentDataset.setNetworkName(dataset.mNetworkName.m8); + mCurrentDataset.setNetworkName(dataset.mNetworkName.m8); } if (dataset.mComponents.mIsExtendedPanIdPresent) { - currentDataset.setExtendedPanId(dataset.mExtendedPanId.m8); + mCurrentDataset.setExtendedPanId(dataset.mExtendedPanId.m8); } if (dataset.mComponents.mIsNetworkKeyPresent) { - currentDataset.setNetworkKey(dataset.mNetworkKey.m8); + mCurrentDataset.setNetworkKey(dataset.mNetworkKey.m8); } if (dataset.mComponents.mIsChannelPresent) { - currentDataset.setChannel(dataset.mChannel); + mCurrentDataset.setChannel(dataset.mChannel); } if (dataset.mComponents.mIsPanIdPresent) { - currentDataset.setPanId(dataset.mPanId); + mCurrentDataset.setPanId(dataset.mPanId); } } else { log_w("Failed to get active dataset (error: %d)", error); - currentDataset.clear(); + mCurrentDataset.clear(); } - return currentDataset; + return mCurrentDataset; } // Get the Mesh Local Prefix @@ -541,7 +576,7 @@ void OpenThread::populateUnicastAddressCache() const { addr = addr->mNext; } - log_d("Populated unicast address cache with %d addresses", mCachedUnicastAddresses.size()); + log_d("Populated unicast address cache with %zu addresses", mCachedUnicastAddresses.size()); } // Populate multicast address cache from OpenThread @@ -560,7 +595,7 @@ void OpenThread::populateMulticastAddressCache() const { mAddr = mAddr->mNext; } - log_d("Populated multicast address cache with %d addresses", mCachedMulticastAddresses.size()); + log_d("Populated multicast address cache with %zu addresses", mCachedMulticastAddresses.size()); } // Clear unicast address cache diff --git a/libraries/OpenThread/src/OThread.h b/libraries/OpenThread/src/OThread.h index e20b278698e..a67a915908e 100644 --- a/libraries/OpenThread/src/OThread.h +++ b/libraries/OpenThread/src/OThread.h @@ -150,7 +150,8 @@ class OpenThread { private: static otInstance *mInstance; - DataSet mCurrentDataSet; + static DataSet mCurrentDataset; // Current dataset being used by the OpenThread instance. + static otNetworkKey mNetworkKey; // Static storage to persist after function return // Address caching for performance (user-controlled) mutable std::vector mCachedUnicastAddresses; From cc145c769991e05512fc33885d59c2e0c7c50e8f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 12:39:27 +0000 Subject: [PATCH 7/7] ci(pre-commit): Apply automatic fixes --- .../LeaderNode/LeaderNode.ino | 34 ++++----- .../RouterNode/RouterNode.ino | 29 ++++---- libraries/OpenThread/src/OThread.cpp | 70 +++++++++---------- libraries/OpenThread/src/OThread.h | 12 ++-- 4 files changed, 72 insertions(+), 73 deletions(-) diff --git a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino index e612d9728d3..b3c4091e1dc 100644 --- a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino +++ b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/LeaderNode/LeaderNode.ino @@ -32,19 +32,19 @@ void setup() { void loop() { // Get current device role ot_device_role_t currentRole = threadLeaderNode.otGetDeviceRole(); - + // Only print network information when not detached if (currentRole != OT_ROLE_DETACHED && currentRole != OT_ROLE_DISABLED) { Serial.println("=============================================="); Serial.println("OpenThread Network Information:"); - + // Basic network information Serial.printf("Role: %s\r\n", threadLeaderNode.otGetStringDeviceRole()); Serial.printf("RLOC16: 0x%04x\r\n", threadLeaderNode.getRloc16()); Serial.printf("Network Name: %s\r\n", threadLeaderNode.getNetworkName().c_str()); Serial.printf("Channel: %d\r\n", threadLeaderNode.getChannel()); Serial.printf("PAN ID: 0x%04x\r\n", threadLeaderNode.getPanId()); - + // Extended PAN ID const uint8_t *extPanId = threadLeaderNode.getExtendedPanId(); if (extPanId) { @@ -54,7 +54,7 @@ void loop() { } Serial.println(); } - + // Network Key const uint8_t *networkKey = threadLeaderNode.getNetworkKey(); if (networkKey) { @@ -64,19 +64,19 @@ void loop() { } Serial.println(); } - + // Mesh Local EID IPAddress meshLocalEid = threadLeaderNode.getMeshLocalEid(); Serial.printf("Mesh Local EID: %s\r\n", meshLocalEid.toString().c_str()); - + // Leader RLOC IPAddress leaderRloc = threadLeaderNode.getLeaderRloc(); Serial.printf("Leader RLOC: %s\r\n", leaderRloc.toString().c_str()); - + // Node RLOC IPAddress nodeRloc = threadLeaderNode.getRloc(); Serial.printf("Node RLOC: %s\r\n", nodeRloc.toString().c_str()); - + // Demonstrate address listing with two different methods: // Method 1: Unicast addresses using counting API (individual access) Serial.println("\r\n--- Unicast Addresses (Using Count + Index API) ---"); @@ -85,29 +85,29 @@ void loop() { IPAddress addr = threadLeaderNode.getUnicastAddress(i); Serial.printf(" [%zu]: %s\r\n", i, addr.toString().c_str()); } - + // Method 2: Multicast addresses using std::vector (bulk access) Serial.println("\r\n--- Multicast Addresses (Using std::vector API) ---"); std::vector allMulticast = threadLeaderNode.getAllMulticastAddresses(); for (size_t i = 0; i < allMulticast.size(); i++) { Serial.printf(" [%zu]: %s\r\n", i, allMulticast[i].toString().c_str()); } - + // Check for role change and clear cache if needed (only when active) if (currentRole != lastKnownRole) { - Serial.printf("Role changed from %s to %s - clearing address cache\r\n", - (lastKnownRole < 5) ? otRoleString[lastKnownRole] : "Unknown", - threadLeaderNode.otGetStringDeviceRole()); + Serial.printf( + "Role changed from %s to %s - clearing address cache\r\n", (lastKnownRole < 5) ? otRoleString[lastKnownRole] : "Unknown", + threadLeaderNode.otGetStringDeviceRole() + ); threadLeaderNode.clearAllAddressCache(); lastKnownRole = currentRole; } } else { - Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", - threadLeaderNode.otGetStringDeviceRole()); - + Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", threadLeaderNode.otGetStringDeviceRole()); + // Update role tracking even when detached/disabled, but don't clear cache lastKnownRole = currentRole; } - + delay(5000); } diff --git a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino index 4725124bdfc..a8959792f5b 100644 --- a/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino +++ b/libraries/OpenThread/examples/Native/SimpleThreadNetwork/RouterNode/RouterNode.ino @@ -24,23 +24,23 @@ void setup() { void loop() { // Get current device role ot_device_role_t currentRole = threadChildNode.otGetDeviceRole(); - + // Only print detailed network information when node is active if (currentRole != OT_ROLE_DETACHED && currentRole != OT_ROLE_DISABLED) { Serial.println("=============================================="); Serial.println("OpenThread Network Information (Active Dataset):"); - + // Get and display the current active dataset const DataSet &activeDataset = threadChildNode.getCurrentDataSet(); - + Serial.printf("Role: %s\r\n", threadChildNode.otGetStringDeviceRole()); Serial.printf("RLOC16: 0x%04x\r\n", threadChildNode.getRloc16()); - + // Dataset information Serial.printf("Network Name: %s\r\n", activeDataset.getNetworkName()); Serial.printf("Channel: %d\r\n", activeDataset.getChannel()); Serial.printf("PAN ID: 0x%04x\r\n", activeDataset.getPanId()); - + // Extended PAN ID from dataset const uint8_t *extPanId = activeDataset.getExtendedPanId(); if (extPanId) { @@ -50,7 +50,7 @@ void loop() { } Serial.println(); } - + // Network Key from dataset const uint8_t *networkKey = activeDataset.getNetworkKey(); if (networkKey) { @@ -60,26 +60,25 @@ void loop() { } Serial.println(); } - + // Additional runtime information IPAddress meshLocalEid = threadChildNode.getMeshLocalEid(); Serial.printf("Mesh Local EID: %s\r\n", meshLocalEid.toString().c_str()); - + IPAddress nodeRloc = threadChildNode.getRloc(); Serial.printf("Node RLOC: %s\r\n", nodeRloc.toString().c_str()); - + IPAddress leaderRloc = threadChildNode.getLeaderRloc(); Serial.printf("Leader RLOC: %s\r\n", leaderRloc.toString().c_str()); Serial.println(); - - } else { + + } else { Serial.println("=============================================="); - Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", - threadChildNode.otGetStringDeviceRole()); - + Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", threadChildNode.otGetStringDeviceRole()); + Serial.println(); } - + delay(5000); } diff --git a/libraries/OpenThread/src/OThread.cpp b/libraries/OpenThread/src/OThread.cpp index 605fe874165..87b748d104d 100644 --- a/libraries/OpenThread/src/OThread.cpp +++ b/libraries/OpenThread/src/OThread.cpp @@ -204,8 +204,8 @@ otNetworkKey OpenThread::mNetworkKey; OpenThread::OpenThread() { // static initialization (node data and stack starting information) otStarted = false; - mCurrentDataset.clear(); // Initialize the current dataset - memset(&mNetworkKey, 0, sizeof(mNetworkKey)); // Initialize the network key + mCurrentDataset.clear(); // Initialize the current dataset + memset(&mNetworkKey, 0, sizeof(mNetworkKey)); // Initialize the network key mInstance = nullptr; } @@ -237,7 +237,7 @@ void OpenThread::begin(bool OThreadAutoStart) { return; } log_d("OpenThread task created successfully"); - + // starts Thread with default dataset from NVS or from IDF default settings if (OThreadAutoStart) { otOperationalDatasetTlvs dataset; @@ -255,7 +255,7 @@ void OpenThread::begin(bool OThreadAutoStart) { log_i("AUTO start OpenThread done"); } } - + // get the OpenThread instance that will be used for all operations mInstance = esp_openthread_get_instance(); if (!mInstance) { @@ -272,26 +272,26 @@ void OpenThread::end() { log_w("OpenThread already stopped"); return; } - + if (s_ot_task != NULL) { vTaskDelete(s_ot_task); s_ot_task = NULL; } - + // Clean up in reverse order of initialization if (openthread_netif != NULL) { esp_netif_destroy(openthread_netif); openthread_netif = NULL; } - + esp_openthread_netif_glue_deinit(); esp_openthread_deinit(); esp_vfs_eventfd_unregister(); - + #if CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM ot_lwip_netif = NULL; #endif - + mInstance = nullptr; otStarted = false; log_d("OpenThread ended successfully"); @@ -302,7 +302,7 @@ void OpenThread::start() { log_w("Error: OpenThread instance not initialized"); return; } - clearAllAddressCache(); // Clear cache when starting network + clearAllAddressCache(); // Clear cache when starting network otThreadSetEnabled(mInstance, true); log_d("Thread network started"); } @@ -312,7 +312,7 @@ void OpenThread::stop() { log_w("Error: OpenThread instance not initialized"); return; } - clearAllAddressCache(); // Clear cache when stopping network + clearAllAddressCache(); // Clear cache when stopping network otThreadSetEnabled(mInstance, false); log_d("Thread network stopped"); } @@ -327,7 +327,7 @@ void OpenThread::networkInterfaceUp() { if (error != OT_ERROR_NONE) { log_e("Error: Failed to enable Thread interface (error code: %d)\n", error); } - clearAllAddressCache(); // Clear cache when interface comes up + clearAllAddressCache(); // Clear cache when interface comes up log_d("OpenThread Network Interface is up"); } @@ -355,7 +355,7 @@ void OpenThread::commitDataSet(const DataSet &dataset) { log_e("Error: Failed to commit dataset (error code: %d)\n", error); return; } - clearAllAddressCache(); // Clear cache when dataset changes + clearAllAddressCache(); // Clear cache when dataset changes log_d("Dataset committed successfully"); } @@ -410,7 +410,7 @@ String OpenThread::getNetworkName() const { log_w("Error: OpenThread instance not initialized"); return String(); // Return empty String, not nullptr } - const char* networkName = otThreadGetNetworkName(mInstance); + const char *networkName = otThreadGetNetworkName(mInstance); return networkName ? String(networkName) : String(); } @@ -463,19 +463,19 @@ otInstance *OpenThread::getInstance() { // Get the current dataset const DataSet &OpenThread::getCurrentDataSet() const { - + if (!mInstance) { log_w("Error: OpenThread instance not initialized"); mCurrentDataset.clear(); return mCurrentDataset; } - + otOperationalDataset dataset; otError error = otDatasetGetActive(mInstance, &dataset); - + if (error == OT_ERROR_NONE) { mCurrentDataset.clear(); - + if (dataset.mComponents.mIsNetworkNamePresent) { mCurrentDataset.setNetworkName(dataset.mNetworkName.m8); } @@ -495,7 +495,7 @@ const DataSet &OpenThread::getCurrentDataSet() const { log_w("Failed to get active dataset (error: %d)", error); mCurrentDataset.clear(); } - + return mCurrentDataset; } @@ -565,17 +565,17 @@ void OpenThread::populateUnicastAddressCache() const { if (!mInstance) { return; } - + // Clear existing cache mCachedUnicastAddresses.clear(); - + // Populate unicast addresses cache const otNetifAddress *addr = otIp6GetUnicastAddresses(mInstance); while (addr != nullptr) { mCachedUnicastAddresses.push_back(IPAddress(IPv6, addr->mAddress.mFields.m8)); addr = addr->mNext; } - + log_d("Populated unicast address cache with %zu addresses", mCachedUnicastAddresses.size()); } @@ -584,17 +584,17 @@ void OpenThread::populateMulticastAddressCache() const { if (!mInstance) { return; } - + // Clear existing cache mCachedMulticastAddresses.clear(); - + // Populate multicast addresses cache const otNetifMulticastAddress *mAddr = otIp6GetMulticastAddresses(mInstance); while (mAddr != nullptr) { mCachedMulticastAddresses.push_back(IPAddress(IPv6, mAddr->mAddress.mFields.m8)); mAddr = mAddr->mNext; } - + log_d("Populated multicast address cache with %zu addresses", mCachedMulticastAddresses.size()); } @@ -623,7 +623,7 @@ size_t OpenThread::getUnicastAddressCount() const { if (mCachedUnicastAddresses.empty()) { populateUnicastAddressCache(); } - + return mCachedUnicastAddresses.size(); } @@ -633,12 +633,12 @@ IPAddress OpenThread::getUnicastAddress(size_t index) const { if (mCachedUnicastAddresses.empty()) { populateUnicastAddressCache(); } - + if (index >= mCachedUnicastAddresses.size()) { log_w("Unicast address index %zu out of range (max: %zu)", index, mCachedUnicastAddresses.size()); return IPAddress(IPv6); } - + return mCachedUnicastAddresses[index]; } @@ -648,8 +648,8 @@ std::vector OpenThread::getAllUnicastAddresses() const { if (mCachedUnicastAddresses.empty()) { populateUnicastAddressCache(); } - - return mCachedUnicastAddresses; // Return copy of cached vector + + return mCachedUnicastAddresses; // Return copy of cached vector } // Get count of multicast addresses @@ -658,7 +658,7 @@ size_t OpenThread::getMulticastAddressCount() const { if (mCachedMulticastAddresses.empty()) { populateMulticastAddressCache(); } - + return mCachedMulticastAddresses.size(); } @@ -668,12 +668,12 @@ IPAddress OpenThread::getMulticastAddress(size_t index) const { if (mCachedMulticastAddresses.empty()) { populateMulticastAddressCache(); } - + if (index >= mCachedMulticastAddresses.size()) { log_w("Multicast address index %zu out of range (max: %zu)", index, mCachedMulticastAddresses.size()); return IPAddress(IPv6); } - + return mCachedMulticastAddresses[index]; } @@ -683,8 +683,8 @@ std::vector OpenThread::getAllMulticastAddresses() const { if (mCachedMulticastAddresses.empty()) { populateMulticastAddressCache(); } - - return mCachedMulticastAddresses; // Return copy of cached vector + + return mCachedMulticastAddresses; // Return copy of cached vector } OpenThread OThread; diff --git a/libraries/OpenThread/src/OThread.h b/libraries/OpenThread/src/OThread.h index a67a915908e..6e21b854574 100644 --- a/libraries/OpenThread/src/OThread.h +++ b/libraries/OpenThread/src/OThread.h @@ -129,7 +129,7 @@ class OpenThread { IPAddress getLeaderRloc() const; // Get the Node RLOC - IPAddress getRloc() const; + IPAddress getRloc() const; // Get the RLOC16 ID uint16_t getRloc16() const; @@ -138,7 +138,7 @@ class OpenThread { size_t getUnicastAddressCount() const; IPAddress getUnicastAddress(size_t index) const; std::vector getAllUnicastAddresses() const; - + size_t getMulticastAddressCount() const; IPAddress getMulticastAddress(size_t index) const; std::vector getAllMulticastAddresses() const; @@ -150,13 +150,13 @@ class OpenThread { private: static otInstance *mInstance; - static DataSet mCurrentDataset; // Current dataset being used by the OpenThread instance. - static otNetworkKey mNetworkKey; // Static storage to persist after function return - + static DataSet mCurrentDataset; // Current dataset being used by the OpenThread instance. + static otNetworkKey mNetworkKey; // Static storage to persist after function return + // Address caching for performance (user-controlled) mutable std::vector mCachedUnicastAddresses; mutable std::vector mCachedMulticastAddresses; - + // Internal cache management void populateUnicastAddressCache() const; void populateMulticastAddressCache() const;