3#ifdef USE_NEXTION_TFT_UPLOAD
12#include <esp_heap_caps.h>
13#include <esp_http_client.h>
17static const char *
const TAG =
"nextion.upload.idf";
23 uint32_t range_size = this->
tft_size_ - range_start;
24 ESP_LOGV(TAG,
"Heap: %" PRIu32, esp_get_free_heap_size());
26 ESP_LOGD(TAG,
"Range start: %" PRIu32, range_start);
27 if (range_size <= 0 or range_end <= range_start) {
28 ESP_LOGD(TAG,
"Range end: %" PRIu32, range_end);
29 ESP_LOGD(TAG,
"Range size: %" PRIu32, range_size);
30 ESP_LOGE(TAG,
"Invalid range");
34 char range_header[32];
35 sprintf(range_header,
"bytes=%" PRIu32
"-%" PRIu32, range_start, range_end);
36 ESP_LOGV(TAG,
"Range: %s", range_header);
37 esp_http_client_set_header(http_client,
"Range", range_header);
38 ESP_LOGV(TAG,
"Open HTTP");
39 esp_err_t err = esp_http_client_open(http_client, 0);
41 ESP_LOGE(TAG,
"HTTP open failed: %s", esp_err_to_name(err));
45 ESP_LOGV(TAG,
"Fetch length");
46 const int chunk_size = esp_http_client_fetch_headers(http_client);
47 ESP_LOGV(TAG,
"Length: %d", chunk_size);
48 if (chunk_size <= 0) {
49 ESP_LOGE(TAG,
"Get length failed: %d", chunk_size);
55 uint8_t *buffer = allocator.
allocate(4096);
57 ESP_LOGE(TAG,
"Buffer alloc failed");
61 std::string recv_string;
64 const uint16_t buffer_size =
66 ESP_LOGV(TAG,
"Fetch %" PRIu16
" bytes", buffer_size);
67 uint16_t read_len = 0;
68 int partial_read_len = 0;
71 while (retries < 5 && read_len < buffer_size) {
73 esp_http_client_read(http_client,
reinterpret_cast<char *
>(buffer) + read_len, buffer_size - read_len);
74 if (partial_read_len > 0) {
75 read_len += partial_read_len;
81 vTaskDelay(pdMS_TO_TICKS(2));
85 if (read_len != buffer_size) {
87 ESP_LOGE(TAG,
"Read failed: %" PRIu16
"/%" PRIu16
" bytes", read_len, buffer_size);
93 ESP_LOGV(TAG,
"Fetched %d bytes", read_len);
102 ESP_LOGD(TAG,
"Upload: %0.2f%% (%" PRIu32
" left, heap: %" PRIu32
"+%" PRIu32
")", upload_percentage,
103 this->
content_length_,
static_cast<uint32_t
>(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)),
104 static_cast<uint32_t
>(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)));
106 ESP_LOGD(TAG,
"Upload: %0.2f%% (%" PRIu32
" left, heap: %" PRIu32
")", upload_percentage, this->
content_length_,
107 static_cast<uint32_t
>(esp_get_free_heap_size()));
110 if (recv_string[0] == 0x08 && recv_string.size() == 5) {
111 ESP_LOGD(TAG,
"Recv: [%s]",
112 format_hex_pretty(
reinterpret_cast<const uint8_t *
>(recv_string.data()), recv_string.size()).c_str());
114 for (
int j = 0; j < 4; ++j) {
115 result +=
static_cast<uint8_t
>(recv_string[j + 1]) << (8 * j);
118 ESP_LOGI(TAG,
"New range: %" PRIu32, result);
120 range_start = result;
122 range_start = range_end + 1;
127 return range_end + 1;
128 }
else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) {
129 ESP_LOGE(TAG,
"Invalid response: [%s]",
130 format_hex_pretty(
reinterpret_cast<const uint8_t *
>(recv_string.data()), recv_string.size()).c_str());
138 }
else if (read_len == 0) {
139 ESP_LOGV(TAG,
"HTTP end");
142 ESP_LOGE(TAG,
"HTTP read failed: %" PRIu16, read_len);
146 range_start = range_end + 1;
150 return range_end + 1;
154 ESP_LOGD(TAG,
"TFT upload requested");
155 ESP_LOGD(TAG,
"Exit reparse: %s", YESNO(exit_reparse));
156 ESP_LOGD(TAG,
"URL: %s", this->
tft_url_.c_str());
159 ESP_LOGW(TAG,
"Upload in progress");
164 ESP_LOGE(TAG,
"No network");
171 ESP_LOGD(TAG,
"Exit reparse mode");
173 ESP_LOGW(TAG,
"Exit reparse failed");
180 static const std::vector<uint32_t> SUPPORTED_BAUD_RATES = {2400, 4800, 9600, 19200, 31250, 38400, 57600,
181 115200, 230400, 250000, 256000, 512000, 921600};
182 if (std::find(SUPPORTED_BAUD_RATES.begin(), SUPPORTED_BAUD_RATES.end(), baud_rate) == SUPPORTED_BAUD_RATES.end()) {
185 ESP_LOGD(TAG,
"Baud rate: %" PRIu32, baud_rate);
188 ESP_LOGV(TAG,
"Init HTTP client");
189 ESP_LOGV(TAG,
"Heap: %" PRIu32, esp_get_free_heap_size());
190 esp_http_client_config_t config = {
193 .method = HTTP_METHOD_HEAD,
195 .disable_auto_redirect =
false,
196 .max_redirection_count = 10,
199 esp_http_client_handle_t http_client = esp_http_client_init(&config);
201 ESP_LOGE(TAG,
"HTTP init failed");
205 esp_err_t err = esp_http_client_set_header(http_client,
"Connection",
"keep-alive");
207 ESP_LOGE(TAG,
"Set header failed: %s", esp_err_to_name(err));
208 esp_http_client_cleanup(http_client);
213 ESP_LOGV(TAG,
"Check connection");
214 ESP_LOGV(TAG,
"Heap: %" PRIu32, esp_get_free_heap_size());
215 err = esp_http_client_perform(http_client);
217 ESP_LOGE(TAG,
"HTTP failed: %s", esp_err_to_name(err));
218 esp_http_client_cleanup(http_client);
223 ESP_LOGV(TAG,
"Check status");
224 ESP_LOGV(TAG,
"Heap: %" PRIu32, esp_get_free_heap_size());
225 int status_code = esp_http_client_get_status_code(http_client);
226 if (status_code != 200 && status_code != 206) {
230 this->
tft_size_ = esp_http_client_get_content_length(http_client);
232 ESP_LOGD(TAG,
"TFT size: %zu bytes", this->
tft_size_);
234 ESP_LOGE(TAG,
"Size check failed");
235 ESP_LOGD(TAG,
"Close HTTP");
236 esp_http_client_close(http_client);
237 esp_http_client_cleanup(http_client);
238 ESP_LOGV(TAG,
"Connection closed");
241 ESP_LOGV(TAG,
"Size check OK");
245 ESP_LOGD(TAG,
"Uploading");
248 ESP_LOGV(TAG,
"Wake-up");
252 vTaskDelay(pdMS_TO_TICKS(250));
253 ESP_LOGV(TAG,
"Heap: %" PRIu32, esp_get_free_heap_size());
260 sprintf(command,
"whmi-wris %" PRIu32
",%" PRIu32
",1", this->
content_length_, baud_rate);
263 ESP_LOGV(TAG,
"Clear RX buffer");
265 vTaskDelay(pdMS_TO_TICKS(250));
266 ESP_LOGV(TAG,
"Heap: %" PRIu32, esp_get_free_heap_size());
268 ESP_LOGV(TAG,
"Upload cmd: %s", command);
277 std::string response;
278 ESP_LOGV(TAG,
"Wait upload resp");
282 ESP_LOGD(TAG,
"Upload resp: [%s] %zu B",
283 format_hex_pretty(
reinterpret_cast<const uint8_t *
>(response.data()), response.size()).c_str(),
285 ESP_LOGV(TAG,
"Heap: %" PRIu32, esp_get_free_heap_size());
287 if (response.find(0x05) != std::string::npos) {
288 ESP_LOGV(TAG,
"Upload prep done");
290 ESP_LOGE(TAG,
"Upload prep failed %d '%s'", response[0], response.c_str());
291 ESP_LOGD(TAG,
"Close HTTP");
292 esp_http_client_close(http_client);
293 esp_http_client_cleanup(http_client);
294 ESP_LOGV(TAG,
"Connection closed");
298 ESP_LOGV(TAG,
"Set method to GET");
299 esp_err_t set_method_result = esp_http_client_set_method(http_client, HTTP_METHOD_GET);
300 if (set_method_result != ESP_OK) {
301 ESP_LOGE(TAG,
"Set GET failed: %s", esp_err_to_name(set_method_result));
305 ESP_LOGD(TAG,
"Uploading TFT:");
306 ESP_LOGD(TAG,
" URL: %s", this->
tft_url_.c_str());
308 ESP_LOGD(TAG,
" Heap: %" PRIu32, esp_get_free_heap_size());
312 ESP_LOGV(TAG,
"Start chunk transfer");
317 if (upload_result < 0) {
318 ESP_LOGE(TAG,
"TFT upload error");
319 ESP_LOGD(TAG,
"Close HTTP");
320 esp_http_client_close(http_client);
321 esp_http_client_cleanup(http_client);
322 ESP_LOGV(TAG,
"Connection closed");
326 ESP_LOGV(TAG,
"Heap: %" PRIu32
" left: %" PRIu32, esp_get_free_heap_size(), this->
content_length_);
329 ESP_LOGD(TAG,
"TFT upload complete");
331 ESP_LOGD(TAG,
"Close HTTP");
332 esp_http_client_close(http_client);
333 esp_http_client_cleanup(http_client);
334 ESP_LOGV(TAG,
"Connection closed");
339 ESP_LOGD(TAG,
"TFT upload done: %s", YESNO(successful));
342 ESP_LOGD(TAG,
"Restart");
346 ESP_LOGE(TAG,
"TFT upload failed");
void feed_wdt(uint32_t time=0)
An STL allocator that uses SPI or internal RAM.
void deallocate(T *p, size_t n)
bool send_command_(const std::string &command)
Manually send a raw command to the display and don't wait for an acknowledgement packet.
bool ignore_is_setup_
Sends commands ignoring of the Nextion has been setup.
bool upload_tft(uint32_t baud_rate=0, bool exit_reparse=true)
Uploads the TFT file to the Nextion display.
bool set_protocol_reparse_mode(bool active_mode)
Sets the Nextion display's protocol reparse mode.
bool upload_end_(bool successful)
Ends the upload process, restart Nextion and, if successful, restarts ESP.
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag)
void reset_(bool reset_nextion=true)
uint32_t original_baud_rate_
int upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start)
will request chunk_size chunks from the web server and send each to the nextion
bool upload_first_chunk_sent_
virtual void load_settings(bool dump_config)
Load the UART settings.
void set_baud_rate(uint32_t baud_rate)
uint32_t get_baud_rate() const
void write_array(const uint8_t *data, size_t len)
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Providing packet encoding functions for exchanging data with a remote host.
void IRAM_ATTR HOT delay(uint32_t ms)
Application App
Global storage of Application pointer - only one Application can exist.
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.