Double MSP (TLM and MAVLink) throughput for Gemini hardware (#3037)
[ExpressLRS.git] / src / lib / SerialUpdate / stub_write_flash.cpp
blob6b9935357821e47b0700ea0638e3994f6b5fc0d3
1 /*
2 * SPDX-FileCopyrightText: 2016 Cesanta Software Limited
4 * SPDX-License-Identifier: GPL-2.0-or-later
6 * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
7 */
9 #if defined(PLATFORM_ESP32) && defined(TARGET_RX)
11 #include "stub_write_flash.h"
12 #include "rom/miniz.h"
13 #include "slip.h"
14 #include "soc_support.h"
15 #include "stub_flasher.h"
16 #include "targets.h"
18 #include <Update.h>
20 /* local flashing state
22 This is wrapped in a structure because gcc 4.8
23 generates significantly more code for ESP32
24 if they are static variables (literal pool, I think!)
26 static struct
28 /* set by flash_begin, cleared by flash_end */
29 bool in_flash_mode;
30 /* number of output bytes remaining to write */
31 uint32_t remaining;
32 /* last error generated by a data packet */
33 esp_command_error last_error;
35 uint8_t *last_buf;
36 uint32_t last_length;
37 uint32_t last_end;
38 MD5Builder md5;
40 /* inflator state for deflate write */
41 tinfl_decompressor inflator;
42 /* number of compressed bytes remaining to read */
43 uint32_t remaining_compressed;
44 } fs;
46 bool is_in_flash_mode(void)
48 return fs.in_flash_mode;
51 esp_command_error get_flash_error(void)
53 return fs.last_error;
56 esp_command_error handle_flash_get_md5sum(uint32_t addr, uint32_t len)
58 /* ESP32 ROM sends as hex, but stub just send raw bytes - esptool.py can handle either. */
59 fs.md5.add(fs.last_buf, len - fs.last_end);
60 fs.md5.calculate();
61 uint8_t md5[16];
62 fs.md5.getBytes(md5);
63 SLIP_send_frame_data_buf(md5, sizeof(md5));
64 return ESP_UPDATE_OK;
67 esp_command_error handle_flash_begin(uint32_t total_size, uint32_t offset)
69 fs.in_flash_mode = true;
70 fs.remaining = total_size;
71 if (total_size != 0)
73 Update.begin(total_size);
74 fs.last_buf = static_cast<uint8_t *>(malloc(32768));
75 fs.md5.begin();
77 fs.last_length = 0;
78 fs.last_end = 0;
79 return ESP_UPDATE_OK;
82 esp_command_error handle_flash_deflated_begin(uint32_t uncompressed_size, uint32_t compressed_size, uint32_t offset)
84 esp_command_error err = handle_flash_begin(uncompressed_size, offset);
85 tinfl_init(&fs.inflator);
86 fs.remaining_compressed = compressed_size;
87 return err;
90 void handle_flash_data(uint8_t *data_buf, uint32_t length)
92 if (fs.last_length)
94 fs.md5.add(fs.last_buf, fs.last_length);
95 fs.last_end += fs.last_length;
97 if (length > fs.remaining)
99 /* Trim the final block, as it may have padding beyond
100 the length we are writing */
101 length = fs.remaining;
103 memcpy(fs.last_buf, data_buf, length);
104 fs.last_length = length;
105 fs.remaining -= length;
106 Update.write(data_buf, length);
108 fs.last_error = ESP_UPDATE_OK;
111 void handle_flash_deflated_data(uint8_t *data_buf, uint32_t length)
113 static uint8_t *out_buf = nullptr;
114 static uint8_t *next_out = nullptr;
115 int status = TINFL_STATUS_NEEDS_MORE_INPUT;
117 const size_t out_size = 32768;
118 if (out_buf == nullptr)
120 out_buf = static_cast<uint8_t *>(malloc(out_size));
121 next_out = out_buf;
123 while (length > 0 && fs.remaining > 0 && status > TINFL_STATUS_DONE)
125 size_t in_bytes = length; /* input remaining */
126 size_t out_bytes = out_buf + out_size - next_out; /* output space remaining */
127 int flags = TINFL_FLAG_PARSE_ZLIB_HEADER;
128 if (fs.remaining_compressed > length)
130 flags |= TINFL_FLAG_HAS_MORE_INPUT;
133 status = tinfl_decompress(&fs.inflator, data_buf, &in_bytes, out_buf, next_out, &out_bytes, flags);
135 fs.remaining_compressed -= in_bytes;
136 length -= in_bytes;
137 data_buf += in_bytes;
139 next_out += out_bytes;
140 size_t bytes_in_out_buf = next_out - out_buf;
141 if (status == TINFL_STATUS_DONE || bytes_in_out_buf == out_size)
143 // Output buffer full, or done
144 handle_flash_data(out_buf, bytes_in_out_buf);
145 next_out = out_buf;
147 } // while
149 if (status < TINFL_STATUS_DONE)
151 /* error won't get sent back to esptool.py until next block is sent */
152 fs.last_error = ESP_INFLATE_ERROR;
155 if (status == TINFL_STATUS_DONE && fs.remaining > 0)
157 fs.last_error = ESP_NOT_ENOUGH_DATA;
159 if (status != TINFL_STATUS_DONE && fs.remaining == 0)
161 fs.last_error = ESP_TOO_MUCH_DATA;
165 esp_command_error handle_flash_end(void)
167 if (!fs.in_flash_mode)
169 return ESP_NOT_IN_FLASH_MODE;
172 if (fs.remaining > 0)
174 return ESP_NOT_ENOUGH_DATA;
177 fs.in_flash_mode = false;
179 if (!Update.end(true))
181 switch (Update.getError())
183 case UPDATE_ERROR_SPACE:
184 return ESP_TOO_MUCH_DATA;
185 case UPDATE_ERROR_SIZE:
186 return ESP_NOT_ENOUGH_DATA;
187 case UPDATE_ERROR_MD5:
188 return ESP_BAD_DATA_CHECKSUM;
189 default:
190 return ESP_INVALID_COMMAND;
193 return fs.last_error;
195 #endif