Skip to content

Commit dfc914e

Browse files
committed
net: openthread: rpc: support setting IEEE EUI64
Add RPC command that sets IEEE EUI64 on the remote device. Only nRF54LX devices are supported for now, on which EUI64 is written to UICR->OTP. Signed-off-by: Damian Krolik <[email protected]>
1 parent 9570e65 commit dfc914e

File tree

7 files changed

+164
-5
lines changed

7 files changed

+164
-5
lines changed

include/net/ot_rpc.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#ifndef OT_RPC_H_
8+
#define OT_RPC_H_
9+
10+
#include <openthread/link.h>
11+
12+
/**
13+
* @file
14+
* @defgroup ot_rpc OpenThread over RPC API additions
15+
* @{
16+
* @brief API additions for OpenThread over RPC.
17+
*/
18+
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
22+
23+
/** @brief Set factory assigned IEEE EUI64 on the remote device.
24+
*
25+
* The function issues an nRF RPC command that configures the factory-assigned IEEE EUI64,
26+
* which can then be retrieved using the @c otLinkGetFactoryAssignedIeeeEui64 API.
27+
*
28+
* @param eui64 IEEE EUI64 identifier.
29+
*
30+
* @retval OT_ERROR_NONE IEEE EUI64 saved successfully.
31+
* @retval OT_ERROR_NOT_CAPABLE Setting IEEE EUI64 unsupported by the remote device.
32+
* @retval OT_ERROR_FAILED Failed to save IEEE EUI64.
33+
*/
34+
otError ot_rpc_set_factory_assigned_ieee_eui64(const otExtAddress * eui64);
35+
36+
#ifdef __cplusplus
37+
}
38+
#endif
39+
40+
/**
41+
* @}
42+
*/
43+
44+
#endif /* OT_RPC_H_ */

samples/nrf_rpc/protocols_serialization/client/src/ot_shell.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include "ot_shell.h"
8+
#include <net/ot_rpc.h>
89

910
#include <zephyr/shell/shell.h>
1011
#include <zephyr/net/net_ip.h>
@@ -1978,6 +1979,33 @@ static int cmd_dns_client_browse(const struct shell *sh, size_t argc, char *argv
19781979
return 0;
19791980
}
19801981

1982+
static otError ot_cli_command_eui64(const struct shell *sh, size_t argc, char *argv[])
1983+
{
1984+
otExtAddress ext_addr;
1985+
1986+
if (argc == 1) {
1987+
/* Read current EUI64 */
1988+
otLinkGetFactoryAssignedIeeeEui64(NULL, &ext_addr);
1989+
shell_print(sh, "%02x%02x%02x%02x%02x%02x%02x%02x", ext_addr.m8[0], ext_addr.m8[1],
1990+
ext_addr.m8[2], ext_addr.m8[3], ext_addr.m8[4], ext_addr.m8[5],
1991+
ext_addr.m8[6], ext_addr.m8[7]);
1992+
return OT_ERROR_NONE;
1993+
}
1994+
1995+
/* Set new EUI64 */
1996+
if (hex2bin(argv[1], strlen(argv[1]), ext_addr.m8, sizeof(ext_addr.m8)) !=
1997+
sizeof(ext_addr.m8)) {
1998+
return OT_ERROR_INVALID_ARGS;
1999+
}
2000+
2001+
return ot_rpc_set_factory_assigned_ieee_eui64(&ext_addr);
2002+
}
2003+
2004+
static int cmd_eui64(const struct shell *sh, size_t argc, char *argv[])
2005+
{
2006+
return ot_cli_command_invoke(ot_cli_command_eui64, sh, argc, argv);
2007+
}
2008+
19812009
SHELL_STATIC_SUBCMD_SET_CREATE(
19822010
ot_cmds, SHELL_CMD_ARG(ifconfig, NULL, "Interface management", cmd_ifconfig, 1, 1),
19832011
SHELL_CMD_ARG(ipmaddr, NULL, "IPv6 multicast configuration", cmd_ipmaddr, 1, 2),
@@ -1987,6 +2015,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
19872015
SHELL_CMD_ARG(thread, NULL, "Role management", cmd_thread, 2, 0),
19882016
SHELL_CMD_ARG(discover, NULL, "Thread discovery scan", cmd_discover, 1, 4),
19892017
SHELL_CMD_ARG(radio, NULL, "Radio configuration", cmd_radio, 1, 1),
2018+
SHELL_CMD_ARG(eui64, NULL, "EUI64 configuration", cmd_eui64, 1, 1),
19902019
SHELL_CMD_ARG(test_message, NULL, "Test message API", cmd_test_message, 1, 0),
19912020
SHELL_CMD_ARG(test_udp_init, NULL, "Test udp init API", cmd_test_udp_init, 1, 0),
19922021
SHELL_CMD_ARG(test_udp_send, NULL, "Test udp send API", cmd_test_udp_send, 1, 0),
@@ -2067,8 +2096,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
20672096
"Network diag, args: <get|reset> <IPv6-address>"
20682097
" <tlv-type ...>",
20692098
cmd_test_net_diag, 4, 255),
2070-
SHELL_CMD_ARG(test_mesh_diag, NULL, "Mesh diag topology discovery, args: <start|cancel>"
2071-
"[ip6] [children]",
2099+
SHELL_CMD_ARG(test_mesh_diag, NULL,
2100+
"Mesh diag topology discovery, args: <start|cancel>"
2101+
"[ip6] [children]",
20722102
cmd_test_mesh_diag, 2, 2),
20732103
SHELL_SUBCMD_SET_END);
20742104

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#
2+
# Copyright (c) 2024 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
CONFIG_IEEE802154_NRF5_UICR_EUI64_ENABLE=y

