From c907a33c598e69f117aca29b8c3fb9c1fede3478 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Thu, 1 Jan 2026 16:54:40 -0500 Subject: [PATCH 01/30] Migrate Zigbee to Simplicity SDK for size testing --- src/zigbee_ncp/app.c | 13 +++-- src/zigbee_ncp/main.c | 87 +++++++++++++++++----------------- src/zigbee_ncp/zigbee_ncp.slcp | 39 +++++++++++---- 3 files changed, 85 insertions(+), 54 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index a0d2a974..0cc620ad 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -16,16 +16,23 @@ ******************************************************************************/ #include PLATFORM_HEADER -#include "ember.h" +#include "sl_zigbee.h" //---------------------- // Implemented Callbacks /** @brief * - * Application framework equivalent of ::emberRadioNeedsCalibratingHandler + * Application framework equivalent of ::sl_zigbee_radio_needs_calibrating_handler */ -void emberAfRadioNeedsCalibratingCallback(void) +void sl_zigbee_af_radio_needs_calibrating_cb(void) { sl_mac_calibrate_current_channel(); } + +/** @brief Init + * Application init function + */ +void sl_zigbee_af_main_init_cb(void) +{ +} diff --git a/src/zigbee_ncp/main.c b/src/zigbee_ncp/main.c index e3c41b0a..0abba207 100644 --- a/src/zigbee_ncp/main.c +++ b/src/zigbee_ncp/main.c @@ -3,75 +3,76 @@ * @brief main() function. ******************************************************************************* * # License - * Copyright 2021 Silicon Laboratories Inc. www.silabs.com + * Copyright 2025 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ - -#ifdef SL_COMPONENT_CATALOG_PRESENT #include "sl_component_catalog.h" -#endif -#include "sl_system_init.h" +#include "sl_main_init.h" #if defined(SL_CATALOG_POWER_MANAGER_PRESENT) #include "sl_power_manager.h" #endif #if defined(SL_CATALOG_KERNEL_PRESENT) -#include "sl_system_kernel.h" -#else -#include "sl_system_process_action.h" -#endif // SL_CATALOG_KERNEL_PRESENT - -#ifdef EMBER_TEST -#define main nodeMain -#endif - -void app_init(void) -{ -} - -void app_process_action(void) -{ -} +#include "sl_main_kernel.h" +#else // SL_CATALOG_KERNEL_PRESENT +#include "sl_main_process_action.h" +#endif // SL_CATALOG_KERNEL_PRESENT +#ifdef SL_ZIGBEE_TEST +int nodeMain(void) +#else #if defined(__ICCARM__) #pragma diag_suppress=Pe111 #endif // defined(__ICCARM__) int main(void) +#endif { // Initialize Silicon Labs device, system, service(s) and protocol stack(s). - // Note that if the kernel is present, processing task(s) will be created by - // this call. - sl_system_init(); - - // Initialize the application. For example, create periodic timer(s) or - // task(s) if the kernel is present. - app_init(); + // Note that if the kernel is present, the start task will be started and software component + // configuration will take place there. + sl_main_init(); #if defined(SL_CATALOG_KERNEL_PRESENT) - // Start the kernel. Task(s) created in app_init() will start running. - sl_system_kernel_start(); + // Start the kernel. The start task will be executed (Highest priority) to complete + // the Simplicity SDK components initialization and the user app_init() hook function will be called. + sl_main_kernel_start(); #else // SL_CATALOG_KERNEL_PRESENT + + // User provided code. + app_init(); + while (1) { - // Do not remove this call: Silicon Labs components process action routine + // Silicon Labs components process action routine // must be called from the super loop. - sl_system_process_action(); + sl_main_process_action(); - // Application process. + // User provided code. Application process. app_process_action(); - // Let the CPU go to sleep if the system allow it. #if defined(SL_CATALOG_POWER_MANAGER_PRESENT) + // Let the CPU go to sleep if the system allows it. sl_power_manager_sleep(); -#endif // SL_CATALOG_POWER_MANAGER_PRESENT +#endif } #endif // SL_CATALOG_KERNEL_PRESENT - - return 0; } diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 93990a4d..b004be0f 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -7,12 +7,20 @@ description: Zigbee NCP firmware. Derived from the `ncp-uart-hw` example Gecko S author: Nabu Casa component: + - id: sl_main - id: iostream_usart instance: - vcom + condition: + - device_series_2 + - id: iostream_eusart + instance: + - vcom + condition: + - device_series_3 - id: zigbee_debug_print - id: iostream_vuart - - id: token_manager + - id: common_token_manager - id: zigbee_token_interface - id: zigbee_mfglib - id: zigbee_pro_stack @@ -21,16 +29,19 @@ component: - id: zigbee_r22_support - id: zigbee_security_link_keys - id: zigbee_zll - - id: zigbee_app_framework_common + - id: zigbee_system_common - id: zigbee_ncp_uart_hardware - id: zigbee_debug_basic - id: zigbee_debug_extended - id: zigbee_xncp - id: rail_util_rssi - id: legacy_hal_wdog + - id: clock_manager + # Platform - enable LTO for gcc + - id: toolchain_gcc_lto define: - - name: EMBER_CUSTOM_MAC_FILTER_TABLE_SIZE + - name: SL_ZIGBEE_CUSTOM_MAC_FILTER_TABLE_SIZE value: 15 configuration: @@ -38,18 +49,22 @@ configuration: value: 16 - name: SL_BOARD_ENABLE_VCOM value: 1 + condition: + - iostream_usart + - name: SL_IOSTREAM_EUSART_VCOM_FLOW_CONTROL_TYPE + value: SL_IOSTREAM_EUSART_UART_FLOW_CTRL_CTS_RTS + condition: + - iostream_eusart - name: SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE value: usartHwFlowControlCtsAndRts - name: SL_CLI_EXAMPLE_IOSTREAM_HANDLE value: sl_iostream_vuart_handle - - name: NVM3_DEFAULT_NVM_SIZE - value: 36864 - condition: - - device_series_1 - name: NVM3_DEFAULT_NVM_SIZE value: 32768 condition: - device_series_2 + - name: SL_ZIGBEE_PACKET_BUFFER_HEAP_SIZE + value: SL_ZIGBEE_LARGE_PACKET_BUFFER_HEAP # If using zigbee_secure_key_storage we do not need to support backwards # compatibility because we have never deployed images with keys in PSA # As a result, these lines end up saving some code space @@ -59,7 +74,15 @@ configuration: value: 0 - name: SL_PSA_ITS_SUPPORT_V3_DRIVER value: 1 - - name: EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ALL_PACKETS + - name: SL_STACK_SIZE + value: 4096 + condition: + - cmsis_rtos2 + - name: SL_ZIGBEE_STACK_RTOS_TASK_STACK_SIZE + value: 4096 + condition: + - cmsis_rtos2 + - name: SL_ZIGBEE_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ALL_PACKETS value: 1 - name: SL_LEGACY_HAL_DISABLE_WATCHDOG value: 0 From d3d0e256e35d9bb7d99c7f5ca412ebd03e6d651b Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Fri, 19 Dec 2025 19:14:10 -0500 Subject: [PATCH 02/30] Make XNCP commands compatible with both SDKs at once --- .../src/xncp_common_commands.c | 79 +++++++++---------- .../extension/xncp_extension/inc/xncp_types.h | 45 +++++++++++ .../extension/xncp_extension/src/xncp_core.c | 33 ++++++-- .../src/xncp_zbt2_commands.c | 7 +- 4 files changed, 114 insertions(+), 50 deletions(-) diff --git a/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c b/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c index a04ed771..714e5150 100644 --- a/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c +++ b/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c @@ -8,7 +8,6 @@ #include "xncp_types.h" #include "xncp_config.h" #include "tx_power.h" -#include "ember.h" #include "ezsp-enum.h" #include "em_usart.h" #include "random.h" @@ -23,17 +22,17 @@ typedef enum { } XncpFlowControlType; typedef enum { - EMBER_ROUTE_ACTIVE = 0, - EMBER_ROUTE_BEING_DISCOVERED = 1, - EMBER_ROUTE_UNUSED = 3, - EMBER_ROUTE_VALIDATING = 4 -} EmberRouteStatus; + ROUTE_ACTIVE = 0, + ROUTE_BEING_DISCOVERED = 1, + ROUTE_UNUSED = 3, + ROUTE_VALIDATING = 4 +} RouteStatus; typedef struct ManualSourceRoute { bool active; uint16_t destination; uint8_t num_relays; - uint16_t relays[EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT]; + uint16_t relays[XNCP_MAX_SOURCE_ROUTE_RELAY_COUNT]; } ManualSourceRoute; static ManualSourceRoute manual_source_routes[XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE]; @@ -88,7 +87,7 @@ void xncp_common_init(uint8_t init_level) // Multicast override (XNCP_FEATURE_MEMBER_OF_ALL_GROUPS) //------------------------------------------------------------------------------ -bool __wrap_sli_zigbee_am_multicast_member(EmberMulticastId multicastId) +bool __wrap_sli_zigbee_am_multicast_member(xncp_multicast_id_t multicastId) { (void)multicastId; // Ignore all binding and multicast table logic, we want all group packets @@ -99,7 +98,7 @@ bool __wrap_sli_zigbee_am_multicast_member(EmberMulticastId multicastId) // Source route management (XNCP_FEATURE_MANUAL_SOURCE_ROUTE) //------------------------------------------------------------------------------ -static ManualSourceRoute* get_manual_source_route(EmberNodeId destination) +static ManualSourceRoute* get_manual_source_route(xncp_node_id_t destination) { for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { if (manual_source_routes[i].active && @@ -110,7 +109,7 @@ static ManualSourceRoute* get_manual_source_route(EmberNodeId destination) return NULL; } -static sli_zigbee_route_table_entry_t* find_free_routing_table_entry(EmberNodeId destination) +static sli_zigbee_route_table_entry_t* find_free_routing_table_entry(xncp_node_id_t destination) { uint8_t index = 0xFF; sli_zigbee_route_table_entry_t *route_table_entry = NULL; @@ -120,14 +119,14 @@ static sli_zigbee_route_table_entry_t* find_free_routing_table_entry(EmberNodeId if (route_table_entry->destination == destination) { return route_table_entry; - } else if (route_table_entry->status == EMBER_ROUTE_UNUSED) { + } else if (route_table_entry->status == ROUTE_UNUSED) { index = i; continue; } } if (index == 0xFF) { - index = emberGetPseudoRandomNumber() % sli_zigbee_route_table_size; + index = xncp_get_pseudo_random_number() % sli_zigbee_route_table_size; } return &sli_zigbee_route_table[index]; @@ -138,7 +137,7 @@ void nc_zigbee_override_append_source_route(uint16_t destination, void *header, bool *consumed) { - EmberMessageBuffer *msg_header = (EmberMessageBuffer *)header; + xncp_message_buffer_t *msg_header = (xncp_message_buffer_t *)header; ManualSourceRoute *route = get_manual_source_route(destination); if (route == NULL) { @@ -154,7 +153,7 @@ void nc_zigbee_override_append_source_route(uint16_t destination, sli_zigbee_route_table_entry_t *route_table_entry = find_free_routing_table_entry(route->destination); route_table_entry->destination = route->destination; route_table_entry->nextHop = route->destination; - route_table_entry->status = EMBER_ROUTE_ACTIVE; + route_table_entry->status = ROUTE_ACTIVE; route_table_entry->cost = 0; route_table_entry->networkIndex = 0; return; @@ -164,29 +163,29 @@ void nc_zigbee_override_append_source_route(uint16_t destination, route->active = false; // Disable the route after a single use - emberAppendToLinkedBuffers(*msg_header, &route->num_relays, 1); - emberAppendToLinkedBuffers(*msg_header, &relay_index, 1); + xncp_append_to_linked_buffers(*msg_header, &route->num_relays, 1); + xncp_append_to_linked_buffers(*msg_header, &relay_index, 1); for (uint8_t i = 0; i < route->num_relays; i++) { - emberAppendToLinkedBuffers(*msg_header, (uint8_t*)&route->relays[route->num_relays - i - 1], 2); + xncp_append_to_linked_buffers(*msg_header, (uint8_t*)&route->relays[route->num_relays - i - 1], 2); } } static bool handle_set_source_route(xncp_context_t *ctx) { if ((ctx->payload_length < 2) || (ctx->payload_length % 2 != 0)) { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } uint8_t num_relays = (ctx->payload_length - 2) / 2; - if (num_relays > EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT) { - *ctx->status = EMBER_BAD_ARGUMENT; + if (num_relays > XNCP_MAX_SOURCE_ROUTE_RELAY_COUNT) { + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } - uint8_t insertion_index = emberGetPseudoRandomNumber() % XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; + uint8_t insertion_index = xncp_get_pseudo_random_number() % XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; uint16_t node_id = BUILD_UINT16(ctx->payload[0], ctx->payload[1]); for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { @@ -211,7 +210,7 @@ static bool handle_set_source_route(xncp_context_t *ctx) route->num_relays = num_relays; route->active = true; - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } @@ -222,13 +221,13 @@ static bool handle_set_source_route(xncp_context_t *ctx) static bool handle_set_route_table_entry(xncp_context_t *ctx) { if (ctx->payload_length != 7) { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } uint8_t route_table_index = ctx->payload[0]; if (route_table_index >= sli_zigbee_route_table_size) { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } @@ -239,20 +238,20 @@ static bool handle_set_route_table_entry(xncp_context_t *ctx) entry->cost = ctx->payload[6]; entry->networkIndex = 0; - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } static bool handle_get_route_table_entry(xncp_context_t *ctx) { if (ctx->payload_length != 1) { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } uint8_t route_table_index = ctx->payload[0]; if (route_table_index >= sli_zigbee_route_table_size) { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } @@ -267,7 +266,7 @@ static bool handle_get_route_table_entry(xncp_context_t *ctx) ctx->reply[(*ctx->reply_length)++] = entry->status; ctx->reply[(*ctx->reply_length)++] = entry->cost; - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } @@ -278,7 +277,7 @@ static bool handle_get_route_table_entry(xncp_context_t *ctx) static bool handle_get_mfg_token_override(xncp_context_t *ctx) { if (ctx->payload_length != 1) { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } @@ -286,16 +285,16 @@ static bool handle_get_mfg_token_override(xncp_context_t *ctx) char *override_value; switch (token_id) { - case EZSP_MFG_STRING: + case SL_ZIGBEE_EZSP_MFG_STRING: override_value = XNCP_MFG_MANUF_NAME; break; - case EZSP_MFG_BOARD_NAME: + case SL_ZIGBEE_EZSP_MFG_BOARD_NAME: override_value = XNCP_MFG_BOARD_NAME; break; default: - *ctx->status = EMBER_NOT_FOUND; + *ctx->status = XNCP_STATUS_NOT_FOUND; return true; } @@ -303,7 +302,7 @@ static bool handle_get_mfg_token_override(xncp_context_t *ctx) memcpy(ctx->reply + *ctx->reply_length, override_value, value_length); *ctx->reply_length += value_length; - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } @@ -313,7 +312,7 @@ static bool handle_get_build_string(xncp_context_t *ctx) memcpy(ctx->reply + *ctx->reply_length, XNCP_BUILD_STRING, value_length); *ctx->reply_length += value_length; - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } @@ -334,7 +333,7 @@ static bool handle_get_flow_control_type(xncp_context_t *ctx) ctx->reply[(*ctx->reply_length)++] = (uint8_t)(flow_control_type & 0xFF); - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } @@ -353,7 +352,7 @@ static bool handle_get_chip_info(xncp_context_t *ctx) memcpy(ctx->reply + *ctx->reply_length, PART_NUMBER, value_length); *ctx->reply_length += value_length; - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } @@ -361,14 +360,14 @@ static bool handle_get_chip_info(xncp_context_t *ctx) static bool handle_get_tx_power_info(xncp_context_t *ctx) { if (ctx->payload_length != 2) { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } - + CountryTxPower result; get_tx_power_for_country(ctx->payload[0], ctx->payload[1], &result); - - *ctx->status = EMBER_SUCCESS; + + *ctx->status = XNCP_STATUS_OK; ctx->reply[(*ctx->reply_length)++] = (uint8_t)result.recommended_power_dbm; ctx->reply[(*ctx->reply_length)++] = (uint8_t)result.max_power_dbm; diff --git a/src/zigbee_ncp/extension/xncp_extension/inc/xncp_types.h b/src/zigbee_ncp/extension/xncp_extension/inc/xncp_types.h index 68a9b0b6..7bd26a20 100644 --- a/src/zigbee_ncp/extension/xncp_extension/inc/xncp_types.h +++ b/src/zigbee_ncp/extension/xncp_extension/inc/xncp_types.h @@ -10,6 +10,51 @@ #include #include +// SDK compatibility layer +#ifdef STACK_TYPES_HEADER +// Simplicity SDK (2025.x) +#include "stack/include/sl_zigbee.h" +#include "stack/include/sl_zigbee_types_internal.h" +#include "stack/include/message.h" + +typedef sl_status_t xncp_status_t; +#define XNCP_STATUS_OK SL_STATUS_OK +#define XNCP_STATUS_BAD_ARGUMENT SL_STATUS_INVALID_PARAMETER +#define XNCP_STATUS_NOT_FOUND SL_STATUS_NOT_FOUND + +#define XNCP_MAX_SOURCE_ROUTE_RELAY_COUNT SL_ZIGBEE_MAX_SOURCE_ROUTE_RELAY_COUNT + +typedef sl_zigbee_multicast_id_t xncp_multicast_id_t; +typedef sl_802154_short_addr_t xncp_node_id_t; +typedef sli_buffer_manager_buffer_t xncp_message_buffer_t; + +#define xncp_get_pseudo_random_number sl_zigbee_get_pseudo_random_number +#define xncp_append_to_linked_buffers sl_legacy_buffer_manager_append_to_linked_buffers + +#else +// Gecko SDK (4.x) +#include "ember.h" + +typedef EmberStatus xncp_status_t; +#define XNCP_STATUS_OK EMBER_SUCCESS +#define XNCP_STATUS_BAD_ARGUMENT EMBER_BAD_ARGUMENT +#define XNCP_STATUS_NOT_FOUND EMBER_NOT_FOUND + +#define XNCP_MAX_SOURCE_ROUTE_RELAY_COUNT EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + +typedef EmberMulticastId xncp_multicast_id_t; +typedef EmberNodeId xncp_node_id_t; +typedef EmberMessageBuffer xncp_message_buffer_t; + +#define xncp_get_pseudo_random_number emberGetPseudoRandomNumber +#define xncp_append_to_linked_buffers emberAppendToLinkedBuffers + +// EZSP enum aliases for new SDK names +#define SL_ZIGBEE_EZSP_MFG_STRING EZSP_MFG_STRING +#define SL_ZIGBEE_EZSP_MFG_BOARD_NAME EZSP_MFG_BOARD_NAME + +#endif + // Feature flags - components OR these together #define XNCP_FEATURE_MEMBER_OF_ALL_GROUPS (1UL << 0) #define XNCP_FEATURE_MANUAL_SOURCE_ROUTE (1UL << 1) diff --git a/src/zigbee_ncp/extension/xncp_extension/src/xncp_core.c b/src/zigbee_ncp/extension/xncp_extension/src/xncp_core.c index 40578aee..683095e5 100644 --- a/src/zigbee_ncp/extension/xncp_extension/src/xncp_core.c +++ b/src/zigbee_ncp/extension/xncp_extension/src/xncp_core.c @@ -6,21 +6,20 @@ #include "xncp_types.h" #include "xncp_dispatcher.h" -#include "ember.h" #define BUILD_UINT16(low, high) (((uint16_t)(low)) | ((uint16_t)(high) << 8)) -EmberStatus emberAfPluginXncpIncomingCustomFrameCallback( +static xncp_status_t xncp_incoming_custom_frame_handler( uint8_t messageLength, uint8_t *messagePayload, uint8_t *replyPayloadLength, uint8_t *replyPayload) { - uint8_t rsp_status = EMBER_SUCCESS; + uint8_t rsp_status = XNCP_STATUS_OK; uint16_t rsp_command_id = XNCP_CMD_UNKNOWN; if (messageLength < 3) { - rsp_status = EMBER_BAD_ARGUMENT; + rsp_status = XNCP_STATUS_BAD_ARGUMENT; goto respond; } @@ -57,12 +56,34 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback( }; if (!xncp_dispatch_command(&ctx)) { - rsp_status = EMBER_NOT_FOUND; + rsp_status = XNCP_STATUS_NOT_FOUND; } respond: replyPayload[0] = (uint8_t)((rsp_command_id >> 0) & 0xFF); replyPayload[1] = (uint8_t)((rsp_command_id >> 8) & 0xFF); replyPayload[2] = rsp_status; - return EMBER_SUCCESS; + return XNCP_STATUS_OK; +} + +#ifdef STACK_TYPES_HEADER +sl_status_t sl_zigbee_af_xncp_incoming_custom_frame_cb( + uint8_t messageLength, + uint8_t *messagePayload, + uint8_t *replyPayloadLength, + uint8_t *replyPayload) +{ + return xncp_incoming_custom_frame_handler(messageLength, messagePayload, + replyPayloadLength, replyPayload); +} +#else +EmberStatus emberAfPluginXncpIncomingCustomFrameCallback( + uint8_t messageLength, + uint8_t *messagePayload, + uint8_t *replyPayloadLength, + uint8_t *replyPayload) +{ + return xncp_incoming_custom_frame_handler(messageLength, messagePayload, + replyPayloadLength, replyPayload); } +#endif diff --git a/src/zigbee_ncp/extension/xncp_zbt2_extension/src/xncp_zbt2_commands.c b/src/zigbee_ncp/extension/xncp_zbt2_extension/src/xncp_zbt2_commands.c index ffc55180..87236a37 100644 --- a/src/zigbee_ncp/extension/xncp_zbt2_extension/src/xncp_zbt2_commands.c +++ b/src/zigbee_ncp/extension/xncp_zbt2_extension/src/xncp_zbt2_commands.c @@ -12,7 +12,6 @@ #include "led_manager.h" #include "sl_i2cspm_instances.h" #include "sl_simple_rgb_pwm_led.h" -#include "ember.h" #include //------------------------------------------------------------------------------ @@ -49,13 +48,13 @@ static bool handle_set_led_state(xncp_context_t *ctx) color.g = ((uint16_t)ctx->payload[2] << 8) | ctx->payload[3]; color.b = ((uint16_t)ctx->payload[4] << 8) | ctx->payload[5]; } else { - *ctx->status = EMBER_BAD_ARGUMENT; + *ctx->status = XNCP_STATUS_BAD_ARGUMENT; return true; } led_manager_set_color(LED_PRIORITY_MANUAL, color); - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } @@ -76,6 +75,6 @@ static bool handle_get_accelerometer(xncp_context_t *ctx) memcpy(ctx->reply + *ctx->reply_length, (uint8_t*)&xyz[2], sizeof(float)); *ctx->reply_length += sizeof(float); - *ctx->status = EMBER_SUCCESS; + *ctx->status = XNCP_STATUS_OK; return true; } From 100bd2bbbabac86923e2f40b232734288393f0eb Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Fri, 19 Dec 2025 19:14:37 -0500 Subject: [PATCH 03/30] Ensure `sl_zigbee_version` isn't stripped by LTO --- src/zigbee_ncp/zigbee_ncp.slcp | 6 ++++++ tools/create_gbl.py | 13 ++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index b004be0f..9fd052d1 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -44,6 +44,12 @@ define: - name: SL_ZIGBEE_CUSTOM_MAC_FILTER_TABLE_SIZE value: 15 +# Prevent LTO from stripping sl_zigbee_version, which is read from the ELF +# by create_gbl.py to extract the EZSP version for firmware metadata. +toolchain_settings: + - option: gcc_linker_option + value: "-Wl,--undefined=sl_zigbee_version" + configuration: - name: SL_CLI_MAX_INPUT_ARGUMENTS value: 16 diff --git a/tools/create_gbl.py b/tools/create_gbl.py index 1a9755b9..0ae50c95 100755 --- a/tools/create_gbl.py +++ b/tools/create_gbl.py @@ -23,7 +23,7 @@ def _jump_to_elf_symbol(file: BinaryIO, symbol_name: str) -> tuple[ELFFile, int, symtab = elf.get_section_by_name(".symtab") symbols = symtab.get_symbol_by_name(symbol_name) - if len(symbols) != 1: + if symbols is None or len(symbols) != 1: raise ValueError(f"Expected one symbol for {symbol_name!r}, got {symbols}") symbol = symbols[0] @@ -216,7 +216,14 @@ def main(): elf = list(build_dir.glob("*.out"))[0] with elf.open("rb") as f: - ember_version = read_elf_symbol(f, "emberVersion") + # Try new SDK symbol name first, fall back to old + try: + ember_version = read_elf_symbol(f, "sl_zigbee_version") + version_symbol = "sl_zigbee_version" + except (ValueError, TypeError): + f.seek(0) + ember_version = read_elf_symbol(f, "emberVersion") + version_symbol = "emberVersion" ( build, @@ -247,7 +254,7 @@ def main(): version_type, padding, ) - ember_version = modify_elf_symbol(f, "emberVersion", new_ember_version) + modify_elf_symbol(f, version_symbol, new_ember_version) metadata["ezsp_version"] = f"{major}.{minor}.{patch}.{special}" From bf1f14eef0b36bf357cc69bd5936d18524be1dae Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Thu, 1 Jan 2026 16:55:48 -0500 Subject: [PATCH 04/30] Migrate all YAML config --- .../skyconnect/skyconnect_zigbee_ncp.yaml | 27 +++++------ .../nabucasa/yellow/yellow_zigbee_ncp.yaml | 29 ++++++------ manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 47 +++++++++---------- 3 files changed, 50 insertions(+), 53 deletions(-) diff --git a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml index 297628f6..1555e159 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml @@ -2,7 +2,7 @@ name: SkyConnect Zigbee device: EFR32MG21A020F512IM32 base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" -sdk: "gecko_sdk:4.5.0" +sdk: "simplicity_sdk:2025.6.2" toolchain: "12.2.1.20221205" gbl: @@ -32,19 +32,18 @@ c_defines: XNCP_BUILD_STRING: template:"{now:%Y%m%d%H%M%S}" XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE: 200 - EMBER_APS_UNICAST_MESSAGE_COUNT: 32 - EMBER_BINDING_TABLE_SIZE: 32 - EMBER_BROADCAST_TABLE_SIZE: 64 - EMBER_KEY_TABLE_SIZE: 12 - EMBER_MAX_END_DEVICE_CHILDREN: 32 - EMBER_PACKET_BUFFER_COUNT: 255 - EMBER_SOURCE_ROUTE_TABLE_SIZE: 200 + SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 32 + SL_ZIGBEE_BINDING_TABLE_SIZE: 32 + SL_ZIGBEE_BROADCAST_TABLE_SIZE: 64 + SL_ZIGBEE_KEY_TABLE_SIZE: 12 + SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 32 + SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 200 - EMBER_CHILD_TABLE_SIZE: + SL_ZIGBEE_CHILD_TABLE_SIZE: type: c_flag value: 32 - EMBER_ROUTE_TABLE_SIZE: + SL_ZIGBEE_ROUTE_TABLE_SIZE: type: c_flag value: 250 @@ -54,13 +53,13 @@ c_defines: SL_IOSTREAM_USART_VCOM_PERIPHERAL: USART0 SL_IOSTREAM_USART_VCOM_PERIPHERAL_NO: 0 - SL_IOSTREAM_USART_VCOM_TX_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_TX_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_TX_PIN: 6 - SL_IOSTREAM_USART_VCOM_RX_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_RX_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_RX_PIN: 5 - SL_IOSTREAM_USART_VCOM_CTS_PORT: gpioPortB + SL_IOSTREAM_USART_VCOM_CTS_PORT: SL_GPIO_PORT_B SL_IOSTREAM_USART_VCOM_CTS_PIN: 1 - SL_IOSTREAM_USART_VCOM_RTS_PORT: gpioPortB + SL_IOSTREAM_USART_VCOM_RTS_PORT: SL_GPIO_PORT_B SL_IOSTREAM_USART_VCOM_RTS_PIN: 0 SL_IOSTREAM_USART_VCOM_RX_BUFFER_SIZE: 128 diff --git a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml index 83a8e76f..b34fe5cc 100644 --- a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml +++ b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml @@ -2,7 +2,7 @@ name: Yellow Zigbee device: MGM210PA32JIA base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" -sdk: "gecko_sdk:4.5.0" +sdk: "simplicity_sdk:2025.6.2" toolchain: "12.2.1.20221205" gbl: @@ -40,19 +40,18 @@ c_defines: XNCP_BUILD_STRING: template:"{now:%Y%m%d%H%M%S}" XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE: 200 - EMBER_APS_UNICAST_MESSAGE_COUNT: 32 - EMBER_BINDING_TABLE_SIZE: 32 - EMBER_BROADCAST_TABLE_SIZE: 64 - EMBER_KEY_TABLE_SIZE: 12 - EMBER_MAX_END_DEVICE_CHILDREN: 32 - EMBER_PACKET_BUFFER_COUNT: 255 - EMBER_SOURCE_ROUTE_TABLE_SIZE: 200 + SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 32 + SL_ZIGBEE_BINDING_TABLE_SIZE: 32 + SL_ZIGBEE_BROADCAST_TABLE_SIZE: 64 + SL_ZIGBEE_KEY_TABLE_SIZE: 12 + SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 32 + SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 200 - EMBER_CHILD_TABLE_SIZE: + SL_ZIGBEE_CHILD_TABLE_SIZE: type: c_flag value: 32 - EMBER_ROUTE_TABLE_SIZE: + SL_ZIGBEE_ROUTE_TABLE_SIZE: type: c_flag value: 250 @@ -62,19 +61,19 @@ c_defines: SL_IOSTREAM_USART_VCOM_PERIPHERAL: USART0 SL_IOSTREAM_USART_VCOM_PERIPHERAL_NO: 0 - SL_IOSTREAM_USART_VCOM_TX_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_TX_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_TX_PIN: 5 - SL_IOSTREAM_USART_VCOM_RX_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_RX_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_RX_PIN: 6 - SL_IOSTREAM_USART_VCOM_CTS_PORT: gpioPortD + SL_IOSTREAM_USART_VCOM_CTS_PORT: SL_GPIO_PORT_D SL_IOSTREAM_USART_VCOM_CTS_PIN: 2 - SL_IOSTREAM_USART_VCOM_RTS_PORT: gpioPortC + SL_IOSTREAM_USART_VCOM_RTS_PORT: SL_GPIO_PORT_C SL_IOSTREAM_USART_VCOM_RTS_PIN: 1 SL_IOSTREAM_USART_VCOM_RX_BUFFER_SIZE: 128 SL_SIMPLE_LED_BOARD_ACTIVITY_POLARITY: SL_SIMPLE_LED_POLARITY_ACTIVE_LOW - SL_SIMPLE_LED_BOARD_ACTIVITY_PORT: gpioPortB + SL_SIMPLE_LED_BOARD_ACTIVITY_PORT: SL_GPIO_PORT_B SL_SIMPLE_LED_BOARD_ACTIVITY_PIN: 1 BOARD_ACTIVITY_LED_INSTANCE: sl_led_board_activity diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index 2e7929dd..dddc78f7 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -2,7 +2,7 @@ name: Home Assistant Connect ZBT-2 Zigbee device: EFR32MG24A420F1536IM40 base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}_{fw_variant}" -sdk: "gecko_sdk:4.5.0" +sdk: "simplicity_sdk:2025.6.2" toolchain: "12.2.1.20221205" gbl: @@ -71,25 +71,24 @@ c_defines: # should not use hardware flow control. XNCP_FLOW_CONTROL_TYPE: usartHwFlowControlNone - EMBER_APS_UNICAST_MESSAGE_COUNT: 32 - EMBER_BINDING_TABLE_SIZE: 32 - EMBER_BROADCAST_TABLE_SIZE: 64 - EMBER_KEY_TABLE_SIZE: 12 - EMBER_MAX_END_DEVICE_CHILDREN: 32 - EMBER_PACKET_BUFFER_COUNT: 255 - EMBER_SOURCE_ROUTE_TABLE_SIZE: 200 + SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 32 + SL_ZIGBEE_BINDING_TABLE_SIZE: 32 + SL_ZIGBEE_BROADCAST_TABLE_SIZE: 64 + SL_ZIGBEE_KEY_TABLE_SIZE: 12 + SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 32 + SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 200 - EMBER_CHILD_TABLE_SIZE: + SL_ZIGBEE_CHILD_TABLE_SIZE: type: c_flag value: 32 - EMBER_ROUTE_TABLE_SIZE: + SL_ZIGBEE_ROUTE_TABLE_SIZE: type: c_flag value: 250 - SL_DEVICE_INIT_HFXO_FREQ: 39000000 - SL_DEVICE_INIT_HFXO_PRECISION: 10 - SL_DEVICE_INIT_HFXO_CTUNE: 108 + SL_CLOCK_MANAGER_HFXO_FREQ: 39000000 + SL_CLOCK_MANAGER_HFXO_PRECISION: 10 + SL_CLOCK_MANAGER_HFXO_CTUNE: 108 SL_IOSTREAM_USART_VCOM_BAUDRATE: 460800 SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE: usartHwFlowControlCtsAndRts @@ -97,13 +96,13 @@ c_defines: SL_IOSTREAM_USART_VCOM_PERIPHERAL: USART0 SL_IOSTREAM_USART_VCOM_PERIPHERAL_NO: 0 - SL_IOSTREAM_USART_VCOM_TX_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_TX_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_TX_PIN: 8 - SL_IOSTREAM_USART_VCOM_RX_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_RX_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_RX_PIN: 7 - SL_IOSTREAM_USART_VCOM_CTS_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_CTS_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_CTS_PIN: 5 - SL_IOSTREAM_USART_VCOM_RTS_PORT: gpioPortA + SL_IOSTREAM_USART_VCOM_RTS_PORT: SL_GPIO_PORT_A SL_IOSTREAM_USART_VCOM_RTS_PIN: 0 SL_IOSTREAM_USART_VCOM_RX_BUFFER_SIZE: 128 @@ -111,28 +110,28 @@ c_defines: # WS2812 LED driver SL_SPIDRV_EUSART_WS2812_PERIPHERAL: EUSART1 SL_SPIDRV_EUSART_WS2812_PERIPHERAL_NO: 1 - SL_SPIDRV_EUSART_WS2812_TX_PORT: gpioPortC + SL_SPIDRV_EUSART_WS2812_TX_PORT: SL_GPIO_PORT_C SL_SPIDRV_EUSART_WS2812_TX_PIN: 2 - SL_SPIDRV_EUSART_WS2812_RX_PORT: gpioPortC + SL_SPIDRV_EUSART_WS2812_RX_PORT: SL_GPIO_PORT_C SL_SPIDRV_EUSART_WS2812_RX_PIN: 1 - SL_SPIDRV_EUSART_WS2812_SCLK_PORT: gpioPortD + SL_SPIDRV_EUSART_WS2812_SCLK_PORT: SL_GPIO_PORT_D SL_SPIDRV_EUSART_WS2812_SCLK_PIN: 2 SL_SPIDRV_EUSART_WS2812_CS_CONTROL: spidrvCsControlApplication SL_SPIDRV_EUSART_WS2812_BITRATE: 3200000 SL_SPIDRV_EUSART_WS2812_BIT_ORDER: spidrvBitOrderMsbFirst - WS2812_EN_PORT: gpioPortC + WS2812_EN_PORT: SL_GPIO_PORT_C WS2812_EN_PIN: 3 WS2812_NUM_LEDS: 4 # I2C SL_I2CSPM_INST_PERIPHERAL: I2C0 - SL_I2CSPM_INST_SCL_PORT: gpioPortC + SL_I2CSPM_INST_SCL_PORT: SL_GPIO_PORT_C SL_I2CSPM_INST_SCL_PIN: 6 - SL_I2CSPM_INST_SDA_PORT: gpioPortC + SL_I2CSPM_INST_SDA_PORT: SL_GPIO_PORT_C SL_I2CSPM_INST_SDA_PIN: 7 # Pinhole button - SL_SIMPLE_BUTTON_PIN_HOLE_BUTTON_PORT: gpioPortC + SL_SIMPLE_BUTTON_PIN_HOLE_BUTTON_PORT: SL_GPIO_PORT_C SL_SIMPLE_BUTTON_PIN_HOLE_BUTTON_PIN: 5 # Product ID to prevent cross-flashing across devices From d636fe9a38a1d4a523b4880d51bc55858a06cf9f Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Thu, 1 Jan 2026 17:54:41 -0500 Subject: [PATCH 05/30] Fix compilation for Yellow --- manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml index b34fe5cc..7f33eb8d 100644 --- a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml +++ b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml @@ -34,7 +34,14 @@ add_components: vendor: nabucasa package: xncp_common +# SLC validates clock settings before c_defines are patched, use `configuration` +configuration: + SL_CLOCK_MANAGER_PCLK_DIVIDER: SL_CLOCK_MANAGER_PCLK_DIV_MIN + c_defines: + # SDK bug: the PCLK divider is set to 1 for the MGM210, it is set to 2 everywhere else + SL_CLOCK_MANAGER_PCLK_DIVIDER: SL_CLOCK_MANAGER_PCLK_DIV_MIN + XNCP_MFG_MANUF_NAME: '"Nabu Casa"' XNCP_MFG_BOARD_NAME: '"Home Assistant Yellow"' XNCP_BUILD_STRING: template:"{now:%Y%m%d%H%M%S}" From 8222f37c1511b856ed0de936fb6ec305b213ef51 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:00:32 -0400 Subject: [PATCH 06/30] Bump SSDK to 2026.12.3 --- Dockerfile | 2 +- .../skyconnect/skyconnect_openthread_rcp.yaml | 2 +- .../skyconnect/skyconnect_zigbee_ncp.yaml | 2 +- .../yellow/yellow_openthread_rcp.yaml | 2 +- .../nabucasa/yellow/yellow_zigbee_ncp.yaml | 2 +- .../nabucasa/zbt2/zbt2_openthread_rcp.yaml | 2 +- manifests/nabucasa/zbt2/zbt2_router.yaml | 2 +- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 2 +- tools/build_project.py | 3 +++ tools/create_gbl.py | 19 ++++++++++++++++--- 10 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 221d6d9e..3d1934bd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -134,7 +134,7 @@ RUN set -e \ ninja/1.12.1 \ commander/1.23.1 \ slc-cli/6.0.17 \ - simplicity-sdk/2025.6.2 \ + simplicity-sdk/2025.12.3 \ zap/2026.02.26 \ # conan cannot resolve two copies of the same package, even with different versions, # in a single command diff --git a/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml b/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml index 3d8e87df..6cfb7041 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml @@ -2,7 +2,7 @@ name: SkyConnect OpenThread RCP device: EFR32MG21A020F512IM32 base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" -sdk: "simplicity_sdk:2025.6.2" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: diff --git a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml index 1555e159..c7c38332 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml @@ -2,7 +2,7 @@ name: SkyConnect Zigbee device: EFR32MG21A020F512IM32 base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" -sdk: "simplicity_sdk:2025.6.2" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: diff --git a/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml b/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml index b36363c9..53a4035a 100644 --- a/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml +++ b/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml @@ -2,7 +2,7 @@ name: Yellow OpenThread RCP device: MGM210PA32JIA base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" -sdk: "simplicity_sdk:2025.6.2" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: diff --git a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml index 7f33eb8d..bf3957ff 100644 --- a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml +++ b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml @@ -2,7 +2,7 @@ name: Yellow Zigbee device: MGM210PA32JIA base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" -sdk: "simplicity_sdk:2025.6.2" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: diff --git a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml index f7f8acfe..22a0b196 100644 --- a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml @@ -2,7 +2,7 @@ name: Home Assistant Connect ZBT-2 OpenThread RCP device: EFR32MG24A420F1536IM40 base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" -sdk: "simplicity_sdk:2025.6.2" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: diff --git a/manifests/nabucasa/zbt2/zbt2_router.yaml b/manifests/nabucasa/zbt2/zbt2_router.yaml index b934d27f..027aac55 100644 --- a/manifests/nabucasa/zbt2/zbt2_router.yaml +++ b/manifests/nabucasa/zbt2/zbt2_router.yaml @@ -2,7 +2,7 @@ name: Home Assistant Connect ZBT-2 Zigbee Router device: EFR32MG24A420F1536IM40 base_project: src/zigbee_router filename: "{manifest_name}_{sdk_version}" -sdk: "simplicity_sdk:2025.6.2" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index dddc78f7..3eff2524 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -2,7 +2,7 @@ name: Home Assistant Connect ZBT-2 Zigbee device: EFR32MG24A420F1536IM40 base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}_{fw_variant}" -sdk: "simplicity_sdk:2025.6.2" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: diff --git a/tools/build_project.py b/tools/build_project.py index b0a8cf4b..2fb0bad5 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -709,6 +709,8 @@ def main(): args.build_dir.absolute(): "/src", f"{cmake_dir.absolute()}/..": "/src", "/home/buildengineer/jenkins/workspace/Gecko_Workspace/gsdk": f"/src/{sdk_name}_{sdk_version}", + # Zigbee sources reference the GitHub Actions workspace they were packaged in + "/__w/zigbee/zigbee": f"/src/{sdk_name}_{sdk_version}/zigbee", "/home/buildengineer/.silabs/slt/installs/conan/p/cmsisfb920dbb6ad42/p": "/src/vendor/cmsis", "/home/buildengineer/.silabs/slt/installs/conan/p/platf85e95225bc406/p": f"/src/{sdk_name}_{sdk_version}/platform_core", # The Z-Wave SDK isn't part of the Simplicity SDK but is still referenced. If we @@ -728,6 +730,7 @@ def main(): "-Wextra", "-Werror", "-Wno-error=maybe-uninitialized", # Linking fails due to a few SDK bugs + "-Wno-error=unused-function", # mbedTLS `ssl_tls.c` with X.509 hostname verification disabled ] build_flags["CXX_FLAGS"] = build_flags["C_FLAGS"] diff --git a/tools/create_gbl.py b/tools/create_gbl.py index 0ae50c95..860dd9ee 100755 --- a/tools/create_gbl.py +++ b/tools/create_gbl.py @@ -301,14 +301,27 @@ def main(): gbl_dynamic.remove("ot_rcp_version") ot_proj_path = project_root / "config/sl_openthread_generic_config.h" - ot_sdk_path = ( - gsdk_path / "protocol/openthread/include/sl_openthread_package_info.h" + ot_sdk_path = next( + ( + path + for path in ( + # Gecko SDK and Simplicity SDK up to 2025.6.x + ( + gsdk_path + / "protocol/openthread/include/sl_openthread_package_info.h" + ), + # Simplicity SDK 2025.12.0 and above + (gsdk_path / "openthread/include/sl_openthread_package_info.h"), + ) + if path.exists() + ), + None, ) if ot_proj_path.exists(): openthread_config_h = parse_c_header_defines(ot_proj_path.read_text()) metadata["ot_rcp_version"] = openthread_config_h["PACKAGE_STRING"] - elif ot_sdk_path.exists(): + elif ot_sdk_path is not None: openthread_package_info_h = parse_c_header_defines(ot_sdk_path.read_text()) metadata["ot_rcp_version"] = ( openthread_package_info_h["PACKAGE_NAME"] From 64433a0c03547526c3cdc4a73ae074b161419563 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:13:37 -0400 Subject: [PATCH 07/30] Migrate Z-Wave as well Bump Z-Wave version --- Dockerfile | 4 ---- manifests/nabucasa/zwa2/zwa2_controller.yaml | 4 ++-- tools/build_project.py | 1 + 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3d1934bd..7d171f02 100644 --- a/Dockerfile +++ b/Dockerfile @@ -136,10 +136,6 @@ RUN set -e \ slc-cli/6.0.17 \ simplicity-sdk/2025.12.3 \ zap/2026.02.26 \ - # conan cannot resolve two copies of the same package, even with different versions, - # in a single command - && slt --non-interactive install \ - simplicity-sdk/2025.12.1 \ # Clean up download caches to reduce image size && rm -rf /root/.silabs/slt/installs/archive/*.zip \ /root/.silabs/slt/installs/archive/*.tar.* \ diff --git a/manifests/nabucasa/zwa2/zwa2_controller.yaml b/manifests/nabucasa/zwa2/zwa2_controller.yaml index 0c67011c..d7798cf6 100644 --- a/manifests/nabucasa/zwa2/zwa2_controller.yaml +++ b/manifests/nabucasa/zwa2/zwa2_controller.yaml @@ -2,7 +2,7 @@ name: Home Assistant Connect ZWA-2 Z-Wave Controller device: EFR32ZG23A020F512GM40 base_project: src/zwa2_controller filename: "{manifest_name}_{zwave_version}" -sdk: "simplicity_sdk:2025.12.1" +sdk: "simplicity_sdk:2025.12.3" toolchain: "12.2.1.20221205" gbl: fw_type: zwave_ncp @@ -126,7 +126,7 @@ c_defines: # Firmware version (reported in SERIALAPI_CAPABILITIES) # See src/zwa2_controller/README.md for versioning scheme details. USER_APP_VERSION: 1 - USER_APP_REVISION: 2 + USER_APP_REVISION: 3 USER_APP_PATCH: 0 # USART0 serial API pins diff --git a/tools/build_project.py b/tools/build_project.py index 2fb0bad5..f0f2d43c 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -713,6 +713,7 @@ def main(): "/__w/zigbee/zigbee": f"/src/{sdk_name}_{sdk_version}/zigbee", "/home/buildengineer/.silabs/slt/installs/conan/p/cmsisfb920dbb6ad42/p": "/src/vendor/cmsis", "/home/buildengineer/.silabs/slt/installs/conan/p/platf85e95225bc406/p": f"/src/{sdk_name}_{sdk_version}/platform_core", + "/home/buildengineer/.silabs/slt/installs/conan/p/platfe548addd6aec0/p": f"/src/{sdk_name}_{sdk_version}/platform_core", # The Z-Wave SDK isn't part of the Simplicity SDK but is still referenced. If we # ever decide to compile it as part of CI, we can change this remap. "/opt/github/runner/_work/z-wave/z-wave": "/src/vendor/zwave", From 05bfa1a3633dc48fff0447412e3117ea1edc25ed Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:13:28 -0400 Subject: [PATCH 08/30] Release notes --- src/openthread_rcp/CHANGELOG.md | 3 +++ src/zigbee_ncp/CHANGELOG.md | 3 +++ src/zwa2_controller/CHANGELOG.md | 3 +++ src/zwa2_controller/README.md | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/openthread_rcp/CHANGELOG.md b/src/openthread_rcp/CHANGELOG.md index 51763492..dceb38ec 100644 --- a/src/openthread_rcp/CHANGELOG.md +++ b/src/openthread_rcp/CHANGELOG.md @@ -1,3 +1,6 @@ +# SL-OPENTHREAD/3.0.2.0_GitHub-61e43cffb +This beta release is built with OpenThread 3.0.2 from Simplicity SDK 2025.12.3. + # SL-OPENTHREAD/2.7.2.0_GitHub-fb0446f53 This beta release is built with Simplicity SDK 2025.6.2. diff --git a/src/zigbee_ncp/CHANGELOG.md b/src/zigbee_ncp/CHANGELOG.md index b4cdad3a..e8cd58ec 100644 --- a/src/zigbee_ncp/CHANGELOG.md +++ b/src/zigbee_ncp/CHANGELOG.md @@ -1,3 +1,6 @@ +# 9.0.2.0 +Beta release built with EmberZNet 9.0 from Simplicity SDK 2025.12.3. This is our first release that migrates from the older Gecko SDK to the newer Simplicity SDK. + # 7.5.1.0 Beta release built with Gecko SDK 4.5.0. This includes a new feature to restore routes on adapter startup, speeding up network responsiveness after a reset. diff --git a/src/zwa2_controller/CHANGELOG.md b/src/zwa2_controller/CHANGELOG.md index 12f6d3b9..e46f8afe 100644 --- a/src/zwa2_controller/CHANGELOG.md +++ b/src/zwa2_controller/CHANGELOG.md @@ -1,3 +1,6 @@ +# 1.3.0 +* SDK updated to Simplicity SDK 2025.12.3 (Z-Wave SDK 8.0.2) + # 1.2.0 * SDK updated to Simplicity SDK 2025.12.1. diff --git a/src/zwa2_controller/README.md b/src/zwa2_controller/README.md index 08524e00..075285e9 100644 --- a/src/zwa2_controller/README.md +++ b/src/zwa2_controller/README.md @@ -22,11 +22,14 @@ Examples: | `0` | [`2024.12.1`][sisdk-2024.12.1] | [`7.23.1`][zdk-7.23.1] | | `1` | [`2024.12.2`][sisdk-2024.12.2] | [`7.23.2`][zdk-7.23.2] | | `2` | [`2025.12.1`][sisdk-2025.12.1] | [`8.0.0`][zdk-8.0.0] | +| `3` | [`2025.12.3`][sisdk-2025.12.3] | [`8.0.2`][zdk-8.0.2] | [sisdk-2024.12.1]: https://github.com/SiliconLabs/simplicity_sdk/releases/tag/v2024.12.1-0 [sisdk-2024.12.2]: https://github.com/SiliconLabs/simplicity_sdk/releases/tag/v2024.12.2 [sisdk-2025.12.1]: https://docs.silabs.com/sisdk-release-notes/2025.12.1/sisdk-release-notes-overview/ +[sisdk-2025.12.3]: https://docs.silabs.com/sisdk-release-notes/2025.12.3/sisdk-release-notes-overview/ [zdk-7.23.1]: https://www.silabs.com/documents/public/release-notes/SRN14930-7.23.1.0.pdf [zdk-7.23.2]: https://www.silabs.com/documents/public/release-notes/SRN14930-7.23.2.0.pdf [zdk-8.0.0]: https://docs.silabs.com/sisdk-release-notes/2025.12.1/sisdk-zwave-release-notes/ +[zdk-8.0.2]: https://docs.silabs.com/sisdk-release-notes/2025.12.3/sisdk-zwave-release-notes/ From 286fbfd15012ebbf371211fc388e7118a375f892 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:13:49 -0400 Subject: [PATCH 09/30] Get router firmware compiling --- .../src/zbt2_router_callbacks.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c b/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c index bbd43a98..77006bcc 100644 --- a/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c +++ b/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c @@ -192,6 +192,8 @@ static void sync_light_state(uint8_t endpoint) // Commissioning event handler - starts network steering static void commissioning_retry_event_handler(sl_zigbee_af_event_t *event) { + (void)event; + if (sl_zigbee_af_network_state() != SL_ZIGBEE_JOINED_NETWORK) { // Switch from white pulse (ready) to blue pulse (searching) led_pattern_t search_pattern = { @@ -248,6 +250,10 @@ void sl_zigbee_af_network_steering_complete_cb(sl_status_t status, uint8_t joinAttempts, uint8_t finalState) { + (void)totalBeacons; + (void)joinAttempts; + (void)finalState; + sl_zigbee_app_debug_println("Network steering complete: 0x%X", status); if (status != SL_STATUS_OK) { @@ -268,6 +274,11 @@ void sl_zigbee_af_post_attribute_change_cb(uint8_t endpoint, uint8_t size, uint8_t* value) { + (void)manufacturerCode; + (void)type; + (void)size; + (void)value; + if (mask != CLUSTER_MASK_SERVER) { return; } From c37f17a7464f26cbf307fda4bab45d5fe00687d4 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:13:59 -0400 Subject: [PATCH 10/30] Fix router firmware blue pulse effect bug --- .../nabucasa_hardware_extension/src/zbt2_router_callbacks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c b/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c index 77006bcc..f192c087 100644 --- a/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c +++ b/extension/nabucasa_hardware_extension/src/zbt2_router_callbacks.c @@ -200,7 +200,9 @@ static void commissioning_retry_event_handler(sl_zigbee_af_event_t *event) .mode = LED_MODE_PULSE, .color = LED_COLOR_SEARCH_BLUE, .period_ms = 2760, - .duration_ms = 0 + .duration_ms = 0, + .brightness_min = 6554, // ~10% + .brightness_max = 65535, }; led_manager_set_pattern(LED_PRIORITY_BACKGROUND, &search_pattern); From 68bfef769065f885936f724813cdd334ad5768c2 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 25 Jan 2026 20:25:49 -0500 Subject: [PATCH 11/30] Zigbee 4.0 router? --- .../nabucasa/zbt2/config/zcl/zcl_config.zap | 136 ++++++++++++++++++ src/zigbee_router/zigbee_router.slcp | 15 +- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/manifests/nabucasa/zbt2/config/zcl/zcl_config.zap b/manifests/nabucasa/zbt2/config/zcl/zcl_config.zap index d5e45f1a..3eea84ea 100644 --- a/manifests/nabucasa/zbt2/config/zcl/zcl_config.zap +++ b/manifests/nabucasa/zbt2/config/zcl/zcl_config.zap @@ -758,6 +758,142 @@ } ] }, + { + "name": "Poll Control", + "code": 32, + "mfgCode": null, + "define": "POLL_CONTROL_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "CheckInResponse", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CheckIn", + "code": 0, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FastPollStop", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Keep-Alive", + "code": 37, + "mfgCode": null, + "define": "KEEPALIVE_CLUSTER", + "side": "client", + "enabled": 1, + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Keep-Alive", + "code": 37, + "mfgCode": null, + "define": "KEEPALIVE_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Keep-Alive Base", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "1", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Keep-Alive Jitter", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "60", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Color Control", "code": 768, diff --git a/src/zigbee_router/zigbee_router.slcp b/src/zigbee_router/zigbee_router.slcp index ac455e17..01021d6b 100644 --- a/src/zigbee_router/zigbee_router.slcp +++ b/src/zigbee_router/zigbee_router.slcp @@ -53,7 +53,14 @@ component: - id: zigbee_basic - id: zigbee_scan_dispatch - id: zigbee_update_tc_link_key + - id: zigbee_update_app_link_key + - id: zigbee_security_link_keys - id: clock_manager + - id: zigbee_dynamic_commissioning + - id: zigbee_trust_center_keepalive + - id: zigbee_poll_control_client + - id: zigbee_bdb_3dot1_rejoin_algorithm + - id: zigbee_bdb_3dot1_trust_center_extension - id: zigbee_application_bootloader # Platform - enable LTO for gcc - id: toolchain_gcc_lto @@ -87,7 +94,7 @@ configuration: - name: SLI_ZIGBEE_PRIMARY_NETWORK_DEVICE_TYPE value: SLI_ZIGBEE_NETWORK_DEVICE_TYPE_ROUTER - name: SLI_ZIGBEE_PRIMARY_NETWORK_SECURITY_TYPE - value: SLI_ZIGBEE_NETWORK_SECURITY_TYPE_3_0 + value: SLI_ZIGBEE_NETWORK_SECURITY_TYPE_4_0 - name: SL_CLI_PROMPT_STRING value: "\"zigbee_router>\"" - name: NVM3_DEFAULT_NVM_SIZE @@ -165,6 +172,12 @@ configuration: value: 2000 condition: - device_series_3 + - name: SL_ZIGBEE_AF_PLUGIN_NETWORK_STEERING_ENABLE_AUTOSTART + value: 0 + - name: SL_ZIGBEE_AF_PLUGIN_TRUST_CENTER_KEEPALIVE_DEFAULT_BASE_PERIOD_MINUTES + value: 1 + - name: SL_ZIGBEE_AF_PLUGIN_TRUST_CENTER_KEEPALIVE_DEFAULT_JITTER_PERIOD_SECONDS + value: 30 source: - path: main.c From 21db05ce62d0a092b29f31c4ec4ce48cf39c09ab Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:20:18 -0400 Subject: [PATCH 12/30] Test: use Z2M config tweaks --- .../skyconnect/skyconnect_zigbee_ncp.yaml | 12 +++++++++- .../nabucasa/yellow/yellow_zigbee_ncp.yaml | 12 +++++++++- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 22 ++++++++++++++----- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml index c7c38332..358f88f5 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml @@ -32,12 +32,14 @@ c_defines: XNCP_BUILD_STRING: template:"{now:%Y%m%d%H%M%S}" XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE: 200 - SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 32 + SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 64 SL_ZIGBEE_BINDING_TABLE_SIZE: 32 SL_ZIGBEE_BROADCAST_TABLE_SIZE: 64 SL_ZIGBEE_KEY_TABLE_SIZE: 12 SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 32 SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 200 + SL_ZIGBEE_NEIGHBOR_TABLE_SIZE: 26 + SL_ZIGBEE_ADDRESS_TABLE_SIZE: 32 SL_ZIGBEE_CHILD_TABLE_SIZE: type: c_flag @@ -47,6 +49,14 @@ c_defines: type: c_flag value: 250 + SL_ZIGBEE_MULTICAST_TABLE_SIZE: + type: c_flag + value: 26 + + SL_ZIGBEE_DISCOVERY_TABLE_SIZE: + type: c_flag + value: 8 + SL_IOSTREAM_USART_VCOM_BAUDRATE: 115200 SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE: usartHwFlowControlCtsAndRts diff --git a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml index bf3957ff..adf0e989 100644 --- a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml +++ b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml @@ -47,12 +47,14 @@ c_defines: XNCP_BUILD_STRING: template:"{now:%Y%m%d%H%M%S}" XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE: 200 - SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 32 + SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 64 SL_ZIGBEE_BINDING_TABLE_SIZE: 32 SL_ZIGBEE_BROADCAST_TABLE_SIZE: 64 SL_ZIGBEE_KEY_TABLE_SIZE: 12 SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 32 SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 200 + SL_ZIGBEE_NEIGHBOR_TABLE_SIZE: 26 + SL_ZIGBEE_ADDRESS_TABLE_SIZE: 32 SL_ZIGBEE_CHILD_TABLE_SIZE: type: c_flag @@ -62,6 +64,14 @@ c_defines: type: c_flag value: 250 + SL_ZIGBEE_MULTICAST_TABLE_SIZE: + type: c_flag + value: 26 + + SL_ZIGBEE_DISCOVERY_TABLE_SIZE: + type: c_flag + value: 8 + SL_IOSTREAM_USART_VCOM_BAUDRATE: 115200 SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE: usartHwFlowControlCtsAndRts diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index 3eff2524..6d80947b 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -71,20 +71,32 @@ c_defines: # should not use hardware flow control. XNCP_FLOW_CONTROL_TYPE: usartHwFlowControlNone - SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 32 + SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 128 SL_ZIGBEE_BINDING_TABLE_SIZE: 32 SL_ZIGBEE_BROADCAST_TABLE_SIZE: 64 SL_ZIGBEE_KEY_TABLE_SIZE: 12 - SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 32 - SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 200 + SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 64 + SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 254 + SL_ZIGBEE_NEIGHBOR_TABLE_SIZE: 26 + SL_ZIGBEE_ADDRESS_TABLE_SIZE: 128 + SL_ZIGBEE_APS_DUPLICATE_REJECTION_MAX_ENTRIES: 64 + SL_ZIGBEE_PACKET_BUFFER_HEAP_SIZE: SL_ZIGBEE_HUGE_PACKET_BUFFER_HEAP SL_ZIGBEE_CHILD_TABLE_SIZE: type: c_flag - value: 32 + value: 64 SL_ZIGBEE_ROUTE_TABLE_SIZE: type: c_flag - value: 250 + value: 254 + + SL_ZIGBEE_MULTICAST_TABLE_SIZE: + type: c_flag + value: 26 + + SL_ZIGBEE_DISCOVERY_TABLE_SIZE: + type: c_flag + value: 16 SL_CLOCK_MANAGER_HFXO_FREQ: 39000000 SL_CLOCK_MANAGER_HFXO_PRECISION: 10 From 37e48fd1d44f233a6e1c28d0bf5d20203b9ed78d Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:35:49 -0400 Subject: [PATCH 13/30] Disable `zigbee_bdb_3dot1_trust_center_extension` for router --- src/zigbee_router/zigbee_router.slcp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zigbee_router/zigbee_router.slcp b/src/zigbee_router/zigbee_router.slcp index 01021d6b..644703c2 100644 --- a/src/zigbee_router/zigbee_router.slcp +++ b/src/zigbee_router/zigbee_router.slcp @@ -60,7 +60,7 @@ component: - id: zigbee_trust_center_keepalive - id: zigbee_poll_control_client - id: zigbee_bdb_3dot1_rejoin_algorithm - - id: zigbee_bdb_3dot1_trust_center_extension + # - id: zigbee_bdb_3dot1_trust_center_extension # Unnecessary for a simple router - id: zigbee_application_bootloader # Platform - enable LTO for gcc - id: toolchain_gcc_lto From 6e1e9f0556f9bfa13636009cfb7b603c4f53728a Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:26:29 -0400 Subject: [PATCH 14/30] Bump to 2026.6.0 --- Dockerfile | 26 ++- .../skyconnect/skyconnect_bootloader.yaml | 2 +- .../skyconnect/skyconnect_openthread_rcp.yaml | 4 +- .../skyconnect/skyconnect_zigbee_ncp.yaml | 4 +- .../nabucasa/yellow/yellow_bootloader.yaml | 2 +- .../yellow/yellow_openthread_rcp.yaml | 4 +- .../nabucasa/yellow/yellow_zigbee_ncp.yaml | 4 +- manifests/nabucasa/zbt2/zbt2_bootloader.yaml | 2 +- .../nabucasa/zbt2/zbt2_openthread_rcp.yaml | 4 +- manifests/nabucasa/zbt2/zbt2_router.yaml | 4 +- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 6 +- manifests/nabucasa/zwa2/zwa2_controller.yaml | 4 +- src/openthread_rcp/openthread_rcp.slcp | 7 +- src/zigbee_ncp/zigbee_ncp.slcp | 7 +- src/zigbee_router/zigbee_router.slcp | 7 +- src/zwa2_controller/app.c | 153 ++++++++++++++++-- .../src/zwave_dmadrv_compat.c | 6 + .../dmadrv-rename-ldma-irqhandler.patch | 17 +- src/zwa2_controller/zwa2_controller.slcp | 2 +- 19 files changed, 205 insertions(+), 60 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7d171f02..bc1eaf16 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,18 +30,16 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \ ca-certificates \ git \ && rm -rf /var/lib/apt/lists/* \ - # Download QEMU 11.0.0 source - && aria2c --checksum=sha-256=253fb688815c7ba4bf1a3ecb582bd4476cfa485deb759f5f641efcde0d4bfabd -o qemu.tar.gz \ - https://gitlab.com/qemu-project/qemu/-/archive/v11.0.0/qemu-v11.0.0.tar.gz \ + # Download QEMU 11.0.2 source + && aria2c --checksum=sha-256=f1ab4eda29aa2e5c0b29ba38b7411c368b9b9bf822de6569c53ea8d4e04f980a -o qemu.tar.gz \ + https://gitlab.com/qemu-project/qemu/-/archive/v11.0.2/qemu-v11.0.2.tar.gz \ && tar xzf qemu.tar.gz && rm qemu.tar.gz \ - && mv qemu-v11.0.0 qemu \ + && mv qemu-v11.0.2 qemu \ && cd qemu \ # Apply execve interception patch from conda-forge && aria2c -o execve.patch \ - https://raw.githubusercontent.com/conda-forge/qemu-execve-feedstock/eaea9abfa56f859c98fb3938535a961465a58ae6/recipe/patches/execve/apply-execve-JH.patch \ + https://raw.githubusercontent.com/conda-forge/qemu-execve-feedstock/988a9d79604e0a88cecc6bc4439625decdc308e9/recipe/patches/execve/apply-execve-JH.patch \ && patch -p1 < execve.patch && rm execve.patch \ - # Skip vsyscall page setup when reserved_va is enabled - && sed -i '/Cannot allocate vsyscall page/{s/.*/ return true;/;n;d}' linux-user/x86_64/elfload.c \ && ./configure \ --target-list=x86_64-linux-user \ --static \ @@ -69,7 +67,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends aria2 ca-certif FROM debian:trixie-slim AS python-venv COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/bin/ COPY requirements.txt /tmp/ -RUN UV_PYTHON_INSTALL_DIR=/opt/pythons uv venv -p 3.13 /opt/venv --no-cache \ +RUN UV_PYTHON_INSTALL_DIR=/opt/pythons uv venv -p 3.14 /opt/venv --no-cache \ && uv pip install --python /opt/venv -r /tmp/requirements.txt # Install slt and all toolchain packages (depends on QEMU for ARM64) @@ -106,9 +104,7 @@ RUN set -e \ # Install conan && slt --non-interactive install conan \ && mv /root/.silabs/slt/engines/conan/conan_engine /root/.silabs/slt/engines/conan/conan_engine-bin \ - # -R limits address space to 47 bits, fixing Go binaries that assume 48-bit sign-extended addresses - # This can be removed once conan_engine is recompiled with a newer Go toolchain - && printf '#!/bin/sh\nexec /usr/bin/qemu-x86_64-static -R 0x800000000000 /root/.silabs/slt/engines/conan/conan_engine-bin "$@"\n' > /root/.silabs/slt/engines/conan/conan_engine \ + && printf '#!/bin/sh\nexec /usr/bin/qemu-x86_64-static /root/.silabs/slt/engines/conan/conan_engine-bin "$@"\n' > /root/.silabs/slt/engines/conan/conan_engine \ && chmod +x /root/.silabs/slt/engines/conan/conan_engine \ # Remove --execve from slt wrapper once we install conan, so native tools (tar, etc.) run without QEMU && printf '#!/bin/sh\nexec /usr/bin/qemu-x86_64-static /usr/bin/slt-bin "$@"\n' > /usr/bin/slt \ @@ -132,10 +128,10 @@ RUN set -e \ && slt --non-interactive install \ cmake/3.30.2 \ ninja/1.12.1 \ - commander/1.23.1 \ - slc-cli/6.0.17 \ - simplicity-sdk/2025.12.3 \ - zap/2026.02.26 \ + commander/1.24.1 \ + slc-cli/6.0.22 \ + simplicity-sdk/2026.6.0 \ + zap/2026.06.17 \ # Clean up download caches to reduce image size && rm -rf /root/.silabs/slt/installs/archive/*.zip \ /root/.silabs/slt/installs/archive/*.tar.* \ diff --git a/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml b/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml index 1c16d901..a6567a7b 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml @@ -3,7 +3,7 @@ device: EFR32MG21A020F512IM32 base_project: src/bootloader filename: "{manifest_name}_{gecko_bootloader_version}" sdk: "gecko_sdk:4.5.0" -toolchain: "12.2.1.20221205" +toolchain: "14.2.1.20241119" gbl: fw_type: gecko-bootloader diff --git a/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml b/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml index 6cfb7041..5acbc5d2 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml @@ -2,8 +2,8 @@ name: SkyConnect OpenThread RCP device: EFR32MG21A020F512IM32 base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: openthread_rcp diff --git a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml index 358f88f5..c4a45f19 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_zigbee_ncp.yaml @@ -2,8 +2,8 @@ name: SkyConnect Zigbee device: EFR32MG21A020F512IM32 base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: zigbee_ncp diff --git a/manifests/nabucasa/yellow/yellow_bootloader.yaml b/manifests/nabucasa/yellow/yellow_bootloader.yaml index 80c62d1d..b5f79259 100644 --- a/manifests/nabucasa/yellow/yellow_bootloader.yaml +++ b/manifests/nabucasa/yellow/yellow_bootloader.yaml @@ -3,7 +3,7 @@ device: MGM210PA32JIA base_project: src/bootloader filename: "{manifest_name}_{gecko_bootloader_version}" sdk: "gecko_sdk:4.5.0" -toolchain: "12.2.1.20221205" +toolchain: "14.2.1.20241119" gbl: fw_type: gecko-bootloader diff --git a/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml b/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml index 53a4035a..2ff641fb 100644 --- a/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml +++ b/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml @@ -2,8 +2,8 @@ name: Yellow OpenThread RCP device: MGM210PA32JIA base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: openthread_rcp diff --git a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml index adf0e989..f3879029 100644 --- a/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml +++ b/manifests/nabucasa/yellow/yellow_zigbee_ncp.yaml @@ -2,8 +2,8 @@ name: Yellow Zigbee device: MGM210PA32JIA base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: zigbee_ncp diff --git a/manifests/nabucasa/zbt2/zbt2_bootloader.yaml b/manifests/nabucasa/zbt2/zbt2_bootloader.yaml index 14905770..0ebef7fb 100644 --- a/manifests/nabucasa/zbt2/zbt2_bootloader.yaml +++ b/manifests/nabucasa/zbt2/zbt2_bootloader.yaml @@ -3,7 +3,7 @@ device: EFR32MG24A420F1536IM40 base_project: src/bootloader filename: "{manifest_name}_{gecko_bootloader_version}" sdk: "gecko_sdk:4.5.0" -toolchain: "12.2.1.20221205" +toolchain: "14.2.1.20241119" gbl: fw_type: gecko-bootloader diff --git a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml index 22a0b196..039a11fe 100644 --- a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml @@ -2,8 +2,8 @@ name: Home Assistant Connect ZBT-2 OpenThread RCP device: EFR32MG24A420F1536IM40 base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: openthread_rcp diff --git a/manifests/nabucasa/zbt2/zbt2_router.yaml b/manifests/nabucasa/zbt2/zbt2_router.yaml index 027aac55..708ab820 100644 --- a/manifests/nabucasa/zbt2/zbt2_router.yaml +++ b/manifests/nabucasa/zbt2/zbt2_router.yaml @@ -2,8 +2,8 @@ name: Home Assistant Connect ZBT-2 Zigbee Router device: EFR32MG24A420F1536IM40 base_project: src/zigbee_router filename: "{manifest_name}_{sdk_version}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: zigbee_router diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index 6d80947b..9c257cab 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -1,9 +1,9 @@ name: Home Assistant Connect ZBT-2 Zigbee device: EFR32MG24A420F1536IM40 base_project: src/zigbee_ncp -filename: "{manifest_name}_{ezsp_version}_{fw_variant}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +filename: "{manifest_name}_{ezsp_version}" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: zigbee_ncp diff --git a/manifests/nabucasa/zwa2/zwa2_controller.yaml b/manifests/nabucasa/zwa2/zwa2_controller.yaml index d7798cf6..fb236a76 100644 --- a/manifests/nabucasa/zwa2/zwa2_controller.yaml +++ b/manifests/nabucasa/zwa2/zwa2_controller.yaml @@ -2,8 +2,8 @@ name: Home Assistant Connect ZWA-2 Z-Wave Controller device: EFR32ZG23A020F512GM40 base_project: src/zwa2_controller filename: "{manifest_name}_{zwave_version}" -sdk: "simplicity_sdk:2025.12.3" -toolchain: "12.2.1.20221205" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "14.2.1.20241119" gbl: fw_type: zwave_ncp zwave_version: dynamic diff --git a/src/openthread_rcp/openthread_rcp.slcp b/src/openthread_rcp/openthread_rcp.slcp index b9849e11..83182e17 100644 --- a/src/openthread_rcp/openthread_rcp.slcp +++ b/src/openthread_rcp/openthread_rcp.slcp @@ -19,8 +19,13 @@ component: - id: bootloader_interface - id: clock_manager - id: ot_reset_utils - # Platform - Enable LTO for gcc by installing the following component + # Platform - Enable LTO for gcc and llvm by installing the following components - id: toolchain_gcc_lto + condition: + - toolchain_gcc + - id: toolchain_llvm_lto + condition: + - toolchain_llvm include: - path: . diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 9fd052d1..eeab3d99 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -37,8 +37,13 @@ component: - id: rail_util_rssi - id: legacy_hal_wdog - id: clock_manager - # Platform - enable LTO for gcc + # Platform - enable LTO for gcc and llvm - id: toolchain_gcc_lto + condition: + - toolchain_gcc + - id: toolchain_llvm_lto + condition: + - toolchain_llvm define: - name: SL_ZIGBEE_CUSTOM_MAC_FILTER_TABLE_SIZE diff --git a/src/zigbee_router/zigbee_router.slcp b/src/zigbee_router/zigbee_router.slcp index 644703c2..68e00f8e 100644 --- a/src/zigbee_router/zigbee_router.slcp +++ b/src/zigbee_router/zigbee_router.slcp @@ -62,8 +62,13 @@ component: - id: zigbee_bdb_3dot1_rejoin_algorithm # - id: zigbee_bdb_3dot1_trust_center_extension # Unnecessary for a simple router - id: zigbee_application_bootloader - # Platform - enable LTO for gcc + # Platform - enable LTO for gcc and llvm - id: toolchain_gcc_lto + condition: + - toolchain_gcc + - id: toolchain_llvm_lto + condition: + - toolchain_llvm # Custom router components - id: router_nvram_reset vendor: nabucasa diff --git a/src/zwa2_controller/app.c b/src/zwa2_controller/app.c index 512f955d..56a1dd61 100644 --- a/src/zwa2_controller/app.c +++ b/src/zwa2_controller/app.c @@ -40,6 +40,9 @@ #if defined(SL_CATALOG_POWER_MANAGER_PRESENT) #include "sl_power_manager.h" #endif +#ifdef SL_CATALOG_ZW_HOST_HIBERNATION_PRESENT +#include "sl_host_hibernation_api.h" +#endif #include #include "led_effects_zwa2.h" @@ -59,6 +62,11 @@ #include "zw_shutdown_manager.h" #endif +#ifdef SL_CATALOG_ZW_JAMMING_DETECTION_PRESENT +#include "sl_jamming_detection.h" +#include "sl_jamming_cmd_handlers.h" +#endif + /* Basic level definitions */ #define BASIC_ON 0xFF #define BASIC_OFF 0x00 @@ -141,6 +149,9 @@ zpal_reset_reason_t g_eApplResetReason; bool bTxStatusReportEnabled; +static void (*m_urgent_app_callback)(const SZwaveReceivePackage *) = NULL; +static bool (*m_keep_alive_callback)(node_id_t) = NULL; + static void ApplicationInitSW(void); static void ApplicationTask(SApplicationHandles *pAppHandles); @@ -149,7 +160,7 @@ static bool request_protocol_cc_encryption(SZwaveReceivePackage *pRPCCEPackage); #endif #ifdef ZW_CONTROLLER_BRIDGE -static void ApplicationCommandHandler_Bridge(SReceiveMulti *pReciveMulti); +void ApplicationCommandHandler_Bridge(SReceiveMulti *pReciveMulti); #else void ApplicationCommandHandler(void *pSubscriberContext, SZwaveReceivePackage* pRxPackage); #endif @@ -168,10 +179,6 @@ extern void ZCB_ComplHandler_ZW_ReplaceFailedNode(uint8_t bStatus); extern void ZCB_ComplHandler_ZW_SetSlaveLearnMode(uint8_t bStatus, uint8_t orgID, uint8_t newID); #endif -#if SUPPORT_ZW_SET_RF_RECEIVE_MODE -extern uint8_t SetRFReceiveMode(uint8_t mode); -#endif - ZW_WEAK void cmds_power_management_init(void) { // Do nothing @@ -314,12 +321,28 @@ void zaf_event_distributor_app_zw_rx(SZwaveReceivePackage *RxPackage) switch (RxPackage->eReceiveType) { case EZWAVERECEIVETYPE_SINGLE: #ifndef ZW_CONTROLLER_BRIDGE +#ifdef SL_CATALOG_ZW_HOST_HIBERNATION_PRESENT + if (is_host_sleeping()) { + node_id_t node_id = RxPackage->uReceiveParams.Rx.RxOptions.sourceNode; + const uint8_t * const payload = (uint8_t*) &RxPackage->uReceiveParams.Rx.Payload; + s2_message_update_count(node_id, payload); + break; + } +#endif ApplicationCommandHandler(NULL, RxPackage); #endif break; #ifdef ZW_CONTROLLER_BRIDGE case EZWAVERECEIVETYPE_MULTI: +#ifdef SL_CATALOG_ZW_HOST_HIBERNATION_PRESENT + if (is_host_sleeping()) { + node_id_t node_id = RxPackage->uReceiveParams.RxMulti.RxOptions.sourceNode; + const uint8_t * const payload = (uint8_t*) &RxPackage->uReceiveParams.RxMulti.Payload; + s2_message_update_count(node_id, payload); + break; + } +#endif ApplicationCommandHandler_Bridge(&RxPackage->uReceiveParams.RxMulti); break; #endif // #ifdef ZW_CONTROLLER_BRIDGE @@ -337,6 +360,18 @@ void zaf_event_distributor_app_zw_rx(SZwaveReceivePackage *RxPackage) ?ERPCCEEVENT_SERIALAPI_OK : ERPCCEEVENT_SERIALAPI_FAIL); break; #endif + case EZWAVERECEIVETYPE_SINGLE_URGENT: + if (m_urgent_app_callback != NULL) { + m_urgent_app_callback(RxPackage); + } else { +#ifndef ZW_CONTROLLER_BRIDGE + ApplicationCommandHandler(NULL, RxPackage); +#else + ApplicationCommandHandler_Bridge(&RxPackage->uReceiveParams.RxMulti); +#endif + } + break; + default: break; } @@ -393,6 +428,11 @@ void zaf_event_distributor_app_zw_command_status(SZwaveCommandStatusPackage *Sta } #endif #endif + case EZWAVECOMMANDSTATUS_KEEP_ALIVE_UPDATE: + if (m_keep_alive_callback != NULL) { + m_keep_alive_callback(Status->Content.KeepAliveUpdate.nodeId); + } + break; default: break; } @@ -488,6 +528,11 @@ ApplicationTask(SApplicationHandles* pAppHandles) #endif zaf_event_distributor_init(); +#ifdef SL_CATALOG_ZW_HOST_HIBERNATION_PRESENT + keep_alive_init(); + gpio_wakeup_host_init(); +#endif + set_state_and_notify(stateStartup); // Wait for and process events ZPAL_LOG_DEBUG(ZPAL_LOG_APP, "SerialApi Event processor Started\r\n"); @@ -554,7 +599,6 @@ static void SerialAPIStateHandler(void) case stateStartup: { ApplicationInitSW(); - SetRFReceiveMode(1); set_state_and_notify(stateIdle); } break; @@ -791,6 +835,62 @@ ApplicationInitSW(void) cmds_power_management_init(); } +/** + * @brief Callback from rssi collection: + * - send proprietary Serial API frame 0xF1 to host. + * - Subcommands + * -- 0x01: Collection + * - Payload is 4 bytes: + * rssi[0] rssi on channel 0 + * rssi[1] rssi on channel 1 + * rssi[2] rssi on channel 2 + * rssi[3] rssi on channel LR Channel A + * rssi[4] rssi on channel LR Channel B + */ +#ifdef SL_CATALOG_ZW_JAMMING_DETECTION_PRESENT +static zpal_status_t application_rssi_collection_callback(const sl_jamming_detection_collection_t *collection) +{ + zpal_status_t status = ZPAL_STATUS_FAIL; + struct __attribute__((packed)) { + uint8_t sub_command; + sl_jamming_detection_collection_t payload; + } collection_packet = { + .sub_command = FUNC_ID_PROP_JAMMING_SUBCOMMAND_COLLECTION, + .payload = *collection + }; + + status = RequestUnsolicited(FUNC_ID_PROP_JAMMING_DETECTION_COMMAND, (uint8_t *)&collection_packet, sizeof(collection_packet)) ? ZPAL_STATUS_OK : ZPAL_STATUS_FAIL; + return status; +} + +/** + * Callback from jamming detection ZPAL: + * - send proprietary Serial API frame 0xF1 to host. + * - Subcommands + * -- 0x00: Report + * - Payload 1 byte is : jammed channels bitmap. + * 0b00000001 = channel 0 is jammed + * 0b00000010 = channel 1 is jammed + * 0b00000100 = channel 2 is jammed + * 0b00001000 = channel LR A is jammed + * 0b00010000 = channel LR B is jammed + */ +static zpal_status_t application_jamming_detected_callback(const sl_jamming_detection_statistics_t *report) +{ + zpal_status_t status = ZPAL_STATUS_FAIL; + struct __attribute__((packed)) { + uint8_t sub_command; + sl_jamming_detection_statistics_t payload; + } jamming_packet = { + .sub_command = FUNC_ID_PROP_JAMMING_SUBCOMMAND_REPORT, + .payload = *report + }; + + status = RequestUnsolicited(FUNC_ID_PROP_JAMMING_DETECTION_COMMAND, (uint8_t *)&jamming_packet, sizeof(jamming_packet)) ? ZPAL_STATUS_OK : ZPAL_STATUS_FAIL; + return status; +} +#endif /* SL_CATALOG_ZW_JAMMING_DETECTION_PRESENT */ + /*============================== ApplicationInit ====================== ** Init UART and setup port pins for LEDs ** @@ -800,12 +900,33 @@ ApplicationInit( zpal_reset_reason_t eResetReason) { #ifdef SL_CATALOG_ZW_SHUTDOWN_MANAGER_PRESENT - zw_shutdown_manager_init(); + zpal_status_t status = zw_shutdown_manager_init(); + if (status != ZPAL_STATUS_OK) { + assert(false); + } #endif // enable the watchdog at init of application zpal_watchdog_init(); zpal_enable_watchdog(true); +#ifdef SL_CATALOG_ZW_JAMMING_DETECTION_PRESENT + sl_jamming_detection_config_t config = { 0 }; + + // set the default configuration for the jamming detection + if ( ZPAL_STATUS_OK == sl_jamming_detection_default_config(&config)) { + // set the callback function to be called when jamming is detected + config.report_callback = application_jamming_detected_callback; + config.collection_callback = application_rssi_collection_callback; + + /*with or without jamming detection, the rest of the application runs as usual.*/ + if (ZPAL_STATUS_OK != sl_jamming_detection_init(&config)) { + assert(false); + } + } else { + assert(false); + } +#endif /* SL_CATALOG_ZW_JAMMING_DETECTION_PRESENT */ + // Serial API can control hardware with information // set in the file system therefore it should be the first // step in the Initialization @@ -815,7 +936,7 @@ ApplicationInit( app_hw_init(); #endif - /* g_eApplResetReason now contains lastest System Reset reason */ + /* g_eApplResetReason now contains lastest System Ryeset reason */ g_eApplResetReason = eResetReason; ZPAL_LOG_INFO(ZPAL_LOG_APP, "ApplicationInit eResetReason = %d\n", eResetReason); @@ -873,8 +994,7 @@ ApplicationInit( ** Handling of received application commands and requests ** **--------------------------------------------------------------------------*/ -void /*RET Nothing */ -ApplicationCommandHandler(__attribute__((unused)) void *pSubscriberContext, SZwaveReceivePackage* pRxPackage) +void ApplicationCommandHandler(__attribute__((unused)) void *pSubscriberContext, SZwaveReceivePackage* pRxPackage) { ZW_APPLICATION_TX_BUFFER *pCmd = (ZW_APPLICATION_TX_BUFFER *)&pRxPackage->uReceiveParams.Rx.Payload; uint8_t cmdLength = pRxPackage->uReceiveParams.Rx.iLength; @@ -923,8 +1043,7 @@ typedef struct SMultiCastNodeMaskHeaderSerial{ ** Handling of received application commands and requests ** **--------------------------------------------------------------------------*/ -static void /*RET Nothing */ -ApplicationCommandHandler_Bridge(SReceiveMulti* pReceiveMulti) +void ApplicationCommandHandler_Bridge(SReceiveMulti* pReceiveMulti) { /* ZW->HOST: REQ | 0xA8 | rxStatus | destNode | sourceNode | cmdLength * | pCmd[] | multiDestsOffset_NodeMaskLen | multiDestsNodeMask[] | rssiVal @@ -1081,3 +1200,13 @@ ZW_WEAK const void * SerialAPI_get_uart_config_ext(void) { return NULL; } + +void set_urgent_app_callback(urgent_app_callback_t callback) +{ + m_urgent_app_callback = callback; +} + +void set_keep_alive_callback(keep_alive_callback_t callback) +{ + m_keep_alive_callback = callback; +} diff --git a/src/zwa2_controller/extension/nabucasa_zwa2_extension/src/zwave_dmadrv_compat.c b/src/zwa2_controller/extension/nabucasa_zwa2_extension/src/zwave_dmadrv_compat.c index 04bd68ab..5733d280 100644 --- a/src/zwa2_controller/extension/nabucasa_zwa2_extension/src/zwave_dmadrv_compat.c +++ b/src/zwa2_controller/extension/nabucasa_zwa2_extension/src/zwave_dmadrv_compat.c @@ -50,6 +50,11 @@ bool zwave_ldma_tx_callback(unsigned int channel, unsigned int sequenceNo, void return false; } +// As of Simplicity SDK 2026.6.0, DMADRV is deprecated in favour of sl_dma_manager (it still works, +// delegating internally). This shim is deliberately built on DMADRV constructs to match the Z-Wave +// ZPAL and SPI/I2C drivers, so we suppress the deprecation warning rather than re-implement it. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" sl_status_t zwave_dmadrv_compat_init() { Ecode_t result = DMADRV_Init(); @@ -82,3 +87,4 @@ sl_status_t zwave_dmadrv_compat_init() return SL_STATUS_OK; } +#pragma GCC diagnostic pop diff --git a/src/zwa2_controller/sdk_patches/dmadrv-rename-ldma-irqhandler.patch b/src/zwa2_controller/sdk_patches/dmadrv-rename-ldma-irqhandler.patch index 464ab7c2..4d259761 100644 --- a/src/zwa2_controller/sdk_patches/dmadrv-rename-ldma-irqhandler.patch +++ b/src/zwa2_controller/sdk_patches/dmadrv-rename-ldma-irqhandler.patch @@ -1,13 +1,12 @@ -diff --git a/platform_core/platform/emdrv/dmadrv/src/dmadrv.c b/platform_core/platform/emdrv/dmadrv/src/dmadrv.c -index dd45751..06234c6 100755 ---- a/platform_core/platform/emdrv/dmadrv/src/dmadrv.c -+++ b/platform_core/platform/emdrv/dmadrv/src/dmadrv.c -@@ -1036,7 +1042,7 @@ Ecode_t DMADRV_TransferRemainingCount(unsigned int channelId, - * @brief - * An interrupt handler for LDMA. +diff --git a/platform_core/platform/service/dma_manager/src/sl_dma_manager_hal_ldma.c b/platform_core/platform/service/dma_manager/src/sl_dma_manager_hal_ldma.c +--- a/platform_core/platform/service/dma_manager/src/sl_dma_manager_hal_ldma.c ++++ b/platform_core/platform/service/dma_manager/src/sl_dma_manager_hal_ldma.c +@@ -275,7 +275,7 @@ void sli_dma_manager_hal_set_pending_errors(uint8_t channel_nbr, uint32_t errors + /***************************************************************************//** + * Interrupt handler for LDMA module. ******************************************************************************/ -void LDMA_IRQHandler(void) +void dmadrv_LDMA_IRQHandler(void) { - bool stop; - ChTable_t *ch; + uint32_t pending; + uint32_t pending_done; diff --git a/src/zwa2_controller/zwa2_controller.slcp b/src/zwa2_controller/zwa2_controller.slcp index 96490412..f3bf9ddc 100644 --- a/src/zwa2_controller/zwa2_controller.slcp +++ b/src/zwa2_controller/zwa2_controller.slcp @@ -186,7 +186,7 @@ configuration: - condition: - device_series_2 name: SL_SLEEPTIMER_PERIPHERAL - value: SL_SLEEPTIMER_PERIPHERAL_BURTC + value: SL_SLEEPTIMER_PERIPHERAL_DEFAULT - name: ZAF_CONFIG_INSTALLER_ICON_TYPE value: '0' - name: ZAF_APP_NAME From 19c7420731fca04e1b819e91ac48bd145d59c8f0 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Fri, 26 Jun 2026 22:40:34 -0400 Subject: [PATCH 15/30] Work around the SiLabs Linux toolchain not having ZSTD support... --- tools/build_project.py | 82 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tools/build_project.py b/tools/build_project.py index f0f2d43c..94e3ed8a 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -9,14 +9,17 @@ import sys import json import time +import zlib import shutil import typing import hashlib import logging import pathlib import argparse +import tempfile import contextlib import subprocess +from compression import zstd from datetime import datetime, timezone from ruamel.yaml import YAML @@ -24,6 +27,8 @@ LOGGER = logging.getLogger(__name__) +ZSTD_MAGIC = b"\x28\xb5\x2f\xfd" +GCC_LTO_FLAG_COMPRESSED = 0x0001 yaml = YAML(typ="safe") @@ -191,6 +196,72 @@ def load_toolchains(paths: list[pathlib.Path]) -> dict[pathlib.Path, str]: return toolchains +def recompress_sdk_lib_lto(sdk_dir: pathlib.Path, toolchain_bin: pathlib.Path) -> None: + """Recompress the SDK libraries' LTO bytecode from ZSTD to zlib.""" + + # `gcc-ar` loads the LTO plugin so the archive index includes symbols defined only + # in LTO bytecode + ar = toolchain_bin / "arm-none-eabi-gcc-ar" + objcopy = toolchain_bin / "arm-none-eabi-objcopy" + + # Simplicity SDK 2026.6.0 compresses the precompiled stack libraries' LTO bytecode + # with ZSTD, but the gcc-arm-none-eabi it distributes is built without ZSTD support + # so LTO linking fails. We recompress them with zlib. + for lib in sorted(sdk_dir.rglob("*.a")): + if ZSTD_MAGIC not in lib.read_bytes(): + continue + + LOGGER.info( + "Recompressing LTO bytecode in SDK lib: %s", lib.relative_to(sdk_dir) + ) + with tempfile.TemporaryDirectory() as tmp_str: + tmp = pathlib.Path(tmp_str) + subprocess.run([str(ar), "x", str(lib.resolve())], cwd=tmp, check=True) + members = sorted(p.name for p in tmp.iterdir()) + + for member in members: + obj = tmp / member + updates = [] + + with obj.open("rb") as f: + for section in ELFFile(f).iter_sections(): + data = section.data() + + if section.name.startswith( + (".gnu.lto_", ".gnu.debuglto_") + ) and data.startswith(ZSTD_MAGIC): + recompressed = zlib.compress(zstd.decompress(data)) + updates.append((section.name, recompressed)) + elif ( + section.name.startswith(".gnu.lto_.lto") and len(data) >= 8 + ): + # GCC records the compression algorithm in the `lto_section` + # header's flags. Clear the LTO bit, since its now zlib. + flags = int.from_bytes(data[6:8], "little") + if flags & GCC_LTO_FLAG_COMPRESSED: + cleared = flags ^ GCC_LTO_FLAG_COMPRESSED + patched = data[:6] + cleared.to_bytes(2, "little") + updates.append((section.name, patched)) + + if not updates: + continue + + update_sections = [] + + for index, (name, payload) in enumerate(updates): + payload_file = tmp / f"{member}.lto{index}" + payload_file.write_bytes(payload) + + update_sections += ["--update-section", f"{name}={payload_file}"] + + subprocess.run([str(objcopy), *update_sections, str(obj)], check=True) + + lib.unlink() + subprocess.run( + [str(ar), "rcs", str(lib.resolve()), *members], cwd=tmp, check=True + ) + + def subprocess_run_verbose(command: list[str], prefix: str, **kwargs) -> None: with subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs @@ -566,6 +637,11 @@ def main(): cwd=projects_root, ) + # Recompress the (copied) precompiled SDK libs' ZSTD LTO bytecode as zlib, which the + # distributed gcc-arm-none-eabi can read + copied_sdk_dir = next(args.build_dir.glob(f"{sdk_name}_*")) + recompress_sdk_lib_lto(copied_sdk_dir, pathlib.Path(toolchain) / "bin") + # Make sure all extensions are valid (check both SDK and project extensions) for sdk_extension in base_project.get("sdk_extension", []): sdk_ext_dir = sdk / f"extension/{sdk_extension['id']}_extension" @@ -714,6 +790,11 @@ def main(): "/home/buildengineer/.silabs/slt/installs/conan/p/cmsisfb920dbb6ad42/p": "/src/vendor/cmsis", "/home/buildengineer/.silabs/slt/installs/conan/p/platf85e95225bc406/p": f"/src/{sdk_name}_{sdk_version}/platform_core", "/home/buildengineer/.silabs/slt/installs/conan/p/platfe548addd6aec0/p": f"/src/{sdk_name}_{sdk_version}/platform_core", + # The Z-Wave libraries were packaged against their own conan hashes + "/home/buildengineer/.silabs/slt/installs/conan/p/cmsis4dea3e6cbb6ce/p": "/src/vendor/cmsis", + "/home/buildengineer/.silabs/slt/installs/conan/p/platf6edd0cd4d4914/p": f"/src/{sdk_name}_{sdk_version}/platform_core", + # The zigbee stack libraries reference the silabs_core package they were built against + "/github/home/.silabs/slt/installs/conan/p/commo8335073ce327e/p": f"/src/{sdk_name}_{sdk_version}/platform_core", # The Z-Wave SDK isn't part of the Simplicity SDK but is still referenced. If we # ever decide to compile it as part of CI, we can change this remap. "/opt/github/runner/_work/z-wave/z-wave": "/src/vendor/zwave", @@ -731,6 +812,7 @@ def main(): "-Wextra", "-Werror", "-Wno-error=maybe-uninitialized", # Linking fails due to a few SDK bugs + "-Wno-error=uninitialized", # False positive in zigbee `core-cli.c` under LTO "-Wno-error=unused-function", # mbedTLS `ssl_tls.c` with X.509 hostname verification disabled ] build_flags["CXX_FLAGS"] = build_flags["C_FLAGS"] From a7bc69ab8206ae56fe01e6c64782a0db76d07943 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sat, 27 Jun 2026 01:36:00 -0400 Subject: [PATCH 16/30] LLVM support --- .../nabucasa/zbt2/zbt2_openthread_rcp.yaml | 2 +- manifests/nabucasa/zbt2/zbt2_router.yaml | 2 +- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 2 +- manifests/nabucasa/zwa2/zwa2_controller.yaml | 2 +- tools/build_project.py | 125 ++++++++++++++---- 5 files changed, 106 insertions(+), 27 deletions(-) diff --git a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml index 039a11fe..6b8a07e5 100644 --- a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml @@ -3,7 +3,7 @@ device: EFR32MG24A420F1536IM40 base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "14.2.1.20241119" +toolchain: "llvm:21.1.1" gbl: fw_type: openthread_rcp diff --git a/manifests/nabucasa/zbt2/zbt2_router.yaml b/manifests/nabucasa/zbt2/zbt2_router.yaml index 708ab820..c0e92cdb 100644 --- a/manifests/nabucasa/zbt2/zbt2_router.yaml +++ b/manifests/nabucasa/zbt2/zbt2_router.yaml @@ -3,7 +3,7 @@ device: EFR32MG24A420F1536IM40 base_project: src/zigbee_router filename: "{manifest_name}_{sdk_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "14.2.1.20241119" +toolchain: "llvm:21.1.1" gbl: fw_type: zigbee_router diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index 9c257cab..3e5cf88f 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -3,7 +3,7 @@ device: EFR32MG24A420F1536IM40 base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "14.2.1.20241119" +toolchain: "llvm:21.1.1" gbl: fw_type: zigbee_ncp diff --git a/manifests/nabucasa/zwa2/zwa2_controller.yaml b/manifests/nabucasa/zwa2/zwa2_controller.yaml index fb236a76..8ad8afca 100644 --- a/manifests/nabucasa/zwa2/zwa2_controller.yaml +++ b/manifests/nabucasa/zwa2/zwa2_controller.yaml @@ -3,7 +3,7 @@ device: EFR32ZG23A020F512GM40 base_project: src/zwa2_controller filename: "{manifest_name}_{zwave_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "14.2.1.20241119" +toolchain: "llvm:21.1.1" gbl: fw_type: zwave_ncp zwave_version: dynamic diff --git a/tools/build_project.py b/tools/build_project.py index 94e3ed8a..1ea7e6c7 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -62,12 +62,13 @@ def get_toolchain_default_paths() -> list[pathlib.Path]: if sys.platform == "darwin": return list( pathlib.Path( - "/Applications/Simplicity Studio.app/Contents/Eclipse/developer/toolchains/gnu_arm/" - ).glob("*") + "/Applications/Simplicity Studio.app/Contents/Eclipse/developer/toolchains/" + ).glob("*/*") ) if is_running_in_docker(): - return list(pathlib.Path("/root/.silabs/slt/installs/conan/p").glob("gcc-*/p")) + root = pathlib.Path("/root/.silabs/slt/installs/conan/p") + return list(root.glob("gcc-*/p")) + list(root.glob("llvm-*/p")) return [] @@ -177,6 +178,20 @@ def load_toolchains(paths: list[pathlib.Path]) -> dict[pathlib.Path, str]: toolchains = {} for toolchain in paths: + # libc++ encodes its version in `__config` as `_LIBCPP_VERSION` (MMmmpp, e.g. 210101) + libcpp_config = next( + toolchain.glob("lib/clang-runtimes/**/include/c++/v1/__config"), None + ) + if libcpp_config is not None: + for line in libcpp_config.read_text().split("\n"): + if "define _LIBCPP_VERSION " in line: + version = int(line.split()[-1]) + toolchains[toolchain] = ( + f"llvm:{version // 10000}.{version // 100 % 100}.{version % 100}" + ) + break + continue + gcc_plugin_version_h = next( toolchain.glob("lib/gcc/arm-none-eabi/*/plugin/include/plugin-version.h") ) @@ -190,7 +205,7 @@ def load_toolchains(paths: list[pathlib.Path]) -> dict[pathlib.Path, str]: version_info[name] = value toolchains[toolchain] = ( - version_info["basever"] + "." + version_info["datestamp"] + f"gcc:{version_info['basever']}.{version_info['datestamp']}" ) return toolchains @@ -335,6 +350,38 @@ def get_elf_source_paths(elf_path: pathlib.Path) -> set[pathlib.PurePosixPath]: return paths +def remap_debug_build_paths(elf_path: pathlib.Path, prefix_map: dict[str, str]) -> None: + """Remap absolute build-path prefixes in an ELF's DWARF string tables, in place.""" + replacements = {} + for old, new in prefix_map.items(): + old_bytes, new_bytes = old.encode(), new.encode() + assert len(new_bytes) <= len(old_bytes), f"{new!r} is longer than {old!r}" + replacements[old_bytes] = new_bytes + b"/" * (len(old_bytes) - len(new_bytes)) + + with elf_path.open("rb") as f: + elf = ELFFile(f) + sections = [ + (section["sh_offset"], bytearray(section.data())) + for name in (".debug_str", ".debug_line_str") + if (section := elf.get_section_by_name(name)) is not None + ] + + with elf_path.open("r+b") as f: + for offset, data in sections: + for old_bytes, padded in replacements.items(): + search = 0 + + while (index := data.find(old_bytes, search)) != -1: + # Only rewrite at a string start (offset 0 or right after a NUL) + if index == 0 or data[index - 1] == 0: + data[index : index + len(old_bytes)] = padded + + search = index + 1 + + f.seek(offset) + f.write(data) + + def main(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter @@ -463,8 +510,11 @@ def main(): toolchains = load_toolchains(args.toolchains) toolchain = next( - path for path, version in toolchains.items() if version == manifest["toolchain"] + path + for path, name in toolchains.items() + if manifest["toolchain"] in (name, name.split(":", 1)[1]) ) + is_llvm = toolchains[toolchain].startswith("llvm:") for key, override in args.overrides: manifest[key] = override @@ -607,7 +657,7 @@ def main(): "--copy-proj-sources", "--copy-sdk-sources", "--new-project", - "--toolchain", "toolchain_gcc", + "--toolchain", "toolchain_llvm" if is_llvm else "toolchain_gcc", "--sdk", sdk, "--output-type", "vscode", ], @@ -638,9 +688,11 @@ def main(): ) # Recompress the (copied) precompiled SDK libs' ZSTD LTO bytecode as zlib, which the - # distributed gcc-arm-none-eabi can read - copied_sdk_dir = next(args.build_dir.glob(f"{sdk_name}_*")) - recompress_sdk_lib_lto(copied_sdk_dir, pathlib.Path(toolchain) / "bin") + # distributed gcc-arm-none-eabi can read. LLVM links its own bitcode libraries + # instead. + if not is_llvm: + copied_sdk_dir = next(args.build_dir.glob(f"{sdk_name}_*")) + recompress_sdk_lib_lto(copied_sdk_dir, pathlib.Path(toolchain) / "bin") # Make sure all extensions are valid (check both SDK and project extensions) for sdk_extension in base_project.get("sdk_extension", []): @@ -778,12 +830,14 @@ def main(): ) ) - cmake_dir = args.build_dir / "cmake_gcc" + cmake_dir = args.build_dir / ("cmake_llvm" if is_llvm else "cmake_gcc") - # Remove absolute paths from the build for reproducibility remapped_paths = { args.build_dir.absolute(): "/src", f"{cmake_dir.absolute()}/..": "/src", + # The toolchain's own resource/runtime headers (e.g. clang's builtin and newlib + # include dirs) are recorded in debug info under a machine-specific conan path + str(toolchain): "/src/vendor/toolchain", "/home/buildengineer/jenkins/workspace/Gecko_Workspace/gsdk": f"/src/{sdk_name}_{sdk_version}", # Zigbee sources reference the GitHub Actions workspace they were packaged in "/__w/zigbee/zigbee": f"/src/{sdk_name}_{sdk_version}/zigbee", @@ -807,14 +861,24 @@ def main(): build_flags["LD_FLAGS"] += ["-Wl,--sort-section=name"] # Enable errors - build_flags["C_FLAGS"] += [ - "-Wall", - "-Wextra", - "-Werror", - "-Wno-error=maybe-uninitialized", # Linking fails due to a few SDK bugs - "-Wno-error=uninitialized", # False positive in zigbee `core-cli.c` under LTO - "-Wno-error=unused-function", # mbedTLS `ssl_tls.c` with X.509 hostname verification disabled - ] + build_flags["C_FLAGS"] += ["-Wall", "-Wextra", "-Werror"] + + if is_llvm: + build_flags["C_FLAGS"] += [ + "-Wno-unknown-warning-option", # ignore GCC-only warning names + "-Wno-error=format-security", # SDK `diagnostic.c` uses a non-literal format string + "-Wno-error=unknown-pragmas", # our `ws2812.c` uses `#pragma GCC optimize` + "-Wno-error=unused-function", # unused statics in SDK/OpenThread sources + "-Wno-error=c23-extensions", # our `cmds_proprietary.c` has a label before a declaration + "-Wno-error=unterminated-string-initialization", # char arrays in zigbee router sources + ] + else: + build_flags["C_FLAGS"] += [ + "-Wno-error=maybe-uninitialized", # Linking fails due to a few SDK bugs + "-Wno-error=uninitialized", # False positive in zigbee `core-cli.c` under LTO + "-Wno-error=unused-function", # mbedTLS `ssl_tls.c` with X.509 hostname verification disabled + ] + build_flags["CXX_FLAGS"] = build_flags["C_FLAGS"] # CMake expects a semicolon-separated list for the post-build command @@ -845,7 +909,7 @@ def main(): env={ "HOME": os.environ["HOME"], "PATH": f"{pathlib.Path(sys.executable).parent}:{os.environ['PATH']}", - "ARM_GCC_DIR": toolchain, + ("ARM_LLVM_DIR" if is_llvm else "ARM_GCC_DIR"): toolchain, "NINJA_EXE_PATH": shutil.which("ninja"), "SOURCE_DATE_EPOCH": str(int(args.build_timestamp.timestamp())), }, @@ -868,15 +932,30 @@ def main(): # Verify that --wrap linker flags don't wrap weak stubs validate_linker_wrap_symbols(map_file=output_artifact.with_suffix(".map")) - # Verify that all source paths in the ELF have been remapped + # Rewrite absolute build paths in the ELF's DWARF for reproducibility, then verify + # none leaked + out_elf = output_artifact.with_suffix(".out") + remap_debug_build_paths( + out_elf, + { + str(args.build_dir.resolve()): "/src", + "/root/.silabs": "/src/vendor", # local conan toolchain/SDK headers + "/home/buildengineer": "/src/vendor", # Silicon Labs build machines + "/github/home": "/src/vendor", # Silicon Labs Zigbee CI + "/opt/github": "/src/vendor", # Silicon Labs Z-Wave CI + "/__w": "/src", # GitHub Actions workspace + }, + ) + unreproducible_paths = [ path - for path in get_elf_source_paths(output_artifact.with_suffix(".out")) + for path in get_elf_source_paths(out_elf) if not path.is_relative_to("/src") ] if unreproducible_paths: raise RuntimeError( - f"Unreproducible source paths in ELF: {'\n - '.join(map(str, unreproducible_paths))}" + "Unreproducible source paths in ELF: " + + "\n - ".join(map(str, unreproducible_paths)) ) # Read the metadata extracted from the source and build trees From fb1d4de18edc22fc52452d8f5844a9c789644eed Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sat, 27 Jun 2026 01:39:35 -0400 Subject: [PATCH 17/30] Switch back to GCC --- manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml | 2 +- manifests/nabucasa/zbt2/zbt2_router.yaml | 2 +- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 2 +- manifests/nabucasa/zwa2/zwa2_controller.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml index 6b8a07e5..29992f78 100644 --- a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml @@ -3,7 +3,7 @@ device: EFR32MG24A420F1536IM40 base_project: src/openthread_rcp filename: "{manifest_name}_{ot_rcp_version.split('/')[-1]}_gsdk_{sdk_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "llvm:21.1.1" +toolchain: "gcc:14.2.1.20241119" gbl: fw_type: openthread_rcp diff --git a/manifests/nabucasa/zbt2/zbt2_router.yaml b/manifests/nabucasa/zbt2/zbt2_router.yaml index c0e92cdb..c6bff3ce 100644 --- a/manifests/nabucasa/zbt2/zbt2_router.yaml +++ b/manifests/nabucasa/zbt2/zbt2_router.yaml @@ -3,7 +3,7 @@ device: EFR32MG24A420F1536IM40 base_project: src/zigbee_router filename: "{manifest_name}_{sdk_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "llvm:21.1.1" +toolchain: "gcc:14.2.1.20241119" gbl: fw_type: zigbee_router diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index 3e5cf88f..590401ef 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -3,7 +3,7 @@ device: EFR32MG24A420F1536IM40 base_project: src/zigbee_ncp filename: "{manifest_name}_{ezsp_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "llvm:21.1.1" +toolchain: "gcc:14.2.1.20241119" gbl: fw_type: zigbee_ncp diff --git a/manifests/nabucasa/zwa2/zwa2_controller.yaml b/manifests/nabucasa/zwa2/zwa2_controller.yaml index 8ad8afca..02418e40 100644 --- a/manifests/nabucasa/zwa2/zwa2_controller.yaml +++ b/manifests/nabucasa/zwa2/zwa2_controller.yaml @@ -3,7 +3,7 @@ device: EFR32ZG23A020F512GM40 base_project: src/zwa2_controller filename: "{manifest_name}_{zwave_version}" sdk: "simplicity_sdk:2026.6.0" -toolchain: "llvm:21.1.1" +toolchain: "gcc:14.2.1.20241119" gbl: fw_type: zwave_ncp zwave_version: dynamic From cb3ab8324b12b61f33d025b44fb5e9ce926a4cc7 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sat, 27 Jun 2026 02:07:20 -0400 Subject: [PATCH 18/30] Switch MG24 Zigbee firmwares from USART to EUSART peripheral --- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 32 +++++++++---------- .../config/xncp_config.h | 4 +++ .../src/xncp_common_commands.c | 6 ++++ src/zigbee_ncp/zigbee_ncp.slcp | 4 +-- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index 590401ef..19a4630a 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -102,22 +102,22 @@ c_defines: SL_CLOCK_MANAGER_HFXO_PRECISION: 10 SL_CLOCK_MANAGER_HFXO_CTUNE: 108 - SL_IOSTREAM_USART_VCOM_BAUDRATE: 460800 - SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE: usartHwFlowControlCtsAndRts - - SL_IOSTREAM_USART_VCOM_PERIPHERAL: USART0 - SL_IOSTREAM_USART_VCOM_PERIPHERAL_NO: 0 - - SL_IOSTREAM_USART_VCOM_TX_PORT: SL_GPIO_PORT_A - SL_IOSTREAM_USART_VCOM_TX_PIN: 8 - SL_IOSTREAM_USART_VCOM_RX_PORT: SL_GPIO_PORT_A - SL_IOSTREAM_USART_VCOM_RX_PIN: 7 - SL_IOSTREAM_USART_VCOM_CTS_PORT: SL_GPIO_PORT_A - SL_IOSTREAM_USART_VCOM_CTS_PIN: 5 - SL_IOSTREAM_USART_VCOM_RTS_PORT: SL_GPIO_PORT_A - SL_IOSTREAM_USART_VCOM_RTS_PIN: 0 - - SL_IOSTREAM_USART_VCOM_RX_BUFFER_SIZE: 128 + SL_IOSTREAM_EUSART_VCOM_BAUDRATE: 460800 + SL_IOSTREAM_EUSART_VCOM_FLOW_CONTROL_TYPE: SL_IOSTREAM_EUSART_UART_FLOW_CTRL_CTS_RTS + + SL_IOSTREAM_EUSART_VCOM_PERIPHERAL: EUSART0 + SL_IOSTREAM_EUSART_VCOM_PERIPHERAL_NO: 0 + + SL_IOSTREAM_EUSART_VCOM_TX_PORT: SL_GPIO_PORT_A + SL_IOSTREAM_EUSART_VCOM_TX_PIN: 8 + SL_IOSTREAM_EUSART_VCOM_RX_PORT: SL_GPIO_PORT_A + SL_IOSTREAM_EUSART_VCOM_RX_PIN: 7 + SL_IOSTREAM_EUSART_VCOM_CTS_PORT: SL_GPIO_PORT_A + SL_IOSTREAM_EUSART_VCOM_CTS_PIN: 5 + SL_IOSTREAM_EUSART_VCOM_RTS_PORT: SL_GPIO_PORT_A + SL_IOSTREAM_EUSART_VCOM_RTS_PIN: 0 + + SL_IOSTREAM_EUSART_VCOM_RX_BUFFER_SIZE: 128 # WS2812 LED driver SL_SPIDRV_EUSART_WS2812_PERIPHERAL: EUSART1 diff --git a/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h b/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h index dfc9f289..08cf15a9 100644 --- a/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h +++ b/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h @@ -5,7 +5,11 @@ #ifndef XNCP_CONFIG_H_ #define XNCP_CONFIG_H_ +#if defined(SL_CATALOG_IOSTREAM_EUSART_PRESENT) +#include "sl_iostream_eusart_vcom_config.h" +#elif defined(SL_CATALOG_IOSTREAM_USART_PRESENT) #include "sl_iostream_usart_vcom_config.h" +#endif // <<< Use Configuration Wizard in Context Menu >>> diff --git a/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c b/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c index 714e5150..73129857 100644 --- a/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c +++ b/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c @@ -11,7 +11,13 @@ #include "ezsp-enum.h" #include "em_usart.h" #include "random.h" + +#if defined(SL_CATALOG_IOSTREAM_EUSART_PRESENT) +#include "sl_iostream_eusart_vcom_config.h" +#elif defined(SL_CATALOG_IOSTREAM_USART_PRESENT) #include "sl_iostream_usart_vcom_config.h" +#endif + #include #define BUILD_UINT16(low, high) (((uint16_t)(low)) | ((uint16_t)(high) << 8)) diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index eeab3d99..8fd1fd17 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -12,12 +12,12 @@ component: instance: - vcom condition: - - device_series_2 + - device_generic_family_efr32xg21 - id: iostream_eusart instance: - vcom condition: - - device_series_3 + - device_has_eusart - id: zigbee_debug_print - id: iostream_vuart - id: common_token_manager From d98a218ba707efcb74805d3ab1f315719b196252 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 28 Jun 2026 00:21:15 -0400 Subject: [PATCH 19/30] Remove ARM64 ZSTD hacks by compiling our own compiler... Fix typo --- Dockerfile | 42 +++++++++++++++++++++++ tools/build_project.py | 78 ------------------------------------------ 2 files changed, 42 insertions(+), 78 deletions(-) diff --git a/Dockerfile b/Dockerfile index bc1eaf16..89079bcd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,40 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \ mkdir -p /usr/src/qemu/build && touch /usr/src/qemu/build/qemu-x86_64; \ fi +# Arm's official aarch64 toolchain was built WITHOUT libzstd and SiLabs uses +# zstd-compressed LTO bytecode in their precompiled SDK stack libraries. This prevents +# any compilation from succeeding on ARM64 hosts. We need to build our own minimal +# toolchain with zstd support to work around this. x86 is not affected. +FROM debian:trixie-slim AS zstd-gcc-builder +ARG TARGETARCH +RUN mkdir -p /opt/zstd-gcc \ + && if [ "$TARGETARCH" = "arm64" ]; then set -eux \ + && apt-get update && apt-get install -y --no-install-recommends \ + build-essential flex bison texinfo gawk libtool autoconf m4 \ + zlib1g-dev libzstd-dev wget file gettext bzip2 xz-utils ca-certificates git aria2 \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir -p /build/src && cd /build \ + && aria2c --checksum=sha-256=e6405f20f8a817a50d92dbf7974d0ee77708dfdf9e79900a59c5d343b464ef9c -o src.tar.xz \ + https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/14.2.rel1/srcrel/arm-gnu-toolchain-src-snapshot-14.2.rel1.tar.xz \ + && tar -xJf src.tar.xz -C /build/src && rm src.tar.xz \ + && git clone --depth 1 --branch v1.1.0 \ + https://git.gitlab.arm.com/tooling/gnu-devtools-for-arm.git /build/src/gnu-devtools-for-arm \ + && ln -sf src/gnu-devtools-for-arm/build-gnu-toolchain.sh . \ + # The `start` stage normally creates `install/`. Running stages individually skips + # it, so pre-create it or the first `do_config` can't write `install/.build_flags`. + && mkdir -p /build/build-arm-none-eabi-armv7e-m/install \ + # Single multilib, no gdb. Through gcc2 so cc1plus (C++) is built too. + && ./build-gnu-toolchain.sh --target=arm-none-eabi --with-arch=armv7e-m \ + --disable-multilib --disable-gdb \ + gmp mpfr mpc isl iconv binutils gcc1 newlib gcc2 \ + && for t in cc1 cc1plus lto1; do \ + cp "$(find /build -path '*/libexec/gcc/arm-none-eabi/*' -name "$t" | head -1)" /opt/zstd-gcc/; \ + done \ + # Strip debug info (Arm ships these stripped; unstripped they are ~340 MB each) + && strip /opt/zstd-gcc/* \ + && rm -rf /build; \ + fi + # The new `slt` tool does not provide Gecko SDK builds so we have to download it ourselves. FROM debian:trixie-slim AS gecko-sdk-v4.5.0 RUN apt-get update && apt-get install -y --no-install-recommends aria2 ca-certificates libarchive-tools \ @@ -172,6 +206,8 @@ RUN set -e \ libpng16-16 \ libpcre2-16-0 \ libglib2.0-0 \ + # Needed at runtime by the zstd-enabled cc1/cc1plus/lto1 swapped in below (ARM64) + libzstd1 \ && rm -rf /var/lib/apt/lists/* \ # Fix git permission error when building locally && git config --global --add safe.directory '*' @@ -183,6 +219,12 @@ COPY --from=python-venv /opt/venv /opt/venv COPY --from=qemu-execve-builder /usr/src/qemu/build/qemu-x86_64 /usr/bin/qemu-x86_64-static COPY --from=slt-toolchain /usr/bin/slt* /usr/bin/ COPY --from=slt-toolchain /root/.silabs /root/.silabs +COPY --from=zstd-gcc-builder /opt/zstd-gcc /tmp/zstd-gcc +RUN if [ "$TARGETARCH" = "arm64" ]; then set -eux \ + && d="$(dirname "$(find /root/.silabs -path '*/libexec/gcc/arm-none-eabi/*' -name lto1 | head -1)")" \ + && cp /tmp/zstd-gcc/cc1 /tmp/zstd-gcc/cc1plus /tmp/zstd-gcc/lto1 "$d/"; \ + fi \ + && rm -rf /tmp/zstd-gcc # Signal to the firmware builder script that we are running within Docker ENV SILABS_FIRMWARE_BUILD_CONTAINER=1 diff --git a/tools/build_project.py b/tools/build_project.py index 1ea7e6c7..33f75ff4 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -9,17 +9,14 @@ import sys import json import time -import zlib import shutil import typing import hashlib import logging import pathlib import argparse -import tempfile import contextlib import subprocess -from compression import zstd from datetime import datetime, timezone from ruamel.yaml import YAML @@ -27,8 +24,6 @@ LOGGER = logging.getLogger(__name__) -ZSTD_MAGIC = b"\x28\xb5\x2f\xfd" -GCC_LTO_FLAG_COMPRESSED = 0x0001 yaml = YAML(typ="safe") @@ -211,72 +206,6 @@ def load_toolchains(paths: list[pathlib.Path]) -> dict[pathlib.Path, str]: return toolchains -def recompress_sdk_lib_lto(sdk_dir: pathlib.Path, toolchain_bin: pathlib.Path) -> None: - """Recompress the SDK libraries' LTO bytecode from ZSTD to zlib.""" - - # `gcc-ar` loads the LTO plugin so the archive index includes symbols defined only - # in LTO bytecode - ar = toolchain_bin / "arm-none-eabi-gcc-ar" - objcopy = toolchain_bin / "arm-none-eabi-objcopy" - - # Simplicity SDK 2026.6.0 compresses the precompiled stack libraries' LTO bytecode - # with ZSTD, but the gcc-arm-none-eabi it distributes is built without ZSTD support - # so LTO linking fails. We recompress them with zlib. - for lib in sorted(sdk_dir.rglob("*.a")): - if ZSTD_MAGIC not in lib.read_bytes(): - continue - - LOGGER.info( - "Recompressing LTO bytecode in SDK lib: %s", lib.relative_to(sdk_dir) - ) - with tempfile.TemporaryDirectory() as tmp_str: - tmp = pathlib.Path(tmp_str) - subprocess.run([str(ar), "x", str(lib.resolve())], cwd=tmp, check=True) - members = sorted(p.name for p in tmp.iterdir()) - - for member in members: - obj = tmp / member - updates = [] - - with obj.open("rb") as f: - for section in ELFFile(f).iter_sections(): - data = section.data() - - if section.name.startswith( - (".gnu.lto_", ".gnu.debuglto_") - ) and data.startswith(ZSTD_MAGIC): - recompressed = zlib.compress(zstd.decompress(data)) - updates.append((section.name, recompressed)) - elif ( - section.name.startswith(".gnu.lto_.lto") and len(data) >= 8 - ): - # GCC records the compression algorithm in the `lto_section` - # header's flags. Clear the LTO bit, since its now zlib. - flags = int.from_bytes(data[6:8], "little") - if flags & GCC_LTO_FLAG_COMPRESSED: - cleared = flags ^ GCC_LTO_FLAG_COMPRESSED - patched = data[:6] + cleared.to_bytes(2, "little") - updates.append((section.name, patched)) - - if not updates: - continue - - update_sections = [] - - for index, (name, payload) in enumerate(updates): - payload_file = tmp / f"{member}.lto{index}" - payload_file.write_bytes(payload) - - update_sections += ["--update-section", f"{name}={payload_file}"] - - subprocess.run([str(objcopy), *update_sections, str(obj)], check=True) - - lib.unlink() - subprocess.run( - [str(ar), "rcs", str(lib.resolve()), *members], cwd=tmp, check=True - ) - - def subprocess_run_verbose(command: list[str], prefix: str, **kwargs) -> None: with subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs @@ -687,13 +616,6 @@ def main(): cwd=projects_root, ) - # Recompress the (copied) precompiled SDK libs' ZSTD LTO bytecode as zlib, which the - # distributed gcc-arm-none-eabi can read. LLVM links its own bitcode libraries - # instead. - if not is_llvm: - copied_sdk_dir = next(args.build_dir.glob(f"{sdk_name}_*")) - recompress_sdk_lib_lto(copied_sdk_dir, pathlib.Path(toolchain) / "bin") - # Make sure all extensions are valid (check both SDK and project extensions) for sdk_extension in base_project.get("sdk_extension", []): sdk_ext_dir = sdk / f"extension/{sdk_extension['id']}_extension" From 0b66bdba42f28359c373000bcf7c0f4216731046 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sat, 27 Jun 2026 23:35:20 -0400 Subject: [PATCH 20/30] Migrate bootloader to Simplicity SDK --- Dockerfile | 10 --- .../skyconnect/skyconnect_bootloader.yaml | 2 +- .../nabucasa/yellow/yellow_bootloader.yaml | 2 +- manifests/nabucasa/zbt2/zbt2_bootloader.yaml | 32 +++------- .../bootloader_gpio_activation_dual.slcc | 24 ------- .../bootloader_gpio_activation_dual.slce | 5 -- .../inc/btl_gpio_activation_dual_cfg.h | 62 ------------------- .../gpio-activation/btl_gpio_activation.h | 31 ---------- .../src/btl_gpio_activation_dual.c | 41 ------------ tools/create_gbl.py | 18 +++++- 10 files changed, 25 insertions(+), 202 deletions(-) delete mode 100644 src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slcc delete mode 100644 src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slce delete mode 100644 src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/btl_gpio_activation_dual_cfg.h delete mode 100644 src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/gpio/gpio-activation/btl_gpio_activation.h delete mode 100644 src/bootloader/extension/bootloader_gpio_activation_dual_extension/src/btl_gpio_activation_dual.c diff --git a/Dockerfile b/Dockerfile index 89079bcd..46a3c0ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -88,15 +88,6 @@ RUN mkdir -p /opt/zstd-gcc \ && rm -rf /build; \ fi -# The new `slt` tool does not provide Gecko SDK builds so we have to download it ourselves. -FROM debian:trixie-slim AS gecko-sdk-v4.5.0 -RUN apt-get update && apt-get install -y --no-install-recommends aria2 ca-certificates libarchive-tools \ - && rm -rf /var/lib/apt/lists/* \ - && aria2c --checksum=sha-256=b5b2b2410eac0c9e2a72320f46605ecac0d376910cafded5daca9c1f78e966c8 -o sdk.zip \ - https://github.com/SiliconLabs/gecko_sdk/releases/download/v4.5.0/gecko-sdk.zip \ - && mkdir /out && bsdtar -xf sdk.zip -C /out \ - && rm sdk.zip - # Python virtual environment for the firmware builder script FROM debian:trixie-slim AS python-venv COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/bin/ @@ -213,7 +204,6 @@ RUN set -e \ && git config --global --add safe.directory '*' # Copy from parallel stages -COPY --from=gecko-sdk-v4.5.0 /out /gecko_sdk_4.5.0 COPY --from=python-venv /opt/pythons /opt/pythons COPY --from=python-venv /opt/venv /opt/venv COPY --from=qemu-execve-builder /usr/src/qemu/build/qemu-x86_64 /usr/bin/qemu-x86_64-static diff --git a/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml b/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml index a6567a7b..bc737853 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_bootloader.yaml @@ -2,7 +2,7 @@ name: SkyConnect Bootloader device: EFR32MG21A020F512IM32 base_project: src/bootloader filename: "{manifest_name}_{gecko_bootloader_version}" -sdk: "gecko_sdk:4.5.0" +sdk: "simplicity_sdk:2026.6.0" toolchain: "14.2.1.20241119" gbl: diff --git a/manifests/nabucasa/yellow/yellow_bootloader.yaml b/manifests/nabucasa/yellow/yellow_bootloader.yaml index b5f79259..f5af9ae5 100644 --- a/manifests/nabucasa/yellow/yellow_bootloader.yaml +++ b/manifests/nabucasa/yellow/yellow_bootloader.yaml @@ -2,7 +2,7 @@ name: Yellow Bootloader device: MGM210PA32JIA base_project: src/bootloader filename: "{manifest_name}_{gecko_bootloader_version}" -sdk: "gecko_sdk:4.5.0" +sdk: "simplicity_sdk:2026.6.0" toolchain: "14.2.1.20241119" gbl: diff --git a/manifests/nabucasa/zbt2/zbt2_bootloader.yaml b/manifests/nabucasa/zbt2/zbt2_bootloader.yaml index 0ebef7fb..cfbdde41 100644 --- a/manifests/nabucasa/zbt2/zbt2_bootloader.yaml +++ b/manifests/nabucasa/zbt2/zbt2_bootloader.yaml @@ -2,7 +2,7 @@ name: Home Assistant Connect ZBT-2 Bootloader device: EFR32MG24A420F1536IM40 base_project: src/bootloader filename: "{manifest_name}_{gecko_bootloader_version}" -sdk: "gecko_sdk:4.5.0" +sdk: "simplicity_sdk:2026.6.0" toolchain: "14.2.1.20241119" gbl: @@ -10,17 +10,6 @@ gbl: gecko_bootloader_version: dynamic baudrate: 115200 -sdk_extension: - - id: bootloader_gpio_activation_dual - vendor: nabucasa - version: 1.0.0 - -remove_components: - - id: bootloader_gpio_activation - -add_components: - - id: bootloader_gpio_activation_dual - c_defines: SL_SERIAL_UART_FLOW_CONTROL: 1 @@ -29,23 +18,16 @@ c_defines: SL_SERIAL_UART_TX_PORT: gpioPortA SL_SERIAL_UART_TX_PIN: 8 + SL_SERIAL_UART_RX_PORT: gpioPortA SL_SERIAL_UART_RX_PIN: 7 + SL_SERIAL_UART_CTS_PORT: gpioPortA SL_SERIAL_UART_CTS_PIN: 5 + SL_SERIAL_UART_RTS_PORT: gpioPortA SL_SERIAL_UART_RTS_PIN: 0 - # The bootloader does not allow downgrades so we need to bump the version - BOOTLOADER_VERSION_MAIN_CUSTOMER: 4 - - # Dual GPIO activation for the bootloader - # Triggered by trace to S3 - NC_PRIMARY_GPIO_ACTIVATION_POLARITY: LOW - NC_BTL_BUTTON_PRIMARY_PORT: gpioPortA - NC_BTL_BUTTON_PRIMARY_PIN: 6 - - # And by the reset button on the back - NC_SECONDARY_GPIO_ACTIVATION_POLARITY: LOW - NC_BTL_BUTTON_SECONDARY_PORT: gpioPortC - NC_BTL_BUTTON_SECONDARY_PIN: 5 \ No newline at end of file + SL_GPIO_ACTIVATION_POLARITY: LOW + SL_BTL_BUTTON_PORT: gpioPortA + SL_BTL_BUTTON_PIN: 6 diff --git a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slcc b/src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slcc deleted file mode 100644 index aff92fcb..00000000 --- a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slcc +++ /dev/null @@ -1,24 +0,0 @@ -id: bootloader_gpio_activation_dual -label: GPIO activation (dual pin) -package: bootloader_gpio_activation_dual -description: > - The Bootloader GPIO activation component provides entry to bootloader firmware upgrade mode - if either of two GPIOs has a given state at reset. The GPIO state is configurable. -category: Platform|Bootloader|Utils -quality: production -source: - - path: src/btl_gpio_activation_dual.c -include: - - path: inc - file_list: - - path: gpio/gpio-activation/btl_gpio_activation.h -config_file: - - path: inc/btl_gpio_activation_dual_cfg.h - file_id: btl_gpio_activation_cfg -define: - - name: BTL_GPIO_ACTIVATION - value: 1 -provides: - - name: bootloader_gpio_activation_dual - - name: bootloader_nonsecure_incompatible - condition: [bootloader_core_nonsecure] \ No newline at end of file diff --git a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slce b/src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slce deleted file mode 100644 index afad976f..00000000 --- a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/bootloader_gpio_activation_dual.slce +++ /dev/null @@ -1,5 +0,0 @@ -id: bootloader_gpio_activation_dual -vendor: nabucasa -version: "1.0.0" -component_path: - - path: "./" diff --git a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/btl_gpio_activation_dual_cfg.h b/src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/btl_gpio_activation_dual_cfg.h deleted file mode 100644 index f9b3a724..00000000 --- a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/btl_gpio_activation_dual_cfg.h +++ /dev/null @@ -1,62 +0,0 @@ -/***************************************************************************//** - * @file - * @brief Configuration header for bootloader Dual GPIO Activation - ******************************************************************************* - * # License - * Copyright 2021 Silicon Laboratories Inc. www.silabs.com - ******************************************************************************* - * - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. - * - ******************************************************************************/ -#ifndef BTL_GPIO_ACTIVATION_DUAL_CONFIG_H -#define BTL_GPIO_ACTIVATION_DUAL_CONFIG_H - -// <<< Use Configuration Wizard in Context Menu >>> - -// Properties of Bootloader Entry - -// Primary button active state -// Low -// High -// Default: LOW -// Enter firmware upgrade mode if primary GPIO pin has this state -#define NC_PRIMARY_GPIO_ACTIVATION_POLARITY LOW - -// Secondary button active state -// Low -// High -// Default: LOW -// Enter firmware upgrade mode if secondary GPIO pin has this state -#define NC_SECONDARY_GPIO_ACTIVATION_POLARITY LOW - -// - -// <<< end of configuration section >>> - -// <<< sl:start pin_tool >>> - -// NC_BTL_BUTTON_PRIMARY - -// $[GPIO_NC_BTL_BUTTON_PRIMARY] -#warning "Primary GPIO activation port not configured" -//#define NC_BTL_BUTTON_PRIMARY_PORT gpioPortA -//#define NC_BTL_BUTTON_PRIMARY_PIN 6 -// [GPIO_NC_BTL_BUTTON_PRIMARY]$ - -// NC_BTL_BUTTON_SECONDARY - -// $[GPIO_NC_BTL_BUTTON_SECONDARY] -#warning "Secondary GPIO activation port not configured" -//#define NC_BTL_BUTTON_SECONDARY_PORT gpioPortC -//#define NC_BTL_BUTTON_SECONDARY_PIN 5 -// [GPIO_NC_BTL_BUTTON_SECONDARY]$ - -// <<< sl:end pin_tool >>> - -#endif // BTL_GPIO_ACTIVATION_DUAL_CONFIG_H diff --git a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/gpio/gpio-activation/btl_gpio_activation.h b/src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/gpio/gpio-activation/btl_gpio_activation.h deleted file mode 100644 index a2671ba4..00000000 --- a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/inc/gpio/gpio-activation/btl_gpio_activation.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef BTL_GPIO_ACTIVATION_H -#define BTL_GPIO_ACTIVATION_H - -/***************************************************************************//** - * @addtogroup Components - * @{ - * @addtogroup GpioActivation GPIO Activation - * @brief Enter bootloader based on GPIO state. - * @brief This component provides functionality to enter firmware upgrade mode automatically after reset if a GPIO pin is active during boot. - * @brief The GPIO pin location and polarity are configurable. - * @details - * @{ - * @addtogroup ButtonGPIO Button GPIO - * @brief Enter bootloader based on Button GPIO state. - * @brief By enabling the GPIO activation component, the firmware upgrade mode can be activated by the GPIO configuration. - * @details - * @{ - ******************************************************************************/ - -/***************************************************************************//** - * Enter the bootlader if the GPIO pin is active. - * - * @return True if the bootloader should be entered - ******************************************************************************/ -bool gpio_enterBootloader(void); - -/** @} (end addtogroup Button GPIO) */ -/** @} (end addtogroup GpioActivation) */ -/** @} (end addtogroup Components) */ - -#endif // BTL_GPIO_ACTIVATION_H diff --git a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/src/btl_gpio_activation_dual.c b/src/bootloader/extension/bootloader_gpio_activation_dual_extension/src/btl_gpio_activation_dual.c deleted file mode 100644 index d2a76deb..00000000 --- a/src/bootloader/extension/bootloader_gpio_activation_dual_extension/src/btl_gpio_activation_dual.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "config/btl_config.h" -#include "em_device.h" -#include "em_gpio.h" -#include "gpio/gpio-activation/btl_gpio_activation.h" -#include "btl_gpio_activation_dual_cfg.h" - -#define HIGH 0 -#define LOW 1 - -bool gpio_enterBootloader(void) -{ - bool pressed; - -#if defined(CMU_HFBUSCLKEN0_GPIO) - CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_GPIO; -#endif -#if defined(_CMU_CLKEN0_MASK) - CMU->CLKEN0_SET = CMU_CLKEN0_GPIO; -#endif - - GPIO_PinModeSet(NC_BTL_BUTTON_PRIMARY_PORT, NC_BTL_BUTTON_PRIMARY_PIN, gpioModePushPull, NC_PRIMARY_GPIO_ACTIVATION_POLARITY); - GPIO_PinModeSet(NC_BTL_BUTTON_SECONDARY_PORT, NC_BTL_BUTTON_SECONDARY_PIN, gpioModePushPull, NC_SECONDARY_GPIO_ACTIVATION_POLARITY); - for (volatile int i = 0; i < 100; i++); - - GPIO_PinModeSet(NC_BTL_BUTTON_PRIMARY_PORT, NC_BTL_BUTTON_PRIMARY_PIN, gpioModeInputPull, NC_PRIMARY_GPIO_ACTIVATION_POLARITY); - GPIO_PinModeSet(NC_BTL_BUTTON_SECONDARY_PORT, NC_BTL_BUTTON_SECONDARY_PIN, gpioModeInputPull, NC_SECONDARY_GPIO_ACTIVATION_POLARITY); - for (volatile int i = 0; i < 500; i++); - - bool primary_pressed = (GPIO_PinInGet(NC_BTL_BUTTON_PRIMARY_PORT, NC_BTL_BUTTON_PRIMARY_PIN) != NC_PRIMARY_GPIO_ACTIVATION_POLARITY); - bool secondary_pressed = (GPIO_PinInGet(NC_BTL_BUTTON_SECONDARY_PORT, NC_BTL_BUTTON_SECONDARY_PIN) != NC_SECONDARY_GPIO_ACTIVATION_POLARITY); - pressed = primary_pressed || secondary_pressed; - - GPIO_PinModeSet(NC_BTL_BUTTON_PRIMARY_PORT, NC_BTL_BUTTON_PRIMARY_PIN, gpioModeDisabled, NC_PRIMARY_GPIO_ACTIVATION_POLARITY); - GPIO_PinModeSet(NC_BTL_BUTTON_SECONDARY_PORT, NC_BTL_BUTTON_SECONDARY_PIN, gpioModeDisabled, NC_SECONDARY_GPIO_ACTIVATION_POLARITY); - -#if defined(CMU_HFBUSCLKEN0_GPIO) - CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_GPIO; -#endif - - return pressed; -} diff --git a/tools/create_gbl.py b/tools/create_gbl.py index 860dd9ee..fbae055e 100755 --- a/tools/create_gbl.py +++ b/tools/create_gbl.py @@ -333,9 +333,23 @@ def main(): if "gecko_bootloader_version" in gbl_dynamic: gbl_dynamic.remove("gecko_bootloader_version") - btl_config_h = parse_c_header_defines( - (gsdk_path / "platform/bootloader/config/btl_config.h").read_text() + btl_config_path = next( + ( + path + for path in ( + # Gecko SDK and Simplicity SDK up to 2025.6.x + (gsdk_path / "platform/bootloader/config/btl_config.h"), + # Simplicity SDK 2025.12.0 and above + (gsdk_path / "bootloader/platform/bootloader/config/btl_config.h"), + ) + if path.exists() + ), + None, ) + if btl_config_path is None: + raise FileNotFoundError("Could not find bootloader btl_config.h") + + btl_config_h = parse_c_header_defines(btl_config_path.read_text()) # Look for overrides btl_core_config_h = parse_c_header_defines( From 128c665ce1f54d3ff24375449ed43d4e5247eb5b Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 28 Jun 2026 00:31:03 -0400 Subject: [PATCH 21/30] Ensure `SOURCE_DATE_EPOCH` is set for all cmake invocations --- tools/build_project.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/build_project.py b/tools/build_project.py index 33f75ff4..cb8dfebf 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -846,6 +846,7 @@ def main(): env={ "HOME": os.environ["HOME"], "PATH": f"{pathlib.Path(sys.executable).parent}:{os.environ['PATH']}", + "SOURCE_DATE_EPOCH": str(int(args.build_timestamp.timestamp())), }, ) From 5d74a1a798a251ce217e0bdb306ba78e6e4c2a61 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 28 Jun 2026 00:54:14 -0400 Subject: [PATCH 22/30] Apply overrides earlier --- tools/build_project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/build_project.py b/tools/build_project.py index cb8dfebf..373b3a54 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -430,6 +430,9 @@ def main(): manifest = yaml.load(args.manifest.read_text()) + for key, override in args.overrides: + manifest[key] = override + # Ensure we can load the correct SDK and toolchain sdks = load_sdks(args.sdks) sdk, sdk_and_version = next( @@ -445,9 +448,6 @@ def main(): ) is_llvm = toolchains[toolchain].startswith("llvm:") - for key, override in args.overrides: - manifest[key] = override - # First, copy the base project into the build dir, under `template/` projects_root = pathlib.Path(__file__).parent.parent base_project_path = projects_root / manifest["base_project"] From 1aecaa830d940474a1860c82165c68233b2b7057 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 28 Jun 2026 01:07:11 -0400 Subject: [PATCH 23/30] Uninstall the LLVM toolchain to save space --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 46a3c0ba..a96eb79e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -157,6 +157,9 @@ RUN set -e \ slc-cli/6.0.22 \ simplicity-sdk/2026.6.0 \ zap/2026.06.17 \ + # We don't currently use the LLVM toolchain that is pulled in as a default + # dependency. Uninstall it to save space. + && slt --non-interactive uninstall --force llvm-arm-toolchain-for-embedded \ # Clean up download caches to reduce image size && rm -rf /root/.silabs/slt/installs/archive/*.zip \ /root/.silabs/slt/installs/archive/*.tar.* \ From c778448b60d0e34027c4ef4b1156865c47fa3355 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 28 Jun 2026 01:39:56 -0400 Subject: [PATCH 24/30] Add changelog entries --- src/openthread_rcp/CHANGELOG.md | 3 +++ src/zigbee_ncp/CHANGELOG.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/openthread_rcp/CHANGELOG.md b/src/openthread_rcp/CHANGELOG.md index dceb38ec..9dd661f3 100644 --- a/src/openthread_rcp/CHANGELOG.md +++ b/src/openthread_rcp/CHANGELOG.md @@ -1,3 +1,6 @@ +# SL-OPENTHREAD/3.1.0.0_GitHub-fb274efe6 +This beta release is built with OpenThread 3.1.0 from Simplicity SDK 2026.6.0. + # SL-OPENTHREAD/3.0.2.0_GitHub-61e43cffb This beta release is built with OpenThread 3.0.2 from Simplicity SDK 2025.12.3. diff --git a/src/zigbee_ncp/CHANGELOG.md b/src/zigbee_ncp/CHANGELOG.md index e8cd58ec..81f7353e 100644 --- a/src/zigbee_ncp/CHANGELOG.md +++ b/src/zigbee_ncp/CHANGELOG.md @@ -1,3 +1,6 @@ +# 9.1.0.0 +Beta release built with EmberZNet 9.1 from Simplicity SDK 2026.6.0. + # 9.0.2.0 Beta release built with EmberZNet 9.0 from Simplicity SDK 2025.12.3. This is our first release that migrates from the older Gecko SDK to the newer Simplicity SDK. From 445f21f252d4fde3923c295d4f03dec0a6c83be7 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:51:52 -0400 Subject: [PATCH 25/30] Apply suggestions from code review Co-authored-by: burmistrzak <61958704+burmistrzak@users.noreply.github.com> --- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 4 ++-- .../extension/xncp_common_extension/config/xncp_config.h | 8 ++++++++ .../xncp_common_extension/src/xncp_common_commands.c | 1 + src/zigbee_ncp/zigbee_ncp.slcp | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index 19a4630a..b3759221 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -69,7 +69,7 @@ c_defines: # The hardware flow control is only between the S3 and the MG24. The application # should not use hardware flow control. - XNCP_FLOW_CONTROL_TYPE: usartHwFlowControlNone + XNCP_FLOW_CONTROL_TYPE: SL_IOSTREAM_EUSART_UART_FLOW_CTRL_NONE SL_ZIGBEE_APS_UNICAST_MESSAGE_COUNT: 128 SL_ZIGBEE_BINDING_TABLE_SIZE: 32 @@ -117,7 +117,7 @@ c_defines: SL_IOSTREAM_EUSART_VCOM_RTS_PORT: SL_GPIO_PORT_A SL_IOSTREAM_EUSART_VCOM_RTS_PIN: 0 - SL_IOSTREAM_EUSART_VCOM_RX_BUFFER_SIZE: 128 + SL_IOSTREAM_EUSART_VCOM_RX_BUFFER_SIZE: 512 # WS2812 LED driver SL_SPIDRV_EUSART_WS2812_PERIPHERAL: EUSART1 diff --git a/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h b/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h index 08cf15a9..c9d1c2a7 100644 --- a/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h +++ b/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h @@ -6,6 +6,7 @@ #define XNCP_CONFIG_H_ #if defined(SL_CATALOG_IOSTREAM_EUSART_PRESENT) +#include "sl_iostream_eusart.h" #include "sl_iostream_eusart_vcom_config.h" #elif defined(SL_CATALOG_IOSTREAM_USART_PRESENT) #include "sl_iostream_usart_vcom_config.h" @@ -45,6 +46,13 @@ // Override only if external flow control differs from internal UART (e.g. ZBT-2) #ifndef XNCP_FLOW_CONTROL_TYPE #define XNCP_FLOW_CONTROL_TYPE SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE +#ifndef XNCP_FLOW_CONTROL_TYPE + #if defined(SL_CATALOG_IOSTREAM_EUSART_PRESENT) + #define XNCP_FLOW_CONTROL_TYPE_DEFAULT SL_IOSTREAM_EUSART_VCOM_FLOW_CONTROL_TYPE + #else + #define XNCP_FLOW_CONTROL_TYPE_DEFAULT SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE + #endif + #define XNCP_FLOW_CONTROL_TYPE XNCP_FLOW_CONTROL_TYPE_DEFAULT #endif // EZSP version patch number override diff --git a/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c b/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c index 73129857..c82364b9 100644 --- a/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c +++ b/src/zigbee_ncp/extension/xncp_common_extension/src/xncp_common_commands.c @@ -13,6 +13,7 @@ #include "random.h" #if defined(SL_CATALOG_IOSTREAM_EUSART_PRESENT) +#include "sl_iostream_eusart.h" #include "sl_iostream_eusart_vcom_config.h" #elif defined(SL_CATALOG_IOSTREAM_USART_PRESENT) #include "sl_iostream_usart_vcom_config.h" diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 8fd1fd17..257dbeea 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -47,7 +47,7 @@ component: define: - name: SL_ZIGBEE_CUSTOM_MAC_FILTER_TABLE_SIZE - value: 15 + value: 2 # Prevent LTO from stripping sl_zigbee_version, which is read from the ELF # by create_gbl.py to extract the EZSP version for firmware metadata. From 2d5b219222bf13db4d129710ecab6f378cab636f Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 30 Jun 2026 11:27:36 -0400 Subject: [PATCH 26/30] Fix `XNCP_FLOW_CONTROL_TYPE` config --- .../extension/xncp_common_extension/config/xncp_config.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h b/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h index c9d1c2a7..7eac5fb8 100644 --- a/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h +++ b/src/zigbee_ncp/extension/xncp_common_extension/config/xncp_config.h @@ -44,14 +44,13 @@ // Flow control type // Default: auto-detect from UART config (SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE) // Override only if external flow control differs from internal UART (e.g. ZBT-2) -#ifndef XNCP_FLOW_CONTROL_TYPE -#define XNCP_FLOW_CONTROL_TYPE SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE #ifndef XNCP_FLOW_CONTROL_TYPE #if defined(SL_CATALOG_IOSTREAM_EUSART_PRESENT) #define XNCP_FLOW_CONTROL_TYPE_DEFAULT SL_IOSTREAM_EUSART_VCOM_FLOW_CONTROL_TYPE #else #define XNCP_FLOW_CONTROL_TYPE_DEFAULT SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE #endif + #define XNCP_FLOW_CONTROL_TYPE XNCP_FLOW_CONTROL_TYPE_DEFAULT #endif From 4b24bd69b5fa7f9877fbea221278117d4b2583b0 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 30 Jun 2026 11:27:44 -0400 Subject: [PATCH 27/30] Enable R23 support for coordinator --- src/zigbee_ncp/zigbee_ncp.slcp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 257dbeea..0bb9af8d 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -26,7 +26,8 @@ component: - id: zigbee_pro_stack - id: zigbee_source_route - id: zigbee_gp - - id: zigbee_r22_support + - id: zigbee_r23_support + - id: zigbee_dynamic_commissioning - id: zigbee_security_link_keys - id: zigbee_zll - id: zigbee_system_common From 4ee6d621f3e1546209d740109622e6198be33d16 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 1 Jul 2026 00:05:03 -0400 Subject: [PATCH 28/30] Enable R22 support too, since the components aren't mutually exclusive --- src/zigbee_ncp/zigbee_ncp.slcp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 0bb9af8d..d6abf647 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -26,6 +26,7 @@ component: - id: zigbee_pro_stack - id: zigbee_source_route - id: zigbee_gp + - id: zigbee_r22_support - id: zigbee_r23_support - id: zigbee_dynamic_commissioning - id: zigbee_security_link_keys From 876c9c60eb4be7c226dc3e0cc2c9d05b9d4c83b3 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 14 Jul 2026 18:42:14 -0400 Subject: [PATCH 29/30] Reduce child table size for the ZBT-2 back down to 32 --- manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml index b3759221..ed9d1bf4 100644 --- a/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_zigbee_ncp.yaml @@ -75,7 +75,7 @@ c_defines: SL_ZIGBEE_BINDING_TABLE_SIZE: 32 SL_ZIGBEE_BROADCAST_TABLE_SIZE: 64 SL_ZIGBEE_KEY_TABLE_SIZE: 12 - SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 64 + SL_ZIGBEE_MAX_END_DEVICE_CHILDREN: 32 SL_ZIGBEE_SOURCE_ROUTE_TABLE_SIZE: 254 SL_ZIGBEE_NEIGHBOR_TABLE_SIZE: 26 SL_ZIGBEE_ADDRESS_TABLE_SIZE: 128 @@ -84,7 +84,7 @@ c_defines: SL_ZIGBEE_CHILD_TABLE_SIZE: type: c_flag - value: 64 + value: 32 SL_ZIGBEE_ROUTE_TABLE_SIZE: type: c_flag From dc14ce8dd242f80e18801d3f63e487d14a2bc453 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 14 Jul 2026 19:02:33 -0400 Subject: [PATCH 30/30] Disable GP packet filtering --- .../skyconnect/skyconnect_openthread_rcp.yaml | 3 +++ .../nabucasa/yellow/yellow_openthread_rcp.yaml | 3 +++ manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml | 3 +++ .../sdk_patches/disable_gp_rx_filter.patch | 14 ++++++++++++++ 4 files changed, 23 insertions(+) create mode 100644 src/openthread_rcp/sdk_patches/disable_gp_rx_filter.patch diff --git a/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml b/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml index 5acbc5d2..b15abdfe 100644 --- a/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml +++ b/manifests/nabucasa/skyconnect/skyconnect_openthread_rcp.yaml @@ -10,6 +10,9 @@ gbl: ot_rcp_version: dynamic baudrate: 460800 +sdk_patches: + - disable_gp_rx_filter.patch + add_components: - id: iostream_usart instance: [vcom] diff --git a/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml b/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml index 2ff641fb..bd9de79d 100644 --- a/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml +++ b/manifests/nabucasa/yellow/yellow_openthread_rcp.yaml @@ -10,6 +10,9 @@ gbl: ot_rcp_version: dynamic baudrate: 460800 +sdk_patches: + - disable_gp_rx_filter.patch + add_components: - id: iostream_usart instance: [vcom] diff --git a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml index 29992f78..8bb510e1 100644 --- a/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml +++ b/manifests/nabucasa/zbt2/zbt2_openthread_rcp.yaml @@ -18,6 +18,9 @@ sdk_extension: version: 1.0.0 vendor: nabucasa +sdk_patches: + - disable_gp_rx_filter.patch + add_components: - id: spidrv_eusart instance: [ws2812] diff --git a/src/openthread_rcp/sdk_patches/disable_gp_rx_filter.patch b/src/openthread_rcp/sdk_patches/disable_gp_rx_filter.patch new file mode 100644 index 00000000..14321306 --- /dev/null +++ b/src/openthread_rcp/sdk_patches/disable_gp_rx_filter.patch @@ -0,0 +1,14 @@ +diff --git a/openthread/platform-abstraction/efr32/sl_gp_interface.c b/openthread/platform-abstraction/efr32/sl_gp_interface.c +index b4601a1..226ea80 100644 +--- a/openthread/platform-abstraction/efr32/sl_gp_interface.c ++++ b/openthread/platform-abstraction/efr32/sl_gp_interface.c +@@ -323,7 +323,8 @@ bool sl_gp_intf_is_gp_pkt(otRadioFrame *aFrame) + bool networkVersionCheck = GP_NWK_PROTOCOL_VERSION_CHECK(fc); + bool frameVersionCheck = (efr32GetFrameVersion(aFrame) == IEEE802154_FRAME_VERSION_2003); + +- isGpPkt = (lengthCheck && networkVersionCheck && frameVersionCheck); ++ // Patched out: misclassifies zero-payload 2003 MAC commands (it reads past the frame) ++ isGpPkt = false && (lengthCheck && networkVersionCheck && frameVersionCheck); + #if 0 // Debugging + if (!isGpPkt) + {