OpenThread Programmatic Configuration Stays Detached - CLI Works Fine

Environment

  • Hardware: nRF52840 DK (PCA10056 v3.0.3)
  • SDK: NCS 3.2.3
  • Board: nrf52840dk/nrf52840

Problem Summary

OpenThread CLI successfully forms networks and UDP messaging works, but programmatic configuration using otDatasetSetActive() stays in detached state (role 1) and never joins the network.

What Works (CLI)

Using the OpenThread CLI sample (nrf/samples/openthread/cli), this sequence works perfectly:

ot dataset init new
ot dataset channel 26
ot dataset panid 0xabcd
ot dataset networkkey 00112233445566778899aabbccddeeff
ot dataset commit active
ot ifconfig up
ot thread start

Result: Board becomes leader/child, UDP messaging works (ot udp send delivers messages).

What Doesn't Work (Programmatic)

Attempting the same configuration programmatically:

prj.conf:

CONFIG_LOG=y
CONFIG_OPENTHREAD=y
CONFIG_OPENTHREAD_NORDIC_LIBRARY_MASTER=y
CONFIG_NETWORKING=y
CONFIG_NET_IPV6=y
CONFIG_NET_UDP=y
CONFIG_NET_SOCKETS=y
CONFIG_POSIX_API=y
CONFIG_NET_PKT_RX_COUNT=16
CONFIG_NET_PKT_TX_COUNT=16
CONFIG_NET_BUF_RX_COUNT=32
CONFIG_NET_BUF_TX_COUNT=32
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_HEAP_MEM_POOL_SIZE=8192
CONFIG_PM_PARTITION_SIZE_SETTINGS_STORAGE=0x8000

Code:

otInstance *instance = otInstanceInitSingle();
otIp6SetEnabled(instance, true);

otOperationalDataset dataset;
memset(&dataset, 0, sizeof(dataset));

// Network name
const char *networkName = "mesh";
memcpy(dataset.mNetworkName.m8, networkName, strlen(networkName));
dataset.mComponents.mIsNetworkNamePresent = true;

// PAN ID
dataset.mPanId = 43981;  // 0xABCD
dataset.mComponents.mIsPanIdPresent = true;

// Channel
dataset.mChannel = 26;
dataset.mComponents.mIsChannelPresent = true;

// Extended PAN ID
uint8_t extPanId[8] = {0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22};
memcpy(dataset.mExtendedPanId.m8, extPanId, sizeof(extPanId));
dataset.mComponents.mIsExtendedPanIdPresent = true;

// Network Key
uint8_t networkKey[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                          0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
memcpy(dataset.mNetworkKey.m8, networkKey, sizeof(networkKey));
dataset.mComponents.mIsNetworkKeyPresent = true;

otDatasetSetActive(instance, &dataset);
otThreadSetEnabled(instance, true);

// Wait for network with tasklet processing
while (timeout-- > 0) {
    otTaskletsProcess(instance);
    otDeviceRole role = otThreadGetDeviceRole(instance);
    // Role stays at 1 (OT_DEVICE_ROLE_DETACHED) forever
    k_sleep(K_MSEC(1000));
}

Result: otThreadGetDeviceRole() returns 1 (detached) indefinitely. Network never forms.

What I've Tried

  1. White check mark Verified CLI works perfectly (network forms, child table shows connections, UDP messaging works)
  2. White check mark Added CONFIG_OPENTHREAD_NORDIC_LIBRARY_MASTER=y (same as CLI sample)
  3. White check mark Called otTaskletsProcess() regularly in main loop
  4. White check mark Tested in NCS 3.0.0, 3.2.1, and 3.2.3 (same issue in all)
  5. White check mark Tried both otInstanceInitSingle() and openthread_get_default_context()
  6. White check mark Set all dataset components (network name, PAN ID, channel, extended PAN ID, network key)
  7. White check mark Called otIp6SetEnabled() before dataset configuration

Questions

  1. What is the CLI doing differently that makes network formation succeed?
  2. Is there a missing initialization step or configuration option for programmatic setup?
  3. Are there additional dataset components required beyond what's shown above?
  4. Is there a working example of programmatic OpenThread network formation (without CLI) in NCS 3.2.3?

The CLI works perfectly but I need automatic network formation without manual CLI commands. What am I missing?

Additional Context

  • RX works (verified with CLI ping tests)
  • TX works (verified with CLI UDP tests)
  • Hardware is functioning correctly
  • Only the programmatic dataset configuration fails to form networks
Parents Reply Children
Related