diff --git a/examples/lighting-app/infineon/cyw30739/README.md b/examples/lighting-app/infineon/cyw30739/README.md index 72753e2299f942..f085272b1c00d6 100644 --- a/examples/lighting-app/infineon/cyw30739/README.md +++ b/examples/lighting-app/infineon/cyw30739/README.md @@ -59,6 +59,24 @@ dataset and CASE credentials are then provided. $ rm -rf out/ ``` +## Building Options + +### DAC / DAC Key / PAI Certificate / Certificate Declaration + +Infineon CYW30739 examples use test certifications, keys, and CD by default. For +a production build, manufacturers can provision certifications, keys, and CD by +the following arguments: + +- `matter_dac`, `matter_dac_key`, `matter_pai`, `matter_cd` + + ```bash + $ ./scripts/examples/gn_build_example.sh examples/lighting-app/infineon/cyw30739 out/lighting-app \ + 'matter_dac="/path/to/dac.der"' \ + 'matter_dac_key="/path/to/dac_key.der"' \ + 'matter_pai="/path/to/pai.der"' \ + 'matter_cd="/path/to/cd.der"' + ``` + ## Flashing the Application ### Enter Recovery Mode diff --git a/examples/lighting-app/infineon/cyw30739/include/CHIPProjectConfig.h b/examples/lighting-app/infineon/cyw30739/include/CHIPProjectConfig.h index 27952f445fbba7..233ffd19da1e59 100644 --- a/examples/lighting-app/infineon/cyw30739/include/CHIPProjectConfig.h +++ b/examples/lighting-app/infineon/cyw30739/include/CHIPProjectConfig.h @@ -34,13 +34,13 @@ #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME "Infineon" /* The VendorID attribute of the Basic cluster. */ -#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF2 /* The ProductName attribute of the Basic cluster. */ #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME "CYW30739 Lighting App" /* The ProductID attribute of the Basic cluster. */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8005 +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8002 /* The HardwareVersionString attribute of the Basic cluster. */ #define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING "30739" diff --git a/examples/lighting-app/infineon/cyw30739/src/main.cpp b/examples/lighting-app/infineon/cyw30739/src/main.cpp index 639ca07595c304..74ff57aa959763 100644 --- a/examples/lighting-app/infineon/cyw30739/src/main.cpp +++ b/examples/lighting-app/infineon/cyw30739/src/main.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,8 @@ using namespace ::chip::DeviceLayer; using namespace ::chip::Shell; static chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; +static FactoryDataProvider sFactoryDataProvider; + static void InitApp(intptr_t args); static void LightManagerCallback(LightingManager::Actor_t actor, LightingManager::Action_t action, uint8_t value); @@ -196,7 +199,7 @@ void InitApp(intptr_t args) initParams.endpointNativeParams = static_cast(&nativeParams); chip::Server::GetInstance().Init(initParams); - SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + SetDeviceAttestationCredentialsProvider(&sFactoryDataProvider); LightMgr().Init(); LightMgr().SetCallbacks(LightManagerCallback, nullptr); diff --git a/examples/lighting-app/infineon/cyw30739/static_config.txt b/examples/lighting-app/infineon/cyw30739/static_config.txt deleted file mode 100644 index f256ac94aa5abf..00000000000000 --- a/examples/lighting-app/infineon/cyw30739/static_config.txt +++ /dev/null @@ -1,21 +0,0 @@ -# The post-building script uses this file to generate specified static configurations. -# All '#' prefixed lines are ignored by the script. -# Each line defines a static configuration by 3 fields separated by commas. -# -# The 1st field is a 16-bit ID from 0x2000 to 0x3ffff. -# All IDs in this file have to be different. -# -# The 2nd field is a type to which the script interprets the value according. -# -# The 3rd field is a value of the static configuration. The value format depends on what the value type is: -# - hex: Multiple hexadecimal values separated by commas. -# - uint32/uint16/uint8/int16/int8: A integer. -# - eui64: random or btext. If the value is btext, the configuration will be generated from the BT address. -# -# ID, type, value -# EUI64 -0x2000, eui64, random -# Setup Pin Code -0x2105, uint32, 20202021 -# Setup Discriminator -0x2107, uint32, 3840 diff --git a/examples/lock-app/infineon/cyw30739/README.md b/examples/lock-app/infineon/cyw30739/README.md index 12ac917071ce55..b91f4b9157e155 100644 --- a/examples/lock-app/infineon/cyw30739/README.md +++ b/examples/lock-app/infineon/cyw30739/README.md @@ -59,6 +59,24 @@ dataset and CASE credentials are then provided. $ rm -rf out/ ``` +## Building Options + +### DAC / DAC Key / PAI Certificate / Certificate Declaration + +Infineon CYW30739 examples use test certifications, keys, and CD by default. For +a production build, manufacturers can provision certifications, keys, and CD by +the following arguments: + +- `matter_dac`, `matter_dac_key`, `matter_pai`, `matter_cd` + + ```bash + $ ./scripts/examples/gn_build_example.sh examples/lighting-app/infineon/cyw30739 out/lighting-app \ + 'matter_dac="/path/to/dac.der"' \ + 'matter_dac_key="/path/to/dac_key.der"' \ + 'matter_pai="/path/to/pai.der"' \ + 'matter_cd="/path/to/cd.der"' + ``` + ## Flashing the Application ### Enter Recovery Mode diff --git a/examples/lock-app/infineon/cyw30739/include/CHIPProjectConfig.h b/examples/lock-app/infineon/cyw30739/include/CHIPProjectConfig.h index 1e0e565e402c10..40eedf4771147d 100644 --- a/examples/lock-app/infineon/cyw30739/include/CHIPProjectConfig.h +++ b/examples/lock-app/infineon/cyw30739/include/CHIPProjectConfig.h @@ -34,13 +34,13 @@ #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME "Infineon" /* The VendorID attribute of the Basic cluster. */ -#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF2 /* The ProductName attribute of the Basic cluster. */ #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME "CYW30739 Lock App" /* The ProductID attribute of the Basic cluster. */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8006 +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8002 /* The HardwareVersionString attribute of the Basic cluster. */ #define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING "30739" diff --git a/examples/lock-app/infineon/cyw30739/src/main.cpp b/examples/lock-app/infineon/cyw30739/src/main.cpp index 2f8bd88eeff599..2ecd230fad5ce6 100644 --- a/examples/lock-app/infineon/cyw30739/src/main.cpp +++ b/examples/lock-app/infineon/cyw30739/src/main.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,8 @@ using namespace CYW30739DoorLock::LockInitParams; wiced_bool_t syncClusterToButtonAction = false; static chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; +static FactoryDataProvider sFactoryDataProvider; + static void InitApp(intptr_t args); static void ActionInitiated(LockManager::Action_t aAction, int32_t aActor); static void ActionCompleted(LockManager::Action_t aAction); @@ -193,7 +196,7 @@ void InitApp(intptr_t args) initParams.endpointNativeParams = static_cast(&nativeParams); chip::Server::GetInstance().Init(initParams); - SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + SetDeviceAttestationCredentialsProvider(&sFactoryDataProvider); // Initial lock state chip::app::DataModel::Nullable state; diff --git a/examples/lock-app/infineon/cyw30739/static_config.txt b/examples/lock-app/infineon/cyw30739/static_config.txt deleted file mode 100644 index f256ac94aa5abf..00000000000000 --- a/examples/lock-app/infineon/cyw30739/static_config.txt +++ /dev/null @@ -1,21 +0,0 @@ -# The post-building script uses this file to generate specified static configurations. -# All '#' prefixed lines are ignored by the script. -# Each line defines a static configuration by 3 fields separated by commas. -# -# The 1st field is a 16-bit ID from 0x2000 to 0x3ffff. -# All IDs in this file have to be different. -# -# The 2nd field is a type to which the script interprets the value according. -# -# The 3rd field is a value of the static configuration. The value format depends on what the value type is: -# - hex: Multiple hexadecimal values separated by commas. -# - uint32/uint16/uint8/int16/int8: A integer. -# - eui64: random or btext. If the value is btext, the configuration will be generated from the BT address. -# -# ID, type, value -# EUI64 -0x2000, eui64, random -# Setup Pin Code -0x2105, uint32, 20202021 -# Setup Discriminator -0x2107, uint32, 3840 diff --git a/examples/ota-requestor-app/infineon/cyw30739/README.md b/examples/ota-requestor-app/infineon/cyw30739/README.md index 7ac0990009fbcd..0a55e93bf60a1d 100644 --- a/examples/ota-requestor-app/infineon/cyw30739/README.md +++ b/examples/ota-requestor-app/infineon/cyw30739/README.md @@ -60,6 +60,24 @@ dataset and CASE credentials are then provided. $ rm -rf out/ ``` +## Building Options + +### DAC / DAC Key / PAI Certificate / Certificate Declaration + +Infineon CYW30739 examples use test certifications, keys, and CD by default. For +a production build, manufacturers can provision certifications, keys, and CD by +the following arguments: + +- `matter_dac`, `matter_dac_key`, `matter_pai`, `matter_cd` + + ```bash + $ ./scripts/examples/gn_build_example.sh examples/lighting-app/infineon/cyw30739 out/lighting-app \ + 'matter_dac="/path/to/dac.der"' \ + 'matter_dac_key="/path/to/dac_key.der"' \ + 'matter_pai="/path/to/pai.der"' \ + 'matter_cd="/path/to/cd.der"' + ``` + ## Flashing the Application ### Enter Recovery Mode diff --git a/examples/ota-requestor-app/infineon/cyw30739/include/CHIPProjectConfig.h b/examples/ota-requestor-app/infineon/cyw30739/include/CHIPProjectConfig.h index 0ad812e4c28c54..f3f4c57bc244a3 100644 --- a/examples/ota-requestor-app/infineon/cyw30739/include/CHIPProjectConfig.h +++ b/examples/ota-requestor-app/infineon/cyw30739/include/CHIPProjectConfig.h @@ -34,13 +34,13 @@ #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME "Infineon" /* The VendorID attribute of the Basic cluster. */ -#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF2 /* The ProductName attribute of the Basic cluster. */ #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME "CYW30739 OTA Requestor App" /* The ProductID attribute of the Basic cluster. */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8008 +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8002 /* The HardwareVersionString attribute of the Basic cluster. */ #define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING "30739" diff --git a/examples/ota-requestor-app/infineon/cyw30739/src/main.cpp b/examples/ota-requestor-app/infineon/cyw30739/src/main.cpp index 6a8498cfbc0b55..d68f4c70eb0c7f 100644 --- a/examples/ota-requestor-app/infineon/cyw30739/src/main.cpp +++ b/examples/ota-requestor-app/infineon/cyw30739/src/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,8 @@ using namespace chip::Credentials; using namespace chip::DeviceLayer; using namespace chip::Shell; +static FactoryDataProvider sFactoryDataProvider; + static void InitApp(intptr_t args); APPLICATION_START() @@ -123,7 +126,7 @@ void InitApp(intptr_t args) initParams.endpointNativeParams = static_cast(&nativeParams); chip::Server::GetInstance().Init(initParams); - SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + SetDeviceAttestationCredentialsProvider(&sFactoryDataProvider); OTAConfig::Init(); } diff --git a/examples/ota-requestor-app/infineon/cyw30739/static_config.txt b/examples/ota-requestor-app/infineon/cyw30739/static_config.txt deleted file mode 100644 index f256ac94aa5abf..00000000000000 --- a/examples/ota-requestor-app/infineon/cyw30739/static_config.txt +++ /dev/null @@ -1,21 +0,0 @@ -# The post-building script uses this file to generate specified static configurations. -# All '#' prefixed lines are ignored by the script. -# Each line defines a static configuration by 3 fields separated by commas. -# -# The 1st field is a 16-bit ID from 0x2000 to 0x3ffff. -# All IDs in this file have to be different. -# -# The 2nd field is a type to which the script interprets the value according. -# -# The 3rd field is a value of the static configuration. The value format depends on what the value type is: -# - hex: Multiple hexadecimal values separated by commas. -# - uint32/uint16/uint8/int16/int8: A integer. -# - eui64: random or btext. If the value is btext, the configuration will be generated from the BT address. -# -# ID, type, value -# EUI64 -0x2000, eui64, random -# Setup Pin Code -0x2105, uint32, 20202021 -# Setup Discriminator -0x2107, uint32, 3840 diff --git a/scripts/requirements.infineon.txt b/scripts/requirements.infineon.txt new file mode 100644 index 00000000000000..bba66165a7654c --- /dev/null +++ b/scripts/requirements.infineon.txt @@ -0,0 +1 @@ +leb128 diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 21a3bb5f5cf0a0..7a1068059111ae 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -14,6 +14,9 @@ virtualenv # openiotsdk -r requirements.openiotsdk.txt +# Infineon +-r requirements.infineon.txt + # cirque tests requests>=2.24.0 diff --git a/src/platform/Infineon/CYW30739/BUILD.gn b/src/platform/Infineon/CYW30739/BUILD.gn index 9feef2ba2880e4..9759c32ede89b9 100644 --- a/src/platform/Infineon/CYW30739/BUILD.gn +++ b/src/platform/Infineon/CYW30739/BUILD.gn @@ -39,6 +39,8 @@ static_library("CYW30739") { "ConnectivityManagerImpl.h", "DiagnosticDataProviderImpl.cpp", "DiagnosticDataProviderImpl.h", + "FactoryDataProvider.cpp", + "FactoryDataProvider.h", "InetPlatformConfig.h", "KeyValueStoreManagerImpl.cpp", "KeyValueStoreManagerImpl.h", @@ -61,6 +63,12 @@ static_library("CYW30739") { deps = [ "${chip_root}/src/crypto" ] + public = [ + "${chip_root}/src/credentials/DeviceAttestationCredsProvider.h", + "FactoryDataProvider.h", + "OTAImageProcessorImpl.h", + ] + public_deps = [ "${chip_root}/src/platform:platform_base" ] if (chip_enable_openthread) { diff --git a/src/platform/Infineon/CYW30739/CYW30739Config.cpp b/src/platform/Infineon/CYW30739/CYW30739Config.cpp index 651b4fb3cb40b4..15438ceb18e446 100644 --- a/src/platform/Infineon/CYW30739/CYW30739Config.cpp +++ b/src/platform/Infineon/CYW30739/CYW30739Config.cpp @@ -24,8 +24,6 @@ #include #include -#include -#include namespace chip { namespace DeviceLayer { @@ -58,10 +56,14 @@ CHIP_ERROR CYW30739Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t buf CHIP_ERROR CYW30739Config::ReadConfigValueBin(Key key, void * buf, size_t bufSize, size_t & outLen) { wiced_result_t result; - uint16_t read_count = wiced_hal_read_nvram(PLATFORM_NVRAM_VSID_MATTER_BASE + key, bufSize, (uint8_t *) buf, &result); - if (kMinConfigKey_ChipFactory <= key && key <= kMaxConfigKey_ChipFactory && result != WICED_SUCCESS) + uint16_t read_count; + if (kMinConfigKey_ChipFactory <= key && key <= kMaxConfigKey_ChipFactory) { - read_count = wiced_hal_read_nvram_static(PLATFORM_NVRAM_SSID_MATTER_BASE + key, bufSize, buf, &result); + read_count = wiced_hal_read_nvram_static(key, bufSize, buf, &result); + } + else + { + read_count = wiced_hal_read_nvram(key, bufSize, (uint8_t *) buf, &result); } if (result == WICED_SUCCESS) { @@ -124,7 +126,7 @@ CHIP_ERROR CYW30739Config::WriteConfigValueBin(Key key, const void * data, size_ } wiced_result_t result; - const uint16_t write_count = wiced_hal_write_nvram(PLATFORM_NVRAM_VSID_MATTER_BASE + key, dataLen, (uint8_t *) data, &result); + const uint16_t write_count = wiced_hal_write_nvram(key, dataLen, (uint8_t *) data, &result); if (result == WICED_SUCCESS && write_count == dataLen) return CHIP_NO_ERROR; @@ -135,7 +137,7 @@ CHIP_ERROR CYW30739Config::WriteConfigValueBin(Key key, const void * data, size_ CHIP_ERROR CYW30739Config::ClearConfigValue(Key key) { wiced_result_t result; - wiced_hal_delete_nvram(PLATFORM_NVRAM_VSID_MATTER_BASE + key, &result); + wiced_hal_delete_nvram(key, &result); if (result == WICED_SUCCESS) { return CHIP_NO_ERROR; diff --git a/src/platform/Infineon/CYW30739/CYW30739Config.h b/src/platform/Infineon/CYW30739/CYW30739Config.h index a2f318a1ed6017..80f0895e10687e 100644 --- a/src/platform/Infineon/CYW30739/CYW30739Config.h +++ b/src/platform/Infineon/CYW30739/CYW30739Config.h @@ -28,13 +28,15 @@ #include +#include + namespace chip { namespace DeviceLayer { namespace Internal { -constexpr inline uint32_t CYW30739ConfigKey(uint8_t keyBaseOffset, uint8_t id) +constexpr inline uint32_t CYW30739ConfigKey(uint16_t keyBaseOffset, uint8_t id) { - return static_cast(keyBaseOffset) << 8 | id; + return keyBaseOffset | id; } /** @@ -45,10 +47,10 @@ class CYW30739Config public: using Key = uint32_t; - static constexpr uint8_t kChipFactory_KeyBase = 0x00; - static constexpr uint8_t kChipConfig_KeyBase = 0x01; - static constexpr uint8_t kChipKvsValue_KeyBase = 0x02; - static constexpr uint8_t kChipKvsKey_KeyBase = 0x03; + static constexpr uint16_t kChipFactory_KeyBase = PLATFORM_NVRAM_SSID_MATTER_BASE; + static constexpr uint16_t kChipConfig_KeyBase = PLATFORM_NVRAM_VSID_MATTER_BASE + 0x0000; + static constexpr uint16_t kChipKvsValue_KeyBase = PLATFORM_NVRAM_VSID_MATTER_BASE + 0x0100; + static constexpr uint16_t kChipKvsKey_KeyBase = PLATFORM_NVRAM_VSID_MATTER_BASE + 0x0200; // Key definitions for well-known keys. // Factory config keys @@ -63,6 +65,10 @@ class CYW30739Config static constexpr Key kConfigKey_Spake2pIterationCount = CYW30739ConfigKey(kChipFactory_KeyBase, 0x08); static constexpr Key kConfigKey_Spake2pSalt = CYW30739ConfigKey(kChipFactory_KeyBase, 0x09); static constexpr Key kConfigKey_Spake2pVerifier = CYW30739ConfigKey(kChipFactory_KeyBase, 0x0a); + static constexpr Key kConfigKey_DAC = CYW30739ConfigKey(kChipFactory_KeyBase, 0x0b); + static constexpr Key kConfigKey_DACKey = CYW30739ConfigKey(kChipFactory_KeyBase, 0x0c); + static constexpr Key kConfigKey_PAICert = CYW30739ConfigKey(kChipFactory_KeyBase, 0x0d); + static constexpr Key kConfigKey_CertDeclaration = CYW30739ConfigKey(kChipFactory_KeyBase, 0x0e); // CHIP Config Keys static constexpr Key kConfigKey_ServiceConfig = CYW30739ConfigKey(kChipConfig_KeyBase, 0x00); static constexpr Key kConfigKey_PairedAccountId = CYW30739ConfigKey(kChipConfig_KeyBase, 0x01); @@ -87,9 +93,9 @@ class CYW30739Config // Set key id limits for each group. static constexpr Key kMinConfigKey_ChipFactory = CYW30739ConfigKey(kChipFactory_KeyBase, 0x00); - static constexpr Key kMaxConfigKey_ChipFactory = CYW30739ConfigKey(kChipFactory_KeyBase, 0x0a); + static constexpr Key kMaxConfigKey_ChipFactory = CYW30739ConfigKey(kChipFactory_KeyBase, 0xff); static constexpr Key kMinConfigKey_ChipConfig = CYW30739ConfigKey(kChipConfig_KeyBase, 0x00); - static constexpr Key kMaxConfigKey_ChipConfig = CYW30739ConfigKey(kChipConfig_KeyBase, 0x13); + static constexpr Key kMaxConfigKey_ChipConfig = CYW30739ConfigKey(kChipConfig_KeyBase, 0xff); static CHIP_ERROR Init(void); diff --git a/src/platform/Infineon/CYW30739/FactoryDataProvider.cpp b/src/platform/Infineon/CYW30739/FactoryDataProvider.cpp new file mode 100644 index 00000000000000..8d12b16a4be04a --- /dev/null +++ b/src/platform/Infineon/CYW30739/FactoryDataProvider.cpp @@ -0,0 +1,127 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * 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 "FactoryDataProvider.h" + +#include +#include + +namespace chip { +namespace DeviceLayer { + +using namespace chip::DeviceLayer::Internal; + +CHIP_ERROR FactoryDataProvider::GetCertificationDeclaration(MutableByteSpan & out_cd_buffer) +{ + size_t read_size; + ReturnErrorOnFailure(CYW30739Config::ReadConfigValueBin(CYW30739Config::kConfigKey_CertDeclaration, out_cd_buffer.data(), + out_cd_buffer.size(), read_size)); + out_cd_buffer.reduce_size(read_size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) +{ + out_firmware_info_buffer.reduce_size(0); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer) +{ + size_t read_size; + ReturnErrorOnFailure(CYW30739Config::ReadConfigValueBin(CYW30739Config::kConfigKey_DAC, out_dac_buffer.data(), + out_dac_buffer.size(), read_size)); + out_dac_buffer.reduce_size(read_size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer) +{ + size_t read_size; + ReturnErrorOnFailure(CYW30739Config::ReadConfigValueBin(CYW30739Config::kConfigKey_PAICert, out_pai_buffer.data(), + out_pai_buffer.size(), read_size)); + out_pai_buffer.reduce_size(read_size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, + MutableByteSpan & out_signature_buffer) +{ + Crypto::P256ECDSASignature signature; + Crypto::P256Keypair keypair; + + VerifyOrReturnError(IsSpanUsable(out_signature_buffer), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsSpanUsable(message_to_sign), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_signature_buffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + + uint8_t dac_key_buffer[128]; + MutableByteSpan dac_key_span(dac_key_buffer); + ReturnErrorOnFailure(GetDeviceAttestationCertKey(dac_key_span)); + ReturnErrorOnFailure(LoadKeypairFromDer(dac_key_span, keypair)); + ReturnErrorOnFailure(keypair.ECDSA_sign_msg(message_to_sign.data(), message_to_sign.size(), signature)); + + return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, out_signature_buffer); +} + +CHIP_ERROR FactoryDataProvider::GetDeviceAttestationCertKey(MutableByteSpan & out_key_buffer) +{ + size_t read_size; + ReturnErrorOnFailure(CYW30739Config::ReadConfigValueBin(CYW30739Config::kConfigKey_DACKey, out_key_buffer.data(), + out_key_buffer.size(), read_size)); + out_key_buffer.reduce_size(read_size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::LoadKeypairFromDer(const ByteSpan & der_buffer, Crypto::P256Keypair & keypair) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int mbedtls_result = 0; + mbedtls_pk_context pk; + mbedtls_ecp_keypair * ecp; + Crypto::P256SerializedKeypair serializedKeypair; + MutableByteSpan public_key(serializedKeypair.Bytes(), Crypto::kP256_PublicKey_Length); + MutableByteSpan private_key(serializedKeypair.Bytes() + Crypto::kP256_PublicKey_Length, Crypto::kP256_PrivateKey_Length); + + mbedtls_pk_init(&pk); + mbedtls_result = mbedtls_pk_parse_key(&pk, der_buffer.data(), der_buffer.size(), nullptr, 0); + VerifyOrExit(mbedtls_result == 0, error = CHIP_ERROR_INTERNAL); + + ecp = mbedtls_pk_ec(pk); + VerifyOrExit(ecp != nullptr, error = CHIP_ERROR_INTERNAL); + + size_t key_length; + mbedtls_result = mbedtls_ecp_point_write_binary(&ecp->grp, &ecp->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &key_length, public_key.data(), + public_key.size()); + VerifyOrExit(mbedtls_result == 0 && key_length == Crypto::kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL); + + mbedtls_result = mbedtls_ecp_write_key(ecp, private_key.data(), private_key.size()); + VerifyOrExit(mbedtls_result == 0, error = CHIP_ERROR_INTERNAL); + + SuccessOrExit(serializedKeypair.SetLength(public_key.size() + private_key.size())); + SuccessOrExit(keypair.Deserialize(serializedKeypair)); + +exit: + if (mbedtls_result != 0) + { + ChipLogError(Crypto, "mbedtls result: 0x%04x", mbedtls_result); + } + mbedtls_pk_free(&pk); + return error; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Infineon/CYW30739/FactoryDataProvider.h b/src/platform/Infineon/CYW30739/FactoryDataProvider.h new file mode 100644 index 00000000000000..6fc22b9c96e20e --- /dev/null +++ b/src/platform/Infineon/CYW30739/FactoryDataProvider.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * 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 { +namespace DeviceLayer { + +class FactoryDataProvider : public chip::Credentials::DeviceAttestationCredentialsProvider +{ +public: + // ===== Members functions that implement the DeviceAttestationCredentialsProvider + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & out_cd_buffer) override; + CHIP_ERROR GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) override; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer) override; + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, MutableByteSpan & out_signature_buffer) override; + +private: + CHIP_ERROR GetDeviceAttestationCertKey(MutableByteSpan & out_key_buffer); + CHIP_ERROR LoadKeypairFromDer(const ByteSpan & der_buffer, Crypto::P256Keypair & keypair); +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/third_party/infineon/cyw30739_sdk/cyw30739_executable.gni b/third_party/infineon/cyw30739_sdk/cyw30739_executable.gni index eed0f9341befa5..0251a1d5805fce 100644 --- a/third_party/infineon/cyw30739_sdk/cyw30739_executable.gni +++ b/third_party/infineon/cyw30739_sdk/cyw30739_executable.gni @@ -29,7 +29,6 @@ template("cyw30739_executable") { flashable_target = "${target_name}.flashable" pre_build_target = "${target_name}.pre_build" post_build_target = "${target_name}.post_build" - ota_image_target = "${target_name}.ota_image" cyw30739_sdk_pre_build(pre_build_target) { } @@ -38,18 +37,11 @@ template("cyw30739_executable") { executable_target = "${flashable_target}.executable" } - cyw30739_sdk_ota_image(ota_image_target) { - deps = [ ":${post_build_target}" ] - } - group(target_name) { - deps = [ ":${flashable_target}" ] - - if (chip_enable_ota_requestor) { - deps += [ ":${ota_image_target}" ] - } else { - deps += [ ":${post_build_target}" ] - } + deps = [ + ":${flashable_target}", + ":${post_build_target}", + ] } # Copy flashing dependencies to the output directory so that the output diff --git a/third_party/infineon/cyw30739_sdk/cyw30739_sdk.gni b/third_party/infineon/cyw30739_sdk/cyw30739_sdk.gni index 7bed70cf01ec28..4e560cf89f26c4 100644 --- a/third_party/infineon/cyw30739_sdk/cyw30739_sdk.gni +++ b/third_party/infineon/cyw30739_sdk/cyw30739_sdk.gni @@ -23,6 +23,18 @@ declare_args() { cyw30739_sdk_root = "${cyw30739_sdk_build_root}/repos" cyw30739_sdk_verbose = false cyw30739_sdk_debug = 0 + + # Matter DAC in the DER format. + matter_dac = "${chip_root}/credentials/test/attestation/Chip-Test-DAC-FFF2-8002-0010-Cert.der" + + # Matter DAC EC key in the DER format. + matter_dac_key = "${chip_root}/credentials/test/attestation/Chip-Test-DAC-FFF2-8002-0010-Key.der" + + # Matter PAI certificate in the DER format. + matter_pai = "${chip_root}/credentials/test/attestation/Chip-Test-PAI-FFF2-NoPID-Cert.der" + + # Matter Certification Declaration in the DER format. + matter_cd = "${chip_root}/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001-8002.der" } assert(cyw30739_sdk_root != "", "cyw30739_sdk_root must be specified") @@ -257,12 +269,14 @@ template("cyw30739_sdk_post_build") { output_base_path = "${root_out_dir}/${invoker.output_base_name}" elf = "${output_base_path}.elf" hex = "${output_base_path}_download.hex" + ss_hex = "${output_base_path}.ss.hex" ds_hex = "${output_base_path}.ds.hex" xs_hex = "${output_base_path}.xs.hex" + ss_hdf = "${output_base_path}.ss.hdf" ss_cgs = "${output_base_path}.ss.cgs" + empty_cgs = "${output_base_path}.empty.cgs" cgs = "${output_base_path}.cgs" cx_cgs = "${output_base_path}.cx.cgs" - static_config = "${output_base_path}.static_config.txt" hdf = "${root_out_dir}/configdef30739A0.hdf" patched_cgs_args = @@ -284,33 +298,89 @@ template("cyw30739_sdk_post_build") { cgs_args += string_split(arg) } - action(target_name) { + group(target_name) { + deps = [ ":${target_name}_merge_hex" ] + if (chip_enable_ota_requestor) { + deps += [ ":${target_name}_ota_image" ] + } + + data_deps = [ + ":${target_name}_btp", + ":${target_name}_disassemble", + ":${target_name}_hci_id", + ":${target_name}_minidriver", + ] + } + + action("${target_name}_merge_hex") { + config_header = + "${chip_root}/src/platform/Infineon/CYW30739/CYW30739Config.h" + script = "${cyw30739_sdk_build_root}/merge_hex.py" outputs = [ hex ] sources = [ + config_header, ds_hex, + matter_cd, + matter_dac, + matter_dac_key, + matter_pai, + ss_hex, xs_hex, ] args = [ "--output=" + rebase_path(hex, root_build_dir), + "--ss_hex=" + rebase_path(ss_hex, root_build_dir), "--ds_hex=" + rebase_path(ds_hex, root_build_dir), "--xs_hex=" + rebase_path(xs_hex, root_build_dir), + "--config_header=" + rebase_path(config_header, root_build_dir), + "--config=DAC:file:" + rebase_path(matter_dac, root_build_dir), + "--config=DACKey:file:" + rebase_path(matter_dac_key, root_build_dir), + "--config=PAICert:file:" + rebase_path(matter_pai, root_build_dir), + "--config=CertDeclaration:file:" + rebase_path(matter_cd, root_build_dir), ] + foreach(arg, cgs_args) { + options = [] + options = string_split(arg, ":") + if (options[0] == "DLConfigBD_ADDRBase") { + args += [ "--config=ExtendedAddress:address:" + options[1] ] + } + } deps = [ - ":${target_name}_gen_ds_hex", - ":${target_name}_gen_xs_hex", + ":${invoker.target_name}_gen_ds_hex", + ":${invoker.target_name}_gen_ss_hex", + ":${invoker.target_name}_gen_xs_hex", ] + } - data_deps = [ - ":${target_name}_btp", - ":${target_name}_disassemble", - ":${target_name}_hci_id", - ":${target_name}_minidriver", + action("${target_name}_gen_ss_hex") { + script = "${build_root}/gn_run_binary.py" + + outputs = [ ss_hex ] + + sources = [ + cyw30739_sdk_btp_file, + empty_cgs, ] + + args = [ + rebase_path("${cyw30739_sdk_tools_dir}/CGS/cgs", root_build_dir), + "-D", + rebase_path(root_out_dir, root_build_dir), + "-I", + rebase_path(ss_hex, root_build_dir), + "-B", + rebase_path(cyw30739_sdk_btp_file, root_build_dir), + "--cgs-files", + rebase_path(empty_cgs, root_build_dir), + ] + args += cgs_args + + deps = [ ":${invoker.target_name}_gen_ss_cgs" ] } action("${target_name}_gen_ds_hex") { @@ -325,9 +395,10 @@ template("cyw30739_sdk_post_build") { sources = [ cx_cgs, cyw30739_sdk_btp_file, - ss_cgs, ] + inputs = [ hdf ] + args = [ rebase_path("${cyw30739_sdk_tools_dir}/CGS/cgs", root_build_dir), "-D", @@ -338,16 +409,15 @@ template("cyw30739_sdk_post_build") { rebase_path(ds_hex, root_build_dir), "-B", rebase_path(cyw30739_sdk_btp_file, root_build_dir), - "--ss-cgs", - rebase_path(ss_cgs, root_build_dir), "--cgs-files", rebase_path(cx_cgs, root_build_dir), + "--paramoverride", + "DLConfigFixedHeader:0", ] - args += cgs_args deps = [ ":${invoker.target_name}_compress_cgs_data", - ":${invoker.target_name}_gen_ss_cgs", + ":${invoker.target_name}_hdf", ] } @@ -387,37 +457,19 @@ template("cyw30739_sdk_post_build") { } action("${target_name}_gen_ss_cgs") { - hdf_in = "${cyw30739_sdk_baselib_dir}/internal/30739A0/configdef30739A0.hdf" - - script_file = "${cyw30739_sdk_scripts_dir}/wiced-gen-ss-cgs.pl" - - script = "${build_root}/gn_run_binary.py" - - inputs = [ script_file ] - - sources = [ - hdf_in, - static_config, - ] + script = "${cyw30739_sdk_build_root}/scripts/gen_ss_cgs.py" outputs = [ - hdf, + ss_hdf, ss_cgs, + empty_cgs, ] args = [ - "perl", - "-I", - rebase_path(cyw30739_sdk_scripts_dir, root_build_dir), - rebase_path(script_file, root_build_dir), - "config=" + rebase_path(static_config, root_build_dir), - "hdf_in=" + rebase_path(hdf_in, root_build_dir), - "hdf_out=" + rebase_path(hdf, root_build_dir), - "cgs_out=" + rebase_path(ss_cgs, root_build_dir), + "--ss_hdf=" + rebase_path(ss_hdf, root_build_dir), + "--ss_cgs=" + rebase_path(ss_cgs, root_build_dir), + "--empty_cgs=" + rebase_path(empty_cgs, root_build_dir), ] - args += cgs_args - - deps = [ ":${invoker.target_name}_static_config" ] } action("${target_name}_gen_cgs") { @@ -454,7 +506,7 @@ template("cyw30739_sdk_post_build") { deps = [ ":${invoker.executable_target}", ":${invoker.pre_build_target}", - ":${invoker.target_name}_gen_ss_cgs", + ":${invoker.target_name}_hdf", ] } @@ -480,16 +532,17 @@ template("cyw30739_sdk_post_build") { deps = [ ":${invoker.executable_target}" ] } - copy("${target_name}_static_config") { - sources = [ "static_config.txt" ] - outputs = [ static_config ] - } - copy("${target_name}_btp") { sources = [ "${cyw30739_sdk_btp_file}" ] outputs = [ "${output_base_path}.btp" ] } + copy("${target_name}_hdf") { + sources = + [ "${cyw30739_sdk_baselib_dir}/internal/30739A0/configdef30739A0.hdf" ] + outputs = [ hdf ] + } + copy("${target_name}_hci_id") { sources = [ "${cyw30739_sdk_platform_dir}/IDFILE.txt" ] outputs = [ "${output_base_path}_hci_id.txt" ] @@ -501,24 +554,23 @@ template("cyw30739_sdk_post_build") { } write_file("${root_out_dir}/chipload_flags.txt", "-NOHCIRESET") -} - -template("cyw30739_sdk_ota_image") { - action(target_name) { - forward_variables_from(invoker, [ "deps" ]) + action("${target_name}_ota_image") { script = "${cyw30739_sdk_build_root}/gen_ota_image.py" - binary = "${root_out_dir}/${invoker.output_base_name}.bin" - hex = "${root_out_dir}/${invoker.output_base_name}_download.hex" + binary = "${output_base_path}.bin" outputs = [ binary ] - inputs = [ hex ] + sources = [ + ds_hex, + xs_hex, + ] args = [ "--binary=" + rebase_path(binary, root_build_dir), - "--hex=" + rebase_path(hex, root_build_dir), + "--ds_hex=" + rebase_path(ds_hex, root_build_dir), + "--xs_hex=" + rebase_path(xs_hex, root_build_dir), "--lzss_tool=" + rebase_path(cyw30739_sdk_tools_dir + "/lzss/lzss", root_build_dir), "--active_xs_len=${btp.ConfigXS1Length}", @@ -528,5 +580,10 @@ template("cyw30739_sdk_ota_image") { "--ota_image_tool=" + rebase_path("${chip_root}/src/app/ota_image_tool.py", root_build_dir), ] + + deps = [ + ":${invoker.target_name}_gen_ds_hex", + ":${invoker.target_name}_gen_xs_hex", + ] } } diff --git a/third_party/infineon/cyw30739_sdk/gen_ota_image.py b/third_party/infineon/cyw30739_sdk/gen_ota_image.py index 2b86d9423b5bd8..aa7755287525bf 100644 --- a/third_party/infineon/cyw30739_sdk/gen_ota_image.py +++ b/third_party/infineon/cyw30739_sdk/gen_ota_image.py @@ -16,7 +16,7 @@ # """OTA image generator -This script generates OTA image file from the input hex file. +This script generates OTA image file from the input hex files. The XS data would be compressed into OTA image with the given LZSS tool. @@ -35,7 +35,8 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument("--binary", required=True, type=pathlib.Path) - parser.add_argument("--hex", required=True, type=pathlib.Path) + parser.add_argument("--ds_hex", required=True, type=pathlib.Path) + parser.add_argument("--xs_hex", required=True, type=pathlib.Path) parser.add_argument("--lzss_tool", required=True, type=pathlib.Path) parser.add_argument("--active_xs_len", required=True, type=lambda x: int(x, 0)) @@ -46,8 +47,9 @@ def main(): option = parser.parse_args() - intel_hex = IntelHex(str(option.hex)) - ds_segment, xs_segment = intel_hex.segments()[1:3] + intel_hex = IntelHex(str(option.ds_hex)) + intel_hex.loadhex(str(option.xs_hex)) + ds_segment, xs_segment = intel_hex.segments()[0:2] ds_header = intel_hex.tobinarray( start=ds_segment[0], end=ds_segment[0] + 0x10 - 1) diff --git a/third_party/infineon/cyw30739_sdk/merge_hex.py b/third_party/infineon/cyw30739_sdk/merge_hex.py index 8cf30eb2a526ad..387b741a00d2e9 100644 --- a/third_party/infineon/cyw30739_sdk/merge_hex.py +++ b/third_party/infineon/cyw30739_sdk/merge_hex.py @@ -16,30 +16,129 @@ # """Hex file merger -This is a helper script for merging DS and XS into a single hex file. +This is a helper script for merging SS, DS and XS into a single hex file. """ import argparse +import os import pathlib +import re import sys +import zlib +import leb128 +from collections import OrderedDict from intelhex import IntelHex +from struct import pack, unpack + +THREAD_FACTORY_KEY_BASE = 0x2000 +MATTER_FACTORY_KEY_BASE = 0x2100 def main(): + args = parse_args() + + configs = gen_thread_factory_config() + configs.update(gen_matter_factory_config(args.config_header)) + + parse_config_args(configs, args.config) + + merged_hex = insert_config(IntelHex(str(args.ss_hex)), configs) + merged_hex.merge(IntelHex(str(args.ds_hex))) + merged_hex.merge(IntelHex(str(args.xs_hex))) + merged_hex.write_hex_file(args.output) + + +def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("--output", required=True, type=pathlib.Path) + parser.add_argument("--ss_hex", required=True, type=pathlib.Path) parser.add_argument("--ds_hex", required=True, type=pathlib.Path) parser.add_argument("--xs_hex", required=True, type=pathlib.Path) + parser.add_argument("--config_header", required=True, type=pathlib.Path) + parser.add_argument("--config", action="append", type=str) + return parser.parse_args() + + +def gen_thread_factory_config() -> OrderedDict: + configs = OrderedDict() + configs["ExtendedAddress"] = {"key": THREAD_FACTORY_KEY_BASE, "value": os.urandom(8)} + return configs + + +def gen_matter_factory_config(path: pathlib.Path) -> OrderedDict: + # compile the regex for extracting name and key of factory configurations. + factory_config_re = re.compile(r""" + .* # Prefix + kConfigKey_(\w+) # Parse the config name + \s*=.* # Allow spaces + kChipFactory_KeyBase # Only match factory configurations + \s*,\s* # Allow spaces + (0x[0-9a-fA-F]+) # Parse the config key + """, re.VERBOSE) + + configs = OrderedDict() + with open(str(path), mode="r") as config_file: + for line in config_file: + match = factory_config_re.match(line.strip()) + if match: + name = match[1] + key = MATTER_FACTORY_KEY_BASE + int(match[2], 0) + configs[name] = {"key": key} + return configs + + +def parse_config_args(configs: OrderedDict, args: list): + for arg in args: + name, category, value = arg.split(":") + + if name not in configs: + print(f"[Warning] Ignored unknown config: {name}") + continue + + if category == "address": + addr = bytearray.fromhex(value) + + if len(addr) == 6: + # RFC 4291 Appendix A + addr[3:3] = b'\xff\xfe' + elif len(addr) != 8: + print(f"[Warning] Ignored config {name}: Invalid length: {len(addr)}") + return + + configs[name]["value"] = addr[::-1] + elif category == "file": + with open(value, mode="rb") as file: + configs[name]["value"] = file.read() + else: + print(f"[Warning] Ignored config {name}: Invalid category: {category}") + + +def insert_config(origin_hex: IntelHex, configs: OrderedDict): + ss_segment = origin_hex.segments()[0] + + origin_ss_header = origin_hex.tobinarray( + start=ss_segment[0], end=ss_segment[0] + 0x10 - 1) + origin_ss_data = origin_hex.tobinarray( + start=ss_segment[0] + 0x10, end=ss_segment[1] - 1) + + signature, _, _ = unpack("<8sLL", origin_ss_header) + + ss_data = bytearray() + for config in configs.values(): + if "value" in config: + ss_data += config["key"].to_bytes(2, byteorder="little") + ss_data += leb128.u.encode(len(config["value"])) + ss_data += config["value"] + ss_data += origin_ss_data - option = parser.parse_args() + ss_header = pack("<8sLL", signature, zlib.crc32(ss_data), len(ss_data)) - ds_hex = IntelHex(str(option.ds_hex)) - xs_hex = IntelHex(str(option.xs_hex)) - ds_hex.merge(xs_hex) - ds_hex.write_hex_file(option.output) + ss_hex = IntelHex() + ss_hex.puts(ss_segment[0], ss_header + ss_data) + return ss_hex if __name__ == "__main__": - sys.exit(main()) + main() diff --git a/third_party/infineon/cyw30739_sdk/scripts/gen_ss_cgs.py b/third_party/infineon/cyw30739_sdk/scripts/gen_ss_cgs.py new file mode 100644 index 00000000000000..41758d0c9becc3 --- /dev/null +++ b/third_party/infineon/cyw30739_sdk/scripts/gen_ss_cgs.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# +# Copyright (c) 2022 Project CHIP Authors +# +# 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. +# +"""SS CGS generator + +This script generates SS CGS and HDF files. + +""" + +import argparse +import io +import os +import pathlib +import sys + +from collections import OrderedDict + +THREAD_FACTORY_KEY_BASE = 0x2000 +MATTER_FACTORY_KEY_BASE = 0x2100 + + +def main(): + args = parse_args() + + configs = gen_thread_factory_config() + + gen_ss_hdf(args.ss_hdf, configs) + gen_ss_cgs(args.ss_cgs, args.ss_hdf, configs) + gen_empty_cgs(args.empty_cgs, args.ss_hdf, configs) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--ss_hdf", required=True, type=pathlib.Path) + parser.add_argument("--ss_cgs", required=True, type=pathlib.Path) + parser.add_argument("--empty_cgs", required=True, type=pathlib.Path) + return parser.parse_args() + + +def gen_thread_factory_config() -> OrderedDict: + configs = OrderedDict() + configs["ExtendedAddress"] = {"key": THREAD_FACTORY_KEY_BASE, "value": os.urandom(8)} + return configs + + +def gen_ss_hdf(path: pathlib.Path, configs: OrderedDict): + with open(str(path), mode="w") as hdf: + hdf.write("""\ +SECTION "Config Data Entries" 0 +{ +""") + for name, config in configs.items(): + if "value" in config: + write_hdf_command(hdf, name, config["key"]) + + hdf.write("}") + + +def write_hdf_command(hdf: io.TextIOBase, name: str, key: int): + hdf.write(f"""\ + COMMAND "{name}" {key:#x} + {{ + PARAM "Data" + uint8[0xff00] omit_pad_bytes; + }} +""") + + +def gen_ss_cgs(cgs_path: pathlib.Path, hdf_path: pathlib.Path, configs: OrderedDict): + with open(str(cgs_path), mode="w") as cgs: + write_cgs_header(cgs, hdf_path) + + for name, config in configs.items(): + if "value" in config: + write_cgs_data(cgs, name, config["value"]) + + +def gen_empty_cgs(cgs_path: pathlib.Path, hdf_path: pathlib.Path, configs: OrderedDict): + with open(str(cgs_path), mode="w") as cgs: + write_cgs_header(cgs, hdf_path) + + for name, config in configs.items(): + if "value" in config: + write_cgs_data(cgs, name) + break + + +def write_cgs_header(cgs: io.TextIOBase, hdf_path: pathlib.Path): + cgs.write(f"""\ +# DO NOT EDIT MANUALLY! FW2 VERSION INCLUDESSCRC32 INCLUDEDSCRC32 +DEFINITION <{hdf_path}> +""") + + +def write_cgs_data(cgs: io.TextIOBase, name: str, data: bytes = b""): + cgs.write(f"""\ +ENTRY "{name}" +{{ + "Data" = + COMMENTED_BYTES + {{ + +""") + + indent = " " + for i in range(0, len(data), 16): + cgs.write(indent + data[i:i+16].hex(' ') + "\n") + + cgs.write("""\ + } END_COMMENTED_BYTES +} +""") + + +if __name__ == "__main__": + main()