From 44ac3ef0a873caa65395621afcb9de87a8ebc232 Mon Sep 17 00:00:00 2001 From: silabs-mehdi Date: Mon, 7 Sep 2026 12:37:18 +0200 Subject: [PATCH 1/2] advertising applications reorganisation --- .../encrypted_advertisement/README.md | 0 .../SimplicityStudio/readme.md | 0 .../soc_encrypted_advertisement_advertiser.slcp | 0 .../soc_encrypted_advertisement_scanner.slcp | 0 .../config/advertiser/gatt_configuration.btconf | 0 .../config/scanner/gatt_configuration.btconf | 0 .../images/add_log_1.png | Bin .../images/add_log_2.png | Bin .../images/add_log_3.png | Bin .../images/add_log_4.png | Bin .../images/add_log_5.png | Bin .../images/add_simple_button_1.png | Bin .../images/add_simple_button_2.png | Bin .../images/add_simple_button_3.png | Bin .../encrypted_advertisement/images/btconf.png | Bin .../images/encrypted_advertisement.png | Bin .../images/extended_scanner.png | Bin .../encrypted_advertisement/images/result.png | Bin .../inc/advertiser/app.h | 0 .../encrypted_advertisement/inc/scanner/app.h | 0 .../src/advertiser/app.c | 0 .../src/advertiser/app_bm.c | 0 .../src/advertiser/main.c | 0 .../encrypted_advertisement/src/scanner/app.c | 0 .../src/scanner/app_bm.c | 0 .../encrypted_advertisement/src/scanner/main.c | 0 .../{ => pawr_sync_transfer}/README.md | 0 .../SimplicityStudio/readme.md | 0 .../SimplicityStudio/soc_pawr_advertiser.slcp | 0 .../SimplicityStudio/soc_pawr_scanner.slcp | 0 .../config/gatt_configuration.btconf | 0 .../images/console_output.png | Bin .../images/pawr_timing.png | Bin .../images/sequence.png | Bin .../inc/advertiser/app.h | 0 .../{ => pawr_sync_transfer}/inc/scanner/app.h | 0 .../src/pawr_advertiser/app.c | 0 .../src/pawr_advertiser/main.c | 0 .../src/pawr_scanner/app.c | 0 .../src/pawr_scanner/main.c | 0 bluetooth_stack_features_app_templates.xml | 16 ++++++++-------- 41 files changed, 8 insertions(+), 8 deletions(-) rename {security => advertising}/encrypted_advertisement/README.md (100%) rename {security => advertising}/encrypted_advertisement/SimplicityStudio/readme.md (100%) rename {security => advertising}/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_advertiser.slcp (100%) rename {security => advertising}/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_scanner.slcp (100%) rename {security => advertising}/encrypted_advertisement/config/advertiser/gatt_configuration.btconf (100%) rename {security => advertising}/encrypted_advertisement/config/scanner/gatt_configuration.btconf (100%) rename {security => advertising}/encrypted_advertisement/images/add_log_1.png (100%) rename {security => advertising}/encrypted_advertisement/images/add_log_2.png (100%) rename {security => advertising}/encrypted_advertisement/images/add_log_3.png (100%) rename {security => advertising}/encrypted_advertisement/images/add_log_4.png (100%) rename {security => advertising}/encrypted_advertisement/images/add_log_5.png (100%) rename {security => advertising}/encrypted_advertisement/images/add_simple_button_1.png (100%) rename {security => advertising}/encrypted_advertisement/images/add_simple_button_2.png (100%) rename {security => advertising}/encrypted_advertisement/images/add_simple_button_3.png (100%) rename {security => advertising}/encrypted_advertisement/images/btconf.png (100%) rename {security => advertising}/encrypted_advertisement/images/encrypted_advertisement.png (100%) rename {security => advertising}/encrypted_advertisement/images/extended_scanner.png (100%) rename {security => advertising}/encrypted_advertisement/images/result.png (100%) rename {security => advertising}/encrypted_advertisement/inc/advertiser/app.h (100%) rename {security => advertising}/encrypted_advertisement/inc/scanner/app.h (100%) rename {security => advertising}/encrypted_advertisement/src/advertiser/app.c (100%) rename {security => advertising}/encrypted_advertisement/src/advertiser/app_bm.c (100%) rename {security => advertising}/encrypted_advertisement/src/advertiser/main.c (100%) rename {security => advertising}/encrypted_advertisement/src/scanner/app.c (100%) rename {security => advertising}/encrypted_advertisement/src/scanner/app_bm.c (100%) rename {security => advertising}/encrypted_advertisement/src/scanner/main.c (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/README.md (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/SimplicityStudio/readme.md (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/SimplicityStudio/soc_pawr_advertiser.slcp (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/SimplicityStudio/soc_pawr_scanner.slcp (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/config/gatt_configuration.btconf (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/images/console_output.png (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/images/pawr_timing.png (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/images/sequence.png (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/inc/advertiser/app.h (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/inc/scanner/app.h (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/src/pawr_advertiser/app.c (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/src/pawr_advertiser/main.c (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/src/pawr_scanner/app.c (100%) rename advertising/periodic_advertisement_with_responses/{ => pawr_sync_transfer}/src/pawr_scanner/main.c (100%) diff --git a/security/encrypted_advertisement/README.md b/advertising/encrypted_advertisement/README.md similarity index 100% rename from security/encrypted_advertisement/README.md rename to advertising/encrypted_advertisement/README.md diff --git a/security/encrypted_advertisement/SimplicityStudio/readme.md b/advertising/encrypted_advertisement/SimplicityStudio/readme.md similarity index 100% rename from security/encrypted_advertisement/SimplicityStudio/readme.md rename to advertising/encrypted_advertisement/SimplicityStudio/readme.md diff --git a/security/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_advertiser.slcp b/advertising/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_advertiser.slcp similarity index 100% rename from security/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_advertiser.slcp rename to advertising/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_advertiser.slcp diff --git a/security/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_scanner.slcp b/advertising/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_scanner.slcp similarity index 100% rename from security/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_scanner.slcp rename to advertising/encrypted_advertisement/SimplicityStudio/soc_encrypted_advertisement_scanner.slcp diff --git a/security/encrypted_advertisement/config/advertiser/gatt_configuration.btconf b/advertising/encrypted_advertisement/config/advertiser/gatt_configuration.btconf similarity index 100% rename from security/encrypted_advertisement/config/advertiser/gatt_configuration.btconf rename to advertising/encrypted_advertisement/config/advertiser/gatt_configuration.btconf diff --git a/security/encrypted_advertisement/config/scanner/gatt_configuration.btconf b/advertising/encrypted_advertisement/config/scanner/gatt_configuration.btconf similarity index 100% rename from security/encrypted_advertisement/config/scanner/gatt_configuration.btconf rename to advertising/encrypted_advertisement/config/scanner/gatt_configuration.btconf diff --git a/security/encrypted_advertisement/images/add_log_1.png b/advertising/encrypted_advertisement/images/add_log_1.png similarity index 100% rename from security/encrypted_advertisement/images/add_log_1.png rename to advertising/encrypted_advertisement/images/add_log_1.png diff --git a/security/encrypted_advertisement/images/add_log_2.png b/advertising/encrypted_advertisement/images/add_log_2.png similarity index 100% rename from security/encrypted_advertisement/images/add_log_2.png rename to advertising/encrypted_advertisement/images/add_log_2.png diff --git a/security/encrypted_advertisement/images/add_log_3.png b/advertising/encrypted_advertisement/images/add_log_3.png similarity index 100% rename from security/encrypted_advertisement/images/add_log_3.png rename to advertising/encrypted_advertisement/images/add_log_3.png diff --git a/security/encrypted_advertisement/images/add_log_4.png b/advertising/encrypted_advertisement/images/add_log_4.png similarity index 100% rename from security/encrypted_advertisement/images/add_log_4.png rename to advertising/encrypted_advertisement/images/add_log_4.png diff --git a/security/encrypted_advertisement/images/add_log_5.png b/advertising/encrypted_advertisement/images/add_log_5.png similarity index 100% rename from security/encrypted_advertisement/images/add_log_5.png rename to advertising/encrypted_advertisement/images/add_log_5.png diff --git a/security/encrypted_advertisement/images/add_simple_button_1.png b/advertising/encrypted_advertisement/images/add_simple_button_1.png similarity index 100% rename from security/encrypted_advertisement/images/add_simple_button_1.png rename to advertising/encrypted_advertisement/images/add_simple_button_1.png diff --git a/security/encrypted_advertisement/images/add_simple_button_2.png b/advertising/encrypted_advertisement/images/add_simple_button_2.png similarity index 100% rename from security/encrypted_advertisement/images/add_simple_button_2.png rename to advertising/encrypted_advertisement/images/add_simple_button_2.png diff --git a/security/encrypted_advertisement/images/add_simple_button_3.png b/advertising/encrypted_advertisement/images/add_simple_button_3.png similarity index 100% rename from security/encrypted_advertisement/images/add_simple_button_3.png rename to advertising/encrypted_advertisement/images/add_simple_button_3.png diff --git a/security/encrypted_advertisement/images/btconf.png b/advertising/encrypted_advertisement/images/btconf.png similarity index 100% rename from security/encrypted_advertisement/images/btconf.png rename to advertising/encrypted_advertisement/images/btconf.png diff --git a/security/encrypted_advertisement/images/encrypted_advertisement.png b/advertising/encrypted_advertisement/images/encrypted_advertisement.png similarity index 100% rename from security/encrypted_advertisement/images/encrypted_advertisement.png rename to advertising/encrypted_advertisement/images/encrypted_advertisement.png diff --git a/security/encrypted_advertisement/images/extended_scanner.png b/advertising/encrypted_advertisement/images/extended_scanner.png similarity index 100% rename from security/encrypted_advertisement/images/extended_scanner.png rename to advertising/encrypted_advertisement/images/extended_scanner.png diff --git a/security/encrypted_advertisement/images/result.png b/advertising/encrypted_advertisement/images/result.png similarity index 100% rename from security/encrypted_advertisement/images/result.png rename to advertising/encrypted_advertisement/images/result.png diff --git a/security/encrypted_advertisement/inc/advertiser/app.h b/advertising/encrypted_advertisement/inc/advertiser/app.h similarity index 100% rename from security/encrypted_advertisement/inc/advertiser/app.h rename to advertising/encrypted_advertisement/inc/advertiser/app.h diff --git a/security/encrypted_advertisement/inc/scanner/app.h b/advertising/encrypted_advertisement/inc/scanner/app.h similarity index 100% rename from security/encrypted_advertisement/inc/scanner/app.h rename to advertising/encrypted_advertisement/inc/scanner/app.h diff --git a/security/encrypted_advertisement/src/advertiser/app.c b/advertising/encrypted_advertisement/src/advertiser/app.c similarity index 100% rename from security/encrypted_advertisement/src/advertiser/app.c rename to advertising/encrypted_advertisement/src/advertiser/app.c diff --git a/security/encrypted_advertisement/src/advertiser/app_bm.c b/advertising/encrypted_advertisement/src/advertiser/app_bm.c similarity index 100% rename from security/encrypted_advertisement/src/advertiser/app_bm.c rename to advertising/encrypted_advertisement/src/advertiser/app_bm.c diff --git a/security/encrypted_advertisement/src/advertiser/main.c b/advertising/encrypted_advertisement/src/advertiser/main.c similarity index 100% rename from security/encrypted_advertisement/src/advertiser/main.c rename to advertising/encrypted_advertisement/src/advertiser/main.c diff --git a/security/encrypted_advertisement/src/scanner/app.c b/advertising/encrypted_advertisement/src/scanner/app.c similarity index 100% rename from security/encrypted_advertisement/src/scanner/app.c rename to advertising/encrypted_advertisement/src/scanner/app.c diff --git a/security/encrypted_advertisement/src/scanner/app_bm.c b/advertising/encrypted_advertisement/src/scanner/app_bm.c similarity index 100% rename from security/encrypted_advertisement/src/scanner/app_bm.c rename to advertising/encrypted_advertisement/src/scanner/app_bm.c diff --git a/security/encrypted_advertisement/src/scanner/main.c b/advertising/encrypted_advertisement/src/scanner/main.c similarity index 100% rename from security/encrypted_advertisement/src/scanner/main.c rename to advertising/encrypted_advertisement/src/scanner/main.c diff --git a/advertising/periodic_advertisement_with_responses/README.md b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/README.md similarity index 100% rename from advertising/periodic_advertisement_with_responses/README.md rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/README.md diff --git a/advertising/periodic_advertisement_with_responses/SimplicityStudio/readme.md b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/readme.md similarity index 100% rename from advertising/periodic_advertisement_with_responses/SimplicityStudio/readme.md rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/readme.md diff --git a/advertising/periodic_advertisement_with_responses/SimplicityStudio/soc_pawr_advertiser.slcp b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/soc_pawr_advertiser.slcp similarity index 100% rename from advertising/periodic_advertisement_with_responses/SimplicityStudio/soc_pawr_advertiser.slcp rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/soc_pawr_advertiser.slcp diff --git a/advertising/periodic_advertisement_with_responses/SimplicityStudio/soc_pawr_scanner.slcp b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/soc_pawr_scanner.slcp similarity index 100% rename from advertising/periodic_advertisement_with_responses/SimplicityStudio/soc_pawr_scanner.slcp rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/soc_pawr_scanner.slcp diff --git a/advertising/periodic_advertisement_with_responses/config/gatt_configuration.btconf b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/config/gatt_configuration.btconf similarity index 100% rename from advertising/periodic_advertisement_with_responses/config/gatt_configuration.btconf rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/config/gatt_configuration.btconf diff --git a/advertising/periodic_advertisement_with_responses/images/console_output.png b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/images/console_output.png similarity index 100% rename from advertising/periodic_advertisement_with_responses/images/console_output.png rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/images/console_output.png diff --git a/advertising/periodic_advertisement_with_responses/images/pawr_timing.png b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/images/pawr_timing.png similarity index 100% rename from advertising/periodic_advertisement_with_responses/images/pawr_timing.png rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/images/pawr_timing.png diff --git a/advertising/periodic_advertisement_with_responses/images/sequence.png b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/images/sequence.png similarity index 100% rename from advertising/periodic_advertisement_with_responses/images/sequence.png rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/images/sequence.png diff --git a/advertising/periodic_advertisement_with_responses/inc/advertiser/app.h b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/inc/advertiser/app.h similarity index 100% rename from advertising/periodic_advertisement_with_responses/inc/advertiser/app.h rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/inc/advertiser/app.h diff --git a/advertising/periodic_advertisement_with_responses/inc/scanner/app.h b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/inc/scanner/app.h similarity index 100% rename from advertising/periodic_advertisement_with_responses/inc/scanner/app.h rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/inc/scanner/app.h diff --git a/advertising/periodic_advertisement_with_responses/src/pawr_advertiser/app.c b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_advertiser/app.c similarity index 100% rename from advertising/periodic_advertisement_with_responses/src/pawr_advertiser/app.c rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_advertiser/app.c diff --git a/advertising/periodic_advertisement_with_responses/src/pawr_advertiser/main.c b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_advertiser/main.c similarity index 100% rename from advertising/periodic_advertisement_with_responses/src/pawr_advertiser/main.c rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_advertiser/main.c diff --git a/advertising/periodic_advertisement_with_responses/src/pawr_scanner/app.c b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_scanner/app.c similarity index 100% rename from advertising/periodic_advertisement_with_responses/src/pawr_scanner/app.c rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_scanner/app.c diff --git a/advertising/periodic_advertisement_with_responses/src/pawr_scanner/main.c b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_scanner/main.c similarity index 100% rename from advertising/periodic_advertisement_with_responses/src/pawr_scanner/main.c rename to advertising/periodic_advertisement_with_responses/pawr_sync_transfer/src/pawr_scanner/main.c diff --git a/bluetooth_stack_features_app_templates.xml b/bluetooth_stack_features_app_templates.xml index ce143d8..d745606 100644 --- a/bluetooth_stack_features_app_templates.xml +++ b/bluetooth_stack_features_app_templates.xml @@ -461,8 +461,8 @@ - - + + @@ -473,8 +473,8 @@ - - + + @@ -488,8 +488,8 @@ solely on the private address and advertising data. "> - - + + @@ -503,8 +503,8 @@ solely on the private address and advertising data. "> - - + + From bafe8fb40679129ec9045b9b8de5a304d8ebc883 Mon Sep 17 00:00:00 2001 From: silabs-mehdi Date: Tue, 8 Sep 2026 13:30:09 +0200 Subject: [PATCH 2/2] added encrypted_pawr Access point and tag apps --- .../encrypted_pawr/README.md | 248 ++++ .../encrypted_pawr/SimplicityStudio/readme.md | 8 + .../soc_encrypted_pawr_access_point.slcp | 62 + .../soc_encrypted_pawr_tag.slcp | 68 ++ .../config/gatt_configuration.btconf | 82 ++ .../encrypted_pawr/images/ap_log.png | Bin 0 -> 88293 bytes .../encrypted_pawr/images/tag_log.png | Bin 0 -> 68408 bytes .../encrypted_pawr/inc/access_point/app.h | 79 ++ .../encrypted_pawr/inc/tag/app.h | 79 ++ .../encrypted_pawr/src/access_point/app.c | 1018 +++++++++++++++++ .../encrypted_pawr/src/access_point/main.c | 71 ++ .../encrypted_pawr/src/tag/app.c | 514 +++++++++ .../encrypted_pawr/src/tag/main.c | 71 ++ .../SimplicityStudio/readme.md | 2 +- bluetooth_stack_features_app_templates.xml | 24 + 15 files changed, 2325 insertions(+), 1 deletion(-) create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/README.md create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/readme.md create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_access_point.slcp create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_tag.slcp create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/config/gatt_configuration.btconf create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/images/ap_log.png create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/images/tag_log.png create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/access_point/app.h create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/tag/app.h create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/app.c create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/main.c create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/app.c create mode 100644 advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/main.c diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/README.md b/advertising/periodic_advertisement_with_responses/encrypted_pawr/README.md new file mode 100644 index 0000000..480f332 --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/README.md @@ -0,0 +1,248 @@ +# Encrypted Periodic Advertising with Responses and PAST Example + +## Description + +This example demonstrates secure application-data exchange between one access point and multiple tags using Bluetooth LE Periodic Advertising with Responses (PAwR) Encrypted Advertising Data (EAD), and Periodic Advertising Synchronization Transfer (PAST). + +The example consists of two projects: + +- **Access point:** provisions tags, operates the PAwR advertiser, encrypts subevent data, and decrypts tag responses. +- **Tag:** advertises for provisioning, receives PAwR synchronization through PAST, decrypts its assigned subevent, and sends an encrypted response. + +A temporary Bluetooth connection is used to provision each tag. After provisioning, the regular data exchange is connectionless and uses PAwR subevents and response slots. + +### Access point + +At boot, the access point initializes its EAD session, begins scanning for tags, and starts its PAwR train. It uses passive scanning on the 1M PHY and identifies tags by the custom **Secure Tag** service UUID included in their extended advertisements. + +In this demonstration, a tag ID selects both the subevent to which the tag subscribes and the response slot in which it transmits. This one-to-one mapping is an application choice and can be changed as needed. + +The following APIs perform the main access-point operations. + +1. Configure and start scanning for tags: + +```c +sl_bt_scanner_set_parameters(sl_bt_scanner_scan_mode_passive, + 200, + 200); + +sl_bt_scanner_start(sl_bt_scanner_scan_phy_1m, + sl_bt_scanner_discover_observation); +``` + +2. Create an advertising set and start the PAwR advertiser: + +```c +sl_bt_advertiser_create_set(&pawr_advertising_set_handle); + +sl_bt_pawr_advertiser_start(pawr_advertising_set_handle, + PERIODIC_ADV_INTERVAL, + PERIODIC_ADV_INTERVAL, + 0, + SUBEVENT_NUMBER, + SUBEVENT_INTERVAL, + RESPONSE_SLOT_DELAY, + RESPONSE_SLOT_SPACING, + RESPONSE_SLOT_NUMBER_PER_SUBVENT); +``` + +3. Connect to a discovered tag and provision it through GATT: + +```c +sl_bt_connection_open(report->address, + report->address_type, + sl_bt_gap_phy_1m, + &connection_handle); + +sl_bt_gatt_discover_primary_services_by_uuid(...); +sl_bt_gatt_discover_characteristics_by_uuid(...); +sl_bt_gatt_write_characteristic_value(...); +``` + +4. Transfer the PAwR synchronization information to the tag using PAST: + +```c +sl_bt_advertiser_past_transfer(connection_handle, + 0, + pawr_advertising_set_handle); +``` + +5. Encrypt and provide data for each requested PAwR subevent: + +```c +sl_bt_ead_randomizer_update(&nonce); +sl_bt_ead_encrypt(...); +sl_bt_ead_pack_ad_data(...); + +sl_bt_pawr_advertiser_set_subevent_data(req.advertising_set, + subevent_index, + 0, + RESPONSE_SLOT_NUMBER_PER_SUBVENT, + advertisement_len, + advertisement_buffer); +``` + +When a response report is received, the access point uses the response slot to locate the associated tag record and tag-specific key. It unpacks and decrypts the response using `sl_bt_ead_unpack_ad_data()` and `sl_bt_ead_decrypt()`. + +The access point periodically checks its tag records. A tag without a successfully decrypted response for 30 seconds is marked stale, allowing its ID and response key slot to be reused. + +### Tag + +At boot, the tag configures itself to synchronize when PAST information is received. It then starts connectable extended advertising. The tag's GATT database advertises the custom [Secure Tag service](config/gatt_configuration.btconf#L51), which contains: + +- **Tag ID:** the identifier assigned by the access point. +- **AP Sync Key Material:** the EAD session key and initialization vector used to decrypt access-point subevent data. +- **Tag Response Key Material:** the tag-specific EAD session key and initialization vector used to encrypt responses. + +The following APIs perform the main tag operations. + +1. Configure automatic synchronization from received PAST information: + +```c +sl_bt_past_receiver_set_default_sync_receive_parameters( + sl_bt_past_receiver_mode_synchronize, + PERIODIC_SYNC_SKIP, + PERIODIC_SYNC_TIMEOUT, + sl_bt_sync_report_all); +``` + +2. Start connectable extended advertising for discovery and provisioning: + +```c +sl_bt_advertiser_create_set(&advertising_set_handle); +sl_bt_extended_advertiser_generate_data( + advertising_set_handle, + sl_bt_advertiser_general_discoverable); + +sl_bt_extended_advertiser_start( + advertising_set_handle, + sl_bt_extended_advertiser_connectable, + 0); +``` + +3. After receiving the PAST transfer, subscribe to the subevent assigned by the tag ID: + +```c +sl_bt_pawr_sync_set_sync_subevents( + pawr_handle, + sizeof(subevents_subscription_list), + subevents_subscription_list); +``` + +4. Decrypt the received subevent data and prepare an encrypted response: + +```c +sl_bt_ead_unpack_ad_data(...); +sl_bt_ead_decrypt(...); +sl_bt_ead_randomizer_update(&tag_resp_nonce); +sl_bt_ead_encrypt(...); +sl_bt_ead_pack_ad_data(...); +``` + +5. Send the response in the slot assigned to the tag: + +```c +sl_bt_pawr_sync_set_response_data(pawr_handle, + sync_report->event_counter, + sync_report->subevent, + sync_report->subevent, + tag_id, + secret_data_len, + response_buffer); +``` + +If the tag loses PAwR synchronization while it is disconnected, a periodic timer causes it to resume connectable advertising so that the access point can provision it again. + +### Provisioning and synchronization sequence + +1. The access point starts the PAwR train and scans for the Secure Tag service. +2. The tag starts connectable extended advertising. +3. The access point discovers the tag and opens a Bluetooth connection. +4. The access point discovers the Secure Tag service and its three characteristics. +5. The devices establish a bonded, encrypted LE Secure Connections link. +6. The access point assigns a tag ID. +7. The access point writes the shared AP synchronization key material. +8. The access point creates and writes unique response key material for the tag. +9. The access point transfers the PAwR synchronization information using PAST. +10. The access point records the tag as active and closes the connection. +11. The tag subscribes to the subevent corresponding to its assigned ID. +12. The devices continue exchanging encrypted data without a Bluetooth connection. + +## Simplicity SDK version + +- Simplicity SDK v2025.12.1 + +## Hardware required + +- Two or more Wireless Starter Kit mainboards +- One Bluetooth-capable Series 2 radio board for the access point +- One Bluetooth-capable Series 2 radio board for each tag + +At least two devices are required: one access point and one tag. + +## Setting up + +> **Note:** The provided projects already contain the required source files, software components, and configuration. The following steps are useful if you you are starting from the basic bluetooth empty + +### Access point + +1. Open Simplicity Studio v6 with Simplicity SDK v2025.12.1 or a compatible version. +2. generate a bluetooth empty project. +3. Verify that the following important software components are installed: + - Extended Advertising + - Scanner for extended advertisements + - Periodic Advertising using PAwR trains + - Transfer periodic synchronization information for a local advertising set + - GATT Client + - Security Manager + - Encrypted Advertising Data Core + - Log +4. Verify that [app.c](src/access_point/app.c), [main.c](src/access_point/main.c), and [app.h](inc/access_point/app.h) are included in the generated project. +5. Build and flash the project to the access-point device. +6. Open the serial console for the device. (make sure that you enable VCOM in the board control component) + +### Tag + +1. Open Simplicity Studio v6 with Simplicity SDK v2025.12.1 or a compatible version. +2. Verify that the following important software components are installed: + - Extended Advertising + - PAST Receiver + - Synchronization to Periodic Advertising with Responses trains + - GATT Server + - Security Manager + - Encrypted Advertising Data Core + - Log +3. Insert [gatt_configuration.btconf](config/gatt_configuration.btconf) is the config/btconf directory +5. Verify that [app.c](src/tag/app.c), [main.c](src/tag/main.c), and [app.h](inc/tag/app.h) are included in the generated project. +6. Build and flash the project to the tag device. +7. Open the serial console for the device.(make sure that you enable VCOM in the board control component) + +## Usage + +1. Reset the access point. It prints its Bluetooth address, starts scanning for tags, and starts the PAwR train. +2. Reset a tag. It advertises the Secure Tag service. +3. The access point connects to the tag, assigns an ID, provisions the EAD keys, and transfers PAwR synchronization. +4. After the connection closes, the tag reports the received PAwR timing and synchronization state. +5. Observe the tag decrypting access-point messages and the access point decrypting tag responses. +6. Reset additional tags one at a time to provision multiple devices. + +## Results + +Below is the tag log, it shows: +- A boot sequence that starts advertising +- A connection with increased security +- Reception of an ID (also keys that are not logged here) +- Reception of the PAWR train and connection close +- The subevent subscribed and the payload +- The response and its payload + +![tag_log](images/tag_log.png) + +Below is the access point log, it shows: +- A boot sequence that starts scanning for tags +- The stack requests to the application for the subevents data of the PAWR train +- A connection event with increased security +- GATT operation to write a tag ID, AP sync key and tag response key +- The response from the tag to subevent 0 in response slot 0 + +![ap_log](images/ap_log.png) diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/readme.md b/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/readme.md new file mode 100644 index 0000000..0e1c633 --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/readme.md @@ -0,0 +1,8 @@ +# encrypted pawr Example + +The readme file of this project can be found [here](https://github.com/SiliconLabs/bluetooth_stack_features/blob/master/advertising/periodic_advertisement_with_responses/encrypted_pawr/README.md). + +. +> Note: In this project all the necessary software components are installed, source files are copied, and configurations are set, hence you can disregard the Setting Up section of the online readme file. Nevertheless, if you want to add the demonstrated feature to your own project, it might be good to know what software components you must install, and what configurations you must set beforehand, hence reading through the Setting Up section might be useful. + +> Note: This project requires a bootloader. For Series 1 (EFR32xG1x) devices please flash a **Bluetooth In-place OTA DFU** bootloader or an **Internal Storage** bootloader to your device to get this application to work. For Series 2 (EFR32xG2x) devices please flash a **Bluetooth Apploader OTA DFU** bootloader to your device diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_access_point.slcp b/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_access_point.slcp new file mode 100644 index 0000000..f2ca6bc --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_access_point.slcp @@ -0,0 +1,62 @@ +project_name: soc_encrypted_pawr_access_point +package: Bluetooth +label: Bluetooth - SoC Encrypted PAwR Access Point +description: > + Provisions PAwR tags, transfers synchronization with PAST, and exchanges encrypted advertising data. +category: Bluetooth Examples +quality: development + +component: + - id: device_init + - id: clock_manager + - id: bluetooth_stack + - id: gatt_configuration + - id: bluetooth_feature_legacy_advertiser + - id: bluetooth_feature_extended_advertiser + - id: bluetooth_feature_legacy_scanner + - id: bluetooth_feature_extended_scanner + - id: bluetooth_feature_connection_role_central + - id: bluetooth_feature_connection_role_peripheral + - id: bluetooth_feature_gatt + - id: bluetooth_feature_gatt_server + - id: bluetooth_feature_sm + - id: bluetooth_feature_system + - id: bluetooth_feature_pawr_advertiser + - id: bluetooth_feature_advertiser_past + - id: ead_core + - id: app_assert + - id: app_log + - id: app_os_helper + - id: component_catalog + - id: gatt_service_device_information_override + - id: mpu + - id: rail_util_pti + - id: sl_main + +source: + - path: ../src/access_point/app.c + - path: ../src/access_point/main.c + +include: + - path: ../inc/access_point/ + file_list: + - path: app.h + +readme: + - path: ../README.md + +configuration: + - name: SL_STACK_SIZE + value: "2752" + - condition: + - psa_crypto + name: SL_PSA_KEY_USER_SLOT_COUNT + value: "0" + +tag: + - hardware:rf:band:2400 + +ui_hints: + highlight: + - path: ../README.md + focus: true diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_tag.slcp b/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_tag.slcp new file mode 100644 index 0000000..18a1a22 --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/SimplicityStudio/soc_encrypted_pawr_tag.slcp @@ -0,0 +1,68 @@ +project_name: soc_encrypted_pawr_tag +package: Bluetooth +label: Bluetooth - SoC Encrypted PAwR Tag +description: > + Receives PAwR synchronization with PAST and exchanges encrypted advertising data with an access point. +category: Bluetooth Examples +quality: development + +component: + - id: device_init + - id: clock_manager + - id: bluetooth_stack + - id: gatt_configuration + - id: bluetooth_feature_legacy_advertiser + - id: bluetooth_feature_extended_advertiser + - id: bluetooth_feature_legacy_scanner + - id: bluetooth_feature_connection_role_central + - id: bluetooth_feature_connection_role_peripheral + - id: bluetooth_feature_gatt + - id: bluetooth_feature_gatt_server + - id: bluetooth_feature_sm + - id: bluetooth_feature_system + - id: bluetooth_feature_past_receiver + - id: bluetooth_feature_pawr_sync + - id: ead_core + - id: app_assert + - id: app_log + - id: app_os_helper + - id: component_catalog + - id: gatt_service_device_information_override + - id: mpu + - id: rail_util_pti + - id: sl_main + +source: + - path: ../src/tag/app.c + - path: ../src/tag/main.c + +include: + - path: ../inc/tag/ + file_list: + - path: app.h + +readme: + - path: ../README.md + +config_file: + - override: + component: gatt_configuration + file_id: gatt_configuration_file_id + path: ../config/gatt_configuration.btconf + directory: btconf + +configuration: + - name: SL_STACK_SIZE + value: "2752" + - condition: + - psa_crypto + name: SL_PSA_KEY_USER_SLOT_COUNT + value: "0" + +tag: + - hardware:rf:band:2400 + +ui_hints: + highlight: + - path: ../README.md + focus: true diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/config/gatt_configuration.btconf b/advertising/periodic_advertisement_with_responses/encrypted_pawr/config/gatt_configuration.btconf new file mode 100644 index 0000000..a47910b --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/config/gatt_configuration.btconf @@ -0,0 +1,82 @@ + + + + + + + Abstract: The generic_access service contains generic information about the device. All available Characteristics are readonly. + + + + tag + + + + + + + + + Abstract: The external appearance of this device. The values are composed of a category (10-bits) and sub-categories (6-bits). + 0000 + + + + + + + + + Abstract: The Device Information Service exposes manufacturer and/or vendor information about a device. Summary: This service exposes manufacturer information about a device. The Device Information Service is instantiated as a Primary Service. Only one instance of the Device Information Service is exposed on a device. + + + + Abstract: The value of this characteristic is a UTF-8 string representing the name of the manufacturer of the device. + Silicon Labs + + + + + + + + Abstract: The SYSTEM ID characteristic consists of a structure with two fields. The first field are the LSOs and the second field contains the MSOs. This is a 64-bit structure which consists of a 40-bit manufacturer-defined identifier concatenated with a 24 bit unique Organizationally Unique Identifier (OUI). The OUI is issued by the IEEE Registration Authority (http://standards.ieee.org/regauth/index.html) and is required to be used in accordance with IEEE Standard 802-2001.6 while the least significant 40 bits are manufacturer defined. If System ID generated based on a Bluetooth Device Address, it is required to be done as follows. System ID and the Bluetooth Device Address have a very similar structure: a Bluetooth Device Address is 48 bits in length and consists of a 24 bit Company Assigned Identifier (manufacturer defined identifier) concatenated with a 24 bit Company Identifier (OUI). In order to encapsulate a Bluetooth Device Address as System ID, the Company Identifier is concatenated with 0xFFFE followed by the Company Assigned Identifier of the Bluetooth Address. For more guidelines related to EUI-64, refer to http://standards.ieee.org/develop/regauth/tut/eui64.pdf. Examples: If the system ID is based of a Bluetooth Device Address with a Company Identifier (OUI) is 0x123456 and the Company Assigned Identifier is 0x9ABCDE, then the System Identifier is required to be 0x123456FFFE9ABCDE. + + + + + + + + + + + + + FF + + + + + + + + + 00 + + + + + + + + + 00 + + + + + + + + diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/images/ap_log.png b/advertising/periodic_advertisement_with_responses/encrypted_pawr/images/ap_log.png new file mode 100644 index 0000000000000000000000000000000000000000..140bf434b79eb5060d5cbaeb368fa2805be7f659 GIT binary patch literal 88293 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 literal 0 HcmV?d00001 diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/images/tag_log.png b/advertising/periodic_advertisement_with_responses/encrypted_pawr/images/tag_log.png new file mode 100644 index 0000000000000000000000000000000000000000..3abbf5d82394864905f8bbb9b972fe8c4aa2f8ad GIT binary patch literal 68408 zcmZsD2~<<();7J~TeMcNb!OCZEhcPZT=Ft@+Sv%7x>>75gsl-X%w~VO#@&48Q^rzNkgMJ zWvl$^zku&sLQh|g(9qDTTl?>eMoiu>8X79{nNv;|qY-lo-=^R;{C2D(3rGH9S8Jd= z8HtP9{B700e!l5Yw&&i%?f?FLVJmslH;?!0rQj0geXB!xf%^wmq90NAezdjv_FoC7 z|1p{rcL#3UiNbt-c>dq_z8l)}MXoLW(^S@L1dW@^h8J?Bdf5$Ge(h7@gc1B?9zijS zw45q|zQ#8Cu)r!IST(r?pc44RcddS&Abg?zVsm%OP*!Y+6JnHY%$OM4NsgitDPFE3 zi23-KHMW3Htt$(>ngCv%RLNbG%`GkFDurskill5Zlo**&)%R$yC7y&C2uML=u5b{D zxVb%wm&oPiMAf1pUaI7)l(|${B^5`348+4%(fIl{*X^A z7VY%??wb)LEr#QFyzSB%Mdr>&$B$Alc?Vx(DqJmZiMOdKP2R2*Na!<@{R&}Da^xAg zNEwKo#RZIJC#iFCns>(U+~n<81=FDAr@ zRrnul^Ar#ji6>a<>gpoMRm$WPq_)BM?S%I{6(GPamP*cIGT$GLq0C#$Z}S%O6Y2?z z+Da$E@FG>&!;~&{B`OC=vIsM9+z-|7%mImy5#&Q70zj^FrC3vX&vGe|{Yy1n66!5AomIwmx#z)+ccIQeQLhH@70?xvFJSO||rw`MSUC)MWV#n91LpIVje6 z;ek>!5zJ|8MNU+3K)S)?g6)TGT>Wv!#JWBea&>x#YC3?>m?(blStXds(=YpSjqCNsWSUB*a?oaqQsA<@h=6k`z6MC1FT%HU^!uL?6UVMZLVOU%Kn;5b@IjXtHl0O5NEEnFZyE?6{ z9M-N;HIFQ#pVy5Dc?!Vxr}^^dOkqfo`S(6NaU4(lZOzh8Vy2p?vfKhrRMO1HI3_M5%+1&JZ*N-XAQU{h&y#=c`SR?OvB&gj<}>>- zg;R)4-Zo^hp1e`T;YSn9?jZ~1?>MH`cMG3*me?jev9Ud5uPMTfnNzAtiTf zn6f4atqI4ReX3#~EIx^F$kR$3x_a*S?K_l1L;V?z2}_@pnFJxGsK`hy?!kVcFhZ31 z8^%;+9VR4LM6nxH&I_s)!56`+_a;=UW{!>@lElic0geD+({xTd3XPXxRP!XM>-Zsg z6>VgD>5VsgYYZe&%66V)X~u8lin-pg+jR|#uL7lf?rpuRS$t^`9~<>)pBAX@YQS{u z2?u(HV_b%->VCor0;HeHw$>ZHT{peg!bq<+M^Z8q0nkd zD^gP&rJtv#@C#FbuN_@Kv!eNQWhWA*$l=19wZpPOiFCtTR12kHjdTd2ssk$*a#hOt zT}ttgSEYE#ZaHvEV$#UJ9bzp*kLaPkT=S<~{mPtc@abdADasD8bm5JaA4@r|Ca-*Xh^H8W zFz3q^Wn$hXT`ESJgTZocI%BxiF;c*On2PQLAv?7rRGF$tNX_6rVFy8kRPc#_TdWzG zE+Hv++P(*@mbd(i_Q&JJ(6?DfL*=mXHBSWrFP{W2JHfZB7#yF~=HbvE?PZw3+tgo@ zC3P&C9R7#T2#=T~5uThq)M~5uQ{vOb@!1E9nBj(+k%BnOWyHv*AWq+D8S##B=x6$|*qQl!o;u2M?7hz^ZyMA;xl2(ukjHRv=NnU_G!{L9x)!< zzeoM&@GnGOwP?xW?;nQm`l$bme;oF3V~x<`ADtFbz;S$`uqz@wt|gr?IXxXvBVRUU z@s@Vt0dtNU{sRa`?tp!7$NI!&7C@)$3(Tfo4$RBM8T%M+M0Y(Bh3zS2&aQ)S6l z#glx(fq-bzPoE}P?;eq++-W+_DEpHN_0D<+aNmg|AmGI=4DmfUQ@4n)e2e7(iksXD zQGIR$W4{6$@aqJGML05q6MJFck2A`B#oi3414%RoiCxH2Q^H&(2yYl?&)pB~c; zU5lVO7*#_qM%kQ#cUb9yfEDB3Ov$t^SajlM@OiTW61n_{P_l?7b`^8Kic33RJ(|$( z%0!z*QshDEbTHJS&uO9M-B63u1zGG&BdJDQ0x&LF^=bmIEH9IXG+m}w1#gZ#5DIqW zUd;kByGOay>MD|yoog5iuN8lw`Y+&(Bix!qU4VEVvHZ~&GWY@34`er!kyxyB2f~;u^jtAgphw(^{|d>kZb@WD86rpagO0?lxNeQB4Nx0KeCBnfF1;<{V>+Q^ zS@A`8dECTwA)mQ&v+#yI^wKJH?^FbMahVX4KVgAft;yv}RvS0PO-^rBeIBcOLya3~ zxw`OHQuBOFn=mrJ8MCI}JTXY{COna<9QU-Wuc~}(d=qRrIe;AhNT>JGgwYvZkkv^mPo85+KsYX@WTveeWWkzdtk@uA%ElSfH(y1T z3sOTJDS;s6lZH5{3v#ndBuz3oh7W%uJv!-9SMnsE1&R|w@KcS!eC0WII`tuU3{F^7 zaDHS`=j}sU*(O)@2JU5HIWE%`Ekn5E^Eay7>kXv`nqLx!?+#( z6hp>q2%TnCMdTAVD~c!=PgX2=1s)aHm3S~{v&7WN$4IqEsvY^-;dKdg@+{2NFLAct z)$)&7MC#2-VJx6{c=flIJHSV0ofy_&=fO6j7yMs>E91f8Q`J z0g_eb!vDPC18H@~|Gc3MZU!a{OC*wsTy3xS>Ghj53=0&#I?pBi?n_ln@%l=RyI0Pc zrMI*cR;D17do+f7Hmedn`0;vcv=66o4aaXA|JqsjJ;pGJU;l;1uVki+n|PhCXg%V8 zg6FeD+otD=d#41!qXQqx?_zfFR{BR{f?NoA^|$Y9&czNe8i7wt1gBY~@3j<4xAJXgE!8{2#Rm)B3KH^BkKGuan#>c?AJKJFIP63yQ`I z-_}Xwa`{3-UWGZ9fx=zbVEC<><3U8MtGrl%`%qjq*(%GWrH2>km^DQ_=}%5h zxdz7*ZrvFC6Z-t%XnpR7`;fbPNd3Cnz>=arRN#S$@R%5{DImZ{|2U%Be#qC-1v8np zRNmlVXRx;K@Z5s*?qGKi;(xIikTjlRZdy#x$(#zJCC&6?mK*9Dilmg|_Q|VOf8U7< z761$AnaEXL4v)5KP|sGn!z;t58K0~fYb$G1=mV+8VsolibV9$v3zk?)UO)R zzd{X8CF{Lk@G2;`Oxz`KDg@XB7~S`WZ|hi8;1}^-{Y$4z)-GubM1QwOqqptA(X}tN z!GrV6NAMQi!KR>y5<{h*Ut9D?crR5q<~#8L?eK(-wpKU>(EtnabvXfJ z_014zxk`&TJoJCB?g{U5Xynoi^A9JR!&K}He@;L>wrqK6$~IuEeDAXeyY?XY15+XB z?fS`FLG+fO^~aTMOo=s5!Ix2?TDsBGUXROD8pNYz1rwNHn1Q<{wK0taS#?Mbdc}mY z6VaztMR~plUGP>e=*_Oh(=_kH0r;d3KTosZ-Ain4O5dvKl6hy?%Nx~DIk(bTh$vKV z^_(Q5lWLFS{(5Z8ay8b}WGeq|nDMoOS*w-u=WFj&|h z)pPq7j1i4(z@PFy%H-WUM-H3z@&v49?MoZE*hpZslqE?m97=)B7n?Gm86PtnayUmy z=x&0M=AH!?%1SSL#*kdR{t)K~c~Edyx{1cC;o}H9rz*a-NVA%o+TNerjp} zBh9rCYS&D{+$(Gw}1Py1G@DLav#_s&J|A5GS<_jWYP zK@_pc3eOW_N@xoLk#X+Td;G#_viv@*|5*8_;{#Hk z34hk5wNtMxUQq709$J3jeWI$b%5|?b6MAN9PwK+YC4!PAACm}<-ep2)l5KZ)gO=F4 zJ9TRBN8I>S43xrVJ0!nmKC$<)j7g$YCiJbo=;qE?d#cW^3Cje|{+___YVE)w6ILB3 zIUUXoPoFjB-AESPb47!7nf1+L6GhB@2TTUll2>Xvzh0JQu}(TZ!m*Ri=;k>5DHrM? za})n*k!ZjvE6-s&eKb1F$)!Qbkx!Edly* z+l1%ZyO-kIY7&e!WPH`EGo9!l^S67(B^J{|TIzr2X64mUE-?^`|eI=CA8tj)Us zgm72dWl)$;{K${6{xha`<6I`cZS1$;x|WFMVwj!gs2Km*XXeKp*F+Y2R6FKjRrsdT zCxxl1J8hiqd)VZnFxmwS_Gfa^=gvV_G0cC=yC6w_ftok_nRbVN2F7pRlmG)wN9V)j zlvZ}c4MhN)l-)Cln~(ggIR61#6xVw*O%(Wy^6Ss@CR}Q1vJsEdA4|1d-|h`tmN59{ zV>-ezMs_{cETqtZVCNiIay;cD(j}0$*Yo~1m_UGhH9Uuq7< z1nD4k?1B5HoX6mz#?^k zKH0l8NBWv=MVS7TBR}$t!Fx+)At>hF-4>aCXi(t5y~^x0T@DDE1`h;al0X)-7CUrX z8*+cbRYP_5McwL02(3}WK{if~NFB7^D=SfH@iV8p|(H1PNC+MTD z?2j@J6_n&-kU4oYke2J$E!E7XjXMi9E&RH#C3M6DJ;Pj><;?6@p5$4;Jr6s6sFxK( zly=@|YEM_eL49!QO8&$)l%;bZ4?1^tzT-M+`<{jR)m|dAy{-G={cWzI?rzk&M~`>E zYAF4S38T|GxTwsI7Ed&ZLD))$g1#e~umEtTJslJ26jN^@=Q8 z3JQdKaqjepQu{k`BUAFoq8nx?T54;Edxw zVkD*2j#ih_llUDip=#IIE6K}F#-ZeA>~Kipk0nCTV{{zXzqM#+ZfXj_&Gbqp^3ia} zItPgKDeKhdi~Uzm1&_sg$@92hD!Ev!B)b$jXJJv^Cwg`l(_;ajO{0@Lm1Nu3uZwfi zjQJcLs+BW0z{}MAF#hI)y}V{iyOd{oPKA_TtQ@@y?b9a>r@J!X7Ypg>V1D_p+faV3 z?2CouoF{}Fh$DwPd!;PLBRP)^)y;mQ#^s!EDW+N`mX-<@4ycj_DZ%;Z;BH>sZ$I*D ze}O)Yz*9aoTlC+Yh57sVJ%C>l#0(r)QP62C15#p;zJ2)-NQm3K3rqZ2{;ps>`__2# zb1xZzb8Q@&(SI>-+kJ(kIAxxUW`E#rGuZbtw$fss;!~d-Cox zqwuWtD;n(wv&N#oOOG=AqyOqgLm~A1T8;D=_jlfAvq!U5eRHV&f6EL2quUwtyN>#Y zkSR%9i+HNtpue6v#DFq0`Z+5066*u!TEZ^DJ9iN#|Dda^{X>qcVx{{8s$Tj}8WuR5 zv&t7c4X=$UVBn2ajIzdjj;5!3M@A`5h0MNq-EF1Id;1-}jM%rDO?e&gvjT9uWpdhT zA58rK;8)_lvj)9BGSS=^SkLK4(TeU+C+;lylnC7C@enGqkO+fQ8?KbKUoRuVOr1;| zuZzwMp!{ApA@4)@n&b@xaqzqiD`wR=JfYvos{)DAWpLiwIaXhmczL$$T41qhKLxh- z*+JQHNmzd__0Lp^&}T$67rU<88UP94rnq0U#ur*T_~|UQ@M~vB_KO=vcRV5AA4?_P zoCkdYuYv;U%?6Z7Z5%QjXKM|ikZ0_1p;4uM#c08Z(sa^YN4Puk6ntjO{PeC=EeMXj zlF>%E0aEii*dWYoK67DyOKtzVj)K*FjFYcpA5a8jm|HM>42=?Xmo~JeUQ2kkN)eTZ z_sr;+dqV6G`N+bCjA{t_Jh_Y_fxG&t$qTg~c`y}DudXhrnl%oGCtf6%0Rr~TRvJyw z$V8)HigD?L_nCS8CzP&bCZYbRnt&`%n=Lb7wx)KDsPqT*CA|r+wJK`;vv_A=1&9bS zxG{w6ZcFy$#^pg~C~@@&v5BIe#r>%;&7vp9?W+Fk4WPG_0dCp`d646Mj_atyyI&PG zJ@QL%drEBlbo>T{!H&5Dpgw0c?~v|T zgZl&~@qnx8^NGOUQUm;zI#Cer(q~DDP~<#L^%IdyRO)-wIFlP-Y-- z52x-@;cB6z`W@;W3UO_@y2G(43WE+qjOoZyw&{H&QCtyWZGeBr1|eKpx(`e`7Jl6KweoMns> z-l$0yJ-eLPzn7+0BIro#-;iR^dpc*m0vA72Ifu-@p+;`57>y6LQc*_XG0A1W1|?Rg z@2s{O`Q^3z&cCz%NZ7C>gZe`Jcj=8I+tr#L&-t7kdI4IA+Q{V5R0Pp$EUP}dE#RU} zZQO^GgB&S7{A-f&`g+k0#3n{D4jk_e)@z&+)KNwWV8;)~gT=*Z-(u=y9!Z`WDD_UV1i<%2|nt4i=KzrqqG|&nas&-jq$% zT|MTPOE5(^!-2dKO?{P~`|1gq>>|qkEa*@WJjA$`y_B@FT%RgD&e*#;oNeohTXJE ztgyAM9e1)Jg5fS}r`VD*&of^J_W8>t4R)PsM2x$CpN&zfuEkKIpS6FKuI= z7;74|gmZGocZ=4Q;27V_@lmGut~jBia>)m9Em*}%SW<~NyR(7@gV9lOSgZo(_hrc# zd(=hP%Jy7yi;OTdEK-az4V>7Dop(YHrb^KCgkE;R!M*#a2l+hQb6tIc)zQ;_XmNmO z>B-FN9z-+Em~cTiJBo1PDDBrlB7*tIT%FdeJAwGw%{UsdNx!?lRcq_z%8-N9$X|@` z7)ANu92F=c()(Q_wsBl7Btji@B(=L4Spf1eNo@d!b1Bs>Nik4KY|2v=m&HmGn+#%T z6EFczKQ-!9aFIpGWp&($&>OdEHMlUC=`!$%DUwC5h+>yn5oZG1sbTs>BL+%`yOy_E zKg#uNdeu4aYrS#kt4uk07V!j?!ZD(=WnRttRQMr%*RqAw87)rsnW>$VL_{IkHl>O1 zy=3ZphJpLEB6eB4ckQI&g%tw{gVCX%`mZzVN8a~YDfx;|e?bWqg!}Zi;?C*~T-wf}_QDN%DnN#d>}>d>Y8fM@UWo>V5yk(CoN60>tCOIV$I)oH31G zD5eRHaCl+( zj0NtHrS#O55HvG`{g;=cvuPQ$B`EgEO6FbDGcs1ICCq$kyDncm=~+Tvxl)ESaqNW= zj_7BnQ!he3@8Dx7xoj|l8TIx0k{ax-0XFF^6BAxTYiY4|0jhHa8k8Swg}?6=^ZTxd zyn5>E2xrV-wE`N+_Q8St5Sr!c2gUpaQWNE4<1_sz%yWja7<8!qiIfwb7Tz{Vt;}U@m;>z_h^0oYA004_WsSlcsSg?efW@NI=ju@)(MJ%l&->Bnz7?vi9bBT4?g%W@{A2tYY*I(Z}exAs?cs>KA`6DeM-%F5< ziirrzLc}6iL9wN%8gpQ_0I0$0IpZ-{!Miz!aGH5p_qPw&o-mTB^Q?9T}Jk&7jA`gO?tNkIjrBUF=($z_xU*%TNbrhcg%lGt>?p!Y?>w} z{k8q{x$36*;^+5c$#uEcXq!s=Js;C@kKn{^Sif;BBs}@)M+TsOrMw{JUZieSH$pet zOO>})OZKz!AFVqt4Go|!Xo#fyAP_y<*0it96&76hq`~HG4!X5GJ)p(`t|1 zZvQtIVwAKnweA3H`p8{zS3>Qhx{4DR9q;BHPg^Ko3ZYo;St>;}5B%pz_dg!LQTnCW>qq`) zXaSN2epHouawCO`w>7+#!0zm^(6N^8s+jI2Z(UimRUiE@@gk`SH1JpYNt+EOX{(1E z%`*}1^NS}KOlf?i+eV74k@9NwR0uX2`(;3(TH!Q?Pxnxvw>jTAOzWGepSDR@%tH&7 zj~JjPAa#@C@`j|zyV!Z7YsrIiPZ_d<4D)c@7}HNy(|^=A-8kMk50_#hh%d#3s<^&Y3zv)F3dHOg1yIbqE`Sgd*31T`Ds zGau>Z*zf@M9K@*fq?O$Wi6LJ3o|6YvLO~SR?+*X}LM_yEM2-^fpucMxxqQLywEg>n zO%)dc0KM|UQA`Js=2ITYebtOr2DD?7O&Mr~)moC)D>h7CHyo*=dcTwc!7dMuNtwFDJ=eu@ zG}oud4FL>)eOo(x?11<5kET9O*zM5DJ!Cqpa|LejmK?c^B6?+dS1_-&ll2(YVRO+x zlj-8{dCN@IXY9t==@c!U3fZppMY-PZIdLm`owsVpv(TlO)S3Rb2zL|0#b%_g1(Vlo zNCo)|#iJYEfT)LksH@HCJXzMsAU^BOfF>i9(c3FtCU+AvoP*j7`O5Q{G`NM>6ge!h z8O7}zlq$}mKlY$ZM1gH%pEu0(&il)cjl=hB-g?=tVl0{w$r^z3z4GV({<(MNs#duE zD@w%eT(>Uq@$Sb+_h}HOK3z|L!!edPJZj1B(K;iP34Sb(%F`K3PTp{fAcM*M)_QM5 zT74CUCOlSOT~GFgBYZI>IXAYm;KoDfSK46${M=(^yQn|ll_hN{6_v7twkY_Q^Pf$H6 zR%-bgbh(UdFSs$$S@#O+vva^T@qz$RsCv-nP`m=1ysa~N^brz4qm$5oIIP436$ zNS4sIJh*Z@4--Q0IaG48*3yGClp((`{f$-zlmjjyIt9wTW?=;f zeZ>DR`WgE#TFeKTdC^qUYAJU=;rUj&P|Zy|Cs)$bjH};NxP0u0a?q|7dl5I~P(^ex z{KsuMWA+f4ws~~6gXU<5zi7gHG`o47{94;>1ln;wSM)wA+ErW6jnj8aT5fQqy`BGg z)m^|ivtdPu+-c+R0Bz3b)r;6;;wH_DaBV}E=YgQQ3I>|mkDV0b{3g(mH#VZ#oIw6P z_?wnjnx4-;MY(ETj$x)I`qDCBk*%e{ACaCdzRf*cVxvKo?4 z*=6{o!E9(NtoU7l{9RM;!R)Z|hwWyO4KTH@iS~VenLTM7?rji#%O|i#E<#*=DWQ4f zvk?FcS8A;SQB=DH7HNog`%r2D#D4=s7{{t;8}D%TrmE`6&M*ArbW3K2X{EmC}OJ?tqWM?H=n&jAofIC)cP^kQmRlHTq5)oKD?^crDG zu7=NGJ~sAxcs>;CCbjg;9G)no^)&2Fx{r#m@u21m?~YWH^yALDWdi2j!m#M4=8{Qs+KZ;Zpo zc9ao`6LX!p?=Xs(V9+yeVeoQP(TUqU&$TCdb7;BV*UYry7o!r5!!i4Rkk26p1H$maMHBZC-4l82O2jq=t5?nE^j zm_Ko32$NLxGAC8y-5udp?!$upFTaaZrc{^mPcM|3rko>aEphUpx@vxY9U1rk{N$iP zL$}tSODoHZIgvk}`1XG*waeapQ%zF1?e8AMzA!Ycd!c+;8uT&d$tAZU?}5*H@N2wB zz57$Zb<#B@sI^R5ApgAbX^q0KL63C*Aw-iqk**A8UUE?&Mu}71zZt10nY}DK`#P`i zqFcqn8K3*hU#+wn&BKAWCH%(cC9^(0{AIQIUEz)(Db*hM_?^gHQ3DB{c+L_oy-*$n z3gGdw!Q}@CYvy2Dmd7wI6^`_0D%YdP z1P`QY*GA|tT2D{b45{_N0dcm7i{)+bKJ8^Nj>W#6x1>OxqWR59AJm)I8W5XqeIW=O z;QmF)-Pr8XJEx;_I=%-OKHfz<{)4{r1jLZ7_1YD3ctxum8mm8l7DVqY-(zp* zjIJ>OP`ZXK60~q11?=6Dp7|__+R)MO$&jM_BT~AFsx01CRLt+aX(sg>9-8$2*(Wv9 zx^Q=}{|gT+bN7zYepK1=8A?&^xQ<_IUXm>ie94_))_Bi6`FOaEogEWaR7zO2B|L9N z=E8#2+8Q@}AMDcxc1)r#QTZxkKE7 zgF_A)+E*|1M2zdCh9}N)Y3vj2nDK~*OfaDNHOXNcZ2?3&@cN4pHW9+PS%zJ3M{jcp zx;$m$k3D_4(5Rub2z}pg!M7@lwK2+_Kaw!GU(ag78#28e)$^`94U5R^)Tu|OEdN+? ztoJ?M@rJX?%M9%AH?oXo z4f7A?wb`#Ai;u!72-bd}x2YTF`-svd|l*kso;q4T)?ghK1pNm3Wq1 z_e{Q+e>2|G?$wO`%A9TQJ^z`H^)-y%4s)2$*PL_3zlH+Dg>xmsr}>9nWe*xA%DN3- zDX_&(g*BJMsy*6aa4d5rVkSu7o)6--^Z+j;u6-PS4|NV-_aY43cjY%<{K=)(|C3S% zq!1p3vxn&od$XY&kD0EP$K}+bz=kv_|6CU9^SjBuQ8TJZzf3`-&dwiUH}S2UR9B4a!mJu*$zQ=kswA5 zZd3#SD2S6y>_;lG^RL!|gbY*BV2Pgu@ew1R~dXTZuHispd;x9I3BGr_} z2F>h`D(rvP57HZaqV*3qar+OxveK1Zvq<>;*w^U1w%kZ&l&>4+bw!%_0wDNlklB#> z#9zz<$rIyb=8LGkp7x)%h~45`8iJltj0;32^_YEr-vgBl>{@IEat3~%e@52E-q|fJ zy%sRw3XB0gyPS;(T0A6R^qx>NTWhps>fdU7bKOKffBU~o#J)VB<}VO4oQwle9N|m) zzmCTXzDDuST|n9U#h#hQn_69`sr9~k_sECwhn_{z(N@?)77@KGn>9f$tf-p`Lnq8R z{p}kr6g_elJ-ve-%KA^*3wb}yUd{eXEfbBP$^VSV*iZatKKGZu%}pcg!QZ{B|Mecp ze{-eeSm}{+GeG)A=EEx6Nm|i8V8{5LkRh1CA-oXBEpZwV( zDYRT=f!UxZZSmAb0a5!r{67#7(6CZ7t#Q7=>F?h^{(oPH5y~ei=_K$XFmwyN`FLcc zWz?l-$(bQ9R&niKGDNkPQym9Pz$_q1-c9(jc(Q~Old>QXE@tQ}@MH;J5pm2SJ=RyD z^dGBhowS`#o`jVQ`a6{XWmX0wl z3Sm-;Vot^A|LPBV?b`<;6v1dbVf7k=1|7gG*CKK_ccY^_aD+ul?&yDY4~l^X=WDjV z7Cl2;wNmu~^T>|c;)%~hVT24!%9LA3DMGlJ71i6g{C@ zL%E0oi=LLpEn@+*ch^RIdasp7P|)Mq%qd`4Dz7v9jT6EDSlo}f== zApC0RPowH(wEAXSzHfG^stNl_Ff!Fi^EPo=$I{`g)&(>QF`_l9khdQ1W)=XPJgsxD zWR-@+hS4~tlD#FJ=FYR*T!Droy!hQ|C2Zg{sYAvoqa{}(O(2+UzdJyVJw{*TGM`X) z@Av~Jne7fzmejK{0QpmUbjRadgDI;oPT;2zpYCmgPG~zfAP%tXJ^6Piao%m^X#pn) zW=Anduc)@BXcP43iF@--hy8PE5JlfmuyES)9L0EVe*P{bszo;CI!|*n^5Znzh1vcN z1-)a3p_h~tL3#3;QT&MPO^BgE#=j)D<#sk)ta%jqBsKFY*=Gb1{NPx*Jfow40d;eu zK&ZTZbG|L6uvrf@oK6f&X2b^KDvvVo*^+F4=FN1Ve(-2x#OV2Uapf-6+7{Os;?28iGMFG=}Yt_5!TGu2$HtYH_*R@dC7d({th0rn3Yd(WsKXrgB#IJeWtbsbmM^zq`UqJi6HaTP6;4ITS(CuF33d@WWf7h)` zO?BohcC@xyAcc>_S8nRFc7uevTfRp;K3HOxNjBG+_D zlEbk~ZAkHc!t`g{7!uAxLu}WPH9tg~(?V0jP3-538|bPB5#4({MdteP&PR3Dz zhBAZI`nn%B#rNIbu;A-1jX2Z#yn#Fh3|+4~K~pl#WC$Ht&zig^)LyHPGFm6W9(g5E zz=ZihqX@z_S3bW$>=1`Uc|TG5gcpiun^=TOEgG5%Qxs12G_MT=?P+T;oNp?2;}h^} zPZhT#*6VSOK%Voq}#f=XA+_OW^a$UlPTX84WqxEwtG~`a^rD=cYG=fF3s)LQK z{0%0z_5Nwht}eL!BDK)E-Cg%B4yE%=c=u9w{}PU-bTV}TVmDm=0Lo)OJqVvUBucg?x5dH@n|o+H=iK438;iXKamuSyFTYE~2Z^oVPzy8yFE! zeMw#dibIKicpIBgddxp~P+jM9_S{5CRhJ#L`JZ#a2n)0twD@uSu8++Ze@~(S*^JHg zW;28#k{tE*?ApI{0R)lV0KT9}XeC)X08+#!pacWiUFK_=r|F)c@DS*;qUOd?Y39k&I^d z5|;d@gH`%UaDB)=znkhbS)(@Q4`I!E8@&i<#GISmUJT5#8TRzU;#TaAi+7W;?NB52 z>Y)#S`e%8&xr68#(n-fc7kC$7$~9(`MRAnuN<}5R3M_$9?h{e{$h+p>!jLy9H??N?K+{b;`x)ZrfFpXK7wfLnGOptMHx5A{@N zk-k=$);71`5&^tEp|c}PJsS{Ey!2w@C@L7Ct})`=cq2`ENg^Yl+x`t>impzJYSG)< zf~rX)J*p)T?t<;wF3iH+IfuBsRFc4%T$&=wgcL1gr zub&`XxWCO=_$5uJ+_e!k!S(Q*vw%eeKk!hUh{{Ly8<*yW6`K;Cn@l7v$t`Jv?thO4 z<+!_WN)8gPn}}LuuLSv>3Yb0st(`H*ED#ln4%a94cIv$>g%qkWiebk;7%KJT#?TJ> z0UIXt{{U+-ijhdHSxx(xN8!MdY~rC* zJJuPiK=O%AaT1AVXD;*FCH|R`USdw0>`6aN0Q4j}883F}zHT;r@F4DwM`8Xm5dMU# z-;?lDw6aHzMxs})wA67)cE19c2`W_rb5;H9Li48-i;GtS*qhi?eD1VT!I3>$?ouyD7H;xv* z@LF>#`Q*d>Ae*~j%(H||sWP_RkJ)?!M-}j|L=br*^rHGzE{!)Xg8kyO_aiRzu)m&I zBL=C<7pOM`#hv{hX1_@V-WxGkO=p`U3O}5jO^sAnR8!)PIj6>;*pETVwCF3}O6zMV zC!h4mOHnXOqQX=+%`a&u|1eG5Y9UGJDBESbaw&Dn zz{d~d60FZ}vSXDxzUvVAplbwIB2EO{X`yC7;UQM6vkMnL?@`x&!=lZ`n-q;7G|pce z-ygN|MvZw4!)}5fZ4I^3y1s7A@tn~FUg>`B zDtx8zpFNW*oeXo~kaY5mGbrd2HM`QA8!tU#T5*Q+B3?S8yf;XLMo zZXWX&veDS!+#}Z)Y z$TIj+`M3l{J4MO(y_A*aL*M(j+|YdT8_}!Ir!RJMJan1<>S2cXfv;qhi3(l1QD&bz zMS-x+a+x7sCYdf}S@`L>1Dw&yyu<Y31-Nt-yzMLI6K}> zSe8p8`#-Bpqfm*m2#Gs66*~{s44!ivW^-ld!c;2<@q(Bbj)`GtzmGKh|;QYJIcB~%5@{`kz-Zq#EP8dOi)G|Ld<6-evW=b9*qn1Bd9U(BR zydyqJKvE*2!&RBmX?jSFWc3`?f;aCnN{ZvVgPY_%EmSOW^l^p+Y!zgVy)l@^+V5Oy zVw@j7<{MfVUOR$kGxqs^Hq?i8{+-3q(ga~Zy4QXnV!y&-30x@YXz(rh@yBncC6WU@#rxNQHU4xvoUvWh^+Y1@xC(WiX0Obg4CrPEU`Gh97pw^8!Z ztehkts>Ypb)?R_HPEy?=(cEgrf|@ksUPD^4OY}C5Gfc9=!IDkA1I@nzWyHY3s4$00 zImybFvN$zmn*HIee`%{oCi7VPM~8D%^hQ~io#Bh>GtO=b%6-NT&|{NTT1tw_ah{st zvr&c#<4X8-yzEIm(c;c#{gb*RuqzswsQ+Z-R&;2Yn{8EuGD}#F2k~v&ReKsc*rx)0 zZ*utPF>sn)>D9ziZ-Vy-)ez~1xb}UwFI7P6t|L-6mdLSG^wj!ifbH=3a57s2gncK2 za5pphg>`3Ihz$TjNOXfp@PPOhJ`W@pJEbJ1@_ABdGJ2Y0j7Y((5V8uP10uSdkvTMU zwncz{3um{)I{UL-;jHTle|E~x-a)dxqn2PP_;uMiAOH#1LPRN_IDlxegikv9Ea#|f zN~+2AaJK%kus@Hy)s(pFlO==c^Vk1q*4*(|+r`RK!@3f1)Z$JhBR>(_^wZsR4$URZ0h1FJ2R<9wC3=V z60tM71Kq@GleRBBD9_s@iP>vD_dATqaao@{eP8MdQxunqMb6!St=h6&bOeXK%Oeyd zHm~qL!;`b3_qh|X&3jxvpj?)1cCj?AUrcqKzdQ(g{}I}KPyh^EpvjYi`GldQd(sTa zyV_S_AB)49Pog^;lk^+iz#D)Hny>PXF>l;h0Q#k4tn%REKvP#Zbbr3<{nn345--E> zaAFuW7G1t;aWlEW)~y_u-^8|>SJXV1GOYVu*TJ7*l%7wnb}`S?J)f`AUq zwNYa!KL`iK#o~Vy7rr8Ykw-j zK1(-HswK^ksBH!02_AKoJC|XDBco`gn=N8l-BZsKyE&hCEe`H;+v}j=sNk)IkSo=Z zCM!*fJ5tcV0;uG+kqfh^P!MugPkX~HTz29^8o#U!z3eN$oLQZ*cVG8W^%OlY5|Ehh zb8LGf?iHUXr`>YGooE{E6XkLM-w7}*Y(A=qcPo*$E%NUWld0Ao4U6Mz5n&6n8Er&b zS^;w6<9R3Q(n9J>qq^|g*|WZCuSk_20rX#Z>OfR;ZHSeB6i6U-tLk0j&(7n&?}&Z+ z5e8K4ZVP^qE%)QBHncG**^86ne%yJg>}$GNNN%VPagm(jHp_i;w-;+v1uthtwneEB zSZ<9k4$#WIHIbtmLo=w++?uEF>Zld^g z7sZd+Q!HAJ+cE2+8r^M&#Y4gmjCr%KW!uz{P!?e|_Z+hk7KTzgI}9~e-H+&u*dD~F zA?r&P8S%nRtmo;mrt{<m|1#Zr?zOUO3lodJJp6_6W!W%UwNP@<4NCc`GI}=pS9U_LzQti;pRJ-T=n46sMXyCRwkdY!$n8wcvP~>C3A?kb0YrT=2L6Ikx3Ue4Jk3t ze%GDiySEh~eSXUClkZsgQAqH1S6cSZk=Rooj$)Y;fJyC$d)az zp+lCa!m6uygi#HtZ2*p|C9*cg6k1Y0q^6oD`amSdFu4k1%J*2qFNfy24c`2nEWqP3 zA*MutHz*a5U#~SBEbcu(RY9byrVf~cEhz74l)8q-4)G>Mcxtqa5!sP3ACLzBfteIt zJC?0Lkt0isH$$lIH7T@8C@6N3(iaoe)cW82Ju6OxmE&F_b!lBa@xhhE_Y4EP(Qger z^;hVEYbIX8n%Fd_RL|LLsWEx~=t6LEQ9IGEZbH__U6JVaBSXkG{3uHjf-g#>+yI`=)M^Lj99`h6f~zDKu7&^`)MXhZXM7TVCU zYUdUT@ZYZSPhr5d5Eyuc|o-e=z9((JDbZ9)4)Yi9@5%2D=L2A7Q;4t7x&La zGB!!=*7o;a8m!x|s$^j@SJZz;P=H?xOYs9iQih?<^`_DTOZ2W4!`}})9R`idmps+q zUr0#d+i9h~p5>_XW9Rz=ODt2W%4y;MTt0JL0_(gB`qBoMaxA53l@ZS~C$9l#Q_mT= zlC1zKWjkL*mUDP8iRB2oRUChUzmD3_U4KRmcX5QIATWQE!BGuEXUWt#T?{rI zbSJLnk&Q|t8Gh;gMs)WBcQs^D#~tiapz|&4vXfcRvU4T0(poipU~f|~$I!K7)XG9Q zm#0(e1UCU&pHd?t89)A+e-p4YXy_e)+tFk^Z(KRF`M~kU*CCAqrL{S8jjM=_V>%L< zX-}Rexg}>W;{v&M0^%cF4|F~K>nOf{lR8YH-p(wU8rygpHdNcvR+`cnQ=IP4duiG4 z)0kjcXRO@VP18hR){6Qn1aDzLBn@XXye)C{48-&Tt3UH#jkZj;Tr=!}{IOBCGhEjU9pp@hU4l8=U`2&Y*QSr) zLPGUJjrY)>>iOa8x{!H9aMLLAZ-{tSKG}J|VKg76dTZ?8eY!LGG99C9DA#8{An4zm zly`@sPYg{*p)O6LAk_^oi$k_imEVz2&vJ&{IT*Kyd@*M(y;5>i)aL_kfnov;vh*+3 zGTbn~)~hNasWb89m@#92L1j4=1kQbJY5x>BXMG1gnQ>i={cFvYPYkB*<|8Ps1l=+? zRTKmr{~zy`j9=;=!=prJ#x+OzW+SEGL}F78BSe0{Wi6%Py?WO0_3#-GFR33KG#y1I ziJu0haE8J;?MW`SVtx7*$Z~)EqEU4{YJdRMm`+e+9;1>w*fSdUIoO)oWYd$csrs%U z@b}eX!0cC$Z#(q*KZ93|x}cc2Z$n$rlx&-e$@C|ub-}lL&vfON2{mKe6I$fKL#jQf zUJ8hWR}B6;k=My zK$NdY*?mv1^R~-uY#Dv{#kl6)(;nr;y>w*5#6aCSn$*=u)OVgnJx2inaAdbro(=c4Jwupj;R zVV4XZmElzZLYCh8uU;2C&f(q%kFlj!*M{?UG6JSxh#dUWzf%y^lw(C~T$t}}RD8LUNTJvwb z7>XG4F_%Vpb;27#!i&t$^Qq`}ai{}8j<_tz`geLZ?x(a<`)8xVh5UW(gD&QC)H}WE zbCeAsA|LOjklyP>FGh_prKPuOCe~7rDKHd>#o5R-UCcDVIx%)lhvya_^?2&Wix?~U z-o8~+-VC)&{i*8$;AT$D%*CUobN2hcG_*pK`U9HGs61>+iSE$7cXnprt%=5oaLeqPvI-^lX2wXxM4GfLDZY#28hiCt=U6yW*h+C4 z*k$tSUXq%1cG7uhUempphi8R(q=a?{x5Q1K{TjzSJbe_j{Er^9jCjG2s`J&;Q89RH z-EBSfOU4to^UaIT?Z)dS1AU=Y2@h^&BpzDrel31d{GI2n^OG0D&O3wKke83}z@V;; zbuBjik|!N}m;=(rv}*sUlfpY6FgCA07=Y#rX-1=l8Igw@eYiE6!qJ04I15$p2WC&lXQNf7YmUX;ft6I zYH@Njv4Qh!Aa5?bi~Z0YRjB>jENcj(qf)P_Z} z-W%~4bbQfv#2uhuM$?TyI`@#IEgL)O2$&c$r-S zzWU83_vGSqO&V>U)e=IjN4AXWzV_V4zEurVr71{^^D~o_i+f8Fe!RtXgfB;_JYt4> zm6@E{`Mp1#cdmQJt=fq*$)06ijh|*h%n3MXA$IEeJQvcNECy^{7oU(J2A{|>X)v!86280bvJ&BJi3vrf{#+1CHht2E>V@%95l7#MF8YQkrqAf zo;cf#JAp(`5XjpAA>kQ|GujFCqi5sNPK6it4u_9tJu&-L-b;%EBQQxGq_==eE!R3W$R zn-KyTXPcVsn^?yV5!DDaX*WxBfckQwNBLiTukf-%-ltroa}dJ=FXv} zA{M+{a$}CCvSvf3STD`_+#XgJCn?{lTi)Yk~Zf&pcLHJ!+t)CipK0 zXN>cFScf(26=2xuu2xkZS@vF4Ug#-4HJP~-7#l7p{BGe&fv2(nTjQ21-fRW#HO&S< z=<)5Q;frhbMyx$j*XZXg*Bd(;G>5N=-8KJ(abaJ_)1f77iy(pS%Q~96!ew~(J8-CI z64V$8V*1oDHKLcfe8O`1XtJg4$#rJNzRNkVyE;n>HX3@YBwTo;H5EuMk!gc2#HG(1 z9SGUI*2wq?0Nr*dyC&C!E4tYGEGDa%yM`(1LL`+)8{b6UGBC7q6Sq!Z(3! zMe=%g_BuQpvK#2)0`?Z=nO8QQg4PZgc0?>ylET>8l ze-9U>CD|jw+)HL2A6ChmPUq#*milkJe1d?p4`owXR!MfkBpn~F z7!RZ53rwjt75z4lQDDLd($CAV8Eqdqlu2)n#5%Cx{WZRTYU?Fd>tg&x_gJtZGQM$s z^s1$n-$cIRMVXP@WF>@;q@P@d-*Mj09P`7415-WUPApr`wmt`*JNg^rAK80mhjL`K z>>U8j+t0c{?ETF-ipf8i?4S-I``|bzbg(O(kgmK?IRl~bV z_D@<0ucikRN(7Dt$j*V^q0P}iJax}QI()Z{e>$>q7v57;IWmgybcVALLDo9>#Gu{| zxJ)>XQ&-D*zbdpY6HN8LHxPnD&#{yJIiIg|jJ=h9*5b3>dGhowo2x0|u>h`tNl;Y0 zVIC&3W$F%9>4i>%RplqAttjpvIe&_MqbC9bqk|zH+X}2Mvl&CFnLWi)YCQEeN!z42 zLxWmqOuM=g&R0Pi04$OIMO#!q4ACj>SD?L&AVA3~l#UkYbN1O|1DnOJAN|!SYiXh6 zsXlGEC`#G@N=wOm`fnlOa^QtCPySN1qNl!y!Tfhvw*PE9FDY|!b!Dg)s@>i?{^3}= zVsZ<}z)KCdry&NXJ^^Q||JCrWe`$07zoI4s z0)CQQ{sD`{0@E?>f8O#<>Iq9UyVFc5CY$r%YYTm+YUuM4r-J3Exron@F4!X3TT|Dy zl))acfBrJxbrl5jg4-{C6n0Hak!{ePb<&gKE`2`#06IQdkY1-%ZTxW34w+y?riRS5 z0Jn+_gu%txt%L;X|AU-Qk`r!PTjQNInjrO7nhjjGc*Z+zB>orv9 zA*S#j@x0d-28bZ^Ct60LWFXm8>zKtACfDti;BMTjb|>$uTgQhlC+q@W1bi-a1mK@) zr(OU8aFdn*eC*YrD&mHqTJALbrI=eEw>q3d`ck*o7>}K1!1A~jQ7-K_r0K!jKYwmV zFZJA2&kG@A+FekKJ0uR03r3z_D@f)Fb43&7RKXv@_g>>U!HHc7yY@T}1H~mexWUiT zTv{hA@Bf^bf~|&xPa58n9FxxGF0?(*egl`64505V@>mVtLlvsJ>!Vv2S=sZ_whmyc zQks+)3;L_hJ!dt)Z8S=oT%BY?d)7ji{|xB8URsbGMy&&Hf?WZ_PUek8r3I(w4Al8S zf%>PW^=uW-*h7r~`#ta%@f`D%Nvshv{|e^swv%U*DU04%%Y+|0L%fY3o5-$*k>5xQ z%6Az8DW^6jJ%XKvPU@RJ&v(SS+tyY^#yeA!ap8*8n@vZJj>?{m&C6l&|10~t-Yt#!oxZZ4_h;uV>HWn5ZM(q&*dwB#2BVzsvS zv!J1($mU{hM<4w1S1jOtXqYVn)CmySgEbC7CLc9d6Ruo*gOq-hNccarlKh`by4jAQ z$WdPjd15o*GjtC5_Xk1t@jDEY8bYx@Ue7D1{tA~HFYXt#!qC5JPSCx=-NrADlS?}taqo*w_3Bd zQ|w!gi$-dKN!t<^q`2pQA|JgAH^oQhRKdj%2#Lm#W54{l z8mr~$evT=NnYut#_GqI?h-c&saHWOK)ik_O9b^pDQMcE~GrkZ`YuUgro)3py?o~Dk z!Q6>lz#?$X9Tut`<|TxxgEN5Pyj+n;ozLaDiGg8_yJPHhuack>3JjNN9V3anQYgwC z0URUmB)u!nTWBQ}F-c#GA#kk;R<`*J1mf2@9f&c< zp!IeleVt~{ta}Gw_(W$wtOCsNw-b9NipnDZu8#P0J{6?&FlW%~qyZzg{O|?gT3R}! z$+qWhvO8k!Vx^!<5mh8k1C2&lgG(X-xKL6<)1_R_mis`{e0Jh~ zIrw7O8JZ5L;C!lt{C|(xt3$862AmPgJLJuuaxW;xs1Ipi8GxTdK!myeJ*)H4MqqD4)FlMF`~c+a8#*6i>;g^GmgQM9<*da%u5% z{FC29Q~TL#Hp5rlT){1yd`ZPM{d!WfL1o?4S9OycucXCvEqp7_Tr1gt__6JgKz*{6>ql*H<3J(BI0k5^$d$h`s5E9l*NLKN!LmugJHX zKYHCI*6mjoz!)29`ugJezrH7QzdHb2pG+mg*u8HrN_FfJbK`bGuI|w9l77bg1N0O8 zx)Y{87M&L(W%+!i`vu0y_LT>9;0Dm2zTWj<;kxnJLax`U;N+dqf5Zo5?0j~c-=faTzUdkS66f*=_K#pv?K3s!oY<1E-n2XByjExk9#jn!h{WoSJ zdH=!`0_f)>N;M0?Ad2sDKY=uwf_OtKPQZ^8yH<<<6FE;21;6|d2 zoqho%4sS=y@Sdp6cHEA2F;hNI)F;%k znGrApsXOVxj}9Mx(tG*#k|f9ez>f`R@(24Bv#%utO}AJc#P|qTtbgoS@UEbD8K<(V zw7x#AYLB&2k1x$E$j6$2-QPLf#6NI4l7&-kaDZ+*HaM4R#x#xVYRm1KL|bu@}C@^QTILWysiKuELZ`#}SljmWpTjf1Mqr5waHzwz|y5(*ZW{~>I;pUDsv z{kOmX=N86%oNaag+gg(_8Vli7r*RFvxTZH+HTlbYN-$b~iYy9{xD=iCy;EZ$o zUgD1a{ngiQYk>U=R{vsGozb!(BF0vXS}$0-T-ch>x#h_8`YZ);rh$LJT$(nCZY72i zHpG|ByVOXto*C1Vyr=3T89jiH*pS99GJFxxTYv@PXLBKx*|w@0YPBajqb8z-c;^;> z6I>{kZZ3C4FvCh&6{?asa{UQ%)mM{eTR)7rgFeP{#iJ*f`0g`MwS@@e@NPm~jr*$b ziK!UyN+Cu)UKCdGVrJ4}I>XlzUC$t*Zdf+>rJGSF3;rg9%~5IOBsq=Ucb(NA3-rZ6 zb4L|65Y2_+iNdLxtpNNpHE;O-sAUzK)7fC>!bOgTeJ!&Q6)@w+dHQ8+%0hqY_{1E# zm}Pql3Ei0uo*p)_WKcC1zl(NnA*1A>+jh|%w|kx^d^6|YrC(JE0+YhDuYXqEE0k3z|Z!>Nav`cv5l7+GsDy)eWKmSV6ypOkTduitEahg=9Kb^aF0lj*n$; z`fDDh>P~+4DR_Q$ypKoU+*j2khN&!V`E|`9ze8snzVB)ZP3bkPn}i2Ik67V&reVE_ z*=o=e{bkw$ ze%|I_-6-RVBaQG`f| zIpM5ZmCbvuxMsqKRFn}ye4OT%_bmU{lxfT&UTrDLs~dT$m@XGwm6uXH{eLtpi?ccz zk2^7~wXuE7x4x98=)+e3TAZhPJgsKuDEy}IUm`)bY!cfk?{6;E`OX;B<5*}1$4BNy z1J5H&SoBR>TseY|H>{8~yeY<2R@UK;ISTKl-_E=aI(F&V8v zgGNfWEZV`Wh(XM9946rh5so*4Q;3V4WX$Veix$rLEK6za8w?eg-lI-Xa3J#FY~8u8 z1t9gnBKhWNK}HNVhXgdx$dv%h|G8*%&OJkS3?NpW{^Ad`Yp=NE+#7h~A}ssL&|%lV z@!OTT48l~adX66iRW$9ZnT0EKfAwvJ;!qV{fHFPZr?H{SGTx=mNO=Or6&5QcFOdPO zraP5{=|9-nba_}H5Uj0w9=?z$UGq83Rnst^5n5^o)VPa||;bn1KD-Dc}$g=B@aM`h7 z#!245iSp6n{G`xXSTPJFZ0HweJb(dFGlu_VZdh5l4OqgwtZ=N&RsjCc`~WQQC25;) zg>@Ty#6W=($so!yEL9Zg_`iE#==(NCKM{U%geV5aPmqm>sk? zv1bj!E)BZC+dg({AI-;+?$pG;Gy0j}sqeXTB>}^YP8Q)-^vU)Iygs)?Y`(472Z3x| zMV#{lb1I@9?8fcgx46!&Ew9{_o@;^k>R8v$b5o?TZ}0B+yCuj#$N;geSAh)sD00QF zzm`A1H>$}3^B4Xz0q)N#F-{uCgk0eYG|s|EWkO2; zZi`L*p`@VC^8YykuppE?wSiov%fBwRFV2EdVN-3Ayz%%}?$qScbSYL?DG5(IcuUlH zWi)qzb=4VX8~D^lguqj!vbRy9#=FIXtfQ8*QAk}``zU3n={Vne;9XUaMb>=V4P~}z zebyc!?2514p_FUB+axsFdElE}_@&YaOF+IQx9rXRPi zkbht3$iH~mzajs2=*hot{}uVysmewNi5T3Gs!FS$IyD|Cx}FjqS`tj)O(yZtpd(Ex z%c5upUHJ7?=Bcnkv+_DW&)Tj3n$=cA{Sa`=_u-%vG%vV<#I^FjPHA;ZBm^hFG>V|j zz6B0rZ;&=X)vjf*0W(`2ht`1NKj71%D}(@lE0A}t3iUmDu(0@rS=x%!SoX?LWRDPC zaOWhJN+ZkrW8>6Z7~#Sr+kD8g3IAgxOS^)I?FqXVZum2EXkaO~n^Ctdchzs9W$yqs z+p|>NjsJGf^fxjy^Z!xrqZgs-;~0DFD$LcQMDa>yUC~cE*_G z+-OzGZ&Q*FDt}ZsQWgbAX2k7}2;XV{_)*@^>Ml^L(rgbUMgi^VT8uOxq%-Mrxq7RO zB=PK@MGc@)dBI~FW2+HCaGT*S7twoVPLsiT%U(an&nxF5U0f?)$!_daWA14Wz$$X$ zN9aOYy&YhR_2HqxI|zSSd?)`4?fR-Jx~scR)8MKL#22x?z#HSYJ;r}OV0G@3`Su7&8VLJxW1c&9NQvf96I#26*AqWLI8q#Ek>pIe?1D z$ZRgplb1Gl0*B4to$)tN!1QSsI!gf5A?dv>z<|@6;cO#)HoOHISqRhQDK5tqu7k+y zx=z!yySY_)|G$*7{)qy|O3UMwfJejG@lTPhn(dmMK5|2M`|EQaB>X`GK4$0Q0|<+|F79x8XXh_kQ95Ot~(VgNl%2O6N)2ZMJZVL?AJP7ma5AO77boKeO z1OiAJO8h3RTG1=Da%KaPRt0@Q6^(i;qX?E^AC`=vnGD}9d(5T+&dPX$dUrh+xGe&G zaR2B}%n(`a8_zJ%FwkLftS}@@`eBVc$!)$r)Pq_oizUlHGzUV6e{CzsiU2O|v$ zNGT98e&VLc5=P>I|3LLNKo|C|at11gO>|{ROu6OQ;(`L721;*gAvw@}ifP3qS+nen z%xV>t&&}Ag0>l_mt%bs0>Rp^)@t&AY0x!qQoVJL=#UVBjKvRZ!plS+eq)9{66y_M! z##7wRC4!A81xWzHlluF$i?18Ad4=I!ZFN!Q5kEN}Oy3Vp9_b81jPlAj=zALH#Yr@? zj>E}EPo;udyktK8J~O_}QZzb0m^bB9up+z#P4TUhBz(v%&fdPY+Qs%N%4Ij|W%S6> zQ6)9DlKwzm!j&Hx*?agQ+c$N(SdsRn`Y&4H<3aZ{lMy|6ZsX_hcuH$o`s zP=rDvhdoifq4wsmjspI0^zSF!!F042*)8rCNbRW^)Mu}4f!U8NRia=Ne%GFB1(RT& zn^6rh$wO8(krOuhWRSBQHG3M2eJ~CZ^@uPx6z^^QH4P52OB(=|R^R$KK{?od=CkKms2R73nYAqaRLql{~Zvg+>_ z<-*s6+`xk|X2!ARsPD+L0bsThTmbjEVOBKOVGm|$eWt`eb6e@w9`GLEHtXUmDCF%b zP;oTdZzZ(6fxxpY$}OJyw|?7D&slSkeF=n_uo7gacJ+fvZ}W8~MXuMcoGP(D7?|2$ z%Uf*Z)W@WgFdQ~7Tp6`FtSv_c8T)m>uQ*TN5tZ$p{yE*XBlfq!rym+D8p&(81eW%u z7(D3K8vR{JUXcmEYAzmqR-{V9tN*01;I54EFgS%jH~UZoO!NM+B|{9-#M4zSA{0av z=4@6V(dA`o86o3zn;3E^8~_!Ssee2B(O?QeX|@ z-R7?*B)StZI2QzrOg|Dj<$XHVy`cP@ux9b+y}I8-e0iR8qiHbaw&Q3r1(lj>JEaYj z2QU720wq4*#Jmk%6!B8nbSC9{Ao!xRt%D19fsJcCxo_#jR4O_Beoo2P8O#-Z1ss`Q zu5aY0f3{emucp9>Q&-P(+7kbZ0g&xd;{tqpL<{_2av&Typ3|tsx87R=g&XHJg^Ltf z!*}%+xmMmB*6x@B+qD|$Y_b7JKb*-+y#wSVouPSNq!k&68E(>aln>+VjH2{BWdDx^2dnJLyo>z^Ju%2dwhw9B zRTOp}7?~!?+{e7(Z8K9+qs>4QhOme0g*mVO{v>!&7sfui@Snn%?0+YWWpTC#HY68~ ziL$AOwAKVRm6a%3aUdxj1}ABH)qbjA_X!iP0#O>AqYG6A7AarY(j|B?+32-azA$(> z6aF9ag^^x5nKhUi0z_SQoK1YuQmRrvjniPZPYHHpAinws^eQQ+A@fdPtD~mqt1c!Hk2z98JAC;YH>LZ}sW~iYHJf=obp*yMgj$_MSu(gi-f< zi;eBox!0-X=&2u1vo-CDOnm|f821iqoAXGzz2GB(W*6L zaun8{lS%{}L@;PCIr^u{L3=TtP=rRHH9%N+r-a>Nvz(JCE)qwn-P_9+yY>Ai@Gg?d zz-*hrP2$$^8E`0bVR?Ybm%y+Am=nNKkSL;(4w{)Y?Zru#N`^{cKsyY_5W_>UfEmO<*x|NS@MRsxTvKgNRtCK;haN5(^ueW#C^gR4c`7$S3QZbVgcIv) z?MF7paMaj6BL--bLlge{lTN*iJ*3%S4@>W6`~Y)DTOz9y2|MYz?QOdGzFv`0!I=FI zH8ql;ZOkHW0BM(D9=GxiBMVC_rc2ug`~ve6w#)p?ZDzbW2`$G3MwE5dvpFLB0@sWT z|LE40LsDlPo*%P&R2MZ);i)JAnaie#Kw`pgnZOh?Mf#79=K@Ul8g42jNeY;*?geB3 z5>=x_*j^*0>5M$NIK|n2oUyo~q?z7uo;E7J$%>jRGZMjVpS!o^m+#1x%}i9ZW^7{S zHTr3KS|Xk4Nl1GitVE!WV5V^)-Uoxx6fM=)fBCSIpLEF&@F_3lEvW?T!$)rl*1+aU z!ZF4sgbrmX1)1m`dPxg0=8n&hBrI5wKCr@`v@GZtM|D%cbFfWOnS3ynS|V|+;3@4T zE_IybA2h`q2&~N{*D#1QB+NOYivz*BRxyj^GgH_M7=eX73Ff*`G-_Q%aM2gc7ja*k z_x*6D(YS@A-DxWM35yCW09c156M%9XOx!=}+bbKts&XzFYo}TQ46yO1&SbacqT?1>r%KL-q=nFLOt2z!EQ<4);M%arP44?GWWb{|d^EgtEgW$_Ad zz9zD}cB9Usyf(Ir8FpTlmd5DKnS)6J^C&jQ5&NUrQO+eYtZ3bsJBMr=o&_9{Si8xN zA-Tw^2t+5$l&T@Gd@A9TGdD^#E9?YD+rVJQpLllvE8g3GSY-bH)RJ?U(JS^C z*RAOT!2^W~YlcwVZ5$0{V^GFt_S) zSCTZe!IdgwW3_-7m?y35?`RG_EwK--Oju~_*76B6n1a_}!kJfAr@HxtMy{>jc0M4@omE3_NEm?*x2kr_%S2oj6L{#MN$ZcnF z*5fDF0-oJj{%`(ap3_4G(E5-Yn|-xNmM<2m>PfAUV=-1#Zrj_5v)59P(t9$bH9Tz+ zF!9)wjbNm+dn99jOPs4&$$1=+XN(9-Z<8Uw$75GfRokf6mwSM9N}D$$FaNF|$}2zO zYg2H27iXRXuP`ldLdVmi&Ia`flMwQGB{?PnxqAhBn98Sh$7lC$;#TdNj6%&$j&-xG zZ@I?PmU1`_wY>2D*z8%epuP^3g>cY_hHlKiu{F5_Hna|N9K#pNw9UMW&?bYkzRvcvzQ5`zEs8 zPCWbuy7eP-AQ&`HaTA9OaUAAT$xd_|;JonoXq8vuvUdyY=x4KF{E60I(G^KUTebM1 zZ_0L2sc$a#E@`a~ZBJ&qZrY6f#YudWZcbYavKfUH_o(Rg%_+VkHs)jG%HMM>Xsd{K z@)Su8ZnZ*Ge{W4)@u_>IU?!KPm|#KWD$+o2VFzO3V}PN++lzWg>$K-A1x!^EnE1MB zS;4;Qre*vv3-&y;)3IoJ%sl|RN&fqv?>d3l?{ja=wX%2CCC(Z-_O z|H9RrncdNT%}q?Mb-)D*77*pk#4|yWtKBI(z?m6Hv{UAz&rbMvc5UZX_Ab$rq9-cj zi@cCz7~%H;D|O`vVkB%e+2Ttvo>SN^RWQLjpt|qZa$s_B+@_ryNyl=KQbXC#Fs%O` zK0F9%5mKIR={FGoFwm!Je)bJnm3ojDipI-fSygm|4gaZvUjR=r?N##qwKoQnq^IjO zA_`77#2t*PWv%<(gi5-1LIePr{~LWdH}*0JXkT6Gn?jlVD&eOv&~Wp0xaxtS-kTvh zaUYx+22H%Xy~&<(Pg!tH+(;53FMvwz9&P$6ZKUb$g5cI2N4#e{X(S^Y81!mj9!UR2 zZtryhbA!N4>rY{m$Hd+HF+zO3m*D9(sWHsrkNS!e6)o(lo$7{hKQT9xupDQC;099_ z{!CIfgKe8+m5+DjWrpSQmsK7_>NraKG_--FquU!5Rz_P#-JN=(%Q3&~%Mb(6c#C*nppd06X@-> zHEUaVgKr`hVsq!a*HW_VNz46rBb7PZ}+nMIG+@A(tC=l0XchG4Y91~-i zWr)MzH5?nJZov{uH}7)K+JPX6e^B4v>E4UL!c^CTNBMUw9ph^i)9kD))Q;G|nB7p% z4wDHnmHAdWg0h(5(0Z+|qejFNBV=mM`~t$krn{1Vfl_s*{eBw>b25nFGe>tK`Nfj; zg>?YWIe(cjDM5|M7u%r`C|&Ac@Vq(mZ);z@pB!s~yLY)%@kVe&OaEiNr~gf#ZOIhv zl`;OH|4|m*Q^OvlVgUWm<`4QG@JTo4x_+S7AsM_2X5wJ>W|K)JaUtqoSB4Hes*LL$ za3V9W)JsqQ6jyI#0;_tK8%9(7KIBg{QX3xz@% zC4@5VV$JCXpZN_Tk~dPNiop1YSrc+n@gJ6+8B>>s=RdQi1FZkZ<{HBgWGfezIM1TH zNVBPkZrEIA-W~6}rs<)4fA99(6#ds^=LhurB_lQDXa+Fw+{RA2r=qipU2g{O=s}-|#Lme^mqhgPu66MwiEBra$M13WSzc z`rp06%G<%H<5TCPul8PdP5d~(G`8D#r=VJ7Se&}aq+hn6uiFhS+TglO5jg~ri+nf! z&Fuu^Z{5Pu5t03)-gOyo{D}^tm7BU0oWEQf8+Ty9aeow*+$Qc=MXa&+2~7DR2?dS$ z!_o5sBhEuUS9TGys)2Nc4&CqYKt2B6(Gz;JTh-Fil8U=-Gx}Wp_2}!1iy!{M{!39Q zAQzYt;p5*v;IRB~mQL>V8H`-rrM$!3!~DY&J^qoP>F@XAl?znm5thc$$*Oy9+g&~Gjs`Rfn6^dbRx(eYMMP# zl|x3a^oOcZDI_7`Ywpc&`Th%dT`obwB6=0WOc*ezZGr2x(A$H}M^21Y#a0H-7Ujnh z2J=g-Vd~Cda_SiZI~YtnP+-W}b|i`W-Qj@2gl#moFo9Sakif0E?MkI8`cpcVyhW)e z+&4~~Ef4ebV%&#XxU|wHZ)T??QT3-r*fOKWrKG4eUnoWR;V%M1$__QaWZ1Fd`%^z@ z)=Qgxf^dpJekVax-#bN9q{{8pfw(H_Y_{7Bm^cF`PaK*72P<$zz{!!V*M>=$r1ll^ zA4|$LYGB|rSLSCZ#-Mtw9gwim)8U2LicTz*vx#gR zz_#s+C@uCT(Q+Jc8%NAGOD#khZAUw3UicS?qQRZ+$m#5)s&VLDYd2ZMn1|ySC&~Vn z1N4g!KGbc+(34l@OB2^(!IH9RMeZEXt*0u-7h*)z}G7!Id#~Qf5pw>`d@u~tDn(4xC*sDw+S3YZC zc|_R?*PAr6fq)(1z};JibUk*3I*Ave0I5#*(vwj^cRo7+7Hyhe0O=8@nqb~z*@gyGuy1P5z~KlPc( z)@kECmE+Lxq2uHAZ%!0L-(8m$QXTn4@h*`mx0*zW{mGKYlTqDY_=jW$!%;RYk6CYF zu0CqK5**&~!5H_MfoUk%>!t7QJbm{tGXM5&|9d-6!W%SteAf8ZxXTez$Y8J$zK>Lv zTlWRNdLNf_lAa2gBS~3pJIK6n!H`kebQ27Bek%^WCZV6G z=b>Q;uRLr&AFSiR^11XRKceAXha}XCqw117jdZ(kilq@asEWFN#ZD|BRXsSME=sH^ zqeccUS^y)&yNh1@Z`zq`7^(egY!`a~G!@ZS=i9pm26u*+rcgCL@)D=Ad3V3D+u5)Z zm4&@WJT}YqVZQ4W-nuWRi*2{w49^uA{ZIDZJ*??7-TP%;XSLHcQ#(^@Dktzc7R z5CKCttS%Mmi435L1V~yDA_<2|gh(L7nRaSb4wa*vk{J*=gd~L!FhCO5SU`>$4oT#Y z#0nvjKqABta^4S#?X0!-de^nq`|fvNdtcY^Pb(M6@A;jc=YGET=lvg zJs!nR?H=e=R~5oZ$cH&#KJzVR;2wdGUVVP4E#kW2}Kg7blFM?DCf&K7fi1Z;-xG%yD%{OPadeSkJ6q>HhflI3=;Nl>vsQu9q`H2GiY=fep+HuXsMRZg3X(i3l>({k=1;Z=!^GSUj#J1UOleC246 z)c`y8^`jZDvC^XrrVn^$mtNjLZk*bs`Mmv^s|I!gOom|$d zVY|z#;d}|*$CZQS&5{!Js)GdaLU(3Tk^of(+EhA4NMQ-Uu8bLr)cO6karbfFm>C|m zXLsMlJ&?rF-8gXE+2(;N=p{&dY>4tDw5KBmU!kjg?2E@1o@%hMm`!;gf+$ZcGlV5j zB@pGbJHCrrPKuBh_gG;ePDEqrUfuWhm3IvR^oW}A#;P}!RfTI+Bt$@WLny;cH;!yp zT|wx&3&7L*t0CW$5Y2IGV-Uv2-rTi#)!Mr@G`gE)jNqaW>az&bbh|?71&16+DMWT_ z2f8no_K*W9hj+-MCEwy2?PpSbk~w0?T9iC$T;zK?OD-a<3;k4^K^cc}tP{>ch!>o2^}Sl{Np}@p=bec5FD}sohCKL2wV=59AWv|kcO+89zFn1go%4*^^j003427c=% zv(1+G7thdF7f@;oPw&j(_qOmM#g&0mYDg7>v$K+Le0UA>8J4e5?k1q{t0m9#N6r-W zsxVo~yiyUEwhtz%^d1bN25eSa{dzF&{k$IP9f)z{Zj&YSc(x#no-EO&=sU}N;S|2( z4O=nlm7fk?Oa9_$Q*$CVpaE%K+`K&c*ef5qozC&>)mJ8)iY}@)s%F{KSOD|+B2)(l zWem!tM(QQbeW~#Pog7&hHFycE@Nb9RN*nuLV=680iBx2a`PVQ!2lbidVAhGzd6%!z zjYL(-P4TnoJS@&}s&^dKcIaTw| zit?Fj`AqT0e|aNmTul4}r5A72B0{Iux%toHpYBx2tJVz%ZrjquYp)J-VJ(6?RLjw< zu{XC{enIuK#DsnhFx%+meH-_w*_K zO;5zTJ353zsFEFePtZa+j*bDw%|(UJN}{|Q5rqojNgvE4&XGQPialu_a0Uf7(!Rid zkVpA8&tKLS|!eV2uG{)Ety#(>a@ea1)yEQ12Kf-=6$=s3e2R~EpO?UuD;DX zd+vWfx=iJ9$w!hQm?Pm3Nx9|Zk%8y7)c6$aJjy2`T6y!?h3Y6x z{+2gqmS_f>z-Jv|_E|~qaRRE{jWR3JuZZ??Kr*ijm*={RR& zX`)Ad8`FY~7=N!2Gn^$xB5ck&vwaln)G((hJwTGB5Gn?&!}oK?4w$hp^7UhKPYb_{ zvX5y=yY@$>+k9Uk-lvkJe0n+%3NU_5nJJ-TdN#2+A0c zub#6m+ir5D0RG0-4c1u&{+@i8<3?M8K~%f)rKCpaSF`jgs!jV!^52VU-C`LZaC>c~ z#)xq8$Oa;zA)kZDd#6T34qqF(Tr28fBd7QFNBB!3$HDYFG+K*QIvGhJm?8v@4dfre z8;aLKXTOonG^2-Tqg{26uk^PB)1K~BL-E8um^yFL^zt}oKEX~Gd+ue9EuFcd-?_{Y zA#`nvhZ^&Zw^lkC8#5jhaip#MN=&Mc@C>tj&2fT%s>rSyWO@7~ues`rdC?=Z#=Ve{$_0Wf?gfcHJ}f@5AhC<x5VCx|&OZL=fY`t+vllZ=*WWb%S8M}<8{ z;kV{3K@CF|`3aP#V6T1A{OFB*!Q)}Uz6p8hb8V!D7UoEXq#A_FqKYjSU%lyJg0cQEz-(vbOYUpOJ5KyzDM|b!4MNZX$N4N|##y=I z;Tn-~UzDb8rT6VPoW3`D>XY%h_0EBt>#S*7*}~|BA%WiwkqNmvEq`0|AMJwiN%Hb1 z(R6wGSrCz4XbFj1WwS$D7$TMg%%rHm3Tiv!ph6!?C;1AAM52YaZ=Lmh z?7<$|bQ+}H4@HhFiW<}|hQxLIx zZ98RMCgk`~mWLuGZlp3Y(tV)jiFTZ)|O{Z5jtI~=Lm7uoO|!d-FlJm>30h!MlgfnB>jH6F+6$w zgf9aH_SCYxk}Av48Cn(T6k`^pvcz7cT$*OJg}M11oD26qK+j61>k9_j@ZJk}o^9w% z2>4S(2yZPe%`baBBC#toVTg7-u|OjnD9;}7aMjnig3s00^5TiEW2}JI_VI2v+DlXI zW7=^8e&Sk^U}6_%;;zfXEIZ4-N-@*y2D?pQ*XzK4En#-0T}QF(rC7oJe;C%t8(j^| zES25Io7X0Zp4dx@?)o4kIY;Q_*&s<~I>L5^JKQAsQ1)u$TrVXM5*-mOc#C=5ZW z;u)S*V|6RyFuW&dEYg#f#GHww-J_12A#<9oxU=+yB*q4sCJkaePVAb_0^dKw4M&*T z!17)cr4*Dv;tF4P*|5m-_dd1RZ7jQ*W#8IBr=Q*!eB{lk%P}u^)->kC1YlzE$GXqM)iQb?VTE{Y))Y48*#>7( zd-1$nvMkDe@`u@7RDO)z^HmkUi6j0~mbUjoUEDh~4edfxubA{QVR%7&h35>e^XfZ) zZYuT|&zxe?KSAMG ztcvIPllYqUQu8>8`uwC$>Y*JEqIHJuV~{jVjE&!`!x~*u1F*N~tWQ|0t;oU}<+UK} zejJ!u{045-Ss)AdpP;EdX=S<2Nb<$;6fD8wHuCefJqKJqmyXKO6sLvh(^?=p{*M>d zR}}blrAd#K4Y8g)q1=CZ#e;&@ALYLlR-<)dK@VM*=M`Y5JMsJ9$mOr5c`^jxiGo0( z6Hi1di(e)ukdp#dXifRydL?}rOC``o?Fp8$ZQkQo$FdTrxJ1yvbOQPH#4!X=HK$_WJb}Q1){R*rAgBU z$KmzvqN9mT)QaW`m@*E?F@}bq4zGyQ9&r#e^ScU^H5-q51t)60*=TjH%0SjF40xRD zuFRS{wNikfl_pNF!MJcS0q`9oxkiEqGDwP$`-C;oKp!PBZ?f6iDZ57J)Haio$df{b zP{E^!shhkF}IHNwC@TkIPB*sFL~Y4=8UJ`u2pmBWGQSm!>n4NAIQH&fIuq zU%KNSZ^bchzIN?j&znou|H8bP!Z_Q5(+4Sqp7^0;)jE4jjft{;9XI4AnX|XN2 zO|i#?b8<&S;j($gp0lreensoCdGCkmNT7DXHQ7Mmc!jq9*VZiSRd@mo;cX<{KzJBU zMbwvujq{V1bw_C70^jHcuU~N6*8yBiyD=fXvvPs6JqD%k)bNI3gZVd_81|_PG=3AK zU#dTDoU+CwR#H5%+yAtshH8)Yr87QOJ98om)6%X};fFfo3){??ideoI2}0 zag+x=!4!9>E`>0rOeWj{Qf*44uKk7nmJ zX(R~<7&y~tjQ51~o+KdA(@>`mo+w@F-O@<&Z|Gw=hsR6Bp4?t4XfR3qdZq-d`IGow z)%k@bs0`|SnUDTv^^yVe1?i6H(d#a@l%TDlF<1647l%Xz^c z#LTkLq*C2$*P;j$utB!GlId&`E%MfZa>quvXVR{XJ}IH*e=CU-|%d(L=KT0=lJwX3?(3&6_;_K{4>8*`dVy5 zZMwZD?SOWN>SXf3N@02DY-uy~ae7`yOyUexbcI)~>O!ZUeg`8y-?h2~N0Cvh4eh0( zwTMK|hFZUcVjy~mHc>Ow@+(}P#$6#TgsZ^S*`wHdPnru2j_*#R_(nO7($pzcB z)fW88$XC5ch^Nex-Il=2hO?R&1ItZ8MunX8m{RLHx7}#|icWa!+W@WLMjqwehpA(_ z>zFD1Dg$`9=!Q~=U|Z7yQ6-oYVY53nni#?~V>4EFs-5Z!Y?7&`WVer;HO2bX zJmsA=%P#Op;egD{%_>7=Zbg*O@P3?1Zupx10ex-g%-NHwxPfp`v!a#W4mFGpR4g2z zuiZHepJ}3wFr%nFA-8^IY8v<79gkXa=tco~_PEQLs2mRprJ8Zn+_s zOH$>t{q^_w4Nt0qh)d^+dMBMKEb|ld)Yd&YjST!34DX6f8mNl6@tY>zdX;eZJ@?^OO6K`N2u3;ksz2rM z@UJ-C8lkvmbUL_|ff%e@D7+WSTSIYJ1I5!uk`X&5K3ZY|9s+vk9lU2m+6NIuXPE`g z#vHK8P<Yeb1X-I!a-Im_HKPZtkN|z0ev#JTf6CC% z<#}7|XWg9;YlY&a^pGrGy}nt|b$NS(QPEY!AvMkzu~B&@AP}2$u(okSS+GG|UQW~5 z15J^Q=BT-yS`=+Xy5QU=-)j6~zV7Uc=f8bgbnFk8KG1^WU{zaLfcmbgD;k9O^Q@2v ztL{S9{7pTSQ_-uADyGy^YxjvJdP>AcC!YBEm;2@vP(_;w;K4~=z?`?I=q)JSm|@+} z$S;`)+6pg2LLDOzjLxl_Pf3MsxgnW>2A}B_92*RNEO=PThc?7&7bn) zmR40K502KOkV`df-)Wbqb#rHIsoC4X(Kv+{f$t)rS;qm^mFHFc-5?&oGKW&Fe#X)s zZ8HYnh8k~2AwhNfo#U$v3q7kWdA%~zl4{#uz0Wa-+L8@Mh8egYxTSq9=X}O5G3>0_ z;Q7{fiLFr#*4>fELvGPbFAP2H$VM}-^X=T|BN~_r+D@fs32;=RNZ)FL-&FDNduUzG zlX?-Ef+X9{f8h9X7niP(XNB>v{$Knf(s*sxk4WQNe?uBS`w?jj{#%#v8&`htBYg4O zACbmAOA?xW-K?Z+>eUi0&BoYadT;I7>1X|w-`)1P`5xwNAO3!H-bo8;D-wR;ItgqB z9ot@C5Ry6v6MV)*``lp1%3h6a_xC>x^ZHwV>wEs+ACbW59MPelg}oaF8LlZ@SK5&3 z$4v1yxX6@FvxKsiC@9O0#cCQ_>1p~-`v{(G(0!<*m<*pL9n$xhJT~(f^72uK3GD;S zEX`;#nXCsl(&Ud<(|*T$G^H}WlOk=C=Drl$z9Ynr**mYvwByRj5wh|@2(j4A%&Ge; z-CC;5sw@XigK0Di&rP)I=(7+!NCA?s-Nf&EKMS<$^GZk733l(B{rW>KP1ZKs@;bH6 zP#5}{zkTYNQI@wibVMptU*!`o7%8{Q+KG&VteqiKrWq53y><&a<2`h~(2GUU+*R^?4OZymgI*>uL6sq~DIl~izEv5T!gz_`+|iB3IS8ioUyb*^2Mt!_5!*9*kI zZqeXQkpzM(#31EWSW$X7L)e{R!Kh^35%$SZK|Dr2d_9~sP~2v9ap{;0wtUsrH?9!v z7&D$rfFg4~Xz1A**|oaju*Yd>|J+E&ChbT&kGDjHXxFEEsLkC7p7wVdKvl>%8tzxJ z^CO02JaZx3>bQ6aAIu(IimF;UQYEK*@aG^2rDp{-+bDp}_Ti(+yjpHyY^g!SNz zGP)oR#uQ&*oly6D*t)huY?umOHh+VUU3T0~GJh2$jLU0c+3smHw882IbwXM?iUEjTFM$bT4o}3BhDHfXb0^X6Q$N4g+|(V_`*9(;RqgDNIoCk_ zK~|f;9AOjlXl?P`6U5~6onk%v^yHHU2!xV8#2tB%+4nrZtJGR+rx^?dHtzWD&m03!IApXX4aQgP?K9Vsmjcw=< zZT3o`*=nN%>D{WV!*40K55ue`zbEY}X{P-XuL)Z=W1-qqYE&Mb*A^nrke((P8$#)% z#LlvXuH*V{Q{j>*+7QbKy9oehFLPUgh#e%E9i7khWpvT~3k%jga|#XvosfzBfU@4X zxwBy&H2Tx8O!H%6q75~L^b`8d^%H3myQ0oQ!u6iL3vJA^0Wf*hY$-&|?FjAFCA3Ei znWgF&!_XQp-c#K2u40df7T-Q52w>X-Ig2s?) zCqidSQ55yvJfEJ-(G>RK{n`RG%?v)O-h7gk)*nfY*R{BnpqUd#iD{3~Eh*u{zf#NXqo+`3VtEktG;zYaRHL_v&$|SPUAq`rMdv z{`(=_dPlyiO}_i;wVc9jpE`f}sU%GHSTB6|YR&FL>S&1Z8(f)}6e;-8m=IETBmj=r z{U)8f%hf{@exm}irnt+Em?mKOK?YX2M^zy#8l}={{-XN0QKX5dzIV(M1HSGwrN9ytG0!{(yL>)%Y=Z9t*) z-P5ZLo9A1`O|J&RuUraa?Dp8cvHi`sH2PZa`p3(!=%%@t+F&o|KFLMqQx~0YIrwz+ zV~y%F?T*6jsbM*<4)kKjJwL&ZoM+e&@#vpI{^gZ*yG!0)f$bM)T_0)7myj*O{9O1e z&4Sh$99niS$3F$4-@h0SZA+1cl2`L5+4k+i+k`ylg}mOhss42!?;jB8s%?eJ9`(bP z(HT?Ziwq(o%z2^rQ#!XV@1FnOnOt*m(eAKK4a>gE3lJ)KZDFhuxozXMqmDndeDo^g zocHxF|DVb@i>3ONMR*z`KZ|ylKi#uebms&VrFs%Q?W3By1#f3SFD22?-j2gR#Qunx z{V!#dp;2aVuz!_MmifXRU;LC{)rV`eH2a_P%#a&}vLhp_NwYn0I^#WB=fKt+*FMx@ z85(^;yz7c>w5_8V{^5{_cY$wNRZG)!E2D9ocES)5ZXGr?_?C90olERMVFQLI+;SVK z5M$}(f(h%)gURs+9CXpW@g4n@hSG@#&ht^8R&I;QSiJwm7p7s=v9COm_-$FNvH=FG zl)1E5WWPG$cTlSoGC*#M+$|indL6=t%w6T3KGL+4zP1l3X#!cE3XNeF$J?YwDidOb zq!rk!*5P?w0x;Fh#=P||>c+26=6qg4k!^Jv7m8v3l(@2kZ&zq7<#Ijpg~5@Vb9qpo z^Nl%j`Nh7T$jgec_h|IsX?%hu4xhHJ_uyuU~|`CqcxGu}gZ(ObX|$u?d|VdbsKDd;P{; z=;MSRIy7D@9|8NJ;KFSv=fl*rIp@xW-Pq5CPpXhzlJJF5a83592=&yq0?gRlZI;wO zGK0^>_#D6&wohhoG?SNW4+~RQa3K)?OAVnjXRLH1@)>c7j13u*uElC3x6%}&h=tQ! zEzXwOB_A^7ZfSQ>v>p1&Oj^@-o-IOLUJF1P9oo^;nMt%3%mxtmkr`mUw=qMie;~FZ zr>8O-Gg3G<(WXaK5wakp}56Ya55YN%md5EQ!HZz!0} zWxlMtVyH!^wf(H=AU7h1slA*O;yBD^p1_v6;v(#mPR$-YWG-I?Fsa!qBjrE@Ul0dB ztg2bOJHwC4yL9fDl<$W5aIU0zz-#c7<{lDrWaF{wXk$5P*v1Ac#mt$6sIw>OX^m8` z0JVO(zk7fO3$5bP%F&9t{_O|F& z7lq`K4$M`@Tz6f0Dz~>A^#4T$6g6y=x{qfu(HaqnnO>rOxg5)&=xs$olA(DRI_F#8 zQc4y%Stay^a65p`-et1kLWqNvKrPsfoUekpDvD>ZY7~QVfM2w%zd4Igo5m4h2gZ9{ zxDhe?({V|``k(GeupeL#8s?Vg*rkMQ=00wQ`kNGSq?PFA(RM<=WR4Qh5ww{E{R&ff zQwvHvyW)gzFi0d#k# z)7|ZaSp`pC_vGbtsv_&n5E3+;6QSSV%aKJ1FOQ~jY*o1m zCBpKF#_w$fhM~NaSE1#UUGZk*#rl9v%uHc1E|pU}@HmWIi3?oht9;6%;m0mH*C_42%X^>Auf8*lT9WeR4H5- zUx6#?pxB@(3U`jO!3;wqRUgHEI(MQ@|>;rguc7rVsviKgkfC!&%gz< z?azj~3k;=Z(@Qh1@9{Gf$#g+~4wT2JX$xBF$W$H5d0L^5UVfZD>s7>Tv(yI6(>j-J z^aS`g}*s(BJceAao8lg_@#k#9> z_2(DK(M4z*BF-m2+~<&+UkZo!J|8=s-yf5yoxaj4^n!!Q&A!~`l$`gaD2W=;KF624 zxE#v)&i#jS<2LiYy3H;oJyP*~$guVg%1xt68H>)_Bh=`V#leG}ha8`|u#UVHad6Y^|pRQh2oBiHf~e_PlW%3mmt3*fJC#3#Q30bk0( z%#x0f6ROqMiNl1C=Kdf*mVbL%*LTQH#aI&zA34VOWKAukRL$HQ2Tr%CQgr@!SY>z) zF3W-onE_Jht+UCx15t&&!|fz45jRXu#up7-*8BYDDc|r+4bY|XiB_0#izYm09wR~@VKLqi#` z-F1*zAeu}6M8lC?0y$cO&tOwPJ$wiM9oujrfO8WB_q6^c+L zqEJ}ke)fWPiPG4y{Z*+@n+a6L$iwW%xNEhK>c^h<@Vb95#i{!}8EbKd5_D?jhm^y9 z8y?96u`Pl=Bz~*J??jp(SZ_d*72l%6PFU|m2|8?-K`Pf>bhk}hH72f^19;8)iNwx- zgV-?inftS-Ui>~3|}Z$6W*u1Ev2>363;oGw=m@FF$ZP%TL}`8eq8&Z zE(w5?N7Bi4K$B^!J84D7G2Wwy zmis^preZRQ3gKLWkn2&oy32r|VNL5kOnUQGy~l6YC1H&CT-5*}0cnd*uU68COP@Zn zvO~UiQFr`FqV~=LyiD8EYdH=K;iL{y6jvApOlTetRIrVI#rJ)urj=j>E?JAH$!cg z(>4s-T@VX#VDeoYTi+5r(*DF+YGQGy;!OdSAKHM@F#U%CXyVpu$^9+iLB${wfAq?4 zyMvm5&;hQcG|ac#lL3z%xv6#530O>Q_6~GLxG=R^8478iX@++~(f?MMpd;2XEtLDR z=8Bc$n%yvS&i>YxcSR504r@Kw+E@u`#b4r7ENV>fB~Yv6Jr|c%XcD2;qEZnC*M852 zD+u*CI*RhnUQs*@x}|gahF<|`73WnUH{`;^rIyrlg#woRb=iF<&_%H>TYdin` z^|$;8-}I86I0M>m)$3rEqW#cZ{6))O9L>eC|F}o8raWJ~V16-!1{Q^~@tskjRE*Wl54jcab9;_6by?g66UH3Ha<26QO zstW(AY@tP2jjiid%6U&67Qy zsdbhuNKg~=KOs}F{ijxE0IjS)33j&tRSF8Ybvm3=hVoy!n+f8XGRG}=S~n^CS1jRI zm;c{n3E5e{jw@0=e0S@jZbpJSqnRsdJW|9lrlsoDmpP4>$A-;D0;Fpipn!gauv;T2JdH`bxzu^lpO0;# zR_V_`hl7neFCy4g!>2Ru+aSy(?N}gAJ=UEi025$B4)!=9VQt(*_NI z#jF=^_FCkXJM^284#_A?N|8PG4m_3XK6LO<56;h*BYx8BKDR}ws!Dw{G3lG#hc-IJ zhcUE2ohS0Qw&fDy%XwCD$VBm0hZ5!%LFAIK!#-JB9v5C3HU7T-_SC7e=)sOaeKwR5~YWp_KpH>fEOn0%`RL7g}JgTpNLUkhPKj&tuq4m69> z=-kq}P2Eyn}aM(u`R>?%=V9q0`B;CC!@iTlFcr!sBafLNN43o$-JlhdJ(i zhj#w>4heu{c*32^EBtFu+6P?~vugSWJ+zmz$t#O|Hr10fnMWM#WsiF@grCrX${B+?=0ejJfp5{*LJV9nt$cqW5=1@Bav*Hw!KE8ibhj zs^%>t!JGooX2p!LYrsu^QU$8~XH2D++t5~?g}%n=q0lqV5tc7mIcUu#e~J&k!lV^b zl4M!(!}(pd@>yVbLd~GVJ$mEd6=v4-FHb^2xoi@3B3R`+vN=P_1Vy;rrXpv>*7ed! zv>s@Oe(npP6q)SLKN15^YZAtciud#vn&i9y>r9Rn_9ultyU^*T(~vol7DDi zOK*X9V!e5$nH+vZFk`}+D$}C!gkH!=cd*TI6-|xQi4tqa<b*Yvw{3Hhek`KYO3V4`8D=EEq{d!z!hIosdfVq6LeHx85HvX@?@LxfK?+DAn_ zMesal0>|J;{N-1*=f>#jC#}kRwTAC32g3}`HVN;w9SQRL~%IW+Jlku(ar7QH#zM&ih4vxIH zvxd0?@D*J3Mq7b5%N42_cGKQ<&B)$PyO$TLup~>u3|v#6N*hfU4d-U1@=>TO%dO=G z)swus$q{LsWH&Ku6@Cj>-O^rbSaG|QB^Qe(Z=FV_y{gUJJYKmybEI&+?$PbKP|gl$ zX#ew1FY2E@TYlYRc_tjW5wjgH^A%>+!5`#qCn~j!2vFiyEj?&I1T-u3RL5#7T}Wqg z`#O3BP8)^Kn^wP=&-|iq{%A%^;0(cX^Xx`h1IVcpyt@@7l&VL!Go}B&x;1kT&%!V= z2e5u>-642eix?%a5IQw2Jbs6aeM)l;o#kyD9;UH_x(Zs9f4y}U3HQnG4EL+IL}_5+ zkQ9Z7D7q&aIqj)vW3}088{_rmqBX{otBhF(A>iTyXJ>sAm(JIw-&N)_3Mm&SNVFbd zj`2DKL#J-Ekq8gW<_)HnFpd$1Q1}Fkg*PPe%#r9E!QXZ5r$&$w{p5MtfSmmNn*pHU z+2V&eCsxCx5J{82SY_}u6q?$W;_m49y56geUzPI}ZhQhC*|}7sDJR5T$?`ymDPk|B zDldlmd{`wU&bEZz1Rrn+jn|PEfmxpjMx~=_2Ie zI0;OZaWGN08yCfoAv~z2yc1XxR!yl`z%JmD?Bep{WMsjBKy}lo?uv05gKSanyH_r1 zce}N{9NO9%d&o-&$J-k=E@krpF2o!qCKo`q@)bDxm{1hKaZWn@70eXRN9*ZaYJD{YRVEsFS(WY zGM}14SlSVdsE2wtOhw>0b~`Q)j?MC@xjUV^ewXW~_pF6GWjGfX^?#k88~FIuhaNsU z`h(BlzlQR3KrS;{bzv4D*BRh;@f+6L*VaDx_lRA-_ZBX_`HN*c&F;vj-wkxq{Vpzh z4p`w2%yz#F$2D+qDSGk4FdyE?{Evvf|Kf<`&Jj`G`*QDX+D^q-xRGF|XI(<7f8T@y zyP|yB7FT9_BXbPS((NEWGkovaYtAV*hFNpJJzPmjux`%_lP~vf!4)swn9Lt_7Q$B10e}3b^wSlecPy1d%6A&{I zfmhaF`zzff3eTzEFxk@QQ>m%bp$(&VD2F(i-OozEK7S-!*Q&==wFr>#bEgp-9{tP< zRru)f?jt?&!)^`YTR?@(6o9S+px(JF#wgz@*k@pI)(Zz(fnHSc?-kVsx7qY^~ zOV50hwocxq$Wc`DFY-BHrPIw`$s9*YnpeWudy?`@+^huA$OJB~Fl^aFH&)*T@h>OK z_2#XiJnSo`?CWmw4-d&dC-gdGnvW@NZ{3~PCA;UJ{*L@MsIQCIl2f&U*>sOA0h&7D z22|2ZA4uAIC=kp$rT236%1NB9sh@>fh21JvomKtcU504CQzo;4 z)h1QZXaTX~t0?9?weuoE<*ulnpm!rj9*amNRn??5MpqAoA=;y_a)r5hsuiDr(#qb2 zaFUg^v=tqEiUyajJ!A0z+x?tTIiFowT62*B`ac{AuZ|-#o{RQ~CU@vv^|^nb>mCfBoWoF?J+k?NteW;*h;)fEiuy1}^l z#eCnN&tpOq_eINvt>VoFl1$N(6%v)fAj$tc&$2Licq!pc9suRW#PNfLCdL+9+lJ-` zFHKGRD}_lsq*(pZt@s`)0_iP>CE$H9^dgU@_1bU!`i!P`h$0kgaOldqHUVF7mG_9QdH~TDk@yPzDaM+vTttJi z;teKJqj=K@RzYyOE`7pcD0q0E9D1t`W#~AJgwM!^b^i!kxF4!0=Pb<)%X~;_ zc-t*;Pk#1Ew_K1Y6naC6uE?VIq{1zZ&~_e$m-I-cZezyEm9#Ci!9RA4(sWMw9K;K8 z$xF5!om6cL79CpY_=Qa0r?J>7)xS(Yp3u{(kvqBde( z>DVkLr;2O1h)P4^-CPy$^<7D+=Mocyr)-OWzzpZcub*ec6G;+>d>j__!_=@uLuekm$11);sAZ3P1HL0I6wRufA`4<=amb(6 z`kQ5iTOk1$n1XV?d%L5k0I+*c53k>SlD-NCOCskccCAcLsMvt`dsQ*-eUMltkOVYH zh~13NxVcjTudXaXC9zwK8lIvrPakEI7I-}s9u01+@z1izk^P4CHWbMHI`E}SDTZcy zwM*C^x__%l{JW*!)*JA5OTWKc`u*L~@9&m=|Npo2^NSJg&~=+?n?I--lGA%T4;xB> zw}K7}&2LLz#JWz>~dDuoP`5d=>}RIN^6JF*%8PQX_af&P^XTh6(cje(iD?vguE zz|GB1AM8t+#wPc<5|zSa-Kv<4(w?!1e3AI-Un$~U@qvRYyZo*|^uVSfc}%>!pEDZ{ zWes4mg5<3bT^%Fj7T)P|6_*xpD6UYuEOH#hWs9HNMZ0#pIW+^U))6^u&n22Gp$wAJ zzaL`M@w|}2W?5<@bu!gm$#daWJJ zpzekcP`aMeWfeZ7>NTfLP>Sh*>&azZqj7&RebV?LqRoS@i>iK&p(ZVH}Jrr1|<`w$>(> z{QF^(_pk7iN7F}HiytZS8~8-!-j=t17XJFrk%N6O%3*VAX&ni%j)e-n@(r zx`qx>^f4c2jf+VaLmD_ReOn~stgyv5a?F?x6rO2nV#9;0lx!OvPt%QWY`J29pX&(# zqGP6x7SHqE$oHpcpFSTO$%p^rz~nL-VA?fP7x~~9i_>%%ntWOius2%JCT`6 zH>{X>P7b$XGpBtOo7}YI(aUZ0$z2oYKU6cy+ZlIzaT!CLzRb~RXg>4L=n<4uc3b}H z$x&8^0^Q{{GH@tHZW=}qIP-Oat5^+eT3y0I<*j+52O#;hCb6wf zJyUZmT`eMVHX!P~TtY~U2Gqiej~q0QsuXB{T^=p@h`m(pkdYo@PxZ>|Gv1oCuUM%c z3RCY3Q~QM99gkG{D1l2&i@$2BM^H@(3{BCu%xTBv9YM)0nz*9CXhX|jh7`l#yoV9H zDct+x$7rKVyIjXUYZ~a`jqX&e79!pIfk$E6bkvgjNo%-%^||6BHEe>9qPXtW*WDc2 zD#YHen!0@!mDo9pTz8D+MQTch!J&;j0mMSnbj?&#-6&@1K_WX?;lm={S|Z|PL}l@! z#Zzn$3Gtl)NpHf`*9^0?cSLSdA)b&_)PMy(hX?t6p<}~&NSdTIexxPOvrO0(Pp_!c z$G*CO*qYGCXWd68Kvk<&b}3(UAR8JEm7t*73c6laM-fe_Vm*9BdqIJ0&It|CU@C)V z<3oPKI#O2e3Yk#~vDz=szlOaZS4`V0HEzD3=ShKSqB!HRs zM8qZ78c5ZLBI(h(ePrbw+F^mhI1ZrZROjll|?FaWr6gI%O=S z>$?|&8S_#0W*%~?d=~qRJ)PlC2~bH?F(c6WCsDawK{x84-KI`e^-x`-tpQpzdz$g2 z+%_}1JCk4aB()Kqkipuro{by9X}tJ+8gM#OVP0KuLL*t)Z4b<|Noc?1zAL#@0_>1%_e+w*Oh7 z?|gkxy|GTPagPkg&=-*Ep=6zBRO;cHz?-=F^F^W&UQCR}FOF~|oKC6g6|q)IXGb2) zBYmB`VQ|GgoRQ&eX z8RaGKp_`^swDfNlStrlsGTK<;5!zUhbLucuZj}F@Wbp)#Mt`$P$2-LIr@9}iH|A@{ zKb!a}ONzeFFn7+9)=uIrV&1*?YHEjRqXpy}z=KrfqZNT^CG%3$+<)eQ#nvxvOx$JU zP3&UC1O5tBt(w_a8tbm$dAm>6dEWBT0+MSVI}6*S5~3CiPQNQ`?em(ImyWgPX)drn z+$!uit1t}@k0}%WJB1xh2?;{9_1{}g!-ah*wS!)NRPP~&DfN%ldj(_e+;G@+JW zWvYj1BZX#*ZhUuY7p2Q{&(l0C?S(noR`_7O`}>{fSY$?dBNqiB$p}h-kWhhu;gT@6q6A1r;7jC^M2#UO zfkX%&xssfnL~Bpitkcu^@B9yZ7xsSl{@(pOzXwBh4D7EGNri=VsxQmxC%&6c^Yq;X zpWl1}a2|45t&|u}tCx#Mdj=F?LBfLRT~HPI-oF%=bO@^ec<*1EL-;uH3{qM7xcO=( zLh(j9+k0fMZ#~(8YLQ}Rqb+u`_;%0}W^7WVZ!J#CFZLvP&lUdWt}|_w@CCX<(IH+@ zcWA>^Q(FPSaHA7LB@Fxi*fN6bn(CcR!<%CR45*8{cFH;VXYJ3&q4jhhE-ioc;gJc~ zCrtNshkFfIQhhcFM&^0=2&4`uaV+$}H{K{9<1p%=Y7-Dq(_^jLBdHgtQ8 z+%hlAc6-qPNpe1p8pYGCR#S*q=^A4!Z~$v|+^E$Y*;nZ4DEl@g9@(bEoBWXyZ}XN} z0_osCG&^Dq_~bR+b!V(&uSUIY2xU%05?;A=TldO?+SgaYNMWw)_6aVH2lV=vZ+c7rw?=+sQ_3Q*q%ctv80-kJ_1t6Te7LutNan7#TMx&PY}okU_@w> zsKQ-2tjp1?up*2Otwd2@z@-2UM3robF=ty^vsf+8_=SokCTfhXlC}|90{)w$OZou= zUf#%fd8YoztiuB8bZZXyp#~b{3+X$BvmY}2VpRfU|e7AdG|#FI0~MzB<5FMB^ag35B4^hYJBF-L=}um z1yCHYLNAs}aR6Et?9yGUim>c)N&1ZB%j`LzzSk-p2fw#nz9jD-OD|KF#Vy+B$kRwtk8e8OFL11M$d%?-tobx- zV?f1gMClWV2&#q18L*&EQ{$41V*lJTBaIRl(iN*IugP5+ZkvV=X(j<+H-={9c=+E5 z0o&^qp-Txq$z&T@#ML`Q-X^Q?4n>GrP;Ko|@*T}+8<)yp<5Cq&^6@RtOCfFiNx#fs zpW282AqB3xyl+07-A25Vnjxu~KnrL8nFUSt>)zG4n%pS87L@ii)f8Q!#sDe{ewuWm z2569d3Jv%I`9C|De`wKUFnrR*ruSnM+wag!2;m}=QmZWpt z^K0+fzn}#D*cn6OR)++iF$$~1FxCr49((~ZWCXb8tzPsVdD?JX^=Kqx@t|N2s&BVz!7N>EzI&Ri|H)vk(gBUCkTZ2G8+tYDve_uYs_B++!0Rj zD?Rp?^c2J%j0YH;cbNp+4l`u}y8B(-qcp7@8v(+^Jjera0LgpkgC{1C;$f3659Oo~ zI~2MF2ZL}}Wxgcopm&acwV|CBv|0$K4CDFgY6G{7n)i3PY528Zxz4eHi^PFon7{v0 z`ceeP@m25C=?s>QkH#C?KG1}7_ZgPY|?Gr`LL9>ObjErYTgP7bj^*yz*XRx`{ez}9oA}ZNUvzm3oyF*ua z5|sDKHPChej1ikj-=G4BPf9Yt^&RKzZ8?=$)G2I00Zc~y;(=&X+bQfZa&Va%gih4L zVM%YN%(adrv-q*_19=@QVbgtAT(duGboA#1c(;$9%Yof7EGAXmrkZN^bnL*S_p2=u zPQ=wjM_qV0YFS4iubgwf|F#b4%N;9U2Oouhh@ex1L+B#K1I^POnB=0G()F-z4N&%y z`boH@Rn3#}mp*eJU_Np?C$g0t`#}98_1DYO)}$+kXUBJEwQ8Q>H?!Q{joaBA)5lnd zEHrjp7^$m|eg~(5+ZcR20$)MiIJ^ZqS%!-{zZ=>HO^!K3KHlxIA&9>@IsM8t{OE5_ zdSct!JY8shw0jUHhTK7e)_I1C=XoNC$ITBq)Y1HFzEhWvI_$;6$vSj|(zOG_D;95+W zypd8#!k@V?9&P#^G%meQC3 z%0(zDv%J=%Q-UMEc!zz-X<*W_W*6TrI>dKtJ;f2-xwIR(%{NQ3Sa`^~7$YJffd7mF zKW^%snIApA1Yyw1`rJc_-n^oMO;xSS-vYWiFvkK5Z(=!#g|BqfBoAAwF;yq|JR)@# zE$a^T&uK%Dm`PzpRo-u(f7~^rZ*94rUG~Y?O!k0o8<6%-i1WSntQRb!mhV%5K z)O-Z;W;b(Mn;pgI&aXRxV;0uVH8{9SSZ*Vqx7d08!Brd4D@HQMoo{<#5V(WDmV&wiVpFD?&` z%JE-sGuZ#;aD0mm5@pt$t?0~N5J^q}{XyRq7zVv$5zm6SPPp&D=5F@aEE&UAWOP{+`;V##o-3-+0NRPsN;a^*TH8W7&%LI^}CwZ>kq5uf!9z_cdq7dD*q^u^^j+YW&6r~kazj~w=R&vHvHAN z<-im#5K}23q#%<9kHyMpVCJ-Q8x@OeH8X8zz#L*Uw;O=v5Fk4}RpIDW=8d^#`mIc?w*B=SA@ZJOn zBov1#3yqO=1H7c^_%aaRJ>%hudx4m6LJdtA&h|XwJcaVB0qz=f1$ne?G71*p*%n;}+0h4da9m}}%&gyTo*-?_Y zMiSIwoKhD3g?{cgMQ%Kh_CSr<6xggs3%UIk07P+(xw|;ZZt}sza$WIV92ESTfG&@) zLPhG1W6b60t1X9ZZ9n^7<)QepP4#G<*`)dI>odAHuB|bPF*gkfLI2s>Y1=$eH6c7g zU<&_oD{)%$j=G&xuz{zbV`Z%*K{~U*w3pMfCBTEX1F93=DDXt%=0+1s`TGMx3v?rl zkSw&Oa^Z?Be;#LU?;@!pn%MSB4%76YvDa6U7EQQ;s+b5RCY%!Bmi;*tR1AP`B9K1i zpI~K_aVk8L!D5Y%Xr_a)N4lzl0X{oa*^N0SRP~)GLE^h6b5b_@16i#&2rB>?1(FlW z16u)7T+~^S=qAgs3;f1H_aE@@sy*#k=igfX_K;3Tr1$%)eGMo=uF+HsoZw&IxR7>FL`eQ@P(pQ4eD*T?u{(EoV>aV3(ANm*DJ>Qd z?B)el=4}I?q%gz%rIX*4j-_A3AURip$2L-Nm8DG9Y^0ooHdoAZg*-nOdUg&J>mqN1 zK(ttLx1ky|jV2l{;+95*e#wh28I2mhf0k4JI1l;!n{DOYnXwzo);gw0nVCHWr>&aM51uU)iCX? zffl+!^Z90E-Vjw!OqZiX1A|SM8?|C-LkA^?nIjx60tvmrX&GiC53_>g#oZ`wJi9Il wr)d=h?{`wt`FOrb?PDuxXYN?d0_$$i*DJT}xz_f`cBkPXkw=-oJM+bV1J*~PnE(I) literal 0 HcmV?d00001 diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/access_point/app.h b/advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/access_point/app.h new file mode 100644 index 0000000..be6ee23 --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/access_point/app.h @@ -0,0 +1,79 @@ +/***************************************************************************//** + * @file + * @brief Application interface. + ******************************************************************************* + * # License + * Copyright 2025 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * 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. + * + ******************************************************************************/ + +#ifndef APP_H +#define APP_H + +#include + +/**************************************************************************//** + * Proceed with execution. (Indicate that it is required to run the application + * process action.) + *****************************************************************************/ +void app_proceed(void); + +/**************************************************************************//** + * Check if it is required to process with execution. + * @return true if required, false otherwise. + *****************************************************************************/ +bool app_is_process_required(void); + +/**************************************************************************//** + * Acquire access to protected variables. + * + * Acquire the guard to operate on the internal state variables. + * Guard is implemented using mutexing (RTOS). + * + * @note Must not be used from ISR context. + * + * @return true if operation was successful. + *****************************************************************************/ +bool app_mutex_acquire(void); + +/**************************************************************************//** + * Finish access to protected variables. + * + * Release the guard to stop working on the internal state variables. + * Guard is implemented using mutexing (RTOS). + * + * @note Must not be used from ISR context. + *****************************************************************************/ +void app_mutex_release(void); + +/**************************************************************************//** + * Initialize the application. + * + * This function initializes the application components. + * + * @note Must not be used from ISR context. + *****************************************************************************/ +void app_init_bt(void); + +#endif // APP_H diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/tag/app.h b/advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/tag/app.h new file mode 100644 index 0000000..be6ee23 --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/inc/tag/app.h @@ -0,0 +1,79 @@ +/***************************************************************************//** + * @file + * @brief Application interface. + ******************************************************************************* + * # License + * Copyright 2025 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * 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. + * + ******************************************************************************/ + +#ifndef APP_H +#define APP_H + +#include + +/**************************************************************************//** + * Proceed with execution. (Indicate that it is required to run the application + * process action.) + *****************************************************************************/ +void app_proceed(void); + +/**************************************************************************//** + * Check if it is required to process with execution. + * @return true if required, false otherwise. + *****************************************************************************/ +bool app_is_process_required(void); + +/**************************************************************************//** + * Acquire access to protected variables. + * + * Acquire the guard to operate on the internal state variables. + * Guard is implemented using mutexing (RTOS). + * + * @note Must not be used from ISR context. + * + * @return true if operation was successful. + *****************************************************************************/ +bool app_mutex_acquire(void); + +/**************************************************************************//** + * Finish access to protected variables. + * + * Release the guard to stop working on the internal state variables. + * Guard is implemented using mutexing (RTOS). + * + * @note Must not be used from ISR context. + *****************************************************************************/ +void app_mutex_release(void); + +/**************************************************************************//** + * Initialize the application. + * + * This function initializes the application components. + * + * @note Must not be used from ISR context. + *****************************************************************************/ +void app_init_bt(void); + +#endif // APP_H diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/app.c b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/app.c new file mode 100644 index 0000000..9833fdc --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/app.c @@ -0,0 +1,1018 @@ +/***************************************************************************//** + * @file + * @brief Core application logic. + ******************************************************************************* + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * 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. + * + ******************************************************************************/ +#include +#include + +#include "app_assert.h" +#include "app.h" +#include "app_log.h" +#include "psa/crypto.h" +#include "psa/crypto_values.h" +#include "sl_bluetooth_connection_config.h" +#include "sl_bt_api.h" +#include "sl_bt_ead_core.h" +#include "sl_main_init.h" +#include "sl_sleeptimer.h" +#include "nvm3.h" +#include "nvm3_default.h" + +// ----------------------------------------------------------------------------- +// Configuration +// ----------------------------------------------------------------------------- +#define KEY_MATERIAL_SIZE (SL_BT_EAD_SESSION_KEY_SIZE + SL_BT_EAD_IV_SIZE) +#define AP_SYNC_KEY_MATERIAL_ID 0x0001 +// user defined NVM3 objects should be placed below 0x10000. +#define AP_SYNC_KEY_IV_NVM3_KEY 0x00000 + +#define PERIODIC_ADV_INTERVAL 2400 +#define SUBEVENT_NUMBER 3 +#define SUBEVENT_INTERVAL 255 +#define RESPONSE_SLOT_DELAY 40 +#define RESPONSE_SLOT_SPACING 80 +#define RESPONSE_SLOT_NUMBER_PER_SUBVENT SUBEVENT_NUMBER + +#define TAG_STALE_TIMEOUT_MS 30000u +#define TAG_STALE_SCAN_PERIOD_MS 5000u +#define TAG_SWEEP_SIGNAL 0x01 +#define TAG_ID_UNASSIGNED 0xFF +#define MAX_TAGS SUBEVENT_NUMBER +#define BLE_EA_ADV_DATA_LEN 0xBF + +// ----------------------------------------------------------------------------- +// Types +// ----------------------------------------------------------------------------- +typedef enum tag_record_state_t { + TAG_RECORD_FREE = 0, + TAG_RECORD_PROVISIONING, + TAG_RECORD_ACTIVE, + TAG_RECORD_STALE +} tag_record_state_t; + +typedef struct tag_record_t { + tag_record_state_t state; + + uint8_t tag_id; + uint8_t response_subevent; + uint8_t response_slot; + + uint64_t last_seen_tick; + bd_addr address; + uint8_t address_type; + uint8_t bonding; + struct sl_bt_ead_key_material_s response_key_material; + struct sl_bt_ead_nonce_s response_nonce; +} tag_record_t; + +typedef enum gatt_sequence_state_t { + GATT_IDLE = 0, + GATT_DISCOVER_SERVICE, + GATT_DISCOVER_TAG_ID, + GATT_READ_TAG_ID, + GATT_WRITE_TAG_ID, + + GATT_DISCOVER_AP_SYNC_KEY, + GATT_WRITE_AP_SYNC_KEY, + + GATT_DISCOVER_TAG_RESP_KEY, + GATT_WRITE_TAG_RESP_KEY, + + GATT_FAILED, + GATT_DONE +} gatt_sequence_state_t; + +// ----------------------------------------------------------------------------- +// Static data +// ----------------------------------------------------------------------------- +static sl_sleeptimer_timer_handle_t tag_sweep_timer; +static uint64_t tag_stale_timeout_ticks; + +static uint8_t pawr_advertising_set_handle = 0xff; +static uint8_t advertisement_buffer[BLE_EA_ADV_DATA_LEN]; +static char name[] = "Encrypted Advertiser"; +static char secret_data[10]; +static uint8_t secret_number = 0; + +static tag_record_t tags[MAX_TAGS] = { 0 }; + +static const uint8_t SecureTagServiceUUID[] = { + 0x81, 0xC2, 0x00, 0x2D, + 0x31, 0xF4, 0xB0, 0xBF, + 0x2B, 0x42, 0x49, 0x68, + 0xC7, 0x25, 0x71, 0x41 +}; + +static const uint8_t TagIDCharUUID[16] = { + 0x91, 0xD4, 0x1E, 0x54, + 0x4B, 0xE1, 0xAC, 0x9B, + 0x08, 0x46, 0xEC, 0x60, + 0x26, 0x53, 0x2A, 0xC6 +}; + +static const uint8_t APSyncKeyMaterialUUID[16] = { + 0xCC, 0x44, 0x0B, 0x61, + 0xB3, 0x00, 0xD4, 0xB9, + 0x3B, 0x40, 0x33, 0x6E, + 0x31, 0xF0, 0x51, 0x2A +}; + +static const uint8_t TagResponseKeyMaterialUUID[16] = { + 0x8C, 0xED, 0xC7, 0x06, + 0x34, 0xA9, 0xDD, 0xB8, + 0x9E, 0x46, 0x57, 0xE3, + 0xCC, 0x4B, 0xAB, 0x8D +}; + +static uint32_t SecureTagServiceHandle = 0; +static uint16_t TagIDCharHandle = 0; +static uint16_t APSyncKeyMaterialCharHandle = 0; +static uint16_t TagResponseKeyMaterialCharHandle = 0; + +static struct sl_bt_ead_key_material_s Ap_sync_key_material = { 0 }; +static psa_key_id_t ead_ap_sync_key_id = AP_SYNC_KEY_MATERIAL_ID; + +#define TAG_RESP_KEY_ID_BASE 0x0002 +// ----------------------------------------------------------------------------- +// Forward declarations +// ----------------------------------------------------------------------------- +static sl_status_t find_tag(sl_bt_evt_scanner_extended_advertisement_report_t *report); +static sl_status_t construct_advertisement_payload(sl_bt_ead_key_material_p key_material, + sl_bt_ead_nonce_p nonce, + uint8_t *index); +static sl_status_t initialize_key(sl_bt_ead_key_material_p key_material); +static sl_status_t decrypt_tag_response(sl_bt_evt_pawr_advertiser_response_report_t *report, + tag_record_t *tag); +static sl_status_t resolve_tag_id(uint8_t claimed_id, + bd_addr address, + uint8_t address_type, + uint8_t *resolved_id); +static void stale_timer_cb(sl_sleeptimer_timer_handle_t *handle, void *data); +static void sweep_stale_tags(void); +static void export_ead_key_value(psa_key_id_t key_id, struct sl_bt_ead_key_material_s key_material, uint8_t key_material_value[KEY_MATERIAL_SIZE]); + +// ----------------------------------------------------------------------------- +// Application entry points +// ----------------------------------------------------------------------------- +void app_init(void) +{ + sl_status_t sc; + psa_status_t psa_sc; + Ecode_t nvm3_sc; + uint32_t stale_scan_period_ticks; + uint32_t timeout_ticks; + psa_key_handle_t ead_ap_sync_key_handle; + + app_log_info(" ++++++++++++++++++++++++++++++++++++ Ap boot ++++++++++++++++++++++++++++++++++++\r\n"); + + sc = sl_sleeptimer_init(); + app_assert_status(sc); + + sc = sl_sleeptimer_ms32_to_tick(TAG_STALE_SCAN_PERIOD_MS, + &stale_scan_period_ticks); + app_assert_status(sc); + + sc = sl_sleeptimer_ms32_to_tick(TAG_STALE_TIMEOUT_MS, &timeout_ticks); + app_assert_status(sc); + tag_stale_timeout_ticks = timeout_ticks; + + sc = sl_sleeptimer_start_periodic_timer(&tag_sweep_timer, + stale_scan_period_ticks, + stale_timer_cb, + NULL, + 0, + 0); + app_assert_status(sc); + + psa_sc = psa_crypto_init(); + app_assert_status(psa_sc); + psa_sc = psa_open_key(ead_ap_sync_key_id, + &ead_ap_sync_key_handle); + // check if AP sync key exists otherwise create key; + if (psa_sc == PSA_SUCCESS) { + app_log_info("Existing AP sync PSA key found\r\n"); + psa_sc = psa_close_key(ead_ap_sync_key_handle); + app_assert_status(psa_sc); + Ap_sync_key_material.key_id = ead_ap_sync_key_id; + nvm3_sc = nvm3_readData(nvm3_defaultHandle, + AP_SYNC_KEY_IV_NVM3_KEY, + Ap_sync_key_material.iv, + sizeof(Ap_sync_key_material.iv)); + app_assert_status(nvm3_sc); + } else if (psa_sc == PSA_ERROR_DOES_NOT_EXIST) { + app_log_info("AP sync key missing; creating it\r\n"); + sc = initialize_key(&Ap_sync_key_material); + app_assert_status(sc); + sc = sl_bt_ead_store_key(PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT, + PSA_KEY_LIFETIME_PERSISTENT, + &Ap_sync_key_material, + &ead_ap_sync_key_id); + app_assert_status(sc); + nvm3_sc = nvm3_writeData(nvm3_defaultHandle, + AP_SYNC_KEY_IV_NVM3_KEY, + Ap_sync_key_material.iv, + sizeof(Ap_sync_key_material.iv)); + app_assert_status(nvm3_sc); + } else { + app_log_error("Failed to open EAD key ID=0x%08lx, PSA status=0x%08lx\r\n", + (unsigned long)ead_ap_sync_key_id, + (unsigned long)psa_sc); + } +} + +void app_process_action(void) +{ + if (app_is_process_required()) { + ///////////////////////////////////////////////////////////////////////////// + // Put your additional application code here! // + // This is will run each time app_proceed() is called. // + // Do not call blocking functions from here! // + ///////////////////////////////////////////////////////////////////////////// + } +} + +/**************************************************************************//** + * Bluetooth stack event handler. + * This overrides the default weak implementation. + * + * @param[in] evt Event coming from the Bluetooth stack. + *****************************************************************************/ +void sl_bt_on_event(sl_bt_msg_t *evt) +{ + sl_status_t sc; + static uint8_t connection_handle = 0xFF; + static gatt_sequence_state_t gatt_state = GATT_IDLE; + static tag_record_t connected_tag = { 0 }; + static uint8_t provisioning_tag_id_value = 0; + static struct sl_bt_ead_nonce_s nonce; + static bool connection_in_progress = false; + + switch (SL_BT_MSG_ID(evt->header)) { + case sl_bt_evt_system_boot_id: { + bd_addr address; + uint8_t address_type; + sc = sl_bt_system_get_identity_address(&address, &address_type); + app_assert_status(sc); + app_log_info("Bluetooth %s address: %02X:%02X:%02X:%02X:%02X:%02X\r\n", + address_type ? "static random" : "public device", + address.addr[5], + address.addr[4], + address.addr[3], + address.addr[2], + address.addr[1], + address.addr[0]); + + sc = sl_bt_sm_set_bondable_mode(1); + app_assert_status(sc); + sc = sl_bt_sm_configure(SL_BT_SM_CONFIGURATION_BONDING_REQUIRED + | SL_BT_SM_CONFIGURATION_SC_ONLY + | SL_BT_SM_CONFIGURATION_BONDING_REQUEST_REQUIRED, + sl_bt_sm_io_capability_noinputnooutput); + app_assert_status(sc); + + sc = sl_bt_ead_session_init(&Ap_sync_key_material, NULL, &nonce); + app_assert_status(sc); + + sc = sl_bt_scanner_set_parameters(sl_bt_scanner_scan_mode_passive, + 200, + 200); + app_assert_status(sc); + + sc = sl_bt_scanner_start(sl_bt_scanner_scan_phy_1m, + sl_bt_scanner_discover_observation); + app_assert_status(sc); + app_log_info("Scanning for Tags\r\n"); + + sc = sl_bt_advertiser_create_set(&pawr_advertising_set_handle); + app_assert_status(sc); + + sc = sl_bt_pawr_advertiser_start(pawr_advertising_set_handle, + PERIODIC_ADV_INTERVAL, + PERIODIC_ADV_INTERVAL, + 0, + SUBEVENT_NUMBER, + SUBEVENT_INTERVAL, + RESPONSE_SLOT_DELAY, + RESPONSE_SLOT_SPACING, + RESPONSE_SLOT_NUMBER_PER_SUBVENT); + app_assert_status(sc); + + break; + } + + case sl_bt_evt_scanner_extended_advertisement_report_id: { + sl_bt_evt_scanner_extended_advertisement_report_t *report = + &evt->data.evt_scanner_extended_advertisement_report; + + if (connection_in_progress) { + break; + } + + sc = find_tag(report); + if (sc == SL_STATUS_OK) { + connection_in_progress = true; + sc = sl_bt_connection_open(report->address, + report->address_type, + sl_bt_gap_phy_1m, + &connection_handle); + app_assert_status(sc); + } + break; + } + + case sl_bt_evt_connection_opened_id: { + sl_bt_evt_connection_opened_t *connection = &evt->data.evt_connection_opened; + app_log_info( + "opened: connection=%u bonding=%u " + "peer=%02X:%02X:%02X:%02X:%02X:%02X type=%u\r\n", + connection->connection, + connection->bonding, + connection->address.addr[5], + connection->address.addr[4], + connection->address.addr[3], + connection->address.addr[2], + connection->address.addr[1], + connection->address.addr[0], + connection->address_type); + mbedtls_platform_zeroize(&connected_tag, sizeof(connected_tag)); + connected_tag.tag_id = TAG_ID_UNASSIGNED; + connected_tag.state = TAG_RECORD_PROVISIONING; + connected_tag.address = connection->address; + connected_tag.address_type = connection->address_type; + connected_tag.bonding = connection->bonding; + gatt_state = GATT_IDLE; + break; + } + + case sl_bt_evt_system_error_id: { + const sl_bt_evt_system_error_t *error = + &evt->data.evt_system_error; + + app_log_error("Bluetooth system error: reason=0x%04X data_len=%u data=", + error->reason, + error->data.len); + + for (uint8_t i = 0; i < error->data.len; i++) { + app_log("%02X", error->data.data[i]); + } + + app_log("\r\n"); + break; + } + + case sl_bt_evt_connection_parameters_id: { + sl_bt_evt_connection_parameters_t *connection = &evt->data.evt_connection_parameters; + + switch (connection->security_mode) { + case sl_bt_connection_mode1_level1: + app_log_info("No Security\r\n"); + sc = sl_bt_gatt_discover_primary_services_by_uuid(connection->connection, + sizeof(SecureTagServiceUUID), + SecureTagServiceUUID); + app_assert_status(sc); + gatt_state = GATT_DISCOVER_SERVICE; + break; + case sl_bt_connection_mode1_level2: + app_log_info("Unauthenticated pairing with encryption\r\n"); + sc = sl_bt_gatt_write_characteristic_value(connection->connection, + TagIDCharHandle, + sizeof(provisioning_tag_id_value), + &provisioning_tag_id_value); + app_assert_status(sc); + gatt_state = GATT_WRITE_TAG_ID; + + break; + case sl_bt_connection_mode1_level3: + app_log_info("Authenticated pairing with encryption\r\n"); + break; + case sl_bt_connection_mode1_level4: + app_log_info("Authenticated Secure connections pairing with encryption\r\n"); + break; + default: + break; + } + break; + } + + case sl_bt_evt_gatt_service_id: { + sl_bt_evt_gatt_service_t *service = &evt->data.evt_gatt_service; + if (memcmp(service->uuid.data, + SecureTagServiceUUID, + sizeof(SecureTagServiceUUID)) == 0) { + SecureTagServiceHandle = service->service; + } + break; + } + + case sl_bt_evt_gatt_characteristic_id: { + const sl_bt_evt_gatt_characteristic_t *char_evt = + &evt->data.evt_gatt_characteristic; + + switch (gatt_state) { + case GATT_DISCOVER_TAG_ID: + TagIDCharHandle = char_evt->characteristic; + break; + case GATT_DISCOVER_AP_SYNC_KEY: + APSyncKeyMaterialCharHandle = char_evt->characteristic; + break; + case GATT_DISCOVER_TAG_RESP_KEY: + TagResponseKeyMaterialCharHandle = char_evt->characteristic; + break; + default: + break; + } + break; + } + + case sl_bt_evt_gatt_characteristic_value_id: { + const sl_bt_evt_gatt_characteristic_value_t *char_evt = + &evt->data.evt_gatt_characteristic_value; + if (char_evt->characteristic == TagIDCharHandle) { + connected_tag.tag_id = char_evt->value.data[0]; + } + + break; + } + + case sl_bt_evt_gatt_procedure_completed_id: { + const sl_bt_evt_gatt_procedure_completed_t *gatt_evt = + &evt->data.evt_gatt_procedure_completed; + + if (gatt_evt->result != SL_STATUS_OK) { + gatt_state = GATT_FAILED; + app_log_info("Gatt procedure failed rc %04X\r\n", gatt_evt->result); + sc = sl_bt_connection_close(gatt_evt->connection); + app_assert_status(sc); + break; + } + + switch (gatt_state) { + case GATT_DISCOVER_SERVICE: + sc = sl_bt_gatt_discover_characteristics_by_uuid(gatt_evt->connection, + SecureTagServiceHandle, + sizeof(TagIDCharUUID), + TagIDCharUUID); + app_assert_status(sc); + gatt_state = GATT_DISCOVER_TAG_ID; + break; + + case GATT_DISCOVER_TAG_ID: + sc = sl_bt_gatt_discover_characteristics_by_uuid(gatt_evt->connection, + SecureTagServiceHandle, + sizeof(APSyncKeyMaterialUUID), + APSyncKeyMaterialUUID); + app_assert_status(sc); + gatt_state = GATT_DISCOVER_AP_SYNC_KEY; + break; + + case GATT_DISCOVER_AP_SYNC_KEY: + sc = sl_bt_gatt_discover_characteristics_by_uuid(gatt_evt->connection, + SecureTagServiceHandle, + sizeof(TagResponseKeyMaterialUUID), + TagResponseKeyMaterialUUID); + app_assert_status(sc); + gatt_state = GATT_DISCOVER_TAG_RESP_KEY; + break; + + case GATT_DISCOVER_TAG_RESP_KEY: + sc = sl_bt_gatt_read_characteristic_value(gatt_evt->connection, + TagIDCharHandle); + app_assert_status(sc); + gatt_state = GATT_READ_TAG_ID; + break; + + case GATT_READ_TAG_ID: + { + sc = resolve_tag_id(connected_tag.tag_id, + connected_tag.address, + connected_tag.address_type, + &provisioning_tag_id_value); + if (sc != SL_STATUS_OK) { + app_log_error("No free/stale tag record available\r\n"); + sc = sl_bt_connection_close(gatt_evt->connection); + app_assert_status(sc); + gatt_state = GATT_FAILED; + break; + } + connected_tag.tag_id = provisioning_tag_id_value; + sc = sl_bt_sm_increase_security(gatt_evt->connection); + app_assert_status(sc); + app_log_info("requested to increase security\r\n"); + break; + } + + case GATT_WRITE_TAG_ID: + { + connected_tag.response_subevent = provisioning_tag_id_value; + connected_tag.response_slot = provisioning_tag_id_value; + app_log_info("Tag ID successfully written, writing AP sync key material\r\n"); + + uint8_t Ap_sync_key_material_value[KEY_MATERIAL_SIZE] = { 0 }; + export_ead_key_value(ead_ap_sync_key_id, Ap_sync_key_material, Ap_sync_key_material_value); + sc = sl_bt_gatt_write_characteristic_value(gatt_evt->connection, + APSyncKeyMaterialCharHandle, + sizeof(Ap_sync_key_material_value), + Ap_sync_key_material_value); + app_assert_status(sc); + mbedtls_platform_zeroize(Ap_sync_key_material_value, + sizeof(Ap_sync_key_material_value)); + gatt_state = GATT_WRITE_AP_SYNC_KEY; + break; + } + + case GATT_WRITE_AP_SYNC_KEY: + { + app_log_info("AP sync key successfully written, writing Tag resp key material\r\n"); + struct sl_bt_ead_key_material_s tag_resp_key_material = { 0 }; + uint8_t tag_resp_key_material_value[KEY_MATERIAL_SIZE] = { 0 }; + sc = initialize_key(&tag_resp_key_material); + app_assert_status(sc); + psa_key_id_t key_id = TAG_RESP_KEY_ID_BASE + connected_tag.tag_id; + sc = sl_bt_ead_store_key(PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT, + PSA_KEY_LIFETIME_PERSISTENT, + &tag_resp_key_material, + &key_id); + app_assert_status(sc); + connected_tag.response_key_material = tag_resp_key_material; + memcpy(connected_tag.response_nonce.iv, + connected_tag.response_key_material.iv, + SL_BT_EAD_IV_SIZE); + app_log_info("Stored response decrypt key for tag_id=%d slot=%d\r\n", + provisioning_tag_id_value, + connected_tag.response_slot); + export_ead_key_value(key_id, tag_resp_key_material, tag_resp_key_material_value); + sc = sl_bt_gatt_write_characteristic_value(gatt_evt->connection, + TagResponseKeyMaterialCharHandle, + sizeof(tag_resp_key_material_value), + tag_resp_key_material_value); + app_assert_status(sc); + mbedtls_platform_zeroize(tag_resp_key_material_value, + sizeof(tag_resp_key_material_value)); + gatt_state = GATT_WRITE_TAG_RESP_KEY; + break; + } + + case GATT_WRITE_TAG_RESP_KEY: + { + sc = sl_bt_advertiser_past_transfer(connection_handle, + 0, + pawr_advertising_set_handle); + app_assert_status(sc); + connected_tag.state = TAG_RECORD_ACTIVE; + connected_tag.last_seen_tick = sl_sleeptimer_get_tick_count64(); + tags[connected_tag.tag_id] = connected_tag; + gatt_state = GATT_DONE; + break; + } + + default: + break; + } + break; + } + + case sl_bt_evt_sm_confirm_bonding_id: { + app_log_info("confirm bonding\r\n"); + break; + } + + case sl_bt_evt_sm_bonded_id: { + app_log_info("device bonded successfully\r\n"); + break; + } + + case sl_bt_evt_sm_bonding_failed_id: { + app_log_info("bonding failed, peer address: %2X:%2X:%2X:%2X:%2X:%2X reason 0x%2X, closing connection\r\n", + connected_tag.address.addr[5], + connected_tag.address.addr[4], + connected_tag.address.addr[3], + connected_tag.address.addr[2], + connected_tag.address.addr[1], + connected_tag.address.addr[0], + evt->data.evt_sm_bonding_failed.reason); + sl_bt_connection_close(evt->data.evt_sm_bonding_failed.connection); + + break; + } + + case sl_bt_evt_connection_closed_id: { + app_log_info("connection closed, reason 0x%2X\r\n", evt->data.evt_connection_closed.reason); + connection_in_progress = false; + break; + } + + case sl_bt_evt_pawr_advertiser_subevent_data_request_id: { + sl_bt_evt_pawr_advertiser_subevent_data_request_t req = + evt->data.evt_pawr_advertiser_subevent_data_request; + + for (uint8_t i = 0; i < req.subevent_data_count; i++) { + uint8_t subevent_index = (req.subevent_start + i) % SUBEVENT_NUMBER; + uint8_t advertisement_len; + + app_log_info("Requesting data for subevent %02X\r\n", subevent_index); + + sc = sl_bt_ead_randomizer_update(&nonce); + app_assert_status(sc); + + sc = construct_advertisement_payload(&Ap_sync_key_material, + &nonce, + &advertisement_len); + app_assert_status(sc); + + sc = sl_bt_pawr_advertiser_set_subevent_data(req.advertising_set, + subevent_index, + 0, + RESPONSE_SLOT_NUMBER_PER_SUBVENT, + advertisement_len, + advertisement_buffer); + } + break; + } + + case sl_bt_evt_pawr_advertiser_response_report_id: { + sl_bt_evt_pawr_advertiser_response_report_t *report = + &evt->data.evt_pawr_advertiser_response_report; + + if (report->data_status != 0) { + break; + } + + app_log_info("response for subevent %02X, response slot %02X\r\n", + report->subevent, + report->response_slot); + + if (report->response_slot >= MAX_TAGS) { + break; + } + + tag_record_t *tag = &tags[report->response_slot]; + + if (tag->state != TAG_RECORD_ACTIVE + || tag->response_subevent != report->subevent + || tag->response_slot != report->response_slot) { + break; + } + + sc = decrypt_tag_response(report, tag); + if (sc == SL_STATUS_OK) { + tag->last_seen_tick = sl_sleeptimer_get_tick_count64(); + } else { + app_log_error("Failed to decrypt response from tag_id=%d slot=%d rc=0x%04lX\r\n", + tag->tag_id, + report->response_slot, + sc); + } + app_log("\n\r**************************************************************************\n\r"); + break; + } + + case sl_bt_evt_system_external_signal_id: { + if (evt->data.evt_system_external_signal.extsignals & TAG_SWEEP_SIGNAL) { + sweep_stale_tags(); + } + break; + } + + case sl_bt_evt_scanner_legacy_advertisement_report_id: { + break; + } + + default: { + // app_log_info("untracked event id %08lX\r\n",(unsigned long)SL_BT_MSG_ID(evt->header)); + break; + } + } +} + +// ----------------------------------------------------------------------------- +// Helpers +// ----------------------------------------------------------------------------- +static sl_status_t construct_advertisement_payload(sl_bt_ead_key_material_p key_material, + sl_bt_ead_nonce_p nonce, + uint8_t *index) +{ + sl_status_t sc = SL_STATUS_FAIL; + uint8_t manufacturer_data_buf[BLE_EA_ADV_DATA_LEN]; + size_t manufacturer_data_len; // len + type + data + sl_bt_ead_mic_t message_integraty_check; + struct sl_bt_ead_ad_structure_s encrypted_ad_structure; + uint8_t encrypted_data_length = BLE_EA_ADV_DATA_LEN; + + *index = 0; + + // Refresh the secret part of the advertisement. + secret_number++; + snprintf(secret_data, sizeof(secret_data), "secret%02d", secret_number); + manufacturer_data_len = (size_t)(2 + strlen(secret_data)); + + // Add flags. + advertisement_buffer[(*index)++] = 0x02; // Ad structure len + advertisement_buffer[(*index)++] = 0x01; // Ad structure type + advertisement_buffer[(*index)++] = 0x06; // Ad structure data + + // Add complete local name. + advertisement_buffer[(*index)++] = strlen(name) + 1; // Ad structure len + advertisement_buffer[(*index)++] = 0x09; // Ad structure type + memcpy(advertisement_buffer + *index, name, strlen(name)); // Ad structure data + *index += strlen(name); + + // Add encrypted manufacturer specific data. + manufacturer_data_buf[0] = strlen(secret_data) + 1; // Ad structure len + manufacturer_data_buf[1] = 0xFF; // Ad structure type + memcpy(manufacturer_data_buf + 2, secret_data, strlen(secret_data)); // Ad structure data + + sc = sl_bt_ead_encrypt(key_material, + nonce, + manufacturer_data_len, + manufacturer_data_buf, + message_integraty_check); + app_assert_status(sc); + + encrypted_ad_structure.length = manufacturer_data_len; + encrypted_ad_structure.ad_type = SL_BT_ENCRYPTED_DATA_AD_TYPE; + encrypted_ad_structure.ad_data = manufacturer_data_buf; + encrypted_ad_structure.randomizer = &(nonce->randomizer); + encrypted_ad_structure.mic = &message_integraty_check; + + sc = sl_bt_ead_pack_ad_data(&encrypted_ad_structure, + &encrypted_data_length, + advertisement_buffer + *index); + app_assert_status(sc); + app_log("Information before encryption:%s\n\r", secret_data); + app_log("Information after encryption:\n\r"); + + for (uint8_t i = *index; i < *index + encrypted_data_length; i++) { + app_log("%02X", advertisement_buffer[i]); + } + + app_log("\n\r"); + app_log("--------------------------------------------------------------------------\n\r"); + (*index) += encrypted_data_length; + + return sc; +} + +static sl_status_t initialize_key(sl_bt_ead_key_material_p key_material) +{ + psa_status_t psa_sc = PSA_SUCCESS; + sl_bt_ead_session_key_t session_key = { 0 }; + sl_bt_ead_iv_t initialization_vector = { 0 }; + + psa_sc = psa_generate_random(session_key, SL_BT_EAD_SESSION_KEY_SIZE); + if (psa_sc != PSA_SUCCESS) { + return SL_STATUS_FAIL; + } + + app_log("\r\n"); + + psa_sc = psa_generate_random(initialization_vector, SL_BT_EAD_IV_SIZE); + if (psa_sc != PSA_SUCCESS) { + return SL_STATUS_FAIL; + } + + app_log("\r\n"); + memcpy(key_material->key, session_key, SL_BT_EAD_SESSION_KEY_SIZE); + memcpy(key_material->iv, initialization_vector, SL_BT_EAD_IV_SIZE); + mbedtls_platform_zeroize(session_key, sizeof(session_key)); + mbedtls_platform_zeroize(initialization_vector, + sizeof(initialization_vector)); + return SL_STATUS_OK; +} + +static sl_status_t decrypt_tag_response(sl_bt_evt_pawr_advertiser_response_report_t *report, + tag_record_t *tag) +{ + sl_status_t sc; + uint8_t i = 0; + struct sl_bt_ead_ad_structure_s response_info; + sl_bt_ead_randomizer_t randomizer; + sl_bt_ead_mic_t mic; + uint8_t decrypted_data_buffer[30]; + + if (report == NULL || tag == NULL) { + return SL_STATUS_NULL_POINTER; + } + + response_info.length = sizeof(decrypted_data_buffer); + response_info.randomizer = &randomizer; + response_info.ad_data = decrypted_data_buffer; + response_info.mic = &mic; + + while (i + 1 < report->data.len) { + uint8_t ad_len = report->data.data[i]; + + if (ad_len == 0) { + break; + } + + if ((uint16_t)i + ad_len >= report->data.len) { + app_log_error("Invalid response AD length: i=%d ad_len=%d report_len=%d\r\n", + i, + ad_len, + report->data.len); + return SL_STATUS_INVALID_PARAMETER; + } + + uint8_t ad_type = report->data.data[i + 1]; + + if (ad_type == SL_BT_ENCRYPTED_DATA_AD_TYPE) { + app_log_info("Encrypted response from tag_id=%d slot=%d, response data:\r\n", + tag->tag_id, + report->response_slot); + + for (uint8_t j = 0; j < ad_len + 1; j++) { + app_log("%02X", report->data.data[i + j]); + } + app_log("\r\n"); + + response_info.length = sizeof(decrypted_data_buffer); + + sc = sl_bt_ead_unpack_ad_data(&report->data.data[i], + &response_info); + if (sc != SL_STATUS_OK) { + app_log_error("response unpack failed rc=0x%04lX\r\n", sc); + return sc; + } + + memcpy(tag->response_nonce.randomizer, + response_info.randomizer, + SL_BT_EAD_RANDOMIZER_SIZE); + + sc = sl_bt_ead_decrypt(&tag->response_key_material, + &tag->response_nonce, + (uint8_t *)response_info.mic, + response_info.length, + response_info.ad_data); + + if (sc != SL_STATUS_OK) { + app_log_error("response decrypt failed rc=0x%04lX\r\n", sc); + return sc; + } + + app_log_info("Decrypted response from tag_id=%d: ", tag->tag_id); + + for (uint8_t k = 0; k < response_info.length; k++) { + app_log("%c", response_info.ad_data[k]); + } + app_log("\r\n"); + + return SL_STATUS_OK; + } + + i = i + ad_len + 1; + } + + return SL_STATUS_NOT_FOUND; +} + +static sl_status_t find_tag(sl_bt_evt_scanner_extended_advertisement_report_t *report) +{ + uint8_t index = 0; + + while (index < report->data.len) { + uint8_t ADdatalen = report->data.data[index]; + uint8_t ADdatatype = report->data.data[index + 1]; + + if (ADdatatype == 0x06 || ADdatatype == 0x07) { + if (memcmp(&report->data.data[index + 2], + SecureTagServiceUUID, + sizeof(SecureTagServiceUUID)) == 0) { + return SL_STATUS_OK; + } + } + + index = index + ADdatalen + 1; + } + + return SL_STATUS_FAIL; +} + +static bool address_compare(const tag_record_t *tag, + bd_addr address, + uint8_t address_type) +{ + return tag->state != TAG_RECORD_FREE + && tag->address_type == address_type + && memcmp(tag->address.addr, address.addr, sizeof(address.addr)) == 0; +} + +static sl_status_t find_record_by_address(bd_addr address, + uint8_t address_type, + uint8_t *tag_id) +{ + for (uint8_t i = 0; i < MAX_TAGS; i++) { + if (address_compare(&tags[i], address, address_type)) { + *tag_id = i; + return SL_STATUS_OK; + } + } + + return SL_STATUS_NOT_FOUND; +} + +static sl_status_t allocate_record(uint8_t *tag_id) +{ + for (uint8_t i = 0; i < MAX_TAGS; i++) { + if (tags[i].state == TAG_RECORD_FREE || tags[i].state == TAG_RECORD_STALE) { + *tag_id = i; + return SL_STATUS_OK; + } + } + + return SL_STATUS_FULL; +} + +static sl_status_t resolve_tag_id(uint8_t claimed_id, + bd_addr address, + uint8_t address_type, + uint8_t *resolved_id) +{ + if (claimed_id < MAX_TAGS && address_compare(&tags[claimed_id], address, address_type)) { + *resolved_id = claimed_id; + return SL_STATUS_OK; + } + + if (find_record_by_address(address, address_type, resolved_id) == SL_STATUS_OK) { + return SL_STATUS_OK; + } + + return allocate_record(resolved_id); +} + +static void sweep_stale_tags(void) +{ + uint64_t now = sl_sleeptimer_get_tick_count64(); + + for (uint8_t i = 0; i < MAX_TAGS; i++) { + tag_record_t *tag = &tags[i]; + + if (tag->state == TAG_RECORD_ACTIVE + && (now - tag->last_seen_tick) > tag_stale_timeout_ticks) { + if (tag->response_key_material.key_id != PSA_KEY_ID_NULL) { + sl_bt_ead_delete_key(&tag->response_key_material); + } + mbedtls_platform_zeroize(&tag->response_nonce, + sizeof(tag->response_nonce)); + tag->state = TAG_RECORD_STALE; + tag->bonding = SL_BT_INVALID_BONDING_HANDLE; + app_log_info("tag_id=%d marked stale\r\n", tag->tag_id); + } + } +} + +static void stale_timer_cb(sl_sleeptimer_timer_handle_t *handle, void *data) +{ + (void)handle; + (void)data; + sl_bt_external_signal(TAG_SWEEP_SIGNAL); +} + +static void export_ead_key_value(psa_key_id_t key_id, struct sl_bt_ead_key_material_s key_material, uint8_t key_material_value[KEY_MATERIAL_SIZE]) +{ + uint8_t session_key_value[SL_BT_EAD_SESSION_KEY_SIZE] = { 0 }; + size_t exported_length = 0; + + psa_status_t psa_sc = psa_export_key( + key_id, + session_key_value, + sizeof(session_key_value), + &exported_length); + app_assert_status(psa_sc); + + for (size_t i = 0; i < exported_length / 2; i++) { + uint8_t tmp = session_key_value[i]; + session_key_value[i] = + session_key_value[exported_length - 1 - i]; + session_key_value[exported_length - 1 - i] = tmp; + } + + memcpy(key_material_value, session_key_value, SL_BT_EAD_SESSION_KEY_SIZE); + memcpy(key_material_value + SL_BT_EAD_SESSION_KEY_SIZE, key_material.iv, SL_BT_EAD_IV_SIZE); + mbedtls_platform_zeroize(session_key_value, + sizeof(session_key_value)); +} diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/main.c b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/main.c new file mode 100644 index 0000000..72c8be4 --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/access_point/main.c @@ -0,0 +1,71 @@ +/***************************************************************************//** + * @file main.c + * @brief main() function. + ******************************************************************************* + * # License + * Copyright 2025 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * 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. + * + ******************************************************************************/ +#include "sl_component_catalog.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_main_kernel.h" +#else // SL_CATALOG_KERNEL_PRESENT +#include "sl_main_process_action.h" +#endif // SL_CATALOG_KERNEL_PRESENT + +int main(void) +{ + // Initialize Silicon Labs device, system, service(s) and protocol stack(s). + // Note that if the kernel is present, the start task will be started and software + // component initialization will take place there. + sl_main_init(); + +#if defined(SL_CATALOG_KERNEL_PRESENT) + // 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) { + // Silicon Labs components process action routine + // must be called from the super loop. + sl_main_process_action(); + + // User provided code. Application process. + app_process_action(); + +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) + // Let the CPU go to sleep if the system allows it. + sl_power_manager_sleep(); +#endif + } +#endif // SL_CATALOG_KERNEL_PRESENT +} diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/app.c b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/app.c new file mode 100644 index 0000000..3637fca --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/app.c @@ -0,0 +1,514 @@ +/***************************************************************************//** + * @file + * @brief Core application logic. + ******************************************************************************* + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * 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. + * + ******************************************************************************/ +#include "sl_bt_api.h" +#include "sl_main_init.h" +#include "app_assert.h" +#include "app.h" +#include "app_log.h" +#include +#include +#include "sl_bt_ead_core.h" +#include "psa/crypto.h" +#include "psa/crypto_values.h" +#include "sl_sleeptimer.h" + +#define U1250_TO_MS(x) ((uint32_t)(x) * 1250u / 1000u) /* 1.25 ms units -> ms */ +#define U0125_TO_US(x) ((uint32_t)(x) * 125u) /* 0.125 ms units -> us */ + +#define PERIODIC_SYNC_SKIP 0 +#define PERIODIC_SYNC_TIMEOUT 600 + +#define gattdb_tag_id 0x15 +#define gattdb_ap_sync_key_material 0x17 +#define gattdb_tag_response_key_material 0x19 + +#define KEY_MATERIAL_SIZE (SL_BT_EAD_SESSION_KEY_SIZE + SL_BT_EAD_IV_SIZE) +uint8_t tag_id = 0; + +static struct sl_bt_ead_key_material_s Ap_sync_key_material = { 0 }; +static struct sl_bt_ead_key_material_s tag_response_key_material = { 0 }; + +// The advertising set handle allocated from Bluetooth stack. +static uint8_t advertising_set_handle = 0xff; +static bool advertising_active = false; + +// Response data +#define BLE_EA_RSP_DATA_LEN 0xBF +#define RESPONSE_PLAINTEXT_MAX_LEN 16 +uint8_t response_buffer[BLE_EA_RSP_DATA_LEN]; +uint8_t secret_data_len = 0; +uint8_t secret_number = 0; + +static sl_sleeptimer_timer_handle_t out_of_sync_timer; +#define TAG_OUT_OF_SYNC_PERIOD_MS 10000 +#define TAG_OUT_OF_SYNC_SIGNAL 0x01 +static void out_of_sync_cb(sl_sleeptimer_timer_handle_t *handle, void *data); + +uint8_t subevents_subscription_list[] = { 0 }; + +uint16_t pawr_handle = SL_BT_INVALID_SYNC_HANDLE; +uint8_t connection = SL_BT_INVALID_CONNECTION_HANDLE; +bd_addr ap_address = { 0 }; + +sl_status_t extract_and_decrypt(sl_bt_evt_pawr_sync_subevent_report_t *sync_report, + sl_bt_ead_key_material_p key_material, + sl_bt_ead_nonce_p nonce); + +sl_status_t construct_response_payload(sl_bt_ead_key_material_p key_material, sl_bt_ead_nonce_p nonce, uint8_t* secret_payload, uint8_t* secret_payload_len); + +// Application Init. +void app_init(void) +{ + sl_status_t sc; + uint32_t out_of_sync_ticks; + + sc = sl_sleeptimer_init(); + app_assert_status(sc); + + sc = sl_sleeptimer_ms32_to_tick(TAG_OUT_OF_SYNC_PERIOD_MS, + &out_of_sync_ticks); + app_assert_status(sc); + sc = sl_sleeptimer_start_periodic_timer(&out_of_sync_timer, + out_of_sync_ticks, + out_of_sync_cb, + NULL, + 0, + 0); + app_assert_status(sc); +} + +void app_process_action(void) +{ + if (app_is_process_required()) { + ///////////////////////////////////////////////////////////////////////////// + // Put your additional application code here! // + // This is will run each time app_proceed() is called. // + // Do not call blocking functions from here! // + ///////////////////////////////////////////////////////////////////////////// + } +} + +/**************************************************************************//** + * Bluetooth stack event handler. + * This overrides the default weak implementation. + * + * @param[in] evt Event coming from the Bluetooth stack. + *****************************************************************************/ +void sl_bt_on_event(sl_bt_msg_t *evt) +{ + sl_status_t sc; + static struct sl_bt_ead_nonce_s ap_sync_nonce, tag_resp_nonce; + static psa_key_id_t ap_sync_key_id = PSA_KEY_ID_NULL; + static psa_key_id_t tag_resp_key_id = PSA_KEY_ID_NULL; + + switch (SL_BT_MSG_ID(evt->header)) { + case sl_bt_evt_system_boot_id: + { + bd_addr address; + uint8_t address_type; + app_log_info("++++++++++++++++++++++++++++++++++++ Tag boot ++++++++++++++++++++++++++++++++++++\r\n"); + sc = sl_bt_system_get_identity_address(&address, &address_type); + app_assert_status(sc); + app_log_info("Bluetooth %s address: %02X:%02X:%02X:%02X:%02X:%02X\r\n", + address_type ? "static random" : "public device", + address.addr[5], + address.addr[4], + address.addr[3], + address.addr[2], + address.addr[1], + address.addr[0]); + + sc = sl_bt_sm_set_bondable_mode(1); + app_assert_status(sc); + sc = sl_bt_sm_configure(SL_BT_SM_CONFIGURATION_BONDING_REQUIRED + | SL_BT_SM_CONFIGURATION_SC_ONLY + | SL_BT_SM_CONFIGURATION_BONDING_REQUEST_REQUIRED, + sl_bt_sm_io_capability_noinputnooutput); + app_assert_status(sc); + + sc = sl_bt_past_receiver_set_default_sync_receive_parameters( + sl_bt_past_receiver_mode_synchronize, + PERIODIC_SYNC_SKIP, + PERIODIC_SYNC_TIMEOUT, + sl_bt_sync_report_all + ); + + sc = sl_bt_advertiser_create_set(&advertising_set_handle); + app_assert_status(sc); + + sc = sl_bt_extended_advertiser_generate_data(advertising_set_handle, + sl_bt_advertiser_general_discoverable); + app_assert_status(sc); + + sc = sl_bt_advertiser_set_timing( + advertising_set_handle, + 160, // min. adv. interval (milliseconds * 1.6) + 160, // max. adv. interval (milliseconds * 1.6) + 0, // adv. duration + 0); // max. num. adv. events + app_assert_status(sc); + // Start advertising and enable connections. + sc = sl_bt_extended_advertiser_start(advertising_set_handle, + sl_bt_extended_advertiser_connectable, 0x00); + app_assert_status(sc); + advertising_active = true; + app_log_info("starting provisioning advertisement\r\n"); + break; + } + + case sl_bt_evt_connection_opened_id: + { + app_log_info("connection opened\r\n"); + connection = evt->data.evt_connection_opened.connection; + ap_address = evt->data.evt_connection_opened.address; + advertising_active = false; + break; + } + + case sl_bt_evt_connection_closed_id: + { + app_log_info("connection closed, reason 0x%2X\r\n", evt->data.evt_connection_closed.reason); + connection = SL_BT_INVALID_CONNECTION_HANDLE; + break; + } + + case sl_bt_evt_connection_parameters_id: { + switch (evt->data.evt_connection_parameters.security_mode) { + case sl_bt_connection_mode1_level1: + app_log_info("No Security\r\n"); + break; + case sl_bt_connection_mode1_level2: + app_log_info("Unauthenticated pairing with encryption\r\n"); + break; + case sl_bt_connection_mode1_level3: + app_log_info("Authenticated pairing with encryption\r\n"); + break; + case sl_bt_connection_mode1_level4: + app_log_info("Authenticated Secure Connections pairing with encryption\r\n"); + break; + } + break; + } + + case sl_bt_evt_gatt_server_attribute_value_id: + { + sl_bt_evt_gatt_server_attribute_value_t *att_value = &evt->data.evt_gatt_server_attribute_value; + switch (att_value->attribute) { + case gattdb_tag_id: + app_log_info("assigned tag id %d\r\n", att_value->value.data[0]); + tag_id = att_value->value.data[0]; + subevents_subscription_list[0] = tag_id; + break; + case gattdb_ap_sync_key_material: + + memcpy(Ap_sync_key_material.key, + att_value->value.data, + SL_BT_EAD_SESSION_KEY_SIZE); + + memcpy(Ap_sync_key_material.iv, + att_value->value.data + SL_BT_EAD_SESSION_KEY_SIZE, + SL_BT_EAD_IV_SIZE); + + memcpy(ap_sync_nonce.iv, + Ap_sync_key_material.iv, + SL_BT_EAD_IV_SIZE); + sc = sl_bt_ead_store_key(PSA_KEY_USAGE_DECRYPT, PSA_KEY_LIFETIME_VOLATILE, &Ap_sync_key_material, &ap_sync_key_id); + app_assert_status(sc); + break; + case gattdb_tag_response_key_material: + memcpy(tag_response_key_material.key, + att_value->value.data, + SL_BT_EAD_SESSION_KEY_SIZE); + + memcpy(tag_response_key_material.iv, + att_value->value.data + SL_BT_EAD_SESSION_KEY_SIZE, + SL_BT_EAD_IV_SIZE); + + memcpy(tag_resp_nonce.iv, + tag_response_key_material.iv, + SL_BT_EAD_IV_SIZE); + sc = sl_bt_ead_store_key(PSA_KEY_USAGE_ENCRYPT, PSA_KEY_LIFETIME_VOLATILE, &tag_response_key_material, &tag_resp_key_id); + app_assert_status(sc); + break; + } + break; + } + + case sl_bt_evt_pawr_sync_transfer_received_id: + { + sl_bt_evt_pawr_sync_transfer_received_t sync_report = evt->data.evt_pawr_sync_transfer_received; + app_log(" sync status %02X\r\n", sync_report.status); + app_log( + "PAwR sync opened:\r\n" + "adv_interval= %" PRIu32 "ms\r\n" + "num_subevents= %d\r\n" + "subevent_interval= %" PRIu32 "ms\r\n" + "rsp_slot_delay= %" PRIu32 "ms\r\n" + "rsp_slot_spacing= %" PRIu32 "us\r\n", + U1250_TO_MS(sync_report.adv_interval), + sync_report.num_subevents, + U1250_TO_MS(sync_report.subevent_interval), + U1250_TO_MS(sync_report.response_slot_delay), + U0125_TO_US(sync_report.response_slot_spacing) + ); + pawr_handle = sync_report.sync; + sc = sl_bt_pawr_sync_set_sync_subevents(pawr_handle, sizeof(subevents_subscription_list), subevents_subscription_list); + app_assert_status(sc); + sc = sl_bt_connection_close(sync_report.connection); + app_assert_status(sc); + break; + } + + case sl_bt_evt_sync_closed_id: + { + app_log_info("Sync closed: handle=0x%04X reason=0x%04X\r\n", + evt->data.evt_sync_closed.sync, + evt->data.evt_sync_closed.reason); + pawr_handle = SL_BT_INVALID_SYNC_HANDLE; + break; + } + + case sl_bt_evt_pawr_sync_opened_id: + { + app_log_info("sync opened\r\n"); + break; + } + + case sl_bt_evt_pawr_sync_subevent_report_id: + { + sl_bt_evt_pawr_sync_subevent_report_t *sync_report = &evt->data.evt_pawr_sync_subevent_report; + for (uint8_t index = 0; index < sizeof(subevents_subscription_list) / sizeof(uint8_t); index++) { + if (subevents_subscription_list[index] == sync_report->subevent) { + app_log("--------------------------------------------------------------------------\n\r"); + app_log_info( + "PAwR report: sync=0x%04X subevent=%u status=%u len=%u counter=%u\r\n", + sync_report->sync, + sync_report->subevent, + sync_report->data_status, + sync_report->data.len, + sync_report->counter); + if (sync_report->data_status == 255) { + app_log_info("Failed to receive subevent data in this subevent\r\n"); + break; + } + sc = extract_and_decrypt(sync_report, &Ap_sync_key_material, &ap_sync_nonce); + if (sc != 0) { + app_log("failed to decrypt the message\r\n"); + sc = sl_bt_sync_close(sync_report->sync); + app_assert_status(sc); + pawr_handle = SL_BT_INVALID_SYNC_HANDLE; + break; + } + sc = sl_bt_ead_randomizer_update(&tag_resp_nonce); + app_assert_status(sc); + + secret_number++; + + secret_data_len = BLE_EA_RSP_DATA_LEN; + + sc = construct_response_payload(&tag_response_key_material, + &tag_resp_nonce, + response_buffer, + &secret_data_len); + app_assert_status(sc); + + sc = sl_bt_pawr_sync_set_response_data(pawr_handle, + sync_report->event_counter, + sync_report->subevent, + sync_report->subevent, + tag_id, + secret_data_len, + response_buffer); + if (sc == SL_STATUS_BT_CTRL_TOO_LATE) { + app_log_warning("TAG PAWR response was too late, skipping\r\n"); + } else { + app_assert_status(sc); + } + } + } + break; + } + + case sl_bt_evt_sm_confirm_bonding_id: { + app_log_info("new bonding request\r\n"); + sl_bt_sm_bonding_confirm(evt->data.evt_sm_confirm_bonding.connection, 0x01); + break; + } + + case sl_bt_evt_sm_bonded_id: + { + app_log_info("device bonded successfully\r\n"); + break; + } + + case sl_bt_evt_sm_bonding_failed_id: + { + app_log_info("bonding failed, peer address: %2X:%2X:%2X:%2X:%2X:%2X reason 0x%2X, closing connection\r\n", + ap_address.addr[5], + ap_address.addr[4], + ap_address.addr[3], + ap_address.addr[2], + ap_address.addr[1], + ap_address.addr[0], + evt->data.evt_sm_bonding_failed.reason); + break; + } + + case sl_bt_evt_system_external_signal_id: + { + if (evt->data.evt_system_external_signal.extsignals & TAG_OUT_OF_SYNC_SIGNAL) { + if (pawr_handle == SL_BT_INVALID_SYNC_HANDLE && connection == SL_BT_INVALID_CONNECTION_HANDLE && !advertising_active) { + sc = sl_bt_extended_advertiser_generate_data(advertising_set_handle, + sl_bt_advertiser_general_discoverable); + app_assert_status(sc); + sc = sl_bt_extended_advertiser_start(advertising_set_handle, + sl_bt_extended_advertiser_connectable, 0x00); + app_assert_status(sc); + advertising_active = true; + app_log_info("sync lost, restarting provisioning advertisement\r\n"); + } + } + } + break; + + default: + { + // app_log_info("untracked event id %08lX\r\n",(unsigned long)SL_BT_MSG_ID(evt->header)); + break; + } + } +} + +sl_status_t extract_and_decrypt(sl_bt_evt_pawr_sync_subevent_report_t *sync_report, + sl_bt_ead_key_material_p key_material, + sl_bt_ead_nonce_p nonce) +{ + sl_status_t sc = SL_STATUS_FAIL; + uint8_t ad_len; + uint8_t ad_type; + uint8_t i = 0; + struct sl_bt_ead_ad_structure_s advertisement_info; + sl_bt_ead_randomizer_t randomizer; + uint8_t encrypted_data_buffer[30]; + sl_bt_ead_mic_t mic; + + app_log("Decrypting\r\n"); + + advertisement_info.length = sizeof(encrypted_data_buffer); + advertisement_info.randomizer = &randomizer; + advertisement_info.ad_data = encrypted_data_buffer; + advertisement_info.mic = &mic; + + while (i < sync_report->data.len) { + ad_len = sync_report->data.data[i]; + ad_type = sync_report->data.data[i + 1]; + if (ad_type == SL_BT_ENCRYPTED_DATA_AD_TYPE) { + app_log("Subevent information encrypted:\r\n"); + for (uint8_t j = 0; j < ad_len + 1; j++) { + app_log("%02X", sync_report->data.data[i + j]); + } + sc = sl_bt_ead_unpack_ad_data(&sync_report->data.data[i], &advertisement_info); + if (sc != 0) { + app_log("unpacking unsuccessful with rc %08lX\r\n", sc); + } + memcpy(nonce->randomizer, advertisement_info.randomizer, SL_BT_EAD_RANDOMIZER_SIZE); + sc = sl_bt_ead_decrypt(key_material, nonce, (uint8_t *)advertisement_info.mic, advertisement_info.length, advertisement_info.ad_data); + if (sc != 0) { + app_log("decrypting unsuccessful with rc %08lX\r\n", sc); + } else { + app_log("\r\nSubevent information decrypted:"); + for (uint8_t i = 2; i < advertisement_info.length; i++) { + app_log("%c", advertisement_info.ad_data[i]); + } + app_log("\r\n"); + } + } + i = i + ad_len + 1; + } + return sc; +} + +sl_status_t construct_response_payload(sl_bt_ead_key_material_p key_material, + sl_bt_ead_nonce_p nonce, + uint8_t *response_payload, + uint8_t *response_payload_len) +{ + sl_status_t sc; + uint8_t plaintext[RESPONSE_PLAINTEXT_MAX_LEN]; + uint8_t packed_len = BLE_EA_RSP_DATA_LEN; + size_t plaintext_len; + sl_bt_ead_mic_t mic; + struct sl_bt_ead_ad_structure_s encrypted_ad_structure; + + snprintf((char *)plaintext, + sizeof(plaintext), + "secret%02d", + secret_number); + + plaintext_len = strlen((char *)plaintext); + + app_log("Response Information before encryption: %s\r\n", + plaintext); + + sc = sl_bt_ead_encrypt(key_material, + nonce, + plaintext_len, + plaintext, + mic); + app_assert_status(sc); + + encrypted_ad_structure.length = plaintext_len; + encrypted_ad_structure.ad_type = SL_BT_ENCRYPTED_DATA_AD_TYPE; + encrypted_ad_structure.ad_data = plaintext; + encrypted_ad_structure.randomizer = &(nonce->randomizer); + encrypted_ad_structure.mic = &mic; + + sc = sl_bt_ead_pack_ad_data(&encrypted_ad_structure, + &packed_len, + response_payload); + app_assert_status(sc); + + *response_payload_len = packed_len; + + app_log("Response Information after encryption:\r\n"); + for (uint8_t i = 0; i < packed_len; i++) { + app_log("%02X", response_payload[i]); + } + app_log("\r\n"); + + return SL_STATUS_OK; +} + +static void out_of_sync_cb(sl_sleeptimer_timer_handle_t *handle, void *data) +{ + (void)handle; + (void)data; + sl_bt_external_signal(TAG_OUT_OF_SYNC_SIGNAL); +} diff --git a/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/main.c b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/main.c new file mode 100644 index 0000000..72c8be4 --- /dev/null +++ b/advertising/periodic_advertisement_with_responses/encrypted_pawr/src/tag/main.c @@ -0,0 +1,71 @@ +/***************************************************************************//** + * @file main.c + * @brief main() function. + ******************************************************************************* + * # License + * Copyright 2025 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * 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. + * + ******************************************************************************/ +#include "sl_component_catalog.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_main_kernel.h" +#else // SL_CATALOG_KERNEL_PRESENT +#include "sl_main_process_action.h" +#endif // SL_CATALOG_KERNEL_PRESENT + +int main(void) +{ + // Initialize Silicon Labs device, system, service(s) and protocol stack(s). + // Note that if the kernel is present, the start task will be started and software + // component initialization will take place there. + sl_main_init(); + +#if defined(SL_CATALOG_KERNEL_PRESENT) + // 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) { + // Silicon Labs components process action routine + // must be called from the super loop. + sl_main_process_action(); + + // User provided code. Application process. + app_process_action(); + +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) + // Let the CPU go to sleep if the system allows it. + sl_power_manager_sleep(); +#endif + } +#endif // SL_CATALOG_KERNEL_PRESENT +} diff --git a/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/readme.md b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/readme.md index fada19f..06de136 100644 --- a/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/readme.md +++ b/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/SimplicityStudio/readme.md @@ -1,6 +1,6 @@ # Periodic Advertisement Example -The readme file of this project can be found [here](https://github.com/SiliconLabs/bluetooth_stack_features/blob/master/advertising/periodic_advertisement_with_responses/README.md). +The readme file of this project can be found [here](https://github.com/SiliconLabs/bluetooth_stack_features/blob/master/advertising/periodic_advertisement_with_responses/pawr_sync_transfer/README.md). . > Note: In this project all the necessary software components are installed, source files are copied, and configurations are set, hence you can disregard the Setting Up section of the online readme file. Nevertheless, if you want to add the demonstrated feature to your own project, it might be good to know what software components you must install, and what configurations you must set beforehand, hence reading through the Setting Up section might be useful. diff --git a/bluetooth_stack_features_app_templates.xml b/bluetooth_stack_features_app_templates.xml index d745606..88d4d36 100644 --- a/bluetooth_stack_features_app_templates.xml +++ b/bluetooth_stack_features_app_templates.xml @@ -481,6 +481,30 @@ + + + + + + + + + + + + + + + + + + + + + + + +