Skip to content

Commit 3ebae10

Browse files
committed
Merge branch 'host_rcp_ota' into 'main'
feat(rcp): integrate the rcp ota feature to rcp_update component See merge request espressif/esp-thread-br!134
2 parents ceeb84a + 3911aab commit 3ebae10

File tree

9 files changed

+495
-174
lines changed

9 files changed

+495
-174
lines changed

components/esp_br_http_ota/src/esp_br_http_ota.c

Lines changed: 55 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
*/
66

77
#include "esp_br_http_ota.h"
8-
#include "esp_br_firmware.h"
98
#include "esp_check.h"
109
#include "esp_log.h"
1110
#include "esp_ota_ops.h"
12-
#include "esp_rcp_update.h"
11+
#include "esp_rcp_firmware.h"
12+
#include "esp_rcp_ota.h"
1313

1414
#define DEFAULT_REQUEST_SIZE 64 * 1024
1515
#define TAG "BR_OTA"
@@ -129,173 +129,80 @@ static int http_client_read_check_connection(esp_http_client_handle_t client, ch
129129
return len;
130130
}
131131

132-
static int http_read_for(esp_http_client_handle_t http_client, char *data, size_t size)
132+
static esp_err_t download_ota_image(esp_http_client_config_t *config)
133133
{
134-
int read_len = 0;
135-
while (read_len < size) {
136-
int len = http_client_read_check_connection(http_client, data, size - read_len);
137-
if (len < 0) {
138-
return read_len;
139-
}
140-
read_len += len;
141-
}
142-
return read_len;
143-
}
144-
145-
static esp_err_t download_br_ota_firmware(esp_http_client_handle_t http_client, uint32_t br_firmware_size)
146-
{
147-
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
148-
ESP_RETURN_ON_FALSE(update_partition != NULL, ESP_ERR_NOT_FOUND, TAG, "Failed to find ota partition");
149-
150-
esp_ota_handle_t ota_handle;
151-
int ret = ESP_OK;
152-
ESP_GOTO_ON_ERROR(esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &ota_handle), exit, TAG,
153-
"Failed to start ota");
154-
ESP_LOGI(TAG, "Downloading Border Router firmware data...");
155-
bool download_done = false;
156-
uint32_t read_size = 0;
157-
while (!download_done) {
158-
int len = http_client_read_check_connection(http_client, s_download_data_buf, sizeof(s_download_data_buf));
159-
download_done = esp_http_client_is_complete_data_received(http_client);
160-
ESP_GOTO_ON_FALSE(len >= 0, ESP_FAIL, exit, TAG, "Failed to download");
161-
read_size += len;
162-
ESP_GOTO_ON_ERROR(esp_ota_write(ota_handle, s_download_data_buf, len), exit, TAG, "Failed to write ota");
163-
ESP_LOGI(TAG, "%lu/%lu bytes", read_size, br_firmware_size);
164-
}
165-
ESP_GOTO_ON_FALSE(read_size == br_firmware_size, ESP_FAIL, exit, TAG, "Incomplete firmware");
166-
167-
exit:
168-
if (ret == ESP_OK) {
169-
ret = esp_ota_end(ota_handle);
170-
if (ret != ESP_OK) {
171-
ESP_LOGE(TAG, "Failed to submit OTA");
172-
}
173-
} else {
174-
esp_ota_abort(ota_handle);
175-
}
176-
return ret;
177-
}
178-
179-
static int write_file_for_length(FILE *fp, const void *buf, size_t size)
180-
{
181-
static const int k_max_retry = 5;
182-
int retry_count = 0;
183-
int offset = 0;
184-
const uint8_t *data = (const uint8_t *)buf;
185-
while (offset < size) {
186-
int ret =
187-
fwrite(data + offset, 1, ((size - offset) < OTA_MAX_WRITE_SIZE ? (size - offset) : OTA_MAX_WRITE_SIZE), fp);
188-
if (ret < 0) {
189-
return ret;
190-
}
191-
if (ret == 0) {
192-
retry_count++;
193-
} else {
194-
offset += ret;
195-
retry_count = 0;
196-
}
197-
if (retry_count > k_max_retry) {
198-
return -1;
199-
}
200-
}
201-
return size;
202-
}
203-
204-
static esp_err_t download_ota_image(esp_http_client_config_t *config, const char *rcp_firmware_dir,
205-
int8_t rcp_update_seq)
206-
{
207-
char rcp_target_path[RCP_FILENAME_MAX_SIZE];
134+
esp_err_t ret = ESP_OK;
208135
bool download_done = false;
209-
210-
sprintf(rcp_target_path, "%s_%d/" ESP_BR_RCP_IMAGE_FILENAME, rcp_firmware_dir, rcp_update_seq);
211-
212-
ESP_LOGI(TAG, "Downloading %s, RCP target file %s\n", config->url, rcp_target_path);
136+
esp_rcp_ota_handle_t rcp_ota_handle = 0;
137+
esp_ota_handle_t host_ota_handle = 0;
138+
uint32_t br_fw_downloaded = 0;
139+
uint32_t br_fw_size = 0;
140+
char *br_fist_write_ptr = NULL;
141+
size_t br_first_write_size = 0;
142+
ESP_LOGI(TAG, "Downloading from %s\n", config->url);
213143
esp_http_client_handle_t http_client = esp_http_client_init(config);
214144
ESP_RETURN_ON_FALSE(http_client != NULL, ESP_FAIL, TAG, "Failed to create HTTP client");
215-
esp_err_t ret = ESP_OK;
216-
FILE *fp = fopen(rcp_target_path, "w");
217-
if (!fp) {
218-
ESP_LOGE(TAG, "Fail to open %s, will delete it and create a new one", rcp_target_path);
219-
remove(rcp_target_path);
220-
fp = fopen(rcp_target_path, "w");
221-
}
222-
223-
ESP_GOTO_ON_FALSE(fp != NULL, ESP_FAIL, exit, TAG, "Failed to open target file");
145+
ESP_GOTO_ON_ERROR(esp_rcp_ota_begin(&rcp_ota_handle), exit, TAG, "Failed to begin RCP OTA");
224146
ESP_GOTO_ON_ERROR(_http_connect(http_client), exit, TAG, "Failed to connect to HTTP server");
225147

226-
// First decide the br firmware offset
227-
uint32_t header_size = 0;
228-
uint32_t read_size = 0;
229-
uint32_t br_firmware_offset = 0;
230-
uint32_t br_firmware_size = 0;
231148
while (!download_done) {
232-
esp_br_subfile_info_t subfile_info;
233-
int len = http_read_for(http_client, (char *)&subfile_info, sizeof(subfile_info));
234-
ESP_LOGI(TAG, "subfile_info: tag 0x%lx size %lu offset %lu\n", subfile_info.tag, subfile_info.size,
235-
subfile_info.offset);
149+
int len = http_client_read_check_connection(http_client, s_download_data_buf, sizeof(s_download_data_buf));
150+
size_t rcp_ota_received_len = 0;
151+
ESP_GOTO_ON_FALSE(len >= 0, ESP_FAIL, exit, TAG, "Failed to download");
236152
download_done = esp_http_client_is_complete_data_received(http_client);
237-
ESP_GOTO_ON_FALSE(len == sizeof(subfile_info), ESP_FAIL, exit, TAG, "Incomplete header");
238-
239-
read_size += len;
240-
if (subfile_info.tag == FILETAG_IMAGE_HEADER) {
241-
header_size = subfile_info.size;
242-
} else if (subfile_info.tag == FILETAG_BR_FIRMWARE) {
243-
br_firmware_offset = subfile_info.offset;
244-
br_firmware_size = subfile_info.size;
245-
}
246-
ESP_GOTO_ON_FALSE(write_file_for_length(fp, &subfile_info, len) == len, ESP_FAIL, exit, TAG,
247-
"Failed to write data");
248-
if (read_size >= header_size) {
153+
ESP_GOTO_ON_ERROR(esp_rcp_ota_receive(rcp_ota_handle, s_download_data_buf, len, &rcp_ota_received_len), exit,
154+
TAG, "Failed to receive host RCP OTA data");
155+
if (esp_rcp_ota_get_state(rcp_ota_handle) == ESP_RCP_OTA_STATE_FINISHED) {
156+
br_fw_size = esp_rcp_ota_get_subfile_size(rcp_ota_handle, FILETAG_HOST_FIRMWARE);
157+
br_fist_write_ptr = &s_download_data_buf[rcp_ota_received_len];
158+
br_first_write_size = len - rcp_ota_received_len;
249159
break;
250160
}
251161
}
252-
253-
while (!download_done && read_size < br_firmware_offset) {
254-
int target_read_size = sizeof(s_download_data_buf) < br_firmware_offset - read_size
255-
? sizeof(s_download_data_buf)
256-
: br_firmware_offset - read_size;
257-
int len = http_client_read_check_connection(http_client, s_download_data_buf, target_read_size);
258-
download_done = esp_http_client_is_complete_data_received(http_client);
259-
260-
ESP_GOTO_ON_FALSE(len >= 0, ESP_FAIL, exit, TAG, "Failed to download");
261-
if (len > 0) {
262-
int r = write_file_for_length(fp, s_download_data_buf, len);
263-
if (r != len) {
264-
ESP_GOTO_ON_FALSE(r == len, ESP_FAIL, exit, TAG, "Failed to write OTA");
265-
}
162+
if (br_fw_size > 0) {
163+
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
164+
ESP_GOTO_ON_FALSE(update_partition != NULL, ESP_ERR_NOT_FOUND, exit, TAG, "Failed to find ota partition");
165+
ESP_GOTO_ON_ERROR(esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &host_ota_handle), exit, TAG,
166+
"Failed to begin host OTA");
167+
if (br_fist_write_ptr && br_first_write_size > 0) {
168+
ESP_GOTO_ON_ERROR(esp_ota_write(host_ota_handle, br_fist_write_ptr, br_first_write_size), exit, TAG,
169+
"Failed to write ota");
170+
br_fw_downloaded += br_first_write_size;
171+
ESP_LOGD(TAG, "Border Router firmware download %lu/%lu bytes", br_fw_downloaded, br_fw_size);
266172
}
267-
read_size += len;
268-
ESP_LOGI(TAG, "Downloaded %lu bytes", read_size);
173+
while (!download_done && br_fw_downloaded < br_fw_size) {
174+
int len = http_client_read_check_connection(http_client, s_download_data_buf, sizeof(s_download_data_buf));
175+
download_done = esp_http_client_is_complete_data_received(http_client);
176+
ESP_GOTO_ON_FALSE(len >= 0, ESP_FAIL, exit, TAG, "Failed to download");
177+
br_fw_downloaded += len;
178+
ESP_GOTO_ON_ERROR(esp_ota_write(host_ota_handle, s_download_data_buf, len), exit, TAG,
179+
"Failed to write ota");
180+
ESP_LOGD(TAG, "Border Router firmware download %lu/%lu bytes", br_fw_downloaded, br_fw_size);
181+
}
182+
ret = esp_ota_end(host_ota_handle);
183+
host_ota_handle = 0;
184+
ESP_GOTO_ON_ERROR(ret, exit, TAG, "Failed to end host OTA");
185+
ESP_GOTO_ON_ERROR(esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL)), exit, TAG,
186+
"Failed to set boot partition");
269187
}
270-
271-
ESP_GOTO_ON_FALSE(read_size == br_firmware_offset, ESP_FAIL, exit, TAG, "Incomplete RCP image");
272-
ESP_GOTO_ON_ERROR(download_br_ota_firmware(http_client, br_firmware_size), exit, TAG,
273-
"Failed to download OTA firmware");
274-
ESP_GOTO_ON_ERROR(esp_rcp_submit_new_image(), exit, TAG, "Failed to submit RCP image");
275-
ret = esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL));
188+
ret = esp_rcp_ota_end(rcp_ota_handle);
276189
if (ret != ESP_OK) {
277-
ESP_LOGE(TAG, "Failed to set new OTA boot partition");
278-
// Try to revert the RCP image submission. The RCP image update sequence will be set back to the original number
279-
// by calling esp_rcp_submit_new_image again.
280-
esp_rcp_submit_new_image();
190+
// rollback the host boot partition when failing to end RCP OTA
191+
esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL));
281192
}
282-
193+
rcp_ota_handle = 0;
283194
exit:
284195
_http_cleanup(http_client);
285-
if (fp != NULL) {
286-
fclose(fp);
196+
if (ret != ESP_OK && host_ota_handle) {
197+
esp_ota_abort(host_ota_handle);
198+
}
199+
if (ret != ESP_OK && rcp_ota_handle) {
200+
esp_rcp_ota_abort(rcp_ota_handle);
287201
}
288202
return ret;
289203
}
290204

