|
5 | 5 | */ |
6 | 6 |
|
7 | 7 | #include "esp_br_http_ota.h" |
8 | | -#include "esp_br_firmware.h" |
9 | 8 | #include "esp_check.h" |
10 | 9 | #include "esp_log.h" |
11 | 10 | #include "esp_ota_ops.h" |
12 | | -#include "esp_rcp_update.h" |
| 11 | +#include "esp_rcp_firmware.h" |
| 12 | +#include "esp_rcp_ota.h" |
13 | 13 |
|
14 | 14 | #define DEFAULT_REQUEST_SIZE 64 * 1024 |
15 | 15 | #define TAG "BR_OTA" |
@@ -129,173 +129,80 @@ static int http_client_read_check_connection(esp_http_client_handle_t client, ch |
129 | 129 | return len; |
130 | 130 | } |
131 | 131 |
|
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) |
133 | 133 | { |
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; |
208 | 135 | 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); |
213 | 143 | esp_http_client_handle_t http_client = esp_http_client_init(config); |
214 | 144 | 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"); |
224 | 146 | ESP_GOTO_ON_ERROR(_http_connect(http_client), exit, TAG, "Failed to connect to HTTP server"); |
225 | 147 |
|
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; |
231 | 148 | 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"); |
236 | 152 | 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; |
249 | 159 | break; |
250 | 160 | } |
251 | 161 | } |
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); |
266 | 172 | } |
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"); |
269 | 187 | } |
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); |
276 | 189 | 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)); |
281 | 192 | } |
282 | | - |
| 193 | + rcp_ota_handle = 0; |
283 | 194 | exit: |
284 | 195 | _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); |
287 | 201 | } |
288 | 202 | return ret; |
289 | 203 | } |
290 | 204 |
|
291 | 205 | esp_err_t esp_br_http_ota(esp_http_client_config_t *http_config) |
292 | 206 | { |
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); |
301 | 208 | } |
0 commit comments