diff --git a/docs/architectures.rst b/docs/architectures.rst
index e8f53533..2f58ccfd 100644
--- a/docs/architectures.rst
+++ b/docs/architectures.rst
@@ -18,6 +18,7 @@ System-on-Chip designs
The single-chip solution has a combined RFIC (the IEEE 802.15.4 in case of Zigbee) and processor.
Both the Zigbee stack and the application layer run on the local processor.
+The ZBOSS stack communicates directly with the nRF 802.15.4 radio driver, bypassing the Zephyr networking (L2) layer.
This design has the following advantages:
diff --git a/docs/configuring.rst b/docs/configuring.rst
index 3b4210e3..6d40f72d 100644
--- a/docs/configuring.rst
+++ b/docs/configuring.rst
@@ -95,24 +95,72 @@ You can enable one of the following alternative options to select the channel on
IEEE 802.15.4 EUI-64 configuration
==================================
-The Zigbee stack uses the EUI-64 address that is configured in the IEEE 802.15.4 shim layer.
-By default, it uses an address from Nordic Semiconductor's pool.
+An IEEE EUI-64 address consists of two parts:
-If your devices should use a different address, you can change the address according to your company's addressing scheme.
+* Company ID, which is a 24-bit MAC Address Block Large (MA-L), formerly called Organizationally Unique Identifier (OUI).
+* Extension identifier, which is a 40-bit device unique identifier.
-.. include:: includes/ieee802154_eui64_conf_nrf54l.txt
+You can configure the EUI-64 for a Zigbee device in the following ways:
+
+.. tabs::
+
+ .. tab:: Use the default
+
+ By default, the company ID is set to Nordic Semiconductor's MA-L (``f4-ce-36``) through the ``CONFIG_ZIGBEE_VENDOR_OUI`` Kconfig option.
+ The extension identifier is set to the DEVICEID from the factory information configuration registers (FICR).
+
+ .. tab:: Replace the company ID
+
+ Change the ``CONFIG_ZIGBEE_VENDOR_OUI`` Kconfig option to your company's MA-L value (24-bit, in hex).
+ The extension identifier remains the DEVICEID from FICR.
+
+ .. tab:: Replace the full EUI-64
+
+ You can provide the full EUI-64 value by programming certain user information configuration registers (UICR).
+ The nRF52 and nRF53 Series devices use the CUSTOMER registers block, while the nRF53 (application core) and nRF54L Series use the OTP registers block.
+
+ To use the EUI-64 value from the UICR you must enable the ``CONFIG_ZIGBEE_UICR_EUI64_ENABLE`` Kconfig option.
+ Then, you need to the ``CONFIG_ZIGBEE_UICR_EUI64_REG`` to the base index of the two consecutive UICR registers that will contain your EUI-64 value.
+
+ The following example shows how to replace the full EUI-64 on the nRF52840 device:
+
+ 1. Enable the ``CONFIG_ZIGBEE_UICR_EUI64_ENABLE`` Kconfig option.
+
+ #. Set ``CONFIG_ZIGBEE_UICR_EUI64_REG`` to the UICR offset.
+ For UICR->CUSTOMER[0] and UICR->CUSTOMER[1], use the default value ``0``.
+
+ #. Build and program your application, erasing the whole memory.
+ Replace *serial_number* with the serial number of your debugger:
+
+ .. parsed-literal::
+ :class: highlight
+
+ west build -b nrf52840dk/nrf52840 -p always
+ west flash --snr *serial_number* --erase
+
+ #. Program the two consecutive UICR registers with your EUI-64 value (replace *serial_number* with the serial number of your debugger).
+ For nRF52840 device with default ``CONFIG_ZIGBEE_UICR_EUI64_REG`` (0), the CUSTOMER base address is ``0x10001080``:
+
+ .. parsed-literal::
+ :class: highlight
+
+ nrfutil device x-write --serial-number *serial_number* --address 0x10001080 --value 0x11223344
+ nrfutil device x-write --serial-number *serial_number* --address 0x10001084 --value 0x55667788
+ nrfutil device reset --reset-kind=RESET_PIN
+
+ If you set ``CONFIG_ZIGBEE_UICR_EUI64_REG`` to a different value, use the corresponding register addresses for your SoC.
At the end of the configuration process, you can check the EUI-64 value using :ref:`lib_zigbee_shell`:
.. code-block:: console
- > zdo eui64
+ uart:~$ zdo eui64
8877665544332211
Done
.. note::
Alternatively, you may use the Production Configuration feature to change the address.
- The Production Configuration takes precedence over the shim's configuration.
+ The Production Configuration takes precedence over the OSIF configuration.
ZBOSS stack start options
=========================
diff --git a/docs/images/zigbee_platform_design_multi.svg b/docs/images/zigbee_platform_design_multi.svg
index dcd3ec01..5f811f9c 100644
--- a/docs/images/zigbee_platform_design_multi.svg
+++ b/docs/images/zigbee_platform_design_multi.svg
@@ -76,18 +76,8 @@
Dynamic connector
-
+
Sheet.96
-
- Sheet.67
- Secure boot
-
- Sheet.68
-
-
-
- Zephyr integration
-
Sheet.95
diff --git a/docs/images/zigbee_platform_design_nRF53.svg b/docs/images/zigbee_platform_design_nRF53.svg
index 86ed11f5..e380fdb0 100644
--- a/docs/images/zigbee_platform_design_nRF53.svg
+++ b/docs/images/zigbee_platform_design_nRF53.svg
@@ -62,16 +62,6 @@
Sheet.107
-
- Sheet.110
- Secure boot
-
- Sheet.111
-
-
-
- Zephyr integration
-
Sheet.112
@@ -91,26 +81,26 @@
nRF53 network core
nRF53 network core
-
+
Sheet.116
-
+
Sheet.117
nRF IEEE 802.15.4 radio driver
nRF IEEE 802.15.4 radio driver
-
+
Sheet.118
IEEE 802.15.4 PHY
IEEE 802.15.4 PHY
-
+
Sheet.120
nRF IEEE 802.15.4 radio driver
nRF IEEE 802.15.4 radio driver
-
+
Dynamic connector.121
diff --git a/docs/images/zigbee_platform_design_nRF5340_multi.svg b/docs/images/zigbee_platform_design_nRF5340_multi.svg
index 9b7bd66a..35d5a4bf 100644
--- a/docs/images/zigbee_platform_design_nRF5340_multi.svg
+++ b/docs/images/zigbee_platform_design_nRF5340_multi.svg
@@ -104,40 +104,30 @@
SM
SM
-
- Sheet.118
- Secure boot
-
- Sheet.119
-
-
-
- Zephyr integration
-
-
+
Sheet.120
nRF IEEE 802.15.4 radio driver
nRF IEEE 802.15.4 radio driver
-
+
Sheet.122
IEEE 802.15.4 MAC
IEEE 802.15.4 MAC
-
+
Sheet.124
-
+
Sheet.125
Zigbee app layer (ZCL)
Zigbee app layer (ZCL)
-
+
Sheet.126
-
+
Sheet.127
Zigbee PRO + Green Power
@@ -167,7 +157,7 @@
Dynamic connector
-
+
Dynamic connector.206
diff --git a/docs/images/zigbee_platform_design_ncp.svg b/docs/images/zigbee_platform_design_ncp.svg
index a1b91d92..81057ced 100644
--- a/docs/images/zigbee_platform_design_ncp.svg
+++ b/docs/images/zigbee_platform_design_ncp.svg
@@ -107,16 +107,6 @@
Multiprotocol Service Layer (MPSL)
-
- Sheet.156
- Secure boot
-
- Sheet.157
-
-
-
- Zephyr integration
-
Sheet.159
@@ -171,7 +161,7 @@
Zigbee Device Object (ZDO)
-
+
Sheet.184
Sheet.150
diff --git a/docs/images/zigbee_platform_design_soc.svg b/docs/images/zigbee_platform_design_soc.svg
index 41367db1..e9f7558d 100644
--- a/docs/images/zigbee_platform_design_soc.svg
+++ b/docs/images/zigbee_platform_design_soc.svg
@@ -74,16 +74,16 @@
Zigbee PRO + Green Power
Zigbee PRO + Green Power
-
+
Sheet.156
-
+
Sheet.157
nRF IEEE 802.15.4 radio driver
nRF IEEE 802.15.4 radio driver
-
+
Sheet.158
IEEE 802.15.4 PHY
@@ -98,15 +98,5 @@
Multiprotocol Service Layer (MPSL)
-
- Sheet.162
- Secure boot
-
- Sheet.163
-
-
-
- Zephyr integration
-
diff --git a/docs/lib/osif.rst b/docs/lib/osif.rst
index c73f297c..f6456f51 100644
--- a/docs/lib/osif.rst
+++ b/docs/lib/osif.rst
@@ -1,4 +1,4 @@
-.. _lib_zigbee_osif:
+.. _lib_zigbee_osif:
Zigbee ZBOSS OSIF
#################
@@ -50,6 +50,10 @@ You can also configure the following OSIF-related Kconfig options:
This option is used only if the device does not have NVRAM storage.
* ``CONFIG_ZIGBEE_TIME_COUNTER`` - Configures the ZBOSS OSIF layer to use a dedicated timer-based counter as the Zigbee time source.
* ``CONFIG_ZIGBEE_TIME_KTIMER`` - Configures the ZBOSS OSIF layer to use Zephyr's system time as the Zigbee time source.
+* ``CONFIG_ZBOSS_RADIO_INIT_PRIORITY`` - Initialization priority for the nRF 802.15.4 radio driver.
+ Must be lower than ``CONFIG_ZBOSS_INIT_PRIORITY`` so the radio is ready before ZBOSS starts.
+* ``CONFIG_ZBOSS_INIT_PRIORITY`` - Initialization priority for the ZBOSS stack.
+ Must be higher than ``CONFIG_ZBOSS_RADIO_INIT_PRIORITY``.
Additionally, the following Kconfig option is available when setting :ref:`zigbee_ug_logging_logger_options`:
diff --git a/samples/light_bulb/prj.conf b/samples/light_bulb/prj.conf
index fc321a44..6256a508 100644
--- a/samples/light_bulb/prj.conf
+++ b/samples/light_bulb/prj.conf
@@ -28,10 +28,5 @@ CONFIG_DK_LIBRARY=y
# This example requires more workqueue stack
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
-# Networking
-CONFIG_NET_IPV6=n
-CONFIG_NET_IP_ADDR_CHECK=n
-CONFIG_NET_UDP=n
-
# Scene extension
CONFIG_ZIGBEE_SCENES=y
diff --git a/samples/light_switch/prj.conf b/samples/light_switch/prj.conf
index 0b98dc51..529c6ad5 100644
--- a/samples/light_switch/prj.conf
+++ b/samples/light_switch/prj.conf
@@ -28,8 +28,3 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
# Enable API for powering down unused RAM parts
CONFIG_RAM_POWER_DOWN_LIBRARY=y
-
-# Networking
-CONFIG_NET_IPV6=n
-CONFIG_NET_IP_ADDR_CHECK=n
-CONFIG_NET_UDP=n
diff --git a/samples/light_switch/prj_fota.conf b/samples/light_switch/prj_fota.conf
index 169157f6..31aa0c51 100644
--- a/samples/light_switch/prj_fota.conf
+++ b/samples/light_switch/prj_fota.conf
@@ -29,11 +29,6 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
# Enable API for powering down unused RAM parts
CONFIG_RAM_POWER_DOWN_LIBRARY=y
-# Networking
-CONFIG_NET_IPV6=n
-CONFIG_NET_IP_ADDR_CHECK=n
-CONFIG_NET_UDP=n
-
#######################
# Zigbee FOTA overlay #
diff --git a/samples/network_coordinator/prj.conf b/samples/network_coordinator/prj.conf
index 51abdacb..25840048 100644
--- a/samples/network_coordinator/prj.conf
+++ b/samples/network_coordinator/prj.conf
@@ -26,8 +26,3 @@ CONFIG_DK_LIBRARY=y
# This example requires more workqueue stack
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
-
-# Networking
-CONFIG_NET_IPV6=n
-CONFIG_NET_IP_ADDR_CHECK=n
-CONFIG_NET_UDP=n
diff --git a/samples/shell/prj.conf b/samples/shell/prj.conf
index 0d54944c..c6b41ae2 100644
--- a/samples/shell/prj.conf
+++ b/samples/shell/prj.conf
@@ -35,11 +35,6 @@ CONFIG_DK_LIBRARY=y
# This example requires more workqueue stack
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
-# Networking
-CONFIG_NET_IPV6=n
-CONFIG_NET_IP_ADDR_CHECK=n
-CONFIG_NET_UDP=n
-
# Zigbee shell
CONFIG_ZIGBEE_SHELL=y
CONFIG_ZIGBEE_SHELL_DEBUG_CMD=y
diff --git a/samples/template/prj.conf b/samples/template/prj.conf
index 81d43487..09294a4a 100644
--- a/samples/template/prj.conf
+++ b/samples/template/prj.conf
@@ -26,8 +26,3 @@ CONFIG_DK_LIBRARY=y
# This example requires more workqueue stack
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
-
-# Networking
-CONFIG_NET_IPV6=n
-CONFIG_NET_IP_ADDR_CHECK=n
-CONFIG_NET_UDP=n
diff --git a/subsys/Kconfig b/subsys/Kconfig
index 0432cd99..c335d130 100644
--- a/subsys/Kconfig
+++ b/subsys/Kconfig
@@ -9,10 +9,10 @@ menuconfig ZIGBEE_ADD_ON
imply FPU
select APP_LINK_WITH_ZBOSS
select PM_SINGLE_IMAGE
- select NET_L2_ZIGBEE
- select NETWORKING
- select NET_PKT_TXTIME
select REBOOT
+ select MPSL if !SOC_NRF5340_CPUAPP
+ select NRF_802154_RADIO_DRIVER if !SOC_NRF5340_CPUAPP
+ select NRF_802154_SER_HOST if SOC_NRF5340_CPUAPP
select PSA_WANT_ALG_ECB_NO_PADDING if NRF_SECURITY
select PSA_WANT_ALG_ECDH if NRF_SECURITY
select PSA_WANT_KEY_TYPE_AES if NRF_SECURITY
@@ -45,12 +45,34 @@ choice LIBC_IMPLEMENTATION
Use minimal libc implementation with Zigbee.
endchoice
-config NET_L2_ZIGBEE
- bool "Zigbee L2"
- depends on NETWORKING
- select NET_L2_CUSTOM_IEEE802154
- select NET_PKT_TIMESTAMP
- select IEEE802154_L2_PKT_INCL_FCS
+config ZIGBEE_VENDOR_OUI
+ hex "A value that represents MAC Address Block Large"
+ default 0xf4ce36
+ help
+ A value that represents MAC Address Block Large (MA-L, formerly called Organizationally Unique Identifier,
+ or OUI), a part of the device's EUI-64 address.
+ By default, use Nordic Semiconductor's MA-L block (f4-ce-36), assigned by the IEEE Registration Authority.
+
+config ZIGBEE_UICR_EUI64_ENABLE
+ bool "Use EUI64 from UICR registers"
+ depends on SOC_SERIES_NRF52X || SOC_SERIES_NRF53X || SOC_SERIES_NRF54LX
+ help
+ Use a custom EUI64 stored in User Information Configuration Registers (UICR)
+ instead of deriving it from FICR and ZIGBEE_VENDOR_OUI.
+
+if ZIGBEE_UICR_EUI64_ENABLE
+
+config ZIGBEE_UICR_EUI64_REG
+ int "UICR base register index for EUI64"
+ range 0 30 if SOC_SERIES_NRF52X
+ range 0 190 if SOC_SERIES_NRF53X
+ range 0 318 if SOC_SERIES_NRF54LX
+ default 0
+ help
+ Base index of the two consecutive UICR registers (customer or OTP section)
+ where the 64-bit EUI64 is stored.
+
+endif # ZIGBEE_UICR_EUI64_ENABLE
choice ZIGBEE_CHANNEL_SELECTION_MODE
prompt "Zigbee channel selection mode"
@@ -405,6 +427,22 @@ config ZIGBEE_TIME_KTIMER
endchoice
+config ZBOSS_RADIO_INIT_PRIORITY
+ int "nRF 802.15.4 radio driver initialization priority"
+ default 80
+ range 0 99
+ help
+ Initialization priority for the nRF 802.15.4 radio driver in POST_KERNEL phase.
+ Must be lower than ZBOSS_INIT_PRIORITY to ensure radio is ready before ZBOSS.
+
+config ZBOSS_INIT_PRIORITY
+ int "ZBOSS stack initialization priority"
+ default 90
+ range 1 99
+ help
+ Initialization priority for the ZBOSS stack in POST_KERNEL phase.
+ Must be higher than ZBOSS_RADIO_INIT_PRIORITY to ensure proper initialization order.
+
endmenu #menu "ZBOSS osif configuration"
config APP_LINK_WITH_ZIGBEE
diff --git a/subsys/osif/zb_nrf_platform.c b/subsys/osif/zb_nrf_platform.c
index fe22687a..f32dd404 100644
--- a/subsys/osif/zb_nrf_platform.c
+++ b/subsys/osif/zb_nrf_platform.c
@@ -5,7 +5,9 @@
*/
#include
+#include
#include
+#include
#include
#include
#include
@@ -13,6 +15,7 @@
#include
#include
+#include
#if !NRF_POWER_HAS_RESETREAS
#include
#endif
@@ -36,6 +39,20 @@
/* The number of bytes to be checked before concluding that the ZBOSS NVRAM is not initialized. */
#define ZB_PAGE_INIT_CHECK_LEN 32
+/* EUI64 address configuration */
+#if defined(CONFIG_ZIGBEE_UICR_EUI64_ENABLE)
+#if defined(CONFIG_SOC_NRF5340_CPUAPP) || defined(CONFIG_SOC_SERIES_NRF54LX)
+#define EUI64_ADDR (NRF_UICR->OTP)
+#else
+#define EUI64_ADDR (NRF_UICR->CUSTOMER)
+#endif
+#define EUI64_ADDR_HIGH CONFIG_ZIGBEE_UICR_EUI64_REG
+#define EUI64_ADDR_LOW (CONFIG_ZIGBEE_UICR_EUI64_REG + 1)
+#else
+#define EUI64_ADDR_HIGH 0
+#define EUI64_ADDR_LOW 1
+#endif /* CONFIG_ZIGBEE_UICR_EUI64_ENABLE */
+
/**
* Enumeration representing type of application callback to execute from ZBOSS
@@ -67,6 +84,9 @@ typedef struct {
LOG_MODULE_REGISTER(zboss_osif, CONFIG_ZBOSS_OSIF_LOG_LEVEL);
+BUILD_ASSERT(CONFIG_ZBOSS_INIT_PRIORITY > CONFIG_ZBOSS_RADIO_INIT_PRIORITY,
+ "ZBOSS init priority must be greater than radio init priority");
+
/* Signal object to indicate that frame has been received */
static struct k_poll_signal zigbee_sig = K_POLL_SIGNAL_INITIALIZER(zigbee_sig);
@@ -338,6 +358,8 @@ int zigbee_init(void)
return 0;
}
+SYS_INIT(zigbee_init, POST_KERNEL, CONFIG_ZBOSS_INIT_PRIORITY);
+
#if IS_ENABLED(CONFIG_ZIGBEE_LIBRARY_NCP_DEV)
void zb_ncp_app_fw_custom_post_start(void)
{
@@ -650,6 +672,28 @@ __weak zb_uint32_t zb_get_utc_time(void)
return ZB_TIME_BEACON_INTERVAL_TO_MSEC(ZB_TIMER_GET()) / 1000;
}
+void zb_osif_get_ieee_eui64(zb_ieee_addr_t ieee_eui64)
+{
+ uint64_t addr;
+
+#if defined(CONFIG_ZIGBEE_UICR_EUI64_ENABLE)
+ addr = (uint64_t)EUI64_ADDR[EUI64_ADDR_HIGH] << 32 | EUI64_ADDR[EUI64_ADDR_LOW];
+#else
+ uint32_t deviceid[2];
+
+ deviceid[0] = nrf_ficr_deviceid_get(NRF_FICR, 0);
+ deviceid[1] = nrf_ficr_deviceid_get(NRF_FICR, 1);
+
+ addr = ((uint64_t)deviceid[EUI64_ADDR_HIGH] << 32 | deviceid[EUI64_ADDR_LOW]) &
+ 0x000000FFFFFFFFFFULL;
+ addr = (addr << 24) | ((CONFIG_ZIGBEE_VENDOR_OUI & 0xFFU) << 16) |
+ (((CONFIG_ZIGBEE_VENDOR_OUI >> 8) & 0xFFU) << 8) |
+ (CONFIG_ZIGBEE_VENDOR_OUI >> 16);
+#endif
+
+ sys_memcpy_swap(ieee_eui64, &addr, sizeof(zb_ieee_addr_t));
+}
+
void zigbee_event_notify(zigbee_event_t event)
{
k_poll_signal_raise(&zigbee_sig, event);
diff --git a/subsys/osif/zb_nrf_transceiver.c b/subsys/osif/zb_nrf_transceiver.c
index ced346c9..5d1a64d8 100644
--- a/subsys/osif/zb_nrf_transceiver.c
+++ b/subsys/osif/zb_nrf_transceiver.c
@@ -5,461 +5,332 @@
*/
#include
-#include
-#include
-#include
+#include
#include
-#include
+#include
+#include
+#include
+#include
#include
#include
#include
#include "zb_nrf_platform.h"
-#define PHR_LENGTH 1
-#define FCS_LENGTH 2
-#define ACK_PKT_LENGTH 5
-#define FRAME_TYPE_MASK 0x07
-#define FRAME_TYPE_ACK 0x02
-
-#if defined(NRF52840_XXAA) || defined(NRF52811_XXAA)
-/* Minimum value in dBm detectable by the radio. */
-#define MIN_RADIO_SENSITIVITY (-92)
-/* Factor needed to calculate the ED result based on the data from the RADIO peripheral. */
-#define ZBOSS_ED_RESULT_FACTOR 4
-
-#elif defined(NRF52833_XXAA) || defined(NRF52820_XXAA) \
-|| defined(NRF5340_XXAA_NETWORK) || defined(NRF5340_XXAA_APPLICATION)
-/* Minimum value in dBm detectable by the radio. */
-#define MIN_RADIO_SENSITIVITY (-93)
-/* Factor needed to calculate the ED result based on the data from the RADIO peripheral. */
-#define ZBOSS_ED_RESULT_FACTOR 5
-
-#else
-/* Minimum value in dBm detectable by the radio. */
-#define MIN_RADIO_SENSITIVITY (-92)
-/* Factor needed to calculate the ED result based on the data from the RADIO peripheral. */
-#define ZBOSS_ED_RESULT_FACTOR 4
-// #error "Selected chip is not supported."
+#if defined(CONFIG_NRF_802154_SER_HOST)
+#include "nrf_802154_serialization_error.h"
+#endif
+
+#if !defined NRF_802154_FRAME_TIMESTAMP_ENABLED || \
+ !NRF_802154_FRAME_TIMESTAMP_ENABLED
+#warning Must define NRF_802154_FRAME_TIMESTAMP_ENABLED!
#endif
-/* dBm value corresponding to value 0 of the energy scan result. */
-#define ZBOSS_ED_MIN_DBM (-75)
-/* dBm value corresponding to value 255 of the energy scan result. */
-#define ZBOSS_ED_MAX_DBM (MIN_RADIO_SENSITIVITY + (255/ZBOSS_ED_RESULT_FACTOR))
+LOG_MODULE_DECLARE(zboss_osif, CONFIG_ZBOSS_OSIF_LOG_LEVEL);
-BUILD_ASSERT(IS_ENABLED(CONFIG_NET_PKT_TIMESTAMP), "Timestamp is required");
-BUILD_ASSERT(!IS_ENABLED(CONFIG_IEEE802154_NET_IF_NO_AUTO_START),
- "Option not supported");
+/** Map ED in dBm to ZBOSS 0..255 scale. */
+static uint8_t zboss_normalize_ed_dbm(int8_t ed_dbm)
+{
+ int32_t ed = ed_dbm;
+ const int32_t min_dbm = ED_DBM_MIN;
+ const int32_t max_dbm = ED_DBM_MAX;
-/* Required by workaround for KRKNWK-12301. */
-#define NO_ACK_DELAY_MS 23U
+ if (ed <= min_dbm) {
+ return 0U;
+ }
+ if (ed >= max_dbm) {
+ return UINT8_MAX;
+ }
-LOG_MODULE_DECLARE(zboss_osif, CONFIG_ZBOSS_OSIF_LOG_LEVEL);
+ return (uint8_t)(UINT8_MAX * (ed - min_dbm) / (max_dbm - min_dbm));
+}
-enum ieee802154_radio_state {
- RADIO_802154_STATE_SLEEP,
- RADIO_802154_STATE_ACTIVE,
- RADIO_802154_STATE_RECEIVE,
- RADIO_802154_STATE_TRANSMIT,
+enum zb_radio_state {
+ ZB_RADIO_STATE_SLEEP,
+ ZB_RADIO_STATE_RECEIVE,
+ ZB_RADIO_STATE_TRANSMIT,
};
-struct ieee802154_state_cache {
+struct zboss_rx_frame {
+ void *fifo_reserved;
+ uint8_t *psdu;
int8_t power;
- enum ieee802154_radio_state radio_state;
+ uint8_t lqi;
+ uint64_t time;
+ bool ack_fpb;
};
-static struct ieee802154_state_cache state_cache = {
- .power = SCHAR_MIN,
- .radio_state = RADIO_802154_STATE_SLEEP,
+struct nrf5_data {
+ enum zb_radio_state state;
+
+ int8_t tx_power;
+ uint8_t channel;
+ bool promiscuous;
+
+ struct {
+ struct zboss_rx_frame frames[CONFIG_NRF_802154_RX_BUFFERS + 1];
+ struct k_fifo fifo;
+ bool last_frame_ack_fpb;
+ } rx;
+
+ struct {
+ uint8_t *psdu;
+ } tx;
+
+ struct {
+ uint32_t time_us;
+ uint8_t value;
+ } energy_detection;
+
+ struct k_sem rssi_wait;
};
-/* RX fifo queue. */
-static struct k_fifo rx_fifo;
+static struct nrf5_data nrf5_data;
-static uint8_t ack_frame_buf[ACK_PKT_LENGTH + PHR_LENGTH];
-static uint8_t *ack_frame;
+#if defined(CONFIG_NRF_802154_SER_HOST)
+static uint8_t *tx_done_pending_ack;
+static void tx_done_ack_work_fn(struct k_work *work);
+static K_WORK_DEFINE(tx_done_ack_work, tx_done_ack_work_fn);
+#endif
-static struct {
- /* Semaphore for waiting for end of energy detection procedure. */
- struct k_sem sem;
- volatile bool failed; /* Energy detection procedure failed. */
- volatile uint32_t time_ms; /* Duration of energy detection procedure. */
- volatile uint8_t rssi_val; /* Detected energy level. */
-} energy_detect;
+static int nrf_802154_radio_init(void)
+{
+ k_fifo_init(&nrf5_data.rx.fifo);
+ k_sem_init(&nrf5_data.rssi_wait, 0, 1);
+
+ nrf_802154_init();
+
+ nrf5_data.state = ZB_RADIO_STATE_SLEEP;
+
+ LOG_INF("802.15.4 radio driver initialized");
+
+ return 0;
+}
-static const struct device *radio_dev;
-static struct ieee802154_radio_api *radio_api;
-static struct net_if *net_iface;
+SYS_INIT(nrf_802154_radio_init, POST_KERNEL, CONFIG_ZBOSS_RADIO_INIT_PRIORITY);
void zb_trans_hw_init(void)
{
- /* Radio hardware is initialized in 802.15.4 driver */
+ nrf_802154_src_addr_matching_method_set(NRF_802154_SRC_ADDR_MATCH_ZIGBEE);
}
-/* Sets the PAN ID used by the device. */
void zb_trans_set_pan_id(zb_uint16_t pan_id)
{
- struct ieee802154_filter filter = { .pan_id = pan_id };
-
- LOG_DBG("Function: %s, PAN ID: 0x%x", __func__, pan_id);
-
- radio_api->filter(radio_dev, true, IEEE802154_FILTER_TYPE_PAN_ID, &filter);
+ LOG_DBG("%s: 0x%x", __func__, pan_id);
+ nrf_802154_pan_id_set((zb_uint8_t *)(&pan_id));
}
-/* Sets the long address in the radio driver. */
void zb_trans_set_long_addr(zb_ieee_addr_t long_addr)
{
- struct ieee802154_filter filter = { .ieee_addr = long_addr };
-
- LOG_DBG("Function: %s, long addr: 0x%llx", __func__, (uint64_t)*long_addr);
-
- radio_api->filter(radio_dev,
- true,
- IEEE802154_FILTER_TYPE_IEEE_ADDR,
- &filter);
+ LOG_DBG("%s: 0x%llx", __func__, (uint64_t)*long_addr);
+ nrf_802154_extended_address_set(long_addr);
}
-/* Sets the short address of the device. */
void zb_trans_set_short_addr(zb_uint16_t addr)
{
- struct ieee802154_filter filter = { .short_addr = addr };
-
- LOG_DBG("Function: %s, 0x%x", __func__, addr);
-
- radio_api->filter(radio_dev,
- true,
- IEEE802154_FILTER_TYPE_SHORT_ADDR,
- &filter);
+ LOG_DBG("%s: 0x%x", __func__, addr);
+ nrf_802154_short_address_set((uint8_t *)(&addr));
}
-/* Energy detection callback */
-static void energy_scan_done(const struct device *dev, int16_t max_ed)
+static int zboss_energy_detection_start(uint32_t time_us)
{
- ARG_UNUSED(dev);
-
- if (max_ed == SHRT_MAX) {
- energy_detect.failed = true;
- } else {
- energy_detect.rssi_val =
- 255 * (max_ed - ZBOSS_ED_MIN_DBM) / (ZBOSS_ED_MAX_DBM - ZBOSS_ED_MIN_DBM);
+ nrf5_data.energy_detection.time_us = time_us;
+
+ if (!nrf_802154_energy_detection(time_us)) {
+ return -EBUSY;
}
- k_sem_give(&energy_detect.sem);
+
+ return 0;
}
-/* Start the energy detection procedure */
void zb_trans_start_get_rssi(zb_uint8_t scan_duration_bi)
{
- energy_detect.failed = false;
- energy_detect.time_ms =
- ZB_TIME_BEACON_INTERVAL_TO_MSEC(scan_duration_bi);
+ int err;
+ uint32_t time_us = ZB_TIME_BEACON_INTERVAL_TO_USEC(scan_duration_bi);
- LOG_DBG("Function: %s, scan duration: %d ms", __func__,
- energy_detect.time_ms);
+ LOG_DBG("%s: %d us", __func__, time_us);
- k_sem_take(&energy_detect.sem, K_FOREVER);
- while (radio_api->ed_scan(radio_dev,
- energy_detect.time_ms,
- energy_scan_done)) {
+ err = zboss_energy_detection_start(time_us);
+
+ while (err != 0) {
+ LOG_DBG("Energy detection start failed, retrying");
k_usleep(500);
+ err = zboss_energy_detection_start(time_us);
}
}
-/* Waiting for the end of energy detection procedure and reads the RSSI */
void zb_trans_get_rssi(zb_uint8_t *rssi_value_p)
{
- LOG_DBG("Function: %s", __func__);
+ LOG_DBG("%s", __func__);
- /*Wait until the ED scan finishes.*/
- while (1) {
- k_sem_take(&energy_detect.sem, K_FOREVER);
- if (!energy_detect.failed) {
- *rssi_value_p = energy_detect.rssi_val;
- LOG_DBG("Energy detected: %d", *rssi_value_p);
- break;
- }
-
- /* Try again */
- LOG_DBG("Energy detect failed, tries again");
- energy_detect.failed = false;
- while (radio_api->ed_scan(radio_dev,
- energy_detect.time_ms,
- energy_scan_done)) {
- k_usleep(500);
- }
- }
- k_sem_give(&energy_detect.sem);
+ /* Blocking implementation: wait for energy detection to complete.
+ * The semaphore is signaled by nrf_802154_energy_detected() callback
+ * or by nrf_802154_energy_detection_failed() after retry attempt.
+ */
+ k_sem_take(&nrf5_data.rssi_wait, K_FOREVER);
+ *rssi_value_p = nrf5_data.energy_detection.value;
+ LOG_DBG("Energy detected: %d", *rssi_value_p);
}
-/* Set channel and go to the normal (not ed scan) mode */
zb_ret_t zb_trans_set_channel(zb_uint8_t channel_number)
{
- LOG_DBG("Function: %s, channel number: %d", __func__, channel_number);
-
- radio_api->set_channel(radio_dev, channel_number);
-
+ LOG_DBG("%s: %d", __func__, channel_number);
+ nrf_802154_channel_set(channel_number);
return RET_OK;
}
-/* Sets the transmit power. */
void zb_trans_set_tx_power(zb_int8_t power)
{
- LOG_DBG("Function: %s, power: %d", __func__, power);
-
- radio_api->set_txpower(radio_dev, power);
- state_cache.power = power;
+ LOG_DBG("%s: %d", __func__, power);
+ nrf_802154_tx_power_set(power);
}
-/* Gets the currently set transmit power. */
void zb_trans_get_tx_power(zb_int8_t *power)
{
- __ASSERT_NO_MSG(state_cache.power != SCHAR_MIN);
-
- *power = state_cache.power;
-
- LOG_DBG("Function: %s, power: %d", __func__, *power);
+ *power = (zb_int8_t)nrf_802154_tx_power_get();
+ LOG_DBG("%s: %d", __func__, *power);
}
-/* Configures the device as the PAN coordinator. */
void zb_trans_set_pan_coord(zb_bool_t enabled)
{
- struct ieee802154_config config = { .pan_coordinator = enabled };
-
- LOG_DBG("Function: %s, enabled: %d", __func__, enabled);
-
- radio_api->configure(radio_dev,
- IEEE802154_CONFIG_PAN_COORDINATOR,
- &config);
-}
-
-/* Enables or disables the automatic acknowledgments (auto ACK) */
-void zb_trans_set_auto_ack(zb_bool_t enabled)
-{
- struct ieee802154_config config = {
- .auto_ack_fpb = {
- .enabled = enabled,
- .mode = IEEE802154_FPB_ADDR_MATCH_ZIGBEE
- }
- };
-
- LOG_DBG("Function: %s, enabled: %d", __func__, enabled);
-
- radio_api->configure(radio_dev,
- IEEE802154_CONFIG_AUTO_ACK_FPB,
- &config);
+ LOG_DBG("%s: %d", __func__, enabled);
+ nrf_802154_pan_coord_set((bool)enabled);
}
-/* Enables or disables the promiscuous radio mode. */
void zb_trans_set_promiscuous_mode(zb_bool_t enabled)
{
- struct ieee802154_config config = {
- .promiscuous = enabled
- };
-
- LOG_DBG("Function: %s, enabled: %d", __func__, enabled);
-
- radio_api->configure(radio_dev,
- IEEE802154_CONFIG_PROMISCUOUS,
- &config);
+ LOG_DBG("%s: %d", __func__, enabled);
+ nrf_802154_promiscuous_set((bool)enabled);
}
-/* Changes the radio state to receive. */
void zb_trans_enter_receive(void)
{
- LOG_DBG("Function: %s", __func__);
-
- radio_api->start(radio_dev);
- state_cache.radio_state = RADIO_802154_STATE_RECEIVE;
+ LOG_DBG("%s", __func__);
+ (void)nrf_802154_receive();
+ nrf5_data.state = ZB_RADIO_STATE_RECEIVE;
}
-/* Changes the radio state to sleep. */
void zb_trans_enter_sleep(void)
{
- LOG_DBG("Function: %s", __func__);
-
- (void)radio_api->stop(radio_dev);
- state_cache.radio_state = RADIO_802154_STATE_SLEEP;
+ LOG_DBG("%s", __func__);
+ (void)nrf_802154_sleep_if_idle();
+ nrf5_data.state = ZB_RADIO_STATE_SLEEP;
}
-/* Returns ZB_TRUE if radio is in receive state, otherwise ZB_FALSE */
zb_bool_t zb_trans_is_receiving(void)
{
- zb_bool_t is_receiv =
- (state_cache.radio_state == RADIO_802154_STATE_RECEIVE) ?
- ZB_TRUE : ZB_FALSE;
-
- LOG_DBG("Function: %s, is receiv: %d", __func__, is_receiv);
+ zb_bool_t is_receiv = (nrf5_data.state == ZB_RADIO_STATE_RECEIVE) ? ZB_TRUE : ZB_FALSE;
+ LOG_DBG("%s: %d", __func__, is_receiv);
return is_receiv;
}
-/* Returns ZB_TRUE if radio is ON or ZB_FALSE if is in sleep state. */
zb_bool_t zb_trans_is_active(void)
{
- zb_bool_t is_active =
- (state_cache.radio_state != RADIO_802154_STATE_SLEEP) ?
- ZB_TRUE : ZB_FALSE;
-
- LOG_DBG("Function: %s, is active: %d", __func__, is_active);
+ zb_bool_t is_active = (nrf5_data.state != ZB_RADIO_STATE_SLEEP) ? ZB_TRUE : ZB_FALSE;
+ LOG_DBG("%s: %d", __func__, is_active);
return is_active;
}
zb_bool_t zb_trans_transmit(zb_uint8_t wait_type, zb_time_t tx_at,
zb_uint8_t *tx_buf, zb_uint8_t current_channel)
{
- struct net_pkt *pkt = NULL;
- struct net_buf frag = {
- .frags = NULL,
- .b = {
- .data = &tx_buf[1],
- .len = tx_buf[0] - FCS_LENGTH,
- .size = tx_buf[0] - FCS_LENGTH,
- .__buf = &tx_buf[1]
- }
- };
- int err = 0;
-
- LOG_DBG("Function: %s, channel: %d", __func__, current_channel);
+ LOG_DBG("%s: channel %d", __func__, current_channel);
+ nrf_802154_tx_error_t result;
+ nrf_802154_capabilities_t caps = nrf_802154_capabilities_get();
#ifndef ZB_ENABLE_ZGP_DIRECT
ARG_UNUSED(tx_at);
ARG_UNUSED(current_channel);
#endif
- pkt = net_pkt_alloc(K_NO_WAIT);
- if (!pkt) {
- ZB_ASSERT(0);
- return ZB_FALSE;
- }
-
- ack_frame = NULL;
+ nrf5_data.state = ZB_RADIO_STATE_TRANSMIT;
switch (wait_type) {
- case ZB_MAC_TX_WAIT_CSMACA: {
- state_cache.radio_state = RADIO_802154_STATE_TRANSMIT;
- enum ieee802154_tx_mode mode;
- if (radio_api->get_capabilities(radio_dev)
- & IEEE802154_HW_CSMA) {
- mode = IEEE802154_TX_MODE_CSMA_CA;
+ case ZB_MAC_TX_WAIT_CSMACA:
+ if (caps & NRF_802154_CAPABILITY_CSMA) {
+ nrf_802154_transmit_csma_ca_metadata_t csma_metadata = {
+ .frame_props = {
+ .is_secured = false,
+ .dynamic_data_is_set = false,
+ },
+ };
+ result = nrf_802154_transmit_csma_ca_raw(tx_buf, &csma_metadata);
} else {
- mode = IEEE802154_TX_MODE_CCA;
+ nrf_802154_transmit_metadata_t cca_metadata = {
+ .frame_props = {
+ .is_secured = false,
+ .dynamic_data_is_set = false,
+ },
+ .cca = true,
+ };
+ result = nrf_802154_transmit_raw(tx_buf, &cca_metadata);
}
-
- err = radio_api->tx(radio_dev, mode, pkt, &frag);
break;
- }
#ifdef ZB_ENABLE_ZGP_DIRECT
- case ZB_MAC_TX_WAIT_ZGP: {
- if (!(radio_api->get_capabilities(radio_dev)
- & IEEE802154_HW_TXTIME)) {
- net_pkt_unref(pkt);
+ case ZB_MAC_TX_WAIT_ZGP:
+ if (!(caps & NRF_802154_CAPABILITY_DELAYED_TX)) {
+ LOG_ERR("NRF_802154_CAPABILITY_DELAYED_TX not supported");
+ nrf5_data.state = ZB_RADIO_STATE_RECEIVE;
return ZB_FALSE;
}
-
- net_pkt_set_timestamp_ns(pkt, (uint64_t)tx_at * NSEC_PER_USEC);
- state_cache.radio_state = RADIO_802154_STATE_TRANSMIT;
- err = radio_api->tx(radio_dev,
- IEEE802154_TX_MODE_TXTIME,
- pkt,
- &frag);
+ nrf_802154_transmit_at_metadata_t at_metadata = {
+ .frame_props = {
+ .is_secured = false,
+ .dynamic_data_is_set = false,
+ },
+ .cca = true,
+ };
+ result = nrf_802154_transmit_raw_at(tx_buf, tx_at, &at_metadata);
break;
- }
#endif
+
case ZB_MAC_TX_WAIT_NONE:
- /* First transmit attempt without CCA. */
- state_cache.radio_state = RADIO_802154_STATE_TRANSMIT;
- err = radio_api->tx(radio_dev,
- IEEE802154_TX_MODE_DIRECT,
- pkt,
- &frag);
+ {
+ nrf_802154_transmit_metadata_t tx_metadata = {
+ .frame_props = {
+ .is_secured = false,
+ .dynamic_data_is_set = false,
+ },
+ .cca = false,
+ };
+ result = nrf_802154_transmit_raw(tx_buf, &tx_metadata);
break;
- default:
- LOG_DBG("Illegal wait_type parameter: %d", wait_type);
- ZB_ASSERT(0);
- net_pkt_unref(pkt);
- return ZB_FALSE;
}
- net_pkt_unref(pkt);
- state_cache.radio_state = RADIO_802154_STATE_RECEIVE;
-
- switch (err) {
- case 0:
- /* ack_frame is overwritten if ack frame was received */
- zb_macll_transmitted_raw(ack_frame);
-
- /* Raise signal to indicate radio event */
- zigbee_event_notify(ZIGBEE_EVENT_TX_DONE);
- break;
- case -ENOMSG:
- zb_macll_transmit_failed(ZB_TRANS_NO_ACK);
- zigbee_event_notify(ZIGBEE_EVENT_TX_FAILED);
-
- /* Workaround for KRKNWK-12301. */
- k_sleep(K_MSEC(NO_ACK_DELAY_MS));
- /* End of workaround. */
- break;
- case -EBUSY:
- case -EIO:
default:
- zb_macll_transmit_failed(ZB_TRANS_CHANNEL_BUSY_ERROR);
- zigbee_event_notify(ZIGBEE_EVENT_TX_FAILED);
- break;
+ LOG_ERR("Invalid wait_type: %d", wait_type);
+ ZB_ASSERT(0);
+ nrf5_data.state = ZB_RADIO_STATE_RECEIVE;
+ return ZB_FALSE;
}
- return ZB_TRUE;
+ return (result == NRF_802154_TX_ERROR_NONE) ? ZB_TRUE : ZB_FALSE;
}
-/* Notifies the driver that the buffer containing the received frame
- * is not used anymore
- */
void zb_trans_buffer_free(zb_uint8_t *buf)
{
- ARG_UNUSED(buf);
- LOG_DBG("Function: %s", __func__);
-
- /* The buffer containing the released frame is freed
- * in 802.15.4 shim driver
- */
+ LOG_DBG("%s", __func__);
+ nrf_802154_buffer_free_raw(buf);
}
-zb_bool_t zb_trans_set_pending_bit(zb_uint8_t *addr, zb_bool_t value,
- zb_bool_t extended)
+zb_bool_t zb_trans_set_pending_bit(zb_uint8_t *addr, zb_bool_t value, zb_bool_t extended)
{
- struct ieee802154_config config = {
- .ack_fpb = {
- .addr = addr,
- .extended = extended,
- .enabled = !value
- }
- };
- int ret;
-
- LOG_DBG("Function: %s, value: %d", __func__, value);
+ LOG_DBG("%s: value=%d", __func__, value);
- ret = radio_api->configure(radio_dev,
- IEEE802154_CONFIG_ACK_FPB,
- &config);
- return !ret ? ZB_TRUE : ZB_FALSE;
+ if (!value) {
+ return (zb_bool_t)nrf_802154_pending_bit_for_addr_set(
+ (const uint8_t *)addr, (bool)extended);
+ } else {
+ return (zb_bool_t)nrf_802154_pending_bit_for_addr_clear(
+ (const uint8_t *)addr, (bool)extended);
+ }
}
void zb_trans_src_match_tbl_drop(void)
{
- struct ieee802154_config config = {
- .ack_fpb = {
- .addr = NULL,
- .enabled = false
- }
- };
-
- LOG_DBG("Function: %s", __func__);
-
- /* reset for short addresses */
- config.ack_fpb.extended = false;
- radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB, &config);
-
- /* reset for long addresses */
- config.ack_fpb.extended = true;
- radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB, &config);
+ LOG_DBG("%s", __func__);
+ nrf_802154_pending_bit_for_addr_reset(false);
+ nrf_802154_pending_bit_for_addr_reset(true);
}
zb_time_t osif_sub_trans_timer(zb_time_t t2, zb_time_t t1)
@@ -469,156 +340,179 @@ zb_time_t osif_sub_trans_timer(zb_time_t t2, zb_time_t t1)
zb_bool_t zb_trans_rx_pending(void)
{
- return k_fifo_is_empty(&rx_fifo) ? ZB_FALSE : ZB_TRUE;
+ return k_fifo_is_empty(&nrf5_data.rx.fifo) ? ZB_FALSE : ZB_TRUE;
}
zb_uint8_t zb_trans_get_next_packet(zb_bufid_t buf)
{
+ LOG_DBG("%s", __func__);
zb_uint8_t *data_ptr;
- size_t length;
-
- LOG_DBG("Function: %s", __func__);
+ zb_uint8_t length = 0;
if (!buf) {
return 0;
}
- /* Packet received with correct CRC, PANID and address */
- struct net_pkt *pkt = k_fifo_get(&rx_fifo, K_NO_WAIT);
-
- if (!pkt) {
+ struct zboss_rx_frame *rx_frame = k_fifo_get(&nrf5_data.rx.fifo, K_NO_WAIT);
+ if (!rx_frame) {
return 0;
}
- length = net_pkt_get_len(pkt);
+ length = rx_frame->psdu[0];
data_ptr = zb_buf_initial_alloc(buf, length);
+ ZB_MEMCPY(data_ptr, (void const *)(rx_frame->psdu + 1), length);
- /* Copy received data */
- net_pkt_cursor_init(pkt);
- net_pkt_read(pkt, data_ptr, length);
-
- /* Put LQI, RSSI */
zb_macll_metadata_t *metadata = ZB_MACLL_GET_METADATA(buf);
+ metadata->lqi = rx_frame->lqi;
+ metadata->power = rx_frame->power;
+
+ *ZB_BUF_GET_PARAM(buf, zb_time_t) = (zb_time_t)rx_frame->time;
+ zb_macll_set_received_data_status(buf, rx_frame->ack_fpb);
- metadata->lqi = net_pkt_ieee802154_lqi(pkt);
- metadata->power = net_pkt_ieee802154_rssi_dbm(pkt);
-
- /* Put timestamp (usec) into the packet tail */
- *ZB_BUF_GET_PARAM(buf, zb_time_t) =
- net_pkt_timestamp(pkt)->second * USEC_PER_SEC +
- net_pkt_timestamp(pkt)->nanosecond / NSEC_PER_USEC;
- /* Additional buffer status for Data Request command */
- zb_macll_set_received_data_status(buf,
- net_pkt_ieee802154_ack_fpb(pkt));
-
- /* Release the packet */
- net_pkt_unref(pkt);
+ nrf_802154_buffer_free_raw(rx_frame->psdu);
+ rx_frame->psdu = NULL;
return 1;
}
zb_ret_t zb_trans_cca(void)
{
- int cca_result = radio_api->cca(radio_dev);
-
- switch (cca_result) {
- case 0:
- return RET_OK;
- case -EBUSY:
- return RET_BUSY;
- default:
- return RET_ERROR;
- }
+ bool cca_result = nrf_802154_cca();
+ return cca_result ? RET_OK : RET_BUSY;
}
-void zb_osif_get_ieee_eui64(zb_ieee_addr_t ieee_eui64)
+#if defined(CONFIG_NRF_802154_SER_HOST)
+static void tx_done_ack_work_fn(struct k_work *work)
{
- __ASSERT_NO_MSG(net_iface);
- __ASSERT_NO_MSG(net_if_get_link_addr(net_iface)->len ==
- sizeof(zb_ieee_addr_t));
+ uint8_t *ack = tx_done_pending_ack;
- sys_memcpy_swap(ieee_eui64,
- net_if_get_link_addr(net_iface)->addr,
- net_if_get_link_addr(net_iface)->len);
+ tx_done_pending_ack = NULL;
+ zb_macll_transmitted_raw(ack);
+ zigbee_event_notify(ZIGBEE_EVENT_TX_DONE);
}
+#endif
+
+/* nRF 802.15.4 driver callbacks - modern API with metadata structures */
-void ieee802154_init(struct net_if *iface)
+void nrf_802154_transmitted_raw(uint8_t *p_frame,
+ const nrf_802154_transmit_done_metadata_t *p_metadata)
{
- __ASSERT_NO_MSG(iface);
- net_iface = iface;
+ ARG_UNUSED(p_frame);
- radio_dev = net_if_get_device(iface);
- __ASSERT_NO_MSG(radio_dev);
+ uint8_t *ack = p_metadata->data.transmitted.p_ack;
- radio_api = (struct ieee802154_radio_api *)radio_dev->api;
- __ASSERT_NO_MSG(radio_api);
+ nrf5_data.state = ZB_RADIO_STATE_RECEIVE;
- zb_trans_set_auto_ack(ZB_TRUE);
+#if defined(CONFIG_NRF_802154_SER_HOST)
+ if (ack != NULL) {
+ tx_done_pending_ack = ack;
+ k_work_submit(&tx_done_ack_work);
+ return;
+ }
+#endif
+ zb_macll_transmitted_raw(ack);
+ zigbee_event_notify(ZIGBEE_EVENT_TX_DONE);
+}
- zigbee_init();
+void nrf_802154_transmit_failed(uint8_t *p_frame,
+ nrf_802154_tx_error_t error,
+ const nrf_802154_transmit_done_metadata_t *p_metadata)
+{
+ ARG_UNUSED(p_frame);
+ ARG_UNUSED(p_metadata);
+
+ switch (error) {
+ case NRF_802154_TX_ERROR_NO_MEM:
+ case NRF_802154_TX_ERROR_ABORTED:
+ case NRF_802154_TX_ERROR_TIMESLOT_DENIED:
+ case NRF_802154_TX_ERROR_TIMESLOT_ENDED:
+ case NRF_802154_TX_ERROR_BUSY_CHANNEL:
+ zb_macll_transmit_failed(ZB_TRANS_CHANNEL_BUSY_ERROR);
+ break;
- k_fifo_init(&rx_fifo);
- k_sem_init(&energy_detect.sem, 1, 1);
+ case NRF_802154_TX_ERROR_INVALID_ACK:
+ case NRF_802154_TX_ERROR_NO_ACK:
+ zb_macll_transmit_failed(ZB_TRANS_NO_ACK);
+ break;
+ default:
+ break;
+ }
- radio_api->stop(radio_dev);
- net_if_up(iface);
- LOG_DBG("The 802.15.4 interface initialized.");
+ nrf5_data.state = ZB_RADIO_STATE_RECEIVE;
+ zigbee_event_notify(ZIGBEE_EVENT_TX_FAILED);
}
-enum net_verdict ieee802154_handle_ack(struct net_if *iface,
- struct net_pkt *pkt)
+void nrf_802154_tx_ack_started(const uint8_t *p_data)
{
- ARG_UNUSED(iface);
+ nrf5_data.rx.last_frame_ack_fpb = p_data[FRAME_PENDING_OFFSET] & FRAME_PENDING_BIT;
+}
- size_t ack_len = net_pkt_get_len(pkt);
+void nrf_802154_received_timestamp_raw(uint8_t *p_data, int8_t power,
+ uint8_t lqi, uint64_t time)
+{
+ struct zboss_rx_frame *rx_frame_free_slot = NULL;
- if (ack_len != ACK_PKT_LENGTH) {
- LOG_ERR("%s: ACK length error", __func__);
- return NET_CONTINUE;
+ for (uint32_t i = 0; i < ARRAY_SIZE(nrf5_data.rx.frames); i++) {
+ if (nrf5_data.rx.frames[i].psdu == NULL) {
+ rx_frame_free_slot = &nrf5_data.rx.frames[i];
+ break;
+ }
}
- if ((*net_pkt_data(pkt) & FRAME_TYPE_MASK) != FRAME_TYPE_ACK) {
- LOG_ERR("%s: ACK frame was expected", __func__);
- return NET_CONTINUE;
+ if (rx_frame_free_slot == NULL) {
+ __ASSERT(false, "Not enough rx frames allocated");
+ return;
}
- if (ack_frame != NULL) {
- LOG_ERR("Overwriting unhandled ACK frame.");
- }
+ rx_frame_free_slot->psdu = p_data;
+ rx_frame_free_slot->power = power;
+ rx_frame_free_slot->lqi = lqi;
+ rx_frame_free_slot->time = time;
- ack_frame_buf[0] = ack_len;
- if (net_pkt_read(pkt, &ack_frame_buf[1], ack_len) < 0) {
- LOG_ERR("Failed to read ACK frame.");
- return NET_CONTINUE;
+ if (p_data[ACK_REQUEST_OFFSET] & ACK_REQUEST_BIT) {
+ rx_frame_free_slot->ack_fpb = nrf5_data.rx.last_frame_ack_fpb;
+ } else {
+ rx_frame_free_slot->ack_fpb = false;
}
- /* ack_frame != NULL informs that ACK frame has been received */
- ack_frame = ack_frame_buf;
-
- return NET_OK;
-}
-
-static enum net_verdict zigbee_l2_recv(struct net_if *iface,
- struct net_pkt *pkt)
-{
- ARG_UNUSED(iface);
-
- k_fifo_put(&rx_fifo, pkt);
+ nrf5_data.rx.last_frame_ack_fpb = false;
+ k_fifo_put(&nrf5_data.rx.fifo, rx_frame_free_slot);
zb_macll_set_rx_flag();
zb_macll_set_trans_int();
-
- /* Raise signal to indicate rx event */
zigbee_event_notify(ZIGBEE_EVENT_RX_DONE);
+}
- return NET_OK;
+void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id)
+{
+ ARG_UNUSED(id);
+ ARG_UNUSED(error);
+ nrf5_data.rx.last_frame_ack_fpb = false;
}
-static enum net_l2_flags zigbee_l2_flags(struct net_if *iface)
+void nrf_802154_energy_detected(const nrf_802154_energy_detected_t *p_result)
{
- ARG_UNUSED(iface);
+ nrf5_data.energy_detection.value = zboss_normalize_ed_dbm(p_result->ed_dbm);
+ k_sem_give(&nrf5_data.rssi_wait);
+}
- return 0;
+void nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error)
+{
+ ARG_UNUSED(error);
+
+ int err = zboss_energy_detection_start(nrf5_data.energy_detection.time_us);
+
+ if (err != 0) {
+ LOG_ERR("Failed to restart energy detection after failure");
+ nrf5_data.energy_detection.value = UINT8_MAX;
+ k_sem_give(&nrf5_data.rssi_wait);
+ }
}
-NET_L2_INIT(ZIGBEE_L2, zigbee_l2_recv, NULL, NULL, zigbee_l2_flags);
+#if defined(CONFIG_NRF_802154_SER_HOST)
+void nrf_802154_serialization_error(const nrf_802154_ser_err_data_t *err)
+{
+ __ASSERT(false, "802.15.4 serialization error: %d", err->reason);
+ k_oops();
+}
+#endif