# STM32WB55 Zigbee master/slave notes ## Project files - Keil project: `MDK-ARM/Zigbee_OnOff_Server_Coord.uvprojx` - Main app config: `App/app_config.h` - Shared data types: `App/app_types.h` - GPIO/hardware layer: `App/hardware.c` - Slave input scan/debounce: `App/slave_inputs.c` - App role/process logic: `App/zigbee_app.c` - Zigbee adapter: `App/zigbee_port.c` - STM32_WPAN Zigbee implementation: `STM32_WPAN/App/app_zigbee.c` ## Roles Role is selected at build time while role detect is disabled: ```c #define APP_ROLE_DEFAULT APP_ROLE_MASTER #define APP_ROLE_DETECT_ENABLED 0U ``` For the slave firmware build: ```c #define APP_ROLE_DEFAULT APP_ROLE_SLAVE ``` `APP_ROLE_MASTER` forms the Zigbee network as coordinator. `APP_ROLE_SLAVE` joins the coordinator network and sends input reports. ## Pins Button inputs: | Signal | Port | Pin | Active level | | --- | --- | --- | --- | | Button 1 | GPIOB | GPIO_PIN_0 | 0 | | Button 2 | GPIOB | GPIO_PIN_1 | 0 | | Button 3 | GPIOB | GPIO_PIN_2 | 0 | Config: ```c #define APP_BUTTON_ACTIVE_LEVEL 0U #define APP_BUTTON_DEBOUNCE_MS 20U #define APP_BUTTON_GPIO_PORT GPIOB #define APP_BUTTON1_GPIO_PIN GPIO_PIN_0 #define APP_BUTTON2_GPIO_PIN GPIO_PIN_1 #define APP_BUTTON3_GPIO_PIN GPIO_PIN_2 ``` Role/status LED: | Signal | Port | Pin | Active level | | --- | --- | --- | --- | | APP_ROLE_LED | GPIOE | GPIO_PIN_4 | GPIO_PIN_SET | Config: ```c #define APP_ROLE_LED_GPIO_PORT GPIOE #define APP_ROLE_LED_GPIO_PIN GPIO_PIN_4 #define APP_ROLE_LED_ACTIVE_LEVEL GPIO_PIN_SET ``` Role detect pins are currently unused: ```c #define APP_ROLE_DETECT_ENABLED 0U #define APP_ROLE_DETECT_GPIO_PORT GPIOA #define APP_ROLE_DETECT_GPIO_PIN GPIO_PIN_9 #define APP_ROLE_DETECT_PULL GPIO_PULLDOWN #define APP_ROLE_DETECT_MASTER_LEVEL GPIO_PIN_RESET ``` ADC is reserved in the app model, but `Hardware_ReadAnalogRaw()` currently returns `0`. ## Zigbee network settings ```c #define APP_ZIGBEE_ENDPOINT 10U #define APP_ZIGBEE_CLUSTER_INPUTS 0xFC10U #define APP_ZIGBEE_REPORT_PERIOD_MS 100U #define APP_ZIGBEE_CHANNEL 20U #define APP_ZIGBEE_PAN_ID 0x1234U #define APP_ZIGBEE_EXTENDED_PAN_ID 0x1122334455667788ULL #define APP_ZIGBEE_PERMIT_JOIN_SEC 0xFFU #define APP_ZIGBEE_PERMIT_REFRESH_MS 5000U #define APP_ZIGBEE_REJOIN_FAIL_COUNT 3U #define APP_ZIGBEE_REJOIN_RETRY_MS 15000U ``` Master opens permit-join and refreshes it every 5 seconds. Slave sends reports to coordinator short address `0x0000`, endpoint `APP_ZIGBEE_ENDPOINT`. Current slave TX options: ```c ZB_APSDE_DATAREQ_TXOPTIONS_SECURITY | ZB_APSDE_DATAREQ_TXOPTIONS_ACK ``` ACK is enabled so slave can detect `ZB_APS_STATUS_NO_ACK` when master is missing. ## Slave input data Local slave input state: ```c typedef struct { AppButton_t buttons[3]; AppAnalogChannel_t analog; uint32_t sequence; } AppSlaveInputs_t; ``` Report sent over Zigbee: ```c typedef struct { uint32_t sequence; uint8_t button_mask; uint16_t analog_raw; uint8_t analog_percent; } AppSlaveReport_t; ``` Button mask bits: | Bit | Button | | --- | --- | | bit0 | Button 1 | | bit1 | Button 2 | | bit2 | Button 3 | Examples: | button_mask | Meaning | | --- | --- | | 0 | No buttons pressed | | 1 | Button 1 | | 2 | Button 2 | | 4 | Button 3 | | 3 | Button 1 + Button 2 | | 7 | All 3 buttons | Wire payload, 8 bytes: | Byte | Field | | --- | --- | | 0..3 | sequence, little-endian | | 4 | button_mask | | 5..6 | analog_raw, little-endian | | 7 | analog_percent | Master stores the last received report here: ```c g_app.master_node.last_report g_app.master_node.last_report.button_mask ``` ## Connection behavior Master `APP_ZB_CONNECTED` means the coordinator formed its Zigbee network. It does not mean that slave is online. Slave is considered visible on master only after first report: ```c g_app.master_node.online = true; watch_master_online = 1; watch_report_rx_count++; ``` When master is turned off while slave is running: 1. Slave TX confirm starts returning `0xA7` (`ZB_APS_STATUS_NO_ACK`). 2. `watch_report_tx_fail_streak` increases. 3. After `APP_ZIGBEE_REJOIN_FAIL_COUNT` failures, slave resets local Zigbee stack with `ZbReset()`. 4. Slave starts normal join again through `CFG_TASK_ZIGBEE_NETWORK_FORM`. When slave is reset while master is running: 1. Master must keep permit-join open. 2. Check `watch_permit_join_count`, `watch_permit_join_status`, and `watch_permit_join_duration` on master. 3. Expected values: count increases, status `0`, duration `0xFF`. ## LED status patterns LED: `APP_ROLE_LED` on GPIOE pin 4. Patterns are non-blocking and updated from `ZigbeeApp_UpdateStatusLed()`. | State | Pattern | | --- | --- | | DISCONNECTED | Short flash every 400 ms | | JOINING | Fast 80 ms on / 80 ms off | | ERROR | Very fast 50 ms on / 50 ms off | | CONNECTED master | One short flash every second | | CONNECTED slave | Two short flashes every second | ## Useful watch variables Role/state: ```c watch_role watch_is_master watch_is_slave watch_zigbee_state watch_zigbee_ready ``` Master receive: ```c watch_master_online watch_master_last_seen_ms watch_master_last_sequence watch_master_button_mask watch_report_rx_count watch_report_rx_ind_count watch_report_rx_decode_fail_count watch_report_rx_last_cluster watch_report_rx_last_length ``` Slave transmit: ```c watch_slave_sequence watch_slave_button_mask watch_report_tx_count watch_report_tx_attempt_count watch_report_tx_ok_count watch_report_tx_busy_count watch_report_tx_confirm_count watch_report_tx_confirm_status watch_report_tx_fail_streak ``` Rejoin/recovery: ```c watch_rejoin_request_count watch_rejoin_success_count watch_rejoin_fail_count watch_rejoin_active watch_rejoin_last_status ``` Master permit-join: ```c watch_permit_join_count watch_permit_join_status watch_permit_join_duration ``` ## Common status codes | Code | Meaning | | --- | --- | | 0x00 | Success | | 0xA7 | `ZB_APS_STATUS_NO_ACK`, destination did not ACK | | 0xCA | `ZB_NWK_STATUS_NO_NETWORKS`, no matching network found | | 0xD0 | `ZB_NWK_STATUS_ROUTE_DISCOVERY_FAILED` | | 0xD1 | `ZB_NWK_STATUS_ROUTE_ERROR` | ## Current debug checklist Master after startup: ```text watch_is_master = 1 watch_zigbee_state = 2 watch_permit_join_count increasing watch_permit_join_status = 0 watch_permit_join_duration = 0xFF ``` Slave after join: ```text watch_is_slave = 1 watch_zigbee_state = 2 watch_zigbee_ready = 1 watch_report_tx_confirm_status = 0 ``` Master after receiving slave: ```text watch_master_online = 1 watch_report_rx_count increasing watch_master_button_mask follows slave buttons ```