291205
esp_err_t esp_br_http_ota(esp_http_client_config_t *http_config)
292206
{
293-
const char *firmware_dir = esp_rcp_get_firmware_dir();
294-
ESP_RETURN_ON_FALSE(http_config != NULL, ESP_ERR_INVALID_ARG, TAG, "NULL http config");
295-
ESP_RETURN_ON_FALSE(http_config->url != NULL, ESP_ERR_INVALID_ARG, TAG, "NULL http url");
296-
297-
int8_t rcp_update_seq = esp_rcp_get_next_update_seq();
298-
ESP_RETURN_ON_ERROR(download_ota_image(http_config, firmware_dir, rcp_update_seq), TAG,
299-
"Failed to download ota image");
300-
return ESP_OK;
207+
return download_ota_image(http_config);
301208
}

components/esp_ot_cli_extension/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "1.2.2"
1+
version: "1.2.3"
22
description: Espressif OpenThread CLI Extension
33
url: https://github.com/espressif/esp-thread-br/tree/main/components/esp_ot_cli_extension
44
dependencies:

components/esp_ot_cli_extension/src/esp_ot_ota_commands.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "esp_check.h"
1313
#include "esp_openthread_border_router.h"
1414
#include "esp_ot_cli_extension.h"
15+
#include "freertos/idf_additions.h"
1516
#include "openthread/cli.h"
1617

