Skip to content

Commit 2c7fad4

Browse files
committed
OtaInterfaceDefault: download in chunks
1 parent 7d4e9e0 commit 2c7fad4

File tree

2 files changed

+65
-15
lines changed

2 files changed

+65
-15
lines changed

src/ota/interface/OTAInterfaceDefault.cpp

+58-12
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() {
8282
return HttpHeaderErrorFail;
8383
}
8484

85-
context->lastReportTime = millis();
85+
context->contentLength = http_client->contentLength();
86+
87+
DEBUG_VERBOSE("OTA file length: %d", context->contentLength);
88+
http_client->stop(); // close the connection
8689

8790
return Fetch;
8891
}
@@ -91,7 +94,45 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
9194
OTACloudProcessInterface::State res = Fetch;
9295
int http_res = 0;
9396
uint32_t start = millis();
97+
char range[128] = {0};
98+
99+
/* request chunk */
100+
http_client->beginRequest();
101+
http_res = http_client->get(context->parsed_url.path());
102+
103+
if(username != nullptr && password != nullptr) {
104+
http_client->sendBasicAuth(username, password);
105+
}
106+
107+
size_t rangeSize = context->downloadedSize + context->maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : context->maxChunkSize;
108+
sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize);
109+
DEBUG_VERBOSE("OTA downloading range: %s", range);
110+
http_client->sendHeader("Range", range);
111+
http_client->endRequest();
112+
113+
if(http_res == HTTP_ERROR_CONNECTION_FAILED) {
114+
DEBUG_VERBOSE("OTA ERROR: http client error connecting to server \"%s:%d\"",
115+
context->parsed_url.host(), context->parsed_url.port());
116+
return ServerConnectErrorFail;
117+
} else if(http_res == HTTP_ERROR_TIMED_OUT) {
118+
DEBUG_VERBOSE("OTA ERROR: http client timeout \"%s\"", OTACloudProcessInterface::context->url);
119+
return OtaHeaderTimeoutFail;
120+
} else if(http_res != HTTP_SUCCESS) {
121+
DEBUG_VERBOSE("OTA ERROR: http client returned %d on get \"%s\"", res, OTACloudProcessInterface::context->url);
122+
return OtaDownloadFail;
123+
}
124+
125+
int statusCode = http_client->responseStatusCode();
94126

127+
if(statusCode != 206) {
128+
DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode);
129+
return HttpResponseFail;
130+
}
131+
132+
http_client->skipResponseHeaders();
133+
134+
/* download chunk */
135+
context->downloadedChunkSize = 0;
95136
do {
96137
if(!http_client->connected()) {
97138
res = OtaDownloadFail;
@@ -104,7 +145,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
104145
continue;
105146
}
106147

107-
http_res = http_client->read(context->buffer, context->buf_len);
148+
http_res = http_client->read(context->buffer, context->bufLen);
108149

109150
if(http_res < 0) {
110151
DEBUG_VERBOSE("OTA ERROR: Download read error %d", http_res);
@@ -119,8 +160,13 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
119160
res = ErrorWriteUpdateFileFail;
120161
goto exit;
121162
}
163+
164+
context->downloadedChunkSize += http_res;
165+
122166
} while((context->downloadState == OtaDownloadFile || context->downloadState == OtaDownloadHeader) &&
123-
millis() - start < downloadTime);
167+
(context->downloadedChunkSize < rangeSize));
168+
169+
context->printProgress = true;
124170

125171
// TODO verify that the information present in the ota header match the info in context
126172
if(context->downloadState == OtaDownloadCompleted) {
@@ -145,8 +191,8 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
145191
}
146192

147193
exit:
194+
http_client->stop(); // close the connection
148195
if(res != Fetch) {
149-
http_client->stop(); // close the connection
150196
delete http_client;
151197
http_client = nullptr;
152198
}
@@ -183,7 +229,6 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t buf_len)
183229
break;
184230
}
185231
case OtaDownloadFile: {
186-
uint32_t contentLength = http_client->contentLength();
187232
context->decoder.decompress(cursor, buf_len - (cursor-buffer)); // TODO verify return value
188233

189234
context->calculatedCrc32 = crc_update(
@@ -195,19 +240,18 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t buf_len)
195240
cursor += buf_len - (cursor-buffer);
196241
context->downloadedSize += (cursor-buffer);
197242

198-
if((millis() - context->lastReportTime) > 10000) { // Report the download progress each X millisecond
199-
DEBUG_VERBOSE("OTA Download Progress %d/%d", context->downloadedSize, contentLength);
200-
243+
if(context->printProgress) {
244+
DEBUG_VERBOSE("OTA Download Progress %d/%d", context->downloadedSize, context->contentLength);
201245
reportStatus(context->downloadedSize);
202-
context->lastReportTime = millis();
246+
context->printProgress = false;
203247
}
204248

205249
// TODO there should be no more bytes available when the download is completed
206-
if(context->downloadedSize == contentLength) {
250+
if(context->downloadedSize == context->contentLength) {
207251
context->downloadState = OtaDownloadCompleted;
208252
}
209253

210-
if(context->downloadedSize > contentLength) {
254+
if(context->downloadedSize > context->contentLength) {
211255
context->downloadState = OtaDownloadError;
212256
}
213257
// TODO fail if we exceed a timeout? and available is 0 (client is broken)
@@ -247,8 +291,10 @@ OTADefaultCloudProcessInterface::Context::Context(
247291
, calculatedCrc32(0xFFFFFFFF)
248292
, headerCopiedBytes(0)
249293
, downloadedSize(0)
250-
, lastReportTime(0)
294+
, printProgress(false)
295+
, contentLength(0)
251296
, writeError(false)
297+
, downloadedChunkSize(0)
252298
, decoder(putc) { }
253299

254300
static const uint32_t crc_table[256] = {

src/ota/interface/OTAInterfaceDefault.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,18 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface {
7373
uint32_t calculatedCrc32;
7474
uint32_t headerCopiedBytes;
7575
uint32_t downloadedSize;
76-
uint32_t lastReportTime;
76+
bool printProgress;
77+
uint32_t contentLength;
7778
bool writeError;
7879

80+
uint32_t downloadedChunkSize;
81+
static constexpr size_t maxChunkSize = 1024 * 10;
82+
7983
// LZSS decoder
8084
LZSSDecoder decoder;
8185

82-
const size_t buf_len = 64;
83-
uint8_t buffer[64];
86+
static constexpr size_t bufLen = 1460;
87+
uint8_t buffer[bufLen];
8488
} *context;
8589
};
8690

0 commit comments

Comments
 (0)