From 40071463724cd4895a03444fb7ab1a4aff909ffe Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Tue, 7 Dec 2021 03:11:32 +0800 Subject: [PATCH] ESP32: Add OTARequstor to all-clusters-app (#12360) * Add OTARequstor to all-clusters-app on ESP32 platform * Change the expected clientList value in Test Suites * If the uart driver is installed, skip intalling the uart driver --- config/esp32/components/chip/CMakeLists.txt | 14 +- .../all-clusters-common/all-clusters-app.zap | 12 +- .../esp32/main/Kconfig.projbuild | 9 + .../all-clusters-app/esp32/partitions.csv | 4 +- .../all-clusters-app/esp32/sdkconfig.defaults | 6 +- .../esp32/sdkconfig_c3devkit.defaults | 6 +- .../esp32/sdkconfig_m5stack.defaults | 7 +- .../esp32/sdkconfig_m5stack_rpc.defaults | 8 +- .../tests/suites/TestDescriptorCluster.yaml | 4 +- .../Framework/CHIPTests/CHIPClustersTests.m | 3 +- src/lib/shell/commands/BUILD.gn | 6 + src/lib/shell/commands/DFUManager_esp32.h | 147 +++++++++++++ src/lib/shell/commands/OTAUpdater_esp32.h | 148 +++++++++++++ src/lib/shell/commands/Ota.cpp | 25 ++- src/lib/shell/streamer_esp32.cpp | 8 +- src/platform/ESP32/InetPlatformConfig.h | 1 + .../zap-generated/CHIPClientCallbacks.cpp | 159 ++++++++++++++ .../zap-generated/CHIPClientCallbacks.h | 25 +++ .../zap-generated/CHIPClusters.cpp | 199 +++++++++++++++++ .../zap-generated/CHIPClusters.h | 41 ++++ .../zap-generated/IMClusterCommandHandler.cpp | 207 +++++++++++++++--- .../PluginApplicationCallbacks.h | 1 + .../zap-generated/endpoint_config.h | 7 +- .../zap-generated/gen_config.h | 5 + .../chip-tool/zap-generated/test/Commands.h | 4 +- 25 files changed, 989 insertions(+), 67 deletions(-) create mode 100644 src/lib/shell/commands/DFUManager_esp32.h create mode 100644 src/lib/shell/commands/OTAUpdater_esp32.h diff --git a/config/esp32/components/chip/CMakeLists.txt b/config/esp32/components/chip/CMakeLists.txt index 455732465136c7..d45d7f365de625 100644 --- a/config/esp32/components/chip/CMakeLists.txt +++ b/config/esp32/components/chip/CMakeLists.txt @@ -29,15 +29,7 @@ if(NOT CHIP_ROOT) get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. REALPATH) endif() -set(CHIP_REQURIE_COMPONENTS freertos lwip bt mdns mbedtls fatfs) - -if (CONFIG_ENABLE_CHIP_SHELL) - list(APPEND CHIP_REQURIE_COMPONENTS console) -endif() - -if (CONFIG_OPENTHREAD_ENABLED) - list(APPEND CHIP_REQURIE_COMPONENTS openthread) -endif() +set(CHIP_REQURIE_COMPONENTS freertos lwip bt mdns mbedtls fatfs app_update console openthread) if (NOT CMAKE_BUILD_EARLY_EXPANSION) if (CONFIG_COMPILER_OPTIMIZATION_DEFAULT OR CONFIG_COMPILER_OPTIMIZATION_NONE) @@ -107,6 +99,10 @@ if (CONFIG_OPENTHREAD_ENABLED) chip_gn_arg_append("chip_enable_openthread" "true") endif() +if (CONFIG_ENABLE_OTA_REQUESTOR) + chip_gn_arg_append("chip_enable_ota_requestor" "true") +endif() + set(args_gn_input "${CMAKE_CURRENT_BINARY_DIR}/args.gn.in") file(GENERATE OUTPUT "${args_gn_input}" CONTENT "${chip_gn_args}") diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index bf4d1e74527fee..ae660f17ab49a4 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -1382,14 +1382,14 @@ "mfgCode": null, "define": "OTA_PROVIDER_CLUSTER", "side": "client", - "enabled": 0, + "enabled": 1, "commands": [ { "name": "QueryImage", "code": 0, "mfgCode": null, "source": "client", - "incoming": 1, + "incoming": 0, "outgoing": 1 }, { @@ -1397,7 +1397,7 @@ "code": 1, "mfgCode": null, "source": "client", - "incoming": 1, + "incoming": 0, "outgoing": 1 }, { @@ -1405,7 +1405,7 @@ "code": 2, "mfgCode": null, "source": "client", - "incoming": 1, + "incoming": 0, "outgoing": 1 } ], @@ -1415,12 +1415,12 @@ "code": 65533, "mfgCode": null, "side": "client", - "included": 1, + "included": 0, "storageOption": "RAM", "singleton": 0, "bounded": 0, "defaultValue": "0x0001", - "reportable": 1, + "reportable": 0, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 diff --git a/examples/all-clusters-app/esp32/main/Kconfig.projbuild b/examples/all-clusters-app/esp32/main/Kconfig.projbuild index 0960168aadca4a..e82f04f2ac00e5 100644 --- a/examples/all-clusters-app/esp32/main/Kconfig.projbuild +++ b/examples/all-clusters-app/esp32/main/Kconfig.projbuild @@ -140,3 +140,12 @@ depends on ENABLE_PW_RPC about available pin numbers for UART. endmenu + +menu "OTA Options" + + config ENABLE_OTA_REQUESTOR + bool "Enable OTA Requestor" + default y + help + Enable this option to enable the OTA Requestor +endmenu diff --git a/examples/all-clusters-app/esp32/partitions.csv b/examples/all-clusters-app/esp32/partitions.csv index 665b8fe311bd5e..43acef25d0245d 100644 --- a/examples/all-clusters-app/esp32/partitions.csv +++ b/examples/all-clusters-app/esp32/partitions.csv @@ -1,6 +1,8 @@ # Name, Type, SubType, Offset, Size, Flags # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x6000, +otadata, data, ota, , 0x2000, phy_init, data, phy, , 0x1000, -factory, app, factory, , 1900K, +ota_0, app, ota_0, , 1500K, +ota_1, app, ota_1, , 1500K, ot_storage, data, 0x3a, , 0x2000, diff --git a/examples/all-clusters-app/esp32/sdkconfig.defaults b/examples/all-clusters-app/esp32/sdkconfig.defaults index 3da9d42e2bc2f3..a3a17d6ef7c47d 100644 --- a/examples/all-clusters-app/esp32/sdkconfig.defaults +++ b/examples/all-clusters-app/esp32/sdkconfig.defaults @@ -36,7 +36,7 @@ CONFIG_LWIP_IPV6_AUTOCONFIG=y # Use a custom partition table CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" # Vendor and product id CONFIG_DEVICE_VENDOR_ID=0x235A @@ -49,3 +49,7 @@ CONFIG_ENABLE_CHIP_SHELL=y #enable lwIP route hooks CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Serial Flasher config +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" diff --git a/examples/all-clusters-app/esp32/sdkconfig_c3devkit.defaults b/examples/all-clusters-app/esp32/sdkconfig_c3devkit.defaults index 39f7907c458080..737935b166f98f 100644 --- a/examples/all-clusters-app/esp32/sdkconfig_c3devkit.defaults +++ b/examples/all-clusters-app/esp32/sdkconfig_c3devkit.defaults @@ -38,8 +38,12 @@ CONFIG_LWIP_IPV6_AUTOCONFIG=y # Use a custom partition table CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" #enable lwIP route hooks CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Serial Flasher config +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" diff --git a/examples/all-clusters-app/esp32/sdkconfig_m5stack.defaults b/examples/all-clusters-app/esp32/sdkconfig_m5stack.defaults index 334cfe1b611cba..5c318378f51189 100644 --- a/examples/all-clusters-app/esp32/sdkconfig_m5stack.defaults +++ b/examples/all-clusters-app/esp32/sdkconfig_m5stack.defaults @@ -38,7 +38,7 @@ CONFIG_LWIP_IPV6_AUTOCONFIG=y # Use a custom partition table CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" # Vendor and product id CONFIG_DEVICE_VENDOR_ID=0x235A @@ -54,3 +54,8 @@ CONFIG_ENABLE_CHIP_SHELL=y #enable lwIP route hooks CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Serial Flasher config +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" + diff --git a/examples/all-clusters-app/esp32/sdkconfig_m5stack_rpc.defaults b/examples/all-clusters-app/esp32/sdkconfig_m5stack_rpc.defaults index 2da74647c0f5fc..75142a9c7c54c6 100644 --- a/examples/all-clusters-app/esp32/sdkconfig_m5stack_rpc.defaults +++ b/examples/all-clusters-app/esp32/sdkconfig_m5stack_rpc.defaults @@ -38,7 +38,7 @@ CONFIG_LWIP_IPV6_AUTOCONFIG=y # Use a custom partition table CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" # Vendor and product id CONFIG_DEVICE_VENDOR_ID=0x235A @@ -56,4 +56,8 @@ CONFIG_EXAMPLE_UART_TXD=1 CONFIG_ENABLE_PW_RPC=y # Disable shell -CONFIG_ENABLE_CHIP_SHELL=n \ No newline at end of file +CONFIG_ENABLE_CHIP_SHELL=n + +# Serial Flasher config +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" diff --git a/src/app/tests/suites/TestDescriptorCluster.yaml b/src/app/tests/suites/TestDescriptorCluster.yaml index a5d060b220d21f..fcc43768ecc833 100644 --- a/src/app/tests/suites/TestDescriptorCluster.yaml +++ b/src/app/tests/suites/TestDescriptorCluster.yaml @@ -60,7 +60,9 @@ tests: command: "readAttribute" attribute: "Client List" response: - value: [] + value: [ + 0x0029, # OTA Software Update Provider + ] - label: "Read attribute Parts list" command: "readAttribute" diff --git a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m index ac4d77dce7c208..4896ed12d1021f 100644 --- a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m @@ -29889,7 +29889,8 @@ - (void)testSendClusterTestDescriptorCluster_000003_ReadAttribute { id actualValue = value; - XCTAssertEqual([actualValue count], 0); + XCTAssertEqual([actualValue count], 1); + XCTAssertEqual([actualValue[0] unsignedIntValue], 41UL); } [expectation fulfill]; diff --git a/src/lib/shell/commands/BUILD.gn b/src/lib/shell/commands/BUILD.gn index 37dab9d07a7d63..85766987f32a3f 100644 --- a/src/lib/shell/commands/BUILD.gn +++ b/src/lib/shell/commands/BUILD.gn @@ -58,6 +58,12 @@ source_set("commands") { if (chip_device_platform == "nrfconnect") { sources += [ "DFUManager_nrfconnect.h" ] } + if (chip_device_platform == "esp32") { + sources += [ + "DFUManager_esp32.h", + "OTAUpdater_esp32.h", + ] + } } if (chip_device_platform != "none") { diff --git a/src/lib/shell/commands/DFUManager_esp32.h b/src/lib/shell/commands/DFUManager_esp32.h new file mode 100644 index 00000000000000..e18c4e04cfe3d2 --- /dev/null +++ b/src/lib/shell/commands/DFUManager_esp32.h @@ -0,0 +1,147 @@ +/* + * + * Copyright (c) 2021 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 "OTAUpdater_esp32.h" +#include "platform/ESP32/ESP32Utils.h" +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace Shell { + +class DFUManager : public bdx::Initiator +{ +public: + void SetInitialExchange(Messaging::ExchangeContext * ec) { mExchangeCtx = ec; } + CHIP_ERROR ApplyUpdate(); + CHIP_ERROR DiscardUpdate(); + +private: + void HandleTransferSessionOutput(bdx::TransferSession::OutputEvent & event) override; + + uint8_t mDfuBuffer[1024]; + bool mIsTransferComplete = false; +}; + +inline CHIP_ERROR DFUManager::ApplyUpdate() +{ + return DeviceLayer::Internal::ESP32Utils::MapError(OTAUpdater::GetInstance().Apply()); +} + +inline CHIP_ERROR DFUManager::DiscardUpdate() +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +inline void DFUManager::HandleTransferSessionOutput(bdx::TransferSession::OutputEvent & event) +{ + using OutputEventType = bdx::TransferSession::OutputEventType; + using MessageType = bdx::MessageType; + using SendMessageFlags = Messaging::SendMessageFlags; + + CHIP_ERROR err = CHIP_NO_ERROR; + + if (event.EventType != OutputEventType::kNone) + { + ChipLogDetail(BDX, "OutputEvent type: %s", event.ToString(event.EventType)); + } + + switch (event.EventType) + { + case OutputEventType::kNone: + if (mIsTransferComplete) + { + ChipLogProgress(BDX, "Transfer complete!"); + OTAUpdater::GetInstance().End(); + mTransfer.Reset(); + mIsTransferComplete = false; + } + break; + case OutputEventType::kMsgToSend: { + Messaging::SendFlags sendFlags; + VerifyOrReturn(mExchangeCtx != nullptr, ChipLogError(BDX, "mExchangeContext is null, cannot proceed")); + sendFlags.Set(SendMessageFlags::kFromInitiator, event.msgTypeData.MessageType == to_underlying(MessageType::ReceiveInit)); + sendFlags.Set(SendMessageFlags::kExpectResponse, event.msgTypeData.MessageType != to_underlying(MessageType::BlockAckEOF)); + err = mExchangeCtx->SendMessage(event.msgTypeData.ProtocolId, event.msgTypeData.MessageType, std::move(event.MsgData), + sendFlags); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "SendMessage() failed: %" CHIP_ERROR_FORMAT, err.Format())); + break; + } + case OutputEventType::kAcceptReceived: { + VerifyOrReturn(CHIP_NO_ERROR == mTransfer.PrepareBlockQuery(), ChipLogError(BDX, "PrepareBlockQuery failed")); + break; + } + case OutputEventType::kBlockReceived: { + ChipLogDetail(BDX, "Got block length %zu", event.blockdata.Length); + if (OTAUpdater::GetInstance().IsInProgress() == false) + { + OTAUpdater::GetInstance().Begin(); + } + // TODO: Process/skip the Matter OTA header + OTAUpdater::GetInstance().Write(reinterpret_cast(event.blockdata.Data), event.blockdata.Length); + if (event.blockdata.IsEof) + { + err = mTransfer.PrepareBlockAck(); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "PrepareBlockAck failed: %" CHIP_ERROR_FORMAT, err.Format())); + mIsTransferComplete = true; + } + else + { + err = mTransfer.PrepareBlockQuery(); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "PrepareBlockQuery failed: %" CHIP_ERROR_FORMAT, err.Format())); + } + break; + } + case OutputEventType::kStatusReceived: { + ChipLogError(BDX, "Got StatusReport %x", static_cast(event.statusData.statusCode)); + OTAUpdater::GetInstance().Abort(); + mTransfer.Reset(); + mExchangeCtx->Close(); + break; + } + case OutputEventType::kInternalError: { + ChipLogError(BDX, "Transfer stopped due to internal error"); + OTAUpdater::GetInstance().Abort(); + mTransfer.Reset(); + mExchangeCtx->Close(); + break; + } + case OutputEventType::kTransferTimeout: { + ChipLogError(BDX, "Transfer timed out"); + OTAUpdater::GetInstance().Abort(); + mTransfer.Reset(); + mExchangeCtx->Close(); + break; + } + case OutputEventType::kInitReceived: + case OutputEventType::kAckReceived: + case OutputEventType::kQueryReceived: + case OutputEventType::kAckEOFReceived: + default: + ChipLogError(BDX, "Unexpected BDX event type: %" PRIu16, static_cast(event.EventType)); + } +} + +} // namespace Shell +} // namespace chip diff --git a/src/lib/shell/commands/OTAUpdater_esp32.h b/src/lib/shell/commands/OTAUpdater_esp32.h new file mode 100644 index 00000000000000..53e10e951ff3b5 --- /dev/null +++ b/src/lib/shell/commands/OTAUpdater_esp32.h @@ -0,0 +1,148 @@ +/* + * + * Copyright (c) 2021 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 "esp_err.h" +#include "esp_log.h" +#include "esp_ota_ops.h" +#include "esp_system.h" + +static const char * TAG = "OTAUpdater"; + +class OTAUpdater +{ +public: + static OTAUpdater & GetInstance(void) + { + static OTAUpdater instance; + return instance; + } + bool IsInProgress(void) { return otaUpdateInProgress; } + esp_err_t Begin(void); + esp_err_t End(void); + esp_err_t Write(const void * data, size_t length); + esp_err_t Abort(void); + esp_err_t Apply(); + +private: + bool otaUpdateInProgress = false; + const esp_partition_t * otaUpdatePartition = nullptr; + esp_ota_handle_t otaUpdateHandle; + uint32_t otaUpdateImageLen = 0; + + OTAUpdater(void) {} + ~OTAUpdater() {} +}; + +inline esp_err_t OTAUpdater::Begin(void) +{ + if (otaUpdateInProgress) + { + ESP_LOGW(TAG, "Already in progress"); + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "Begin OTA"); + otaUpdatePartition = esp_ota_get_next_update_partition(NULL); + if (otaUpdatePartition == NULL) + { + ESP_LOGE(TAG, "Partition not found"); + return ESP_ERR_NOT_FOUND; + } + ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", otaUpdatePartition->subtype, otaUpdatePartition->address); + + esp_err_t err = esp_ota_begin(otaUpdatePartition, OTA_WITH_SEQUENTIAL_WRITES, &otaUpdateHandle); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); + return err; + } + otaUpdateImageLen = 0; + otaUpdateInProgress = true; + return ESP_OK; +} + +inline esp_err_t OTAUpdater::Write(const void * data, size_t length) +{ + if (otaUpdateInProgress == false) + { + return ESP_ERR_INVALID_STATE; + } + esp_err_t err = esp_ota_write(otaUpdateHandle, data, length); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err)); + Abort(); + return err; + } + otaUpdateImageLen += length; + ESP_LOGI(TAG, "Written image length %d", otaUpdateImageLen); + return ESP_OK; +} + +inline esp_err_t OTAUpdater::Abort(void) +{ + if (otaUpdateInProgress == false) + { + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "OTA Abort"); + otaUpdateInProgress = false; + otaUpdateImageLen = 0; + return esp_ota_abort(otaUpdateHandle); +} + +inline esp_err_t OTAUpdater::End(void) +{ + if (otaUpdateInProgress == false) + { + return ESP_ERR_INVALID_STATE; + } + ESP_LOGI(TAG, "OTA image length %d bytes", otaUpdateImageLen); + esp_err_t err = esp_ota_end(otaUpdateHandle); + if (err != ESP_OK) + { + if (err == ESP_ERR_OTA_VALIDATE_FAILED) + { + ESP_LOGE(TAG, "Image validation failed, image is corrupted"); + } + else + { + ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err)); + } + } + otaUpdateInProgress = false; + return err; +} + +inline esp_err_t OTAUpdater::Apply() +{ + if (otaUpdateInProgress == true) + { + return ESP_ERR_INVALID_STATE; + } + + esp_err_t err = esp_ota_set_boot_partition(otaUpdatePartition); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); + return err; + } + ESP_LOGI(TAG, "Applying, Boot partition set offset:0x%x", otaUpdatePartition->address); + return ESP_OK; +} diff --git a/src/lib/shell/commands/Ota.cpp b/src/lib/shell/commands/Ota.cpp index d6fa03951b3c08..7581c32e572795 100644 --- a/src/lib/shell/commands/Ota.cpp +++ b/src/lib/shell/commands/Ota.cpp @@ -37,8 +37,10 @@ #include "DFUManager_nrfconnect.h" #endif +#if CHIP_DEVICE_LAYER_TARGET_ESP32 +#include "DFUManager_esp32.h" +#endif #include -#include using namespace chip; using namespace chip::app; @@ -167,7 +169,16 @@ void OnQueryImageFailure(void * /* context */, EmberAfStatus status) ChipLogError(SoftwareUpdate, "QueryImage failed: %" PRIu16, static_cast(status)); } -void OnQueryImageConnection(void * /* context */, DeviceProxy * deviceProxy) +} // namespace +} // namespace Shell +} // namespace chip + +#include +namespace chip { +namespace Shell { +namespace { + +void OnQueryImageConnection(void * /* context */, OperationalDeviceProxy * deviceProxy) { // Initialize cluster object Controller::OtaSoftwareUpdateProviderCluster cluster; @@ -187,8 +198,8 @@ void OnQueryImageConnection(void * /* context */, DeviceProxy * deviceProxy) DeviceLayer::ConfigurationMgr().GetVendorId(vendorId); DeviceLayer::ConfigurationMgr().GetProductId(productId); - DeviceLayer::ConfigurationMgr().GetProductRevision(hardwareVersion); - DeviceLayer::ConfigurationMgr().GetFirmwareRevision(softwareVersion); + DeviceLayer::ConfigurationMgr().GetHardwareVersion(hardwareVersion); + DeviceLayer::ConfigurationMgr().GetSoftwareVersion(softwareVersion); QueryImage::Type request; request.vendorId = static_cast(vendorId); @@ -238,7 +249,7 @@ void OnApplyUpdateFailure(void * /* context */, EmberAfStatus status) ChipLogError(SoftwareUpdate, "ApplyUpdate failed: %" PRIu16, static_cast(status)); } -void OnApplyUpdateConnection(void * /* context */, DeviceProxy * deviceProxy) +void OnApplyUpdateConnection(void * /* context */, OperationalDeviceProxy * deviceProxy) { // Initialize cluster object Controller::OtaSoftwareUpdateProviderCluster cluster; @@ -258,8 +269,8 @@ void OnApplyUpdateConnection(void * /* context */, DeviceProxy * deviceProxy) DeviceLayer::ConfigurationMgr().GetVendorId(vendorId); DeviceLayer::ConfigurationMgr().GetProductId(productId); - DeviceLayer::ConfigurationMgr().GetProductRevision(hardwareVersion); - DeviceLayer::ConfigurationMgr().GetFirmwareRevision(softwareVersion); + DeviceLayer::ConfigurationMgr().GetHardwareVersion(hardwareVersion); + DeviceLayer::ConfigurationMgr().GetSoftwareVersion(softwareVersion); ApplyUpdateRequest::Type request; request.updateToken = ByteSpan(sOtaContext.updateToken, sOtaContext.updateTokenLen); diff --git a/src/lib/shell/streamer_esp32.cpp b/src/lib/shell/streamer_esp32.cpp index 497328d9c53257..e5daaf324c7281 100644 --- a/src/lib/shell/streamer_esp32.cpp +++ b/src/lib/shell/streamer_esp32.cpp @@ -51,8 +51,10 @@ int streamer_esp32_init(streamer_t * streamer) setvbuf(stdin, NULL, _IONBF, 0); esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); - - ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); + if (!uart_is_driver_installed(CONFIG_ESP_CONSOLE_UART_NUM)) + { + ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); + } uart_config_t uart_config = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, @@ -78,7 +80,7 @@ int streamer_esp32_init(streamer_t * streamer) linenoiseSetDumbMode(1); } - esp_console_cmd_t command = { .command = "chip", .help = "CHIP utilities", .func = chip_command_handler }; + esp_console_cmd_t command = { .command = "matter", .help = "Matter utilities", .func = chip_command_handler }; ESP_ERROR_CHECK(esp_console_cmd_register(&command)); return 0; } diff --git a/src/platform/ESP32/InetPlatformConfig.h b/src/platform/ESP32/InetPlatformConfig.h index b835452c6d225e..ffa8d2a65a57e9 100644 --- a/src/platform/ESP32/InetPlatformConfig.h +++ b/src/platform/ESP32/InetPlatformConfig.h @@ -41,3 +41,4 @@ #ifndef INET_CONFIG_NUM_UDP_ENDPOINTS #define INET_CONFIG_NUM_UDP_ENDPOINTS CONFIG_NUM_UDP_ENDPOINTS #endif // INET_CONFIG_NUM_UDP_ENDPOINTS +#define INET_CONFIG_ENABLE_IPV4 1 diff --git a/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.cpp b/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.cpp index 759d13c5028d26..daeade20704895 100644 --- a/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.cpp +++ b/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.cpp @@ -16,3 +16,162 @@ */ // THIS FILE IS GENERATED BY ZAP + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app::DataModel; +using namespace ::chip::app::List; + +namespace { +[[maybe_unused]] constexpr uint16_t kByteSpanSizeLengthInBytes = 2; +} // namespace + +#define CHECK_STATUS_WITH_RETVAL(error, retval) \ + if (CHIP_NO_ERROR != error) \ + { \ + ChipLogError(Zcl, "CHECK_STATUS %s", ErrorStr(error)); \ + if (onFailureCallback != nullptr) \ + { \ + Callback::Callback * cb = \ + Callback::Callback::FromCancelable(onFailureCallback); \ + cb->mCall(cb->mContext, static_cast(EMBER_ZCL_STATUS_INVALID_VALUE)); \ + } \ + return retval; \ + } + +#define CHECK_STATUS(error) CHECK_STATUS_WITH_RETVAL(error, true) +#define CHECK_STATUS_VOID(error) CHECK_STATUS_WITH_RETVAL(error, ) + +#define CHECK_MESSAGE_LENGTH_WITH_RETVAL(value, retval) \ + if (!CanCastTo(value)) \ + { \ + ChipLogError(Zcl, "CHECK_MESSAGE_LENGTH expects a uint16_t value, got: %d", value); \ + if (onFailureCallback != nullptr) \ + { \ + Callback::Callback * cb = \ + Callback::Callback::FromCancelable(onFailureCallback); \ + cb->mCall(cb->mContext, static_cast(EMBER_ZCL_STATUS_INVALID_VALUE)); \ + } \ + return retval; \ + } \ + \ + if (messageLen < value) \ + { \ + ChipLogError(Zcl, "Unexpected response length: %d", messageLen); \ + if (onFailureCallback != nullptr) \ + { \ + Callback::Callback * cb = \ + Callback::Callback::FromCancelable(onFailureCallback); \ + cb->mCall(cb->mContext, static_cast(EMBER_ZCL_STATUS_INVALID_VALUE)); \ + } \ + return retval; \ + } \ + \ + messageLen = static_cast(messageLen - static_cast(value)); + +#define CHECK_MESSAGE_LENGTH(value) CHECK_MESSAGE_LENGTH_WITH_RETVAL(value, true) +#define CHECK_MESSAGE_LENGTH_VOID(value) CHECK_MESSAGE_LENGTH_WITH_RETVAL(value, ) + +#define GET_RESPONSE_CALLBACKS(name) \ + Callback::Cancelable * onSuccessCallback = nullptr; \ + Callback::Cancelable * onFailureCallback = nullptr; \ + NodeId sourceId = emberAfCurrentCommand()->SourceNodeId(); \ + uint8_t sequenceNumber = emberAfCurrentCommand()->seqNum; \ + CHIP_ERROR err = gCallbacks.GetResponseCallback(sourceId, sequenceNumber, &onSuccessCallback, &onFailureCallback); \ + \ + if (CHIP_NO_ERROR != err) \ + { \ + if (onSuccessCallback == nullptr) \ + { \ + ChipLogDetail(Zcl, "%s: Missing success callback", name); \ + } \ + \ + if (onFailureCallback == nullptr) \ + { \ + ChipLogDetail(Zcl, "%s: Missing failure callback", name); \ + } \ + \ + return true; \ + } + +#define GET_CLUSTER_RESPONSE_CALLBACKS(name) \ + Callback::Cancelable * onSuccessCallback = nullptr; \ + Callback::Cancelable * onFailureCallback = nullptr; \ + NodeId sourceIdentifier = reinterpret_cast(commandObj); \ + /* #6559: Currently, we only have one commands for the IMInvokeCommands and to a device, so the seqNum is always set to 0. */ \ + CHIP_ERROR err = gCallbacks.GetResponseCallback(sourceIdentifier, 0, &onSuccessCallback, &onFailureCallback); \ + \ + if (CHIP_NO_ERROR != err) \ + { \ + if (onSuccessCallback == nullptr) \ + { \ + ChipLogDetail(Zcl, "%s: Missing success callback", name); \ + } \ + \ + if (onFailureCallback == nullptr) \ + { \ + ChipLogDetail(Zcl, "%s: Missing failure callback", name); \ + } \ + \ + return true; \ + } + +// Singleton instance of the callbacks manager +app::CHIPDeviceCallbacksMgr & gCallbacks = app::CHIPDeviceCallbacksMgr::GetInstance(); + +bool emberAfOtaSoftwareUpdateProviderClusterApplyUpdateResponseCallback(EndpointId endpoint, app::CommandSender * commandObj, + uint8_t action, uint32_t delayedActionTime) +{ + ChipLogProgress(Zcl, "ApplyUpdateResponse:"); + ChipLogProgress(Zcl, " action: %" PRIu8 "", action); + ChipLogProgress(Zcl, " delayedActionTime: %" PRIu32 "", delayedActionTime); + + GET_CLUSTER_RESPONSE_CALLBACKS("OtaSoftwareUpdateProviderClusterApplyUpdateResponseCallback"); + + Callback::Callback * cb = + Callback::Callback::FromCancelable(onSuccessCallback); + cb->mCall(cb->mContext, action, delayedActionTime); + return true; +} + +bool emberAfOtaSoftwareUpdateProviderClusterQueryImageResponseCallback(EndpointId endpoint, app::CommandSender * commandObj, + uint8_t status, uint32_t delayedActionTime, + chip::CharSpan imageURI, uint32_t softwareVersion, + chip::CharSpan softwareVersionString, + chip::ByteSpan updateToken, bool userConsentNeeded, + chip::ByteSpan metadataForRequestor) +{ + ChipLogProgress(Zcl, "QueryImageResponse:"); + ChipLogProgress(Zcl, " status: %" PRIu8 "", status); + ChipLogProgress(Zcl, " delayedActionTime: %" PRIu32 "", delayedActionTime); + ChipLogProgress(Zcl, " imageURI: %.*s", static_cast(imageURI.size()), imageURI.data()); + ChipLogProgress(Zcl, " softwareVersion: %" PRIu32 "", softwareVersion); + ChipLogProgress(Zcl, " softwareVersionString: %.*s", static_cast(softwareVersionString.size()), + softwareVersionString.data()); + ChipLogProgress(Zcl, " updateToken: %zu", updateToken.size()); + ChipLogProgress(Zcl, " userConsentNeeded: %d", userConsentNeeded); + ChipLogProgress(Zcl, " metadataForRequestor: %zu", metadataForRequestor.size()); + + GET_CLUSTER_RESPONSE_CALLBACKS("OtaSoftwareUpdateProviderClusterQueryImageResponseCallback"); + + Callback::Callback * cb = + Callback::Callback::FromCancelable(onSuccessCallback); + cb->mCall(cb->mContext, status, delayedActionTime, imageURI, softwareVersion, softwareVersionString, updateToken, + userConsentNeeded, metadataForRequestor); + return true; +} diff --git a/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.h b/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.h index 302d36ce5d8076..499a1924413099 100644 --- a/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.h +++ b/zzz_generated/all-clusters-app/zap-generated/CHIPClientCallbacks.h @@ -17,4 +17,29 @@ // THIS FILE IS GENERATED BY ZAP +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Note: The IMDefaultResponseCallback is a bridge to the old CallbackMgr before IM is landed, so it still accepts EmberAfStatus +// instead of IM status code. +// #6308 should handle IM error code on the application side, either modify this function or remove this. + +// Cluster Specific Response Callbacks +typedef void (*OtaSoftwareUpdateProviderClusterApplyUpdateResponseCallback)(void * context, uint8_t action, + uint32_t delayedActionTime); +typedef void (*OtaSoftwareUpdateProviderClusterQueryImageResponseCallback)( + void * context, uint8_t status, uint32_t delayedActionTime, chip::CharSpan imageURI, uint32_t softwareVersion, + chip::CharSpan softwareVersionString, chip::ByteSpan updateToken, bool userConsentNeeded, chip::ByteSpan metadataForRequestor); + // List specific responses diff --git a/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.cpp b/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.cpp index 759d13c5028d26..3abd6a7b9c3916 100644 --- a/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.cpp +++ b/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.cpp @@ -16,3 +16,202 @@ */ // THIS FILE IS GENERATED BY ZAP + +#include "CHIPClusters.h" + +#include +#include + +namespace chip { + +using namespace app::Clusters; +using namespace System; +using namespace Encoding::LittleEndian; + +namespace Controller { + +// TODO(#4502): onCompletion is not used by IM for now. +// TODO(#4503): length should be passed to commands when byte string is in argument list. +// TODO(#4503): Commands should take group id as an argument. + +// OtaSoftwareUpdateProvider Cluster Commands +CHIP_ERROR OtaSoftwareUpdateProviderCluster::ApplyUpdateRequest(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, + chip::ByteSpan updateToken, uint32_t newVersion) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVWriter * writer = nullptr; + uint8_t argSeqNumber = 0; + + // Used when encoding non-empty command. Suppress error message when encoding empty commands. + (void) writer; + (void) argSeqNumber; + + VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE); + + app::CommandPathParams cmdParams = { mEndpoint, /* group id */ 0, mClusterId, + OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Id, + (app::CommandPathFlags::kEndpointIdValid) }; + + CommandSenderHandle sender( + Platform::New(mDevice->GetInteractionModelDelegate(), mDevice->GetExchangeManager())); + + VerifyOrReturnError(sender != nullptr, CHIP_ERROR_NO_MEMORY); + + SuccessOrExit(err = sender->PrepareCommand(cmdParams)); + + VerifyOrExit((writer = sender->GetCommandDataIBTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + // updateToken: octetString + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), updateToken)); + // newVersion: int32u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), newVersion)); + + SuccessOrExit(err = sender->FinishCommand()); + + // #6308: This is a temporary solution before we fully support IM on application side and should be replaced by IMDelegate. + mDevice->AddIMResponseHandler(sender.get(), onSuccessCallback, onFailureCallback); + + SuccessOrExit(err = mDevice->SendCommands(sender.get())); + + // We have successfully sent the command, and the callback handler will be responsible to free the object, release the object + // now. + sender.release(); +exit: + return err; +} + +CHIP_ERROR OtaSoftwareUpdateProviderCluster::NotifyUpdateApplied(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, + chip::ByteSpan updateToken, uint32_t softwareVersion) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVWriter * writer = nullptr; + uint8_t argSeqNumber = 0; + + // Used when encoding non-empty command. Suppress error message when encoding empty commands. + (void) writer; + (void) argSeqNumber; + + VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE); + + app::CommandPathParams cmdParams = { mEndpoint, /* group id */ 0, mClusterId, + OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Id, + (app::CommandPathFlags::kEndpointIdValid) }; + + CommandSenderHandle sender( + Platform::New(mDevice->GetInteractionModelDelegate(), mDevice->GetExchangeManager())); + + VerifyOrReturnError(sender != nullptr, CHIP_ERROR_NO_MEMORY); + + SuccessOrExit(err = sender->PrepareCommand(cmdParams)); + + VerifyOrExit((writer = sender->GetCommandDataIBTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + // updateToken: octetString + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), updateToken)); + // softwareVersion: int32u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), softwareVersion)); + + SuccessOrExit(err = sender->FinishCommand()); + + // #6308: This is a temporary solution before we fully support IM on application side and should be replaced by IMDelegate. + mDevice->AddIMResponseHandler(sender.get(), onSuccessCallback, onFailureCallback); + + SuccessOrExit(err = mDevice->SendCommands(sender.get())); + + // We have successfully sent the command, and the callback handler will be responsible to free the object, release the object + // now. + sender.release(); +exit: + return err; +} + +CHIP_ERROR OtaSoftwareUpdateProviderCluster::QueryImage(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, chip::VendorId vendorId, + uint16_t productId, uint32_t softwareVersion, uint8_t protocolsSupported, + uint16_t hardwareVersion, chip::CharSpan location, bool requestorCanConsent, + chip::ByteSpan metadataForProvider) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVWriter * writer = nullptr; + uint8_t argSeqNumber = 0; + + // Used when encoding non-empty command. Suppress error message when encoding empty commands. + (void) writer; + (void) argSeqNumber; + + VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE); + + app::CommandPathParams cmdParams = { mEndpoint, /* group id */ 0, mClusterId, + OtaSoftwareUpdateProvider::Commands::QueryImage::Id, + (app::CommandPathFlags::kEndpointIdValid) }; + + CommandSenderHandle sender( + Platform::New(mDevice->GetInteractionModelDelegate(), mDevice->GetExchangeManager())); + + VerifyOrReturnError(sender != nullptr, CHIP_ERROR_NO_MEMORY); + + SuccessOrExit(err = sender->PrepareCommand(cmdParams)); + + VerifyOrExit((writer = sender->GetCommandDataIBTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + // vendorId: vendorId + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), vendorId)); + // productId: int16u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), productId)); + // softwareVersion: int32u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), softwareVersion)); + // protocolsSupported: OTADownloadProtocol + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), protocolsSupported)); + // hardwareVersion: int16u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), hardwareVersion)); + // location: charString + SuccessOrExit(err = writer->PutString(TLV::ContextTag(argSeqNumber++), location)); + // requestorCanConsent: boolean + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), requestorCanConsent)); + // metadataForProvider: octetString + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), metadataForProvider)); + + SuccessOrExit(err = sender->FinishCommand()); + + // #6308: This is a temporary solution before we fully support IM on application side and should be replaced by IMDelegate. + mDevice->AddIMResponseHandler(sender.get(), onSuccessCallback, onFailureCallback); + + SuccessOrExit(err = mDevice->SendCommands(sender.get())); + + // We have successfully sent the command, and the callback handler will be responsible to free the object, release the object + // now. + sender.release(); +exit: + return err; +} + +// OtaSoftwareUpdateProvider Cluster Attributes +CHIP_ERROR OtaSoftwareUpdateProviderCluster::ReadAttributeClusterRevision(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback) +{ + app::AttributePathParams attributePath; + attributePath.mEndpointId = mEndpoint; + attributePath.mClusterId = mClusterId; + attributePath.mAttributeId = 0x0000FFFD; + return mDevice->SendReadAttributeRequest(attributePath, onSuccessCallback, onFailureCallback, + BasicAttributeFilter); +} + +CHIP_ERROR OtaSoftwareUpdateProviderCluster::SubscribeAttributeClusterRevision(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, + uint16_t minInterval, uint16_t maxInterval) +{ + chip::app::AttributePathParams attributePath; + attributePath.mEndpointId = mEndpoint; + attributePath.mClusterId = mClusterId; + attributePath.mAttributeId = Globals::Attributes::ClusterRevision::Id; + return mDevice->SendSubscribeAttributeRequest(attributePath, minInterval, maxInterval, onSuccessCallback, onFailureCallback); +} + +CHIP_ERROR OtaSoftwareUpdateProviderCluster::ReportAttributeClusterRevision(Callback::Cancelable * onReportCallback) +{ + return RequestAttributeReporting(Globals::Attributes::ClusterRevision::Id, onReportCallback, + BasicAttributeFilter); +} + +} // namespace Controller +} // namespace chip diff --git a/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.h b/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.h index 759d13c5028d26..7b04b96f436f42 100644 --- a/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.h +++ b/zzz_generated/all-clusters-app/zap-generated/CHIPClusters.h @@ -16,3 +16,44 @@ */ // THIS FILE IS GENERATED BY ZAP + +// Prevent multiple inclusion +#pragma once + +#include +#include + +#include +#include +#include + +namespace chip { +namespace Controller { + +class DLL_EXPORT OtaSoftwareUpdateProviderCluster : public ClusterBase +{ +public: + OtaSoftwareUpdateProviderCluster() : ClusterBase(app::Clusters::OtaSoftwareUpdateProvider::Id) {} + ~OtaSoftwareUpdateProviderCluster() {} + + // Cluster Commands + CHIP_ERROR ApplyUpdateRequest(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, + chip::ByteSpan updateToken, uint32_t newVersion); + CHIP_ERROR NotifyUpdateApplied(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, + chip::ByteSpan updateToken, uint32_t softwareVersion); + CHIP_ERROR QueryImage(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, + chip::VendorId vendorId, uint16_t productId, uint32_t softwareVersion, uint8_t protocolsSupported, + uint16_t hardwareVersion, chip::CharSpan location, bool requestorCanConsent, + chip::ByteSpan metadataForProvider); + + // Cluster Attributes + CHIP_ERROR ReadAttributeClusterRevision(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback); + CHIP_ERROR SubscribeAttributeClusterRevision(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, + uint16_t minInterval, uint16_t maxInterval); + CHIP_ERROR ReportAttributeClusterRevision(Callback::Cancelable * onReportCallback); + +private: +}; + +} // namespace Controller +} // namespace chip diff --git a/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp b/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp index f125b0f5eec346..985d51a557aac6 100644 --- a/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp +++ b/zzz_generated/all-clusters-app/zap-generated/IMClusterCommandHandler.cpp @@ -1253,43 +1253,169 @@ void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandP namespace OtaSoftwareUpdateProvider { -void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) +void DispatchClientCommand(CommandSender * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) { // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. // Any error value TLVUnpackError means we have received an illegal value. // The following variables are used for all commands to save code size. - CHIP_ERROR TLVError = CHIP_NO_ERROR; - bool wasHandled = false; + CHIP_ERROR TLVError = CHIP_NO_ERROR; + CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; + uint32_t validArgumentCount = 0; + uint32_t expectArgumentCount = 0; + uint32_t currentDecodeTagId = 0; + bool wasHandled = false; { switch (aCommandPath.mCommandId) { - case Commands::ApplyUpdateRequest::Id: { - Commands::ApplyUpdateRequest::DecodableType commandData; - TLVError = DataModel::Decode(aDataTlv, commandData); - if (TLVError == CHIP_NO_ERROR) - { - wasHandled = - emberAfOtaSoftwareUpdateProviderClusterApplyUpdateRequestCallback(apCommandObj, aCommandPath, commandData); - } - break; - } - case Commands::NotifyUpdateApplied::Id: { - Commands::NotifyUpdateApplied::DecodableType commandData; - TLVError = DataModel::Decode(aDataTlv, commandData); - if (TLVError == CHIP_NO_ERROR) - { - wasHandled = - emberAfOtaSoftwareUpdateProviderClusterNotifyUpdateAppliedCallback(apCommandObj, aCommandPath, commandData); - } - break; - } - case Commands::QueryImage::Id: { - Commands::QueryImage::DecodableType commandData; - TLVError = DataModel::Decode(aDataTlv, commandData); - if (TLVError == CHIP_NO_ERROR) - { - wasHandled = emberAfOtaSoftwareUpdateProviderClusterQueryImageCallback(apCommandObj, aCommandPath, commandData); + case Commands::ApplyUpdateResponse::Id: { + expectArgumentCount = 2; + uint8_t action; + uint32_t delayedActionTime; + bool argExists[2]; + + memset(argExists, 0, sizeof argExists); + + while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) + { + // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. + // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. + if (!TLV::IsContextTag(aDataTlv.GetTag())) + { + continue; + } + currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); + if (currentDecodeTagId < 2) + { + if (argExists[currentDecodeTagId]) + { + ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); + TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + break; + } + else + { + argExists[currentDecodeTagId] = true; + validArgumentCount++; + } + } + switch (currentDecodeTagId) + { + case 0: + TLVUnpackError = aDataTlv.Get(action); + break; + case 1: + TLVUnpackError = aDataTlv.Get(delayedActionTime); + break; + default: + // Unsupported tag, ignore it. + ChipLogProgress(Zcl, "Unknown TLV tag during processing."); + break; + } + if (CHIP_NO_ERROR != TLVUnpackError) + { + break; + } + } + + if (CHIP_END_OF_TLV == TLVError) + { + // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. + TLVError = CHIP_NO_ERROR; + } + + if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount) + { + wasHandled = emberAfOtaSoftwareUpdateProviderClusterApplyUpdateResponseCallback( + aCommandPath.mEndpointId, apCommandObj, action, delayedActionTime); + } + break; + } + case Commands::QueryImageResponse::Id: { + expectArgumentCount = 8; + uint8_t status; + uint32_t delayedActionTime; + chip::CharSpan imageURI; + uint32_t softwareVersion; + chip::CharSpan softwareVersionString; + chip::ByteSpan updateToken; + bool userConsentNeeded; + chip::ByteSpan metadataForRequestor; + bool argExists[8]; + + memset(argExists, 0, sizeof argExists); + + while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) + { + // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. + // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. + if (!TLV::IsContextTag(aDataTlv.GetTag())) + { + continue; + } + currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); + if (currentDecodeTagId < 8) + { + if (argExists[currentDecodeTagId]) + { + ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); + TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + break; + } + else + { + argExists[currentDecodeTagId] = true; + validArgumentCount++; + } + } + switch (currentDecodeTagId) + { + case 0: + TLVUnpackError = aDataTlv.Get(status); + break; + case 1: + TLVUnpackError = aDataTlv.Get(delayedActionTime); + break; + case 2: + TLVUnpackError = aDataTlv.Get(imageURI); + break; + case 3: + TLVUnpackError = aDataTlv.Get(softwareVersion); + break; + case 4: + TLVUnpackError = aDataTlv.Get(softwareVersionString); + break; + case 5: + TLVUnpackError = aDataTlv.Get(updateToken); + break; + case 6: + TLVUnpackError = aDataTlv.Get(userConsentNeeded); + break; + case 7: + TLVUnpackError = aDataTlv.Get(metadataForRequestor); + break; + default: + // Unsupported tag, ignore it. + ChipLogProgress(Zcl, "Unknown TLV tag during processing."); + break; + } + if (CHIP_NO_ERROR != TLVUnpackError) + { + break; + } + } + + if (CHIP_END_OF_TLV == TLVError) + { + // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. + TLVError = CHIP_NO_ERROR; + } + + if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 8 == validArgumentCount) + { + wasHandled = emberAfOtaSoftwareUpdateProviderClusterQueryImageResponseCallback( + aCommandPath.mEndpointId, apCommandObj, status, delayedActionTime, imageURI, softwareVersion, + softwareVersionString, updateToken, userConsentNeeded, metadataForRequestor); } break; } @@ -1301,15 +1427,31 @@ void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandP } } - if (CHIP_NO_ERROR != TLVError || !wasHandled) + if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::InvalidCommand); - ChipLogProgress(Zcl, "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT, TLVError.Format()); + ChipLogProgress(Zcl, + "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT + ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, + validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId); + // A command with no arguments would never write currentDecodeTagId. If + // progress logging is also disabled, it would look unused. Silence that + // warning. + UNUSED_VAR(currentDecodeTagId); } } } // namespace OtaSoftwareUpdateProvider +namespace OtaSoftwareUpdateProvider { + +void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) +{ + ReportCommandUnsupported(apCommandObj, aCommandPath); +} + +} // namespace OtaSoftwareUpdateProvider + namespace OnOff { void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) @@ -2034,6 +2176,9 @@ void DispatchSingleClusterResponseCommand(const ConcreteCommandPath & aCommandPa SuccessOrExit(aReader.EnterContainer(dataTlvType)); switch (aCommandPath.mClusterId) { + case Clusters::OtaSoftwareUpdateProvider::Id: + Clusters::OtaSoftwareUpdateProvider::DispatchClientCommand(apCommandObj, aCommandPath, aReader); + break; default: ChipLogError(Zcl, "Unknown cluster " ChipLogFormatMEI, ChipLogValueMEI(aCommandPath.mClusterId)); apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::UnsupportedCluster); diff --git a/zzz_generated/all-clusters-app/zap-generated/PluginApplicationCallbacks.h b/zzz_generated/all-clusters-app/zap-generated/PluginApplicationCallbacks.h index 82034fa0785e5b..93223ac1e068f3 100644 --- a/zzz_generated/all-clusters-app/zap-generated/PluginApplicationCallbacks.h +++ b/zzz_generated/all-clusters-app/zap-generated/PluginApplicationCallbacks.h @@ -58,6 +58,7 @@ MatterMediaPlaybackPluginServerInitCallback(); \ MatterModeSelectPluginServerInitCallback(); \ MatterNetworkCommissioningPluginServerInitCallback(); \ + MatterOtaSoftwareUpdateProviderPluginClientInitCallback(); \ MatterOtaSoftwareUpdateProviderPluginServerInitCallback(); \ MatterOtaSoftwareUpdateRequestorPluginServerInitCallback(); \ MatterOccupancySensingPluginServerInitCallback(); \ diff --git a/zzz_generated/all-clusters-app/zap-generated/endpoint_config.h b/zzz_generated/all-clusters-app/zap-generated/endpoint_config.h index 7c52ed6067ddc9..0eafb5c9197646 100644 --- a/zzz_generated/all-clusters-app/zap-generated/endpoint_config.h +++ b/zzz_generated/all-clusters-app/zap-generated/endpoint_config.h @@ -2320,7 +2320,7 @@ }; #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 67 +#define GENERATED_CLUSTER_COUNT 68 #define GENERATED_CLUSTERS \ { \ { 0x0003, \ @@ -2342,6 +2342,9 @@ 687, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayBasicServer }, /* Endpoint: 0, Cluster: Basic (server) */ \ + { \ + 0x0029, ZAP_ATTRIBUTE_INDEX(32), 0, 0, ZAP_CLUSTER_MASK(CLIENT), NULL \ + }, /* Endpoint: 0, Cluster: OTA Software Update Provider (client) */ \ { \ 0x0029, ZAP_ATTRIBUTE_INDEX(32), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: OTA Software Update Provider (server) */ \ @@ -2579,7 +2582,7 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 20, 1929 }, { ZAP_CLUSTER_INDEX(20), 44, 6400 }, { ZAP_CLUSTER_INDEX(64), 3, 18 }, \ + { ZAP_CLUSTER_INDEX(0), 21, 1929 }, { ZAP_CLUSTER_INDEX(21), 44, 6400 }, { ZAP_CLUSTER_INDEX(65), 3, 18 }, \ } // Largest attribute size is needed for various buffers diff --git a/zzz_generated/all-clusters-app/zap-generated/gen_config.h b/zzz_generated/all-clusters-app/zap-generated/gen_config.h index b35545b642546b..0630089311861f 100644 --- a/zzz_generated/all-clusters-app/zap-generated/gen_config.h +++ b/zzz_generated/all-clusters-app/zap-generated/gen_config.h @@ -65,6 +65,7 @@ #define EMBER_AF_MEDIA_PLAYBACK_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_MODE_SELECT_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_NETWORK_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_OTA_PROVIDER_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_PROVIDER_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_REQUESTOR_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OCCUPANCY_SENSING_CLUSTER_SERVER_ENDPOINT_COUNT (2) @@ -282,6 +283,10 @@ #define EMBER_AF_PLUGIN_NETWORK_COMMISSIONING_SERVER #define EMBER_AF_PLUGIN_NETWORK_COMMISSIONING +// Use this macro to check if the client side of the OTA Software Update Provider cluster is included +#define ZCL_USING_OTA_PROVIDER_CLUSTER_CLIENT +#define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_PROVIDER_CLIENT + // Use this macro to check if the server side of the OTA Software Update Provider cluster is included #define ZCL_USING_OTA_PROVIDER_CLUSTER_SERVER #define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_PROVIDER_SERVER diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index 3dcb82891f4f1d..c91a49f4c0f1d2 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -47703,7 +47703,9 @@ class TestDescriptorCluster : public TestCommand void OnSuccessResponse_3(const chip::app::DataModel::DecodableList & clientList) { auto iter = clientList.begin(); - VerifyOrReturn(CheckNoMoreListItems("clientList", iter, 0)); + VerifyOrReturn(CheckNextListItemDecodes("clientList", iter, 0)); + VerifyOrReturn(CheckValue("clientList[0]", iter.GetValue(), 41UL)); + VerifyOrReturn(CheckNoMoreListItems("clientList", iter, 1)); NextTest(); }