diff --git a/.github/workflows/examples-k32w.yaml b/.github/workflows/examples-k32w.yaml index f71f3f26f1ae61..d5d31eddbdaba0 100644 --- a/.github/workflows/examples-k32w.yaml +++ b/.github/workflows/examples-k32w.yaml @@ -40,7 +40,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-k32w:0.7.3 + image: connectedhomeip/chip-build-k32w:0.7.14 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/docs/guides/nxp_manufacturing_flow.md b/docs/guides/nxp_manufacturing_flow.md index 019cfa67a38680..141f90c8b8b57c 100644 --- a/docs/guides/nxp_manufacturing_flow.md +++ b/docs/guides/nxp_manufacturing_flow.md @@ -6,141 +6,193 @@ orphan: true By default, the example application is configured to use generic test certificates and provisioning data embedded with the application code. It is -possible for a final stage application to generate its own manufacturing data: - -- Generate new certificates - - _PAI_VID_ and _PAI_PID_ variables must be changed accordingly inside - generate_cert.sh script - - _generate_cert.sh_ script needs as input parameter the path to chip-cert - tool (compile it from ./src/tools/chip-cert). The output of the script is: - the DAC, PAI and PAA certificates. The DAC and PAI certificates will be - written in a special section of the internal flash, while the PAA will be - used on the chip-tool side as trust anchor. Please note that for _real - production manufacturing_ the "production PAA" is trusted via the DCL rather - than thorough PAA certificate generated along with DAC and PAI. The PAI cert - may also have a different lifecycle. - - ``` - user@ubuntu:~/Desktop/git/connectedhomeip$ ./examples/platform/nxp/k32w/k32w0/scripts/generate_cert.sh ./src/tools/chip-cert/out/chip-cert - ``` - -- Generate new provisioning data and convert all the data to a binary - (unencrypted data): - - ``` - user@ubuntu:~/Desktop/git/connectedhomeip$ python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid 0x1037 --pid 0xa220 --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "SN:12345678" --date "2022-10-21" --hw_version 1 --hw_version_str "1.0" --cert_declaration /home/ubuntu/manufacturing/Chip-Test-CD-1037-a220.der --dac_cert /home/ubuntu/manufacturing/Chip-DAC-NXP-Cert.der --dac_key /home/ubuntu/manufacturing/Chip-DAC-NXP-Key.der --pai_cert /home/ubuntu/manufacturing/Chip-PAI-NXP-Cert.der --spake2p_path ./src/tools/spake2p/out/spake2p --out out.bin - ``` - -- Same example as above, but with an already generated verifier passed as - input: - - ``` - user@ubuntu:~/Desktop/git/connectedhomeip$ python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid 0x1037 --pid 0xa220 --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "SN:12345678" --date "2022-10-21" --hw_version 1 --hw_version_str "1.0" --cert_declaration /home/ubuntu/manufacturing/Chip-Test-CD-1037-a220.der --dac_cert /home/ubuntu/manufacturing/Chip-DAC-NXP-Cert.der --dac_key /home/ubuntu/manufacturing/Chip-DAC-NXP-Key.der --pai_cert /home/ubuntu/manufacturing/Chip-PAI-NXP-Cert.der --spake2p_path ./src/tools/spake2p/out/spake2p --spake2p_verifier ivD5n3L2t5+zeFt6SjW7BhHRF30gFXWZVvvXgDxgCNcE+BGuTA5AUaVm3qDZBcMMKn1a6CakI4SxyPUnJr0CpJ4pwpr0DvpTlkQKqaRvkOQfAQ1XDyf55DuavM5KVGdDrg== --out out.bin - ``` +possible for a final stage application to generate its own manufacturing data +using the procedure described below. -- Generate new provisioning data and convert all the data to a binary - (encrypted data with the AES key): +## 1. Prerequisites - ``` - user@ubuntu:~/Desktop/git/connectedhomeip$ python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid 0x1037 --pid 0xa220 --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "SN:12345678" --date "2022-10-21" --hw_version 1 --hw_version_str "1.0" --cert_declaration /home/ubuntu/manufacturing/Chip-Test-CD-1037-a220.der --dac_cert /home/ubuntu/manufacturing/Chip-DAC-NXP-Cert.der --dac_key /home/ubuntu/manufacturing/Chip-DAC-NXP-Key.der --pai_cert /home/ubuntu/manufacturing/Chip-PAI-NXP-Cert.der --spake2p_path ./src/tools/spake2p/out/spake2p --out outEncrypted.bin --aes128_key 2B7E151628AED2A6ABF7158809CF4F3C - ``` +Build `chip-cert` tool: - Here is the interpretation of the parameters: +``` +cd src/tools/chip-cert +gn gen out +ninja -C out +``` - ``` - -i -> SPAKE2+ iteration - -s -> SPAKE2+ salt (passed as base64 encoded string) - -p -> SPAKE2+ passcode - -d -> discriminator - --vid -> Vendor ID - --pid -> Product ID - --vendor_name -> Vendor Name - --product_name -> Product Name - --serial_num -> Serial Number - --date -> Manufacturing Date (YYYY-MM-DD format) - --hw_version -> Hardware Version as number - --hw_version_str -> Hardware Version as string - --cert_declaration -> path to the Certification Declaration (der format) location - --dac_cert -> path to the DAC (der format) location - --dac_key -> path to the DAC key (der format) location - --pai_cert -> path to the PAI (der format) location - --spake2p_path -> path to the spake2p tool (compile it from ./src/tools/spake2p) - --out -> name of the binary that will be used for storing all the generated data - --aes128_key -> 128 bits AES key used to encrypt the whole dataset - --spake2p_verifier -> SPAKE2+ verifier (passed as base64 encoded string). If this option is set, - all SPAKE2+ inputs will be encoded in the final binary. The spake2p tool - will not be used to generate a new verifier on the fly. - ``` +Build `spake2p` tool: -- Write out.bin to the \$platform: +``` +cd src/tool/spake2p +gn gen out +ninja -C out +``` + +### Environment variables + +A user can customize the certificate generation by setting some environment +variables that are used within the utility scripts. Please note that the values +below are just an example and should be modified accordingly: - For the K32W0x1 platform, the binary needs to be written in the internal - flash at location 0x9D600 using DK6Programmer: +``` +export FACTORY_DATA_DEST=path/factory/data/dest +export DEVICE_TYPE=100 +export DATE=$(date +"%F") +export TIME=$(date +"%T") +export LIFETIME="7305" +export VID="1037" +export PID="A220" +``` + +`FACTORY_DATA_DEST` is the path where all factory related data is generated. + +`DEVICE_TYPE` should be updated according to the application device type (0x0100 +for the provided K32W0 lighting app). + +Additionally, `PAA_CERT` and `PAA_KEY` paths can be specified to use an already +existent **PAA**: + +``` +export PAA_CERT=path/certs/Chip-PAA-NXP-Cert.pem +export PAA_KEY=path/certs/Chip-PAA-NXP-Key.pem +``` + +## 2. Generate + +### a. Certificates + +``` +./scripts/tools/nxp/generate_cert.sh ./src/tools/chip-cert/out/chip-cert +``` + +The output of the script is the **DAC**, **PAI** and **PAA** certificates. If +`FACTORY_DATA_DEST` is set, the certificates will be moved there. The **DAC** +and **PAI** certificates will be written in a special section of the internal +flash, while the **PAA** will be used by `chip-tool` as trust anchor. Please +note that for _real production manufacturing_ the "production PAA" is trusted +via the **DCL** rather than through the generated **PAA** certificate. The +**PAI** certificate may also have a different lifecycle. - ``` - DK6Programmer.exe -Y -V2 -s -P 1000000 -Y -p FLASH@0x9D600="out.bin" - ``` +### b. Certification declaration (CD) -- Generate a new CD (certification declaration): +``` +./src/tools/chip-cert/out/chip-cert gen-cd --key ./credentials/test/certification-declaration/Chip-Test-CD-Signing-Key.pem --cert ./credentials/test/certification-declaration/Chip-Test-CD-Signing-Cert.pem --out $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --format-version 1 --vendor-id "0x$VID" --product-id "0x$PID" --device-type-id "0x$DEVICE_TYPE" --certificate-id "ZIG20142ZB330003-24" --security-level 0 --security-info 0 --version-number 9876 --certification-type 1 +``` - Inside _gen-test-cds.sh_, the parameters _vids_, _pid0_, _device_type_id_ - must be changed accordingly. Use _Chip-Test-CD-Signing-\*_ key and - certificate already available in - _./credentials/test/certification-declaration/_ which acts as CSA - Certificate. This CSA certificate is also hard-coded as Trust Anchor in the - current chip-tool version. To use this certificate and avoid generating a - new one, lines 69-70 must be commented in the _gen-test-cds.sh_ script (the - ones that are generating a new CD signing authority). +The command above is extracted from `./credentials/test/gen-test-cds.sh` script. +The CD generation uses predefined key and certificate found in +`./credentials/test/certification-declaration`. This **CSA** certificate is also +hard-coded as Trust Anchor in the current `chip-tool` version. - ``` - user@ubuntu:~/Desktop/git/connectedhomeip$ ./credentials/test/gen-test-cds.sh ./src/tools/chip-cert/out/chip-cert - ``` +By default, the CD is added to the factory data section. In order to have it +integrated in the application binary, set +`CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION` to 1 in the application's +CHIPProjectConfig.h file. -- Set the correct VID/PID and CD in the - examples/$APP_NAME/nxp/$platform/ChipProjectConfig.h file VID and PID values - should correspond to the ones used for DAC. CD bytes should be the ones - obtained at the step above: +### c. Provisioning data - ``` - user@ubuntu:~/manufacturing hexdump -ve '1/1 "0x%.2x, "' Chip-Test-CD-1037-A220.der - ``` +Generate new provisioning data and convert all the data to a binary (unencrypted +data): -- Use _chip_with_factory_data=1_ gn compilation argument +``` +python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid "0x$VID" --pid "0x$PID" --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "12345678" --date "$DATE" --hw_version 1 --hw_version_str "1.0" --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --dac_cert $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Cert.der --dac_key $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Key.der --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der --spake2p_path ./src/tools/spake2p/out/spake2p --unique_id "00112233445566778899aabbccddeeff" --out $FACTORY_DATA_DEST/factory_data.bin +``` - This is needed in order to load the data from the special flash section. - Build and flash the application. +Same example as above, but with an already generated verifier passed as input: -- Run chip-tool with a new PAA: +``` +python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid "0x$VID" --pid "0x$PID" --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "12345678" --date "$DATE" --hw_version 1 --hw_version_str "1.0" --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --dac_cert $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Cert.der --dac_key $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Key.der --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der --spake2p_path ./src/tools/spake2p/out/spake2p --spake2p_verifier ivD5n3L2t5+zeFt6SjW7BhHRF30gFXWZVvvXgDxgCNcE+BGuTA5AUaVm3qDZBcMMKn1a6CakI4SxyPUnJr0CpJ4pwpr0DvpTlkQKqaRvkOQfAQ1XDyf55DuavM5KVGdDrg== --unique_id "00112233445566778899aabbccddeeff" --out $FACTORY_DATA_DEST/factory_data.bin +``` - ``` - ./chip-tool pairing ble-thread 2 hex: $hex_value 14014 1000 --paa-trust-store-path /home/ubuntu/certs/paa - ``` +Generate new provisioning data and convert all the data to a binary (encrypted +data with the AES key). Add the following option to one of the above examples: - Here is the interpretation of the parameters: +``` +--aes128_key 2B7E151628AED2A6ABF7158809CF4F3C +``` - ``` - --paa-trust-store-path -> path to the generated PAA (der format) - ``` +Here is the interpretation of the **required** parameters: - _paa-trust-store-path_ must contain only the PAA certificate. Avoid placing - other certificates in the same location as this may confuse chip-tool. +``` +-i -> SPAKE2+ iteration +-s -> SPAKE2+ salt (passed as base64 encoded string) +-p -> SPAKE2+ passcode +-d -> discriminator +--vid -> Vendor ID +--pid -> Product ID +--vendor_name -> Vendor Name +--product_name -> Product Name +--hw_version -> Hardware Version as number +--hw_version_str -> Hardware Version as string +--cert_declaration -> path to the Certification Declaration (der format) location +--dac_cert -> path to the DAC (der format) location +--dac_key -> path to the DAC key (der format) location +--pai_cert -> path to the PAI (der format) location +--spake2p_path -> path to the spake2p tool (compile it from ./src/tools/spake2p) +--out -> name of the binary that will be used for storing all the generated data - PAA certificate can be copied to the chip-tool machine using SCP for - example. - This is needed for testing self-generated DACs, but likely not required for - "true production" with production PAI issued DACs. +``` -- Useful information/Known issues +Here is the interpretation of the **optional** parameters: - Implementation of manufacturing data provisioning has been validated using test certificates generated by OpenSSL 1.1.1l. +``` +--dac_key_password -> Password to decode DAC key +--spake2p_verifier -> SPAKE2+ verifier (passed as base64 encoded string). If this option is set, + all SPAKE2+ inputs will be encoded in the final binary. The spake2p tool + will not be used to generate a new verifier on the fly. +--aes128_key -> 128 bits AES key used to encrypt the whole dataset +--date -> Manufacturing Date (YYYY-MM-DD format) +--part_number -> Part number as string +--product_url -> Product URL as string +--product_label -> Product label as string +--serial_num -> Serial Number +--unique_id -> Unique id used for rotating device id generation +``` - Also, demo DAC, PAI and PAA certificates needed in case _chip_with_factory_data=1_ is used can be found in examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs. +## 3. Write provisioning data - dut1/dut2 folders contains different DACs/Private Keys and can be used for testing topologies with 2 DUTS. +For the **K32W0x1** variants, the binary needs to be written in the internal +flash at location **0x9D600** using `DK6Programmer.exe`: - out_dut1.bin/out2_dut2.bin contains the corresponding DACs/PAIs generated using generate_nxp_chip_factory_bin.py script. The discriminator is 14014 and the passcode is 1000. +``` +DK6Programmer.exe -Y -V2 -s -P 1000000 -Y -p FLASH@0x9D600="factory_data.bin" +``` - These demo certificates are working with the CDs installed in CHIPProjectConfig.h. +For the **RT1060**, **RT1170** and **RW61X** platform, the binary needs to be +written using `MCUXpresso Flash Tool GUI` at the address value corresponding to +`__FACTORY_DATA_START` (the map file of the application should be checked to get +the exact value). + +## 4. Build app and usage + +Use `chip_with_factory_data=1` when compiling to enable factory data usage. + +Run chip-tool with a new PAA: + +``` +./chip-tool pairing ble-thread 2 hex: $hex_value 14014 1000 --paa-trust-store-path /home/ubuntu/certs/paa +``` + +Here is the interpretation of the parameters: + +``` +--paa-trust-store-path -> path to the generated PAA (der format) +``` + +`paa-trust-store-path` must contain only the PAA certificate. Avoid placing +other certificates in the same location as this may confuse `chip-tool`. + +**PAA** certificate can be copied to the chip-tool machine using **SCP** for +example. + +This is needed for testing self-generated **DACs**, but likely not required for +"true production" with production **PAI** issued **DACs**. + +## 5. Useful information/Known issues + +Implementation of manufacturing data provisioning has been validated using test +certificates generated by `OpenSSL 1.1.1l`. + +Also, demo **DAC**, **PAI** and **PAA** certificates needed in case +`chip_with_factory_data=1` is used can be found in +`./scripts/tools/nxp/demo_generated_certs`. diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn b/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn index 0087777552cdce..fc64f7de9c8e66 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn @@ -167,12 +167,22 @@ if (chip_pw_tokenizer_logging) { } group("k32w0") { - deps = [ ":contact_sensor_app" ] + deps = [ + ":binsign", + ":contact_sensor_app", + ] if (chip_pw_tokenizer_logging) { deps += [ ":contact_sensor_app.database" ] } } +action("binsign") { + deps = [ ":contact_sensor_app" ] + script = "${k32w0_platform_dir}/scripts/sign-outdir.py" + output_name = "bignsign.log" + outputs = [ "${root_build_dir}/${output_name}" ] +} + group("default") { deps = [ ":k32w0" ] } diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/README.md b/examples/contact-sensor-app/nxp/k32w/k32w0/README.md index 54854b41613622..bfbf287e113d6c 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/README.md +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/README.md @@ -177,20 +177,19 @@ In order to build the Project CHIP example, we recommend using a Linux distribution (the demo-application was compiled on Ubuntu 20.04). - Download - [K32W061DK6 SDK 2.6.10](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_10_K32W061DK6.zip). + [K32W061DK6 SDK 2.6.11](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_11_K32W061DK6.zip). - Start building the application either with Secure Element or without - without Secure Element ``` - user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W0_SDK_ROOT=/home/user/Desktop/SDK_2_6_10_K32W061DK6/ + user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W0_SDK_ROOT=/home/user/Desktop/SDK_2_6_11_K32W061DK6/ user@ubuntu:~/Desktop/git/connectedhomeip$ ./third_party/nxp/k32w0_sdk/sdk_fixes/patch_k32w_sdk.sh user@ubuntu:~/Desktop/git/connectedhomeip$ source ./scripts/activate.sh user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/contact-sensor-app/nxp/k32w/k32w0 user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w/k32w0$ gn gen out/debug --args="k32w0_sdk_root=\"${NXP_K32W0_SDK_ROOT}\" chip_with_OM15082=1 chip_with_ot_cli=0 is_debug=false chip_crypto=\"platform\" chip_with_se05x=0 chip_pw_tokenizer_logging=true" user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w/k32w0$ ninja -C out/debug - user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w/k32w0$ $NXP_K32W0_SDK_ROOT/tools/imagetool/sign_images.sh out/debug/ ``` - with Secure element Exactly the same steps as above but set @@ -204,7 +203,7 @@ Secure Element. These can be changed if building without Secure Element Exactly the same steps as above but set argument build_for_k32w041am=1 in the gn command and use - [K32W041AMDK6 SDK 2.6.10](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_10_K32W041AMDK6.zip). + [K32W041AMDK6 SDK 2.6.11](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_11_K32W041AMDK6.zip). Also, in case the OM15082 Expansion Board is not attached to the DK6 board, the build argument (chip_with_OM15082) inside the gn build instruction should be set @@ -218,8 +217,8 @@ running oscillator as a clock source. In this case one must set the use_fro_32k argument to 1. In case signing errors are encountered when running the "sign_images.sh" script -install the recommanded packages (python version > 3, pip3, pycrypto, -pycryptodome): +(run automatically) install the recommanded packages (python version > 3, pip3, +pycrypto, pycryptodome): ``` user@ubuntu:~$ python3 --version @@ -238,6 +237,21 @@ The resulting output file can be found in out/debug/chip-k32w0x-contact-example. - When using Secure element and cross-compiling on Linux, log messages from the Plug&Trust middleware stack may not echo to the console. +## Rotating device id + +This is an optional feature and can be used in multiple ways (please see section +5.4.2.4.5 from Matter specification). One use case is Amazon Frustration Free +Setup, which leverages the C3 Characteristic (Additional commissioning-related +data) to offer an easier way to set up the device. The rotating device id will +be encoded in this additional data and is programmed to rotate at pre-defined +moments. The algorithm uses a unique per-device identifier that must be +programmed during factory provisioning. + +Please use the following build args: + +- `chip_enable_rotating_device_id=1` - to enable rotating device id. +- `chip_enable_additional_data_advertising=1` - to enable C3 characteristic. + ## Manufacturing data See @@ -375,18 +389,34 @@ application. ### Writing the SSBL -The SSBL can ge generated from one of the SDK demo examples. The SDK demo -example needs to be compiled inside MCUXpresso with the define _PDM_EXT_FLASH_. -The SSBL demo application can be imported from the _Quickstart panel_: _Import -SDK example(s)_ -> select _wireless->framework->ssbl_ application. +The SDK already provides an SSBL binary compiled with external flash support: +`boards/k32w061dk6/wireless_examples/framework/ssbl/binary/ssbl_ext_flash_pdm_support.bin`, +but it does not offer multi-image OTA support. + +Alternatively, the SSBL can ge generated from one of the SDK demo examples. The +SSBL demo application can be imported from the `Quickstart panel`: +`Import SDK example(s) -> select wireless -> framework -> ssbl` application. ![SSBL Application Select](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG) -The SSBL project must be compiled using the PDM_EXT_FLASH define. +To support multi-image OTA feature, the SSBL project must be compiled using the +following defines: -![PDM_EXT_FLASH](../../../../platform/nxp/k32w/k32w0/doc/images/pdm_ext_flash.JPG) +- `PDM_EXT_FLASH=1` - support PDM in external flash. +- `gOTAUseCustomOtaEntry=1` - support custom OTA entry for multi-image. +- `gOTACustomOtaEntryMemory=OTACustomStorage_ExtFlash` - K32W0 uses + `OTACustomStorage_ExtFlash` (1) by default. +- `SPIFI_DUAL_MODE_SUPPORT=1` - only for configurations that use dual `SPIFI` + flash (e.g. K32W041AM variant). -Once compiled, the required ssbl file is called k32w061dk6_ssbl.bin +Optionally, add the following defines: + +- `SPIFI_OPTIM_SIZE=1` - to optimize SSBL size. +- `EXTERNAL_FLASH_DATA_OTA=1` - to support external read only data. + +![SSBL_MULTI_IMAGE](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG) + +Once compiled, the required SSBL file is called `k32w061dk6_ssbl.bin`. ![SSBL_BIN](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG) @@ -396,7 +426,7 @@ Before writing the SSBL, it it recommanded to fully erase the internal flash: DK6Programmer.exe -V 5 -P 1000000 -s -e Flash ``` -k32w061dk6_ssbl.bin must be written at address 0 in the internal flash: +`k32w061dk6_ssbl.bin` must be written at address 0 in the internal flash: ``` DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x00="k32w061dk6_ssbl.bin" @@ -404,7 +434,46 @@ DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x00="k32w061dk6_ssbl ### Writing the PSECT -First, image directory 0 must be written: +This is the list of all supported partitions: + +``` +0000000010000000 : SSBL partition + + 00000000 -----------> Start Address + 1000 ---------------> 0x0010 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + 00 -----------------> 0x00 Image type (0x00 = SSBL) + +004000000f020101: Application partition + + 00400000 -----------> 0x00004000 Start Address + 0f02 ---------------> 0x020f Number of 512-bytes pages + 01 -----------------> 0x01 Bootable flag + 01 -----------------> 0x01 Image type (0x01 = Application) + +00000010800000fe: Ext Flash text partition + + 00000010 -----------> 0x10000000 Start Address (external flash) + 8000 ---------------> 0x0080 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fe -----------------> 0xFE Image type (0xFE = Ext Flash text) + +00000110300200fc : OTA Image partition + + 00000110 -----------> 0x10010000 Start Address + 3002----------------> 0x0230 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fc -----------------> 0xFC Image type (0xFC = OTA partition) + +00000510100000fd: NVM partition + + 00000510 -----------> 0x10050000 Start Address + 1000 ---------------> 0x0010 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fd -----------------> 0xFD Image type (0xFD = NVM partition) +``` + +First, image directory 0 (SSBL partition) must be written: ``` DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_0=0000000010000000 @@ -419,7 +488,7 @@ Here is the interpretation of the fields: 00 -> SSBL Image Type ``` -Second, image directory 1 must be written: +Second, image directory 1 (application partition) must be written: ``` DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_1=00400000C9040101 @@ -429,11 +498,14 @@ Here is the interpretation of the fields: ``` 00400000 -> start address 0x00004000 -CD04 -> 0x4C9 pages of 512-bytes (= 612,5kB) +C904 -> 0x4C9 pages of 512-bytes (= 612.5kB) 01 -> bootable flag 01 -> image type for the application ``` +Please note the user can write additional partitions by writing +`image_dir_2/3/4` with the wanted configuration. + ### Writing the application DK6Programmer can be used for flashing the application: @@ -500,37 +572,56 @@ Build OTA image: In order to build an OTA image, use NXP wrapper over the standard tool `src/app/ota_image_tool.py`: -- `scripts/tools/nxp/factory_data_generator/ota_image_tool.py`. The tool can - be used to generate an OTA image with the following format: - `| OTA image header | TLV1 | TLV2 | ... | TLVn |` where each TLV is in the - form `|tag|length|value|` +- `scripts/tools/nxp/ota/ota_image_tool.py`. + +The tool can be used to generate an OTA image with the following format: + +``` + | OTA image header | TLV1 | TLV2 | ... | TLVn | +``` + +where each TLV is in the form `|tag|length|value|`. Note that "standard" TLV format is used. Matter TLV format is only used for -factory data TLV value. A user can enable the default processors by specifying -`chip_enable_ota_default_processors=1` in the build command. Please see more in -the [OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). +factory data TLV value. -Here is an example that generate an OTA image with factory data and app TLV: -`user@computer1:~/connectedhomeip$ : ./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 1 -vs "1.0" -da sha256 -fd --cert_declaration ~/manufacturing/Chip-Test-CD-1037-a220.der -app chip-k32w0x-contact-example.bin chip-k32w0x-contact-example.bin chip-k32w0x-contact-example.ota` +A user can select which default processors to enable: -Start the OTA Provider Application: +- `chip_enable_ota_firmware_processor=1` to enable default firmware (app/SSBL) + update processor (enabled by default). +- `chip_enable_ota_factory_data_processor=1` to enable default factory data + update processor (disabled by default). + +The address for storing the custom OTA entry can also be specified: + +- `ota_custom_entry_address="0x000C1000"` is the default value, where + `0x000C1000` is the end address of the PDM area. PDM area ends at + `0x00100000` (top of external flash) and has a size of `63 * 4096` bytes. + The user should be aware of the external flash configuration and use an + address that does not overlap with anything else. + +Please see more in the +[OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). + +Here is an example that generates an OTA image with application update TLV: ``` -user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* -user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-k32w0x-contact-example.ota +./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 42021 -vs "1.0" -da sha256 --app-input-file chip-k32w0x-contact-example.bin chip-k32w0x-contact-example.ota ``` A note regarding OTA image header version (`-vn` option). An application binary -has its own software version (given by -`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION`, which can be overwritten). For -having a correct OTA process, the OTA header version should be the same as the -binary embedded software version. A user can set a custom software version in -the gn build args by setting `chip_software_version` to the wanted version. +has its own software version, given by +`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION` (`42020` by default), which can be +overwritten. For having a correct OTA process, the OTA header version should be +the same as the binary embedded software version. A user can set a custom +software version in the gn build args by setting `chip_software_version` to the +wanted version. -Build Linux chip-tool: +Start the OTA Provider Application: ``` -user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/chip-tool out/chip-tool-app +user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-k32w0x-contact-example.ota ``` Provision the OTA provider application and assign node id _1_. Also, grant ACL diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp b/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp index 3630e581ba9954..ecd120d9020f17 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp @@ -99,6 +99,15 @@ static BDXDownloader gDownloader; constexpr uint16_t requestedOtaBlockSize = 1024; #endif +#if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA +CHIP_ERROR CustomFactoryDataRestoreMechanism(void) +{ + K32W_LOG("This is a custom factory data restore mechanism."); + + return CHIP_NO_ERROR; +} +#endif + CHIP_ERROR AppTask::StartAppTask() { CHIP_ERROR err = CHIP_NO_ERROR; @@ -114,6 +123,40 @@ CHIP_ERROR AppTask::StartAppTask() return err; } +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static void CheckOtaEntry() +{ + K32W_LOG("Current OTA_ENTRY_TOP_ADDR: 0x%x", OTA_ENTRY_TOP_ADDR); + + CustomOtaEntries_t ota_entries; + if (gOtaSuccess_c == OTA_GetCustomEntries(&ota_entries) && ota_entries.ota_state != otaNoImage) + { + if (ota_entries.ota_state == otaApplied) + { + K32W_LOG("OTA successfully applied"); +#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR + // If this point is reached, it means OTA_CommitCustomEntries was successfully called. + // Delete the factory data backup to stop doing a restore when the factory data provider + // is initialized. This ensures that both the factory data and app were updated, otherwise + // revert to the backed up factory data. + PDM_vDeleteDataRecord(kNvmId_FactoryDataBackup); +#endif + } + else + { + K32W_LOG("OTA failed with status %d", ota_entries.ota_state); + } + + // Clear the entry + OTA_ResetCustomEntries(); + } + else + { + K32W_LOG("Unable to access OTA entries structure"); + } +} +#endif + CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; @@ -129,10 +172,15 @@ CHIP_ERROR AppTask::Init() // Init ZCL Data Model and start server PlatformMgr().ScheduleWork(InitServer, 0); -// Initialize device attestation config +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + CheckOtaEntry(); +#endif + + // Initialize device attestation config #if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA // Initialize factory data provider ReturnErrorOnFailure(AppTask::FactoryDataProvider::GetDefaultInstance().Init()); + AppTask::FactoryDataProvider::GetDefaultInstance().RegisterRestoreMechanism(CustomFactoryDataRestoreMechanism); SetDeviceInstanceInfoProvider(&AppTask::FactoryDataProvider::GetDefaultInstance()); SetDeviceAttestationCredentialsProvider(&AppTask::FactoryDataProvider::GetDefaultInstance()); SetCommissionableDataProvider(&AppTask::FactoryDataProvider::GetDefaultInstance()); diff --git a/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn b/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn index 3ccf6f3df1b282..54721dad1a397d 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn +++ b/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn @@ -160,12 +160,22 @@ if (chip_pw_tokenizer_logging) { } group("k32w0") { - deps = [ ":light_app" ] + deps = [ + ":binsign", + ":light_app", + ] if (chip_pw_tokenizer_logging) { deps += [ ":light_app.database" ] } } +action("binsign") { + deps = [ ":light_app" ] + script = "${k32w0_platform_dir}/scripts/sign-outdir.py" + output_name = "bignsign.log" + outputs = [ "${root_build_dir}/${output_name}" ] +} + group("default") { deps = [ ":k32w0" ] } diff --git a/examples/lighting-app/nxp/k32w/k32w0/README.md b/examples/lighting-app/nxp/k32w/k32w0/README.md index 1bebb18a50e650..5019e8a4f612f6 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/README.md +++ b/examples/lighting-app/nxp/k32w/k32w0/README.md @@ -192,18 +192,17 @@ In order to build the Project CHIP example, we recommend using a Linux distribution (the demo-application was compiled on Ubuntu 20.04). - Download - [K32W061DK6 SDK 2.6.10](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_10_K32W061DK6.zip). + [K32W061DK6 SDK 2.6.11](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_11_K32W061DK6.zip). - Start building the application either with Secure Element or without - without Secure Element ``` -user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W0_SDK_ROOT=/home/user/Desktop/SDK_2_6_10_K32W061DK6/ +user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W0_SDK_ROOT=/home/user/Desktop/SDK_2_6_11_K32W061DK6/ user@ubuntu:~/Desktop/git/connectedhomeip$ source ./scripts/activate.sh user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/lighting-app/nxp/k32w/k32w0 user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w/k32w0$ gn gen out/debug --args="k32w0_sdk_root=\"${NXP_K32W0_SDK_ROOT}\" chip_with_OM15082=1 chip_with_ot_cli=0 is_debug=false chip_crypto=\"platform\" chip_with_se05x=0 chip_pw_tokenizer_logging=true" user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w/k32w0$ ninja -C out/debug -user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w/k32w0$ $NXP_K32W0_SDK_ROOT/tools/imagetool/sign_images.sh out/debug/ ``` - with Secure element @@ -217,7 +216,7 @@ Secure Element. These can be changed if building without Secure Element Exactly the same steps as above but set argument build_for_k32w041am=1 in the gn command and use - [K32W041AMDK6 SDK 2.6.10](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_10_K32W041AMDK6.zip). + [K32W041AMDK6 SDK 2.6.11](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_11_K32W041AMDK6.zip). Also, in case the OM15082 Expansion Board is not attached to the DK6 board, the build argument (chip_with_OM15082) inside the gn build instruction should be set @@ -231,8 +230,8 @@ running oscillator as a clock source. In this case one must set the use_fro_32k argument to 1. In case signing errors are encountered when running the "sign_images.sh" script -install the recommanded packages (python version > 3, pip3, pycrypto, -pycryptodome): +(run automatically) install the recommanded packages (python version > 3, pip3, +pycrypto, pycryptodome): ``` user@ubuntu:~$ python3 --version @@ -251,6 +250,21 @@ The resulting output file can be found in out/debug/chip-k32w0x-light-example. - When using Secure element and cross-compiling on Linux, log messages from the Plug&Trust middleware stack may not echo to the console. +## Rotating device id + +This is an optional feature and can be used in multiple ways (please see section +5.4.2.4.5 from Matter specification). One use case is Amazon Frustration Free +Setup, which leverages the C3 Characteristic (Additional commissioning-related +data) to offer an easier way to set up the device. The rotating device id will +be encoded in this additional data and is programmed to rotate at pre-defined +moments. The algorithm uses a unique per-device identifier that must be +programmed during factory provisioning. + +Please use the following build args: + +- `chip_enable_rotating_device_id=1` - to enable rotating device id. +- `chip_enable_additional_data_advertising=1` - to enable C3 characteristic. + ## Manufacturing data See @@ -388,18 +402,34 @@ application. ### Writing the SSBL -The SSBL can ge generated from one of the SDK demo examples. The SDK demo -example needs to be compiled inside MCUXpresso with the define _PDM_EXT_FLASH_. -The SSBL demo application can be imported from the _Quickstart panel_: _Import -SDK example(s)_ -> select _wireless->framework->ssbl_ application. +The SDK already provides an SSBL binary compiled with external flash support: +`boards/k32w061dk6/wireless_examples/framework/ssbl/binary/ssbl_ext_flash_pdm_support.bin`, +but it does not offer multi-image OTA support. + +Alternatively, the SSBL can ge generated from one of the SDK demo examples. The +SSBL demo application can be imported from the `Quickstart panel`: +`Import SDK example(s) -> select wireless -> framework -> ssbl` application. ![SSBL Application Select](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG) -The SSBL project must be compiled using the PDM_EXT_FLASH define. +To support multi-image OTA feature, the SSBL project must be compiled using the +following defines: -![PDM_EXT_FLASH](../../../../platform/nxp/k32w/k32w0/doc/images/pdm_ext_flash.JPG) +- `PDM_EXT_FLASH=1` - support PDM in external flash. +- `gOTAUseCustomOtaEntry=1` - support custom OTA entry for multi-image. +- `gOTACustomOtaEntryMemory=OTACustomStorage_ExtFlash` - K32W0 uses + `OTACustomStorage_ExtFlash` (1) by default. +- `SPIFI_DUAL_MODE_SUPPORT=1` - only for configurations that use dual `SPIFI` + flash (e.g. K32W041AM variant). -Once compiled, the required ssbl file is called k32w061dk6_ssbl.bin +Optionally, add the following defines: + +- `SPIFI_OPTIM_SIZE=1` - to optimize SSBL size. +- `EXTERNAL_FLASH_DATA_OTA=1` - to support external read only data. + +![SSBL_MULTI_IMAGE](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG) + +Once compiled, the required SSBL file is called `k32w061dk6_ssbl.bin`. ![SSBL_BIN](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG) @@ -409,7 +439,7 @@ Before writing the SSBL, it it recommanded to fully erase the internal flash: DK6Programmer.exe -V 5 -P 1000000 -s -e Flash ``` -k32w061dk6_ssbl.bin must be written at address 0 in the internal flash: +`k32w061dk6_ssbl.bin` must be written at address 0 in the internal flash: ``` DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x00="k32w061dk6_ssbl.bin" @@ -417,7 +447,46 @@ DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x00="k32w061dk6_ssbl ### Writing the PSECT -First, image directory 0 must be written: +This is the list of all supported partitions: + +``` +0000000010000000 : SSBL partition + + 00000000 -----------> Start Address + 1000 ---------------> 0x0010 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + 00 -----------------> 0x00 Image type (0x00 = SSBL) + +004000000f020101: Application partition + + 00400000 -----------> 0x00004000 Start Address + 0f02 ---------------> 0x020f Number of 512-bytes pages + 01 -----------------> 0x01 Bootable flag + 01 -----------------> 0x01 Image type (0x01 = Application) + +00000010800000fe: Ext Flash text partition + + 00000010 -----------> 0x10000000 Start Address (external flash) + 8000 ---------------> 0x0080 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fe -----------------> 0xFE Image type (0xFE = Ext Flash text) + +00000110300200fc : OTA Image partition + + 00000110 -----------> 0x10010000 Start Address + 3002----------------> 0x0230 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fc -----------------> 0xFC Image type (0xFC = OTA partition) + +00000510100000fd: NVM partition + + 00000510 -----------> 0x10050000 Start Address + 1000 ---------------> 0x0010 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fd -----------------> 0xFD Image type (0xFD = NVM partition) +``` + +First, image directory 0 (SSBL partition) must be written: ``` DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_0=0000000010000000 @@ -432,7 +501,7 @@ Here is the interpretation of the fields: 00 -> SSBL Image Type ``` -Second, image directory 1 must be written: +Second, image directory 1 (application partition) must be written: ``` DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_1=00400000C9040101 @@ -442,11 +511,14 @@ Here is the interpretation of the fields: ``` 00400000 -> start address 0x00004000 -CD04 -> 0x4C9 pages of 512-bytes (= 612,5kB) +C904 -> 0x4C9 pages of 512-bytes (= 612.5kB) 01 -> bootable flag 01 -> image type for the application ``` +Please note the user can write additional partitions by writing +`image_dir_2/3/4` with the wanted configuration. + ### Writing the application DK6Programmer can be used for flashing the application: @@ -513,18 +585,50 @@ Build OTA image: In order to build an OTA image, use NXP wrapper over the standard tool `src/app/ota_image_tool.py`: -- `scripts/tools/nxp/factory_data_generator/ota_image_tool.py` The tool can be - used to generate an OTA image with the following format: - `| OTA image header | TLV1 | TLV2 | ... | TLVn |` where each TLV is in the - form `|tag|length|value|` +- `scripts/tools/nxp/ota/ota_image_tool.py` + +The tool can be used to generate an OTA image with the following format: + +``` + | OTA image header | TLV1 | TLV2 | ... | TLVn | +``` + +where each TLV is in the form `|tag|length|value|`. Note that "standard" TLV format is used. Matter TLV format is only used for -factory data TLV value. A user can enable the default processors by specifying -`chip_enable_ota_default_processors=1` in the build command. Please see more in -the [OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). +factory data TLV value. + +A user can select which default processors to enable: + +- `chip_enable_ota_firmware_processor=1` to enable default firmware (app/SSBL) + update processor (enabled by default). +- `chip_enable_ota_factory_data_processor=1` to enable default factory data + update processor (disabled by default). + +The address for storing the custom OTA entry can also be specified: -Here is an example that generate an OTA image with factory data and app TLV: -`user@computer1:~/connectedhomeip$ : ./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 1 -vs "1.0" -da sha256 -fd --cert_declaration ~/manufacturing/Chip-Test-CD-1037-a220.der -app chip-k32w0x-contact-example.bin chip-k32w0x-contact-example.bin chip-k32w0x-contact-example.ota` +- `ota_custom_entry_address="0x000C1000"` is the default value, where + `0x000C1000` is the end address of the PDM area. PDM area ends at + `0x00100000` (top of external flash) and has a size of `63 * 4096` bytes. + The user should be aware of the external flash configuration and use an + address that does not overlap with anything else. + +Please see more in the +[OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). + +Here is an example that generates an OTA image with application update TLV: + +``` +./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 42021 -vs "1.0" -da sha256 --app-input-file chip-k32w0x-light-example.bin chip-k32w0x-light-example.ota +``` + +A note regarding OTA image header version (`-vn` option). An application binary +has its own software version, given by +`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION` (`42020` by default), which can be +overwritten. For having a correct OTA process, the OTA header version should be +the same as the binary embedded software version. A user can set a custom +software version in the gn build args by setting `chip_software_version` to the +wanted version. Start the OTA Provider Application: @@ -533,13 +637,6 @@ user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-k32w0x-light-example.ota ``` -A note regarding OTA image header version (`-vn` option). An application binary -has its own software version (given by -`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION`, which can be overwritten). For -having a correct OTA process, the OTA header version should be the same as the -binary embedded software version. A user can set a custom software version in -the gn build args by setting `chip_software_version` to the wanted version. - Provision the OTA provider application and assign node id _1_. Also, grant ACL entries to allow OTA requestors: diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp b/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp index 2298c42c4c395c..d2bdbe55c0d2cc 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp +++ b/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp @@ -110,6 +110,15 @@ static BDXDownloader gDownloader; constexpr uint16_t requestedOtaBlockSize = 1024; #endif +#if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA +CHIP_ERROR CustomFactoryDataRestoreMechanism(void) +{ + K32W_LOG("This is a custom factory data restore mechanism."); + + return CHIP_NO_ERROR; +} +#endif + CHIP_ERROR AppTask::StartAppTask() { CHIP_ERROR err = CHIP_NO_ERROR; @@ -125,6 +134,40 @@ CHIP_ERROR AppTask::StartAppTask() return err; } +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static void CheckOtaEntry() +{ + K32W_LOG("Current OTA_ENTRY_TOP_ADDR: 0x%x", OTA_ENTRY_TOP_ADDR); + + CustomOtaEntries_t ota_entries; + if (gOtaSuccess_c == OTA_GetCustomEntries(&ota_entries) && ota_entries.ota_state != otaNoImage) + { + if (ota_entries.ota_state == otaApplied) + { + K32W_LOG("OTA successfully applied"); +#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR + // If this point is reached, it means OTA_CommitCustomEntries was successfully called. + // Delete the factory data backup to stop doing a restore when the factory data provider + // is initialized. This ensures that both the factory data and app were updated, otherwise + // revert to the backed up factory data. + PDM_vDeleteDataRecord(kNvmId_FactoryDataBackup); +#endif + } + else + { + K32W_LOG("OTA failed with status %d", ota_entries.ota_state); + } + + // Clear the entry + OTA_ResetCustomEntries(); + } + else + { + K32W_LOG("Unable to access OTA entries structure"); + } +} +#endif + CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; @@ -134,10 +177,15 @@ CHIP_ERROR AppTask::Init() // Init ZCL Data Model and start server PlatformMgr().ScheduleWork(InitServer, 0); -// Initialize device attestation config +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + CheckOtaEntry(); +#endif + + // Initialize device attestation config #if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA // Initialize factory data provider ReturnErrorOnFailure(AppTask::FactoryDataProvider::GetDefaultInstance().Init()); + AppTask::FactoryDataProvider::GetDefaultInstance().RegisterRestoreMechanism(CustomFactoryDataRestoreMechanism); SetDeviceInstanceInfoProvider(&AppTask::FactoryDataProvider::GetDefaultInstance()); SetDeviceAttestationCredentialsProvider(&AppTask::FactoryDataProvider::GetDefaultInstance()); SetCommissionableDataProvider(&AppTask::FactoryDataProvider::GetDefaultInstance()); diff --git a/examples/lock-app/nxp/k32w/k32w0/BUILD.gn b/examples/lock-app/nxp/k32w/k32w0/BUILD.gn index 70753788008300..7a18fc3eb14396 100644 --- a/examples/lock-app/nxp/k32w/k32w0/BUILD.gn +++ b/examples/lock-app/nxp/k32w/k32w0/BUILD.gn @@ -150,12 +150,22 @@ if (chip_pw_tokenizer_logging) { } } group("k32w0") { - deps = [ ":lock_app" ] + deps = [ + ":binsign", + ":lock_app", + ] if (chip_pw_tokenizer_logging) { deps += [ ":lock_app.database" ] } } +action("binsign") { + deps = [ ":lock_app" ] + script = "${k32w0_platform_dir}/scripts/sign-outdir.py" + output_name = "bignsign.log" + outputs = [ "${root_build_dir}/${output_name}" ] +} + group("default") { deps = [ ":k32w0" ] } diff --git a/examples/lock-app/nxp/k32w/k32w0/README.md b/examples/lock-app/nxp/k32w/k32w0/README.md index 3a2f027e447ab8..26ccf8fe663a11 100644 --- a/examples/lock-app/nxp/k32w/k32w0/README.md +++ b/examples/lock-app/nxp/k32w/k32w0/README.md @@ -173,20 +173,19 @@ In order to build the Project CHIP example, we recommend using a Linux distribution (the demo-application was compiled on Ubuntu 20.04). - Download - [K32W061DK6 SDK 2.6.10](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_10_K32W061DK6.zip). + [K32W061DK6 SDK 2.6.11](https://cache.nxp.com/lgfiles/bsps/SDK_2_6_11_K32W061DK6.zip). - Start building the application either with Secure Element or without - without Secure Element ``` -user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W0_SDK_ROOT=/home/user/Desktop/SDK_2_6_10_K32W061DK6/ +user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W0_SDK_ROOT=/home/user/Desktop/SDK_2_6_11_K32W061DK6/ user@ubuntu:~/Desktop/git/connectedhomeip$ ./third_party/nxp/k32w0_sdk/sdk_fixes/patch_k32w_sdk.sh user@ubuntu:~/Desktop/git/connectedhomeip$ source ./scripts/activate.sh user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/lock-app/nxp/k32w/k32w0 user@ubuntu:~/Desktop/git/connectedhomeip/examples/lock-app/nxp/k32w/k32w0$ gn gen out/debug --args="k32w0_sdk_root=\"${NXP_K32W0_SDK_ROOT}\" chip_with_OM15082=1 chip_with_ot_cli=0 is_debug=false chip_crypto=\"platform\" chip_with_se05x=0 chip_pw_tokenizer_logging=true" user@ubuntu:~/Desktop/git/connectedhomeip/examples/lock-app/nxp/k32w/k32w0$ ninja -C out/debug -user@ubuntu:~/Desktop/git/connectedhomeip/examples/lock-app/nxp/k32w/k32w0$ $NXP_K32W0_SDK_ROOT/tools/imagetool/sign_images.sh out/debug/ ``` - with Secure element @@ -204,8 +203,8 @@ running oscillator as a clock source. In this case one must set the use_fro_32k argument to 1. In case signing errors are encountered when running the "sign_images.sh" script -install the recommanded packages (python version > 3, pip3, pycrypto, -pycryptodome): +(run automatically) install the recommanded packages (python version > 3, pip3, +pycrypto, pycryptodome): ``` user@ubuntu:~$ python3 --version @@ -224,6 +223,21 @@ The resulting output file can be found in out/debug/chip-k32w0x-lock-example. - When using Secure element and cross-compiling on Linux, log messages from the Plug&Trust middleware stack may not echo to the console. +## Rotating device id + +This is an optional feature and can be used in multiple ways (please see section +5.4.2.4.5 from Matter specification). One use case is Amazon Frustration Free +Setup, which leverages the C3 Characteristic (Additional commissioning-related +data) to offer an easier way to set up the device. The rotating device id will +be encoded in this additional data and is programmed to rotate at pre-defined +moments. The algorithm uses a unique per-device identifier that must be +programmed during factory provisioning. + +Please use the following build args: + +- `chip_enable_rotating_device_id=1` - to enable rotating device id. +- `chip_enable_additional_data_advertising=1` - to enable C3 characteristic. + ## Manufacturing data See diff --git a/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld b/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld index 82580235b3bdda..c7a2e4009865e5 100644 --- a/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld +++ b/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld @@ -31,6 +31,61 @@ * GCC linker script for K32W061/K32W041. */ +/******************* Map of K32W0 internal flash *********************************** + + 0x000A_0000 + - - - +---------------+ - - - - - - - - + | | + 8.5K | Flash config | + | RESERVED | 0x0009_DE00 + - - - +---------------+ - - - - - - - - + | | + 2K | Factory data | + | | 0x0009_D600 + - - - +---------------+ - - - - - - - - + | | + 1K | App metadata | + | | 0x0009_D200 + - - - +---------------+ - - - - - - - - + | | + 612.5K | Application | + | | 0x0000_4000 + - - - +---------------+ - - - - - - - - + | | + 8K | SSBL update | + | | 0x0000_2000 + - - - +---------------+ - - - - - - - - + | | + 8K | SSBL | + | | 0x0000_0000 + - - - +---------------+ - - - - - - - - + 0x0000_0000 + +* - If OTA is disabled, SSBL and SSBL updated region are not present. + - The only address range that changes is the application, which will span from + 0x0000_0000 to 0x0009_D200, having 628.5K max size. + *****************************************************************************/ + +/******************* Map of DK6 external flash *********************************** + + 0x0010_0000 + - - - +---------------+ - - - - - - - - + | | + 252K | PDM area | + | | 0x000C_1000 + - - - +---------------+ - - - - - - - - + | | + 4K | OTA entry | + | | 0x000C_0000 + - - - +---------------+ - - - - - - - - + | | + 768K | OTA area | + | | + - - - +---------------+ - - - - - - - - + 0x0000_0000 + + *****************************************************************************/ + OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") /* @@ -81,10 +136,11 @@ MEMORY } /* Define a symbol for the top of each memory region */ -__top_RAM1 = MEM_RAM1_BASE + MEM_RAM1_SIZE; /* 64K bytes */ +__top_RAM1 = MEM_RAM1_BASE + MEM_RAM1_SIZE; /* 64K bytes */ -/* To be improved. At this moment the second RAM bank is dedicated entirely to heap + stack. */ -HEAP_SIZE = DEFINED(HEAP_SIZE) ? HEAP_SIZE : 0x10000; +/* The second RAM bank is dedicated entirely to heap + stack. */ +HEAP_SIZE = MEM_RAM1_SIZE - STACK_SIZE; +ASSERT(((HEAP_SIZE + STACK_SIZE) == MEM_RAM1_SIZE), "Heap size + stack size should total RAM1 size."); /* set external flash properties - external flash is present on the DK6 board */ m_ext_flash_size = 0x00100000; @@ -376,9 +432,10 @@ SECTIONS __StackLimit = _vStackTop - STACK_SIZE; - __FACTORY_DATA_START = FACTORY_DATA_START_ADDRESS; - __FACTORY_DATA_SIZE = m_factory_data_size; + __FACTORY_DATA_START = FACTORY_DATA_START_ADDRESS; + __FACTORY_DATA_SIZE = m_factory_data_size; - ASSERT(((m_app_start + m_app_size + m_app_meta_data + m_factory_data_size + m_flash_config_size) <= m_int_flash_size), - "Internal flash capacity exceeded") + ASSERT(((m_app_start + m_app_size + m_app_meta_data + m_factory_data_size + m_flash_config_size) <= m_int_flash_size), + "Internal flash capacity exceeded") + } diff --git a/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h b/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h index 93f6d442baefe9..52cf1d2a738f90 100644 --- a/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h +++ b/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h @@ -37,8 +37,8 @@ #undef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY #define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY 120 // default is 28800 -#undef OPENTHREAD_CONFIG_MAC__DEFAULT_MAX_FRAME_RETRIES_DIRECT -#define OPENTHREAD_CONFIG_MAC__DEFAULT_MAX_FRAME_RETRIES_DIRECT 15 // default is 3 +#undef OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT +#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT 15 // default is 3 #undef OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT #define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT 1 // default is 0 diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG b/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG new file mode 100644 index 00000000000000..31449b25cf269e Binary files /dev/null and b/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG differ diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/out_dut1.bin b/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/demo_factory_data_dut1.bin similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/out_dut1.bin rename to examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/demo_factory_data_dut1.bin diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/out_dut2.bin b/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/demo_factory_data_dut2.bin similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/out_dut2.bin rename to examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/demo_factory_data_dut2.bin diff --git a/examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py b/examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py index a4035d0655baa1..6f76903e97f8a5 100644 --- a/examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py +++ b/examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py @@ -77,17 +77,16 @@ def decode_serial(serialport, outfile, database): try: while (True): - if (input.in_waiting > 0): - # read line from serial port and ascii decode - line = input.readline().decode('ascii').strip() - # find token start and detokenize - idx = line.rfind(']') - dstr = decode_string(line[idx + 1:], detokenizer) - if dstr: - line = line[:idx+1] + dstr - print(line, file=sys.stdout) - if output: - print(line, file=output) + # read line from serial port and ascii decode + line = input.readline().decode('ascii').strip() + # find token start and detokenize + idx = line.rfind(']') + dstr = decode_string(line[idx + 1:], detokenizer) + if dstr: + line = line[:idx+1] + dstr + print(line, file=sys.stdout) + if output: + print(line, file=output) except Exception: print("Serial error or program closed", file=sys.stderr) diff --git a/examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py b/examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py new file mode 100644 index 00000000000000..0c4a0b34a9dc17 --- /dev/null +++ b/examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py @@ -0,0 +1,14 @@ +import os +import subprocess + +sign_images_path = os.environ["NXP_K32W0_SDK_ROOT"] + "/tools/imagetool/sign_images.sh" + +# Give execute permission if needed +if os.access(sign_images_path, os.X_OK) is False: + os.chmod(sign_images_path, 0o766) + +# Convert script to unix format if needed +subprocess.call("(file " + sign_images_path + " | grep CRLF > /dev/null) && (dos2unix " + sign_images_path + ")", shell=True) + +# Call sign_images.sh script with the output directory +subprocess.call(sign_images_path + " " + os.getcwd(), shell=True) diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Cert.der b/scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Cert.der old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Cert.der rename to scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Cert.der diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Cert.pem b/scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Cert.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Cert.pem rename to scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Cert.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Key.der b/scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Key.der old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Key.der rename to scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Key.der diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Key.pem b/scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Key.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut1/Chip-DAC-NXP-1037-A220-Key.pem rename to scripts/tools/nxp/demo_generated_certs/dac/dut1/Chip-DAC-NXP-1037-A220-Key.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Cert.der b/scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Cert.der old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Cert.der rename to scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Cert.der diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Cert.pem b/scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Cert.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Cert.pem rename to scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Cert.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Key.der b/scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Key.der old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Key.der rename to scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Key.der diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Key.pem b/scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Key.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/dut2/Chip-DAC-NXP-1037-A220-Key.pem rename to scripts/tools/nxp/demo_generated_certs/dac/dut2/Chip-DAC-NXP-1037-A220-Key.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/paa/Chip-PAA-NXP-Cert.der b/scripts/tools/nxp/demo_generated_certs/paa/Chip-PAA-NXP-Cert.der old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/paa/Chip-PAA-NXP-Cert.der rename to scripts/tools/nxp/demo_generated_certs/paa/Chip-PAA-NXP-Cert.der diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/paa/Chip-PAA-NXP-Cert.pem b/scripts/tools/nxp/demo_generated_certs/paa/Chip-PAA-NXP-Cert.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/paa/Chip-PAA-NXP-Cert.pem rename to scripts/tools/nxp/demo_generated_certs/paa/Chip-PAA-NXP-Cert.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/paa/Chip-PAA-NXP-Key.pem b/scripts/tools/nxp/demo_generated_certs/paa/Chip-PAA-NXP-Key.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/paa/Chip-PAA-NXP-Key.pem rename to scripts/tools/nxp/demo_generated_certs/paa/Chip-PAA-NXP-Key.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.der b/scripts/tools/nxp/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.der old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.der rename to scripts/tools/nxp/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.der diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.pem b/scripts/tools/nxp/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.pem rename to scripts/tools/nxp/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Cert.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Key.pem b/scripts/tools/nxp/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Key.pem old mode 100755 new mode 100644 similarity index 100% rename from examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Key.pem rename to scripts/tools/nxp/demo_generated_certs/pai/Chip-PAI-NXP-1037-A220-Key.pem diff --git a/examples/platform/nxp/k32w/k32w0/scripts/generate_cert.sh b/scripts/tools/nxp/generate_cert.sh similarity index 64% rename from examples/platform/nxp/k32w/k32w0/scripts/generate_cert.sh rename to scripts/tools/nxp/generate_cert.sh index 172662ed192496..e7f93f2b79be93 100755 --- a/examples/platform/nxp/k32w/k32w0/scripts/generate_cert.sh +++ b/scripts/tools/nxp/generate_cert.sh @@ -33,23 +33,49 @@ function exit_err() { exit 1 } -DATE="2022-06-21 12:35:00" -LIFETIME="7305" +if [ -z "$DATE" ]; then + DATE="2023-01-19" +fi + +if [ -z "$TIME" ]; then + TIME="10:17:00" +fi + +if [ -z "$LIFETIME" ]; then + LIFETIME="7305" +fi + +if [ -z "$VID" ]; then + VID="1037" +fi + +if [ -z "$PID" ]; then + PID="A220" +fi -PAA_DATE="$DATE" +PAA_DATE="$DATE $TIME" PAA_LIFETIME="$LIFETIME" -PAA_CERT="Chip-PAA-NXP-Cert.pem" -PAA_KEY="Chip-PAA-NXP-Key.pem" -PAI_DATE="$DATE" +# Generate a new PAA only if PAA cert and key paths were not both specified. +if [[ -n "$PAA_CERT" && -n "$PAA_KEY" ]]; then + echo "A PAA was provided. Will not generate a new one." + GENERATE_PAA=false +else + GENERATE_PAA=true + PAA_CERT="Chip-PAA-NXP-Cert.pem" + PAA_CERT_DER="Chip-PAA-NXP-Cert.der" + PAA_KEY="Chip-PAA-NXP-Key.pem" +fi + +PAI_DATE="$PAA_DATE" PAI_LIFETIME="$LIFETIME" -PAI_VID="1037" -PAI_PID="A220" +PAI_VID="$VID" +PAI_PID="$PID" PAI_CERT="Chip-PAI-NXP-"$PAI_VID"-"$PAI_PID"-Cert.pem" PAI_CERT_DER="Chip-PAI-NXP-"$PAI_VID"-"$PAI_PID"-Cert.der" PAI_KEY="Chip-PAI-NXP-"$PAI_VID"-"$PAI_PID"-Key.pem" -DAC_DATE="$DATE" +DAC_DATE="$PAA_DATE" DAC_LIFETIME="$LIFETIME" DAC_VID="$PAI_VID" DAC_PID="$PAI_PID" @@ -59,13 +85,19 @@ DAC_KEY="Chip-DAC-NXP-"$DAC_VID"-"$DAC_PID"-Key.pem" DAC_KEY_DER="Chip-DAC-NXP-"$DAC_VID"-"$DAC_PID"-Key.der" # Remove certificates if present -rm -rf "$PAA_CERT" "$PAA_KEY" "$PAI_CERT" "$PAI_KEY" "$DAC_CERT" "$DAC_KEY" "$PAI_CERT_DER" "$DAC_CERT_DER" "$DAC_KEY_DER" >/dev/null 2>&1 +if [ "$GENERATE_PAA" = true ]; then + rm -rf "$PAA_CERT" "$PAA_KEY" "$PAA_CERT_DER" >/dev/null 2>&1 +fi + +rm -rf "$PAI_CERT" "$PAI_KEY" "$DAC_CERT" "$DAC_KEY" "$PAI_CERT_DER" "$DAC_CERT_DER" "$DAC_KEY_DER" >/dev/null 2>&1 # Generate certificates echo "Generate certificates" # PAA (root authoritity) -"$CHIP_CERT_TOOL" gen-att-cert --type a --subject-cn "Matter Development PAA NXP" --valid-from "$PAA_DATE" --lifetime "$PAA_LIFETIME" --out-key "$PAA_KEY" --out "$PAA_CERT" && echo "Generated PAA" || exit_err "Failed to generate PAA" +if [ "$GENERATE_PAA" = true ]; then + "$CHIP_CERT_TOOL" gen-att-cert --type a --subject-cn "Matter Development PAA NXP" --valid-from "$PAA_DATE" --lifetime "$PAA_LIFETIME" --out-key "$PAA_KEY" --out "$PAA_CERT" && echo "Generated PAA" || exit_err "Failed to generate PAA" +fi # PAI (vendor) "$CHIP_CERT_TOOL" gen-att-cert --type i --subject-cn "Matter Development PAI NXP" --subject-vid "$PAI_VID" --valid-from "$PAI_DATE" --lifetime "$PAI_LIFETIME" --ca-key "$PAA_KEY" --ca-cert "$PAA_CERT" --out-key "$PAI_KEY" --out "$PAI_CERT" && echo "Generated PAI" || exit_err "Failed to generate PAI" @@ -76,6 +108,11 @@ echo "Generate certificates" # Convert certificates and keys to der format (binary x509) echo "Convert certificates and keys to DER format" +# PAA +if [ "$GENERATE_PAA" = true ]; then + "$CHIP_CERT_TOOL" convert-cert -d "$PAA_CERT" "$PAA_CERT_DER" && echo "Converted PAA" || exit_err "Failed to convert PAA" +fi + # PAI "$CHIP_CERT_TOOL" convert-cert -d "$PAI_CERT" "$PAI_CERT_DER" && echo "Converted PAI" || exit_err "Failed to convert PAI" @@ -84,3 +121,8 @@ echo "Convert certificates and keys to DER format" # DAC Key "$CHIP_CERT_TOOL" convert-key -d "$DAC_KEY" "$DAC_KEY_DER" && echo "Converted DAC Key" || exit_err "Failed to convert DAC Key" + +if [ -n "$FACTORY_DATA_DEST" ]; then + echo "Moving certificates to $FACTORY_DATA_DEST" + mv Chip-* "$FACTORY_DATA_DEST" +fi diff --git a/scripts/tools/nxp/ota/README.md b/scripts/tools/nxp/ota/README.md index e1848a007f3441..45766b1db8d44f 100644 --- a/scripts/tools/nxp/ota/README.md +++ b/scripts/tools/nxp/ota/README.md @@ -7,121 +7,83 @@ orphan: true ## Overview This tool can generate an OTA image in the `|OTA standard header|TLV1|...|TLVn|` -format. The payload contains data in standard TLV format (not Matter TLV format. -During OTA transfer, these TLV can span across multiple BDX blocks, thus the -`OTAImageProcessorImpl` instance should take this into account. +format. The payload contains data in standard TLV format (not Matter TLV +format). During OTA transfer, these TLV can span across multiple BDX blocks, +thus the `OTAImageProcessorImpl` instance should take this into account. -Each TLV will be processed by its associated processor, pre-registered in -`OTAImageProcessorImpl` and identified by the TLV tag. If a processor cannot be -found for current decoded tag, the OTA transfer will be canceled. +## Supported platforms -An application is able to define its own processors, thus enabling extending the -default OTA functionality. The application can also opt to disable the default -processors (application, bootloader and factory data) by setting -`chip_enable_ota_default_processors=0`. +- K32W0 - + [K32W OTA README](../../../../src/platform/nxp/k32w/common/K32W_OTA_README.md) ## Usage -TODO: add more options - -Example: - -``` -python3 ./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 50000 -vs "1.0" -da sha256 -fd --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --dac_cert $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Cert.der --dac_key $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Key.der --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der -app ~/binaries/ota_update/chip-k32w0x-light-example-50000.bin --app-version 50000 --app-version-str "50000_test" --app-build-date "$DATE" ~/binaries/ota_update/chip-k32w0x-light-example-50000.bin $FACTORY_DATA_DEST/chip-k32w0x-light-example-50000.ota -``` - -Example (only factory data update): +This is a wrapper over standard `ota_image_tool.py`, so the options for `create` +are also available here: ``` -python3 ./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 50000 -vs "1.0" -da sha256 -fd --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --dac_cert $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Cert.der --dac_key $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Key.der --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der $FACTORY_DATA_DEST/chip-k32w0x-light-example-50000.ota +python3 ./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 50000 -vs "1.0" -da sha256 ``` -## Default processors - -The default processors for K32W0 are already implemented in: +followed by \*_custom options_- and a positional argument (should be last) that +specifies the output file. Please see the `create_ota_images.sh` for some +reference commands. -- `OTAApplicationProcessor` for application update. -- TODO: `OTABootloaderProcessor` for SSBL update. -- `OTAFactoryDataProcessor` for factory data update. - -## Implementing custom processors - -A custom processor should implement the interface defined by the -`OTATlvProcessor` abstract interface (simplified version; see `OTATlvHeader.h` -for full version): +The list of **custom options**: ``` -class OTATlvProcessor -{ -public: - virtual CHIP_ERROR Init() = 0; - virtual CHIP_ERROR Clear() = 0; - virtual CHIP_ERROR ApplyAction() = 0; - virtual CHIP_ERROR AbortAction() = 0; - - CHIP_ERROR Process(ByteSpan & block); -protected: - virtual CHIP_ERROR ProcessInternal(ByteSpan & block) = 0; -}; - +# Application options +--app-input-file --> Path to the application binary. +--app-version --> Application version. It's part of the descriptor and + can be different than the OTA image header version: -vn. +--app-version-str --> Application version string. Same as above. +--app-build-date --> Application build date. Same as above. + +# SSBL options +--bl-input-file --> Path to the SSBL binary. +--bl-version --> SSBL version. +--bl-version-str --> SSBL version string. +--bl-build-date --> SSBL build date. + +# Factory data options +--factory-data --> If set, enables the generation of factory data. +--cert_declaration --> Certification Declaration. +--dac_cert --> DAC certificate. +--dac_key --> DAC private key. +--pai_cert --> PAI certificate. + +# Custom TLV options +--json --> Path to a JSON file following ota_payload.schema ``` -Note that `ProcessInternal` should return: - -- `CHIP_NO_ERROR` if block was processed successfully. -- `CHIP_ERROR_BUFFER_TOO_SMALL` if current block doesn't contain all necessary - data. This can happen when a TLV value field has a header, but it is split - across two blocks. -- `CHIP_OTA_FETCH_ALREADY_SCHEDULED` if block was processed successfully and - the fetching is already scheduled by the processor. This happens in the - default application processor, because the next data fetching is scheduled - through a callback (called when enough external flash was erased). - -`Process` is the public API that is used inside `OTAImageProcessorImpl` for data -processing. This is a wrapper over `ProcessInternal`, which can return -`CHIP_OTA_CHANGE_PROCESSOR` to notify a new processor should be selected for the -remaining data. - -Furthermore, a processor can use an instance of `OTADataAccumulator` to to -accumulate data until a given threshold. This is useful when a custom payload -contains metadata that need parsing: accumulate data until the threshold is -reached or return `CHIP_ERROR_BUFFER_TOO_SMALL` to signal -`OTAImageProcessorImpl` more data is needed. - -``` -/** - * This class can be used to accumulate data until a given threshold. - * Should be used by OTATlvProcessor derived classes if they need - * metadata accumulation (e.g. for custom header decoding). - */ -class OTADataAccumulator -{ -public: - void Init(uint32_t threshold); - void Clear(); - CHIP_ERROR Accumulate(ByteSpan & block); - - inline uint8_t* data() { return mBuffer.Get(); } - -private: - uint32_t mThreshold; - uint32_t mBufferOffset; - Platform::ScopedMemoryBuffer mBuffer; -}; -``` - -## Factory data update - -`DAC`, `PAI` and `CD` can be updated at a later time by creating a factory data -update OTA image. If the `PAA` changes, make sure to generate the new -certificates using the new `PAA` (which is only used by the controller, e.g. -`chip-tool`). Please see the -[manufacturing flow guide](../../../../docs/guides/nxp_manufacturing_flow.md) -for generating new certificates. - -Example of OTA image generation with factory data and application update (using -env variables set in the prerequisites of manufacturing flow): - -``` -python3 ./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 50000 -vs "1.0" -da sha256 -fd --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --dac_cert $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Cert.der --dac_key $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Key.der --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der -app $FACTORY_DATA_DEST/chip-k32w0x-light-example-50000.bin --app-version 50000 --app-version-str "50000_test" --app-build-date "$DATE" $FACTORY_DATA_DEST/chip-k32w0x-light-example-50000.bin $FACTORY_DATA_DEST/chip-k32w0x-light-example-50000.ota -``` +Please note that the options above are separated into four categories: +application, bootloader, factory data and custom TLV (`--json` option). If no +descriptor options are specified for app/SSBL, the script will use the default +values (`50000`, `"50000-default"`, `"2023-01-01"`). The descriptor feature is +optional, TLV processors having the option to register a callback for descriptor +processing. + +## Custom payload + +When defining a custom processor, a user is able to also specify the custom +format of the TLV by creating a JSON file based on the `ota_payload.schema`. The +tool offers support for describing multiple TLV in the same JSON file. Please +see the `examples/ota_max_entries_example.json` for a multi-app + SSBL example. +Option `--json` must be used to specify the path to the JSON file. + +## Examples + +A set of examples can be found in `./examples`. Please run `create_ota_image.sh` +to generate the examples: + +- Application image with default descriptor +- Application image with specified descriptor +- Factory data image +- SSBL image +- Application + SSBL + factory data image +- Maximum number of entries image, using `ota_max_entries_example.json`. The + examples uses 8 SSBL binaries because they have a small size and fit in + external flash. + +The binaries from `./examples/binaries` should only be used only as an example. +The user should provide their own binaries when generating the OTA image. diff --git a/scripts/tools/nxp/ota/examples/binaries/ssbl_ext_flash_ota_entry_example.bin b/scripts/tools/nxp/ota/examples/binaries/ssbl_ext_flash_ota_entry_example.bin new file mode 100755 index 00000000000000..5800a9860f70aa Binary files /dev/null and b/scripts/tools/nxp/ota/examples/binaries/ssbl_ext_flash_ota_entry_example.bin differ diff --git a/scripts/tools/nxp/ota/examples/binaries/ssbl_ram_ota_entry_example.bin b/scripts/tools/nxp/ota/examples/binaries/ssbl_ram_ota_entry_example.bin new file mode 100755 index 00000000000000..9a5bc3ac60b970 Binary files /dev/null and b/scripts/tools/nxp/ota/examples/binaries/ssbl_ram_ota_entry_example.bin differ diff --git a/scripts/tools/nxp/ota/examples/create_ota_images.sh b/scripts/tools/nxp/ota/examples/create_ota_images.sh new file mode 100644 index 00000000000000..36b100376de058 --- /dev/null +++ b/scripts/tools/nxp/ota/examples/create_ota_images.sh @@ -0,0 +1,119 @@ +#!/usr/bin/bash + +ROOT=../../../../../ +CHIP_CERT=$ROOT/src/tools/chip-cert +SPAKE2P=$ROOT/src/tools/spake2p + +# Prerequisites +if [ ! -d "$CHIP_CERT/out" ]; then + printf "chip-cert is not available. Compile it.\n" + cd "$CHIP_CERT" + gn gen out + ninja -C out + cd - +else + printf "chip-cert is available.\n" +fi + +if [ ! -d "$SPAKE2P/out" ]; then + printf "spake2p is not available. Compile it.\n" + cd "$SPAKE2P" + gn gen out + ninja -C out + cd - +else + printf "spake2p is available.\n" +fi + +VERSION=50000 +export FACTORY_DATA_DEST=./out/factory_data +export DEVICE_TYPE=100 +export DATE="2023-01-01" +export TIME="$(date +"%T")" +export LIFETIME="7305" +export VID="1037" +export PID="A220" +export PAA_CERT=../../demo_generated_certs/paa/Chip-PAA-NXP-Cert.pem +export PAA_KEY=../../demo_generated_certs/paa/Chip-PAA-NXP-Key.pem + +if [ ! -d "./out" ]; then + mkdir "./out" +fi + +if [ ! -d "$FACTORY_DATA_DEST" ]; then + mkdir "$FACTORY_DATA_DEST" +fi + +printf "Generate new certificates based on the same PAA\n" +../../generate_cert.sh "$CHIP_CERT"/out/chip-cert + +printf "Generate new Certification Declaration\n" +"$CHIP_CERT"/out/chip-cert gen-cd \ + --key "$ROOT"/credentials/test/certification-declaration/Chip-Test-CD-Signing-Key.pem \ + --cert "$ROOT"/credentials/test/certification-declaration/Chip-Test-CD-Signing-Cert.pem \ + --out "$FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID".der \ + --format-version 1 \ + --vendor-id "0x$VID" \ + --product-id "0x$PID" \ + --device-type-id "0x$DEVICE_TYPE" \ + --certificate-id "ZIG20142ZB330003-24" \ + --security-level 0 \ + --security-info 0 \ + --version-number 9876 \ + --certification-type 1 + +printf "\nExample: command without input option specified\n" +python3 ../ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn "$VERSION" -vs "1.0" -da sha256 \ + ./out/app-standard-example-50000.ota || printf "Command failed because no option was specified.\n" + +printf "\nExample: generate app OTA image with default descriptor\n" +python3 ../ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn "$VERSION" -vs "1.0" -da sha256 \ + --app-input-file ./binaries/app_example.bin \ + ./out/app-standard-example-50000.ota + +printf "\nExample: generate app OTA image with specified descriptor\n" +python3 ../ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn "$VERSION" -vs "1.0" -da sha256 \ + --app-input-file ./binaries/app_example.bin \ + --app-version 50000 \ + --app-version-str "50000-version" \ + --app-build-date "$(date +\"%F\")" \ + ./out/app-with-descriptor-example-50000.ota + +printf "\nExample: generate factory data OTA image\n" +python3 ../ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn "$VERSION" -vs "1.0" -da sha256 \ + -fd \ + --cert_declaration "$FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID".der \ + --dac_cert "$FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID"-Cert.der \ + --dac_key "$FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID"-Key.der \ + --pai_cert "$FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID"-Cert.der \ + ./out/factory-data-example-50000.ota + +printf "\nExample: generate SSBL OTA image with specified descriptor\n" +python3 ../ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 1 -vs "1.0" -da sha256 \ + --bl-input-file ./binaries/ssbl_ram_ota_entry_example.bin \ + --bl-version 1 \ + --bl-version-str "SSBL-version-1" \ + --bl-build-date "$(date +\"%F\")" \ + ./out/ssbl-with-descriptor-example.ota + +printf "\nExample: generate app + SSBL + factory data update OTA image\n" +python3 ../ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 1 -vs "1.0" -da sha256 \ + --app-input-file ./binaries/app_example.bin \ + --app-version 50000 \ + --app-version-str "50000-version" \ + --app-build-date "$(date +\"%F\")" \ + --bl-input-file ./binaries/ssbl_ram_ota_entry_example.bin \ + --bl-version 1 \ + --bl-version-str "SSBL-version-1" \ + --bl-build-date "$(date +\"%F\")" \ + -fd \ + --cert_declaration "$FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID".der \ + --dac_cert "$FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID"-Cert.der \ + --dac_key "$FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID"-Key.der \ + --pai_cert "$FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID"-Cert.der \ + ./out/app-ssbl-factory-data-example.ota + +printf "\nExample: generate OTA image for maximum number of entries (8) using JSON\n" +python3 ../ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 50000 -vs "1.0" -da sha256 \ + --json ./ota_max_entries_example.json \ + ./out/max-entries-example.ota diff --git a/scripts/tools/nxp/ota/examples/ota_max_entries_example.json b/scripts/tools/nxp/ota/examples/ota_max_entries_example.json new file mode 100644 index 00000000000000..d5ba8ff8e80964 --- /dev/null +++ b/scripts/tools/nxp/ota/examples/ota_max_entries_example.json @@ -0,0 +1,172 @@ +{ + "inputs": [ + { + "tag": 4, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1003 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + }, + { + "tag": 5, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1004 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + }, + { + "tag": 6, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1005 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + }, + { + "tag": 7, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1006 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + }, + { + "tag": 8, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1007 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + }, + { + "tag": 9, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1008 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + }, + { + "tag": 10, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1009 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + }, + { + "tag": 11, + "descriptor": [ + { + "name": "ssbl_version", + "length": 4, + "value": 1010 + }, + { + "name": "ssbl_version_str", + "length": 64, + "value": "SsblTestVersion" + }, + { + "name": "ssbl_build_date", + "length": 64, + "value": "2023-02-13" + } + ], + "path": "./binaries/ssbl_ext_flash_ota_entry_example.bin" + } + ] +} diff --git a/scripts/tools/nxp/ota/ota_image_tool.py b/scripts/tools/nxp/ota/ota_image_tool.py index 13b1895fac6acf..bf796f1010119f 100755 --- a/scripts/tools/nxp/ota/ota_image_tool.py +++ b/scripts/tools/nxp/ota/ota_image_tool.py @@ -30,15 +30,13 @@ ''' import argparse +import glob +import json import logging import os import sys -import ota_image_tool -from chip.tlv import TLVWriter -from custom import CertDeclaration, DacCert, DacPKey, PaiCert -from default import InputArgument -from generate import set_logger +import jsonschema sys.path.insert(0, os.path.join( os.path.dirname(__file__), '../factory_data_generator')) @@ -47,9 +45,15 @@ sys.path.insert(0, os.path.join( os.path.dirname(__file__), '../../../../src/app/')) +import ota_image_tool # noqa: E402 isort:skip +from chip.tlv import TLVWriter # noqa: E402 isort:skip +from custom import CertDeclaration, DacCert, DacPKey, PaiCert # noqa: E402 isort:skip +from default import InputArgument # noqa: E402 isort:skip +from generate import set_logger # noqa: E402 isort:skip -OTA_FACTORY_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_factory_tlv_temp.bin") -OTA_APP_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_app_tlv_temp.bin") +OTA_APP_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_temp_app_tlv.bin") +OTA_BOOTLOADER_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_temp_ssbl_tlv.bin") +OTA_FACTORY_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_temp_factory_tlv.bin") class TAG: @@ -58,6 +62,13 @@ class TAG: FACTORY_DATA = 3 +def write_to_temp(path: str, payload: bytearray): + with open(path, "wb") as _handle: + _handle.write(payload) + + logging.info(f"Data payload size for {path.split('/')[-1]}: {len(payload)}") + + def generate_header(tag: int, length: int): header = bytearray(tag.to_bytes(4, "little")) header += bytearray(length.to_bytes(4, "little")) @@ -84,29 +95,100 @@ def generate_factory_data(args: object): payload = generate_header(TAG.FACTORY_DATA, len(writer.encoding)) payload += writer.encoding - with open(OTA_FACTORY_TLV_TEMP, "wb") as _handle: - _handle.write(payload) + write_to_temp(OTA_FACTORY_TLV_TEMP, payload) + + return [OTA_FACTORY_TLV_TEMP] + + +def generate_descriptor(version: int, versionStr: str, buildDate: str): + """ + Generate descriptor as bytearray for app/SSBL payload. + """ + v = version if version is not None else 50000 + vs = versionStr if versionStr is not None else "50000-default" + bd = buildDate if buildDate is not None else "2023-01-01" + + logging.info(f"\t-version: {v}") + logging.info(f"\t-version str: {vs}") + logging.info(f"\t-build date: {bd}") + + v = v.to_bytes(4, "little") + vs = bytearray(vs, "ascii") + bytearray(64 - len(vs)) + bd = bytearray(bd, "ascii") + bytearray(64 - len(bd)) - logging.info(f"Factory data payload size: {len(payload)}") + return v + vs + bd def generate_app(args: object): - version = args.app_version.to_bytes(4, "little") - versionStr = bytearray(args.app_version_str, "ascii") + bytearray(64 - len(args.app_version_str)) - buildDate = bytearray(args.app_build_date, "ascii") + bytearray(64 - len(args.app_build_date)) - descriptor = version + versionStr + buildDate + """ + Generate app payload with descriptor. If a certain option is not specified, use the default values. + """ + logging.info("App descriptor information:") + + descriptor = generate_descriptor(args.app_version, args.app_version_str, args.app_build_date) file_size = os.path.getsize(args.app_input_file) payload = generate_header(TAG.APPLICATION, len(descriptor) + file_size) + descriptor - with open(OTA_APP_TLV_TEMP, "wb") as _handle: - _handle.write(payload) + write_to_temp(OTA_APP_TLV_TEMP, payload) - logging.info(f"Application payload size: {len(payload)}") + return [OTA_APP_TLV_TEMP, args.app_input_file] def generate_bootloader(args: object): - # TODO - pass + """ + Generate SSBL payload with descriptor. If a certain option is not specified, use the default values. + """ + logging.info("SSBL descriptor information:") + + descriptor = generate_descriptor(args.bl_version, args.bl_version_str, args.bl_build_date) + file_size = os.path.getsize(args.bl_input_file) + payload = generate_header(TAG.BOOTLOADER, len(descriptor) + file_size) + descriptor + + write_to_temp(OTA_BOOTLOADER_TLV_TEMP, payload) + + return [OTA_BOOTLOADER_TLV_TEMP, args.bl_input_file] + + +def validate_json(data: str): + with open(os.path.join(os.path.dirname(__file__), 'ota_payload.schema'), 'r') as fd: + payload_schema = json.load(fd) + + try: + jsonschema.validate(instance=data, schema=payload_schema) + logging.info("JSON data is valid") + except jsonschema.exceptions.ValidationError as err: + logging.error(f"JSON data is invalid: {err}") + sys.exit(1) + + +def generate_custom_tlvs(data): + """ + Generate custom OTA payload from a JSON object following a predefined schema. + The payload is written in a temporary file that will be appended to args.input_files. + """ + input_files = [] + + payload = bytearray() + descriptor = bytearray() + iteration = 0 + for entry in data["inputs"]: + if "descriptor" in entry: + for field in entry["descriptor"]: + if isinstance(field["value"], str): + descriptor += bytearray(field["value"], "ascii") + bytearray(field["length"] - len(field["value"])) + elif isinstance(field["value"], int): + descriptor += bytearray(field["value"].to_bytes(field["length"], "little")) + file_size = os.path.getsize(entry["path"]) + payload = generate_header(entry["tag"], len(descriptor) + file_size) + descriptor + + temp_output = os.path.join(os.path.dirname(__file__), "ota_temp_custom_tlv_" + str(iteration) + ".bin") + write_to_temp(temp_output, payload) + + input_files += [temp_output, entry["path"]] + iteration += 1 + descriptor = bytearray() + + return input_files def show_payload(args: object): @@ -119,23 +201,36 @@ def show_payload(args: object): def create_image(args: object): ota_image_tool.validate_header_attributes(args) + input_files = list() + if args.json: + with open(args.json, 'r') as fd: + data = json.load(fd) + validate_json(data) + input_files += generate_custom_tlvs(data) + if args.factory_data: - generate_factory_data(args) - input_files += [OTA_FACTORY_TLV_TEMP] + input_files += generate_factory_data(args) + + if args.bl_input_file: + input_files += generate_bootloader(args) + + if args.app_input_file: + input_files += generate_app(args) + + if len(input_files) == 0: + print("Please specify an input option.") + sys.exit(1) + + logging.info("Input files used:") + [logging.info(f"\t- {_file}") for _file in input_files] - if args.app_input_file is not None: - generate_app(args) - input_files += [OTA_APP_TLV_TEMP, args.app_input_file] - print(input_files) args.input_files = input_files ota_image_tool.generate_image(args) - if args.factory_data: - os.remove(OTA_FACTORY_TLV_TEMP) - if args.app_input_file is not None: - os.remove(OTA_APP_TLV_TEMP) + for filename in glob.glob(os.path.dirname(__file__) + "/ota_temp_*"): + os.remove(filename) def main(): @@ -169,14 +264,11 @@ def any_base_int(s): return int(s, 0) help='Minimum software version that can be updated to this image') create_parser.add_argument('-ma', '--max-version', type=any_base_int, help='Maximum software version that can be updated to this image') - create_parser.add_argument( - '-rn', '--release-notes', help='Release note URL') - create_parser.add_argument('input_files', nargs='*', - help='Path to input image payload file') - create_parser.add_argument('output_file', help='Path to output image file') + create_parser.add_argument('-rn', '--release-notes', + help='Release note URL') - create_parser.add_argument('-app', '--app-input-file', - help='Path to input application image payload file') + create_parser.add_argument('-app', "--app-input-file", + help='Path to application input file') create_parser.add_argument('--app-version', type=any_base_int, help='Application Software version (numeric)') create_parser.add_argument('--app-version-str', type=str, @@ -184,7 +276,7 @@ def any_base_int(s): return int(s, 0) create_parser.add_argument('--app-build-date', type=str, help='Application build date (string)') - create_parser.add_argument('-bl', '--bootloader-input-file', + create_parser.add_argument('-bl', '--bl-input-file', help='Path to input bootloader image payload file') create_parser.add_argument('--bl-version', type=any_base_int, help='Bootloader Software version (numeric)') @@ -192,8 +284,6 @@ def any_base_int(s): return int(s, 0) help='Bootloader Software version (string)') create_parser.add_argument('--bl-build-date', type=str, help='Bootloader build date (string)') - create_parser.add_argument('--bl-load-addr', type=any_base_int, - help='Bootloader load address (numeric)') # Factory data specific arguments. Will be used to generate the TLV payload. create_parser.add_argument('-fd', '--factory-data', action='store_true', @@ -209,6 +299,13 @@ def any_base_int(s): return int(s, 0) create_parser.add_argument("--pai_cert", type=PaiCert, help="[path] Path to PAI certificate in DER format") + # Path to input JSON file which describes custom TLVs. + create_parser.add_argument('--json', help="[path] Path to the JSON describing custom TLVs") + + create_parser.add_argument('-i', '--input_files', default=list(), + help='Path to input image payload file') + create_parser.add_argument('output_file', help='Path to output image file') + show_parser = subcommands.add_parser('show', help='Show OTA image info') show_parser.add_argument('image_file', help='Path to OTA image file') diff --git a/scripts/tools/nxp/ota/ota_payload.schema b/scripts/tools/nxp/ota/ota_payload.schema new file mode 100644 index 00000000000000..bceacf75f029b9 --- /dev/null +++ b/scripts/tools/nxp/ota/ota_payload.schema @@ -0,0 +1,67 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "Custom_OTA_TLV_schema", + "description": "A representation of custom OTA payload with variable number of TLVs", + "type": "object", + "required": [ + "inputs" + ], + "properties": { + "inputs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "tag", + "path" + ], + "properties": { + "tag": { + "type": "integer", + "description": "TLV's tag value used to select a parser" + }, + "descriptor": { + "type": "array", + "description": "Metadata of the TLV value field (C struct)", + "items": { + "$ref": "#/$defs/field" + } + }, + "path": { + "type": "string", + "description": "System path to the binary" + } + } + } + } + }, + "$defs": { + "field": { + "type": "object", + "required": [ + "name", + "length", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "length": { + "type": "integer", + "description": "Number of bytes occupied in memory" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h b/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h index 0d466e3913e160..b55e8fccc38fc8 100644 --- a/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h +++ b/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h @@ -122,6 +122,16 @@ #define kNvmId_OTConfigData (uint16_t) 0x4F00 #endif +/** + * @def kNvmId_ApplicationBase + * + * Base PDM ID to be used by applications to define their own + * PDM IDs by using an offset. + */ +#ifndef kNvmId_ApplicationBase +#define kNvmId_ApplicationBase (uint16_t) 0xA000 +#endif + #if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA /** * @def kNvmId_FactoryDataBackup diff --git a/src/platform/nxp/k32w/common/K32W_OTA_README.md b/src/platform/nxp/k32w/common/K32W_OTA_README.md new file mode 100644 index 00000000000000..97c73ec9e5a7a2 --- /dev/null +++ b/src/platform/nxp/k32w/common/K32W_OTA_README.md @@ -0,0 +1,143 @@ +# K32W OTA + +The OTA processing is now delegated to instances of `OTATlvProcessor` derived +classes. These instances are registered with the `OTAImageProcessorImpl` +instance, which manages the selection of processors that should process the next +blocks, until a full TLV block was transferred. + +The application is able to define its own processors, thus extending the default +OTA functionality. The application can also opt to disable the default +processors (application, SSBL and factory data). + +Please note that if an OTA image containing multiple TLV is transferred, then +the action for each TLV is applied sequentially, If one of the actions fails, +the remaining actions will not be applied and OTA abort is called. TBD: should +all actions be applied only if there is no error? Or should each action be +applied separately? + +## Default processors + +The default processors for K32W0 are already implemented in: + +- `OTAFirmwareProcessor` for application/SSBL update. Enabled by default. +- `OTAFactoryDataProcessor` for factory data update. Disabled by default, user + has to specify `chip_ota_enable_factory_data_processor=1` in the build args. + +Some SDK OTA module flags are defined to support additional features: + +- `gOTAAllowCustomStartAddress=1` - enable `EEPROM` offset value. Used + internally by SDK OTA module. +- `gOTAUseCustomOtaEntry=1` - support custom OTA entry for multi-image. +- `gOTACustomOtaEntryMemory=1` - K32W0 uses `OTACustomStorage_ExtFlash` (1) by + default. + +## Implementing custom processors + +A custom processor should implement the abstract interface defined in +`OTATlvProcessor.h`. Below is a compact version: + +``` +class OTATlvProcessor +{ +public: + virtual CHIP_ERROR Init() = 0; + virtual CHIP_ERROR Clear() = 0; + virtual CHIP_ERROR ApplyAction() = 0; + virtual CHIP_ERROR AbortAction() = 0; + virtual CHIP_ERROR ExitAction(); + + CHIP_ERROR Process(ByteSpan & block); + void RegisterDescriptorCallback(ProcessDescriptor callback); + +protected: + virtual CHIP_ERROR ProcessInternal(ByteSpan & block) = 0; +}; + +``` + +Some details regarding the interface: + +- `Init` will be called whenever the processor is selected. +- `Clear` will be called when abort occurs or after the apply action takes + place. +- `ApplyAction` will be called in `OTAImageProcessorImpl::HandleApply`, before + the board is reset. +- `AbortAction` will be called in `OTAImageProcessorImpl::HandleAbort`. + Processors should reset state here. +- `ExitAction` is optional and should be implemented by the processors that + want to execute an action after all data has been transferred, but before + `HandleApply` is called. It's called before the new processor selection + takes place. This is useful in the context of multiple TLV transferred in a + single OTA process. +- `Process` is the public API used inside `OTAImageProcessorImpl` for data + processing. This is a wrapper over `ProcessInternal`, which can return + `CHIP_OTA_CHANGE_PROCESSOR` to notify a new processor should be selected for + the remaining data. +- `RegisterDescriptorCallback` can be used to register a callback for + processing the descriptor. It's optional. +- `ProcessInternal` should return: _ `CHIP_NO_ERROR` if block was processed + successfully. _ `CHIP_ERROR_BUFFER_TOO_SMALL` if current block doesn't + contain all necessary data. This can happen when a TLV value field has a + header, but it is split across two blocks. \* + `CHIP_OTA_FETCH_ALREADY_SCHEDULED` if block was processed successfully and + the fetching is already scheduled by the processor. This happens in the + default application processor, because the next data fetching is scheduled + through a callback (called when enough external flash was erased). + +Furthermore, a processor can use an instance of `OTADataAccumulator` to +accumulate data until a given threshold. This is useful when a custom payload +contains metadata that need parsing: accumulate data until the threshold is +reached or return `CHIP_ERROR_BUFFER_TOO_SMALL` to signal +`OTAImageProcessorImpl` more data is needed. + +``` +/** + * This class can be used to accumulate data until a given threshold. + * Should be used by OTATlvProcessor derived classes if they need + * metadata accumulation (e.g. for custom header decoding). + */ +class OTADataAccumulator +{ +public: + void Init(uint32_t threshold); + void Clear(); + CHIP_ERROR Accumulate(ByteSpan & block); + + inline uint8_t* data() { return mBuffer.Get(); } + +private: + uint32_t mThreshold; + uint32_t mBufferOffset; + Platform::ScopedMemoryBuffer mBuffer; +}; +``` + +## SSBL max entries example + +`CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST` can be set to 1 to enable max entries test. +There will be 8 additional processors registered in default `OtaHooks` +implementation. The OTA image should be generated with the +`create_ota_images.sh` script from `./scripts/tools/nxp/ota/examples`. + +## Factory data restore mechanism + +Prior to factory data update, the old factory data is backed up in external +flash. If anything interrupts the update (e.g. power loss), there is a slight +chance the internal flash factory data section is erased and has to be restored +at next boot. The `K32W0FactoryDataProvider` offers a default restore mechanism +and support for registering additional restore mechanisms or overwriting the +default one. + +Restore mechanisms are just functions that have this signature: +`CHIP_ERROR (*)(void)`. Any such function can be registered through +`K32W0FactoryDataProvider::RegisterRestoreMechanism`. + +The default restore mechanism is implemented as a weak function: +`FactoryDataDefaultRestoreMechanism`. It is registered in +`K32W0FactoryDataProvider::Init`, before factory data validation, and it can be +overwritten at application level. When doing the actual restore, the mechanisms +are called in the order they were registered. + +Please note that the restore mechanisms registration order matters. Once a +restore mechanism is successful (`CHIP_NO_ERROR` is returned), the restore +process has finished and subsequent restore mechanisms will not be called. diff --git a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp index 4efb456e4a8f23..b87ef560aa5841 100644 --- a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp +++ b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp @@ -105,6 +105,8 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) return; } + GetRequestorInstance()->GetProviderLocation(imageProcessor->mBackupProviderLocation); + imageProcessor->mHeaderParser.Init(); imageProcessor->mAccumulator.Init(sizeof(OTATlvHeader)); imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); @@ -133,7 +135,7 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessPayload(ByteSpan & block) ReturnErrorOnFailure(mAccumulator.Accumulate(block)); ByteSpan tlvHeader{ mAccumulator.data(), sizeof(OTATlvHeader) }; ReturnErrorOnFailure(SelectProcessor(tlvHeader)); - mCurrentProcessor->Init(); + ReturnErrorOnFailure(mCurrentProcessor->Init()); } status = mCurrentProcessor->Process(block); @@ -141,6 +143,7 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessPayload(ByteSpan & block) { mAccumulator.Clear(); mAccumulator.Init(sizeof(OTATlvHeader)); + mCurrentProcessor = nullptr; } else @@ -167,6 +170,7 @@ CHIP_ERROR OTAImageProcessorImpl::SelectProcessor(ByteSpan & block) return CHIP_OTA_PROCESSOR_NOT_REGISTERED; } + ChipLogDetail(SoftwareUpdate, "Selected processor with tag: %ld", pair->first); mCurrentProcessor = pair->second; mCurrentProcessor->SetLength(header.length); mCurrentProcessor->SetWasSelected(true); @@ -194,16 +198,11 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context) auto * imageProcessor = reinterpret_cast(context); if (imageProcessor != nullptr) { - for (auto const & pair : imageProcessor->mProcessorMap) - { - if (pair.second->WasSelected()) - { - pair.second->AbortAction(); - pair.second->Clear(); - } - } + imageProcessor->AbortAllProcessors(); } imageProcessor->Clear(); + + OtaHookAbort(); } void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) @@ -255,6 +254,21 @@ void OTAImageProcessorImpl::HandleStatus(CHIP_ERROR status) } } +void OTAImageProcessorImpl::AbortAllProcessors() +{ + ChipLogError(SoftwareUpdate, "All selected processors will call abort action"); + + for (auto const & pair : mProcessorMap) + { + if (pair.second->WasSelected()) + { + pair.second->AbortAction(); + pair.second->Clear(); + pair.second->SetWasSelected(false); + } + } +} + bool OTAImageProcessorImpl::IsFirstImageRun() { OTARequestorInterface * requestor = chip::GetRequestorInstance(); @@ -344,15 +358,23 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) if (error != CHIP_NO_ERROR) { ChipLogError(SoftwareUpdate, "Apply action for tag %d processor failed.", (uint8_t) pair.first); + // Revert all previously applied actions if current apply action fails. + // Reset image processor and requestor states. + imageProcessor->AbortAllProcessors(); imageProcessor->Clear(); GetRequestorInstance()->Reset(); + return; } - pair.second->Clear(); - pair.second->SetWasSelected(false); } } + for (auto const & pair : imageProcessor->mProcessorMap) + { + pair.second->Clear(); + pair.second->SetWasSelected(false); + } + imageProcessor->mAccumulator.Clear(); // Set the necessary information to inform the SSBL that a new image is available diff --git a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.h b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.h index 4c545c2a218f13..4eea088891109f 100644 --- a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.h +++ b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.h @@ -22,22 +22,40 @@ #include #include #include +#include #include #include /* * OTA hooks that can be overwritten by application. - * Default behavior is implemented as WEAK symbols in - * platform OtaHooks.cpp. + * Default behavior is implemented as WEAK symbols in platform OtaHooks.cpp. + */ + +/* + * This hook is called at the end of OTAImageProcessorImpl::Init. + * It should generally register the OTATlvProcessor instances. */ extern "C" CHIP_ERROR OtaHookInit(); + +/* + * This hook is called at the end of OTAImageProcessorImpl::HandleApply. + * The default implementation saves the internal OTA entry structure and resets the device. + */ extern "C" void OtaHookReset(); +/* + * This hook is called at the end of OTAImageProcessorImpl::HandleAbort. + * For example, it can be used to schedule a retry. + */ +extern "C" void OtaHookAbort(); + namespace chip { class OTAImageProcessorImpl : public OTAImageProcessorInterface { public: + using ProviderLocation = chip::OTARequestorInterface::ProviderLocationType; + CHIP_ERROR Init(OTADownloader * downloader); void Clear(); @@ -54,6 +72,7 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface CHIP_ERROR ProcessPayload(ByteSpan & block); CHIP_ERROR SelectProcessor(ByteSpan & block); CHIP_ERROR RegisterProcessor(uint32_t tag, OTATlvProcessor * processor); + Optional & GetBackupProvider() { return mBackupProviderLocation; } static void FetchNextData(uint32_t context); static OTAImageProcessorImpl & GetDefaultInstance(); @@ -78,12 +97,18 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface */ CHIP_ERROR ReleaseBlock(); + /** + * Call AbortAction for all processors that were used + */ + void AbortAllProcessors(); + MutableByteSpan mBlock; OTADownloader * mDownloader; OTAImageHeaderParser mHeaderParser; OTATlvProcessor * mCurrentProcessor = nullptr; OTADataAccumulator mAccumulator; std::map mProcessorMap; + Optional mBackupProviderLocation; }; } // namespace chip diff --git a/src/platform/nxp/k32w/common/OTATlvProcessor.cpp b/src/platform/nxp/k32w/common/OTATlvProcessor.cpp index 819f539263f572..40b068b446ead5 100644 --- a/src/platform/nxp/k32w/common/OTATlvProcessor.cpp +++ b/src/platform/nxp/k32w/common/OTATlvProcessor.cpp @@ -36,18 +36,29 @@ CHIP_ERROR OTATlvProcessor::Process(ByteSpan & block) { mProcessedLength += bytes; block = block.SubSpan(bytes); - if (mProcessedLength == mLength && block.size() > 0) + if (mProcessedLength == mLength) { - // If current block was processed fully and the block still contains data, it - // means that the block contains another TLV's data and the current processor - // should be changed by OTAImageProcessorImpl. - return CHIP_OTA_CHANGE_PROCESSOR; + status = ExitAction(); + if (!IsError(status) && (block.size() > 0)) + { + // If current block was processed fully and the block still contains data, it + // means that the block contains another TLV's data and the current processor + // should be changed by OTAImageProcessorImpl. + return CHIP_OTA_CHANGE_PROCESSOR; + } } } return status; } +void OTATlvProcessor::ClearInternal() +{ + mLength = 0; + mProcessedLength = 0; + mWasSelected = false; +} + bool OTATlvProcessor::IsError(CHIP_ERROR & status) { return status != CHIP_NO_ERROR && status != CHIP_ERROR_BUFFER_TOO_SMALL && status != CHIP_OTA_FETCH_ALREADY_SCHEDULED; diff --git a/src/platform/nxp/k32w/common/OTATlvProcessor.h b/src/platform/nxp/k32w/common/OTATlvProcessor.h index 0f3f00ffaf9688..400e23e8f9a4e1 100644 --- a/src/platform/nxp/k32w/common/OTATlvProcessor.h +++ b/src/platform/nxp/k32w/common/OTATlvProcessor.h @@ -36,7 +36,10 @@ namespace chip { #define CHIP_OTA_PROCESSOR_PUSH_CHUNK CHIP_ERROR_TLV_PROCESSOR(0x07) #define CHIP_OTA_PROCESSOR_IMG_AUTH CHIP_ERROR_TLV_PROCESSOR(0x08) #define CHIP_OTA_FETCH_ALREADY_SCHEDULED CHIP_ERROR_TLV_PROCESSOR(0x09) -#define CHIP_OTA_PROCESSOR_IMG_COMMIT CHIP_ERROR_TLV_PROCESSOR(0x0a) +#define CHIP_OTA_PROCESSOR_IMG_COMMIT CHIP_ERROR_TLV_PROCESSOR(0x0A) +#define CHIP_OTA_PROCESSOR_CB_NOT_REGISTERED CHIP_ERROR_TLV_PROCESSOR(0x0B) +#define CHIP_OTA_PROCESSOR_EEPROM_OFFSET CHIP_ERROR_TLV_PROCESSOR(0x0C) +#define CHIP_OTA_PROCESSOR_START_IMAGE CHIP_ERROR_TLV_PROCESSOR(0x0D) // Descriptor constants constexpr size_t kVersionStringSize = 64; @@ -44,6 +47,13 @@ constexpr size_t kBuildDateSize = 64; constexpr uint16_t requestedOtaMaxBlockSize = 1024; +/** + * Used alongside RegisterDescriptorCallback to register + * a custom descriptor processing function with a certain + * TLV processor. + */ +typedef CHIP_ERROR (*ProcessDescriptor)(void * descriptor); + struct OTATlvHeader { uint32_t tag; @@ -59,7 +69,7 @@ struct OTATlvHeader * data from two different TLVs, the processor should ensure the remaining * data is returned in the block passed as input. * The default processors: application, SSBL and factory data are registered - * in OTAImageProcessorImpl::Init. + * in OTAImageProcessorImpl::Init through OtaHookInit. * Applications should use OTAImageProcessorImpl::RegisterProcessor * to register additional processors. */ @@ -72,8 +82,10 @@ class OTATlvProcessor virtual CHIP_ERROR Clear() = 0; virtual CHIP_ERROR ApplyAction() = 0; virtual CHIP_ERROR AbortAction() = 0; + virtual CHIP_ERROR ExitAction() { return CHIP_NO_ERROR; } CHIP_ERROR Process(ByteSpan & block); + void RegisterDescriptorCallback(ProcessDescriptor callback) { mCallbackProcessDescriptor = callback; } void SetLength(uint32_t length) { mLength = length; } void SetWasSelected(bool selected) { mWasSelected = selected; } bool WasSelected() { return mWasSelected; } @@ -104,11 +116,14 @@ class OTATlvProcessor */ virtual CHIP_ERROR ProcessInternal(ByteSpan & block) = 0; + void ClearInternal(); + bool IsError(CHIP_ERROR & status); - uint32_t mLength = 0; - uint32_t mProcessedLength = 0; - bool mWasSelected = false; + uint32_t mLength = 0; + uint32_t mProcessedLength = 0; + bool mWasSelected = false; + ProcessDescriptor mCallbackProcessDescriptor = nullptr; }; /** diff --git a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp b/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp index 29a3e9ee88ef3a..7ae29b191578fe 100644 --- a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp +++ b/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp @@ -1614,17 +1614,20 @@ void BLEManagerImpl::blekw_new_data_received_notification(uint32_t mask) void BLEManagerImpl::BleAdvTimeoutHandler(TimerHandle_t xTimer) { - if (sInstance.mFlags.Has(Flags::kFastAdvertisingEnabled)) + // If stop advertising fails (timeout on event wait), then + // rearm the timer as fast as possible to retry. + // Once stop advertising is successful, slow advertising can start. + auto err = sInstance.StopAdvertising(); + if (err != CHIP_NO_ERROR) { - ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertisement"); - - sInstance.mFlags.Clear(Flags::kFastAdvertisingEnabled); - // stop advertiser, change interval and restart it; - sInstance.StopAdvertising(); - sInstance.StartAdvertising(); + ChipLogDetail(DeviceLayer, "Stop advertising failed. Retrying..."); + StartBleAdvTimeoutTimer(portTICK_PERIOD_MS); + return; } - return; + sInstance.mFlags.Clear(Flags::kFastAdvertisingEnabled); + ChipLogDetail(DeviceLayer, "Start slow advertisement"); + sInstance.StartAdvertising(); } void BLEManagerImpl::CancelBleAdvTimeoutTimer(void) diff --git a/src/platform/nxp/k32w/k32w0/BUILD.gn b/src/platform/nxp/k32w/k32w0/BUILD.gn index f8f33dd6798c46..9e2a205d8e0ba6 100644 --- a/src/platform/nxp/k32w/k32w0/BUILD.gn +++ b/src/platform/nxp/k32w/k32w0/BUILD.gn @@ -88,16 +88,15 @@ static_library("k32w0") { "../common/OTATlvProcessor.h", ] - if (chip_enable_ota_default_processors == 1) { + if (chip_enable_ota_firmware_processor == 1) { sources += [ - "OTAApplicationProcessor.cpp", - "OTAApplicationProcessor.h", - "OTABootloaderProcessor.cpp", - "OTABootloaderProcessor.h", + "OTAFirmwareProcessor.cpp", + "OTAFirmwareProcessor.h", "OTAHooks.cpp", ] - if (chip_with_factory_data == 1) { + if (chip_with_factory_data == 1 && + chip_enable_ota_factory_data_processor == 1) { sources += [ "OTAFactoryDataProcessor.cpp", "OTAFactoryDataProcessor.h", diff --git a/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h b/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h index 5bd6c3199d3c1d..310a175fcf4cbf 100644 --- a/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h +++ b/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h @@ -104,14 +104,14 @@ #endif // CHIP_DEVICE_LAYER_OTA_REBOOT_DELAY /** - * @def CONFIG_CHIP_K32W0_OTA_DEFAULT_PROCESSORS + * @def CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR * - * Enables default OTA TLV processors. + * Enables default OTA TLV factory data processor. * Disabled by default. */ -#ifndef CONFIG_CHIP_K32W0_OTA_DEFAULT_PROCESSORS -#define CONFIG_CHIP_K32W0_OTA_DEFAULT_PROCESSORS 0 -#endif // CONFIG_CHIP_K32W0_OTA_DEFAULT_PROCESSORS +#ifndef CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#define CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR 0 +#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR /** * @def CHIP_DEVICE_LAYER_ENABLE_PDM_LOGS diff --git a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.cpp b/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.cpp index b58ecc6be850f7..b27bdec546e4d0 100644 --- a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.cpp +++ b/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.cpp @@ -80,6 +80,8 @@ CHIP_ERROR ConfigurationManagerImpl::Init() SuccessOrExit(err); } + rebootCause = POWER_GetResetCause(); + // Initialize the generic implementation base class. err = Internal::GenericConfigurationManagerImpl::Init(); SuccessOrExit(err); @@ -114,26 +116,25 @@ CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOp CHIP_ERROR ConfigurationManagerImpl::GetBootReason(uint32_t & bootReason) { - bootReason = to_underlying(BootReasonType::kUnspecified); - uint8_t reason = POWER_GetResetCause(); - - if (reason == RESET_UNDEFINED) + bootReason = to_underlying(BootReasonType::kUnspecified); + // rebootCause is obtained at bootup. + if (rebootCause == RESET_UNDEFINED) { bootReason = to_underlying(BootReasonType::kUnspecified); } - else if ((reason == RESET_POR) || (reason == RESET_EXT_PIN)) + else if ((rebootCause == RESET_POR) || (rebootCause == RESET_EXT_PIN)) { bootReason = to_underlying(BootReasonType::kPowerOnReboot); } - else if (reason == RESET_BOR) + else if (rebootCause == RESET_BOR) { bootReason = to_underlying(BootReasonType::kBrownOutReset); } - else if (reason == RESET_SW_REQ) + else if (rebootCause == RESET_SW_REQ) { bootReason = to_underlying(BootReasonType::kSoftwareReset); } - else if (reason == RESET_WDT) + else if (rebootCause == RESET_WDT) { bootReason = to_underlying(BootReasonType::kSoftwareWatchdogReset); /* Reboot can be due to hardware or software watchdog */ diff --git a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.h b/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.h index 61cd098ae606d3..4807162ee00ba9 100644 --- a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.h +++ b/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.h @@ -76,7 +76,7 @@ class ConfigurationManagerImpl final : public Internal::GenericConfigurationMana void RunConfigUnitTest(void) override; // ===== Private members reserved for use by this class only. - + uint8_t rebootCause; static void DoFactoryReset(intptr_t arg); }; diff --git a/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.cpp b/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.cpp index 34ef40e47b1351..96b8e663fe15aa 100644 --- a/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.cpp +++ b/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.cpp @@ -222,9 +222,22 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** uint8_t macBuffer[ConfigurationManager::kPrimaryMACAddressLength]; ConfigurationMgr().GetPrimary802154MACAddress(macBuffer); ifp->hardwareAddress = ByteSpan(macBuffer, ConfigurationManager::kPrimaryMACAddressLength); - *netifpp = ifp; + ifp->Next = nullptr; + + *netifpp = ifp; + return CHIP_NO_ERROR; } +void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp) +{ + while (netifp) + { + NetworkInterface * del = netifp; + netifp = netifp->Next; + delete del; + } +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.h b/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.h index 05be335999482b..2adbb1b2180a71 100644 --- a/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.h +++ b/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.h @@ -52,6 +52,7 @@ class DiagnosticDataProviderImpl : public DiagnosticDataProvider CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; CHIP_ERROR GetBootReason(BootReasonType & bootReason) override; CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override; + void ReleaseNetworkInterfaces(NetworkInterface * netifp) override; }; /** diff --git a/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.cpp b/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.cpp index 9bde35a7dcebc0..53533218cccf72 100644 --- a/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.cpp +++ b/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.cpp @@ -63,6 +63,37 @@ K32W0FactoryDataProvider & K32W0FactoryDataProvider::GetDefaultInstance() return sInstance; } +extern "C" WEAK CHIP_ERROR FactoryDataDefaultRestoreMechanism() +{ + CHIP_ERROR error = CHIP_NO_ERROR; + uint16_t backupLength = 0; + +#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR + // Check if PDM id related to factory data backup exists. + // If it does, it means an external event (such as a power loss) + // interrupted the factory data update process and the section + // from internal flash is most likely erased and should be restored. + if (PDM_bDoesDataExist(kNvmId_FactoryDataBackup, &backupLength)) + { + chip::Platform::ScopedMemoryBuffer buffer; + buffer.Calloc(K32W0FactoryDataProvider::kFactoryDataSize); + ReturnErrorCodeIf(buffer.Get() == nullptr, CHIP_ERROR_NO_MEMORY); + + auto status = PDM_eReadDataFromRecord(kNvmId_FactoryDataBackup, (void *) buffer.Get(), + K32W0FactoryDataProvider::kFactoryDataSize, &backupLength); + ReturnErrorCodeIf(PDM_E_STATUS_OK != status, CHIP_FACTORY_DATA_PDM_RESTORE); + + error = K32W0FactoryDataProvider::GetDefaultInstance().UpdateData(buffer.Get()); + if (error == CHIP_NO_ERROR) + { + ChipLogProgress(DeviceLayer, "Factory data was restored successfully"); + } + } +#endif + + return error; +} + K32W0FactoryDataProvider::K32W0FactoryDataProvider() { maxLengths[FactoryDataId::kVerifierId] = kSpake2pSerializedVerifier_MaxBase64Len; @@ -86,6 +117,8 @@ K32W0FactoryDataProvider::K32W0FactoryDataProvider() maxLengths[FactoryDataId::kPartNumber] = ConfigurationManager::kMaxPartNumberLength; maxLengths[FactoryDataId::kProductURL] = ConfigurationManager::kMaxProductURLLength; maxLengths[FactoryDataId::kProductLabel] = ConfigurationManager::kMaxProductLabelLength; + + RegisterRestoreMechanism(FactoryDataDefaultRestoreMechanism); } CHIP_ERROR K32W0FactoryDataProvider::Init() @@ -106,22 +139,43 @@ CHIP_ERROR K32W0FactoryDataProvider::Init() kFactoryDataSize); } - error = Validate(); + VerifyOrReturnError(mRestoreMechanisms.size() > 0, CHIP_FACTORY_DATA_RESTORE_MECHANISM); + + for (auto & restore : mRestoreMechanisms) + { + error = restore(); + if (error != CHIP_NO_ERROR) + { + continue; + } + + error = Validate(); + if (error != CHIP_NO_ERROR) + { + continue; + } + + break; + } + if (error != CHIP_NO_ERROR) { - ChipLogError(DeviceLayer, "Factory data validation failed with error: %s", ErrorStr(error)); - return error; + ChipLogError(DeviceLayer, "Factory data init failed with: %s", ErrorStr(error)); + } + else + { +#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR + PDM_vDeleteDataRecord(kNvmId_FactoryDataBackup); +#endif } - return CHIP_NO_ERROR; + return error; } CHIP_ERROR K32W0FactoryDataProvider::Validate() { uint8_t sha256Output[SHA256_HASH_SIZE] = { 0 }; - ReturnErrorOnFailure(Restore()); - auto status = OtaUtils_ReadFromInternalFlash((uint16_t) sizeof(Header), kFactoryDataStart, (uint8_t *) &mHeader, NULL, pFunctionEepromRead); ReturnErrorCodeIf(gOtaUtilsSuccess_c != status, CHIP_FACTORY_DATA_HEADER_READ); @@ -133,34 +187,9 @@ CHIP_ERROR K32W0FactoryDataProvider::Validate() return CHIP_NO_ERROR; } -CHIP_ERROR K32W0FactoryDataProvider::Restore() +void K32W0FactoryDataProvider::RegisterRestoreMechanism(RestoreMechanism restore) { - CHIP_ERROR error = CHIP_NO_ERROR; - uint16_t backupLength = 0; - - // Check if PDM id related to factory data backup exists. - // If it does, it means an external event (such as a power loss) - // interrupted the factory data update process and the section - // from internal flash is most likely erased and should be restored. - if (PDM_bDoesDataExist(kNvmId_FactoryDataBackup, &backupLength)) - { - chip::Platform::ScopedMemoryBuffer buffer; - buffer.Calloc(kFactoryDataSize); - ReturnErrorCodeIf(buffer.Get() == nullptr, CHIP_ERROR_NO_MEMORY); - - auto status = PDM_eReadDataFromRecord(kNvmId_FactoryDataBackup, (void *) buffer.Get(), kFactoryDataSize, &backupLength); - ReturnErrorCodeIf(PDM_E_STATUS_OK != status, CHIP_FACTORY_DATA_PDM_RESTORE); - - error = UpdateData(buffer.Get()); - if (CHIP_NO_ERROR == error) - { - PDM_vDeleteDataRecord(kNvmId_FactoryDataBackup); - } - } - - // TODO: add hook to enable restore customization - - return error; + mRestoreMechanisms.insert(mRestoreMechanisms.end(), restore); } CHIP_ERROR K32W0FactoryDataProvider::UpdateData(uint8_t * pBuf) @@ -469,19 +498,25 @@ CHIP_ERROR K32W0FactoryDataProvider::GetHardwareVersionString(char * buf, size_t CHIP_ERROR K32W0FactoryDataProvider::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) { - ChipError err = CHIP_ERROR_WRONG_KEY_TYPE; -#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) - char uniqueId[ConfigurationManager::kMaxUniqueIDLength] = { 0 }; - uint16_t uniqueIdLen = 0; - ReturnErrorOnFailure(SearchForId(FactoryDataId::kUniqueId, (uint8_t *) (&uniqueId[0]), sizeof(uniqueId), uniqueIdLen)); + CHIP_ERROR err = CHIP_ERROR_NOT_IMPLEMENTED; +#if CHIP_ENABLE_ROTATING_DEVICE_ID static_assert(ConfigurationManager::kRotatingDeviceIDUniqueIDLength >= ConfigurationManager::kMinRotatingDeviceIDUniqueIDLength, "Length of unique ID for rotating device ID is smaller than minimum."); + uint16_t uniqueIdLen = 0; + err = SearchForId(FactoryDataId::kUniqueId, (uint8_t *) uniqueIdSpan.data(), uniqueIdSpan.size(), uniqueIdLen); +#if defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + if (err != CHIP_NO_ERROR) + { + constexpr uint8_t uniqueId[] = CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID; - ReturnErrorCodeIf(uniqueIdLen > uniqueIdSpan.size(), CHIP_ERROR_BUFFER_TOO_SMALL); - ReturnErrorCodeIf(uniqueIdLen != ConfigurationManager::kRotatingDeviceIDUniqueIDLength, CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(uniqueIdSpan.data(), uniqueId, uniqueIdLen); + ReturnErrorCodeIf(sizeof(uniqueId) > uniqueIdSpan.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(uniqueIdSpan.data(), uniqueId, sizeof(uniqueId)); + uniqueIdLen = sizeof(uniqueId); + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID + ReturnErrorOnFailure(err); uniqueIdSpan.reduce_size(uniqueIdLen); - return CHIP_NO_ERROR; #endif return err; diff --git a/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.h b/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.h index 742a750b2fcc45..2cbfeb664dc7fa 100644 --- a/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.h +++ b/src/platform/nxp/k32w/k32w0/K32W0FactoryDataProvider.h @@ -28,6 +28,8 @@ #include "OtaUtils.h" #include "SecLib.h" +#include + /* Grab symbol for the base address from the linker file. */ extern uint32_t __FACTORY_DATA_START[]; extern uint32_t __FACTORY_DATA_SIZE[]; @@ -48,6 +50,7 @@ namespace DeviceLayer { #define CHIP_FACTORY_DATA_INTERNAL_FLASH_READ CHIP_FACTORY_DATA_ERROR(0x08) #define CHIP_FACTORY_DATA_PDM_SAVE_RECORD CHIP_FACTORY_DATA_ERROR(0x09) #define CHIP_FACTORY_DATA_PDM_READ_RECORD CHIP_FACTORY_DATA_ERROR(0x0A) +#define CHIP_FACTORY_DATA_RESTORE_MECHANISM CHIP_FACTORY_DATA_ERROR(0x0B) /** * @brief This class provides Commissionable data, Device Attestation Credentials, @@ -110,15 +113,17 @@ class K32W0FactoryDataProvider : public DeviceInstanceInfoProvider, static constexpr size_t kHashId = 0xCE47BA5E; typedef otaUtilsResult_t (*OtaUtils_EEPROM_ReadData)(uint16_t nbBytes, uint32_t address, uint8_t * pInbuf); - static uint8_t ReadDataMemcpy(uint16_t num, uint32_t src, uint8_t * dst); + using RestoreMechanism = CHIP_ERROR (*)(void); + + static uint8_t ReadDataMemcpy(uint16_t num, uint32_t src, uint8_t * dst); static K32W0FactoryDataProvider & GetDefaultInstance(); K32W0FactoryDataProvider(); CHIP_ERROR Init(); CHIP_ERROR Validate(); - CHIP_ERROR Restore(); + void RegisterRestoreMechanism(RestoreMechanism mechanism); CHIP_ERROR UpdateData(uint8_t * pBuf); CHIP_ERROR SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, uint32_t * offset = nullptr); @@ -159,6 +164,7 @@ class K32W0FactoryDataProvider : public DeviceInstanceInfoProvider, protected: uint16_t maxLengths[kNumberOfIds]; Header mHeader; + std::vector mRestoreMechanisms; }; } // namespace DeviceLayer diff --git a/src/platform/nxp/k32w/k32w0/OTABootloaderProcessor.cpp b/src/platform/nxp/k32w/k32w0/OTABootloaderProcessor.cpp deleted file mode 100644 index eafb57bba9bd40..00000000000000 --- a/src/platform/nxp/k32w/k32w0/OTABootloaderProcessor.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright (c) 2023 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#include "OtaSupport.h" -#include "OtaUtils.h" - -namespace chip { - -CHIP_ERROR OTABootloaderProcessor::Init() -{ - return CHIP_NO_ERROR; -} - -CHIP_ERROR OTABootloaderProcessor::Clear() -{ - return CHIP_NO_ERROR; -} - -CHIP_ERROR OTABootloaderProcessor::ProcessInternal(ByteSpan & block) -{ - return CHIP_NO_ERROR; -} - -CHIP_ERROR OTABootloaderProcessor::ApplyAction() -{ - return CHIP_NO_ERROR; -} - -CHIP_ERROR OTABootloaderProcessor::AbortAction() -{ - return CHIP_NO_ERROR; -} - -} // namespace chip diff --git a/src/platform/nxp/k32w/k32w0/OTABootloaderProcessor.h b/src/platform/nxp/k32w/k32w0/OTABootloaderProcessor.h deleted file mode 100644 index e4e428114c8110..00000000000000 --- a/src/platform/nxp/k32w/k32w0/OTABootloaderProcessor.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Copyright (c) 2023 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -namespace chip { - -struct BootLoaderDescriptor -{ - uint32_t version; - char versionString[kVersionStringSize]; - char buildDate[kBuildDateSize]; - uint32_t loadAddress; -}; - -class OTABootloaderProcessor : public OTATlvProcessor -{ -public: - CHIP_ERROR Init() override; - CHIP_ERROR Clear() override; - CHIP_ERROR ApplyAction() override; - CHIP_ERROR AbortAction() override; - -private: - CHIP_ERROR ProcessInternal(ByteSpan & block) override; -}; - -} // namespace chip diff --git a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp b/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp index 367d11d4ce2bf9..8a3a9b7b661779 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp +++ b/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp @@ -38,6 +38,7 @@ CHIP_ERROR OTAFactoryDataProcessor::Init() CHIP_ERROR OTAFactoryDataProcessor::Clear() { + OTATlvProcessor::ClearInternal(); mAccumulator.Clear(); mPayload.Clear(); ClearBuffer(); @@ -86,24 +87,22 @@ CHIP_ERROR OTAFactoryDataProcessor::ApplyAction() if (error != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "Failed to update factory data. Error: %s", ErrorStr(error)); - error = Restore(); - if (error == CHIP_NO_ERROR) - { - error = FactoryProvider::GetDefaultInstance().UpdateData(mFactoryData); - } } else { ChipLogProgress(DeviceLayer, "Factory data update finished."); } - ClearBuffer(); - return error; } CHIP_ERROR OTAFactoryDataProcessor::AbortAction() { + ReturnErrorOnFailure(Restore()); + ReturnErrorOnFailure(FactoryProvider::GetDefaultInstance().UpdateData(mFactoryData)); + + PDM_vDeleteDataRecord(kNvmId_FactoryDataBackup); + return CHIP_NO_ERROR; } @@ -207,11 +206,10 @@ void OTAFactoryDataProcessor::ClearBuffer() { if (mFactoryData) { + memset(mFactoryData, 0, FactoryProvider::kFactoryDataSize); chip::Platform::MemoryFree(mFactoryData); mFactoryData = nullptr; } - - PDM_vDeleteDataRecord(kNvmId_FactoryDataBackup); } CHIP_ERROR OTAFactoryDataProcessor::UpdateValue(uint8_t tag, ByteSpan & newValue) diff --git a/src/platform/nxp/k32w/k32w0/OTAApplicationProcessor.cpp b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp similarity index 64% rename from src/platform/nxp/k32w/k32w0/OTAApplicationProcessor.cpp rename to src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp index 9c78b705f0d852..cf26fc8c2149ea 100644 --- a/src/platform/nxp/k32w/k32w0/OTAApplicationProcessor.cpp +++ b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp @@ -18,36 +18,41 @@ #include #include -#include -#include +#include #include "OtaSupport.h" #include "OtaUtils.h" namespace chip { -CHIP_ERROR OTAApplicationProcessor::Init() +CHIP_ERROR OTAFirmwareProcessor::Init() { - mAccumulator.Init(sizeof(AppDescriptor)); - + ReturnErrorCodeIf(mCallbackProcessDescriptor == nullptr, CHIP_OTA_PROCESSOR_CB_NOT_REGISTERED); + mAccumulator.Init(sizeof(Descriptor)); ReturnErrorCodeIf(gOtaSuccess_c != OTA_ClientInit(), CHIP_OTA_PROCESSOR_CLIENT_INIT); - ReturnErrorCodeIf(gOtaSuccess_c != OTA_StartImage(mLength - sizeof(AppDescriptor)), CHIP_ERROR_INTERNAL); + + auto offset = OTA_GetCurrentEepromAddressOffset(); + if (offset != 0) + { + offset += 1; + } + + ReturnErrorCodeIf(OTA_UTILS_IMAGE_INVALID_ADDR == OTA_SetStartEepromOffset(offset), CHIP_OTA_PROCESSOR_EEPROM_OFFSET); + ReturnErrorCodeIf(gOtaSuccess_c != OTA_StartImage(mLength - sizeof(Descriptor)), CHIP_OTA_PROCESSOR_START_IMAGE); return CHIP_NO_ERROR; } -CHIP_ERROR OTAApplicationProcessor::Clear() +CHIP_ERROR OTAFirmwareProcessor::Clear() { + OTATlvProcessor::ClearInternal(); mAccumulator.Clear(); - mLength = 0; - mProcessedLength = 0; - mWasSelected = false; mDescriptorProcessed = false; return CHIP_NO_ERROR; } -CHIP_ERROR OTAApplicationProcessor::ProcessInternal(ByteSpan & block) +CHIP_ERROR OTAFirmwareProcessor::ProcessInternal(ByteSpan & block) { if (!mDescriptorProcessed) { @@ -71,11 +76,10 @@ CHIP_ERROR OTAApplicationProcessor::ProcessInternal(ByteSpan & block) return CHIP_OTA_FETCH_ALREADY_SCHEDULED; } -CHIP_ERROR OTAApplicationProcessor::ProcessDescriptor(ByteSpan & block) +CHIP_ERROR OTAFirmwareProcessor::ProcessDescriptor(ByteSpan & block) { ReturnErrorOnFailure(mAccumulator.Accumulate(block)); - - // TODO: use accumulator data in some way. What should be done with AppDescriptor data? + ReturnErrorOnFailure(mCallbackProcessDescriptor(static_cast(mAccumulator.data()))); mDescriptorProcessed = true; mAccumulator.Clear(); @@ -83,27 +87,38 @@ CHIP_ERROR OTAApplicationProcessor::ProcessDescriptor(ByteSpan & block) return CHIP_NO_ERROR; } -CHIP_ERROR OTAApplicationProcessor::ApplyAction() +CHIP_ERROR OTAFirmwareProcessor::ApplyAction() +{ + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFirmwareProcessor::AbortAction() +{ + OTA_CancelImage(); + OTA_ResetCustomEntries(); + OTA_ResetCurrentEepromAddress(); + OTA_SetStartEepromOffset(0); + Clear(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFirmwareProcessor::ExitAction() { if (OTA_CommitImage(NULL) != gOtaSuccess_c) { - ChipLogError(SoftwareUpdate, "Failed to commit application image."); + ChipLogError(SoftwareUpdate, "Failed to commit firmware image."); return CHIP_OTA_PROCESSOR_IMG_COMMIT; } if (OTA_ImageAuthenticate() != gOtaImageAuthPass_c) { - ChipLogError(SoftwareUpdate, "Failed to authenticate application image."); + ChipLogError(SoftwareUpdate, "Failed to authenticate firmware image."); return CHIP_OTA_PROCESSOR_IMG_AUTH; } - return CHIP_NO_ERROR; -} - -CHIP_ERROR OTAApplicationProcessor::AbortAction() -{ - OTA_CancelImage(); - Clear(); + OTA_AddNewImageFlag(); return CHIP_NO_ERROR; } diff --git a/src/platform/nxp/k32w/k32w0/OTAApplicationProcessor.h b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h similarity index 82% rename from src/platform/nxp/k32w/k32w0/OTAApplicationProcessor.h rename to src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h index c500eccff8c247..bc12394598ac89 100644 --- a/src/platform/nxp/k32w/k32w0/OTAApplicationProcessor.h +++ b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h @@ -23,20 +23,21 @@ namespace chip { -struct AppDescriptor -{ - uint32_t version; - char versionString[kVersionStringSize]; - char buildDate[kBuildDateSize]; -}; - -class OTAApplicationProcessor : public OTATlvProcessor +class OTAFirmwareProcessor : public OTATlvProcessor { public: + struct Descriptor + { + uint32_t version; + char versionString[kVersionStringSize]; + char buildDate[kBuildDateSize]; + }; + CHIP_ERROR Init() override; CHIP_ERROR Clear() override; CHIP_ERROR ApplyAction() override; CHIP_ERROR AbortAction() override; + CHIP_ERROR ExitAction() override; private: CHIP_ERROR ProcessInternal(ByteSpan & block) override; diff --git a/src/platform/nxp/k32w/k32w0/OTAHooks.cpp b/src/platform/nxp/k32w/k32w0/OTAHooks.cpp index 28b8f764aac59e..a00ae428a0f40d 100644 --- a/src/platform/nxp/k32w/k32w0/OTAHooks.cpp +++ b/src/platform/nxp/k32w/k32w0/OTAHooks.cpp @@ -19,37 +19,100 @@ #include #include +#include + #include -#include -#include -#if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA +#include +#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR #include -#endif // CONFIG_CHIP_K32W0_REAL_FACTORY_DATA +#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR #include "OtaSupport.h" +#ifndef CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST +#define CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST 0 +#endif + +#ifndef CONFIG_CHIP_K32W0_OTA_ABORT_HOOK +#define CONFIG_CHIP_K32W0_OTA_ABORT_HOOK 0 +#endif + extern "C" void ResetMCU(void); -static chip::OTAApplicationProcessor sApplicationProcessor; -static chip::OTABootloaderProcessor sBootloaderProcessor; -#if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA -static chip::OTAFactoryDataProcessor sFactoryDataProcessor; -#endif // CONFIG_CHIP_K32W0_REAL_FACTORY_DATA +CHIP_ERROR ProcessDescriptor(void * descriptor) +{ + auto desc = static_cast(descriptor); + ChipLogDetail(SoftwareUpdate, "Descriptor: %ld, %s, %s", desc->version, desc->versionString, desc->buildDate); + + return CHIP_NO_ERROR; +} extern "C" WEAK CHIP_ERROR OtaHookInit() { + static chip::OTAFirmwareProcessor sApplicationProcessor; + static chip::OTAFirmwareProcessor sBootloaderProcessor; +#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR + static chip::OTAFactoryDataProcessor sFactoryDataProcessor; +#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST + static chip::OTAFirmwareProcessor processors[8]; +#endif + + sApplicationProcessor.RegisterDescriptorCallback(ProcessDescriptor); + sBootloaderProcessor.RegisterDescriptorCallback(ProcessDescriptor); + auto & imageProcessor = chip::OTAImageProcessorImpl::GetDefaultInstance(); ReturnErrorOnFailure(imageProcessor.RegisterProcessor(1, &sApplicationProcessor)); ReturnErrorOnFailure(imageProcessor.RegisterProcessor(2, &sBootloaderProcessor)); -#if CONFIG_CHIP_K32W0_REAL_FACTORY_DATA +#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR ReturnErrorOnFailure(imageProcessor.RegisterProcessor(3, &sFactoryDataProcessor)); -#endif // CONFIG_CHIP_K32W0_REAL_FACTORY_DATA +#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST + for (auto i = 0; i < 8; i++) + { + processors[i].RegisterDescriptorCallback(ProcessDescriptor); + ReturnErrorOnFailure(imageProcessor.RegisterProcessor(i + 4, &processors[i])); + } +#endif // CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST return CHIP_NO_ERROR; } extern "C" WEAK void OtaHookReset() { - OTA_SetNewImageFlag(); + OTA_CommitCustomEntries(); ResetMCU(); } + +extern "C" WEAK void OtaHookAbort() +{ + /* + Disclaimer: This is not default behavior and it was not checked against + Matter specification compliance. You should use this at your own discretion. + + Use CONFIG_CHIP_K32W0_OTA_ABORT_HOOK to enable/disable this feature (disabled by default). + This hook is called inside OTAImageProcessorImpl::HandleAbort to schedule a retry (when enabled). + */ +#if CONFIG_CHIP_K32W0_OTA_ABORT_HOOK + auto & imageProcessor = chip::OTAImageProcessorImpl::GetDefaultInstance(); + auto & providerLocation = imageProcessor.GetBackupProvider(); + + if (providerLocation.HasValue()) + { + auto * requestor = chip::GetRequestorInstance(); + requestor->SetCurrentProviderLocation(providerLocation.Value()); + if (requestor->GetCurrentUpdateState() == chip::OTARequestorInterface::OTAUpdateStateEnum::kIdle) + { + chip::DeviceLayer::SystemLayer().ScheduleLambda([requestor] { requestor->TriggerImmediateQueryInternal(); }); + } + else + { + ChipLogError(SoftwareUpdate, "OTA requestor not in kIdle"); + } + } + else + { + ChipLogError(SoftwareUpdate, "Backup provider info not available"); + } +#endif +} diff --git a/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp b/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp index 289296c25d6d4d..771e2638a8a176 100644 --- a/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp +++ b/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp @@ -644,7 +644,7 @@ CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) secEcp256Status_t st; ecp256KeyPair_t * keypair; keypair = to_keypair(&mKeypair); - if ((st = ECP256_GenerateKeyPair(&keypair->public_key, &keypair->private_key)) != gSecEcp256Success_c) + if ((st = ECP256_GenerateKeyPair(&keypair->public_key, &keypair->private_key, NULL)) != gSecEcp256Success_c) { result = st; } @@ -918,7 +918,7 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FEGenerate(void * fe) ecp256Point_t PublicKey; ecp256Coordinate_t PrivateKey; - result = ECP256_GenerateKeyPair(&PublicKey, &PrivateKey); + result = ECP256_GenerateKeyPair(&PublicKey, &PrivateKey, NULL); Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); @@ -1016,19 +1016,19 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeL(uint8_t * Lout, size_t * L_le secEcp256Status_t result; uint8_t * p; - uint32_t W1[ECP256_COORDINATE_WLEN]; + uint32_t W1[SEC_ECP256_COORDINATE_WLEN]; do { result = ECP256_ModularReductionN(W1, w1in, w1in_len); if (result != gSecEcp256Success_c) break; ecp256Point_t gen_point; - result = ECP256_GeneratePublicKey((uint8_t *) &gen_point, (uint8_t *) &W1); + result = ECP256_GeneratePublicKey((uint8_t *) &gen_point, (uint8_t *) &W1, NULL); if (result != gSecEcp256Success_c) break; p = Lout; *p++ = 0x04; /* uncompressed format */ - memcpy(p, (uint8_t *) &gen_point, ECP256_COORDINATE_LEN * 2); + memcpy(p, (uint8_t *) &gen_point, SEC_ECP256_COORDINATE_LEN * 2); } while (0); exit: @@ -1461,7 +1461,7 @@ CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256P keypair = (ecp256KeyPair_t *) (mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(pk)).pk_ctx; Uint8::to_uchar(pubkey)[0] = 0x04; // uncompressed type - memcpy(Uint8::to_uchar(pubkey) + 1, keypair->public_key.raw, 2 * ECP256_COORDINATE_LEN); + memcpy(Uint8::to_uchar(pubkey) + 1, keypair->public_key.raw, 2 * SEC_ECP256_COORDINATE_LEN); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); diff --git a/third_party/nxp/k32w0_sdk/k32w0_sdk.gni b/third_party/nxp/k32w0_sdk/k32w0_sdk.gni index b9900540a79169..41e9761044106f 100644 --- a/third_party/nxp/k32w0_sdk/k32w0_sdk.gni +++ b/third_party/nxp/k32w0_sdk/k32w0_sdk.gni @@ -43,7 +43,10 @@ declare_args() { use_custom_factory_provider = 0 chip_crypto_flavor = "NXP-Ultrafast-P256" chip_reduce_ssbl_size = false - chip_enable_ota_default_processors = 1 + chip_enable_ota_firmware_processor = 1 + chip_enable_ota_factory_data_processor = 0 + chip_with_pdm_encryption = 1 + ota_custom_entry_address = "0x000C1000" } assert(k32w0_sdk_root != "", "k32w0_sdk_root must be specified") @@ -81,6 +84,16 @@ template("k32w0_sdk") { use_custom_factory_provider == 0 || chip_with_factory_data == 1, "Please set chip_with_factory_data=1 if using custom factory provider.") + assert( + chip_enable_ota_factory_data_processor == 0 || + chip_enable_ota_firmware_processor == 1, + "Please set chip_enable_ota_firmware_processor=1 if using default factory data processor.") + + assert( + chip_enable_ota_factory_data_processor == 0 || + chip_with_factory_data == 1, + "Please set chip_with_factory_data=1 if using default factory data processor.") + if (build_for_k32w041am == 1 || build_for_k32w041a == 1 || build_for_k32w041 == 1) { build_for_k32w061 = 0 @@ -125,7 +138,10 @@ template("k32w0_sdk") { print("increased TX power:", chip_with_high_power) print("FRO32k: ", use_fro_32k) print("low power: ", chip_with_low_power) - print("OTA default processors: ", chip_enable_ota_default_processors) + print("OTA default firmware processor: ", chip_enable_ota_firmware_processor) + print("OTA default factory data processor: ", + chip_enable_ota_factory_data_processor) + print("PDM Encryption: ", chip_with_pdm_encryption) if (chip_with_low_power == 1 && chip_logging == true) { print( @@ -237,15 +253,9 @@ template("k32w0_sdk") { "${k32w0_sdk_root}/middleware/wireless/ieee-802.15.4/lib/libMiniMac_Sched.a", "${k32w0_sdk_root}/middleware/wireless/framework/PDM/Library/libPDM_extFlash.a", "${k32w0_sdk_root}/middleware/wireless/framework/XCVR/lib/libRadio.a", + "${k32w0_sdk_root}/middleware/wireless/framework/SecLib/lib_crypto_m4.a", ] - if (chip_crypto == "platform" && - chip_crypto_flavor == "NXP-Ultrafast-P256") { - libs += [ "${k32w0_sdk_root}/middleware/wireless/framework/SecLib/lib_crypto_m4_dspext.a" ] - } else { - libs += [ "${k32w0_sdk_root}/middleware/wireless/framework/SecLib/lib_crypto_m4.a" ] - } - defines = [ "gPWR_CpuClk_48MHz=1", "gMainThreadPriority_c=5", @@ -262,7 +272,7 @@ template("k32w0_sdk") { "USE_SDK_OSA=0", "gSerialManagerMaxInterfaces_c=2", "FSL_RTOS_FREE_RTOS=1", - "gTotalHeapSize_c=0x10000", + "gTotalHeapSize_c=0xF000", "DEBUG_SERIAL_INTERFACE_INSTANCE=0", "APP_SERIAL_INTERFACE_INSTANCE=1", "gOTA_externalFlash_d=1", @@ -272,7 +282,6 @@ template("k32w0_sdk") { "gExternalFlashIsCiphered_d=1", "PDM_USE_DYNAMIC_MEMORY=1", "PDM_SAVE_IDLE=1", - "PDM_ENCRYPTION=1", "gBootData_None_c=1", "PROGRAM_PAGE_SZ=256", "configFRTOS_MEMORY_SCHEME=4", @@ -305,6 +314,21 @@ template("k32w0_sdk") { "gResetSystemReset_d=1", ] + # If OTA default processors are enabled, then OTA custom entry structure + # will be saved in external flash: gOTACustomOtaEntryMemory=OTACustomStorage_ExtFlash (1) + if (chip_enable_ota_firmware_processor == 1) { + defines += [ + "gOTAAllowCustomStartAddress=1", + "gOTAUseCustomOtaEntry=1", + "gOTACustomOtaEntryMemory=1", + "OTA_ENTRY_TOP_ADDR=${ota_custom_entry_address}", + ] + + if (chip_enable_ota_factory_data_processor == 1) { + defines += [ "CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR=1" ] + } + } + if (chip_crypto == "platform" && chip_crypto_flavor == "NXP-Ultrafast-P256") { defines += [ "EC_P256_DSPEXT=1" ] @@ -316,6 +340,12 @@ template("k32w0_sdk") { defines += [ "gClkUseFro32K=0" ] } + if (chip_with_pdm_encryption == 1) { + defines += [ "PDM_ENCRYPTION=1" ] + } else { + defines += [ "PDM_ENCRYPTION=0" ] + } + if (chip_mdns == "platform") { defines += [ "OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE=1", @@ -429,10 +459,6 @@ template("k32w0_sdk") { defines += [ "CONFIG_CHIP_K32W0_REAL_FACTORY_DATA=1" ] } - if (chip_enable_ota_default_processors == 1) { - defines += [ "CONFIG_CHIP_K32W0_OTA_DEFAULT_PROCESSORS=1" ] - } - if (defined(invoker.defines)) { defines += invoker.defines } diff --git a/third_party/nxp/k32w0_sdk/sdk_fixes/patch_k32w_sdk.sh b/third_party/nxp/k32w0_sdk/sdk_fixes/patch_k32w_sdk.sh index 9f7a1c517177a8..c9e048d64a4f39 100755 --- a/third_party/nxp/k32w0_sdk/sdk_fixes/patch_k32w_sdk.sh +++ b/third_party/nxp/k32w0_sdk/sdk_fixes/patch_k32w_sdk.sh @@ -15,5 +15,5 @@ convert_to_dos() { SOURCE=${BASH_SOURCE[0]} SOURCE_DIR=$(cd "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd) -echo "K32W0 SDK 2.6.9 no patch needed!" +echo "K32W0 SDK 2.6.11 no patch needed!" exit 0 diff --git a/third_party/openthread/ot-nxp b/third_party/openthread/ot-nxp index 4c2fa0d3d29c35..389c4776124c6d 160000 --- a/third_party/openthread/ot-nxp +++ b/third_party/openthread/ot-nxp @@ -1 +1 @@ -Subproject commit 4c2fa0d3d29c358fbdc57fa627ed2ba1e76dcdfc +Subproject commit 389c4776124c6dd887869cae060efa4eeccaf965