samples/nrf_rpc/protocols_serialization/server/snippets/openthread/snippet.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ boards:
1212
nrf54l15dk/nrf54l15/cpuapp:
1313
append:
1414
EXTRA_DTC_OVERLAY_FILE: boards/nrf54l15dk_nrf54l15_cpuapp.overlay
15+
EXTRA_CONF_FILE: boards/nrf54l15dk_nrf54l15_cpuapp.conf
1516
nrf52840dk/nrf52840:
1617
append:
1718
EXTRA_DTC_OVERLAY_FILE: boards/nrf52840dk_nrf52840.overlay

subsys/net/openthread/rpc/client/ot_rpc_link.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,24 @@ void otLinkGetFactoryAssignedIeeeEui64(otInstance *aInstance, otExtAddress *aEui
9797

9898
ARG_UNUSED(aInstance);
9999

100-
if (aEui64 == NULL) {
101-
return;
102-
}
100+
__ASSERT_NO_MSG(aEui64 != NULL);
103101

104102
NRF_RPC_CBOR_ALLOC(&ot_group, ctx, 0);
105103
nrf_rpc_cbor_cmd_no_err(&ot_group, OT_RPC_CMD_LINK_GET_FACTORY_ASSIGNED_EUI64, &ctx,
106104
ot_rpc_decode_eui64, aEui64->m8);
107105
}
106+
107+
otError ot_rpc_set_factory_assigned_ieee_eui64(const otExtAddress *eui64)
108+
{
109+
struct nrf_rpc_cbor_ctx ctx;
110+
otError error;
111+
112+
__ASSERT_NO_MSG(eui64 != NULL);
113+
114+
NRF_RPC_CBOR_ALLOC(&ot_group, ctx, 1 + OT_EXT_ADDRESS_SIZE);
115+
nrf_rpc_encode_buffer(&ctx, &eui64->m8, OT_EXT_ADDRESS_SIZE);
116+
nrf_rpc_cbor_cmd_no_err(&ot_group, OT_RPC_CMD_LINK_SET_FACTORY_ASSIGNED_EUI64, &ctx,
117+
ot_rpc_decode_error, &error);
118+
119+
return error;
120+
}

subsys/net/openthread/rpc/common/ot_rpc_ids.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ enum ot_rpc_cmd_server {
170170
OT_RPC_CMD_DNS_SERVICE_RESP_GET_SERVICE_INFO,
171171
OT_RPC_CMD_DNS_SERVICE_RESP_GET_HOST_ADDRESS,
172172
OT_RPC_CMD_LINK_RAW_GET_RADIO_TIME,
173+
174+
/* OpenThread over RPC API additions */
175+
OT_RPC_CMD_LINK_SET_FACTORY_ASSIGNED_EUI64,
173176
};
174177

175178
#endif /* OT_RPC_IDS_H_ */

subsys/net/openthread/rpc/server/ot_rpc_link.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,18 @@
1212

1313
#include <nrf_rpc_cbor.h>
1414

15+
#include <zephyr/net/net_if.h>
1516
#include <zephyr/net/openthread.h>
17+
#include <zephyr/sys/byteorder.h>
1618

