From f9d57412e06011db5918657fa44aaeb5a903debe Mon Sep 17 00:00:00 2001 From: Trevor Holbrook Date: Thu, 10 Jun 2021 12:15:27 -0700 Subject: [PATCH] OTAServerDelegate class for vendor logic (#6476) * OTAServerDelegate class for vendor logic - define OTAServerDelegate class for implementing vendor OTA Server logic - add some common logic for OTA Server Cluster commands - use OTA_SERVER_CLUSTER_EXAMPLE_IMPL to conditionally build example logic - add OTA Server Cluster to all-clusters-app and chip-tool - fix AnnounceOTAServer command direction * add build macros to all-clusters-app esp32 build files * use virtual delegate methods instead of static singleton * fix whitespace * add OTA Server to all-clusters-app, remove ota-client callbacks ota-client response callbacks are automatically generated now * generated files * remove src/darwin edits * edit zap files to include just ota clusters * regenerate gen files after zap fix * add multiple endpoint support and EMBER_ZCL_STATUS_INVALID_ARGUMENT * remove OTA Server Cluster from all-clusters-app Endpoint 1 - There should only be one OTA Server Cluster, in endpoint 0 * fix darwin tests - enable Cluster Revision attribute reporting for OTA Server Cluster in all-clusters-app - change darwin test to use endpoint 0 instead of endpoint 1 * edit helper.js in darwin to fix OTA Server test - note: tv-app files were also modified and tv-app build is failing * generated files after merge conflict * resolve merge conflicts + regen * default destructor for OTAServerDelegate Co-authored-by: Tennessee Carmel-Veilleux * error logging and value change for EMBER_ZCL_STATUS_INVALID_ARGUMENT * regenerate * regenerated files after merge conflict fix * add generated tv-app files * Revert "add generated tv-app files" This reverts commit 48acb905fba5bb1581c595fbf2c4ff261263a7c1. Co-authored-by: Tennessee Carmel-Veilleux --- .../all-clusters-common/all-clusters-app.zap | 109 +++++++- .../all-clusters-common/gen/callback-stub.cpp | 8 - .../all-clusters-common/gen/callback.h | 79 ------ .../all-clusters-common/gen/endpoint_config.h | 154 ++++++------ .../all-clusters-common/gen/gen_config.h | 6 - .../chip-tool/commands/clusters/Commands.h | 236 ++++++++++++++++++ .../clusters/ota-server/ota-server-delegate.h | 48 ++++ src/app/clusters/ota-server/ota-server.cpp | 128 +++++++++- src/app/clusters/ota-server/ota-server.h | 33 +++ src/app/util/af-enums.h | 1 + src/app/zap-templates/zcl/chip-ota.xml | 2 +- src/app/zap_cluster_list.py | 4 +- .../data_model/controller-clusters.zap | 94 +++++++ .../data_model/gen/CHIPClientCallbacks.cpp | 46 ++++ .../data_model/gen/CHIPClientCallbacks.h | 6 + .../data_model/gen/CHIPClusters.cpp | 165 ++++++++++++ src/controller/data_model/gen/CHIPClusters.h | 27 ++ .../gen/IMClusterCommandHandler.cpp | 207 +++++++++++++++ .../data_model/gen/call-command-handler.cpp | 103 ++++++++ .../data_model/gen/callback-stub.cpp | 8 + src/controller/data_model/gen/callback.h | 95 +++++++ .../data_model/gen/chip-zcl-zpro-codec-api.h | 27 ++ src/controller/data_model/gen/encoder.cpp | 35 +++ .../data_model/gen/endpoint_config.h | 89 ++++--- src/controller/data_model/gen/gen_config.h | 5 + .../python/chip/clusters/CHIPClusters.cpp | 46 ++++ .../python/chip/clusters/CHIPClusters.py | 52 ++++ .../Framework/CHIP/gen/CHIPClustersObjc.h | 25 ++ .../Framework/CHIP/gen/CHIPClustersObjc.mm | 209 ++++++++++++++++ src/darwin/Framework/CHIP/templates/helper.js | 1 + .../Framework/CHIPTests/CHIPClustersTests.m | 19 ++ 31 files changed, 1838 insertions(+), 229 deletions(-) create mode 100644 src/app/clusters/ota-server/ota-server-delegate.h create mode 100644 src/app/clusters/ota-server/ota-server.h 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 0a8b464413baf9..5f88afd6d7764c 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 @@ -1188,6 +1188,100 @@ } ] }, + { + "name": "OTA Software Update Server", + "code": 41, + "mfgCode": null, + "define": "OTA_SERVER_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "QueryImage", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ApplyUpdateRequest", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "NotifyUpdateApplied", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "client", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "OTA Software Update Server", + "code": 41, + "mfgCode": null, + "define": "OTA_SERVER_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "QueryImageResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ApplyUpdateRequestResponse", + "code": 4, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "server", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, { "name": "General Commissioning", "code": 48, @@ -7005,7 +7099,7 @@ "mfgCode": null, "define": "OTA_SERVER_CLUSTER", "side": "server", - "enabled": 1, + "enabled": 0, "commands": [ { "name": "QueryImageResponse", @@ -7104,17 +7198,8 @@ "mfgCode": null, "define": "OTA_CLIENT_CLUSTER", "side": "server", - "enabled": 1, - "commands": [ - { - "name": "AnnounceOtaServer", - "code": 0, - "mfgCode": null, - "source": "server", - "incoming": 0, - "outgoing": 1 - } - ], + "enabled": 0, + "commands": [], "attributes": [ { "name": "cluster revision", diff --git a/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp b/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp index f83cdc10c24a97..0259d65191b6d0 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/gen/callback-stub.cpp @@ -110,9 +110,6 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_NETWORK_COMMISSIONING_CLUSTER_ID: emberAfNetworkCommissioningClusterInitCallback(endpoint); break; - case ZCL_OTA_CLIENT_CLUSTER_ID: - emberAfOtaSoftwareUpdateClientClusterInitCallback(endpoint); - break; case ZCL_OTA_SERVER_CLUSTER_ID: emberAfOtaSoftwareUpdateServerClusterInitCallback(endpoint); break; @@ -311,11 +308,6 @@ void __attribute__((weak)) emberAfNetworkCommissioningClusterInitCallback(Endpoi // To prevent warning (void) endpoint; } -void __attribute__((weak)) emberAfOtaSoftwareUpdateClientClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} void __attribute__((weak)) emberAfOtaSoftwareUpdateServerClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/examples/all-clusters-app/all-clusters-common/gen/callback.h b/examples/all-clusters-app/all-clusters-common/gen/callback.h index b5ec3158b52c37..fda0f32b81295f 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/callback.h +++ b/examples/all-clusters-app/all-clusters-common/gen/callback.h @@ -256,14 +256,6 @@ void emberAfMediaPlaybackClusterInitCallback(chip::EndpointId endpoint); */ void emberAfNetworkCommissioningClusterInitCallback(chip::EndpointId endpoint); -/** @brief OTA Software Update Client Cluster Init - * - * Cluster Init - * - * @param endpoint Endpoint that is being initialized - */ -void emberAfOtaSoftwareUpdateClientClusterInitCallback(chip::EndpointId endpoint); - /** @brief OTA Software Update Server Cluster Init * * Cluster Init @@ -2303,77 +2295,6 @@ EmberAfStatus emberAfNetworkCommissioningClusterServerPreAttributeChangedCallbac */ void emberAfNetworkCommissioningClusterServerTickCallback(chip::EndpointId endpoint); -// -// OTA Software Update Client Cluster server -// - -/** @brief OTA Software Update Client Cluster Server Init - * - * Server Init - * - * @param endpoint Endpoint that is being initialized - */ -void emberAfOtaSoftwareUpdateClientClusterServerInitCallback(chip::EndpointId endpoint); - -/** @brief OTA Software Update Client Cluster Server Attribute Changed - * - * Server Attribute Changed - * - * @param endpoint Endpoint that is being initialized - * @param attributeId Attribute that changed - */ -void emberAfOtaSoftwareUpdateClientClusterServerAttributeChangedCallback(chip::EndpointId endpoint, chip::AttributeId attributeId); - -/** @brief OTA Software Update Client Cluster Server Manufacturer Specific Attribute Changed - * - * Server Manufacturer Specific Attribute Changed - * - * @param endpoint Endpoint that is being initialized - * @param attributeId Attribute that changed - * @param manufacturerCode Manufacturer Code of the attribute that changed - */ -void emberAfOtaSoftwareUpdateClientClusterServerManufacturerSpecificAttributeChangedCallback(chip::EndpointId endpoint, - chip::AttributeId attributeId, - uint16_t manufacturerCode); - -/** @brief OTA Software Update Client Cluster Server Message Sent - * - * Server Message Sent - * - * @param type The type of message sent - * @param destination The destination to which the message was sent - * @param apsFrame The APS frame for the message - * @param msgLen The length of the message - * @param message The message that was sent - * @param status The status of the sent message - */ -void emberAfOtaSoftwareUpdateClientClusterServerMessageSentCallback(const chip::MessageSendDestination & destination, - EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, - EmberStatus status); - -/** @brief OTA Software Update Client Cluster Server Pre Attribute Changed - * - * server Pre Attribute Changed - * - * @param endpoint Endpoint that is being initialized - * @param attributeId Attribute to be changed - * @param attributeType Attribute type - * @param size Attribute size - * @param value Attribute value - */ -EmberAfStatus emberAfOtaSoftwareUpdateClientClusterServerPreAttributeChangedCallback(chip::EndpointId endpoint, - chip::AttributeId attributeId, - EmberAfAttributeType attributeType, - uint16_t size, uint8_t * value); - -/** @brief OTA Software Update Client Cluster Server Tick - * - * server Tick - * - * @param endpoint Endpoint that is being served - */ -void emberAfOtaSoftwareUpdateClientClusterServerTickCallback(chip::EndpointId endpoint); - // // OTA Software Update Server Cluster server // diff --git a/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h b/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h index 4ba77e2577c8ed..58b487ef4b3c61 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h +++ b/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h @@ -1649,7 +1649,7 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 315 +#define GENERATED_ATTRIBUTE_COUNT 314 #define GENERATED_ATTRIBUTES \ { \ \ @@ -1688,6 +1688,9 @@ ZAP_SIMPLE_DEFAULT(0x00) }, /* LocalConfigDisabled */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(SINGLETON), ZAP_SIMPLE_DEFAULT(3) }, /* cluster revision */ \ \ + /* Endpoint: 0, Cluster: OTA Software Update Server (server) */ \ + { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* cluster revision */ \ + \ /* Endpoint: 0, Cluster: General Commissioning (server) */ \ { 0x0000, ZAP_TYPE(OCTET_STRING), 8, 0, ZAP_LONG_DEFAULTS_INDEX(1880) }, /* FabricId */ \ { 0x0001, ZAP_TYPE(INT64U), 8, ZAP_ATTRIBUTE_MASK(WRITABLE), ZAP_LONG_DEFAULTS_INDEX(1888) }, /* Breadcrumb */ \ @@ -1842,12 +1845,6 @@ { 0x0003, ZAP_TYPE(ARRAY), 254, 0, ZAP_LONG_DEFAULTS_INDEX(4429) }, /* parts list */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* cluster revision */ \ \ - /* Endpoint: 1, Cluster: OTA Software Update Server (server) */ \ - { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* cluster revision */ \ - \ - /* Endpoint: 1, Cluster: OTA Software Update Client (server) */ \ - { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* cluster revision */ \ - \ /* Endpoint: 1, Cluster: Bridged Device Basic (server) */ \ { 0x0001, ZAP_TYPE(CHAR_STRING), 32, ZAP_ATTRIBUTE_MASK(SINGLETON), ZAP_LONG_DEFAULTS_INDEX(4683) }, /* VendorName */ \ { 0x0002, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(SINGLETON), ZAP_EMPTY_DEFAULT() }, /* VendorID */ \ @@ -2131,7 +2128,7 @@ }; #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 51 +#define GENERATED_CLUSTER_COUNT 50 #define GENERATED_CLUSTERS \ { \ { \ @@ -2144,179 +2141,176 @@ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayBasicServer }, /* Endpoint: 0, Cluster: Basic (server) */ \ { \ - 0x0030, ZAP_ATTRIBUTE_INDEX(23), 3, 18, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0029, ZAP_ATTRIBUTE_INDEX(23), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + }, /* Endpoint: 0, Cluster: OTA Software Update Server (server) */ \ + { \ + 0x0030, ZAP_ATTRIBUTE_INDEX(24), 3, 18, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: General Commissioning (server) */ \ { \ - 0x0031, ZAP_ATTRIBUTE_INDEX(26), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0031, ZAP_ATTRIBUTE_INDEX(27), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Network Commissioning (server) */ \ { \ - 0x0033, ZAP_ATTRIBUTE_INDEX(27), 3, 258, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0033, ZAP_ATTRIBUTE_INDEX(28), 3, 258, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: General Diagnostics (server) */ \ { \ - 0x0034, ZAP_ATTRIBUTE_INDEX(30), 2, 10, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0034, ZAP_ATTRIBUTE_INDEX(31), 2, 10, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Software Diagnostics (server) */ \ { \ - 0x0035, ZAP_ATTRIBUTE_INDEX(32), 61, 730, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0035, ZAP_ATTRIBUTE_INDEX(33), 61, 730, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Thread Network Diagnostics (server) */ \ { \ - 0x0036, ZAP_ATTRIBUTE_INDEX(93), 6, 13, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0036, ZAP_ATTRIBUTE_INDEX(94), 6, 13, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: WiFi Network Diagnostics (server) */ \ { \ - 0x0037, ZAP_ATTRIBUTE_INDEX(99), 6, 42, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0037, ZAP_ATTRIBUTE_INDEX(100), 6, 42, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Ethernet Network Diagnostics (server) */ \ { \ - 0x003E, ZAP_ATTRIBUTE_INDEX(105), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x003E, ZAP_ATTRIBUTE_INDEX(106), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Operational Credentials (server) */ \ { \ - 0x003F, ZAP_ATTRIBUTE_INDEX(107), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x003F, ZAP_ATTRIBUTE_INDEX(108), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Trusted Root Certificates (server) */ \ { \ - 0x0405, ZAP_ATTRIBUTE_INDEX(108), 4, 8, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0405, ZAP_ATTRIBUTE_INDEX(109), 4, 8, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Relative Humidity Measurement (server) */ \ { \ - 0xF000, ZAP_ATTRIBUTE_INDEX(112), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0xF000, ZAP_ATTRIBUTE_INDEX(113), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Binding (server) */ \ { \ - 0xF004, ZAP_ATTRIBUTE_INDEX(113), 3, 510, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0xF004, ZAP_ATTRIBUTE_INDEX(114), 3, 510, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Group Key Management (server) */ \ { 0x0003, \ - ZAP_ATTRIBUTE_INDEX(116), \ + ZAP_ATTRIBUTE_INDEX(117), \ 2, \ 4, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION), \ chipFuncArrayIdentifyServer }, /* Endpoint: 1, Cluster: Identify (server) */ \ { 0x0004, \ - ZAP_ATTRIBUTE_INDEX(118), \ + ZAP_ATTRIBUTE_INDEX(119), \ 2, \ 3, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayGroupsServer }, /* Endpoint: 1, Cluster: Groups (server) */ \ { 0x0005, \ - ZAP_ATTRIBUTE_INDEX(120), \ + ZAP_ATTRIBUTE_INDEX(121), \ 6, \ 8, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayScenesServer }, /* Endpoint: 1, Cluster: Scenes (server) */ \ { 0x0006, \ - ZAP_ATTRIBUTE_INDEX(126), \ + ZAP_ATTRIBUTE_INDEX(127), \ 2, \ 3, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayOnOffServer }, /* Endpoint: 1, Cluster: On/off (server) */ \ { 0x0008, \ - ZAP_ATTRIBUTE_INDEX(128), \ + ZAP_ATTRIBUTE_INDEX(129), \ 2, \ 3, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayLevelControlServer }, /* Endpoint: 1, Cluster: Level Control (server) */ \ { \ - 0x000F, ZAP_ATTRIBUTE_INDEX(130), 4, 5, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x000F, ZAP_ATTRIBUTE_INDEX(131), 4, 5, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Binary Input (Basic) (server) */ \ { \ - 0x001D, ZAP_ATTRIBUTE_INDEX(134), 5, 1018, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x001D, ZAP_ATTRIBUTE_INDEX(135), 5, 1018, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Descriptor (server) */ \ { \ - 0x0029, ZAP_ATTRIBUTE_INDEX(139), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ - }, /* Endpoint: 1, Cluster: OTA Software Update Server (server) */ \ - { \ - 0x002A, ZAP_ATTRIBUTE_INDEX(140), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ - }, /* Endpoint: 1, Cluster: OTA Software Update Client (server) */ \ - { \ - 0x0039, ZAP_ATTRIBUTE_INDEX(141), 15, 855, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0039, ZAP_ATTRIBUTE_INDEX(140), 15, 855, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Bridged Device Basic (server) */ \ { \ - 0x003B, ZAP_ATTRIBUTE_INDEX(156), 3, 4, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x003B, ZAP_ATTRIBUTE_INDEX(155), 3, 4, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Switch (server) */ \ { \ - 0x0040, ZAP_ATTRIBUTE_INDEX(159), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0040, ZAP_ATTRIBUTE_INDEX(158), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Fixed Label (server) */ \ { 0x0101, \ - ZAP_ATTRIBUTE_INDEX(161), \ + ZAP_ATTRIBUTE_INDEX(160), \ 4, \ 5, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION), \ chipFuncArrayDoorLockServer }, /* Endpoint: 1, Cluster: Door Lock (server) */ \ { \ - 0x0102, ZAP_ATTRIBUTE_INDEX(165), 10, 17, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0102, ZAP_ATTRIBUTE_INDEX(164), 10, 17, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Window Covering (server) */ \ { \ - 0x0103, ZAP_ATTRIBUTE_INDEX(175), 5, 7, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0103, ZAP_ATTRIBUTE_INDEX(174), 5, 7, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Barrier Control (server) */ \ { \ - 0x0200, ZAP_ATTRIBUTE_INDEX(180), 8, 13, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0200, ZAP_ATTRIBUTE_INDEX(179), 8, 13, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Pump Configuration and Control (server) */ \ { \ - 0x0201, ZAP_ATTRIBUTE_INDEX(188), 6, 10, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0201, ZAP_ATTRIBUTE_INDEX(187), 6, 10, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Thermostat (server) */ \ { 0x0300, \ - ZAP_ATTRIBUTE_INDEX(194), \ + ZAP_ATTRIBUTE_INDEX(193), \ 51, \ 336, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayColorControlServer }, /* Endpoint: 1, Cluster: Color Control (server) */ \ { \ - 0x0402, ZAP_ATTRIBUTE_INDEX(245), 4, 8, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0402, ZAP_ATTRIBUTE_INDEX(244), 4, 8, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Temperature Measurement (server) */ \ { \ - 0x0405, ZAP_ATTRIBUTE_INDEX(249), 4, 8, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0405, ZAP_ATTRIBUTE_INDEX(248), 4, 8, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Relative Humidity Measurement (server) */ \ { 0x0500, \ - ZAP_ATTRIBUTE_INDEX(253), \ + ZAP_ATTRIBUTE_INDEX(252), \ 6, \ 16, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION) | \ ZAP_CLUSTER_MASK(MESSAGE_SENT_FUNCTION), \ chipFuncArrayIasZoneServer }, /* Endpoint: 1, Cluster: IAS Zone (server) */ \ { \ - 0x0503, ZAP_ATTRIBUTE_INDEX(259), 2, 34, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0503, ZAP_ATTRIBUTE_INDEX(258), 2, 34, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Wake on LAN (server) */ \ { \ - 0x0504, ZAP_ATTRIBUTE_INDEX(261), 4, 320, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0504, ZAP_ATTRIBUTE_INDEX(260), 4, 320, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: TV Channel (server) */ \ { \ - 0x0505, ZAP_ATTRIBUTE_INDEX(265), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0505, ZAP_ATTRIBUTE_INDEX(264), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Target Navigator (server) */ \ { \ - 0x0506, ZAP_ATTRIBUTE_INDEX(267), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0506, ZAP_ATTRIBUTE_INDEX(266), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Media Playback (server) */ \ { \ - 0x0507, ZAP_ATTRIBUTE_INDEX(268), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0507, ZAP_ATTRIBUTE_INDEX(267), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Media Input (server) */ \ { \ - 0x0508, ZAP_ATTRIBUTE_INDEX(270), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0508, ZAP_ATTRIBUTE_INDEX(269), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Low Power (server) */ \ { \ - 0x0509, ZAP_ATTRIBUTE_INDEX(271), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0509, ZAP_ATTRIBUTE_INDEX(270), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Keypad Input (server) */ \ { \ - 0x050A, ZAP_ATTRIBUTE_INDEX(272), 3, 510, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x050A, ZAP_ATTRIBUTE_INDEX(271), 3, 510, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Content Launch (server) */ \ { \ - 0x050B, ZAP_ATTRIBUTE_INDEX(275), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x050B, ZAP_ATTRIBUTE_INDEX(274), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Audio Output (server) */ \ { \ - 0x050C, ZAP_ATTRIBUTE_INDEX(277), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x050C, ZAP_ATTRIBUTE_INDEX(276), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Application Launcher (server) */ \ { \ - 0x050D, ZAP_ATTRIBUTE_INDEX(279), 8, 105, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x050D, ZAP_ATTRIBUTE_INDEX(278), 8, 105, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Application Basic (server) */ \ { \ - 0x050E, ZAP_ATTRIBUTE_INDEX(287), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x050E, ZAP_ATTRIBUTE_INDEX(286), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Account Login (server) */ \ { \ - 0x050F, ZAP_ATTRIBUTE_INDEX(288), 20, 579, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x050F, ZAP_ATTRIBUTE_INDEX(287), 20, 579, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Test Cluster (server) */ \ { \ - 0xF000, ZAP_ATTRIBUTE_INDEX(308), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0xF000, ZAP_ATTRIBUTE_INDEX(307), 1, 2, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Binding (server) */ \ { 0x0006, \ - ZAP_ATTRIBUTE_INDEX(309), \ + ZAP_ATTRIBUTE_INDEX(308), \ 2, \ 3, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayOnOffServer }, /* Endpoint: 2, Cluster: On/off (server) */ \ { 0x0406, \ - ZAP_ATTRIBUTE_INDEX(311), \ + ZAP_ATTRIBUTE_INDEX(310), \ 4, \ 5, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ @@ -2328,7 +2322,7 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 14, 3744 }, { ZAP_CLUSTER_INDEX(14), 35, 5165 }, { ZAP_CLUSTER_INDEX(49), 2, 8 }, \ + { ZAP_CLUSTER_INDEX(0), 15, 3746 }, { ZAP_CLUSTER_INDEX(15), 33, 5161 }, { ZAP_CLUSTER_INDEX(48), 2, 8 }, \ } // Largest attribute size is needed for various buffers @@ -2338,7 +2332,7 @@ #define ATTRIBUTE_SINGLETONS_SIZE (1730) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (8917) +#define ATTRIBUTE_MAX_SIZE (8915) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (3) @@ -2382,7 +2376,7 @@ // Array of EmberAfCommandMetadata structs. #define ZAP_COMMAND_MASK(mask) COMMAND_MASK_##mask -#define EMBER_AF_GENERATED_COMMAND_COUNT (197) +#define EMBER_AF_GENERATED_COMMAND_COUNT (196) #define GENERATED_COMMANDS \ { \ \ @@ -2392,6 +2386,13 @@ { 0x0028, 0x02, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* Leave */ \ { 0x0028, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) | ZAP_COMMAND_MASK(OUTGOING_SERVER) }, /* MfgSpecificPing */ \ \ + /* Endpoint: 0, Cluster: OTA Software Update Server (server) */ \ + { 0x0029, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* QueryImage */ \ + { 0x0029, 0x01, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* ApplyUpdateRequest */ \ + { 0x0029, 0x02, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* NotifyUpdateApplied */ \ + { 0x0029, 0x03, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* QueryImageResponse */ \ + { 0x0029, 0x04, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* ApplyUpdateRequestResponse */ \ + \ /* Endpoint: 0, Cluster: General Commissioning (server) */ \ { 0x0030, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* ArmFailSafe */ \ { 0x0030, 0x01, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* ArmFailSafeResponse */ \ @@ -2492,16 +2493,6 @@ { 0x0008, 0x06, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* StepWithOnOff */ \ { 0x0008, 0x07, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* StopWithOnOff */ \ \ - /* Endpoint: 1, Cluster: OTA Software Update Server (server) */ \ - { 0x0029, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* QueryImage */ \ - { 0x0029, 0x01, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* ApplyUpdateRequest */ \ - { 0x0029, 0x02, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* NotifyUpdateApplied */ \ - { 0x0029, 0x03, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* QueryImageResponse */ \ - { 0x0029, 0x04, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* ApplyUpdateRequestResponse */ \ - \ - /* Endpoint: 1, Cluster: OTA Software Update Client (server) */ \ - { 0x002A, 0x00, ZAP_COMMAND_MASK(OUTGOING_SERVER) }, /* AnnounceOtaServer */ \ - \ /* Endpoint: 1, Cluster: Bridged Device Basic (server) */ \ { 0x0039, 0x00, ZAP_COMMAND_MASK(OUTGOING_SERVER) }, /* StartUp */ \ { 0x0039, 0x01, ZAP_COMMAND_MASK(OUTGOING_SERVER) }, /* ShutDown */ \ @@ -2685,17 +2676,22 @@ #define ZAP_REPORT_DIRECTION(x) ZRD(x) // User options for plugin Reporting -#define EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE (18) +#define EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE (19) #define EMBER_AF_PLUGIN_REPORTING_ENABLE_GROUP_BOUND_REPORTS -#define EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS_TABLE_SIZE (18) +#define EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS_TABLE_SIZE (19) #define EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS \ { \ \ - /* Endpoint: 0, Cluster: Relative Humidity Measurement (server) */ \ + /* Endpoint: 0, Cluster: OTA Software Update Server (server) */ \ { \ - ZAP_REPORT_DIRECTION(REPORTED), 0x0000, 0x0405, 0x0000, ZAP_CLUSTER_MASK(SERVER), 0x0000, { { 0, 65344, 0 } } \ - }, /* measured value */ \ + ZAP_REPORT_DIRECTION(REPORTED), 0x0000, 0x0029, 0xFFFD, ZAP_CLUSTER_MASK(SERVER), 0x0000, { { 0, 65344, 0 } } \ + }, /* cluster revision */ \ + \ + /* Endpoint: 0, Cluster: Relative Humidity Measurement (server) */ \ + { \ + ZAP_REPORT_DIRECTION(REPORTED), 0x0000, 0x0405, 0x0000, ZAP_CLUSTER_MASK(SERVER), 0x0000, { { 0, 65344, 0 } } \ + }, /* measured value */ \ \ /* Endpoint: 1, Cluster: On/off (server) */ \ { \ diff --git a/examples/all-clusters-app/all-clusters-common/gen/gen_config.h b/examples/all-clusters-app/all-clusters-common/gen/gen_config.h index 2f0504a00b5cea..449294ddb41dc9 100644 --- a/examples/all-clusters-app/all-clusters-common/gen/gen_config.h +++ b/examples/all-clusters-app/all-clusters-common/gen/gen_config.h @@ -56,7 +56,6 @@ #define EMBER_AF_MEDIA_INPUT_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_MEDIA_PLAYBACK_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_NETWORK_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) -#define EMBER_AF_OTA_CLIENT_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_SERVER_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OCCUPANCY_SENSING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT (2) @@ -224,11 +223,6 @@ #define EMBER_AF_PLUGIN_NETWORK_COMMISSIONING_SERVER #define EMBER_AF_PLUGIN_NETWORK_COMMISSIONING -// Use this macro to check if the server side of the OTA Software Update Client cluster is included -#define ZCL_USING_OTA_CLIENT_CLUSTER_SERVER -#define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_CLIENT_SERVER -#define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_CLIENT - // Use this macro to check if the server side of the OTA Software Update Server cluster is included #define ZCL_USING_OTA_SERVER_CLUSTER_SERVER #define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_SERVER_SERVER diff --git a/examples/chip-tool/commands/clusters/Commands.h b/examples/chip-tool/commands/clusters/Commands.h index 024d376293f04f..05ffd60fcd0f69 100644 --- a/examples/chip-tool/commands/clusters/Commands.h +++ b/examples/chip-tool/commands/clusters/Commands.h @@ -570,6 +570,24 @@ static void OnNetworkCommissioningClusterUpdateWiFiNetworkResponse(void * contex command->SetCommandExitStatus(true); } +static void OnOtaSoftwareUpdateServerClusterApplyUpdateRequestResponse(void * context, uint8_t action, uint32_t delayedActionTime) +{ + ChipLogProgress(chipTool, "OtaSoftwareUpdateServerClusterApplyUpdateRequestResponse"); + + ModelCommand * command = reinterpret_cast(context); + command->SetCommandExitStatus(true); +} + +static void OnOtaSoftwareUpdateServerClusterQueryImageResponse(void * context, uint32_t delayedActionTime, uint8_t * imageURI, + uint32_t softwareVersion, chip::ByteSpan updateToken, + uint8_t userConsentNeeded, chip::ByteSpan metadataForClient) +{ + ChipLogProgress(chipTool, "OtaSoftwareUpdateServerClusterQueryImageResponse"); + + ModelCommand * command = reinterpret_cast(context); + command->SetCommandExitStatus(true); +} + static void OnOperationalCredentialsClusterOpCSRResponse(void * context, chip::ByteSpan CSR, chip::ByteSpan CSRNonce, chip::ByteSpan VendorReserved1, chip::ByteSpan VendorReserved2, chip::ByteSpan VendorReserved3, chip::ByteSpan Signature) @@ -990,6 +1008,7 @@ static void OnTestClusterListStructOctetStringListAttributeResponse(void * conte | MediaInput | 0x0507 | | MediaPlayback | 0x0506 | | NetworkCommissioning | 0x0031 | +| OtaSoftwareUpdateServer | 0x0029 | | OnOff | 0x0006 | | OperationalCredentials | 0x003E | | PumpConfigurationAndControl | 0x0200 | @@ -1033,6 +1052,7 @@ constexpr chip::ClusterId kLowPowerClusterId = 0x0508; constexpr chip::ClusterId kMediaInputClusterId = 0x0507; constexpr chip::ClusterId kMediaPlaybackClusterId = 0x0506; constexpr chip::ClusterId kNetworkCommissioningClusterId = 0x0031; +constexpr chip::ClusterId kOtaSoftwareUpdateServerClusterId = 0x0029; constexpr chip::ClusterId kOnOffClusterId = 0x0006; constexpr chip::ClusterId kOperationalCredentialsClusterId = 0x003E; constexpr chip::ClusterId kPumpConfigurationAndControlClusterId = 0x0200; @@ -11910,6 +11930,209 @@ class ReadNetworkCommissioningClusterRevision : public ModelCommand new chip::Callback::Callback(OnDefaultFailureResponse, this); }; +/*----------------------------------------------------------------------------*\ +| Cluster OtaSoftwareUpdateServer | 0x0029 | +|------------------------------------------------------------------------------| +| Commands: | | +| * ApplyUpdateRequest | 0x01 | +| * NotifyUpdateApplied | 0x02 | +| * QueryImage | 0x00 | +|------------------------------------------------------------------------------| +| Attributes: | | +| * ClusterRevision | 0xFFFD | +\*----------------------------------------------------------------------------*/ + +/* + * Command ApplyUpdateRequest + */ +class OtaSoftwareUpdateServerApplyUpdateRequest : public ModelCommand +{ +public: + OtaSoftwareUpdateServerApplyUpdateRequest() : ModelCommand("apply-update-request") + { + AddArgument("updateToken", &mUpdateToken); + AddArgument("newVersion", 0, UINT32_MAX, &mNewVersion); + ModelCommand::AddArguments(); + } + ~OtaSoftwareUpdateServerApplyUpdateRequest() + { + delete onSuccessCallback; + delete onFailureCallback; + } + + CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x0029) command (0x01) on endpoint %" PRIu16, endpointId); + + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, endpointId); + return cluster.ApplyUpdateRequest(onSuccessCallback->Cancel(), onFailureCallback->Cancel(), mUpdateToken, mNewVersion); + } + +private: + chip::Callback::Callback * onSuccessCallback = + new chip::Callback::Callback( + OnOtaSoftwareUpdateServerClusterApplyUpdateRequestResponse, this); + chip::Callback::Callback * onFailureCallback = + new chip::Callback::Callback(OnDefaultFailureResponse, this); + chip::ByteSpan mUpdateToken; + uint32_t mNewVersion; +}; + +/* + * Command NotifyUpdateApplied + */ +class OtaSoftwareUpdateServerNotifyUpdateApplied : public ModelCommand +{ +public: + OtaSoftwareUpdateServerNotifyUpdateApplied() : ModelCommand("notify-update-applied") + { + AddArgument("updateToken", &mUpdateToken); + AddArgument("currentVersion", 0, UINT32_MAX, &mCurrentVersion); + ModelCommand::AddArguments(); + } + ~OtaSoftwareUpdateServerNotifyUpdateApplied() + { + delete onSuccessCallback; + delete onFailureCallback; + } + + CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x0029) command (0x02) on endpoint %" PRIu16, endpointId); + + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, endpointId); + return cluster.NotifyUpdateApplied(onSuccessCallback->Cancel(), onFailureCallback->Cancel(), mUpdateToken, mCurrentVersion); + } + +private: + chip::Callback::Callback * onSuccessCallback = + new chip::Callback::Callback(OnDefaultSuccessResponse, this); + chip::Callback::Callback * onFailureCallback = + new chip::Callback::Callback(OnDefaultFailureResponse, this); + chip::ByteSpan mUpdateToken; + uint32_t mCurrentVersion; +}; + +/* + * Command QueryImage + */ +class OtaSoftwareUpdateServerQueryImage : public ModelCommand +{ +public: + OtaSoftwareUpdateServerQueryImage() : ModelCommand("query-image") + { + AddArgument("vendorId", 0, UINT16_MAX, &mVendorId); + AddArgument("productId", 0, UINT16_MAX, &mProductId); + AddArgument("imageType", 0, UINT16_MAX, &mImageType); + AddArgument("hardwareVersion", 0, UINT16_MAX, &mHardwareVersion); + AddArgument("currentVersion", 0, UINT32_MAX, &mCurrentVersion); + AddArgument("protocolsSupported", 0, UINT8_MAX, &mProtocolsSupported); + AddArgument("location", &mLocation); + AddArgument("clientCanConsent", 0, UINT8_MAX, &mClientCanConsent); + AddArgument("metadataForServer", &mMetadataForServer); + ModelCommand::AddArguments(); + } + ~OtaSoftwareUpdateServerQueryImage() + { + delete onSuccessCallback; + delete onFailureCallback; + } + + CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x0029) command (0x00) on endpoint %" PRIu16, endpointId); + + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, endpointId); + return cluster.QueryImage(onSuccessCallback->Cancel(), onFailureCallback->Cancel(), mVendorId, mProductId, mImageType, + mHardwareVersion, mCurrentVersion, mProtocolsSupported, + chip::ByteSpan(chip::Uint8::from_char(mLocation), strlen(mLocation)), mClientCanConsent, + mMetadataForServer); + } + +private: + chip::Callback::Callback * onSuccessCallback = + new chip::Callback::Callback( + OnOtaSoftwareUpdateServerClusterQueryImageResponse, this); + chip::Callback::Callback * onFailureCallback = + new chip::Callback::Callback(OnDefaultFailureResponse, this); + uint16_t mVendorId; + uint16_t mProductId; + uint16_t mImageType; + uint16_t mHardwareVersion; + uint32_t mCurrentVersion; + uint8_t mProtocolsSupported; + char * mLocation; + uint8_t mClientCanConsent; + chip::ByteSpan mMetadataForServer; +}; + +/* + * Discover Attributes + */ +class DiscoverOtaSoftwareUpdateServerAttributes : public ModelCommand +{ +public: + DiscoverOtaSoftwareUpdateServerAttributes() : ModelCommand("discover") { ModelCommand::AddArguments(); } + + ~DiscoverOtaSoftwareUpdateServerAttributes() + { + delete onSuccessCallback; + delete onFailureCallback; + } + + CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x0000) command (0x0C) on endpoint %" PRIu16, endpointId); + + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, endpointId); + return cluster.DiscoverAttributes(onSuccessCallback->Cancel(), onFailureCallback->Cancel()); + } + +private: + chip::Callback::Callback * onSuccessCallback = + new chip::Callback::Callback(OnDefaultSuccessResponse, this); + chip::Callback::Callback * onFailureCallback = + new chip::Callback::Callback(OnDefaultFailureResponse, this); +}; + +/* + * Attribute ClusterRevision + */ +class ReadOtaSoftwareUpdateServerClusterRevision : public ModelCommand +{ +public: + ReadOtaSoftwareUpdateServerClusterRevision() : ModelCommand("read") + { + AddArgument("attr-name", "cluster-revision"); + ModelCommand::AddArguments(); + } + + ~ReadOtaSoftwareUpdateServerClusterRevision() + { + delete onSuccessCallback; + delete onFailureCallback; + } + + CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x0029) command (0x00) on endpoint %" PRIu16, endpointId); + + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, endpointId); + return cluster.ReadAttributeClusterRevision(onSuccessCallback->Cancel(), onFailureCallback->Cancel()); + } + +private: + chip::Callback::Callback * onSuccessCallback = + new chip::Callback::Callback(OnInt16uAttributeResponse, this); + chip::Callback::Callback * onFailureCallback = + new chip::Callback::Callback(OnDefaultFailureResponse, this); +}; + /*----------------------------------------------------------------------------*\ | Cluster OnOff | 0x0006 | |------------------------------------------------------------------------------| @@ -18197,6 +18420,18 @@ void registerClusterNetworkCommissioning(Commands & commands) commands.Register(clusterName, clusterCommands); } +void registerClusterOtaSoftwareUpdateServer(Commands & commands) +{ + const char * clusterName = "OtaSoftwareUpdateServer"; + + commands_list clusterCommands = { + make_unique(), make_unique(), + make_unique(), make_unique(), + make_unique(), + }; + + commands.Register(clusterName, clusterCommands); +} void registerClusterOnOff(Commands & commands) { const char * clusterName = "OnOff"; @@ -18501,6 +18736,7 @@ void registerClusters(Commands & commands) registerClusterMediaInput(commands); registerClusterMediaPlayback(commands); registerClusterNetworkCommissioning(commands); + registerClusterOtaSoftwareUpdateServer(commands); registerClusterOnOff(commands); registerClusterOperationalCredentials(commands); registerClusterPumpConfigurationAndControl(commands); diff --git a/src/app/clusters/ota-server/ota-server-delegate.h b/src/app/clusters/ota-server/ota-server-delegate.h new file mode 100644 index 00000000000000..6da0dc2447ffff --- /dev/null +++ b/src/app/clusters/ota-server/ota-server-delegate.h @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace app { +namespace clusters { + +/** @brief + * Defines methods for implementing application-specific logic for the OTA Server Cluster. + */ +class OTAServerDelegate +{ +public: + // TODO: protocolsSupported should be list of OTADownloadProtocol enums, not uint8_t* + virtual EmberAfStatus HandleQueryImage(uint16_t vendorId, uint16_t productId, uint16_t imageType, uint16_t hardwareVersion, + uint32_t currentVersion, uint8_t * protocolsSupported, const chip::ByteSpan & location, + bool clientCanConsent, const chip::ByteSpan & metadataForServer) = 0; + + virtual EmberAfStatus HandleApplyUpdateRequest(const chip::ByteSpan & updateToken, uint32_t newVersion) = 0; + + virtual EmberAfStatus HandleNotifyUpdateApplied(const chip::ByteSpan & updateToken, uint32_t currentVersion) = 0; + + virtual ~OTAServerDelegate() = default; +}; + +} // namespace clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/ota-server/ota-server.cpp b/src/app/clusters/ota-server/ota-server.cpp index 36868afce48931..646cfe49365b7d 100644 --- a/src/app/clusters/ota-server/ota-server.cpp +++ b/src/app/clusters/ota-server/ota-server.cpp @@ -28,13 +28,44 @@ #include +#include "ota-server-delegate.h" +#include "ota-server.h" + using namespace chip; +using namespace chip::app::clusters; + +using chip::app::clusters::OTAServerDelegate; + +namespace { +constexpr uint8_t kLocationParamLength = 2; // The expected length of the Location parameter in QueryImage +constexpr size_t kMaxMetadataLen = 512; // The maximum length of Metadata in any OTA Server command +constexpr size_t kUpdateTokenParamLength = 32; // The expected length of the Update Token parameter used in multiple commands -// TODO: all callbacks need implementations +OTAServerDelegate * gDelegateTable[EMBER_AF_OTA_SERVER_CLUSTER_SERVER_ENDPOINT_COUNT] = { nullptr }; + +OTAServerDelegate * GetDelegate(chip::EndpointId endpoint) +{ + uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_OTA_SERVER_CLUSTER_ID); + return (ep == 0xFF ? NULL : gDelegateTable[ep]); +} + +bool SendStatusIfDelegateNull(chip::EndpointId endpointId) +{ + if (GetDelegate(endpointId) == nullptr) + { + ChipLogError(Zcl, "No OTAServerDelegate set for ep:%d", endpointId); + emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_UNSUP_COMMAND); + return true; + } + return false; +} +} // namespace /** * @brief OTA Software Update Server Cluster ApplyUpdateRequest Command callback * + * @note It is the application's reponsibility to send the ApplyUpdateRequestResponse command after this is handled. + * * @param updateToken Identifier for the Software Image to be applied. Should be 32 octets long. * @param newVersion The SoftwareVersion value of the new Software Image that the client is ready to apply. */ @@ -42,12 +73,36 @@ using namespace chip; bool emberAfOtaSoftwareUpdateServerClusterApplyUpdateRequestCallback(app::Command * commandObj, chip::ByteSpan updateToken, uint32_t newVersion) { - return false; + EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS; + chip::EndpointId endpointId = emberAfCurrentEndpoint(); + OTAServerDelegate * delegate = GetDelegate(endpointId); + + ChipLogDetail(Zcl, "OTA Server received ApplyUpdateRequest"); + + if (SendStatusIfDelegateNull(endpointId)) + { + return true; + } + + if (updateToken.size() != kUpdateTokenParamLength) + { + ChipLogError(Zcl, "expected size %d for UpdateToken, got %d", kUpdateTokenParamLength, updateToken.size()); + emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_ARGUMENT); + } + + status = delegate->HandleApplyUpdateRequest(updateToken, newVersion); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + emberAfSendImmediateDefaultResponse(status); + } + + return true; } /** * @brief OTA Software Update Server Cluster NotifyUpdateApplied Command callback * + * * @param updateToken Identifier for the Software Image that was applied. Should be 32 octets long. * @param currentVersion The current SoftwareVersion value. Should match the SoftwarVersion attribute in the * OTA Client's Basic Information Cluster. @@ -56,7 +111,30 @@ bool emberAfOtaSoftwareUpdateServerClusterApplyUpdateRequestCallback(app::Comman bool emberAfOtaSoftwareUpdateServerClusterNotifyUpdateAppliedCallback(app::Command * commandObj, chip::ByteSpan updateToken, uint32_t currentVersion) { - return false; + EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS; + chip::EndpointId endpointId = emberAfCurrentEndpoint(); + OTAServerDelegate * delegate = GetDelegate(endpointId); + + ChipLogDetail(Zcl, "OTA Server received NotifyUpdateUpplied"); + + if (SendStatusIfDelegateNull(endpointId)) + { + return true; + } + + if (updateToken.size() != kUpdateTokenParamLength) + { + ChipLogError(Zcl, "expected size %d for UpdateToken, got %d", kUpdateTokenParamLength, updateToken.size()); + emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_ARGUMENT); + } + + status = delegate->HandleNotifyUpdateApplied(updateToken, currentVersion); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + emberAfSendImmediateDefaultResponse(status); + } + + return true; } /** @@ -82,5 +160,47 @@ bool emberAfOtaSoftwareUpdateServerClusterQueryImageCallback( /* TYPE WARNING: array array defaults to */ uint8_t * protocolsSupported, uint8_t * location, uint8_t clientCanConsent, chip::ByteSpan metadataForServer) { - return false; + EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS; + chip::EndpointId endpointId = emberAfCurrentEndpoint(); + OTAServerDelegate * delegate = GetDelegate(endpointId); + + if (SendStatusIfDelegateNull(endpointId)) + { + return true; + }; + + ChipLogDetail(Zcl, "OTA Server received QueryImage"); + + // TODO: (#7112) change location size checking once CHAR_STRING is supported + const uint8_t locationLen = emberAfStringLength(location); + if (locationLen != kLocationParamLength) + { + ChipLogError(Zcl, "expected location length %d, got %d", locationLen, kLocationParamLength); + emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_ARGUMENT); + } + else if (metadataForServer.size() > kMaxMetadataLen) + { + ChipLogError(Zcl, "metadata size %d exceeds max %d", metadataForServer.size(), kMaxMetadataLen); + emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_ARGUMENT); + } + + chip::ByteSpan locationSpan(location, locationLen); + + status = delegate->HandleQueryImage(vendorId, productId, imageType, hardwareVersion, currentVersion, protocolsSupported, + locationSpan, clientCanConsent, metadataForServer); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + emberAfSendImmediateDefaultResponse(status); + } + + return true; +} + +void chip::app::clusters::OTAServer::SetDelegate(chip::EndpointId endpointId, OTAServerDelegate * delegate) +{ + uint8_t ep = emberAfFindClusterServerEndpointIndex(endpointId, ZCL_OTA_SERVER_CLUSTER_ID); + if (ep != 0xFF) + { + gDelegateTable[ep] = delegate; + } } diff --git a/src/app/clusters/ota-server/ota-server.h b/src/app/clusters/ota-server/ota-server.h new file mode 100644 index 00000000000000..d2cd1ecab39b81 --- /dev/null +++ b/src/app/clusters/ota-server/ota-server.h @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ota-server-delegate.h" + +namespace chip { +namespace app { +namespace clusters { +namespace OTAServer { + +void SetDelegate(chip::EndpointId endpointId, OTAServerDelegate * delegate); + +} +} // namespace clusters +} // namespace app +} // namespace chip diff --git a/src/app/util/af-enums.h b/src/app/util/af-enums.h index 000a3bb7684c69..f74d605d542453 100644 --- a/src/app/util/af-enums.h +++ b/src/app/util/af-enums.h @@ -55,6 +55,7 @@ typedef enum EMBER_ZCL_STATUS_SOFTWARE_FAILURE = 0xC1, EMBER_ZCL_STATUS_UNSUPPORTED_CLUSTER = 0xC3, EMBER_ZCL_STATUS_LIMIT_REACHED = 0xC4, + EMBER_ZCL_STATUS_INVALID_ARGUMENT = 0xC6, } EmberAfStatus; typedef enum diff --git a/src/app/zap-templates/zcl/chip-ota.xml b/src/app/zap-templates/zcl/chip-ota.xml index f7b784d8fd8fe9..5f68be3c00617c 100644 --- a/src/app/zap-templates/zcl/chip-ota.xml +++ b/src/app/zap-templates/zcl/chip-ota.xml @@ -93,7 +93,7 @@ limitations under the License. true default ota server update possible - + Notify OTA Server that an update was applied diff --git a/src/app/zap_cluster_list.py b/src/app/zap_cluster_list.py index 89ff0b8c198d84..6f177096da049a 100755 --- a/src/app/zap_cluster_list.py +++ b/src/app/zap_cluster_list.py @@ -100,8 +100,8 @@ 'ON_OFF_CLUSTER': [], 'OPERATIONAL_CREDENTIALS_CLUSTER': [], 'OTA_BOOTLOAD_CLUSTER': [], - 'OTA_SERVER_CLUSTER': ['ota-server'], - 'OTA_CLIENT_CLUSTER': [], + 'OTA_SERVER_CLUSTER': [], + 'OTA_CLIENT_CLUSTER': ['ota-server'], 'POWER_CONFIG_CLUSTER': [], 'PUMP_CONFIG_CONTROL_CLUSTER': ['pump-configuration-and-control-client'], 'RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER': [], diff --git a/src/controller/data_model/controller-clusters.zap b/src/controller/data_model/controller-clusters.zap index db3fd4beca331f..394c9775616547 100644 --- a/src/controller/data_model/controller-clusters.zap +++ b/src/controller/data_model/controller-clusters.zap @@ -1285,6 +1285,100 @@ } ] }, + { + "name": "OTA Software Update Server", + "code": 41, + "mfgCode": null, + "define": "OTA_SERVER_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "QueryImage", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "ApplyUpdateRequest", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "NotifyUpdateApplied", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "client", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "OTA Software Update Server", + "code": 41, + "mfgCode": null, + "define": "OTA_SERVER_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "QueryImageResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "ApplyUpdateRequestResponse", + "code": 4, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "cluster revision", + "code": 65533, + "mfgCode": null, + "side": "server", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, { "name": "General Commissioning", "code": 48, diff --git a/src/controller/data_model/gen/CHIPClientCallbacks.cpp b/src/controller/data_model/gen/CHIPClientCallbacks.cpp index 59744d85dad33d..385ee212806f5f 100644 --- a/src/controller/data_model/gen/CHIPClientCallbacks.cpp +++ b/src/controller/data_model/gen/CHIPClientCallbacks.cpp @@ -2219,6 +2219,52 @@ bool emberAfNetworkCommissioningClusterUpdateWiFiNetworkResponseCallback(chip::a return true; } +bool emberAfOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallback(chip::app::Command * commandObj, uint8_t action, + uint32_t delayedActionTime) +{ + ChipLogProgress(Zcl, "ApplyUpdateRequestResponse:"); + ChipLogProgress(Zcl, " action: %" PRIu8 "", action); + ChipLogProgress(Zcl, " delayedActionTime: %" PRIu32 "", delayedActionTime); + + GET_CLUSTER_RESPONSE_CALLBACKS("OtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallback"); + + Callback::Callback * cb = + Callback::Callback::FromCancelable(onSuccessCallback); + cb->mCall(cb->mContext, action, delayedActionTime); + return true; +} + +bool emberAfOtaSoftwareUpdateServerClusterQueryImageResponseCallback(chip::app::Command * commandObj, uint8_t status, + uint32_t delayedActionTime, uint8_t * imageURI, + uint32_t softwareVersion, chip::ByteSpan updateToken, + uint8_t userConsentNeeded, chip::ByteSpan metadataForClient) +{ + ChipLogProgress(Zcl, "QueryImageResponse:"); + LogStatus(status); + ChipLogProgress(Zcl, " delayedActionTime: %" PRIu32 "", delayedActionTime); + // Currently the generated code emits `uint8_t *` for CHAR_STRING, it needs to emits chip::ByteSpan + // ChipLogProgress(Zcl, " imageURI: %.*s", imageURI.size(), imageURI.data()); + ChipLogProgress(Zcl, " softwareVersion: %" PRIu32 "", softwareVersion); + ChipLogProgress(Zcl, " updateToken: %zu", updateToken.size()); + ChipLogProgress(Zcl, " userConsentNeeded: %" PRIu8 "", userConsentNeeded); + ChipLogProgress(Zcl, " metadataForClient: %zu", metadataForClient.size()); + + GET_CLUSTER_RESPONSE_CALLBACKS("OtaSoftwareUpdateServerClusterQueryImageResponseCallback"); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + Callback::Callback * cb = + Callback::Callback::FromCancelable(onFailureCallback); + cb->mCall(cb->mContext, status); + return true; + } + + Callback::Callback * cb = + Callback::Callback::FromCancelable(onSuccessCallback); + cb->mCall(cb->mContext, delayedActionTime, imageURI, softwareVersion, updateToken, userConsentNeeded, metadataForClient); + return true; +} + bool emberAfOperationalCredentialsClusterOpCSRResponseCallback(chip::app::Command * commandObj, chip::ByteSpan CSR, chip::ByteSpan CSRNonce, chip::ByteSpan VendorReserved1, chip::ByteSpan VendorReserved2, chip::ByteSpan VendorReserved3, diff --git a/src/controller/data_model/gen/CHIPClientCallbacks.h b/src/controller/data_model/gen/CHIPClientCallbacks.h index 84c5275ccafbea..73069e2664aee4 100644 --- a/src/controller/data_model/gen/CHIPClientCallbacks.h +++ b/src/controller/data_model/gen/CHIPClientCallbacks.h @@ -117,6 +117,12 @@ typedef void (*NetworkCommissioningClusterUpdateThreadNetworkResponseCallback)(v uint8_t * debugText); typedef void (*NetworkCommissioningClusterUpdateWiFiNetworkResponseCallback)(void * context, uint8_t errorCode, uint8_t * debugText); +typedef void (*OtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallback)(void * context, uint8_t action, + uint32_t delayedActionTime); +typedef void (*OtaSoftwareUpdateServerClusterQueryImageResponseCallback)(void * context, uint32_t delayedActionTime, + uint8_t * imageURI, uint32_t softwareVersion, + chip::ByteSpan updateToken, uint8_t userConsentNeeded, + chip::ByteSpan metadataForClient); typedef void (*OperationalCredentialsClusterOpCSRResponseCallback)(void * context, chip::ByteSpan CSR, chip::ByteSpan CSRNonce, chip::ByteSpan VendorReserved1, chip::ByteSpan VendorReserved2, chip::ByteSpan VendorReserved3, chip::ByteSpan Signature); diff --git a/src/controller/data_model/gen/CHIPClusters.cpp b/src/controller/data_model/gen/CHIPClusters.cpp index 5ff7d8ebfc6b55..e78bf5ab5ee4c7 100644 --- a/src/controller/data_model/gen/CHIPClusters.cpp +++ b/src/controller/data_model/gen/CHIPClusters.cpp @@ -5876,6 +5876,171 @@ CHIP_ERROR NetworkCommissioningCluster::ReadAttributeClusterRevision(Callback::C return SendCommand(seqNum, std::move(encodedCommand), onSuccessCallback, onFailureCallback); } +// OtaSoftwareUpdateServer Cluster Commands +CHIP_ERROR OtaSoftwareUpdateServerCluster::ApplyUpdateRequest(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, chip::ByteSpan updateToken, + uint32_t newVersion) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + app::CommandSender * sender = nullptr; + 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, kApplyUpdateRequestCommandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + + SuccessOrExit(err = chip::app::InteractionModelEngine::GetInstance()->NewCommandSender(&sender)); + + SuccessOrExit(err = sender->PrepareCommand(&cmdParams)); + + VerifyOrExit((writer = sender->GetCommandDataElementTLVWriter()) != 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, onSuccessCallback, onFailureCallback); + + err = mDevice->SendCommands(sender); + +exit: + // On error, we are responsible to close the sender. + if (err != CHIP_NO_ERROR && sender != nullptr) + { + sender->Shutdown(); + } + return err; +} + +CHIP_ERROR OtaSoftwareUpdateServerCluster::NotifyUpdateApplied(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, chip::ByteSpan updateToken, + uint32_t currentVersion) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + app::CommandSender * sender = nullptr; + 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, kNotifyUpdateAppliedCommandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + + SuccessOrExit(err = chip::app::InteractionModelEngine::GetInstance()->NewCommandSender(&sender)); + + SuccessOrExit(err = sender->PrepareCommand(&cmdParams)); + + VerifyOrExit((writer = sender->GetCommandDataElementTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + // updateToken: octetString + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), updateToken)); + // currentVersion: int32u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), currentVersion)); + + 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, onSuccessCallback, onFailureCallback); + + err = mDevice->SendCommands(sender); + +exit: + // On error, we are responsible to close the sender. + if (err != CHIP_NO_ERROR && sender != nullptr) + { + sender->Shutdown(); + } + return err; +} + +CHIP_ERROR OtaSoftwareUpdateServerCluster::QueryImage(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback, uint16_t vendorId, + uint16_t productId, uint16_t imageType, uint16_t hardwareVersion, + uint32_t currentVersion, uint8_t protocolsSupported, chip::ByteSpan location, + uint8_t clientCanConsent, chip::ByteSpan metadataForServer) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + app::CommandSender * sender = nullptr; + 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, kQueryImageCommandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + + SuccessOrExit(err = chip::app::InteractionModelEngine::GetInstance()->NewCommandSender(&sender)); + + SuccessOrExit(err = sender->PrepareCommand(&cmdParams)); + + VerifyOrExit((writer = sender->GetCommandDataElementTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + // vendorId: int16u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), vendorId)); + // productId: int16u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), productId)); + // imageType: int16u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), imageType)); + // hardwareVersion: int16u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), hardwareVersion)); + // currentVersion: int32u + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), currentVersion)); + // protocolsSupported: oTADownloadProtocol + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), protocolsSupported)); + // location: charString + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), location)); + // clientCanConsent: boolean + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), clientCanConsent)); + // metadataForServer: octetString + SuccessOrExit(err = writer->Put(TLV::ContextTag(argSeqNumber++), metadataForServer)); + + 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, onSuccessCallback, onFailureCallback); + + err = mDevice->SendCommands(sender); + +exit: + // On error, we are responsible to close the sender. + if (err != CHIP_NO_ERROR && sender != nullptr) + { + sender->Shutdown(); + } + return err; +} + +// OtaSoftwareUpdateServer Cluster Attributes +CHIP_ERROR OtaSoftwareUpdateServerCluster::DiscoverAttributes(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback) +{ + uint8_t seqNum = mDevice->GetNextSequenceNumber(); + System::PacketBufferHandle encodedCommand = encodeOtaSoftwareUpdateServerClusterDiscoverAttributes(seqNum, mEndpoint); + return SendCommand(seqNum, std::move(encodedCommand), onSuccessCallback, onFailureCallback); +} +CHIP_ERROR OtaSoftwareUpdateServerCluster::ReadAttributeClusterRevision(Callback::Cancelable * onSuccessCallback, + Callback::Cancelable * onFailureCallback) +{ + uint8_t seqNum = mDevice->GetNextSequenceNumber(); + System::PacketBufferHandle encodedCommand = encodeOtaSoftwareUpdateServerClusterReadClusterRevisionAttribute(seqNum, mEndpoint); + return SendCommand(seqNum, std::move(encodedCommand), onSuccessCallback, onFailureCallback); +} + // OnOff Cluster Commands CHIP_ERROR OnOffCluster::Off(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback) { diff --git a/src/controller/data_model/gen/CHIPClusters.h b/src/controller/data_model/gen/CHIPClusters.h index 813e1f31a4ae06..2bd7d8541bc137 100644 --- a/src/controller/data_model/gen/CHIPClusters.h +++ b/src/controller/data_model/gen/CHIPClusters.h @@ -53,6 +53,7 @@ constexpr ClusterId kLowPowerClusterId = 0x0508; constexpr ClusterId kMediaInputClusterId = 0x0507; constexpr ClusterId kMediaPlaybackClusterId = 0x0506; constexpr ClusterId kNetworkCommissioningClusterId = 0x0031; +constexpr ClusterId kOtaSoftwareUpdateServerClusterId = 0x0029; constexpr ClusterId kOnOffClusterId = 0x0006; constexpr ClusterId kOperationalCredentialsClusterId = 0x003E; constexpr ClusterId kPumpConfigurationAndControlClusterId = 0x0200; @@ -894,6 +895,32 @@ class DLL_EXPORT NetworkCommissioningCluster : public ClusterBase static constexpr CommandId kUpdateWiFiNetworkCommandId = 0x04; }; +class DLL_EXPORT OtaSoftwareUpdateServerCluster : public ClusterBase +{ +public: + OtaSoftwareUpdateServerCluster() : ClusterBase(kOtaSoftwareUpdateServerClusterId) {} + ~OtaSoftwareUpdateServerCluster() {} + + // 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 currentVersion); + CHIP_ERROR QueryImage(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, uint16_t vendorId, + uint16_t productId, uint16_t imageType, uint16_t hardwareVersion, uint32_t currentVersion, + uint8_t protocolsSupported, chip::ByteSpan location, uint8_t clientCanConsent, + chip::ByteSpan metadataForServer); + + // Cluster Attributes + CHIP_ERROR DiscoverAttributes(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback); + CHIP_ERROR ReadAttributeClusterRevision(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback); + +private: + static constexpr CommandId kApplyUpdateRequestCommandId = 0x01; + static constexpr CommandId kNotifyUpdateAppliedCommandId = 0x02; + static constexpr CommandId kQueryImageCommandId = 0x00; +}; + class DLL_EXPORT OnOffCluster : public ClusterBase { public: diff --git a/src/controller/data_model/gen/IMClusterCommandHandler.cpp b/src/controller/data_model/gen/IMClusterCommandHandler.cpp index 5f35cd36f1c0e8..b144470cbdaf24 100644 --- a/src/controller/data_model/gen/IMClusterCommandHandler.cpp +++ b/src/controller/data_model/gen/IMClusterCommandHandler.cpp @@ -4006,6 +4006,210 @@ void DispatchClientCommand(app::Command * apCommandObj, CommandId aCommandId, En } // namespace NetworkCommissioning +namespace OtaSoftwareUpdateServer { + +void DispatchClientCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, 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; + CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; + uint32_t validArgumentCount = 0; + uint32_t expectArgumentCount = 0; + uint32_t currentDecodeTagId = 0; + bool wasHandled = false; + { + switch (aCommandId) + { + case ZCL_APPLY_UPDATE_REQUEST_RESPONSE_COMMAND_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) + { + // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. + wasHandled = emberAfOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallback(apCommandObj, action, + delayedActionTime); + } + break; + } + case ZCL_QUERY_IMAGE_RESPONSE_COMMAND_ID: { + expectArgumentCount = 7; + uint8_t status; + uint32_t delayedActionTime; + const uint8_t * imageURI; + uint32_t softwareVersion; + chip::ByteSpan updateToken; + uint8_t userConsentNeeded; + chip::ByteSpan metadataForClient; + bool argExists[7]; + + 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 < 7) + { + 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: + // TODO(#5542): The cluster handlers should accept a ByteSpan for all string types. + TLVUnpackError = aDataTlv.GetDataPtr(imageURI); + break; + case 3: + TLVUnpackError = aDataTlv.Get(softwareVersion); + break; + case 4: { + const uint8_t * data = nullptr; + TLVUnpackError = aDataTlv.GetDataPtr(data); + updateToken = chip::ByteSpan(data, aDataTlv.GetLength()); + } + break; + case 5: + TLVUnpackError = aDataTlv.Get(userConsentNeeded); + break; + case 6: { + const uint8_t * data = nullptr; + TLVUnpackError = aDataTlv.GetDataPtr(data); + metadataForClient = chip::ByteSpan(data, aDataTlv.GetLength()); + } + 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 && 7 == validArgumentCount) + { + // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. + wasHandled = emberAfOtaSoftwareUpdateServerClusterQueryImageResponseCallback( + apCommandObj, status, delayedActionTime, const_cast(imageURI), softwareVersion, updateToken, + userConsentNeeded, metadataForClient); + } + break; + } + default: { + // Unrecognized command ID, error status will apply. + chip::app::CommandPathParams returnStatusParam = { aEndpointId, + 0, // GroupId + ZCL_OTA_SERVER_CLUSTER_ID, aCommandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + apCommandObj->AddStatusCode(&returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, + Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure); + ChipLogError(Zcl, "Unknown command %" PRIx16 " for cluster %" PRIx16, aCommandId, ZCL_OTA_SERVER_CLUSTER_ID); + return; + } + } + } + + if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) + { + chip::app::CommandPathParams returnStatusParam = { aEndpointId, + 0, // GroupId + ZCL_OTA_SERVER_CLUSTER_ID, aCommandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + apCommandObj->AddStatusCode(&returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, + Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure); + ChipLogProgress(Zcl, + "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32 + " (last decoded tag = %" PRIu32, + validArgumentCount, expectArgumentCount, TLVError, TLVUnpackError, currentDecodeTagId); + } +} + +} // namespace OtaSoftwareUpdateServer + namespace OperationalCredentials { void DispatchClientCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) @@ -5126,6 +5330,9 @@ void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aC case ZCL_NETWORK_COMMISSIONING_CLUSTER_ID: clusters::NetworkCommissioning::DispatchClientCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; + case ZCL_OTA_SERVER_CLUSTER_ID: + clusters::OtaSoftwareUpdateServer::DispatchClientCommand(apCommandObj, aCommandId, aEndPointId, aReader); + break; case ZCL_OPERATIONAL_CREDENTIALS_CLUSTER_ID: clusters::OperationalCredentials::DispatchClientCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; diff --git a/src/controller/data_model/gen/call-command-handler.cpp b/src/controller/data_model/gen/call-command-handler.cpp index 6b6c623d07ad9e..0f9833aaa80d37 100644 --- a/src/controller/data_model/gen/call-command-handler.cpp +++ b/src/controller/data_model/gen/call-command-handler.cpp @@ -53,6 +53,7 @@ EmberAfStatus emberAfLowPowerClusterClientCommandParse(EmberAfClusterCommand * c EmberAfStatus emberAfMediaInputClusterClientCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfMediaPlaybackClusterClientCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfNetworkCommissioningClusterClientCommandParse(EmberAfClusterCommand * cmd); +EmberAfStatus emberAfOtaSoftwareUpdateServerClusterClientCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfOnOffClusterClientCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfOperationalCredentialsClusterClientCommandParse(EmberAfClusterCommand * cmd); EmberAfStatus emberAfPumpConfigurationAndControlClusterClientCommandParse(EmberAfClusterCommand * cmd); @@ -192,6 +193,9 @@ EmberAfStatus emberAfClusterSpecificCommandParse(EmberAfClusterCommand * cmd) case ZCL_NETWORK_COMMISSIONING_CLUSTER_ID: result = emberAfNetworkCommissioningClusterClientCommandParse(cmd); break; + case ZCL_OTA_SERVER_CLUSTER_ID: + result = emberAfOtaSoftwareUpdateServerClusterClientCommandParse(cmd); + break; case ZCL_ON_OFF_CLUSTER_ID: // No commands are enabled for cluster On/off result = status(false, true, cmd->mfgSpecific); @@ -1484,6 +1488,105 @@ EmberAfStatus emberAfNetworkCommissioningClusterClientCommandParse(EmberAfCluste } return status(wasHandled, true, cmd->mfgSpecific); } +EmberAfStatus emberAfOtaSoftwareUpdateServerClusterClientCommandParse(EmberAfClusterCommand * cmd) +{ + bool wasHandled = false; + + if (!cmd->mfgSpecific) + { + switch (cmd->commandId) + { + case ZCL_APPLY_UPDATE_REQUEST_RESPONSE_COMMAND_ID: { + uint16_t payloadOffset = cmd->payloadStartIndex; + uint8_t action; + uint32_t delayedActionTime; + + if (cmd->bufLen < payloadOffset + 1) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + action = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); + payloadOffset = static_cast(payloadOffset + 1); + if (cmd->bufLen < payloadOffset + 4) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + delayedActionTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); + + wasHandled = + emberAfOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallback(nullptr, action, delayedActionTime); + break; + } + case ZCL_QUERY_IMAGE_RESPONSE_COMMAND_ID: { + uint16_t payloadOffset = cmd->payloadStartIndex; + uint8_t status; + uint32_t delayedActionTime; + uint8_t * imageURI; + uint32_t softwareVersion; + chip::ByteSpan updateToken; + uint8_t userConsentNeeded; + chip::ByteSpan metadataForClient; + + if (cmd->bufLen < payloadOffset + 1) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + status = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); + payloadOffset = static_cast(payloadOffset + 1); + if (cmd->bufLen < payloadOffset + 4) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + delayedActionTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); + payloadOffset = static_cast(payloadOffset + 4); + if (cmd->bufLen < payloadOffset + 1u) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + imageURI = emberAfGetString(cmd->buffer, payloadOffset, cmd->bufLen); + payloadOffset = static_cast(payloadOffset + emberAfStringLength(imageURI) + 1u); + if (cmd->bufLen < payloadOffset + 4) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + softwareVersion = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); + payloadOffset = static_cast(payloadOffset + 4); + if (cmd->bufLen < payloadOffset + 1u) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + { + uint8_t * rawData = emberAfGetString(cmd->buffer, payloadOffset, cmd->bufLen); + updateToken = chip::ByteSpan(rawData + 1u, emberAfStringLength(rawData)); + } + payloadOffset = static_cast(payloadOffset + updateToken.size() + 1u); + if (cmd->bufLen < payloadOffset + 1) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + userConsentNeeded = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); + payloadOffset = static_cast(payloadOffset + 1); + if (cmd->bufLen < payloadOffset + 1u) + { + return EMBER_ZCL_STATUS_MALFORMED_COMMAND; + } + { + uint8_t * rawData = emberAfGetString(cmd->buffer, payloadOffset, cmd->bufLen); + metadataForClient = chip::ByteSpan(rawData + 1u, emberAfStringLength(rawData)); + } + + wasHandled = emberAfOtaSoftwareUpdateServerClusterQueryImageResponseCallback( + nullptr, status, delayedActionTime, imageURI, softwareVersion, updateToken, userConsentNeeded, metadataForClient); + break; + } + default: { + // Unrecognized command ID, error status will apply. + break; + } + } + } + return status(wasHandled, true, cmd->mfgSpecific); +} EmberAfStatus emberAfOperationalCredentialsClusterClientCommandParse(EmberAfClusterCommand * cmd) { bool wasHandled = false; diff --git a/src/controller/data_model/gen/callback-stub.cpp b/src/controller/data_model/gen/callback-stub.cpp index 3313e9dd75aa61..71526c6b036b96 100644 --- a/src/controller/data_model/gen/callback-stub.cpp +++ b/src/controller/data_model/gen/callback-stub.cpp @@ -107,6 +107,9 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_NETWORK_COMMISSIONING_CLUSTER_ID: emberAfNetworkCommissioningClusterInitCallback(endpoint); break; + case ZCL_OTA_SERVER_CLUSTER_ID: + emberAfOtaSoftwareUpdateServerClusterInitCallback(endpoint); + break; case ZCL_ON_OFF_CLUSTER_ID: emberAfOnOffClusterInitCallback(endpoint); break; @@ -288,6 +291,11 @@ void __attribute__((weak)) emberAfNetworkCommissioningClusterInitCallback(Endpoi // To prevent warning (void) endpoint; } +void __attribute__((weak)) emberAfOtaSoftwareUpdateServerClusterInitCallback(EndpointId endpoint) +{ + // To prevent warning + (void) endpoint; +} void __attribute__((weak)) emberAfOnOffClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/src/controller/data_model/gen/callback.h b/src/controller/data_model/gen/callback.h index f346545604d57d..a87679f0f73c2f 100644 --- a/src/controller/data_model/gen/callback.h +++ b/src/controller/data_model/gen/callback.h @@ -248,6 +248,14 @@ void emberAfMediaPlaybackClusterInitCallback(chip::EndpointId endpoint); */ void emberAfNetworkCommissioningClusterInitCallback(chip::EndpointId endpoint); +/** @brief OTA Software Update Server Cluster Init + * + * Cluster Init + * + * @param endpoint Endpoint that is being initialized + */ +void emberAfOtaSoftwareUpdateServerClusterInitCallback(chip::EndpointId endpoint); + /** @brief On/off Cluster Init * * Cluster Init @@ -2186,6 +2194,77 @@ EmberAfStatus emberAfNetworkCommissioningClusterClientPreAttributeChangedCallbac */ void emberAfNetworkCommissioningClusterClientTickCallback(chip::EndpointId endpoint); +// +// OTA Software Update Server Cluster client +// + +/** @brief OTA Software Update Server Cluster Client Init + * + * Client Init + * + * @param endpoint Endpoint that is being initialized + */ +void emberAfOtaSoftwareUpdateServerClusterClientInitCallback(chip::EndpointId endpoint); + +/** @brief OTA Software Update Server Cluster Client Attribute Changed + * + * Client Attribute Changed + * + * @param endpoint Endpoint that is being initialized + * @param attributeId Attribute that changed + */ +void emberAfOtaSoftwareUpdateServerClusterClientAttributeChangedCallback(chip::EndpointId endpoint, chip::AttributeId attributeId); + +/** @brief OTA Software Update Server Cluster Client Manufacturer Specific Attribute Changed + * + * Client Manufacturer Specific Attribute Changed + * + * @param endpoint Endpoint that is being initialized + * @param attributeId Attribute that changed + * @param manufacturerCode Manufacturer Code of the attribute that changed + */ +void emberAfOtaSoftwareUpdateServerClusterClientManufacturerSpecificAttributeChangedCallback(chip::EndpointId endpoint, + chip::AttributeId attributeId, + uint16_t manufacturerCode); + +/** @brief OTA Software Update Server Cluster Client Message Sent + * + * Client Message Sent + * + * @param type The type of message sent + * @param destination The destination to which the message was sent + * @param apsFrame The APS frame for the message + * @param msgLen The length of the message + * @param message The message that was sent + * @param status The status of the sent message + */ +void emberAfOtaSoftwareUpdateServerClusterClientMessageSentCallback(const chip::MessageSendDestination & destination, + EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, + EmberStatus status); + +/** @brief OTA Software Update Server Cluster Client Pre Attribute Changed + * + * client Pre Attribute Changed + * + * @param endpoint Endpoint that is being initialized + * @param attributeId Attribute to be changed + * @param attributeType Attribute type + * @param size Attribute size + * @param value Attribute value + */ +EmberAfStatus emberAfOtaSoftwareUpdateServerClusterClientPreAttributeChangedCallback(chip::EndpointId endpoint, + chip::AttributeId attributeId, + EmberAfAttributeType attributeType, + uint16_t size, uint8_t * value); + +/** @brief OTA Software Update Server Cluster Client Tick + * + * client Tick + * + * @param endpoint Endpoint that is being served + */ +void emberAfOtaSoftwareUpdateServerClusterClientTickCallback(chip::EndpointId endpoint); + // // On/off Cluster client // @@ -3596,6 +3675,22 @@ bool emberAfNetworkCommissioningClusterUpdateThreadNetworkResponseCallback(chip: bool emberAfNetworkCommissioningClusterUpdateWiFiNetworkResponseCallback(chip::app::Command * commandObj, uint8_t errorCode, uint8_t * debugText); +/** + * @brief OTA Software Update Server Cluster ApplyUpdateRequestResponse Command callback + */ + +bool emberAfOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallback(chip::app::Command * commandObj, uint8_t action, + uint32_t delayedActionTime); + +/** + * @brief OTA Software Update Server Cluster QueryImageResponse Command callback + */ + +bool emberAfOtaSoftwareUpdateServerClusterQueryImageResponseCallback(chip::app::Command * commandObj, uint8_t status, + uint32_t delayedActionTime, uint8_t * imageURI, + uint32_t softwareVersion, chip::ByteSpan updateToken, + uint8_t userConsentNeeded, chip::ByteSpan metadataForClient); + /** * @brief Operational Credentials Cluster OpCSRResponse Command callback */ diff --git a/src/controller/data_model/gen/chip-zcl-zpro-codec-api.h b/src/controller/data_model/gen/chip-zcl-zpro-codec-api.h index fd9e0610fd635b..0f7f6e5bd8b655 100644 --- a/src/controller/data_model/gen/chip-zcl-zpro-codec-api.h +++ b/src/controller/data_model/gen/chip-zcl-zpro-codec-api.h @@ -54,6 +54,7 @@ | MediaInput | 0x0507 | | MediaPlayback | 0x0506 | | NetworkCommissioning | 0x0031 | +| OtaSoftwareUpdateServer | 0x0029 | | OnOff | 0x0006 | | OperationalCredentials | 0x003E | | PumpConfigurationAndControl | 0x0200 | @@ -1954,6 +1955,32 @@ chip::System::PacketBufferHandle encodeNetworkCommissioningClusterDiscoverAttrib chip::System::PacketBufferHandle encodeNetworkCommissioningClusterReadClusterRevisionAttribute(uint8_t seqNum, chip::EndpointId destinationEndpoint); +/*----------------------------------------------------------------------------*\ +| Cluster OtaSoftwareUpdateServer | 0x0029 | +|------------------------------------------------------------------------------| +| Commands: | | +| * ApplyUpdateRequest | 0x01 | +| * NotifyUpdateApplied | 0x02 | +| * QueryImage | 0x00 | +|------------------------------------------------------------------------------| +| Attributes: | | +| * ClusterRevision | 0xFFFD | +\*----------------------------------------------------------------------------*/ + +/** + * @brief + * Encode a OTA Software Update Server server discover command into buffer including the APS frame + */ +chip::System::PacketBufferHandle encodeOtaSoftwareUpdateServerClusterDiscoverAttributes(uint8_t seqNum, + chip::EndpointId destinationEndpoint); + +/** + * @brief + * Encode a OTA Software Update Server server read command for the cluster revision attribute into buffer including the APS frame + */ +chip::System::PacketBufferHandle +encodeOtaSoftwareUpdateServerClusterReadClusterRevisionAttribute(uint8_t seqNum, chip::EndpointId destinationEndpoint); + /*----------------------------------------------------------------------------*\ | Cluster OnOff | 0x0006 | |------------------------------------------------------------------------------| diff --git a/src/controller/data_model/gen/encoder.cpp b/src/controller/data_model/gen/encoder.cpp index 57673215a45a04..2d6d522c4b5184 100644 --- a/src/controller/data_model/gen/encoder.cpp +++ b/src/controller/data_model/gen/encoder.cpp @@ -80,6 +80,7 @@ using namespace chip::Encoding::LittleEndian; | MediaInput | 0x0507 | | MediaPlayback | 0x0506 | | NetworkCommissioning | 0x0031 | +| OtaSoftwareUpdateServer | 0x0029 | | OnOff | 0x0006 | | OperationalCredentials | 0x003E | | PumpConfigurationAndControl | 0x0200 | @@ -270,6 +271,11 @@ using namespace chip::Encoding::LittleEndian; #define ZCL_UPDATE_THREAD_NETWORK_COMMAND_ID (0x08) #define ZCL_UPDATE_WI_FI_NETWORK_COMMAND_ID (0x04) +#define OTA_SERVER_CLUSTER_ID 0x0029 +#define ZCL_APPLY_UPDATE_REQUEST_COMMAND_ID (0x01) +#define ZCL_NOTIFY_UPDATE_APPLIED_COMMAND_ID (0x02) +#define ZCL_QUERY_IMAGE_COMMAND_ID (0x00) + #define ON_OFF_CLUSTER_ID 0x0006 #define ZCL_OFF_COMMAND_ID (0x00) #define ZCL_ON_COMMAND_ID (0x01) @@ -2910,6 +2916,35 @@ PacketBufferHandle encodeNetworkCommissioningClusterReadClusterRevisionAttribute COMMAND_FOOTER(); } +/*----------------------------------------------------------------------------*\ +| Cluster OtaSoftwareUpdateServer | 0x0029 | +|------------------------------------------------------------------------------| +| Commands: | | +| * ApplyUpdateRequest | 0x01 | +| * NotifyUpdateApplied | 0x02 | +| * QueryImage | 0x00 | +|------------------------------------------------------------------------------| +| Attributes: | | +| * ClusterRevision | 0xFFFD | +\*----------------------------------------------------------------------------*/ + +PacketBufferHandle encodeOtaSoftwareUpdateServerClusterDiscoverAttributes(uint8_t seqNum, EndpointId destinationEndpoint) +{ + COMMAND_HEADER("DiscoverOtaSoftwareUpdateServerAttributes", OTA_SERVER_CLUSTER_ID); + buf.Put8(kFrameControlGlobalCommand).Put8(seqNum).Put8(ZCL_DISCOVER_ATTRIBUTES_COMMAND_ID).Put16(0x0000).Put8(0xFF); + COMMAND_FOOTER(); +} + +/* + * Attribute ClusterRevision + */ +PacketBufferHandle encodeOtaSoftwareUpdateServerClusterReadClusterRevisionAttribute(uint8_t seqNum, EndpointId destinationEndpoint) +{ + COMMAND_HEADER("ReadOtaSoftwareUpdateServerClusterRevision", OTA_SERVER_CLUSTER_ID); + buf.Put8(kFrameControlGlobalCommand).Put8(seqNum).Put8(ZCL_READ_ATTRIBUTES_COMMAND_ID).Put16(0xFFFD); + COMMAND_FOOTER(); +} + /*----------------------------------------------------------------------------*\ | Cluster OnOff | 0x0006 | |------------------------------------------------------------------------------| diff --git a/src/controller/data_model/gen/endpoint_config.h b/src/controller/data_model/gen/endpoint_config.h index b8cdc594acdad4..e3c55949952fb5 100644 --- a/src/controller/data_model/gen/endpoint_config.h +++ b/src/controller/data_model/gen/endpoint_config.h @@ -63,7 +63,7 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 41 +#define GENERATED_ATTRIBUTE_COUNT 42 #define GENERATED_ATTRIBUTES \ { \ \ @@ -92,6 +92,9 @@ { 0xFFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(CLIENT) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ ZAP_SIMPLE_DEFAULT(3) }, /* cluster revision */ \ \ + /* Endpoint: 1, Cluster: OTA Software Update Server (client) */ \ + { 0xFFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(CLIENT), ZAP_SIMPLE_DEFAULT(0x0001) }, /* cluster revision */ \ + \ /* Endpoint: 1, Cluster: General Commissioning (client) */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(CLIENT), ZAP_SIMPLE_DEFAULT(0x0001) }, /* cluster revision */ \ \ @@ -200,7 +203,7 @@ #define GENERATED_FUNCTION_ARRAYS #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 41 +#define GENERATED_CLUSTER_COUNT 42 #define GENERATED_CLUSTERS \ { \ { 0x0003, ZAP_ATTRIBUTE_INDEX(0), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: Identify (client) */ \ @@ -218,101 +221,104 @@ }, /* Endpoint: 1, Cluster: Descriptor (client) */ \ { 0x0028, ZAP_ATTRIBUTE_INDEX(7), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: Basic (client) */ \ { \ - 0x0030, ZAP_ATTRIBUTE_INDEX(8), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0029, ZAP_ATTRIBUTE_INDEX(8), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + }, /* Endpoint: 1, Cluster: OTA Software Update Server (client) */ \ + { \ + 0x0030, ZAP_ATTRIBUTE_INDEX(9), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: General Commissioning (client) */ \ { \ - 0x0031, ZAP_ATTRIBUTE_INDEX(9), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0031, ZAP_ATTRIBUTE_INDEX(10), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Network Commissioning (client) */ \ { \ - 0x0033, ZAP_ATTRIBUTE_INDEX(10), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0033, ZAP_ATTRIBUTE_INDEX(11), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: General Diagnostics (client) */ \ { \ - 0x0034, ZAP_ATTRIBUTE_INDEX(11), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0034, ZAP_ATTRIBUTE_INDEX(12), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Software Diagnostics (client) */ \ { \ - 0x0037, ZAP_ATTRIBUTE_INDEX(12), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0037, ZAP_ATTRIBUTE_INDEX(13), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Ethernet Network Diagnostics (client) */ \ { \ - 0x0039, ZAP_ATTRIBUTE_INDEX(13), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0039, ZAP_ATTRIBUTE_INDEX(14), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Bridged Device Basic (client) */ \ - { 0x003B, ZAP_ATTRIBUTE_INDEX(14), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: Switch (client) */ \ + { 0x003B, ZAP_ATTRIBUTE_INDEX(15), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: Switch (client) */ \ { \ - 0x003E, ZAP_ATTRIBUTE_INDEX(15), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x003E, ZAP_ATTRIBUTE_INDEX(16), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Operational Credentials (client) */ \ { \ - 0x003F, ZAP_ATTRIBUTE_INDEX(16), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x003F, ZAP_ATTRIBUTE_INDEX(17), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Trusted Root Certificates (client) */ \ { \ - 0x0040, ZAP_ATTRIBUTE_INDEX(17), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0040, ZAP_ATTRIBUTE_INDEX(18), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Fixed Label (client) */ \ { \ - 0x0101, ZAP_ATTRIBUTE_INDEX(18), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0101, ZAP_ATTRIBUTE_INDEX(19), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Door Lock (client) */ \ { \ - 0x0102, ZAP_ATTRIBUTE_INDEX(19), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0102, ZAP_ATTRIBUTE_INDEX(20), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Window Covering (client) */ \ { \ - 0x0103, ZAP_ATTRIBUTE_INDEX(20), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0103, ZAP_ATTRIBUTE_INDEX(21), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Barrier Control (client) */ \ { \ - 0x0200, ZAP_ATTRIBUTE_INDEX(21), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0200, ZAP_ATTRIBUTE_INDEX(22), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Pump Configuration and Control (client) */ \ { \ - 0x0201, ZAP_ATTRIBUTE_INDEX(22), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0201, ZAP_ATTRIBUTE_INDEX(23), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Thermostat (client) */ \ { \ - 0x0300, ZAP_ATTRIBUTE_INDEX(23), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0300, ZAP_ATTRIBUTE_INDEX(24), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Color Control (client) */ \ { \ - 0x0402, ZAP_ATTRIBUTE_INDEX(24), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0402, ZAP_ATTRIBUTE_INDEX(25), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Temperature Measurement (client) */ \ { \ - 0x0405, ZAP_ATTRIBUTE_INDEX(25), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0405, ZAP_ATTRIBUTE_INDEX(26), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Relative Humidity Measurement (client) */ \ { \ - 0x0503, ZAP_ATTRIBUTE_INDEX(26), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0503, ZAP_ATTRIBUTE_INDEX(27), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Wake on LAN (client) */ \ { \ - 0x0504, ZAP_ATTRIBUTE_INDEX(27), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0504, ZAP_ATTRIBUTE_INDEX(28), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: TV Channel (client) */ \ { \ - 0x0505, ZAP_ATTRIBUTE_INDEX(28), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0505, ZAP_ATTRIBUTE_INDEX(29), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Target Navigator (client) */ \ { \ - 0x0506, ZAP_ATTRIBUTE_INDEX(29), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0506, ZAP_ATTRIBUTE_INDEX(30), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Media Playback (client) */ \ { \ - 0x0507, ZAP_ATTRIBUTE_INDEX(30), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0507, ZAP_ATTRIBUTE_INDEX(31), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Media Input (client) */ \ { \ - 0x0508, ZAP_ATTRIBUTE_INDEX(31), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0508, ZAP_ATTRIBUTE_INDEX(32), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Low Power (client) */ \ { \ - 0x0509, ZAP_ATTRIBUTE_INDEX(32), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x0509, ZAP_ATTRIBUTE_INDEX(33), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Keypad Input (client) */ \ { \ - 0x050A, ZAP_ATTRIBUTE_INDEX(33), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x050A, ZAP_ATTRIBUTE_INDEX(34), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Content Launch (client) */ \ { \ - 0x050B, ZAP_ATTRIBUTE_INDEX(34), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x050B, ZAP_ATTRIBUTE_INDEX(35), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Audio Output (client) */ \ { \ - 0x050C, ZAP_ATTRIBUTE_INDEX(35), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x050C, ZAP_ATTRIBUTE_INDEX(36), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Application Launcher (client) */ \ { \ - 0x050D, ZAP_ATTRIBUTE_INDEX(36), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x050D, ZAP_ATTRIBUTE_INDEX(37), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Application Basic (client) */ \ { \ - 0x050E, ZAP_ATTRIBUTE_INDEX(37), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x050E, ZAP_ATTRIBUTE_INDEX(38), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Account Login (client) */ \ { \ - 0x050F, ZAP_ATTRIBUTE_INDEX(38), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0x050F, ZAP_ATTRIBUTE_INDEX(39), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Test Cluster (client) */ \ { \ - 0xF000, ZAP_ATTRIBUTE_INDEX(39), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0xF000, ZAP_ATTRIBUTE_INDEX(40), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Binding (client) */ \ { \ - 0xF004, ZAP_ATTRIBUTE_INDEX(40), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ + 0xF004, ZAP_ATTRIBUTE_INDEX(41), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: Group Key Management (client) */ \ } @@ -321,7 +327,7 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 41, 82 }, \ + { ZAP_CLUSTER_INDEX(0), 42, 84 }, \ } // Largest attribute size is needed for various buffers @@ -331,7 +337,7 @@ #define ATTRIBUTE_SINGLETONS_SIZE (4) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (82) +#define ATTRIBUTE_MAX_SIZE (84) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (1) @@ -375,7 +381,7 @@ // Array of EmberAfCommandMetadata structs. #define ZAP_COMMAND_MASK(mask) COMMAND_MASK_##mask -#define EMBER_AF_GENERATED_COMMAND_COUNT (212) +#define EMBER_AF_GENERATED_COMMAND_COUNT (217) #define GENERATED_COMMANDS \ { \ \ @@ -432,6 +438,13 @@ { 0x0028, 0x02, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* Leave */ \ { 0x0028, 0x00, ZAP_COMMAND_MASK(OUTGOING_CLIENT) }, /* MfgSpecificPing */ \ \ + /* Endpoint: 1, Cluster: OTA Software Update Server (client) */ \ + { 0x0029, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* QueryImage */ \ + { 0x0029, 0x01, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* ApplyUpdateRequest */ \ + { 0x0029, 0x02, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* NotifyUpdateApplied */ \ + { 0x0029, 0x03, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* QueryImageResponse */ \ + { 0x0029, 0x04, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* ApplyUpdateRequestResponse */ \ + \ /* Endpoint: 1, Cluster: General Commissioning (client) */ \ { 0x0030, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* ArmFailSafe */ \ { 0x0030, 0x01, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* ArmFailSafeResponse */ \ diff --git a/src/controller/data_model/gen/gen_config.h b/src/controller/data_model/gen/gen_config.h index 3609aa8bbb7d8d..1e9b4e8a0c7c57 100644 --- a/src/controller/data_model/gen/gen_config.h +++ b/src/controller/data_model/gen/gen_config.h @@ -55,6 +55,7 @@ #define EMBER_AF_MEDIA_INPUT_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_MEDIA_PLAYBACK_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_NETWORK_COMMISSIONING_CLUSTER_CLIENT_ENDPOINT_COUNT (1) +#define EMBER_AF_OTA_SERVER_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_ON_OFF_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_OPERATIONAL_CREDENTIALS_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_PUMP_CONFIG_CONTROL_CLUSTER_CLIENT_ENDPOINT_COUNT (1) @@ -177,6 +178,10 @@ #define ZCL_USING_NETWORK_COMMISSIONING_CLUSTER_CLIENT #define EMBER_AF_PLUGIN_NETWORK_COMMISSIONING_CLIENT +// Use this macro to check if the client side of the OTA Software Update Server cluster is included +#define ZCL_USING_OTA_SERVER_CLUSTER_CLIENT +#define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_SERVER_CLIENT + // Use this macro to check if the client side of the On/off cluster is included #define ZCL_USING_ON_OFF_CLUSTER_CLIENT #define EMBER_AF_PLUGIN_ON_OFF_CLIENT diff --git a/src/controller/python/chip/clusters/CHIPClusters.cpp b/src/controller/python/chip/clusters/CHIPClusters.cpp index c56ea9ac80e475..585f9cc9a959d8 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.cpp +++ b/src/controller/python/chip/clusters/CHIPClusters.cpp @@ -2618,6 +2618,52 @@ CHIP_ERROR chip_ime_ReadAttribute_NetworkCommissioning_ClusterRevision(chip::Con } // End of Cluster NetworkCommissioning +// Cluster OtaSoftwareUpdateServer + +CHIP_ERROR chip_ime_AppendCommand_OtaSoftwareUpdateServer_ApplyUpdateRequest(chip::Controller::Device * device, + chip::EndpointId ZCLendpointId, chip::GroupId, + const uint8_t * updateToken, uint32_t updateToken_Len, + uint32_t newVersion) +{ + VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, ZCLendpointId); + return cluster.ApplyUpdateRequest(nullptr, nullptr, chip::ByteSpan(updateToken, updateToken_Len), newVersion); +} +CHIP_ERROR chip_ime_AppendCommand_OtaSoftwareUpdateServer_NotifyUpdateApplied(chip::Controller::Device * device, + chip::EndpointId ZCLendpointId, chip::GroupId, + const uint8_t * updateToken, uint32_t updateToken_Len, + uint32_t currentVersion) +{ + VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, ZCLendpointId); + return cluster.NotifyUpdateApplied(nullptr, nullptr, chip::ByteSpan(updateToken, updateToken_Len), currentVersion); +} +CHIP_ERROR chip_ime_AppendCommand_OtaSoftwareUpdateServer_QueryImage( + chip::Controller::Device * device, chip::EndpointId ZCLendpointId, chip::GroupId, uint16_t vendorId, uint16_t productId, + uint16_t imageType, uint16_t hardwareVersion, uint32_t currentVersion, uint8_t protocolsSupported, const uint8_t * location, + uint32_t location_Len, uint8_t clientCanConsent, const uint8_t * metadataForServer, uint32_t metadataForServer_Len) +{ + VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, ZCLendpointId); + return cluster.QueryImage(nullptr, nullptr, vendorId, productId, imageType, hardwareVersion, currentVersion, protocolsSupported, + chip::ByteSpan(location, location_Len), clientCanConsent, + chip::ByteSpan(metadataForServer, metadataForServer_Len)); +} + +CHIP_ERROR chip_ime_ReadAttribute_OtaSoftwareUpdateServer_ClusterRevision(chip::Controller::Device * device, + chip::EndpointId ZCLendpointId, + chip::GroupId /* ZCLgroupId */) +{ + VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + chip::Controller::OtaSoftwareUpdateServerCluster cluster; + cluster.Associate(device, ZCLendpointId); + return cluster.ReadAttributeClusterRevision(gInt16uAttributeCallback.Cancel(), gDefaultFailureCallback.Cancel()); +} + +// End of Cluster OtaSoftwareUpdateServer // Cluster OnOff CHIP_ERROR chip_ime_AppendCommand_OnOff_Off(chip::Controller::Device * device, chip::EndpointId ZCLendpointId, chip::GroupId) diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 6681ef4bafd04a..3c799d604307aa 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -484,6 +484,27 @@ def ListClusterCommands(self): "timeoutMs": "int", }, }, + "OtaSoftwareUpdateServer": { + "ApplyUpdateRequest": { + "updateToken": "bytes", + "newVersion": "int", + }, + "NotifyUpdateApplied": { + "updateToken": "bytes", + "currentVersion": "int", + }, + "QueryImage": { + "vendorId": "int", + "productId": "int", + "imageType": "int", + "hardwareVersion": "int", + "currentVersion": "int", + "protocolsSupported": "int", + "location": "str", + "clientCanConsent": "int", + "metadataForServer": "bytes", + }, + }, "OnOff": { "Off": { }, @@ -845,6 +866,9 @@ def ListClusterAttributes(self): "NetworkCommissioning": [ "ClusterRevision", ], + "OtaSoftwareUpdateServer": [ + "ClusterRevision", + ], "OnOff": [ "OnOff", "ClusterRevision", @@ -1376,6 +1400,19 @@ def ClusterNetworkCommissioning_CommandUpdateWiFiNetwork(self, device: ctypes.c_ return self._chipLib.chip_ime_AppendCommand_NetworkCommissioning_UpdateWiFiNetwork( device, ZCLendpoint, ZCLgroupid, ssid, len(ssid), credentials, len(credentials), breadcrumb, timeoutMs ) + def ClusterOtaSoftwareUpdateServer_CommandApplyUpdateRequest(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int, updateToken: bytes, newVersion: int): + return self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_ApplyUpdateRequest( + device, ZCLendpoint, ZCLgroupid, updateToken, len(updateToken), newVersion + ) + def ClusterOtaSoftwareUpdateServer_CommandNotifyUpdateApplied(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int, updateToken: bytes, currentVersion: int): + return self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_NotifyUpdateApplied( + device, ZCLendpoint, ZCLgroupid, updateToken, len(updateToken), currentVersion + ) + def ClusterOtaSoftwareUpdateServer_CommandQueryImage(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int, vendorId: int, productId: int, imageType: int, hardwareVersion: int, currentVersion: int, protocolsSupported: int, location: bytes, clientCanConsent: int, metadataForServer: bytes): + location = location.encode("utf-8") + b'\x00' + return self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_QueryImage( + device, ZCLendpoint, ZCLgroupid, vendorId, productId, imageType, hardwareVersion, currentVersion, protocolsSupported, location, len(location), clientCanConsent, metadataForServer, len(metadataForServer) + ) def ClusterOnOff_CommandOff(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int): return self._chipLib.chip_ime_AppendCommand_OnOff_Off( device, ZCLendpoint, ZCLgroupid @@ -1853,6 +1890,8 @@ def ClusterMediaPlayback_ReadAttributeClusterRevision(self, device: ctypes.c_voi return self._chipLib.chip_ime_ReadAttribute_MediaPlayback_ClusterRevision(device, ZCLendpoint, ZCLgroupid) def ClusterNetworkCommissioning_ReadAttributeClusterRevision(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int): return self._chipLib.chip_ime_ReadAttribute_NetworkCommissioning_ClusterRevision(device, ZCLendpoint, ZCLgroupid) + def ClusterOtaSoftwareUpdateServer_ReadAttributeClusterRevision(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int): + return self._chipLib.chip_ime_ReadAttribute_OtaSoftwareUpdateServer_ClusterRevision(device, ZCLendpoint, ZCLgroupid) def ClusterOnOff_ReadAttributeOnOff(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int): return self._chipLib.chip_ime_ReadAttribute_OnOff_OnOff(device, ZCLendpoint, ZCLgroupid) def ClusterOnOff_ConfigureAttributeOnOff(self, device: ctypes.c_void_p, ZCLendpoint: int, minInterval: int, maxInterval: int, change: int): @@ -2817,6 +2856,19 @@ def InitLib(self, chipLib): # Cluster NetworkCommissioning ReadAttribute ClusterRevision self._chipLib.chip_ime_ReadAttribute_NetworkCommissioning_ClusterRevision.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16] self._chipLib.chip_ime_ReadAttribute_NetworkCommissioning_ClusterRevision.restype = ctypes.c_uint32 + # Cluster OtaSoftwareUpdateServer + # Cluster OtaSoftwareUpdateServer Command ApplyUpdateRequest + self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_ApplyUpdateRequest.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_uint32] + self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_ApplyUpdateRequest.restype = ctypes.c_uint32 + # Cluster OtaSoftwareUpdateServer Command NotifyUpdateApplied + self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_NotifyUpdateApplied.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_uint32] + self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_NotifyUpdateApplied.restype = ctypes.c_uint32 + # Cluster OtaSoftwareUpdateServer Command QueryImage + self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_QueryImage.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16, ctypes.c_uint16, ctypes.c_uint16, ctypes.c_uint16, ctypes.c_uint16, ctypes.c_uint32, ctypes.c_uint8, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_uint8, ctypes.c_char_p, ctypes.c_uint32] + self._chipLib.chip_ime_AppendCommand_OtaSoftwareUpdateServer_QueryImage.restype = ctypes.c_uint32 + # Cluster OtaSoftwareUpdateServer ReadAttribute ClusterRevision + self._chipLib.chip_ime_ReadAttribute_OtaSoftwareUpdateServer_ClusterRevision.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16] + self._chipLib.chip_ime_ReadAttribute_OtaSoftwareUpdateServer_ClusterRevision.restype = ctypes.c_uint32 # Cluster OnOff # Cluster OnOff Command Off self._chipLib.chip_ime_AppendCommand_OnOff_Off.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16] diff --git a/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.h b/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.h index ea5b258d783344..c2f60c19329493 100644 --- a/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.h +++ b/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.h @@ -749,6 +749,31 @@ NS_ASSUME_NONNULL_BEGIN @end +/** + * Cluster OTA Software Update Server + * + */ +@interface CHIPOtaSoftwareUpdateServer : CHIPCluster + +- (void)applyUpdateRequest:(NSData *)updateToken newVersion:(uint32_t)newVersion responseHandler:(ResponseHandler)responseHandler; +- (void)notifyUpdateApplied:(NSData *)updateToken + currentVersion:(uint32_t)currentVersion + responseHandler:(ResponseHandler)responseHandler; +- (void)queryImage:(uint16_t)vendorId + productId:(uint16_t)productId + imageType:(uint16_t)imageType + hardwareVersion:(uint16_t)hardwareVersion + currentVersion:(uint32_t)currentVersion + protocolsSupported:(uint8_t)protocolsSupported + location:(NSString *)location + clientCanConsent:(uint8_t)clientCanConsent + metadataForServer:(NSData *)metadataForServer + responseHandler:(ResponseHandler)responseHandler; + +- (void)readAttributeClusterRevisionWithResponseHandler:(ResponseHandler)responseHandler; + +@end + /** * Cluster On/off * diff --git a/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.mm b/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.mm index f67f097105af8f..579c02ab332829 100644 --- a/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.mm +++ b/src/darwin/Framework/CHIP/gen/CHIPClustersObjc.mm @@ -2183,6 +2183,77 @@ static void CallbackFn(void * context, uint8_t errorCode, uint8_t * debugText) dispatch_queue_t mQueue; }; +class CHIPOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallbackBridge + : public Callback::Callback { +public: + CHIPOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallbackBridge(ResponseHandler handler, dispatch_queue_t queue) + : Callback::Callback(CallbackFn, this) + , mHandler(handler) + , mQueue(queue) + { + } + + ~CHIPOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallbackBridge() {}; + + static void CallbackFn(void * context, uint8_t action, uint32_t delayedActionTime) + { + CHIPOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallbackBridge * callback + = reinterpret_cast(context); + if (callback && callback->mQueue) { + dispatch_async(callback->mQueue, ^{ + callback->mHandler(nil, @ { + @"action" : [NSNumber numberWithUnsignedChar:action], + @"delayedActionTime" : [NSNumber numberWithUnsignedLong:delayedActionTime], + }); + callback->Cancel(); + delete callback; + }); + } + }; + +private: + ResponseHandler mHandler; + dispatch_queue_t mQueue; +}; + +class CHIPOtaSoftwareUpdateServerClusterQueryImageResponseCallbackBridge + : public Callback::Callback { +public: + CHIPOtaSoftwareUpdateServerClusterQueryImageResponseCallbackBridge(ResponseHandler handler, dispatch_queue_t queue) + : Callback::Callback(CallbackFn, this) + , mHandler(handler) + , mQueue(queue) + { + } + + ~CHIPOtaSoftwareUpdateServerClusterQueryImageResponseCallbackBridge() {}; + + static void CallbackFn(void * context, uint32_t delayedActionTime, uint8_t * imageURI, uint32_t softwareVersion, + chip::ByteSpan updateToken, uint8_t userConsentNeeded, chip::ByteSpan metadataForClient) + { + CHIPOtaSoftwareUpdateServerClusterQueryImageResponseCallbackBridge * callback + = reinterpret_cast(context); + if (callback && callback->mQueue) { + dispatch_async(callback->mQueue, ^{ + callback->mHandler(nil, @ { + @"delayedActionTime" : [NSNumber numberWithUnsignedLong:delayedActionTime], + @"imageURI" : [NSString stringWithFormat:@"%s", imageURI], + @"softwareVersion" : [NSNumber numberWithUnsignedLong:softwareVersion], + @"updateToken" : [NSData dataWithBytes:updateToken.data() length:updateToken.size()], + @"userConsentNeeded" : [NSNumber numberWithUnsignedChar:userConsentNeeded], + @"metadataForClient" : [NSData dataWithBytes:metadataForClient.data() length:metadataForClient.size()], + }); + callback->Cancel(); + delete callback; + }); + } + }; + +private: + ResponseHandler mHandler; + dispatch_queue_t mQueue; +}; + class CHIPOperationalCredentialsClusterOpCSRResponseCallbackBridge : public Callback::Callback { public: @@ -11489,6 +11560,144 @@ - (void)readAttributeClusterRevisionWithResponseHandler:(ResponseHandler)respons @end +@interface CHIPOtaSoftwareUpdateServer () +@property (readonly) Controller::OtaSoftwareUpdateServerCluster cppCluster; +@end + +@implementation CHIPOtaSoftwareUpdateServer + +- (Controller::ClusterBase *)getCluster +{ + return &_cppCluster; +} + +- (void)applyUpdateRequest:(NSData *)updateToken newVersion:(uint32_t)newVersion responseHandler:(ResponseHandler)responseHandler +{ + CHIPOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallbackBridge * onSuccess + = new CHIPOtaSoftwareUpdateServerClusterApplyUpdateRequestResponseCallbackBridge(responseHandler, [self callbackQueue]); + if (!onSuccess) { + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + CHIPDefaultFailureCallbackBridge * onFailure = new CHIPDefaultFailureCallbackBridge(responseHandler, [self callbackQueue]); + if (!onFailure) { + delete onSuccess; + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + __block CHIP_ERROR err; + dispatch_sync([self chipWorkQueue], ^{ + err = self.cppCluster.ApplyUpdateRequest(onSuccess->Cancel(), onFailure->Cancel(), + chip::ByteSpan((const uint8_t *) updateToken.bytes, updateToken.length), newVersion); + }); + + if (err != CHIP_NO_ERROR) { + delete onSuccess; + delete onFailure; + responseHandler([CHIPError errorForCHIPErrorCode:err], nil); + } +} +- (void)notifyUpdateApplied:(NSData *)updateToken + currentVersion:(uint32_t)currentVersion + responseHandler:(ResponseHandler)responseHandler +{ + CHIPDefaultSuccessCallbackBridge * onSuccess = new CHIPDefaultSuccessCallbackBridge(responseHandler, [self callbackQueue]); + if (!onSuccess) { + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + CHIPDefaultFailureCallbackBridge * onFailure = new CHIPDefaultFailureCallbackBridge(responseHandler, [self callbackQueue]); + if (!onFailure) { + delete onSuccess; + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + __block CHIP_ERROR err; + dispatch_sync([self chipWorkQueue], ^{ + err = self.cppCluster.NotifyUpdateApplied(onSuccess->Cancel(), onFailure->Cancel(), + chip::ByteSpan((const uint8_t *) updateToken.bytes, updateToken.length), currentVersion); + }); + + if (err != CHIP_NO_ERROR) { + delete onSuccess; + delete onFailure; + responseHandler([CHIPError errorForCHIPErrorCode:err], nil); + } +} +- (void)queryImage:(uint16_t)vendorId + productId:(uint16_t)productId + imageType:(uint16_t)imageType + hardwareVersion:(uint16_t)hardwareVersion + currentVersion:(uint32_t)currentVersion + protocolsSupported:(uint8_t)protocolsSupported + location:(NSString *)location + clientCanConsent:(uint8_t)clientCanConsent + metadataForServer:(NSData *)metadataForServer + responseHandler:(ResponseHandler)responseHandler +{ + CHIPOtaSoftwareUpdateServerClusterQueryImageResponseCallbackBridge * onSuccess + = new CHIPOtaSoftwareUpdateServerClusterQueryImageResponseCallbackBridge(responseHandler, [self callbackQueue]); + if (!onSuccess) { + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + CHIPDefaultFailureCallbackBridge * onFailure = new CHIPDefaultFailureCallbackBridge(responseHandler, [self callbackQueue]); + if (!onFailure) { + delete onSuccess; + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + __block CHIP_ERROR err; + dispatch_sync([self chipWorkQueue], ^{ + err = self.cppCluster.QueryImage(onSuccess->Cancel(), onFailure->Cancel(), vendorId, productId, imageType, hardwareVersion, + currentVersion, protocolsSupported, + chip::ByteSpan((const uint8_t *) [location dataUsingEncoding:NSUTF8StringEncoding].bytes, + [location lengthOfBytesUsingEncoding:NSUTF8StringEncoding]), + clientCanConsent, chip::ByteSpan((const uint8_t *) metadataForServer.bytes, metadataForServer.length)); + }); + + if (err != CHIP_NO_ERROR) { + delete onSuccess; + delete onFailure; + responseHandler([CHIPError errorForCHIPErrorCode:err], nil); + } +} + +- (void)readAttributeClusterRevisionWithResponseHandler:(ResponseHandler)responseHandler +{ + CHIPInt16uAttributeCallbackBridge * onSuccess = new CHIPInt16uAttributeCallbackBridge(responseHandler, [self callbackQueue]); + if (!onSuccess) { + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + CHIPDefaultFailureCallbackBridge * onFailure = new CHIPDefaultFailureCallbackBridge(responseHandler, [self callbackQueue]); + if (!onFailure) { + delete onSuccess; + responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); + return; + } + + __block CHIP_ERROR err; + dispatch_sync([self chipWorkQueue], ^{ + err = self.cppCluster.ReadAttributeClusterRevision(onSuccess->Cancel(), onFailure->Cancel()); + }); + + if (err != CHIP_NO_ERROR) { + delete onSuccess; + delete onFailure; + responseHandler([CHIPError errorForCHIPErrorCode:err], nil); + } +} + +@end + @interface CHIPOnOff () @property (readonly) Controller::OnOffCluster cppCluster; @end diff --git a/src/darwin/Framework/CHIP/templates/helper.js b/src/darwin/Framework/CHIP/templates/helper.js index b8d112ec160e5c..a93f218859b9ac 100644 --- a/src/darwin/Framework/CHIP/templates/helper.js +++ b/src/darwin/Framework/CHIP/templates/helper.js @@ -38,6 +38,7 @@ function asExpectedEndpointForCluster(clusterName) case 'NetworkCommissioning': case 'OperationalCredentials': case 'TrustedRootCertificates': + case 'OtaSoftwareUpdateServer': return 0; } diff --git a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m index 0f5323c22082d1..2f2648dac5ce06 100644 --- a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m @@ -3489,6 +3489,25 @@ - (void)testSendClusterNetworkCommissioningReadAttributeClusterRevisionWithRespo [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; } +- (void)testSendClusterOtaSoftwareUpdateServerReadAttributeClusterRevisionWithResponseHandler +{ + XCTestExpectation * expectation = + [self expectationWithDescription:@"OtaSoftwareUpdateServerReadAttributeClusterRevisionWithResponseHandler"]; + + CHIPDevice * device = GetPairedDevice(kDeviceId); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPOtaSoftwareUpdateServer * cluster = [[CHIPOtaSoftwareUpdateServer alloc] initWithDevice:device endpoint:0 queue:queue]; + XCTAssertNotNil(cluster); + + [cluster readAttributeClusterRevisionWithResponseHandler:^(NSError * err, NSDictionary * values) { + NSLog(@"OtaSoftwareUpdateServer ClusterRevision Error: %@", err); + XCTAssertEqual(err.code, 0); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} + - (void)testSendClusterOnOffReadAttributeOnOffWithResponseHandler { XCTestExpectation * expectation = [self expectationWithDescription:@"OnOffReadAttributeOnOffWithResponseHandler"];