3#ifdef USE_NEXTION_TFT_UPLOAD
14#include <esp_heap_caps.h>
19static const char *
const TAG =
"nextion.upload.arduino";
26 return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
27#elif defined(USE_ESP8266)
28 return EspClass::getFreeHeap();
33 uint32_t range_size = this->
tft_size_ - range_start;
36 ESP_LOGD(TAG,
"Range start: %" PRIu32, range_start);
37 if (range_size <= 0 or range_end <= range_start) {
38 ESP_LOGD(TAG,
"Range end: %" PRIu32, range_end);
39 ESP_LOGD(TAG,
"Range size: %" PRIu32, range_size);
40 ESP_LOGE(TAG,
"Invalid range");
44 char range_header[32];
45 sprintf(range_header,
"bytes=%" PRIu32
"-%" PRIu32, range_start, range_end);
46 ESP_LOGV(TAG,
"Range: %s", range_header);
47 http_client.addHeader(
"Range", range_header);
48 int code = http_client.GET();
49 if (code != HTTP_CODE_OK and code != HTTP_CODE_PARTIAL_CONTENT) {
50 ESP_LOGW(TAG,
"HTTP failed: %s", HTTPClient::errorToString(code).c_str());
56 uint8_t *buffer = allocator.
allocate(4096);
58 ESP_LOGE(TAG,
"Buffer alloc failed");
62 std::string recv_string;
65 const uint16_t buffer_size =
67 ESP_LOGV(TAG,
"Fetch %" PRIu16
" bytes", buffer_size);
68 uint16_t read_len = 0;
69 int partial_read_len = 0;
70 const uint32_t start_time =
millis();
71 while (read_len < buffer_size &&
millis() - start_time < 5000) {
72 if (http_client.getStreamPtr()->available() > 0) {
74 http_client.getStreamPtr()->readBytes(
reinterpret_cast<char *
>(buffer) + read_len, buffer_size - read_len);
75 read_len += partial_read_len;
76 if (partial_read_len > 0) {
82 if (read_len != buffer_size) {
84 ESP_LOGE(TAG,
"Read failed: %" PRIu16
"/%" PRIu16
" bytes", read_len, buffer_size);
90 ESP_LOGV(TAG,
"Fetched %d bytes", read_len);
98#if defined(USE_ESP32) && defined(USE_PSRAM)
99 ESP_LOGD(TAG,
"Upload: %0.2f%% (%" PRIu32
" left, heap: %" PRIu32
"+%" PRIu32
")", upload_percentage,
100 this->
content_length_,
static_cast<uint32_t
>(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)),
101 static_cast<uint32_t
>(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)));
103 ESP_LOGD(TAG,
"Upload: %0.2f%% (%" PRIu32
" left, heap: %" PRIu32
")", upload_percentage, this->
content_length_,
107 if (recv_string[0] == 0x08 && recv_string.size() == 5) {
108 ESP_LOGD(TAG,
"Recv: [%s]",
109 format_hex_pretty(
reinterpret_cast<const uint8_t *
>(recv_string.data()), recv_string.size()).c_str());
111 for (
int j = 0; j < 4; ++j) {
112 result +=
static_cast<uint8_t
>(recv_string[j + 1]) << (8 * j);
115 ESP_LOGI(TAG,
"New range: %" PRIu32, result);
117 range_start = result;
119 range_start = range_end + 1;
124 return range_end + 1;
125 }
else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) {
126 ESP_LOGE(TAG,
"Invalid response: [%s]",
127 format_hex_pretty(
reinterpret_cast<const uint8_t *
>(recv_string.data()), recv_string.size()).c_str());
135 }
else if (read_len == 0) {
136 ESP_LOGV(TAG,
"HTTP end");
139 ESP_LOGE(TAG,
"HTTP read failed: %d", read_len);
143 range_start = range_end + 1;
147 return range_end + 1;
151 ESP_LOGD(TAG,
"TFT upload requested");
152 ESP_LOGD(TAG,
"Exit reparse: %s", YESNO(exit_reparse));
153 ESP_LOGD(TAG,
"URL: %s", this->
tft_url_.c_str());
156 ESP_LOGW(TAG,
"Upload in progress");
161 ESP_LOGE(TAG,
"No network");
168 ESP_LOGD(TAG,
"Exit reparse mode");
170 ESP_LOGW(TAG,
"Exit reparse failed");
177 static const std::vector<uint32_t> SUPPORTED_BAUD_RATES = {2400, 4800, 9600, 19200, 31250, 38400, 57600,
178 115200, 230400, 250000, 256000, 512000, 921600};
179 if (std::find(SUPPORTED_BAUD_RATES.begin(), SUPPORTED_BAUD_RATES.end(), baud_rate) == SUPPORTED_BAUD_RATES.end()) {
182 ESP_LOGD(TAG,
"Baud rate: %" PRIu32, baud_rate);
185 ESP_LOGV(TAG,
"Init HTTP client");
187 HTTPClient http_client;
188 http_client.setTimeout(15000);
190 bool begin_status =
false;
192 begin_status = http_client.begin(this->
tft_url_.c_str());
195#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0)
196 http_client.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
197#elif USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0)
198 http_client.setFollowRedirects(
true);
200#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0)
201 http_client.setRedirectLimit(3);
207 ESP_LOGD(TAG,
"Connection failed");
210 ESP_LOGD(TAG,
"Connected");
212 http_client.addHeader(
"Range",
"bytes=0-255");
213 const char *header_names[] = {
"Content-Range"};
214 http_client.collectHeaders(header_names, 1);
215 ESP_LOGD(TAG,
"URL: %s", this->
tft_url_.c_str());
216 http_client.setReuse(
true);
219 int code = http_client.GET();
223 while (code != 200 && code != 206 && tries <= 5) {
224 ESP_LOGW(TAG,
"HTTP fail: URL: %s; Error: %s, retry %d/5", this->
tft_url_.c_str(),
225 HTTPClient::errorToString(code).c_str(), tries);
229 code = http_client.GET();
233 if (code != 200 and code != 206) {
237 String content_range_string = http_client.header(
"Content-Range");
238 content_range_string.remove(0, 12);
239 this->
tft_size_ = content_range_string.toInt();
241 ESP_LOGD(TAG,
"TFT size: %zu bytes", this->
tft_size_);
243 ESP_LOGE(TAG,
"Size check failed");
244 ESP_LOGD(TAG,
"Close HTTP");
246 ESP_LOGV(TAG,
"Connection closed");
249 ESP_LOGV(TAG,
"Size check OK");
253 ESP_LOGD(TAG,
"Uploading");
256 ESP_LOGV(TAG,
"Wake-up");
268 sprintf(command,
"whmi-wris %d,%d,1", this->
content_length_, baud_rate);
271 ESP_LOGV(TAG,
"Clear RX buffer");
276 ESP_LOGV(TAG,
"Upload cmd: %s", command);
287 std::string response;
288 ESP_LOGV(TAG,
"Wait upload resp");
292 ESP_LOGD(TAG,
"Upload resp: [%s] %zu B",
293 format_hex_pretty(
reinterpret_cast<const uint8_t *
>(response.data()), response.size()).c_str(),
297 if (response.find(0x05) != std::string::npos) {
298 ESP_LOGV(TAG,
"Upload prep done");
300 ESP_LOGE(TAG,
"Prep failed %d '%s'", response[0], response.c_str());
301 ESP_LOGD(TAG,
"Close HTTP");
303 ESP_LOGV(TAG,
"Connection closed");
307 ESP_LOGD(TAG,
"Upload TFT:");
308 ESP_LOGD(TAG,
" URL: %s", this->
tft_url_.c_str());
314 ESP_LOGV(TAG,
"Start chunk transfer");
319 if (upload_result < 0) {
320 ESP_LOGE(TAG,
"Upload error");
321 ESP_LOGD(TAG,
"Close HTTP");
323 ESP_LOGV(TAG,
"Connection closed");
330 ESP_LOGD(TAG,
"Upload complete");
332 ESP_LOGV(TAG,
"Close HTTP");
334 ESP_LOGV(TAG,
"Connection closed");
339 ESP_LOGD(TAG,
"TFT upload done: %s", YESNO(successful));
342 ESP_LOGD(TAG,
"Restart");
347 ESP_LOGE(TAG,
"TFT upload failed");
365 if (this->
tft_url_.compare(0, 6,
"https:") == 0) {
void feed_wdt(uint32_t time=0)
An STL allocator that uses SPI or internal RAM.
void deallocate(T *p, size_t n)
uint32_t get_free_heap_()
Returns the ESP Free Heap memory.
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.
WiFiClient * wifi_client_
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.
BearSSL::WiFiClientSecure * wifi_client_secure_
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag)
WiFiClient * get_wifi_client_()
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)
uint32_t IRAM_ATTR HOT millis()
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.