1719
#include <openthread/link.h>
1820

21+
#ifdef CONFIG_IEEE802154_NRF5_UICR_EUI64_ENABLE
22+
#ifdef CONFIG_NRFX_RRAMC
23+
#include <nrfx_rramc.h>
24+
#endif
25+
#endif
26+
1927
static void ot_rpc_cmd_set_poll_period(const struct nrf_rpc_group *group,
2028
struct nrf_rpc_cbor_ctx *ctx, void *handler_data)
2129
{
@@ -123,6 +131,55 @@ static void ot_rpc_cmd_get_factory_assigned_eui64(const struct nrf_rpc_group *gr
123131
nrf_rpc_cbor_rsp_no_err(group, &rsp_ctx);
124132
}
125133

134+
static void ot_rpc_cmd_set_factory_assigned_eui64(const struct nrf_rpc_group *group,
135+
struct nrf_rpc_cbor_ctx *ctx, void *handler_data)
136+
{
137+
otError error = OT_ERROR_NOT_CAPABLE;
138+
otExtAddress ext_addr;
139+
140+
nrf_rpc_decode_buffer(ctx, ext_addr.m8, OT_EXT_ADDRESS_SIZE);
141+
142+
if (!nrf_rpc_decoding_done_and_check(group, ctx)) {
143+
ot_rpc_report_cmd_decoding_error(OT_RPC_CMD_LINK_SET_FACTORY_ASSIGNED_EUI64);
144+
return;
145+
}
146+
147+
#ifdef CONFIG_IEEE802154_NRF5_UICR_EUI64_ENABLE
148+
#ifdef CONFIG_NRFX_RRAMC
149+
if (nrfx_rramc_otp_word_write(CONFIG_IEEE802154_NRF5_UICR_EUI64_REG + 1,
150+
sys_get_le32(ext_addr.m8)) &&
151+
nrfx_rramc_otp_word_write(CONFIG_IEEE802154_NRF5_UICR_EUI64_REG,
152+
sys_get_le32(ext_addr.m8 + 4))) {
153+
error = OT_ERROR_NONE;
154+
} else {
155+
error = OT_ERROR_FAILED;
156+
}
157+
#endif
158+
#endif
159+
160+
/*
161+
* The IEEE EUI64 is only copied from UICR to the network interface once, during
162+
* the network interface initialization, so the network interface must also be
163+
* updated after writing the new identifier to UICR.
164+
*/
165+
if (IS_ENABLED(CONFIG_NET_L2_OPENTHREAD) && error == OT_ERROR_NONE) {
166+
struct net_if *iface = net_if_get_first_by_type(&NET_L2_GET_NAME(OPENTHREAD));
167+
struct net_linkaddr *addr;
168+
169+
__ASSERT_NO_MSG(iface != NULL);
170+
171+
net_if_lock(iface);
172+
addr = net_if_get_link_addr(iface);
173+
174+
__ASSERT_NO_MSG(addr != NULL && addr->len == OT_EXT_ADDRESS_SIZE);
175+
176+
memcpy(addr->addr, ext_addr.m8, OT_EXT_ADDRESS_SIZE);
177+
net_if_unlock(iface);
178+
}
179+
180+
nrf_rpc_rsp_send_uint(group, error);
181+
}
182+
126183
NRF_RPC_CBOR_CMD_DECODER(ot_group, ot_rpc_cmd_set_poll_period, OT_RPC_CMD_LINK_SET_POLL_PERIOD,
127184
ot_rpc_cmd_set_poll_period, NULL);
128185

@@ -143,3 +200,7 @@ NRF_RPC_CBOR_CMD_DECODER(ot_group, ot_rpc_cmd_set_link_enabled, OT_RPC_CMD_LINK_
143200
NRF_RPC_CBOR_CMD_DECODER(ot_group, ot_rpc_cmd_get_factory_assigned_eui64,
144201
OT_RPC_CMD_LINK_GET_FACTORY_ASSIGNED_EUI64,
145202
ot_rpc_cmd_get_factory_assigned_eui64, NULL);
203+
204+
NRF_RPC_CBOR_CMD_DECODER(ot_group, ot_rpc_cmd_set_factory_assigned_eui64,
205+
OT_RPC_CMD_LINK_SET_FACTORY_ASSIGNED_EUI64,
206+
ot_rpc_cmd_set_factory_assigned_eui64, NULL);

0 commit comments

Comments
 (0)