1718
static const char *s_server_cert = NULL;
@@ -21,6 +22,27 @@ static void print_help(void)
2122
otCliOutputFormat("rcp download ${server_url}\n");
2223
}
2324

25+
static void ota_image_download_task(void *ctx)
26+
{
27+
char *url = (char *)ctx;
28+
esp_err_t err = ESP_OK;
29+
esp_http_client_config_t config = {
30+
.url = url,
31+
.cert_pem = s_server_cert,
32+
.event_handler = NULL,
33+
.keep_alive_enable = true,
34+
};
35+
err = esp_br_http_ota(&config);
36+
free(url);
37+
if (err != ESP_OK) {
38+
otCliOutputFormat("Failed to download image");
39+
} else {
40+
// OTA succeed, restart.
41+
esp_restart();
42+
}
43+
vTaskDelete(NULL);
44+
}
45+
2446
otError esp_openthread_process_ota_command(void *aContext, uint8_t aArgsLength, char *aArgs[])
2547
{
2648
if (aArgsLength == 0) {
@@ -29,18 +51,12 @@ otError esp_openthread_process_ota_command(void *aContext, uint8_t aArgsLength,
2951
if (aArgsLength != 2) {
3052
print_help();
3153
} else {
32-
char *url = aArgs[1];
33-
esp_http_client_config_t config = {
34-
.url = url,
35-
.cert_pem = s_server_cert,
36-
.event_handler = NULL,
37-
.keep_alive_enable = true,
38-
};
39-
if (esp_br_http_ota(&config) != ESP_OK) {
40-
otCliOutputFormat("Failed to download image");
54+
char *url = strdup(aArgs[1]);
55+
if (!url) {
56+
return OT_ERROR_NO_BUFS;
4157
}
58+
xTaskCreate(ota_image_download_task, "ota_image_download", 3072, url, 5, NULL);
4259
}
43-
esp_restart();
4460
} else {
4561
print_help();
4662
}

components/esp_rcp_update/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "1.2.0"
1+
version: "1.3.0"
22
description: Espressif RCP Update Component for Thread Border Router and Zigbee Gateway
33
url: https://github.com/espressif/esp-thread-br/tree/main/components/esp_rcp_update
44
dependencies:

components/esp_rcp_update/include/esp_br_firmware.h renamed to components/esp_rcp_update/include/esp_rcp_firmware.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,35 @@
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
6+
#pragma once
67

78
#include <stdint.h>
89

910
#ifdef __cplusplus
1011
extern "C" {
1112
#endif
1213

14+
#define MAX_SUBFILE_INFO 7
15+
1316
typedef enum {
1417
FILETAG_RCP_VERSION = 0,
1518
FILETAG_RCP_FLASH_ARGS = 1,
1619
FILETAG_RCP_BOOTLOADER = 2,
1720
FILETAG_RCP_PARTITION_TABLE = 3,
1821
FILETAG_RCP_FIRMWARE = 4,
19-
FILETAG_BR_FIRMWARE = 5,
22+
FILETAG_HOST_FIRMWARE = 5,
2023
FILETAG_IMAGE_HEADER = 0xff,
21-
} esp_br_filetag_t;
24+
} esp_rcp_filetag_t;
2225

23-
struct esp_br_subfile_info {
26+
struct esp_rcp_subfile_info {
2427
uint32_t tag;
2528
uint32_t size;
2629
uint32_t offset;
2730
} __attribute__((packed));
2831

29-
typedef struct esp_br_subfile_info esp_br_subfile_info_t;
32+
typedef struct esp_rcp_subfile_info esp_rcp_subfile_info_t;
3033

31-
#define ESP_BR_RCP_IMAGE_FILENAME "rcp_image"
34+
#define ESP_RCP_IMAGE_FILENAME "rcp_image"
3235

3336
#ifdef __cplusplus
3437
}

0 commit comments

Comments
 (0)