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
Verified CLI works perfectly (network forms, child table shows connections, UDP messaging works)
Added
CONFIG_OPENTHREAD_NORDIC_LIBRARY_MASTER=y(same as CLI sample)Called
otTaskletsProcess()regularly in main loopTested in NCS 3.0.0, 3.2.1, and 3.2.3 (same issue in all)
Tried both
otInstanceInitSingle()andopenthread_get_default_context()Set all dataset components (network name, PAN ID, channel, extended PAN ID, network key)
Called
otIp6SetEnabled()before dataset configuration
Questions
- What is the CLI doing differently that makes network formation succeed?
- Is there a missing initialization step or configuration option for programmatic setup?
- Are there additional dataset components required beyond what's shown above?
- 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