-
Notifications
You must be signed in to change notification settings - Fork 2k
/
ota-provider.cpp
205 lines (172 loc) · 8.34 KB
/
ota-provider.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
*
* 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.
*/
#include <app-common/zap-generated/att-storage.h>
#include <app-common/zap-generated/attribute-id.h>
#include <app-common/zap-generated/attribute-type.h>
#include <app-common/zap-generated/callback.h>
#include <app-common/zap-generated/cluster-id.h>
#include <app-common/zap-generated/command-id.h>
#include <app-common/zap-generated/enums.h>
#include <app/CommandHandler.h>
#include <app/util/af.h>
#include <lib/support/Span.h>
#include "ota-provider-delegate.h"
#include "ota-provider.h"
using namespace chip;
using chip::app::clusters::OTAProviderDelegate;
namespace {
constexpr size_t kMaxMetadataLen = 512; // The maximum length of Metadata in any OTA Provider command
constexpr size_t kUpdateTokenParamLength = 32; // The expected length of the Update Token parameter used in multiple commands
OTAProviderDelegate * gDelegateTable[EMBER_AF_OTA_PROVIDER_CLUSTER_SERVER_ENDPOINT_COUNT] = { nullptr };
OTAProviderDelegate * GetDelegate(EndpointId endpoint)
{
uint16_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_OTA_PROVIDER_CLUSTER_ID);
return (ep == 0xFFFF ? NULL : gDelegateTable[ep]);
}
bool SendStatusIfDelegateNull(EndpointId endpoint)
{
if (GetDelegate(endpoint) == nullptr)
{
ChipLogError(Zcl, "No OTAProviderDelegate set for ep:%" PRIu16, endpoint);
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_UNSUP_COMMAND);
return true;
}
return false;
}
} // namespace
/**
* @brief OTA Software Update Provider 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.
*/
bool emberAfOtaSoftwareUpdateProviderClusterApplyUpdateRequestCallback(EndpointId endpoint, app::CommandHandler * commandObj,
ByteSpan updateToken, uint32_t newVersion)
{
EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
OTAProviderDelegate * delegate = GetDelegate(endpoint);
ChipLogDetail(Zcl, "OTA Provider received ApplyUpdateRequest");
if (SendStatusIfDelegateNull(endpoint))
{
return true;
}
if (updateToken.size() != kUpdateTokenParamLength)
{
ChipLogError(Zcl, "expected size %zu for UpdateToken, got %zu", kUpdateTokenParamLength, updateToken.size());
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_ARGUMENT);
}
status = delegate->HandleApplyUpdateRequest(commandObj, updateToken, newVersion);
if (status != EMBER_ZCL_STATUS_SUCCESS)
{
emberAfSendImmediateDefaultResponse(status);
}
return true;
}
/**
* @brief OTA Software Update Provider 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 Requestor's Basic Information Cluster.
*/
bool emberAfOtaSoftwareUpdateProviderClusterNotifyUpdateAppliedCallback(EndpointId endpoint, app::CommandHandler * commandObj,
ByteSpan updateToken, uint32_t currentVersion)
{
EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
OTAProviderDelegate * delegate = GetDelegate(endpoint);
ChipLogDetail(Zcl, "OTA Provider received NotifyUpdateUpplied");
if (SendStatusIfDelegateNull(endpoint))
{
return true;
}
if (updateToken.size() != kUpdateTokenParamLength)
{
ChipLogError(Zcl, "expected size %zu for UpdateToken, got %zu", kUpdateTokenParamLength, updateToken.size());
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_ARGUMENT);
}
status = delegate->HandleNotifyUpdateApplied(updateToken, currentVersion);
if (status != EMBER_ZCL_STATUS_SUCCESS)
{
emberAfSendImmediateDefaultResponse(status);
}
return true;
}
/**
* @brief OTA Software Update Provider Cluster QueryImage Command callback
*
* @param vendorId The Vendor ID applying to the OTA Requestor’s Node. Should match the value in the Basic Information Cluster.
* @param productId The Product ID applying to the OTA Requestor’s Node. Should match the value in the Basic Information Cluster.
* @param imageType A Vendor-specific numerical value that may help an OTA Provider select the correct payload.
* @param hardwareVersion The OTA Requestor’s hardware version. Should match the HardwareVersion attribute of the Client's Basic
* Information Cluster.
* @param currentVersion The current version running on the OTA Requestor. Should match the SoftwareVersion attribute of the
* Client's Basic Information Cluster.
* @param protocolsSupported A list of OTADownloadProtocol enum values indicating download protocols supported by the OTA Requestor
* (max length 8 entries).
* @param location Optional, 2 chars. If present, it should match the Location value in the Client's Basic Information Cluster.
* @param clientCanConsent Optional. May be set by an OTA Requestor which is capable of obtaining user consent for OTA application.
* @param metadataForProvider Optional, max 512 octets. A TLV-encoded Vendor-specific payload.
*/
bool emberAfOtaSoftwareUpdateProviderClusterQueryImageCallback(EndpointId endpoint, app::CommandHandler * commandObj,
uint16_t vendorId, uint16_t productId, uint16_t imageType,
uint16_t hardwareVersion, uint32_t currentVersion,
/* TODO(#8605): change this to list */ uint8_t protocolsSupported,
uint8_t * location, bool clientCanConsent,
ByteSpan metadataForProvider)
{
EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
OTAProviderDelegate * delegate = GetDelegate(endpoint);
if (SendStatusIfDelegateNull(endpoint))
{
return true;
};
ChipLogDetail(Zcl, "OTA Provider received QueryImage");
// TODO: (#7112) support location param and verify length once CHAR_STRING is supported
// Using location parameter is blocked by #5542 (use Span for string arguments). For now, there is no way to safely get the
// length of the location string because it is not guaranteed to be null-terminated.
Span<const char> locationSpan;
if (metadataForProvider.size() > kMaxMetadataLen)
{
ChipLogError(Zcl, "metadata size %zu exceeds max %zu", metadataForProvider.size(), kMaxMetadataLen);
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_ARGUMENT);
}
status = delegate->HandleQueryImage(commandObj, vendorId, productId, imageType, hardwareVersion, currentVersion,
protocolsSupported, locationSpan, clientCanConsent, metadataForProvider);
if (status != EMBER_ZCL_STATUS_SUCCESS)
{
emberAfSendImmediateDefaultResponse(status);
}
return true;
}
namespace chip {
namespace app {
namespace clusters {
void OTAProvider::SetDelegate(EndpointId endpoint, OTAProviderDelegate * delegate)
{
uint16_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_OTA_PROVIDER_CLUSTER_ID);
if (ep != 0xFFFF)
{
gDelegateTable[ep] = delegate;
}
}
} // namespace clusters
} // namespace app
} // namespace chip