From 6fa70bda011419520c1484ab7f861114a827e45a Mon Sep 17 00:00:00 2001 From: Martin Ayotte Date: Sun, 6 Dec 2015 09:42:51 -0500 Subject: [PATCH 1/9] replace delay with while loop in WiFiClient.ino --- libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino b/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino index 7ffc78acd..8ed67168a 100644 --- a/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino +++ b/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino @@ -71,7 +71,13 @@ void loop() { client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); - delay(10); + while (client.available() == 0) { + if (timeout - millis() < 0) { + Serial.println(">>> Client Timeout !"); + client.stop(); + return; + } + } // Read all the lines of the reply from server and print them to Serial while(client.available()){ From e166e85f739758a258567b2f49834b05dd8dbd16 Mon Sep 17 00:00:00 2001 From: Martin Ayotte Date: Sun, 6 Dec 2015 09:47:00 -0500 Subject: [PATCH 2/9] oupps ! I forgot to set the timout value --- libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino b/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino index 8ed67168a..eb7c02eff 100644 --- a/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino +++ b/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino @@ -71,6 +71,7 @@ void loop() { client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); + int timeout = millis() + 5000; while (client.available() == 0) { if (timeout - millis() < 0) { Serial.println(">>> Client Timeout !"); From 3d1fbc60ab5c96294a6c68ea6bb9f292cb11aead Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 6 Dec 2015 20:22:54 +0300 Subject: [PATCH 3/9] Replace chain of UDP pbufs with a single pbuf before sending (#1009) Packets up to 1492 bytes may be sent this way. Also reduced pbuf_unit_size to 128 bytes. --- .../ESP8266WiFi/src/include/UdpContext.h | 58 ++++++++----------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index d9347fd34..708007036 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -1,9 +1,9 @@ -/* +/* UdpContext.h - UDP connection handling on top of lwIP Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. This file is part of the esp8266 core for Arduino environment. - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either @@ -206,10 +206,10 @@ public: size_t max_size = _rx_buf->len - _rx_buf_offset; size = (size < max_size) ? size : max_size; DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf_offset); - - os_memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, size); + + memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, size); _consume(size); - + return size; } @@ -236,7 +236,7 @@ public: { _reserve(_tx_buf_offset + size); } - + size_t left_to_copy = size; while(left_to_copy) { @@ -249,7 +249,7 @@ public: continue; } size_t will_copy = (left_to_copy < free_cur) ? left_to_copy : free_cur; - os_memcpy(reinterpret_cast(_tx_buf_cur->payload) + used_cur, data, will_copy); + memcpy(reinterpret_cast(_tx_buf_cur->payload) + used_cur, data, will_copy); _tx_buf_offset += will_copy; left_to_copy -= will_copy; data += will_copy; @@ -259,18 +259,20 @@ public: void send(ip_addr_t* addr = 0, uint16_t port = 0) { - size_t orig_size = _tx_buf_head->tot_len; - size_t data_size = _tx_buf_offset; - size_t size_adjustment = orig_size - data_size; - for (pbuf* p = _tx_buf_head; p; p = p->next) - { - p->tot_len -= size_adjustment; - if (!p->next) - { - p->len = p->tot_len; - } + pbuf* tx_copy = pbuf_alloc(PBUF_TRANSPORT, data_size, PBUF_RAM); + uint8_t* dst = reinterpret_cast(tx_copy->payload); + for (pbuf* p = _tx_buf_head; p; p = p->next) { + size_t will_copy = (data_size < p->len) ? data_size : p->len; + memcpy(dst, p->payload, will_copy); + dst += will_copy; + data_size -= will_copy; } + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + if (!addr) { addr = &_dest_addr; @@ -282,30 +284,16 @@ public: _pcb->ttl = _multicast_ttl; } - udp_sendto(_pcb, _tx_buf_head, addr, port); - + udp_sendto(_pcb, tx_copy, addr, port); _pcb->ttl = old_ttl; - - for (pbuf* p = _tx_buf_head; p; p = p->next) - { - p->tot_len += size_adjustment; - if (!p->next) - { - p->len = p->tot_len; - } - } - - pbuf_free(_tx_buf_head); - _tx_buf_head = 0; - _tx_buf_cur = 0; - _tx_buf_offset = 0; + pbuf_free(tx_copy); } private: void _reserve(size_t size) { - const size_t pbuf_unit_size = 512; + const size_t pbuf_unit_size = 128; if (!_tx_buf_head) { _tx_buf_head = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM); @@ -357,7 +345,7 @@ private: } - static void _s_recv(void *arg, + static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, ip_addr_t *addr, u16_t port) { From c6c7d2475059fff19f7127b0a4aba082c7ca7200 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 6 Dec 2015 20:39:54 +0300 Subject: [PATCH 4/9] Add __throw_logic_error (#1136) --- cores/esp8266/abi.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cores/esp8266/abi.cpp b/cores/esp8266/abi.cpp index b38f16453..ff865d9ca 100644 --- a/cores/esp8266/abi.cpp +++ b/cores/esp8266/abi.cpp @@ -68,6 +68,10 @@ void __throw_length_error(char const*) { void __throw_bad_alloc() { panic(); } + +void __throw_logic_error(const char* str) { + panic(); +} } // TODO: rebuild windows toolchain to make this unnecessary: From ee314f2cdc1890997516338491aeea4e4510ef71 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 6 Dec 2015 20:54:35 +0300 Subject: [PATCH 5/9] fix portInput(Output, Mode)Register definitions to return pointers (#1110) --- cores/esp8266/Arduino.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 7e06e0058..10c6ebd44 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -219,14 +219,12 @@ void loop(void); void yield(void); void optimistic_yield(uint32_t interval_us); -// Get the bit location within the hardware port of the given virtual pin. -// This comes from the pins_*.c file for the active board configuration. #define digitalPinToPort(pin) (0) #define digitalPinToBitMask(pin) (1UL << (pin)) #define digitalPinToTimer(pin) (0) -#define portOutputRegister(port) ((volatile uint32_t*) GPO) -#define portInputRegister(port) ((volatile uint32_t*) GPI) -#define portModeRegister(port) ((volatile uint32_t*) GPE) +#define portOutputRegister(port) ((volatile uint32_t*) &GPO) +#define portInputRegister(port) ((volatile uint32_t*) &GPI) +#define portModeRegister(port) ((volatile uint32_t*) &GPE) #define NOT_A_PIN -1 #define NOT_A_PORT -1 From cc0a8ead55ce756103ff47146cdbd499cd1a2d77 Mon Sep 17 00:00:00 2001 From: Christopher Pascoe Date: Sun, 6 Dec 2015 21:03:05 -0800 Subject: [PATCH 6/9] Always arm the "TX FIFO Empty" interrupt after we write into _tx_buffer. This avoids a race where the interrupt handler detects an empty _tx_buffer just before we write data into it. Note that commit d6f62943d4b511e7d5fe6147096c8979890416f5 works around this race when data is continually added to _tx_buffer in the hung state. We revert that change here as the race should no longer occur. Testing performed: - set UART_CONF1.txfifo_empty_thrhd=0x70 (which exacerbates the issue) - generate a ~240 byte burst of data, sent in back-to-back Serial1.write(, 4) calls, optionally followed by a Serial1.flush() Test results: - before this change, observe occasional unsent data and hang in flush() (if used). - after this change, data is sent as expected. --- cores/esp8266/HardwareSerial.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 2e93f8aee..78108bee7 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -617,18 +617,15 @@ size_t HardwareSerial::write(uint8_t c) { size_t room = uart_get_tx_fifo_room(_uart); if(room > 0 && _tx_buffer->empty()) { uart_transmit_char(_uart, c); - if(room < 10) { - uart_arm_tx_interrupt(_uart); - } return 1; } while(_tx_buffer->room() == 0) { yield(); - uart_arm_tx_interrupt(_uart); } _tx_buffer->write(c); + uart_arm_tx_interrupt(_uart); return 1; } From 7133a6c1f99b74986586c56a9a2ab7013cdc7cb9 Mon Sep 17 00:00:00 2001 From: Christopher Pascoe Date: Mon, 7 Dec 2015 00:23:46 -0800 Subject: [PATCH 7/9] Ensure that we never write an out of bounds value (_bufend) to _begin or _end, even temporarily. Testing: - Boot tested, ran basic serial I/O code Notes: - Before this change, there are instruction like "s32i.n , , <_begin>" in the disassembled output, followed by an overwrite if turns out to be _bufend. After this change, there is only one store instruction to <_begin> per function. --- cores/esp8266/cbuf.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cores/esp8266/cbuf.h b/cores/esp8266/cbuf.h index fee98a94b..ce3ac5c64 100644 --- a/cores/esp8266/cbuf.h +++ b/cores/esp8266/cbuf.h @@ -62,7 +62,7 @@ class cbuf { if(getSize() == 0) return -1; char result = *_begin; - if(++_begin == _bufend) _begin = _buf; + _begin = wrap_if_bufend(_begin + 1); return static_cast(result); } @@ -78,8 +78,7 @@ class cbuf { dst += top_size; } memcpy(dst, _begin, size_to_read); - _begin += size_to_read; - if(_begin == _bufend) _begin = _buf; + _begin = wrap_if_bufend(_begin + size_to_read); return size_read; } @@ -87,7 +86,7 @@ class cbuf { if(room() == 0) return 0; *_end = c; - if(++_end == _bufend) _end = _buf; + _end = wrap_if_bufend(_end + 1); return 1; } @@ -103,8 +102,7 @@ class cbuf { src += top_size; } memcpy(_end, src, size_to_write); - _end += size_to_write; - if(_end == _bufend) _end = _buf; + _end = wrap_if_bufend(_end + size_to_write); return size_written; } @@ -114,6 +112,10 @@ class cbuf { } private: + inline char* wrap_if_bufend(char* ptr) { + return (ptr == _bufend) ? _buf : ptr; + } + size_t _size; char* _buf; char* _bufend; From d8417c2855b685e31d1d5796c5a89e5a70d49e84 Mon Sep 17 00:00:00 2001 From: Christopher Pascoe Date: Mon, 7 Dec 2015 00:31:46 -0800 Subject: [PATCH 8/9] Remove a check in room() for (_begin == _end). It's covered by the (_end >= _begin) case. --- cores/esp8266/cbuf.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/cores/esp8266/cbuf.h b/cores/esp8266/cbuf.h index ce3ac5c64..087e7200b 100644 --- a/cores/esp8266/cbuf.h +++ b/cores/esp8266/cbuf.h @@ -42,9 +42,6 @@ class cbuf { if(_end >= _begin) { return _size - (_end - _begin) - 1; } - if(_begin == _end) { - return _size; - } return _begin - _end - 1; } From dd89de4dad042a427c7e7399d6bb2a1a1b5cc537 Mon Sep 17 00:00:00 2001 From: Jens Hauke Date: Mon, 7 Dec 2015 18:01:15 +0100 Subject: [PATCH 9/9] Make pgm_read_byte() and pgm_read_word() usable from c files. The two defines used reinterpret_cast<> which is only available when compiling with c++. Now using plain old c casts instead. --- cores/esp8266/pgmspace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/pgmspace.h b/cores/esp8266/pgmspace.h index 4ee599557..c9e83fa05 100644 --- a/cores/esp8266/pgmspace.h +++ b/cores/esp8266/pgmspace.h @@ -78,7 +78,7 @@ int vsnprintf_P(char *str, size_t strSize, PGM_P formatP, va_list ap) __attribut (__extension__({ \ PGM_P __local = (PGM_P)(addr); /* isolate varible for macro expansion */ \ ptrdiff_t __offset = ((uint32_t)__local & 0x00000003); /* byte aligned mask */ \ - const uint32_t* __addr32 = reinterpret_cast(reinterpret_cast(__local)-__offset); \ + const uint32_t* __addr32 = (const uint32_t*)((const uint8_t*)(__local)-__offset); \ uint8_t __result = ((*__addr32) >> (__offset * 8)); \ __result; \ })) @@ -87,7 +87,7 @@ int vsnprintf_P(char *str, size_t strSize, PGM_P formatP, va_list ap) __attribut (__extension__({ \ PGM_P __local = (PGM_P)(addr); /* isolate varible for macro expansion */ \ ptrdiff_t __offset = ((uint32_t)__local & 0x00000002); /* word aligned mask */ \ - const uint32_t* __addr32 = reinterpret_cast(reinterpret_cast(__local) - __offset); \ + const uint32_t* __addr32 = (const uint32_t*)((const uint8_t*)(__local) - __offset); \ uint16_t __result = ((*__addr32) >> (__offset * 8)); \ __result; \ }))