Skip to content

Commit f5bd923

Browse files
committed
OTA: chunked/timed download, improve code reuse
1 parent a00b853 commit f5bd923

File tree

2 files changed

+53
-103
lines changed

2 files changed

+53
-103
lines changed

src/ota/interface/OTAInterfaceDefault.cpp

Lines changed: 48 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -92,59 +92,20 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() {
9292
}
9393

9494
OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
95-
if(fetchMode == OtaFetchTime) {
96-
return fetchTime();
97-
} else {
98-
return fetchChunk();
99-
}
100-
}
101-
102-
OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() {
10395
OTACloudProcessInterface::State res = Fetch;
104-
int http_res = 0;
105-
uint32_t start = millis();
106-
char range[128] = {0};
107-
108-
/* stop connected client */
109-
http_client->stop();
110-
111-
/* request chunk */
112-
http_client->beginRequest();
113-
http_res = http_client->get(context->parsed_url.path());
11496

115-
if(username != nullptr && password != nullptr) {
116-
http_client->sendBasicAuth(username, password);
97+
if(fetchMode == OtaFetchChunk) {
98+
res = requestChunk();
11799
}
118100

119-
size_t rangeSize = context->downloadedSize + context->maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : context->maxChunkSize;
120-
sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize);
121-
DEBUG_VERBOSE("OTA downloading range: %s", range);
122-
http_client->sendHeader("Range", range);
123-
http_client->endRequest();
124-
125-
if(http_res == HTTP_ERROR_CONNECTION_FAILED) {
126-
DEBUG_VERBOSE("OTA ERROR: http client error connecting to server \"%s:%d\"",
127-
context->parsed_url.host(), context->parsed_url.port());
128-
return ServerConnectErrorFail;
129-
} else if(http_res == HTTP_ERROR_TIMED_OUT) {
130-
DEBUG_VERBOSE("OTA ERROR: http client timeout \"%s\"", OTACloudProcessInterface::context->url);
131-
return OtaHeaderTimeoutFail;
132-
} else if(http_res != HTTP_SUCCESS) {
133-
DEBUG_VERBOSE("OTA ERROR: http client returned %d on get \"%s\"", res, OTACloudProcessInterface::context->url);
134-
return OtaDownloadFail;
135-
}
136-
137-
int statusCode = http_client->responseStatusCode();
101+
context->downloadedChunkSize = 0;
102+
context->downloadedChunkStartTime = millis();
138103

139-
if(statusCode != 206) {
140-
DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode);
141-
return HttpResponseFail;
104+
if(res != Fetch) {
105+
goto exit;
142106
}
143107

144-
http_client->skipResponseHeaders();
145-
146-
/* download chunk */
147-
context->downloadedChunkSize = 0;
108+
/* download chunked or timed */
148109
do {
149110
if(!http_client->connected()) {
150111
res = OtaDownloadFail;
@@ -157,7 +118,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() {
157118
continue;
158119
}
159120

160-
http_res = http_client->read(context->buffer, context->bufLen);
121+
int http_res = http_client->read(context->buffer, context->bufLen);
161122

162123
if(http_res < 0) {
163124
DEBUG_VERBOSE("OTA ERROR: Download read error %d", http_res);
@@ -175,8 +136,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() {
175136

176137
context->downloadedChunkSize += http_res;
177138

178-
} while((context->downloadState == OtaDownloadFile || context->downloadState == OtaDownloadHeader) &&
179-
(context->downloadedChunkSize < rangeSize));
139+
} while(context->downloadState < OtaDownloadCompleted && fetchMore());
180140

181141
// TODO verify that the information present in the ota header match the info in context
182142
if(context->downloadState == OtaDownloadCompleted) {
@@ -209,70 +169,58 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() {
209169
return res;
210170
}
211171

212-
OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchTime() {
213-
OTACloudProcessInterface::State res = Fetch;
172+
OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestChunk() {
214173
int http_res = 0;
215174
uint32_t start = millis();
175+
char range[128] = {0};
216176

217-
do {
218-
if(!http_client->connected()) {
219-
res = OtaDownloadFail;
220-
goto exit;
221-
}
177+
/* stop connected client */
178+
http_client->stop();
222179

223-
if(http_client->available() == 0) {
224-
/* Avoid tight loop and allow yield */
225-
delay(1);
226-
continue;
227-
}
180+
/* request chunk */
181+
http_client->beginRequest();
182+
http_res = http_client->get(context->parsed_url.path());
228183

229-
http_res = http_client->read(context->buffer, context->bufLen);
184+
if(username != nullptr && password != nullptr) {
185+
http_client->sendBasicAuth(username, password);
186+
}
230187

231-
if(http_res < 0) {
232-
DEBUG_VERBOSE("OTA ERROR: Download read error %d", http_res);
233-
res = OtaDownloadFail;
234-
goto exit;
235-
}
188+
size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize;
189+
sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize);
190+
DEBUG_VERBOSE("OTA downloading range: %s", range);
191+
http_client->sendHeader("Range", range);
192+
http_client->endRequest();
236193

237-
parseOta(context->buffer, http_res);
194+
if(http_res == HTTP_ERROR_CONNECTION_FAILED) {
195+
DEBUG_VERBOSE("OTA ERROR: http client error connecting to server \"%s:%d\"",
196+
context->parsed_url.host(), context->parsed_url.port());
197+
return ServerConnectErrorFail;
198+
} else if(http_res == HTTP_ERROR_TIMED_OUT) {
199+
DEBUG_VERBOSE("OTA ERROR: http client timeout \"%s\"", OTACloudProcessInterface::context->url);
200+
return OtaHeaderTimeoutFail;
201+
} else if(http_res != HTTP_SUCCESS) {
202+
DEBUG_VERBOSE("OTA ERROR: http client returned %d on get \"%s\"", http_res, OTACloudProcessInterface::context->url);
203+
return OtaDownloadFail;
204+
}
238205

239-
if(context->writeError) {
240-
DEBUG_VERBOSE("OTA ERROR: File write error");
241-
res = ErrorWriteUpdateFileFail;
242-
goto exit;
243-
}
244-
} while((context->downloadState == OtaDownloadFile || context->downloadState == OtaDownloadHeader) &&
245-
millis() - start < downloadTime);
206+
int statusCode = http_client->responseStatusCode();
246207

247-
// TODO verify that the information present in the ota header match the info in context
248-
if(context->downloadState == OtaDownloadCompleted) {
249-
// Verify that the downloaded file size is matching the expected size ??
250-
// this could distinguish between consistency of the downloaded bytes and filesize
208+
if(statusCode != 206) {
209+
DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode);
210+
return HttpResponseFail;
211+
}
251212

252-
// validate CRC
253-
context->calculatedCrc32 ^= 0xFFFFFFFF; // finalize CRC
254-
if(context->header.header.crc32 == context->calculatedCrc32) {
255-
DEBUG_VERBOSE("Ota download completed successfully");
256-
res = FlashOTA;
257-
} else {
258-
res = OtaHeaderCrcFail;
259-
}
260-
} else if(context->downloadState == OtaDownloadError) {
261-
DEBUG_VERBOSE("OTA ERROR: OtaDownloadError");
213+
http_client->skipResponseHeaders();
262214

263-
res = OtaDownloadFail;
264-
} else if(context->downloadState == OtaDownloadMagicNumberMismatch) {
265-
DEBUG_VERBOSE("OTA ERROR: Magic number mismatch");
266-
res = OtaHeaderMagicNumberFail;
267-
}
215+
return Fetch;
216+
}
268217

269-
exit:
270-
if(res != Fetch) {
271-
http_client->stop(); // close the connection
272-
delete http_client;
273-
http_client = nullptr;
218+
bool OTADefaultCloudProcessInterface::fetchMore() {
219+
if (fetchMode == OtaFetchChunk) {
220+
return context->downloadedChunkSize < maxChunkSize;
221+
} else {
222+
return (millis() - context->downloadedChunkStartTime) < downloadTime;
274223
}
275-
return res;
276224
}
277225

278226
void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t bufLen) {

src/ota/interface/OTAInterfaceDefault.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface {
5050

5151
private:
5252
void parseOta(uint8_t* buffer, size_t bufLen);
53-
State fetchTime();
54-
State fetchChunk();
53+
State requestChunk();
54+
bool fetchMore();
5555

5656
Client* client;
5757
HttpClient* http_client;
@@ -63,6 +63,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface {
6363
// This mitigate the issues arising from tasks run in main loop that are using all the computing time
6464
static constexpr uint32_t downloadTime = 2000;
6565

66+
static constexpr size_t maxChunkSize = 1024 * 10;
67+
6668
enum OTADownloadState: uint8_t {
6769
OtaDownloadHeader,
6870
OtaDownloadFile,
@@ -87,8 +89,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface {
8789
uint32_t contentLength;
8890
bool writeError;
8991

92+
uint32_t downloadedChunkStartTime;
9093
uint32_t downloadedChunkSize;
91-
static constexpr size_t maxChunkSize = 1024 * 10;
9294

9395
// LZSS decoder
9496
LZSSDecoder decoder;

0 commit comments

Comments
 (0)