feat(openthread): native API extension (#11598)
* feat(openthread): native API extension * fix(openthread): wrong return type and parameter * fix(openthread): wrong field reference * fix(openthread): CR/LF fix * feat(openthread): print leader RLOC information * feat(openthread): code improvements * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
parent
82d56bc679
commit
6015fd73e0
5 changed files with 566 additions and 26 deletions
|
|
@ -3,6 +3,9 @@
|
||||||
OpenThread threadLeaderNode;
|
OpenThread threadLeaderNode;
|
||||||
DataSet dataset;
|
DataSet dataset;
|
||||||
|
|
||||||
|
// Track last known device role for state change detection
|
||||||
|
ot_device_role_t lastKnownRole = OT_ROLE_DISABLED;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
|
@ -27,8 +30,84 @@ void setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// Print network information every 5 seconds
|
// 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("==============================================");
|
||||||
threadLeaderNode.otPrintNetworkInformation(Serial);
|
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) {
|
||||||
|
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\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) ---");
|
||||||
|
size_t unicastCount = threadLeaderNode.getUnicastAddressCount();
|
||||||
|
for (size_t i = 0; i < unicastCount; i++) {
|
||||||
|
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<IPAddress> 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()
|
||||||
|
);
|
||||||
|
threadLeaderNode.clearAllAddressCache();
|
||||||
|
lastKnownRole = currentRole;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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);
|
delay(5000);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,63 @@ void setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// Print network information every 5 seconds
|
// 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("==============================================");
|
||||||
threadChildNode.otPrintNetworkInformation(Serial);
|
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) {
|
||||||
|
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\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 {
|
||||||
|
Serial.println("==============================================");
|
||||||
|
Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", threadChildNode.otGetStringDeviceRole());
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
delay(5000);
|
delay(5000);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ OpenThread KEYWORD1
|
||||||
DataSet KEYWORD1
|
DataSet KEYWORD1
|
||||||
ot_cmd_return_t KEYWORD1
|
ot_cmd_return_t KEYWORD1
|
||||||
ot_device_role_t KEYWORD1
|
ot_device_role_t KEYWORD1
|
||||||
|
OnReceiveCb_t KEYWORD1
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
|
|
@ -59,6 +60,23 @@ stop KEYWORD2
|
||||||
networkInterfaceUp KEYWORD2
|
networkInterfaceUp KEYWORD2
|
||||||
networkInterfaceDown KEYWORD2
|
networkInterfaceDown KEYWORD2
|
||||||
commitDataSet 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)
|
# Constants (LITERAL1)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#if SOC_IEEE802154_SUPPORTED
|
#if SOC_IEEE802154_SUPPORTED
|
||||||
#if CONFIG_OPENTHREAD_ENABLED
|
#if CONFIG_OPENTHREAD_ENABLED
|
||||||
|
|
||||||
|
#include "IPAddress.h"
|
||||||
|
#include <vector>
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
|
|
@ -132,16 +134,29 @@ const otOperationalDataset &DataSet::getDataset() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataSet::setNetworkName(const char *name) {
|
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;
|
mDataset.mComponents.mIsNetworkNamePresent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataSet::setExtendedPanId(const uint8_t *extPanId) {
|
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);
|
memcpy(mDataset.mExtendedPanId.m8, extPanId, OT_EXT_PAN_ID_SIZE);
|
||||||
mDataset.mComponents.mIsExtendedPanIdPresent = true;
|
mDataset.mComponents.mIsExtendedPanIdPresent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataSet::setNetworkKey(const uint8_t *key) {
|
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);
|
memcpy(mDataset.mNetworkKey.m8, key, OT_NETWORK_KEY_SIZE);
|
||||||
mDataset.mComponents.mIsNetworkKeyPresent = true;
|
mDataset.mComponents.mIsNetworkKeyPresent = true;
|
||||||
}
|
}
|
||||||
|
|
@ -181,10 +196,18 @@ void DataSet::apply(otInstance *instance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenThread Implementation
|
// 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() {
|
OpenThread::~OpenThread() {
|
||||||
end();
|
end();
|
||||||
|
|
@ -214,13 +237,7 @@ void OpenThread::begin(bool OThreadAutoStart) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log_d("OpenThread task created successfully");
|
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
|
// starts Thread with default dataset from NVS or from IDF default settings
|
||||||
if (OThreadAutoStart) {
|
if (OThreadAutoStart) {
|
||||||
otOperationalDatasetTlvs dataset;
|
otOperationalDatasetTlvs dataset;
|
||||||
|
|
@ -238,23 +255,46 @@ void OpenThread::begin(bool OThreadAutoStart) {
|
||||||
log_i("AUTO start OpenThread done");
|
log_i("AUTO start OpenThread done");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
otStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenThread::end() {
|
void OpenThread::end() {
|
||||||
|
if (!otStarted) {
|
||||||
|
log_w("OpenThread already stopped");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (s_ot_task != NULL) {
|
if (s_ot_task != NULL) {
|
||||||
vTaskDelete(s_ot_task);
|
vTaskDelete(s_ot_task);
|
||||||
s_ot_task = NULL;
|
s_ot_task = NULL;
|
||||||
// Clean up
|
}
|
||||||
esp_openthread_deinit();
|
|
||||||
|
// 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_netif_glue_deinit();
|
||||||
|
esp_openthread_deinit();
|
||||||
|
esp_vfs_eventfd_unregister();
|
||||||
|
|
||||||
#if CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM
|
#if CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM
|
||||||
ot_lwip_netif = NULL;
|
ot_lwip_netif = NULL;
|
||||||
#endif
|
#endif
|
||||||
esp_netif_destroy(openthread_netif);
|
|
||||||
esp_vfs_eventfd_unregister();
|
mInstance = nullptr;
|
||||||
}
|
|
||||||
otStarted = false;
|
otStarted = false;
|
||||||
|
log_d("OpenThread ended successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenThread::start() {
|
void OpenThread::start() {
|
||||||
|
|
@ -262,6 +302,7 @@ void OpenThread::start() {
|
||||||
log_w("Error: OpenThread instance not initialized");
|
log_w("Error: OpenThread instance not initialized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
clearAllAddressCache(); // Clear cache when starting network
|
||||||
otThreadSetEnabled(mInstance, true);
|
otThreadSetEnabled(mInstance, true);
|
||||||
log_d("Thread network started");
|
log_d("Thread network started");
|
||||||
}
|
}
|
||||||
|
|
@ -271,6 +312,7 @@ void OpenThread::stop() {
|
||||||
log_w("Error: OpenThread instance not initialized");
|
log_w("Error: OpenThread instance not initialized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
clearAllAddressCache(); // Clear cache when stopping network
|
||||||
otThreadSetEnabled(mInstance, false);
|
otThreadSetEnabled(mInstance, false);
|
||||||
log_d("Thread network stopped");
|
log_d("Thread network stopped");
|
||||||
}
|
}
|
||||||
|
|
@ -285,6 +327,7 @@ void OpenThread::networkInterfaceUp() {
|
||||||
if (error != OT_ERROR_NONE) {
|
if (error != OT_ERROR_NONE) {
|
||||||
log_e("Error: Failed to enable Thread interface (error code: %d)\n", error);
|
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");
|
log_d("OpenThread Network Interface is up");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,6 +355,7 @@ void OpenThread::commitDataSet(const DataSet &dataset) {
|
||||||
log_e("Error: Failed to commit dataset (error code: %d)\n", error);
|
log_e("Error: Failed to commit dataset (error code: %d)\n", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
clearAllAddressCache(); // Clear cache when dataset changes
|
||||||
log_d("Dataset committed successfully");
|
log_d("Dataset committed successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -360,6 +404,289 @@ void OpenThread::otPrintNetworkInformation(Stream &output) {
|
||||||
output.println();
|
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;
|
||||||
|
}
|
||||||
|
otThreadGetNetworkKey(mInstance, &mNetworkKey);
|
||||||
|
return mNetworkKey.m8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (dataset.mComponents.mIsExtendedPanIdPresent) {
|
||||||
|
mCurrentDataset.setExtendedPanId(dataset.mExtendedPanId.m8);
|
||||||
|
}
|
||||||
|
if (dataset.mComponents.mIsNetworkKeyPresent) {
|
||||||
|
mCurrentDataset.setNetworkKey(dataset.mNetworkKey.m8);
|
||||||
|
}
|
||||||
|
if (dataset.mComponents.mIsChannelPresent) {
|
||||||
|
mCurrentDataset.setChannel(dataset.mChannel);
|
||||||
|
}
|
||||||
|
if (dataset.mComponents.mIsPanIdPresent) {
|
||||||
|
mCurrentDataset.setPanId(dataset.mPanId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_w("Failed to get active dataset (error: %d)", error);
|
||||||
|
mCurrentDataset.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mCurrentDataset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
otIp6Address otAddr;
|
||||||
|
otError error = otThreadGetLeaderRloc(mInstance, &otAddr);
|
||||||
|
if (error != OT_ERROR_NONE) {
|
||||||
|
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 %zu 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 %zu 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<IPAddress> 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<IPAddress> OpenThread::getAllMulticastAddresses() const {
|
||||||
|
// Populate cache if empty
|
||||||
|
if (mCachedMulticastAddresses.empty()) {
|
||||||
|
populateMulticastAddressCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mCachedMulticastAddresses; // Return copy of cached vector
|
||||||
|
}
|
||||||
|
|
||||||
OpenThread OThread;
|
OpenThread OThread;
|
||||||
|
|
||||||
#endif /* CONFIG_OPENTHREAD_ENABLED */
|
#endif /* CONFIG_OPENTHREAD_ENABLED */
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
#include <openthread/dataset_ftd.h>
|
#include <openthread/dataset_ftd.h>
|
||||||
#include <esp_openthread.h>
|
#include <esp_openthread.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include "IPAddress.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OT_ROLE_DISABLED = 0, ///< The Thread stack is disabled.
|
OT_ROLE_DISABLED = 0, ///< The Thread stack is disabled.
|
||||||
|
|
@ -96,9 +98,68 @@ public:
|
||||||
// Set the dataset
|
// Set the dataset
|
||||||
void commitDataSet(const DataSet &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<IPAddress> getAllUnicastAddresses() const;
|
||||||
|
|
||||||
|
size_t getMulticastAddressCount() const;
|
||||||
|
IPAddress getMulticastAddress(size_t index) const;
|
||||||
|
std::vector<IPAddress> getAllMulticastAddresses() const;
|
||||||
|
|
||||||
|
// Cache management
|
||||||
|
void clearUnicastAddressCache() const;
|
||||||
|
void clearMulticastAddressCache() const;
|
||||||
|
void clearAllAddressCache() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static otInstance *mInstance;
|
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<IPAddress> mCachedUnicastAddresses;
|
||||||
|
mutable std::vector<IPAddress> mCachedMulticastAddresses;
|
||||||
|
|
||||||
|
// Internal cache management
|
||||||
|
void populateUnicastAddressCache() const;
|
||||||
|
void populateMulticastAddressCache() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern OpenThread OThread;
|
extern OpenThread OThread;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue