@@ -41,39 +41,17 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() {
41
41
}
42
42
);
43
43
44
- // make the http get request
44
+ // check url
45
45
if (strcmp (context->parsed_url .schema (), " https" ) == 0 ) {
46
46
http_client = new HttpClient (*client, context->parsed_url .host (), context->parsed_url .port ());
47
47
} else {
48
48
return UrlParseErrorFail;
49
49
}
50
50
51
- http_client->beginRequest ();
52
- auto res = http_client->get (context->parsed_url .path ());
53
-
54
- if (username != nullptr && password != nullptr ) {
55
- http_client->sendBasicAuth (username, password);
56
- }
57
-
58
- http_client->endRequest ();
59
-
60
- if (res == HTTP_ERROR_CONNECTION_FAILED) {
61
- DEBUG_VERBOSE (" OTA ERROR: http client error connecting to server \" %s:%d\" " ,
62
- context->parsed_url .host (), context->parsed_url .port ());
63
- return ServerConnectErrorFail;
64
- } else if (res == HTTP_ERROR_TIMED_OUT) {
65
- DEBUG_VERBOSE (" OTA ERROR: http client timeout \" %s\" " , OTACloudProcessInterface::context->url );
66
- return OtaHeaderTimeoutFail;
67
- } else if (res != HTTP_SUCCESS) {
68
- DEBUG_VERBOSE (" OTA ERROR: http client returned %d on get \" %s\" " , res, OTACloudProcessInterface::context->url );
69
- return OtaDownloadFail;
70
- }
71
-
72
- int statusCode = http_client->responseStatusCode ();
73
-
74
- if (statusCode != 200 ) {
75
- DEBUG_VERBOSE (" OTA ERROR: get response on \" %s\" returned status %d" , OTACloudProcessInterface::context->url , statusCode);
76
- return HttpResponseFail;
51
+ // make the http get request
52
+ OTACloudProcessInterface::State res = requestOta ();
53
+ if (res != Fetch) {
54
+ return res;
77
55
}
78
56
79
57
// The following call is required to save the header value , keep it
@@ -82,16 +60,27 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() {
82
60
return HttpHeaderErrorFail;
83
61
}
84
62
63
+ context->contentLength = http_client->contentLength ();
85
64
context->lastReportTime = millis ();
86
-
65
+ DEBUG_VERBOSE ( " OTA file length: %d " , context-> contentLength );
87
66
return Fetch;
88
67
}
89
68
90
69
OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch () {
91
70
OTACloudProcessInterface::State res = Fetch;
92
- int http_res = 0 ;
93
- uint32_t start = millis ();
94
71
72
+ if (getOtaPolicy (ChunkDownload)) {
73
+ res = requestOta (ChunkDownload);
74
+ }
75
+
76
+ context->downloadedChunkSize = 0 ;
77
+ context->downloadedChunkStartTime = millis ();
78
+
79
+ if (res != Fetch) {
80
+ goto exit ;
81
+ }
82
+
83
+ /* download chunked or timed */
95
84
do {
96
85
if (!http_client->connected ()) {
97
86
res = OtaDownloadFail;
@@ -104,7 +93,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
104
93
continue ;
105
94
}
106
95
107
- http_res = http_client->read (context->buffer , context->buf_len );
96
+ int http_res = http_client->read (context->buffer , context->bufLen );
108
97
109
98
if (http_res < 0 ) {
110
99
DEBUG_VERBOSE (" OTA ERROR: Download read error %d" , http_res);
@@ -119,8 +108,10 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
119
108
res = ErrorWriteUpdateFileFail;
120
109
goto exit ;
121
110
}
122
- } while ((context->downloadState == OtaDownloadFile || context->downloadState == OtaDownloadHeader) &&
123
- millis () - start < downloadTime);
111
+
112
+ context->downloadedChunkSize += http_res;
113
+
114
+ } while (context->downloadState < OtaDownloadCompleted && fetchMore ());
124
115
125
116
// TODO verify that the information present in the ota header match the info in context
126
117
if (context->downloadState == OtaDownloadCompleted) {
@@ -153,13 +144,69 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
153
144
return res;
154
145
}
155
146
156
- void OTADefaultCloudProcessInterface::parseOta (uint8_t * buffer, size_t buf_len) {
147
+ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta (OtaFlags mode) {
148
+ int http_res = 0 ;
149
+
150
+ /* stop connected client */
151
+ http_client->stop ();
152
+
153
+ /* request chunk */
154
+ http_client->beginRequest ();
155
+ http_res = http_client->get (context->parsed_url .path ());
156
+
157
+ if (username != nullptr && password != nullptr ) {
158
+ http_client->sendBasicAuth (username, password);
159
+ }
160
+
161
+ if ((mode & ChunkDownload) == ChunkDownload) {
162
+ char range[128 ] = {0 };
163
+ size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize;
164
+ sprintf (range, " bytes=%" PRIu32 " -%" PRIu32, context->downloadedSize , context->downloadedSize + rangeSize);
165
+ DEBUG_VERBOSE (" OTA downloading range: %s" , range);
166
+ http_client->sendHeader (" Range" , range);
167
+ }
168
+
169
+ http_client->endRequest ();
170
+
171
+ if (http_res == HTTP_ERROR_CONNECTION_FAILED) {
172
+ DEBUG_VERBOSE (" OTA ERROR: http client error connecting to server \" %s:%d\" " ,
173
+ context->parsed_url .host (), context->parsed_url .port ());
174
+ return ServerConnectErrorFail;
175
+ } else if (http_res == HTTP_ERROR_TIMED_OUT) {
176
+ DEBUG_VERBOSE (" OTA ERROR: http client timeout \" %s\" " , OTACloudProcessInterface::context->url );
177
+ return OtaHeaderTimeoutFail;
178
+ } else if (http_res != HTTP_SUCCESS) {
179
+ DEBUG_VERBOSE (" OTA ERROR: http client returned %d on get \" %s\" " , http_res, OTACloudProcessInterface::context->url );
180
+ return OtaDownloadFail;
181
+ }
182
+
183
+ int statusCode = http_client->responseStatusCode ();
184
+
185
+ if ((((mode & ChunkDownload) == ChunkDownload) && (statusCode != 206 )) ||
186
+ (((mode & ChunkDownload) != ChunkDownload) && (statusCode != 200 ))) {
187
+ DEBUG_VERBOSE (" OTA ERROR: get response on \" %s\" returned status %d" , OTACloudProcessInterface::context->url , statusCode);
188
+ return HttpResponseFail;
189
+ }
190
+
191
+ http_client->skipResponseHeaders ();
192
+ return Fetch;
193
+ }
194
+
195
+ bool OTADefaultCloudProcessInterface::fetchMore () {
196
+ if (getOtaPolicy (ChunkDownload)) {
197
+ return context->downloadedChunkSize < maxChunkSize;
198
+ } else {
199
+ return (millis () - context->downloadedChunkStartTime ) < downloadTime;
200
+ }
201
+ }
202
+
203
+ void OTADefaultCloudProcessInterface::parseOta (uint8_t * buffer, size_t bufLen) {
157
204
assert (context != nullptr ); // This should never fail
158
205
159
- for (uint8_t * cursor=(uint8_t *)buffer; cursor<buffer+buf_len ; ) {
206
+ for (uint8_t * cursor=(uint8_t *)buffer; cursor<buffer+bufLen ; ) {
160
207
switch (context->downloadState ) {
161
208
case OtaDownloadHeader: {
162
- const uint32_t headerLeft = context->headerCopiedBytes + buf_len <= sizeof (context->header .buf ) ? buf_len : sizeof (context->header .buf ) - context->headerCopiedBytes ;
209
+ const uint32_t headerLeft = context->headerCopiedBytes + bufLen <= sizeof (context->header .buf ) ? bufLen : sizeof (context->header .buf ) - context->headerCopiedBytes ;
163
210
memcpy (context->header .buf +context->headerCopiedBytes , buffer, headerLeft);
164
211
cursor += headerLeft;
165
212
context->headerCopiedBytes += headerLeft;
@@ -184,8 +231,7 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t buf_len)
184
231
break ;
185
232
}
186
233
case OtaDownloadFile: {
187
- const uint32_t contentLength = http_client->contentLength ();
188
- const uint32_t dataLeft = buf_len - (cursor-buffer);
234
+ const uint32_t dataLeft = bufLen - (cursor-buffer);
189
235
context->decoder .decompress (cursor, dataLeft); // TODO verify return value
190
236
191
237
context->calculatedCrc32 = crc_update (
@@ -198,18 +244,18 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t buf_len)
198
244
context->downloadedSize += dataLeft;
199
245
200
246
if ((millis () - context->lastReportTime ) > 10000 ) { // Report the download progress each X millisecond
201
- DEBUG_VERBOSE (" OTA Download Progress %d/%d" , context->downloadedSize , contentLength);
247
+ DEBUG_VERBOSE (" OTA Download Progress %d/%d" , context->downloadedSize , context-> contentLength );
202
248
203
249
reportStatus (context->downloadedSize );
204
250
context->lastReportTime = millis ();
205
251
}
206
252
207
253
// TODO there should be no more bytes available when the download is completed
208
- if (context->downloadedSize == contentLength) {
254
+ if (context->downloadedSize == context-> contentLength ) {
209
255
context->downloadState = OtaDownloadCompleted;
210
256
}
211
257
212
- if (context->downloadedSize > contentLength) {
258
+ if (context->downloadedSize > context-> contentLength ) {
213
259
context->downloadState = OtaDownloadError;
214
260
}
215
261
// TODO fail if we exceed a timeout? and available is 0 (client is broken)
@@ -250,7 +296,9 @@ OTADefaultCloudProcessInterface::Context::Context(
250
296
, headerCopiedBytes(0 )
251
297
, downloadedSize(0 )
252
298
, lastReportTime(0 )
299
+ , contentLength(0 )
253
300
, writeError(false )
301
+ , downloadedChunkSize(0 )
254
302
, decoder(putc) { }
255
303
256
304
static const uint32_t crc_table[256 ] = {
0 commit comments