1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-21 10:26:06 +03:00

Merge branch 'master' into wifi_mesh_update_2.2

This commit is contained in:
aerlon 2019-10-29 21:55:08 +01:00 committed by GitHub
commit b0ef9195b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
192 changed files with 18054 additions and 14744 deletions

View File

@ -1,19 +1,11 @@
language: bash
os: linux
dist: trusty
dist: bionic
git:
depth: 1
submodules: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
- gcc-7
before_install:
- git submodule update --init # no recursive update
@ -87,14 +79,14 @@ jobs:
- name: "Host tests"
stage: build
script: $TRAVIS_BUILD_DIR/tests/ci/host_test.sh
install: sudo apt-get install valgrind lcov
env: CC=gcc-7 CXX=g++-7
install:
- sudo apt-get install valgrind lcov
- name: "Docs"
stage: build
script: $TRAVIS_BUILD_DIR/tests/ci/build_docs.sh
install:
- sudo apt-get install python3-pip
- sudo apt-get install python3-pip python3-setuptools
- pip3 install --user -r doc/requirements.txt;
- name: "Style check"
@ -105,7 +97,6 @@ jobs:
- name: "Mock trivial test"
stage: build
script: $TRAVIS_BUILD_DIR/tests/buildm.sh
env: CC=gcc-7 CXX=g++-7
- name: "Mac OSX can build sketches"
os: osx

View File

@ -16,7 +16,7 @@ ESP8266 Arduino core comes with libraries to communicate over WiFi using TCP and
# Contents
- Installing options:
- [Using Boards Manager](#installing-with-boards-manager)
- [Using git version](#using-git-version-basic-instructions)
- [Using git version](#using-git-version)
- [Using PlatformIO](#using-platformio)
- [Building with make](#building-with-make)
- [Documentation](#documentation)
@ -38,35 +38,13 @@ Boards manager link: `https://arduino.esp8266.com/stable/package_esp8266com_inde
Documentation: [https://arduino-esp8266.readthedocs.io/en/2.5.2/](https://arduino-esp8266.readthedocs.io/en/2.5.2/)
### Using git version (basic instructions)
### Using git version
[![Linux build status](https://travis-ci.org/esp8266/Arduino.svg)](https://travis-ci.org/esp8266/Arduino)
Also known as latest git or master branch.
- Install the current upstream Arduino IDE at the 1.8 level or later. The current version is on the [Arduino website](https://www.arduino.cc/en/main/software).
- Go to Arduino directory
- For Mac OS X, it is `Arduino.app` showing as the Arduino icon.
This location may be your `~/Downloads`, `~/Desktop` or even `/Applications`.
```bash
cd <application-directory>/Arduino.app/Contents/Java
```
- For Linux, it is ~/Arduino by default.
```bash
cd ~/Arduino
```
- Clone this repository into hardware/esp8266com/esp8266 directory (or clone it elsewhere and create a symlink)
```bash
cd hardware
mkdir esp8266com
cd esp8266com
git clone https://github.com/esp8266/Arduino.git esp8266
cd esp8266
git submodule update --init
```
- Download binary tools (you need Python 2.7)
```bash
cd esp8266/tools
python get.py
```
- Restart Arduino
- Follow the [instructions in the documentation](https://arduino-esp8266.readthedocs.io/en/latest/installing.html#using-git-version).
### Using PlatformIO

View File

@ -76,6 +76,10 @@ generic.menu.FlashFreq.40=40MHz
generic.menu.FlashFreq.40.build.flash_freq=40
generic.menu.FlashFreq.80=80MHz
generic.menu.FlashFreq.80.build.flash_freq=80
generic.menu.FlashFreq.20=20MHz
generic.menu.FlashFreq.20.build.flash_freq=20
generic.menu.FlashFreq.26=26MHz
generic.menu.FlashFreq.26.build.flash_freq=26
generic.menu.FlashMode.dout=DOUT (compatible)
generic.menu.FlashMode.dout.build.flash_mode=dout
generic.menu.FlashMode.dout.build.flash_flags=-DFLASHMODE_DOUT
@ -370,11 +374,13 @@ generic.menu.led.15=15
generic.menu.led.15.build.led=-DLED_BUILTIN=15
generic.menu.led.16=16
generic.menu.led.16.build.led=-DLED_BUILTIN=16
generic.menu.sdk.nonosdk222_100=nonos-sdk 2.2.1+100 (testing)
generic.menu.sdk.nonosdk222_100.build.sdk=NONOSDK22y
generic.menu.sdk.nonosdk222_100=nonos-sdk 2.2.1+100 (190703 approved)
generic.menu.sdk.nonosdk222_100.build.sdk=NONOSDK22x_190703
generic.menu.sdk.nonosdk222_111=nonos-sdk 2.2.1+111 (191024 testing)
generic.menu.sdk.nonosdk222_111.build.sdk=NONOSDK22x_191024
generic.menu.sdk.nonosdk221=nonos-sdk 2.2.1 (legacy)
generic.menu.sdk.nonosdk221.build.sdk=NONOSDK221
generic.menu.sdk.nonosdk3v0=nonos-sdk pre-3 (known issues)
generic.menu.sdk.nonosdk3v0=nonos-sdk pre-3 (180626 known issues)
generic.menu.sdk.nonosdk3v0.build.sdk=NONOSDK3V0
generic.menu.ip.lm2f=v2 Lower Memory
generic.menu.ip.lm2f.build.lwip_include=lwip2/include
@ -4758,6 +4764,10 @@ wifinfo.menu.FlashFreq.40=40MHz
wifinfo.menu.FlashFreq.40.build.flash_freq=40
wifinfo.menu.FlashFreq.80=80MHz
wifinfo.menu.FlashFreq.80.build.flash_freq=80
wifinfo.menu.FlashFreq.20=20MHz
wifinfo.menu.FlashFreq.20.build.flash_freq=20
wifinfo.menu.FlashFreq.26=26MHz
wifinfo.menu.FlashFreq.26.build.flash_freq=26
wifinfo.menu.eesz.1M64=1MB (FS:64KB OTA:~470KB)
wifinfo.menu.eesz.1M64.build.flash_size=1M
wifinfo.menu.eesz.1M64.build.flash_size_bytes=0x100000
@ -5778,6 +5788,10 @@ wifi_slot.menu.FlashFreq.40=40MHz
wifi_slot.menu.FlashFreq.40.build.flash_freq=40
wifi_slot.menu.FlashFreq.80=80MHz
wifi_slot.menu.FlashFreq.80.build.flash_freq=80
wifi_slot.menu.FlashFreq.20=20MHz
wifi_slot.menu.FlashFreq.20.build.flash_freq=20
wifi_slot.menu.FlashFreq.26=26MHz
wifi_slot.menu.FlashFreq.26.build.flash_freq=26
wifi_slot.menu.FlashMode.dout=DOUT (compatible)
wifi_slot.menu.FlashMode.dout.build.flash_mode=dout
wifi_slot.menu.FlashMode.dout.build.flash_flags=-DFLASHMODE_DOUT

View File

@ -275,17 +275,16 @@ long secureRandom(long);
long secureRandom(long, long);
long map(long, long, long, long, long);
extern "C" void configTime(long timezone, int daylightOffset_sec,
const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
void configTime(int timezone, int daylightOffset_sec, const char* server1,
const char* server2 = nullptr, const char* server3 = nullptr);
#endif
void configTime(const char* tz, const char* server1,
const char* server2 = nullptr, const char* server3 = nullptr);
#endif // __cplusplus
#include "pins_arduino.h"
#ifndef PUYA_SUPPORT
#define PUYA_SUPPORT 1
#endif
#endif
#ifdef DEBUG_ESP_OOM

View File

@ -18,7 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Arduino.h"
#include "Esp.h"
#include "flash_utils.h"
#include "eboot_command.h"
#include <memory>
@ -36,6 +36,14 @@ extern struct rst_info resetInfo;
//#define DEBUG_SERIAL Serial
#ifndef PUYA_SUPPORT
#define PUYA_SUPPORT 1
#endif
#ifndef PUYA_BUFFER_SIZE
// Good alternative for buffer size is: SPI_FLASH_SEC_SIZE (= 4k)
// Always use a multiple of flash page size (256 bytes)
#define PUYA_BUFFER_SIZE 256
#endif
/**
* User-defined Literals
@ -494,7 +502,7 @@ uint32_t EspClass::getSketchSize() {
image_header_t image_header;
uint32_t pos = APP_START_OFFSET;
if (spi_flash_read(pos, (uint32_t*) &image_header, sizeof(image_header))) {
if (spi_flash_read(pos, (uint32_t*) &image_header, sizeof(image_header)) != SPI_FLASH_RESULT_OK) {
return 0;
}
pos += sizeof(image_header);
@ -506,7 +514,7 @@ uint32_t EspClass::getSketchSize() {
++section_index)
{
section_header_t section_header = {0, 0};
if (spi_flash_read(pos, (uint32_t*) &section_header, sizeof(section_header))) {
if (spi_flash_read(pos, (uint32_t*) &section_header, sizeof(section_header)) != SPI_FLASH_RESULT_OK) {
return 0;
}
pos += sizeof(section_header);
@ -577,26 +585,27 @@ bool EspClass::flashEraseSector(uint32_t sector) {
}
#if PUYA_SUPPORT
static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) {
static SpiFlashOpResult spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) {
if (data == nullptr) {
return 1; // SPI_FLASH_RESULT_ERR
return SPI_FLASH_RESULT_ERR;
}
// PUYA flash chips need to read existing data, update in memory and write modified data again.
static uint32_t *flash_write_puya_buf = nullptr;
int rc = 0;
uint32_t* ptr = data;
if (flash_write_puya_buf == nullptr) {
flash_write_puya_buf = (uint32_t*) malloc(PUYA_BUFFER_SIZE);
// No need to ever free this, since the flash chip will never change at runtime.
if (flash_write_puya_buf == nullptr) {
// Memory could not be allocated.
return 1; // SPI_FLASH_RESULT_ERR
return SPI_FLASH_RESULT_ERR;
}
}
SpiFlashOpResult rc = SPI_FLASH_RESULT_OK;
uint32_t* ptr = data;
size_t bytesLeft = size;
uint32_t pos = offset;
while (bytesLeft > 0 && rc == 0) {
while (bytesLeft > 0 && rc == SPI_FLASH_RESULT_OK) {
size_t bytesNow = bytesLeft;
if (bytesNow > PUYA_BUFFER_SIZE) {
bytesNow = PUYA_BUFFER_SIZE;
@ -605,7 +614,7 @@ static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) {
bytesLeft = 0;
}
rc = spi_flash_read(pos, flash_write_puya_buf, bytesNow);
if (rc != 0) {
if (rc != SPI_FLASH_RESULT_OK) {
return rc;
}
for (size_t i = 0; i < bytesNow / 4; ++i) {
@ -620,7 +629,7 @@ static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) {
#endif
bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
int rc = 0;
SpiFlashOpResult rc = SPI_FLASH_RESULT_OK;
#if PUYA_SUPPORT
if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA) {
rc = spi_flash_write_puya(offset, data, size);
@ -630,12 +639,12 @@ bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
{
rc = spi_flash_write(offset, data, size);
}
return rc == 0;
return rc == SPI_FLASH_RESULT_OK;
}
bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size) {
int rc = spi_flash_read(offset, (uint32_t*) data, size);
return rc == 0;
auto rc = spi_flash_read(offset, (uint32_t*) data, size);
return rc == SPI_FLASH_RESULT_OK;
}
String EspClass::getSketchMD5()

View File

@ -23,15 +23,6 @@
#include <Arduino.h>
#ifndef PUYA_SUPPORT
#define PUYA_SUPPORT 0
#endif
#ifndef PUYA_BUFFER_SIZE
// Good alternative for buffer size is: SPI_FLASH_SEC_SIZE (= 4k)
// Always use a multiple of flash page size (256 bytes)
#define PUYA_BUFFER_SIZE 256
#endif
// Vendor IDs taken from Flashrom project
// https://review.coreboot.org/cgit/flashrom.git/tree/flashchips.h?h=1.0.x
typedef enum {

View File

@ -1,166 +1,168 @@
/*
HardwareSerial.cpp - esp8266 UART support
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266)
Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266)
Modified 3 May 2015 by Hristo Gochkov (change register access methods)
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <PolledTimeout.h>
#include "Arduino.h"
#include "HardwareSerial.h"
#include "Esp.h"
HardwareSerial::HardwareSerial(int uart_nr)
: _uart_nr(uart_nr), _rx_size(256)
{}
void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
{
end();
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size);
#if defined(DEBUG_ESP_PORT) && !defined(NDEBUG)
if (static_cast<void*>(this) == static_cast<void*>(&DEBUG_ESP_PORT))
{
setDebugOutput(true);
println();
println(ESP.getFullVersion());
}
#endif
}
void HardwareSerial::end()
{
if(uart_get_debug() == _uart_nr) {
uart_set_debug(UART_NO);
}
uart_uninit(_uart);
_uart = NULL;
}
void HardwareSerial::updateBaudRate(unsigned long baud)
{
if(!_uart) {
return;
}
uart_set_baudrate(_uart, baud);
}
size_t HardwareSerial::setRxBufferSize(size_t size){
if(_uart) {
_rx_size = uart_resize_rx_buffer(_uart, size);
} else {
_rx_size = size;
}
return _rx_size;
}
void HardwareSerial::setDebugOutput(bool en)
{
if(!_uart) {
return;
}
if(en) {
if(uart_tx_enabled(_uart)) {
uart_set_debug(_uart_nr);
} else {
uart_set_debug(UART_NO);
}
} else {
// disable debug for this interface
if(uart_get_debug() == _uart_nr) {
uart_set_debug(UART_NO);
}
}
}
int HardwareSerial::available(void)
{
int result = static_cast<int>(uart_rx_available(_uart));
if (!result) {
optimistic_yield(10000);
}
return result;
}
void HardwareSerial::flush()
{
if(!_uart || !uart_tx_enabled(_uart)) {
return;
}
uart_wait_tx_empty(_uart);
//Workaround for a bug in serial not actually being finished yet
//Wait for 8 data bits, 1 parity and 2 stop bits, just in case
delayMicroseconds(11000000 / uart_get_baudrate(_uart) + 1);
}
void HardwareSerial::startDetectBaudrate()
{
uart_start_detect_baudrate(_uart_nr);
}
unsigned long HardwareSerial::testBaudrate()
{
return uart_detect_baudrate(_uart_nr);
}
unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
{
esp8266::polledTimeout::oneShotFastMs timeOut(timeoutMillis);
unsigned long detectedBaudrate;
while (!timeOut) {
if ((detectedBaudrate = testBaudrate())) {
break;
}
yield();
delay(100);
}
return detectedBaudrate;
}
size_t HardwareSerial::readBytes(char* buffer, size_t size)
{
size_t got = 0;
while (got < size)
{
esp8266::polledTimeout::oneShotFastMs timeOut(_timeout);
size_t avail;
while ((avail = available()) == 0 && !timeOut);
if (avail == 0)
break;
got += read(buffer + got, std::min(size - got, avail));
}
return got;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
HardwareSerial Serial(UART0);
#endif
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL1)
HardwareSerial Serial1(UART1);
#endif
/*
HardwareSerial.cpp - esp8266 UART support
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266)
Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266)
Modified 3 May 2015 by Hristo Gochkov (change register access methods)
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <PolledTimeout.h>
#include "Arduino.h"
#include "HardwareSerial.h"
#include "Esp.h"
HardwareSerial::HardwareSerial(int uart_nr)
: _uart_nr(uart_nr), _rx_size(256)
{}
void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
{
end();
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size);
#if defined(DEBUG_ESP_PORT) && !defined(NDEBUG)
if (static_cast<void*>(this) == static_cast<void*>(&DEBUG_ESP_PORT))
{
setDebugOutput(true);
println();
println(ESP.getFullVersion());
}
#endif
}
void HardwareSerial::end()
{
if(uart_get_debug() == _uart_nr) {
uart_set_debug(UART_NO);
}
uart_uninit(_uart);
_uart = NULL;
}
void HardwareSerial::updateBaudRate(unsigned long baud)
{
if(!_uart) {
return;
}
uart_set_baudrate(_uart, baud);
}
size_t HardwareSerial::setRxBufferSize(size_t size){
if(_uart) {
_rx_size = uart_resize_rx_buffer(_uart, size);
} else {
_rx_size = size;
}
return _rx_size;
}
void HardwareSerial::setDebugOutput(bool en)
{
if(!_uart) {
return;
}
if(en) {
if(uart_tx_enabled(_uart)) {
uart_set_debug(_uart_nr);
} else {
uart_set_debug(UART_NO);
}
} else {
// disable debug for this interface
if(uart_get_debug() == _uart_nr) {
uart_set_debug(UART_NO);
}
}
}
int HardwareSerial::available(void)
{
int result = static_cast<int>(uart_rx_available(_uart));
if (!result) {
optimistic_yield(10000);
}
return result;
}
void HardwareSerial::flush()
{
uint8_t bit_length = 0;
if(!_uart || !uart_tx_enabled(_uart)) {
return;
}
bit_length = uart_get_bit_length(_uart_nr); // data width, parity and stop
uart_wait_tx_empty(_uart);
//Workaround for a bug in serial not actually being finished yet
//Wait for 8 data bits, 1 parity and 2 stop bits, just in case
delayMicroseconds(bit_length * 1000000 / uart_get_baudrate(_uart) + 1);
}
void HardwareSerial::startDetectBaudrate()
{
uart_start_detect_baudrate(_uart_nr);
}
unsigned long HardwareSerial::testBaudrate()
{
return uart_detect_baudrate(_uart_nr);
}
unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
{
esp8266::polledTimeout::oneShotFastMs timeOut(timeoutMillis);
unsigned long detectedBaudrate;
while (!timeOut) {
if ((detectedBaudrate = testBaudrate())) {
break;
}
yield();
delay(100);
}
return detectedBaudrate;
}
size_t HardwareSerial::readBytes(char* buffer, size_t size)
{
size_t got = 0;
while (got < size)
{
esp8266::polledTimeout::oneShotFastMs timeOut(_timeout);
size_t avail;
while ((avail = available()) == 0 && !timeOut);
if (avail == 0)
break;
got += read(buffer + got, std::min(size - got, avail));
}
return got;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
HardwareSerial Serial(UART0);
#endif
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL1)
HardwareSerial Serial1(UART1);
#endif

View File

@ -24,16 +24,18 @@ struct recurrent_fn_t
recurrent_fn_t* mNext = nullptr;
mRecFuncT mFunc;
esp8266::polledTimeout::periodicFastUs callNow;
recurrent_fn_t (esp8266::polledTimeout::periodicFastUs interval): callNow(interval) { }
std::function<bool(void)> alarm = nullptr;
recurrent_fn_t(esp8266::polledTimeout::periodicFastUs interval) : callNow(interval) { }
};
static recurrent_fn_t* rFirst = nullptr; // fifo not needed
static recurrent_fn_t* rFirst = nullptr;
static recurrent_fn_t* rLast = nullptr;
// Returns a pointer to an unused sched_fn_t,
// or if none are available allocates a new one,
// or nullptr if limit is reached
IRAM_ATTR // called from ISR
static scheduled_fn_t* get_fn_unsafe ()
static scheduled_fn_t* get_fn_unsafe()
{
scheduled_fn_t* result = nullptr;
// try to get an item from unused items list
@ -52,7 +54,7 @@ static scheduled_fn_t* get_fn_unsafe ()
return result;
}
static void recycle_fn_unsafe (scheduled_fn_t* fn)
static void recycle_fn_unsafe(scheduled_fn_t* fn)
{
fn->mFunc = nullptr; // special overload in c++ std lib
fn->mNext = sUnused;
@ -60,8 +62,11 @@ static void recycle_fn_unsafe (scheduled_fn_t* fn)
}
IRAM_ATTR // (not only) called from ISR
bool schedule_function (const std::function<void(void)>& fn)
bool schedule_function(const std::function<void(void)>& fn)
{
if (!fn)
return false;
esp8266::InterruptLock lockAllInterruptsInThisScope;
scheduled_fn_t* item = get_fn_unsafe();
@ -80,27 +85,37 @@ bool schedule_function (const std::function<void(void)>& fn)
return true;
}
bool schedule_recurrent_function_us (const std::function<bool(void)>& fn, uint32_t repeat_us)
bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
uint32_t repeat_us, const std::function<bool(void)>& alarm)
{
assert(repeat_us < decltype(recurrent_fn_t::callNow)::neverExpires); //~26800000us (26.8s)
esp8266::InterruptLock lockAllInterruptsInThisScope;
if (!fn)
return false;
recurrent_fn_t* item = new (std::nothrow) recurrent_fn_t(repeat_us);
if (!item)
return false;
item->mFunc = fn;
item->alarm = alarm;
if (rFirst)
item->mNext = rFirst;
esp8266::InterruptLock lockAllInterruptsInThisScope;
rFirst = item;
if (rLast)
{
rLast->mNext = item;
}
else
{
rFirst = item;
}
rLast = item;
return true;
}
void run_scheduled_functions ()
void run_scheduled_functions()
{
esp8266::polledTimeout::periodicFastMs yieldNow(100); // yield every 100ms
@ -128,15 +143,18 @@ void run_scheduled_functions ()
}
}
void run_scheduled_recurrent_functions ()
void run_scheduled_recurrent_functions()
{
esp8266::polledTimeout::periodicFastMs yieldNow(100); // yield every 100ms
// Note to the reader:
// There is no exposed API to remove a scheduled function:
// Scheduled functions are removed only from this function, and
// its purpose is that it is never called from an interrupt
// (always on cont stack).
if (!rFirst)
auto current = rFirst;
if (!current)
return;
static bool fence = false;
@ -153,26 +171,35 @@ void run_scheduled_recurrent_functions ()
}
recurrent_fn_t* prev = nullptr;
recurrent_fn_t* current = rFirst;
// prevent scheduling of new functions during this run
auto stop = rLast;
while (current)
bool done;
do
{
if (current->callNow && !current->mFunc())
done = current == stop;
const bool wakeup = current->alarm && current->alarm();
bool callNow = current->callNow;
if ((wakeup || callNow) && !current->mFunc())
{
// remove function from stack
esp8266::InterruptLock lockAllInterruptsInThisScope;
auto to_ditch = current;
// removing rLast
if (rLast == current)
rLast = prev;
current = current->mNext;
if (prev)
{
current = current->mNext;
prev->mNext = current;
}
else
{
rFirst = rFirst->mNext;
current = rFirst;
rFirst = current;
}
delete(to_ditch);
@ -182,7 +209,15 @@ void run_scheduled_recurrent_functions ()
prev = current;
current = current->mNext;
}
}
if (yieldNow)
{
// because scheduled functions might last too long for watchdog etc,
// this is yield() in cont stack:
esp_schedule();
cont_yield(g_pcont);
}
} while (current && !done);
fence = false;
}

View File

@ -10,7 +10,7 @@
// in user stack (called CONT stack) without the common restrictions from
// system context. Details are below.
// The purpose of recurrent scheduled function is to independantly execute
// The purpose of recurrent scheduled function is to independently execute
// user code in CONT stack on a regular basis.
// It has been introduced with ethernet service in mind, it can also be used
// for all libraries in the need of a regular `libdaemon_handlestuff()`.
@ -58,14 +58,14 @@ void run_scheduled_functions();
// functions. However a user function returning false will cancel itself.
// * Long running operations or yield() or delay() are not allowed in the
// recurrent function.
// * A recurrent function currently must not schedule another recurrent
// functions.
bool schedule_recurrent_function_us (const std::function<bool(void)>& fn, uint32_t repeat_us);
// * If alarm is used, anytime during scheduling when it returns true,
// any remaining delay from repeat_us is disregarded, and fn is executed.
bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
uint32_t repeat_us, const std::function<bool(void)>& alarm = nullptr);
// Test recurrence and run recurrent scheduled functions.
// (internally called at every `yield()` and `loop()`)
void run_scheduled_recurrent_functions ();
void run_scheduled_recurrent_functions();
#endif // ESP_SCHEDULE_H

View File

@ -1,39 +1,39 @@
/**
StreamString.h
Copyright (c) 2015 Markus Sattler. 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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef STREAMSTRING_H_
#define STREAMSTRING_H_
class StreamString: public Stream, public String {
public:
size_t write(const uint8_t *buffer, size_t size) override;
size_t write(uint8_t data) override;
int available() override;
int read() override;
int peek() override;
void flush() override;
};
#endif /* STREAMSTRING_H_ */
/**
StreamString.h
Copyright (c) 2015 Markus Sattler. 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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef STREAMSTRING_H_
#define STREAMSTRING_H_
class StreamString: public Stream, public String {
public:
size_t write(const uint8_t *buffer, size_t size) override;
size_t write(uint8_t data) override;
int available() override;
int read() override;
int peek() override;
void flush() override;
};
#endif /* STREAMSTRING_H_ */

475
cores/esp8266/TZ.h Normal file
View File

@ -0,0 +1,475 @@
// autogenerated from https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
// by script <esp8266 arduino core>/tools/TZupdate.sh
// Mon Sep 9 20:58:30 UTC 2019
//
// This database is autogenerated from IANA timezone database
// https://www.iana.org/time-zones
// and can be updated on demand in this repository
// or by yourself using the above script
#ifndef TZDB_H
#define TZDB_H
#define TZ_Africa_Abidjan PSTR("GMT0")
#define TZ_Africa_Accra PSTR("GMT0")
#define TZ_Africa_Addis_Ababa PSTR("EAT-3")
#define TZ_Africa_Algiers PSTR("CET-1")
#define TZ_Africa_Asmara PSTR("EAT-3")
#define TZ_Africa_Bamako PSTR("GMT0")
#define TZ_Africa_Bangui PSTR("WAT-1")
#define TZ_Africa_Banjul PSTR("GMT0")
#define TZ_Africa_Bissau PSTR("GMT0")
#define TZ_Africa_Blantyre PSTR("CAT-2")
#define TZ_Africa_Brazzaville PSTR("WAT-1")
#define TZ_Africa_Bujumbura PSTR("CAT-2")
#define TZ_Africa_Cairo PSTR("EET-2")
#define TZ_Africa_Casablanca PSTR("<+01>-1")
#define TZ_Africa_Ceuta PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Africa_Conakry PSTR("GMT0")
#define TZ_Africa_Dakar PSTR("GMT0")
#define TZ_Africa_Dar_es_Salaam PSTR("EAT-3")
#define TZ_Africa_Djibouti PSTR("EAT-3")
#define TZ_Africa_Douala PSTR("WAT-1")
#define TZ_Africa_El_Aaiun PSTR("<+01>-1")
#define TZ_Africa_Freetown PSTR("GMT0")
#define TZ_Africa_Gaborone PSTR("CAT-2")
#define TZ_Africa_Harare PSTR("CAT-2")
#define TZ_Africa_Johannesburg PSTR("SAST-2")
#define TZ_Africa_Juba PSTR("EAT-3")
#define TZ_Africa_Kampala PSTR("EAT-3")
#define TZ_Africa_Khartoum PSTR("CAT-2")
#define TZ_Africa_Kigali PSTR("CAT-2")
#define TZ_Africa_Kinshasa PSTR("WAT-1")
#define TZ_Africa_Lagos PSTR("WAT-1")
#define TZ_Africa_Libreville PSTR("WAT-1")
#define TZ_Africa_Lome PSTR("GMT0")
#define TZ_Africa_Luanda PSTR("WAT-1")
#define TZ_Africa_Lubumbashi PSTR("CAT-2")
#define TZ_Africa_Lusaka PSTR("CAT-2")
#define TZ_Africa_Malabo PSTR("WAT-1")
#define TZ_Africa_Maputo PSTR("CAT-2")
#define TZ_Africa_Maseru PSTR("SAST-2")
#define TZ_Africa_Mbabane PSTR("SAST-2")
#define TZ_Africa_Mogadishu PSTR("EAT-3")
#define TZ_Africa_Monrovia PSTR("GMT0")
#define TZ_Africa_Nairobi PSTR("EAT-3")
#define TZ_Africa_Ndjamena PSTR("WAT-1")
#define TZ_Africa_Niamey PSTR("WAT-1")
#define TZ_Africa_Nouakchott PSTR("GMT0")
#define TZ_Africa_Ouagadougou PSTR("GMT0")
#define TZ_Africa_PortomNovo PSTR("WAT-1")
#define TZ_Africa_Sao_Tome PSTR("GMT0")
#define TZ_Africa_Tripoli PSTR("EET-2")
#define TZ_Africa_Tunis PSTR("CET-1")
#define TZ_Africa_Windhoek PSTR("CAT-2")
#define TZ_America_Adak PSTR("HST10HDT,M3.2.0,M11.1.0")
#define TZ_America_Anchorage PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Anguilla PSTR("AST4")
#define TZ_America_Antigua PSTR("AST4")
#define TZ_America_Araguaina PSTR("<-03>3")
#define TZ_America_Argentina_Buenos_Aires PSTR("<-03>3")
#define TZ_America_Argentina_Catamarca PSTR("<-03>3")
#define TZ_America_Argentina_Cordoba PSTR("<-03>3")
#define TZ_America_Argentina_Jujuy PSTR("<-03>3")
#define TZ_America_Argentina_La_Rioja PSTR("<-03>3")
#define TZ_America_Argentina_Mendoza PSTR("<-03>3")
#define TZ_America_Argentina_Rio_Gallegos PSTR("<-03>3")
#define TZ_America_Argentina_Salta PSTR("<-03>3")
#define TZ_America_Argentina_San_Juan PSTR("<-03>3")
#define TZ_America_Argentina_San_Luis PSTR("<-03>3")
#define TZ_America_Argentina_Tucuman PSTR("<-03>3")
#define TZ_America_Argentina_Ushuaia PSTR("<-03>3")
#define TZ_America_Aruba PSTR("AST4")
#define TZ_America_Asuncion PSTR("<-04>4<-03>,M10.1.0/0,M3.4.0/0")
#define TZ_America_Atikokan PSTR("EST5")
#define TZ_America_Bahia PSTR("<-03>3")
#define TZ_America_Bahia_Banderas PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Barbados PSTR("AST4")
#define TZ_America_Belem PSTR("<-03>3")
#define TZ_America_Belize PSTR("CST6")
#define TZ_America_BlancmSablon PSTR("AST4")
#define TZ_America_Boa_Vista PSTR("<-04>4")
#define TZ_America_Bogota PSTR("<-05>5")
#define TZ_America_Boise PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Cambridge_Bay PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Campo_Grande PSTR("<-04>4")
#define TZ_America_Cancun PSTR("EST5")
#define TZ_America_Caracas PSTR("<-04>4")
#define TZ_America_Cayenne PSTR("<-03>3")
#define TZ_America_Cayman PSTR("EST5")
#define TZ_America_Chicago PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Chihuahua PSTR("MST7MDT,M4.1.0,M10.5.0")
#define TZ_America_Costa_Rica PSTR("CST6")
#define TZ_America_Creston PSTR("MST7")
#define TZ_America_Cuiaba PSTR("<-04>4")
#define TZ_America_Curacao PSTR("AST4")
#define TZ_America_Danmarkshavn PSTR("GMT0")
#define TZ_America_Dawson PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Dawson_Creek PSTR("MST7")
#define TZ_America_Denver PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Detroit PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Dominica PSTR("AST4")
#define TZ_America_Edmonton PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Eirunepe PSTR("<-05>5")
#define TZ_America_El_Salvador PSTR("CST6")
#define TZ_America_Fortaleza PSTR("<-03>3")
#define TZ_America_Fort_Nelson PSTR("MST7")
#define TZ_America_Glace_Bay PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Godthab PSTR("<-03>3<-02>,M3.5.0/-2,M10.5.0/-1")
#define TZ_America_Goose_Bay PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Grand_Turk PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Grenada PSTR("AST4")
#define TZ_America_Guadeloupe PSTR("AST4")
#define TZ_America_Guatemala PSTR("CST6")
#define TZ_America_Guayaquil PSTR("<-05>5")
#define TZ_America_Guyana PSTR("<-04>4")
#define TZ_America_Halifax PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Havana PSTR("CST5CDT,M3.2.0/0,M11.1.0/1")
#define TZ_America_Hermosillo PSTR("MST7")
#define TZ_America_Indiana_Indianapolis PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Knox PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Marengo PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Petersburg PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Tell_City PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Vevay PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Vincennes PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Winamac PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Inuvik PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Iqaluit PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Jamaica PSTR("EST5")
#define TZ_America_Juneau PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Kentucky_Louisville PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Kentucky_Monticello PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Kralendijk PSTR("AST4")
#define TZ_America_La_Paz PSTR("<-04>4")
#define TZ_America_Lima PSTR("<-05>5")
#define TZ_America_Los_Angeles PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Lower_Princes PSTR("AST4")
#define TZ_America_Maceio PSTR("<-03>3")
#define TZ_America_Managua PSTR("CST6")
#define TZ_America_Manaus PSTR("<-04>4")
#define TZ_America_Marigot PSTR("AST4")
#define TZ_America_Martinique PSTR("AST4")
#define TZ_America_Matamoros PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Mazatlan PSTR("MST7MDT,M4.1.0,M10.5.0")
#define TZ_America_Menominee PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Merida PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Metlakatla PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Mexico_City PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Miquelon PSTR("<-03>3<-02>,M3.2.0,M11.1.0")
#define TZ_America_Moncton PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Monterrey PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Montevideo PSTR("<-03>3")
#define TZ_America_Montreal PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Montserrat PSTR("AST4")
#define TZ_America_Nassau PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_New_York PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Nipigon PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Nome PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Noronha PSTR("<-02>2")
#define TZ_America_North_Dakota_Beulah PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_North_Dakota_Center PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_North_Dakota_New_Salem PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Ojinaga PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Panama PSTR("EST5")
#define TZ_America_Pangnirtung PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Paramaribo PSTR("<-03>3")
#define TZ_America_Phoenix PSTR("MST7")
#define TZ_America_PortmaumPrince PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Port_of_Spain PSTR("AST4")
#define TZ_America_Porto_Velho PSTR("<-04>4")
#define TZ_America_Puerto_Rico PSTR("AST4")
#define TZ_America_Punta_Arenas PSTR("<-03>3")
#define TZ_America_Rainy_River PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Rankin_Inlet PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Recife PSTR("<-03>3")
#define TZ_America_Regina PSTR("CST6")
#define TZ_America_Resolute PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Rio_Branco PSTR("<-05>5")
#define TZ_America_Santarem PSTR("<-03>3")
#define TZ_America_Santiago PSTR("<-04>4<-03>,M9.1.6/24,M4.1.6/24")
#define TZ_America_Santo_Domingo PSTR("AST4")
#define TZ_America_Sao_Paulo PSTR("<-03>3")
#define TZ_America_Scoresbysund PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
#define TZ_America_Sitka PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_St_Barthelemy PSTR("AST4")
#define TZ_America_St_Johns PSTR("NST3:30NDT,M3.2.0,M11.1.0")
#define TZ_America_St_Kitts PSTR("AST4")
#define TZ_America_St_Lucia PSTR("AST4")
#define TZ_America_St_Thomas PSTR("AST4")
#define TZ_America_St_Vincent PSTR("AST4")
#define TZ_America_Swift_Current PSTR("CST6")
#define TZ_America_Tegucigalpa PSTR("CST6")
#define TZ_America_Thule PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Thunder_Bay PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Tijuana PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Toronto PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Tortola PSTR("AST4")
#define TZ_America_Vancouver PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Whitehorse PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Winnipeg PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Yakutat PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Yellowknife PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_Antarctica_Casey PSTR("<+08>-8")
#define TZ_Antarctica_Davis PSTR("<+07>-7")
#define TZ_Antarctica_DumontDUrville PSTR("<+10>-10")
#define TZ_Antarctica_Macquarie PSTR("<+11>-11")
#define TZ_Antarctica_Mawson PSTR("<+05>-5")
#define TZ_Antarctica_McMurdo PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3")
#define TZ_Antarctica_Palmer PSTR("<-03>3")
#define TZ_Antarctica_Rothera PSTR("<-03>3")
#define TZ_Antarctica_Syowa PSTR("<+03>-3")
#define TZ_Antarctica_Troll PSTR("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3")
#define TZ_Antarctica_Vostok PSTR("<+06>-6")
#define TZ_Arctic_Longyearbyen PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Asia_Aden PSTR("<+03>-3")
#define TZ_Asia_Almaty PSTR("<+06>-6")
#define TZ_Asia_Amman PSTR("EET-2EEST,M3.5.4/24,M10.5.5/1")
#define TZ_Asia_Anadyr PSTR("<+12>-12")
#define TZ_Asia_Aqtau PSTR("<+05>-5")
#define TZ_Asia_Aqtobe PSTR("<+05>-5")
#define TZ_Asia_Ashgabat PSTR("<+05>-5")
#define TZ_Asia_Atyrau PSTR("<+05>-5")
#define TZ_Asia_Baghdad PSTR("<+03>-3")
#define TZ_Asia_Bahrain PSTR("<+03>-3")
#define TZ_Asia_Baku PSTR("<+04>-4")
#define TZ_Asia_Bangkok PSTR("<+07>-7")
#define TZ_Asia_Barnaul PSTR("<+07>-7")
#define TZ_Asia_Beirut PSTR("EET-2EEST,M3.5.0/0,M10.5.0/0")
#define TZ_Asia_Bishkek PSTR("<+06>-6")
#define TZ_Asia_Brunei PSTR("<+08>-8")
#define TZ_Asia_Chita PSTR("<+09>-9")
#define TZ_Asia_Choibalsan PSTR("<+08>-8")
#define TZ_Asia_Colombo PSTR("<+0530>-5:30")
#define TZ_Asia_Damascus PSTR("EET-2EEST,M3.5.5/0,M10.5.5/0")
#define TZ_Asia_Dhaka PSTR("<+06>-6")
#define TZ_Asia_Dili PSTR("<+09>-9")
#define TZ_Asia_Dubai PSTR("<+04>-4")
#define TZ_Asia_Dushanbe PSTR("<+05>-5")
#define TZ_Asia_Famagusta PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Asia_Gaza PSTR("EET-2EEST,M3.5.5/0,M10.5.6/1")
#define TZ_Asia_Hebron PSTR("EET-2EEST,M3.5.5/0,M10.5.6/1")
#define TZ_Asia_Ho_Chi_Minh PSTR("<+07>-7")
#define TZ_Asia_Hong_Kong PSTR("HKT-8")
#define TZ_Asia_Hovd PSTR("<+07>-7")
#define TZ_Asia_Irkutsk PSTR("<+08>-8")
#define TZ_Asia_Jakarta PSTR("WIB-7")
#define TZ_Asia_Jayapura PSTR("WIT-9")
#define TZ_Asia_Jerusalem PSTR("IST-2IDT,M3.4.4/26,M10.5.0")
#define TZ_Asia_Kabul PSTR("<+0430>-4:30")
#define TZ_Asia_Kamchatka PSTR("<+12>-12")
#define TZ_Asia_Karachi PSTR("PKT-5")
#define TZ_Asia_Kathmandu PSTR("<+0545>-5:45")
#define TZ_Asia_Khandyga PSTR("<+09>-9")
#define TZ_Asia_Kolkata PSTR("IST-5:30")
#define TZ_Asia_Krasnoyarsk PSTR("<+07>-7")
#define TZ_Asia_Kuala_Lumpur PSTR("<+08>-8")
#define TZ_Asia_Kuching PSTR("<+08>-8")
#define TZ_Asia_Kuwait PSTR("<+03>-3")
#define TZ_Asia_Macau PSTR("CST-8")
#define TZ_Asia_Magadan PSTR("<+11>-11")
#define TZ_Asia_Makassar PSTR("WITA-8")
#define TZ_Asia_Manila PSTR("PST-8")
#define TZ_Asia_Muscat PSTR("<+04>-4")
#define TZ_Asia_Nicosia PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Asia_Novokuznetsk PSTR("<+07>-7")
#define TZ_Asia_Novosibirsk PSTR("<+07>-7")
#define TZ_Asia_Omsk PSTR("<+06>-6")
#define TZ_Asia_Oral PSTR("<+05>-5")
#define TZ_Asia_Phnom_Penh PSTR("<+07>-7")
#define TZ_Asia_Pontianak PSTR("WIB-7")
#define TZ_Asia_Pyongyang PSTR("KST-9")
#define TZ_Asia_Qatar PSTR("<+03>-3")
#define TZ_Asia_Qyzylorda PSTR("<+05>-5")
#define TZ_Asia_Riyadh PSTR("<+03>-3")
#define TZ_Asia_Sakhalin PSTR("<+11>-11")
#define TZ_Asia_Samarkand PSTR("<+05>-5")
#define TZ_Asia_Seoul PSTR("KST-9")
#define TZ_Asia_Shanghai PSTR("CST-8")
#define TZ_Asia_Singapore PSTR("<+08>-8")
#define TZ_Asia_Srednekolymsk PSTR("<+11>-11")
#define TZ_Asia_Taipei PSTR("CST-8")
#define TZ_Asia_Tashkent PSTR("<+05>-5")
#define TZ_Asia_Tbilisi PSTR("<+04>-4")
#define TZ_Asia_Tehran PSTR("<+0330>-3:30<+0430>,J79/24,J263/24")
#define TZ_Asia_Thimphu PSTR("<+06>-6")
#define TZ_Asia_Tokyo PSTR("JST-9")
#define TZ_Asia_Tomsk PSTR("<+07>-7")
#define TZ_Asia_Ulaanbaatar PSTR("<+08>-8")
#define TZ_Asia_Urumqi PSTR("<+06>-6")
#define TZ_Asia_UstmNera PSTR("<+10>-10")
#define TZ_Asia_Vientiane PSTR("<+07>-7")
#define TZ_Asia_Vladivostok PSTR("<+10>-10")
#define TZ_Asia_Yakutsk PSTR("<+09>-9")
#define TZ_Asia_Yangon PSTR("<+0630>-6:30")
#define TZ_Asia_Yekaterinburg PSTR("<+05>-5")
#define TZ_Asia_Yerevan PSTR("<+04>-4")
#define TZ_Atlantic_Azores PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
#define TZ_Atlantic_Bermuda PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_Atlantic_Canary PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Atlantic_Cape_Verde PSTR("<-01>1")
#define TZ_Atlantic_Faroe PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Atlantic_Madeira PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Atlantic_Reykjavik PSTR("GMT0")
#define TZ_Atlantic_South_Georgia PSTR("<-02>2")
#define TZ_Atlantic_Stanley PSTR("<-03>3")
#define TZ_Atlantic_St_Helena PSTR("GMT0")
#define TZ_Australia_Adelaide PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Brisbane PSTR("AEST-10")
#define TZ_Australia_Broken_Hill PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Currie PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Darwin PSTR("ACST-9:30")
#define TZ_Australia_Eucla PSTR("<+0845>-8:45")
#define TZ_Australia_Hobart PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Lindeman PSTR("AEST-10")
#define TZ_Australia_Lord_Howe PSTR("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
#define TZ_Australia_Melbourne PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Perth PSTR("AWST-8")
#define TZ_Australia_Sydney PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Europe_Amsterdam PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Andorra PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Astrakhan PSTR("<+04>-4")
#define TZ_Europe_Athens PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Belgrade PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Berlin PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Bratislava PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Brussels PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Bucharest PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Budapest PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Busingen PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Chisinau PSTR("EET-2EEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Copenhagen PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Dublin PSTR("IST-1GMT0,M10.5.0,M3.5.0/1")
#define TZ_Europe_Gibraltar PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Guernsey PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Helsinki PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Isle_of_Man PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Istanbul PSTR("<+03>-3")
#define TZ_Europe_Jersey PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Kaliningrad PSTR("EET-2")
#define TZ_Europe_Kiev PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Kirov PSTR("<+03>-3")
#define TZ_Europe_Lisbon PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Ljubljana PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_London PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Luxembourg PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Madrid PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Malta PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Mariehamn PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Minsk PSTR("<+03>-3")
#define TZ_Europe_Monaco PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Moscow PSTR("MSK-3")
#define TZ_Europe_Oslo PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Paris PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Podgorica PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Prague PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Riga PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Rome PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Samara PSTR("<+04>-4")
#define TZ_Europe_San_Marino PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Sarajevo PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Saratov PSTR("<+04>-4")
#define TZ_Europe_Simferopol PSTR("MSK-3")
#define TZ_Europe_Skopje PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Sofia PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Stockholm PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Tallinn PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Tirane PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Ulyanovsk PSTR("<+04>-4")
#define TZ_Europe_Uzhgorod PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Vaduz PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Vatican PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Vienna PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Vilnius PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Volgograd PSTR("<+04>-4")
#define TZ_Europe_Warsaw PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Zagreb PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Zaporozhye PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Zurich PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Indian_Antananarivo PSTR("EAT-3")
#define TZ_Indian_Chagos PSTR("<+06>-6")
#define TZ_Indian_Christmas PSTR("<+07>-7")
#define TZ_Indian_Cocos PSTR("<+0630>-6:30")
#define TZ_Indian_Comoro PSTR("EAT-3")
#define TZ_Indian_Kerguelen PSTR("<+05>-5")
#define TZ_Indian_Mahe PSTR("<+04>-4")
#define TZ_Indian_Maldives PSTR("<+05>-5")
#define TZ_Indian_Mauritius PSTR("<+04>-4")
#define TZ_Indian_Mayotte PSTR("EAT-3")
#define TZ_Indian_Reunion PSTR("<+04>-4")
#define TZ_Pacific_Apia PSTR("<+13>-13<+14>,M9.5.0/3,M4.1.0/4")
#define TZ_Pacific_Auckland PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3")
#define TZ_Pacific_Bougainville PSTR("<+11>-11")
#define TZ_Pacific_Chatham PSTR("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
#define TZ_Pacific_Chuuk PSTR("<+10>-10")
#define TZ_Pacific_Easter PSTR("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
#define TZ_Pacific_Efate PSTR("<+11>-11")
#define TZ_Pacific_Enderbury PSTR("<+13>-13")
#define TZ_Pacific_Fakaofo PSTR("<+13>-13")
#define TZ_Pacific_Fiji PSTR("<+12>-12<+13>,M11.1.0,M1.2.2/123")
#define TZ_Pacific_Funafuti PSTR("<+12>-12")
#define TZ_Pacific_Galapagos PSTR("<-06>6")
#define TZ_Pacific_Gambier PSTR("<-09>9")
#define TZ_Pacific_Guadalcanal PSTR("<+11>-11")
#define TZ_Pacific_Guam PSTR("ChST-10")
#define TZ_Pacific_Honolulu PSTR("HST10")
#define TZ_Pacific_Kiritimati PSTR("<+14>-14")
#define TZ_Pacific_Kosrae PSTR("<+11>-11")
#define TZ_Pacific_Kwajalein PSTR("<+12>-12")
#define TZ_Pacific_Majuro PSTR("<+12>-12")
#define TZ_Pacific_Marquesas PSTR("<-0930>9:30")
#define TZ_Pacific_Midway PSTR("SST11")
#define TZ_Pacific_Nauru PSTR("<+12>-12")
#define TZ_Pacific_Niue PSTR("<-11>11")
#define TZ_Pacific_Norfolk PSTR("<+11>-11")
#define TZ_Pacific_Noumea PSTR("<+11>-11")
#define TZ_Pacific_Pago_Pago PSTR("SST11")
#define TZ_Pacific_Palau PSTR("<+09>-9")
#define TZ_Pacific_Pitcairn PSTR("<-08>8")
#define TZ_Pacific_Pohnpei PSTR("<+11>-11")
#define TZ_Pacific_Port_Moresby PSTR("<+10>-10")
#define TZ_Pacific_Rarotonga PSTR("<-10>10")
#define TZ_Pacific_Saipan PSTR("ChST-10")
#define TZ_Pacific_Tahiti PSTR("<-10>10")
#define TZ_Pacific_Tarawa PSTR("<+12>-12")
#define TZ_Pacific_Tongatapu PSTR("<+13>-13")
#define TZ_Pacific_Wake PSTR("<+12>-12")
#define TZ_Pacific_Wallis PSTR("<+12>-12")
#define TZ_Etc_GMT PSTR("GMT0")
#define TZ_Etc_GMTm0 PSTR("GMT0")
#define TZ_Etc_GMTm1 PSTR("<+01>-1")
#define TZ_Etc_GMTm2 PSTR("<+02>-2")
#define TZ_Etc_GMTm3 PSTR("<+03>-3")
#define TZ_Etc_GMTm4 PSTR("<+04>-4")
#define TZ_Etc_GMTm5 PSTR("<+05>-5")
#define TZ_Etc_GMTm6 PSTR("<+06>-6")
#define TZ_Etc_GMTm7 PSTR("<+07>-7")
#define TZ_Etc_GMTm8 PSTR("<+08>-8")
#define TZ_Etc_GMTm9 PSTR("<+09>-9")
#define TZ_Etc_GMTm10 PSTR("<+10>-10")
#define TZ_Etc_GMTm11 PSTR("<+11>-11")
#define TZ_Etc_GMTm12 PSTR("<+12>-12")
#define TZ_Etc_GMTm13 PSTR("<+13>-13")
#define TZ_Etc_GMTm14 PSTR("<+14>-14")
#define TZ_Etc_GMT0 PSTR("GMT0")
#define TZ_Etc_GMTp0 PSTR("GMT0")
#define TZ_Etc_GMTp1 PSTR("<-01>1")
#define TZ_Etc_GMTp2 PSTR("<-02>2")
#define TZ_Etc_GMTp3 PSTR("<-03>3")
#define TZ_Etc_GMTp4 PSTR("<-04>4")
#define TZ_Etc_GMTp5 PSTR("<-05>5")
#define TZ_Etc_GMTp6 PSTR("<-06>6")
#define TZ_Etc_GMTp7 PSTR("<-07>7")
#define TZ_Etc_GMTp8 PSTR("<-08>8")
#define TZ_Etc_GMTp9 PSTR("<-09>9")
#define TZ_Etc_GMTp10 PSTR("<-10>10")
#define TZ_Etc_GMTp11 PSTR("<-11>11")
#define TZ_Etc_GMTp12 PSTR("<-12>12")
#define TZ_Etc_UCT PSTR("UTC0")
#define TZ_Etc_UTC PSTR("UTC0")
#define TZ_Etc_Greenwich PSTR("GMT0")
#define TZ_Etc_Universal PSTR("UTC0")
#define TZ_Etc_Zulu PSTR("UTC0")
#endif // TZDB_H

View File

@ -23,6 +23,7 @@ extern "C" {
}
extern "C" uint32_t _FS_start;
extern "C" uint32_t _FS_end;
UpdaterClass::UpdaterClass()
: _async(false)
@ -105,15 +106,17 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
wifi_set_sleep_type(NONE_SLEEP_T);
//address where we will start writing the update
uintptr_t updateStartAddress = 0;
//size of current sketch rounded to a sector
size_t currentSketchSize = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
//size of the update rounded to a sector
size_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
if (command == U_FLASH) {
//size of current sketch rounded to a sector
size_t currentSketchSize = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
//address of the end of the space available for sketch and update
uintptr_t updateEndAddress = (uintptr_t)&_FS_start - 0x40200000;
//size of the update rounded to a sector
size_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
//address where we will start writing the update
updateStartAddress = (updateEndAddress > roundedSize)? (updateEndAddress - roundedSize) : 0;
#ifdef DEBUG_UPDATER
@ -129,7 +132,24 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
}
}
else if (command == U_FS) {
updateStartAddress = (uintptr_t)&_FS_start - 0x40200000;
if((uintptr_t)&_FS_start + roundedSize > (uintptr_t)&_FS_end) {
_setError(UPDATE_ERROR_SPACE);
return false;
}
#ifdef ATOMIC_FS_UPDATE
//address of the end of the space available for update
uintptr_t updateEndAddress = (uintptr_t)&_FS_start - 0x40200000;
updateStartAddress = (updateEndAddress > roundedSize)? (updateEndAddress - roundedSize) : 0;
if(updateStartAddress < currentSketchSize) {
_setError(UPDATE_ERROR_SPACE);
return false;
}
#else
updateStartAddress = (uintptr_t)&_FS_start - 0x40200000;
#endif
}
else {
// unknown command
@ -272,8 +292,19 @@ bool UpdaterClass::end(bool evenIfRemaining){
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("Staged: address:0x%08X, size:0x%08zX\n"), _startAddress, _size);
#endif
}
else if (_command == U_FS) {
#ifdef ATOMIC_FS_UPDATE
eboot_command ebcmd;
ebcmd.action = ACTION_COPY_RAW;
ebcmd.args[0] = _startAddress;
ebcmd.args[1] = (uintptr_t)&_FS_start - 0x40200000;
ebcmd.args[2] = _size;
eboot_command_write(&ebcmd);
#endif
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("Filesystem: address:0x%08X, size:0x%08zX\n"), _startAddress, _size);
#endif
}
@ -387,7 +418,7 @@ bool UpdaterClass::_verifyHeader(uint8_t data) {
}
return true;
} else if(_command == U_FS) {
// no check of SPIFFS possible with first byte.
// no check of FS possible with first byte.
return true;
}
return false;
@ -421,7 +452,7 @@ bool UpdaterClass::_verifyEnd() {
return true;
} else if(_command == U_FS) {
// SPIFFS is already over written checks make no sense any more.
// FS is already over written checks make no sense any more.
return true;
}
return false;

View File

@ -129,10 +129,9 @@ String::~String() {
// /*********************************************/
inline void String::init(void) {
setSSO(false);
setCapacity(0);
setSSO(true);
setLen(0);
setBuffer(nullptr);
wbuffer()[0] = 0;
}
void String::invalidate(void) {

View File

@ -53,7 +53,7 @@ class String {
// if the initial value is null or invalid, or if memory allocation
// fails, the string will be marked as invalid (i.e. "if (s)" will
// be false).
String(const char *cstr = "");
String(const char *cstr = nullptr);
String(const String &str);
String(const __FlashStringHelper *str);
#ifdef __GXX_EXPERIMENTAL_CXX0X__

View File

@ -1,71 +1,71 @@
/**
* base64.cpp
*
* Created on: 09.12.2015
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the ESP8266 core for Arduino.
*
* 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
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "Arduino.h"
extern "C" {
#include "libb64/cdecode.h"
#include "libb64/cencode.h"
}
#include "base64.h"
/**
* convert input data to base64
* @param data uint8_t *
* @param length size_t
* @return String
*/
String base64::encode(uint8_t * data, size_t length, bool doNewLines) {
// base64 needs more size then the source data, use cencode.h macros
size_t size = ((doNewLines ? base64_encode_expected_len(length)
: base64_encode_expected_len_nonewlines(length)) + 1);
char * buffer = (char *) malloc(size);
if(buffer) {
base64_encodestate _state;
if(doNewLines)
{
base64_init_encodestate(&_state);
}
else
{
base64_init_encodestate_nonewlines(&_state);
}
int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state);
len = base64_encode_blockend((buffer + len), &_state);
String base64 = String(buffer);
free(buffer);
return base64;
}
return String("-FAIL-");
}
/**
* convert input data to base64
* @param text String
* @return String
*/
String base64::encode(String text, bool doNewLines) {
return base64::encode((uint8_t *) text.c_str(), text.length(), doNewLines);
}
/**
* base64.cpp
*
* Created on: 09.12.2015
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the ESP8266 core for Arduino.
*
* 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
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "Arduino.h"
extern "C" {
#include "libb64/cdecode.h"
#include "libb64/cencode.h"
}
#include "base64.h"
/**
* convert input data to base64
* @param data const uint8_t *
* @param length size_t
* @return String
*/
String base64::encode(const uint8_t * data, size_t length, bool doNewLines) {
// base64 needs more size then the source data, use cencode.h macros
size_t size = ((doNewLines ? base64_encode_expected_len(length)
: base64_encode_expected_len_nonewlines(length)) + 1);
char * buffer = (char *) malloc(size);
if(buffer) {
base64_encodestate _state;
if(doNewLines)
{
base64_init_encodestate(&_state);
}
else
{
base64_init_encodestate_nonewlines(&_state);
}
int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state);
len = base64_encode_blockend((buffer + len), &_state);
String base64 = String(buffer);
free(buffer);
return base64;
}
return String("-FAIL-");
}
/**
* convert input data to base64
* @param text const String&
* @return String
*/
String base64::encode(const String& text, bool doNewLines) {
return base64::encode((const uint8_t *) text.c_str(), text.length(), doNewLines);
}

View File

@ -1,39 +1,39 @@
/**
* base64.h
*
* Created on: 09.12.2015
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the ESP8266 core for Arduino.
*
* 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
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef CORE_BASE64_H_
#define CORE_BASE64_H_
class base64 {
public:
// NOTE: The default behaviour of backend (lib64)
// is to add a newline every 72 (encoded) characters output.
// This may 'break' longer uris and json variables
static String encode(uint8_t * data, size_t length, bool doNewLines = true);
static String encode(String text, bool doNewLines = true);
private:
};
#endif /* CORE_BASE64_H_ */
/**
* base64.h
*
* Created on: 09.12.2015
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the ESP8266 core for Arduino.
*
* 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
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef CORE_BASE64_H_
#define CORE_BASE64_H_
class base64 {
public:
// NOTE: The default behaviour of backend (lib64)
// is to add a newline every 72 (encoded) characters output.
// This may 'break' longer uris and json variables
static String encode(const uint8_t * data, size_t length, bool doNewLines = true);
static String encode(const String& text, bool doNewLines = true);
private:
};
#endif /* CORE_BASE64_H_ */

View File

@ -18,7 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
.text
.section .irom0.text
.align 4
.literal_position
.global cont_yield
@ -84,7 +84,7 @@ cont_wrapper:
////////////////////////////////////////////////////
.text
.section .irom0.text
.align 4
.literal_position
.global cont_run

View File

@ -1,50 +1,50 @@
/*
core_esp8266_features.h - list of features integrated in to ESP8266 core
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CORE_ESP8266_FEATURES_H
#define CORE_ESP8266_FEATURES_H
#define CORE_HAS_LIBB64
#define CORE_HAS_BASE64_CLASS
#define CORE_HAS_CXA_GUARD
#define CORE_HAS_UMM
#define WIFI_HAS_EVENT_CALLBACK
#ifdef __cplusplus
#include <stdlib.h> // malloc()
#include <stddef.h> // size_t
/*
core_esp8266_features.h - list of features integrated in to ESP8266 core
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CORE_ESP8266_FEATURES_H
#define CORE_ESP8266_FEATURES_H
#define CORE_HAS_LIBB64
#define CORE_HAS_BASE64_CLASS
#define CORE_HAS_CXA_GUARD
#define CORE_HAS_UMM
#define WIFI_HAS_EVENT_CALLBACK
#ifdef __cplusplus
#include <stdlib.h> // malloc()
#include <stddef.h> // size_t
namespace arduino
{
{
extern "C++"
template <typename T, typename ...TConstructorArgs>
T* new0 (size_t n, TConstructorArgs... TconstructorArgs)
{
// n==0: single allocation, otherwise it is an array
size_t offset = n? sizeof(size_t): 0;
{
// n==0: single allocation, otherwise it is an array
size_t offset = n? sizeof(size_t): 0;
size_t arraysize = n? n: 1;
T* ptr = (T*)malloc(offset + (arraysize * sizeof(T)));
if (ptr)
@ -54,43 +54,43 @@ namespace arduino
for (size_t i = 0; i < arraysize; i++)
new (ptr + offset + i * sizeof(T)) T(TconstructorArgs...);
return ptr + offset;
}
}
return nullptr;
}
}
#define arduino_new(Type, ...) arduino::new0<Type>(0, ##__VA_ARGS__)
#define arduino_newarray(Type, n, ...) arduino::new0<Type>(n, ##__VA_ARGS__)
#endif // __cplusplus
#ifndef __STRINGIFY
#define __STRINGIFY(a) #a
#endif
// these low level routines provide a replacement for SREG interrupt save that AVR uses
// but are esp8266 specific. A normal use pattern is like
//
//{
// uint32_t savedPS = xt_rsil(1); // this routine will allow level 2 and above
// // do work here
// xt_wsr_ps(savedPS); // restore the state
//}
//
// level (0-15), interrupts of the given level and above will be active
// level 15 will disable ALL interrupts,
// level 0 will enable ALL interrupts,
//
#ifndef CORE_MOCK
#define xt_rsil(level) (__extension__({uint32_t state; __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state) :: "memory"); state;}))
#define xt_wsr_ps(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory")
#define arduino_new(Type, ...) arduino::new0<Type>(0, ##__VA_ARGS__)
#define arduino_newarray(Type, n, ...) arduino::new0<Type>(n, ##__VA_ARGS__)
#endif // __cplusplus
#ifndef __STRINGIFY
#define __STRINGIFY(a) #a
#endif
// these low level routines provide a replacement for SREG interrupt save that AVR uses
// but are esp8266 specific. A normal use pattern is like
//
//{
// uint32_t savedPS = xt_rsil(1); // this routine will allow level 2 and above
// // do work here
// xt_wsr_ps(savedPS); // restore the state
//}
//
// level (0-15), interrupts of the given level and above will be active
// level 15 will disable ALL interrupts,
// level 0 will enable ALL interrupts,
//
#ifndef CORE_MOCK
#define xt_rsil(level) (__extension__({uint32_t state; __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state) :: "memory"); state;}))
#define xt_wsr_ps(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory")
inline uint32_t esp_get_cycle_count() __attribute__((always_inline));
inline uint32_t esp_get_cycle_count() {
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
return ccount;
}
#endif // not CORE_MOCK
#endif // CORE_ESP8266_FEATURES_H
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
return ccount;
}
#endif // not CORE_MOCK
#endif // CORE_ESP8266_FEATURES_H

View File

@ -62,6 +62,10 @@ static int s_user_reset_reason = REASON_DEFAULT_RST;
// From UMM, the last caller of a malloc/realloc/calloc which failed:
extern void *umm_last_fail_alloc_addr;
extern int umm_last_fail_alloc_size;
#if defined(DEBUG_ESP_OOM)
extern const char *umm_last_fail_alloc_file;
extern int umm_last_fail_alloc_line;
#endif
static void raise_exception() __attribute__((noreturn));
@ -108,8 +112,7 @@ void __wrap_system_restart_local() {
else
rst_info.reason = s_user_reset_reason;
// TODO: ets_install_putc1 definition is wrong in ets_sys.h, need cast
ets_install_putc1((void *)&uart_write_char_d);
ets_install_putc1(&uart_write_char_d);
if (s_panic_line) {
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
@ -182,7 +185,13 @@ void __wrap_system_restart_local() {
// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
if (umm_last_fail_alloc_addr) {
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
#if defined(DEBUG_ESP_OOM)
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)@%S:%d\n"),
(uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size,
umm_last_fail_alloc_file, umm_last_fail_alloc_line);
#else
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
#endif
}
custom_crash_callback( &rst_info, sp_dump + offset, stack_end );

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,6 @@ extern bool timeshift64_is_set;
void esp_yield();
void esp_schedule();
void tune_timeshift64 (uint64_t now_us);
void settimeofday_cb (void (*cb)(void));
void disable_extra4k_at_link_time (void) __attribute__((noinline));
uint32_t sqrt32 (uint32_t n);
@ -25,6 +24,14 @@ uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);
#ifdef __cplusplus
}
#include <functional>
using TrivialCB = std::function<void()>;
void settimeofday_cb (TrivialCB&& cb);
void settimeofday_cb (const TrivialCB& cb);
#endif
#endif // __COREDECLS_H

View File

@ -1,36 +1,36 @@
/*
debug.cpp - debug helper functions
Copyright (c) 2015 Markus Sattler. 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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Arduino.h"
#include "debug.h"
void ICACHE_RAM_ATTR hexdump(const void *mem, uint32_t len, uint8_t cols) {
const uint8_t* src = (const uint8_t*) mem;
os_printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
for(uint32_t i = 0; i < len; i++) {
if(i % cols == 0) {
os_printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
yield();
}
os_printf("%02X ", *src);
src++;
}
os_printf("\n");
}
/*
debug.cpp - debug helper functions
Copyright (c) 2015 Markus Sattler. 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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Arduino.h"
#include "debug.h"
void ICACHE_RAM_ATTR hexdump(const void *mem, uint32_t len, uint8_t cols) {
const uint8_t* src = (const uint8_t*) mem;
os_printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
for(uint32_t i = 0; i < len; i++) {
if(i % cols == 0) {
os_printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
yield();
}
os_printf("%02X ", *src);
src++;
}
os_printf("\n");
}

View File

@ -11,6 +11,27 @@ extern int rom_i2c_readReg_Mask(int, int, int, int, int);
extern int uart_baudrate_detect(int, int);
/*
ROM function, uart_buff_switch(), is used to switch printing between UART0 and
UART1. It updates a structure that only controls a select group of print
functions. ets_putc() and ets_uart_printf() are examples and are not affected by
calls to ets_install_putc1().
Use:
0 for UART0, also clears RX FIFO
1 for UART1
*/
extern void uart_buff_switch(uint8_t);
/*
ROM function, ets_uart_printf(), prints on the UART selected by
uart_buff_switch(). Supported format options are the same as vprintf(). Also
has cooked newline behavior. No flash format/string support; however, ISR safe.
Also, uses a static function in ROM to print characters which is only
controlled by uart_buff_switch().
*/
extern int ets_uart_printf(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
extern void ets_delay_us(uint32_t us);
#ifdef __cplusplus

View File

@ -7,38 +7,134 @@
#include "umm_malloc/umm_malloc.h"
#include <c_types.h>
#include <sys/reent.h>
#include <user_interface.h>
extern "C" {
#if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE)
#define UMM_MALLOC(s) umm_poison_malloc(s)
#define UMM_CALLOC(n,s) umm_poison_calloc(n,s)
#define UMM_REALLOC_FL(p,s,f,l) umm_poison_realloc_fl(p,s,f,l)
#define UMM_FREE_FL(p,f,l) umm_poison_free_fl(p,f,l)
#undef realloc
#undef free
#elif defined(DEBUG_ESP_OOM)
#define UMM_MALLOC(s) umm_malloc(s)
#define UMM_CALLOC(n,s) umm_calloc(n,s)
#define UMM_REALLOC_FL(p,s,f,l) umm_realloc(p,s)
#define UMM_FREE_FL(p,f,l) umm_free(p)
#undef realloc
#undef free
#else // ! UMM_POISON_CHECK && ! DEBUG_ESP_OOM
#define UMM_MALLOC(s) malloc(s)
#define UMM_CALLOC(n,s) calloc(n,s)
#define UMM_REALLOC_FL(p,s,f,l) realloc(p,s)
#define UMM_FREE_FL(p,f,l) free(p)
#endif
#if defined(UMM_POISON_CHECK)
#define POISON_CHECK__ABORT() \
do { \
if ( ! POISON_CHECK() ) \
abort(); \
} while(0)
#define POISON_CHECK__PANIC_FL(file, line) \
do { \
if ( ! POISON_CHECK() ) \
__panic_func(file, line, ""); \
} while(0)
#else // No full heap poison checking.
#define POISON_CHECK__ABORT() do {} while(0)
#define POISON_CHECK__PANIC_FL(file, line) do { (void)file; (void)line; } while(0)
#endif
// Debugging helper, last allocation which returned NULL
void *umm_last_fail_alloc_addr = NULL;
int umm_last_fail_alloc_size = 0;
#if defined(DEBUG_ESP_OOM)
const char *umm_last_fail_alloc_file = NULL;
int umm_last_fail_alloc_line = 0;
#endif
#ifdef UMM_INTEGRITY_CHECK
#define INTEGRITY_CHECK__ABORT() \
do { \
if ( ! INTEGRITY_CHECK() ) \
abort(); \
} while(0)
#define INTEGRITY_CHECK__PANIC_FL(file, line) \
do { \
if ( ! INTEGRITY_CHECK() ) \
__panic_func(file, line, ""); \
} while(0)
#else // ! UMM_INTEGRITY_CHECK
#define INTEGRITY_CHECK__ABORT() do {} while(0)
#define INTEGRITY_CHECK__PANIC_FL(file, line) do { (void)file; (void)line; } while(0)
#endif // UMM_INTEGRITY_CHECK
#if defined(DEBUG_ESP_OOM)
#define PTR_CHECK__LOG_LAST_FAIL_FL(p, s, f, l) \
if(0 != (s) && 0 == p)\
{\
umm_last_fail_alloc_addr = __builtin_return_address(0);\
umm_last_fail_alloc_size = s;\
umm_last_fail_alloc_file = f;\
umm_last_fail_alloc_line = l;\
}
#define PTR_CHECK__LOG_LAST_FAIL(p, s) \
if(0 != (s) && 0 == p)\
{\
umm_last_fail_alloc_addr = __builtin_return_address(0);\
umm_last_fail_alloc_size = s;\
umm_last_fail_alloc_file = NULL;\
umm_last_fail_alloc_line = 0;\
}
#else
#define PTR_CHECK__LOG_LAST_FAIL_FL(p, s, f, l) \
(void)f;\
(void)l;\
if(0 != (s) && 0 == p)\
{\
umm_last_fail_alloc_addr = __builtin_return_address(0);\
umm_last_fail_alloc_size = s;\
}
#define PTR_CHECK__LOG_LAST_FAIL(p, s) \
if(0 != (s) && 0 == p)\
{\
umm_last_fail_alloc_addr = __builtin_return_address(0);\
umm_last_fail_alloc_size = s;\
}
#endif
void* _malloc_r(struct _reent* unused, size_t size)
{
(void) unused;
void *ret = malloc(size);
if (0 != size && 0 == ret) {
umm_last_fail_alloc_addr = __builtin_return_address(0);
umm_last_fail_alloc_size = size;
}
PTR_CHECK__LOG_LAST_FAIL(ret, size);
return ret;
}
void _free_r(struct _reent* unused, void* ptr)
{
(void) unused;
return free(ptr);
free(ptr);
}
void* _realloc_r(struct _reent* unused, void* ptr, size_t size)
{
(void) unused;
void *ret = realloc(ptr, size);
if (0 != size && 0 == ret) {
umm_last_fail_alloc_addr = __builtin_return_address(0);
umm_last_fail_alloc_size = size;
}
PTR_CHECK__LOG_LAST_FAIL(ret, size);
return ret;
}
@ -46,140 +142,169 @@ void* _calloc_r(struct _reent* unused, size_t count, size_t size)
{
(void) unused;
void *ret = calloc(count, size);
if (0 != (count * size) && 0 == ret) {
umm_last_fail_alloc_addr = __builtin_return_address(0);
umm_last_fail_alloc_size = count * size;
PTR_CHECK__LOG_LAST_FAIL(ret, count * size);
return ret;
}
#ifdef DEBUG_ESP_OOM
#undef malloc
#undef calloc
#undef realloc
#define DEBUG_HEAP_PRINTF ets_uart_printf
void ICACHE_RAM_ATTR print_loc(size_t size, const char* file, int line)
{
(void)size;
(void)line;
if (system_get_os_print()) {
DEBUG_HEAP_PRINTF(":oom(%d)@", (int)size);
bool inISR = ETS_INTR_WITHINISR();
if (inISR && (uint32_t)file >= 0x40200000) {
DEBUG_HEAP_PRINTF("File: %p", file);
} else if (!inISR && (uint32_t)file >= 0x40200000) {
char buf[ets_strlen(file)] __attribute__ ((aligned(4)));
ets_strcpy(buf, file);
DEBUG_HEAP_PRINTF(buf);
} else {
DEBUG_HEAP_PRINTF(file);
}
DEBUG_HEAP_PRINTF(":%d\n", line);
}
}
void ICACHE_RAM_ATTR print_oom_size(size_t size)
{
(void)size;
if (system_get_os_print()) {
DEBUG_HEAP_PRINTF(":oom(%d)@?\n", (int)size);
}
}
#define OOM_CHECK__PRINT_OOM(p, s) if (!p) print_oom_size(s)
#define OOM_CHECK__PRINT_LOC(p, s, f, l) if (!p) print_loc(s, f, l)
#else // ! DEBUG_ESP_OOM
#if 1
//C - to be discussed - is this what you want?
//C Skip OOM logging of last fail for malloc/... and pvPort... .
//C It cost 64 more bytes of IRAM to turn on. And was not previously enabled.
#undef PTR_CHECK__LOG_LAST_FAIL_FL
#define PTR_CHECK__LOG_LAST_FAIL_FL(p, s, f, l)
#undef PTR_CHECK__LOG_LAST_FAIL
#define PTR_CHECK__LOG_LAST_FAIL(p, s)
#endif
#define OOM_CHECK__PRINT_OOM(p, s)
#define OOM_CHECK__PRINT_LOC(p, s, f, l)
#endif
#if defined(DEBUG_ESP_OOM) || defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) || defined(UMM_INTEGRITY_CHECK)
/*
The thinking behind the ordering of Integrity Check, Full Poison Check, and
the specific *alloc function.
1. Integrity Check - verifies the heap management information is not corrupt.
This allows any other testing, that walks the heap, to run safely.
2. Place Full Poison Check before or after a specific *alloc function?
a. After, when the *alloc function operates on an existing allocation.
b. Before, when the *alloc function creates a new, not modified, allocation.
In a free() or realloc() call, the focus is on their allocation. It is
checked 1st and reported on 1ST if an error exists. Full Posion Check is
done after.
For malloc(), calloc(), and zalloc() Full Posion Check is done 1st since
these functions do not modify an existing allocation.
*/
void* ICACHE_RAM_ATTR malloc(size_t size)
{
INTEGRITY_CHECK__ABORT();
POISON_CHECK__ABORT();
void* ret = UMM_MALLOC(size);
PTR_CHECK__LOG_LAST_FAIL(ret, size);
OOM_CHECK__PRINT_OOM(ret, size);
return ret;
}
void* ICACHE_RAM_ATTR calloc(size_t count, size_t size)
{
INTEGRITY_CHECK__ABORT();
POISON_CHECK__ABORT();
void* ret = UMM_CALLOC(count, size);
PTR_CHECK__LOG_LAST_FAIL(ret, count * size);
OOM_CHECK__PRINT_OOM(ret, size);
return ret;
}
void* ICACHE_RAM_ATTR realloc(void* ptr, size_t size)
{
INTEGRITY_CHECK__ABORT();
void* ret = UMM_REALLOC_FL(ptr, size, NULL, 0);
POISON_CHECK__ABORT();
PTR_CHECK__LOG_LAST_FAIL(ret, size);
OOM_CHECK__PRINT_OOM(ret, size);
return ret;
}
void ICACHE_RAM_ATTR free(void* p)
{
INTEGRITY_CHECK__ABORT();
UMM_FREE_FL(p, NULL, 0);
POISON_CHECK__ABORT();
}
#endif
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line)
{
INTEGRITY_CHECK__PANIC_FL(file, line);
POISON_CHECK__PANIC_FL(file, line);
void* ret = UMM_MALLOC(size);
PTR_CHECK__LOG_LAST_FAIL_FL(ret, size, file, line);
OOM_CHECK__PRINT_LOC(ret, size, file, line);
return ret;
}
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line)
{
INTEGRITY_CHECK__PANIC_FL(file, line);
POISON_CHECK__PANIC_FL(file, line);
void* ret = UMM_CALLOC(count, size);
PTR_CHECK__LOG_LAST_FAIL_FL(ret, count * size, file, line);
OOM_CHECK__PRINT_LOC(ret, size, file, line);
return ret;
}
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line)
{
INTEGRITY_CHECK__PANIC_FL(file, line);
void* ret = UMM_REALLOC_FL(ptr, size, file, line);
POISON_CHECK__PANIC_FL(file, line);
PTR_CHECK__LOG_LAST_FAIL_FL(ret, size, file, line);
OOM_CHECK__PRINT_LOC(ret, size, file, line);
return ret;
}
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line)
{
INTEGRITY_CHECK__PANIC_FL(file, line);
POISON_CHECK__PANIC_FL(file, line);
void* ret = UMM_CALLOC(1, size);
PTR_CHECK__LOG_LAST_FAIL_FL(ret, size, file, line);
OOM_CHECK__PRINT_LOC(ret, size, file, line);
return ret;
}
void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line)
{
(void) file;
(void) line;
free(ptr);
}
#ifdef DEBUG_ESP_OOM
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line)
{
return malloc_loc(size, file, line);
}
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line)
{
return calloc_loc(count, size, file, line);
}
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line)
{
return realloc_loc(ptr, size, file, line);
}
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line)
{
return calloc_loc(1, size, file, line);
}
#undef malloc
#undef calloc
#undef realloc
static const char oom_fmt[] PROGMEM STORE_ATTR = ":oom(%d)@?\n";
static const char oom_fmt_1[] PROGMEM STORE_ATTR = ":oom(%d)@";
static const char oom_fmt_2[] PROGMEM STORE_ATTR = ":%d\n";
void* malloc (size_t s)
{
void* ret = umm_malloc(s);
if (!ret)
os_printf(oom_fmt, (int)s);
return ret;
}
void* calloc (size_t n, size_t s)
{
void* ret = umm_calloc(n, s);
if (!ret)
os_printf(oom_fmt, (int)s);
return ret;
}
void* realloc (void* p, size_t s)
{
void* ret = umm_realloc(p, s);
if (!ret)
os_printf(oom_fmt, (int)s);
return ret;
}
void print_loc (size_t s, const char* file, int line)
{
os_printf(oom_fmt_1, (int)s);
os_printf(file);
os_printf(oom_fmt_2, line);
}
void* malloc_loc (size_t s, const char* file, int line)
{
void* ret = umm_malloc(s);
if (!ret)
print_loc(s, file, line);
return ret;
}
void* calloc_loc (size_t n, size_t s, const char* file, int line)
{
void* ret = umm_calloc(n, s);
if (!ret)
print_loc(s, file, line);
return ret;
}
void* realloc_loc (void* p, size_t s, const char* file, int line)
{
void* ret = umm_realloc(p, s);
if (!ret)
print_loc(s, file, line);
return ret;
}
#else
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line)
{
(void) file;
(void) line;
return malloc(size);
}
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line)
{
(void) file;
(void) line;
return calloc(count, size);
}
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line)
{
(void) file;
(void) line;
return realloc(ptr, size);
}
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line)
{
(void) file;
(void) line;
return calloc(1, size);
}
#endif // !defined(DEBUG_ESP_OOM)
size_t xPortGetFreeHeapSize(void)
{
return umm_free_heap_size();
INTEGRITY_CHECK__PANIC_FL(file, line);
UMM_FREE_FL(ptr, file, line);
POISON_CHECK__PANIC_FL(file, line);
}
size_t ICACHE_RAM_ATTR xPortWantedSizeAlign(size_t size)

View File

@ -100,7 +100,8 @@ int ICACHE_RAM_ATTR _putc_r(struct _reent* r, int c, FILE* file) __attribute__((
int ICACHE_RAM_ATTR _putc_r(struct _reent* r, int c, FILE* file) {
(void) r;
if (file->_file == STDOUT_FILENO) {
return ets_putc(c);
ets_putc(c);
return c;
}
return EOF;
}

View File

@ -42,16 +42,22 @@
#include <osapi.h>
#include <os_type.h>
#include "coredecls.h"
#include "Schedule.h"
extern "C" {
static TrivialCB _settimeofday_cb;
static void (*_settimeofday_cb)(void) = NULL;
void settimeofday_cb (TrivialCB&& cb)
{
_settimeofday_cb = std::move(cb);
}
void settimeofday_cb (void (*cb)(void))
void settimeofday_cb (const TrivialCB& cb)
{
_settimeofday_cb = cb;
}
extern "C" {
#if LWIP_VERSION_MAJOR == 1
#include <pgmspace.h>
@ -478,7 +484,7 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz)
sntp_set_system_time(tv->tv_sec);
if (_settimeofday_cb)
_settimeofday_cb();
schedule_function(_settimeofday_cb);
}
return 0;
}

View File

@ -25,6 +25,21 @@
using namespace fs;
// Deprecated functions, to be deleted in next release
int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
return flash_hal_write(addr, size, src);
}
int32_t spiffs_hal_erase(uint32_t addr, uint32_t size) {
return flash_hal_erase(addr, size);
}
int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
return flash_hal_read(addr, size, dst);
}
namespace spiffs_impl {
FileImplPtr SPIFFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode)

View File

@ -39,6 +39,26 @@ extern "C" {
using namespace fs;
// The following are deprecated symbols and functions, to be removed at the next major release.
// They are provided only for backwards compatibility and to give libs a chance to update.
extern "C" uint32_t _SPIFFS_start __attribute__((deprecated));
extern "C" uint32_t _SPIFFS_end __attribute__((deprecated));
extern "C" uint32_t _SPIFFS_page __attribute__((deprecated));
extern "C" uint32_t _SPIFFS_block __attribute__((deprecated));
#define SPIFFS_PHYS_ADDR ((uint32_t) (&_SPIFFS_start) - 0x40200000)
#define SPIFFS_PHYS_SIZE ((uint32_t) (&_SPIFFS_end) - (uint32_t) (&_SPIFFS_start))
#define SPIFFS_PHYS_PAGE ((uint32_t) &_SPIFFS_page)
#define SPIFFS_PHYS_BLOCK ((uint32_t) &_SPIFFS_block)
extern int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) __attribute__((deprecated));
extern int32_t spiffs_hal_erase(uint32_t addr, uint32_t size) __attribute__((deprecated));
extern int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) __attribute__((deprecated));
namespace spiffs_impl {
int getSpiffsMode(OpenMode openMode, AccessMode accessMode);
@ -151,11 +171,6 @@ public:
bool begin() override
{
#if defined(ARDUINO) && !defined(CORE_MOCK)
if (&_FS_end <= &_FS_start)
return false;
#endif
if (SPIFFS_mounted(&_fs) != 0) {
return true;
}

View File

@ -16,6 +16,7 @@
*
*/
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/reent.h>
@ -55,25 +56,12 @@ static void setServer(int id, const char* name_or_ip)
{
if (name_or_ip)
{
//TODO: check whether server is given by name or IP
// per current configuration,
// lwIP can receive an IP address or a fqdn
sntp_setservername(id, (char*) name_or_ip);
}
}
void configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)
{
sntp_stop();
setServer(0, server1);
setServer(1, server2);
setServer(2, server3);
sntp_set_timezone_in_seconds(timezone_sec);
sntp_set_daylight(daylightOffset_sec);
sntp_init();
}
int clock_gettime(clockid_t unused, struct timespec *tp)
{
(void) unused;
@ -108,4 +96,33 @@ int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp)
return 0;
}
};
}; // extern "C"
void configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)
{
sntp_stop();
setServer(0, server1);
setServer(1, server2);
setServer(2, server3);
sntp_set_timezone_in_seconds(timezone_sec);
sntp_set_daylight(daylightOffset_sec);
sntp_init();
}
void configTime(const char* tz, const char* server1, const char* server2, const char* server3)
{
sntp_stop();
setServer(0, server1);
setServer(1, server2);
setServer(2, server3);
char tzram[strlen_P(tz) + 1];
memcpy_P(tzram, tz, sizeof(tzram));
setenv("TZ", tzram, 1/*overwrite*/);
tzset();
sntp_init();
}

View File

@ -1,23 +1,23 @@
/*
twi.h - Software I2C library for esp8266
twi.h - Software I2C library for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
Copyright (c) 2015 Hristo Gochkov. 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
version 2.1 of the License, or (at your option) any later version.
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support
*/
#ifndef SI2C_h
#define SI2C_h
@ -48,12 +48,13 @@ uint8_t twi_status();
uint8_t twi_transmit(const uint8_t*, uint8_t);
void twi_attachSlaveRxEvent( void (*)(uint8_t*, size_t) );
void twi_attachSlaveTxEvent( void (*)(void) );
void twi_attachSlaveRxEvent(void (*)(uint8_t*, size_t));
void twi_attachSlaveTxEvent(void (*)(void));
void twi_reply(uint8_t);
//void twi_stop(void);
void twi_releaseBus(void);
void twi_enableSlaveMode(void);
#ifdef __cplusplus
}

View File

@ -48,6 +48,10 @@
#include "user_interface.h"
#include "uart_register.h"
#define MODE2WIDTH(mode) (((mode%16)>>2)+5)
#define MODE2STOP(mode) (((mode)>>5)+1)
#define MODE2PARITY(mode) (mode%4)
/*
Some general architecture for GDB integration with the UART to enable
serial debugging.
@ -83,7 +87,7 @@ struct uart_rx_buffer_
uint8_t * buffer;
};
struct uart_
struct uart_
{
int uart_nr;
int baud_rate;
@ -112,7 +116,7 @@ struct uart_
// called by ISR
inline size_t ICACHE_RAM_ATTR
uart_rx_fifo_available(const int uart_nr)
uart_rx_fifo_available(const int uart_nr)
{
return (USS(uart_nr) >> USRXC) & 0xFF;
}
@ -121,12 +125,12 @@ uart_rx_fifo_available(const int uart_nr)
/**********************************************************/
/************ UNSAFE FUNCTIONS ****************************/
/**********************************************************/
inline size_t
uart_rx_buffer_available_unsafe(const struct uart_rx_buffer_ * rx_buffer)
inline size_t
uart_rx_buffer_available_unsafe(const struct uart_rx_buffer_ * rx_buffer)
{
if(rx_buffer->wpos < rx_buffer->rpos)
if(rx_buffer->wpos < rx_buffer->rpos)
return (rx_buffer->wpos + rx_buffer->size) - rx_buffer->rpos;
return rx_buffer->wpos - rx_buffer->rpos;
}
@ -141,14 +145,14 @@ uart_rx_available_unsafe(uart_t* uart)
// Copy all the rx fifo bytes that fit into the rx buffer
// called by ISR
inline void ICACHE_RAM_ATTR
uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
{
struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;
while(uart_rx_fifo_available(uart->uart_nr))
{
size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
if(nextPos == rx_buffer->rpos)
if(nextPos == rx_buffer->rpos)
{
if (!uart->rx_overrun)
{
@ -175,17 +179,17 @@ uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
}
}
inline int
inline int
uart_peek_char_unsafe(uart_t* uart)
{
if (!uart_rx_available_unsafe(uart))
return -1;
//without the following if statement and body, there is a good chance of a fifo overrun
if (uart_rx_buffer_available_unsafe(uart->rx_buffer) == 0)
// hw fifo can't be peeked, data need to be copied to sw
uart_rx_copy_fifo_to_buffer_unsafe(uart);
return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
}
@ -204,12 +208,19 @@ uart_read_char_unsafe(uart_t* uart)
return -1;
}
uint8_t
uart_get_bit_length(const int uart_nr)
{
// return bit length from uart mode, +1 for the start bit which is always there.
return MODE2WIDTH(USC0(uart_nr)) + MODE2PARITY(USC0(uart_nr)) + MODE2STOP(USC0(uart_nr)) + 1;
}
size_t
uart_rx_available(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled)
return 0;
ETS_UART_INTR_DISABLE();
int uartrxbufferavailable = uart_rx_buffer_available_unsafe(uart->rx_buffer);
ETS_UART_INTR_ENABLE();
@ -217,19 +228,19 @@ uart_rx_available(uart_t* uart)
return uartrxbufferavailable + uart_rx_fifo_available(uart->uart_nr);
}
int
int
uart_peek_char(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled)
return -1;
ETS_UART_INTR_DISABLE(); //access to rx_buffer can be interrupted by the isr (similar to a critical section), so disable interrupts here
int ret = uart_peek_char_unsafe(uart);
ETS_UART_INTR_ENABLE();
return ret;
}
int
int
uart_read_char(uart_t* uart)
{
uint8_t ret;
@ -322,26 +333,26 @@ static void ICACHE_RAM_ATTR uart_isr_handle_data(void* arg, uint8_t data)
USIC(uart->uart_nr) = usis;
}
size_t
size_t
uart_resize_rx_buffer(uart_t* uart, size_t new_size)
{
if(uart == NULL || !uart->rx_enabled)
if(uart == NULL || !uart->rx_enabled)
return 0;
if(uart->rx_buffer->size == new_size)
if(uart->rx_buffer->size == new_size)
return uart->rx_buffer->size;
uint8_t * new_buf = (uint8_t*)malloc(new_size);
if(!new_buf)
return uart->rx_buffer->size;
size_t new_wpos = 0;
ETS_UART_INTR_DISABLE();
while(uart_rx_available_unsafe(uart) && new_wpos < new_size)
new_buf[new_wpos++] = uart_read_char_unsafe(uart); //if uart_rx_available_unsafe() returns non-0, uart_read_char_unsafe() can't return -1
if (new_wpos == new_size)
new_wpos = 0;
uint8_t * old_buf = uart->rx_buffer->buffer;
uart->rx_buffer->rpos = 0;
uart->rx_buffer->wpos = new_wpos;
@ -359,13 +370,13 @@ uart_get_rx_buffer_size(uart_t* uart)
}
// The default ISR handler called when GDB is not enabled
void ICACHE_RAM_ATTR
void ICACHE_RAM_ATTR
uart_isr(void * arg)
{
uart_t* uart = (uart_t*)arg;
uint32_t usis = USIS(uart->uart_nr);
if(uart == NULL || !uart->rx_enabled)
if(uart == NULL || !uart->rx_enabled)
{
USIC(uart->uart_nr) = usis;
ETS_UART_INTR_DISABLE();
@ -380,14 +391,14 @@ uart_isr(void * arg)
uart->rx_overrun = true;
//os_printf_plus(overrun_str);
}
if (usis & ((1 << UIFR) | (1 << UIPE) | (1 << UITO)))
uart->rx_error = true;
USIC(uart->uart_nr) = usis;
}
static void
static void
uart_start_isr(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled)
@ -422,7 +433,7 @@ uart_start_isr(uart_t* uart)
ETS_UART_INTR_ENABLE();
}
static void
static void
uart_stop_isr(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled)
@ -459,7 +470,7 @@ uart_tx_fifo_full(const int uart_nr)
}
static void
static void
uart_do_write_char(const int uart_nr, char c)
{
while(uart_tx_fifo_full(uart_nr));
@ -467,7 +478,7 @@ uart_do_write_char(const int uart_nr, char c)
USF(uart_nr) = c;
}
size_t
size_t
uart_write_char(uart_t* uart, char c)
{
if(uart == NULL || !uart->tx_enabled)
@ -481,7 +492,7 @@ uart_write_char(uart_t* uart, char c)
return 1;
}
size_t
size_t
uart_write(uart_t* uart, const char* buf, size_t size)
{
if(uart == NULL || !uart->tx_enabled)
@ -501,7 +512,7 @@ uart_write(uart_t* uart, const char* buf, size_t size)
}
size_t
size_t
uart_tx_free(uart_t* uart)
{
if(uart == NULL || !uart->tx_enabled)
@ -510,7 +521,7 @@ uart_tx_free(uart_t* uart)
return UART_TX_FIFO_SIZE - uart_tx_fifo_available(uart->uart_nr);
}
void
void
uart_wait_tx_empty(uart_t* uart)
{
if(uart == NULL || !uart->tx_enabled)
@ -521,14 +532,14 @@ uart_wait_tx_empty(uart_t* uart)
}
void
void
uart_flush(uart_t* uart)
{
if(uart == NULL)
return;
uint32_t tmp = 0x00000000;
if(uart->rx_enabled)
if(uart->rx_enabled)
{
tmp |= (1 << UCRXRST);
ETS_UART_INTR_DISABLE();
@ -546,7 +557,7 @@ uart_flush(uart_t* uart)
}
}
void
void
uart_set_baudrate(uart_t* uart, int baud_rate)
{
if(uart == NULL)
@ -556,7 +567,7 @@ uart_set_baudrate(uart_t* uart, int baud_rate)
USD(uart->uart_nr) = (ESP8266_CLOCK / uart->baud_rate);
}
int
int
uart_get_baudrate(uart_t* uart)
{
if(uart == NULL)
@ -565,7 +576,7 @@ uart_get_baudrate(uart_t* uart)
return uart->baud_rate;
}
uart_t*
uart_t*
uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size)
{
uart_t* uart = (uart_t*) malloc(sizeof(uart_t));
@ -576,7 +587,7 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
uart->rx_overrun = false;
uart->rx_error = false;
switch(uart->uart_nr)
switch(uart->uart_nr)
{
case UART0:
ETS_UART_INTR_DISABLE();
@ -586,10 +597,10 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
uart->rx_enabled = (mode != UART_TX_ONLY);
uart->tx_enabled = (mode != UART_RX_ONLY);
uart->rx_pin = (uart->rx_enabled)?3:255;
if(uart->rx_enabled)
if(uart->rx_enabled)
{
struct uart_rx_buffer_ * rx_buffer = (struct uart_rx_buffer_ *)malloc(sizeof(struct uart_rx_buffer_));
if(rx_buffer == NULL)
if(rx_buffer == NULL)
{
free(uart);
return NULL;
@ -598,7 +609,7 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
rx_buffer->rpos = 0;
rx_buffer->wpos = 0;
rx_buffer->buffer = (uint8_t *)malloc(rx_buffer->size);
if(rx_buffer->buffer == NULL)
if(rx_buffer->buffer == NULL)
{
free(rx_buffer);
free(uart);
@ -607,20 +618,20 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
uart->rx_buffer = rx_buffer;
pinMode(uart->rx_pin, SPECIAL);
}
if(uart->tx_enabled)
if(uart->tx_enabled)
{
if (tx_pin == 2)
if (tx_pin == 2)
{
uart->tx_pin = 2;
pinMode(uart->tx_pin, FUNCTION_4);
}
else
}
else
{
uart->tx_pin = 1;
pinMode(uart->tx_pin, FUNCTION_0);
}
}
else
}
else
{
uart->tx_pin = 255;
}
@ -666,7 +677,7 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
return uart;
}
void
void
uart_uninit(uart_t* uart)
{
if(uart == NULL)
@ -675,7 +686,7 @@ uart_uninit(uart_t* uart)
uart_stop_isr(uart);
if(uart->tx_enabled && (!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0)) {
switch(uart->tx_pin)
switch(uart->tx_pin)
{
case 1:
pinMode(1, INPUT);
@ -693,7 +704,7 @@ uart_uninit(uart_t* uart)
free(uart->rx_buffer->buffer);
free(uart->rx_buffer);
if(!gdbstub_has_uart_isr_control()) {
switch(uart->rx_pin)
switch(uart->rx_pin)
{
case 3:
pinMode(3, INPUT);
@ -707,16 +718,16 @@ uart_uninit(uart_t* uart)
free(uart);
}
void
void
uart_swap(uart_t* uart, int tx_pin)
{
if(uart == NULL)
return;
switch(uart->uart_nr)
switch(uart->uart_nr)
{
case UART0:
if(((uart->tx_pin == 1 || uart->tx_pin == 2) && uart->tx_enabled) || (uart->rx_pin == 3 && uart->rx_enabled))
if(((uart->tx_pin == 1 || uart->tx_pin == 2) && uart->tx_enabled) || (uart->rx_pin == 3 && uart->rx_enabled))
{
if(uart->tx_enabled) //TX
{
@ -728,15 +739,15 @@ uart_swap(uart_t* uart, int tx_pin)
pinMode(uart->rx_pin, INPUT);
uart->rx_pin = 13;
}
if(uart->tx_enabled)
if(uart->tx_enabled)
pinMode(uart->tx_pin, FUNCTION_4); //TX
if(uart->rx_enabled)
pinMode(uart->rx_pin, FUNCTION_4); //RX
IOSWAP |= (1 << IOSWAPU0);
}
else
}
else
{
if(uart->tx_enabled) //TX
{
@ -751,7 +762,7 @@ uart_swap(uart_t* uart, int tx_pin)
if(uart->tx_enabled)
pinMode(uart->tx_pin, (tx_pin == 2)?FUNCTION_4:SPECIAL); //TX
if(uart->rx_enabled)
if(uart->rx_enabled)
pinMode(3, SPECIAL); //RX
IOSWAP &= ~(1 << IOSWAPU0);
@ -765,24 +776,24 @@ uart_swap(uart_t* uart, int tx_pin)
}
}
void
void
uart_set_tx(uart_t* uart, int tx_pin)
{
if(uart == NULL)
return;
switch(uart->uart_nr)
switch(uart->uart_nr)
{
case UART0:
if(uart->tx_enabled)
if(uart->tx_enabled)
{
if (uart->tx_pin == 1 && tx_pin == 2)
if (uart->tx_pin == 1 && tx_pin == 2)
{
pinMode(uart->tx_pin, INPUT);
uart->tx_pin = 2;
pinMode(uart->tx_pin, FUNCTION_4);
}
else if (uart->tx_pin == 2 && tx_pin != 2)
}
else if (uart->tx_pin == 2 && tx_pin != 2)
{
pinMode(uart->tx_pin, INPUT);
uart->tx_pin = 1;
@ -799,7 +810,7 @@ uart_set_tx(uart_t* uart, int tx_pin)
}
}
void
void
uart_set_pins(uart_t* uart, int tx, int rx)
{
if(uart == NULL)
@ -807,13 +818,13 @@ uart_set_pins(uart_t* uart, int tx, int rx)
if(uart->uart_nr == UART0) // Only UART0 allows pin changes
{
if(uart->tx_enabled && uart->tx_pin != tx)
if(uart->tx_enabled && uart->tx_pin != tx)
{
if( rx == 13 && tx == 15)
if( rx == 13 && tx == 15)
{
uart_swap(uart, 15);
}
else if (rx == 3 && (tx == 1 || tx == 2))
}
else if (rx == 3 && (tx == 1 || tx == 2))
{
if (uart->rx_pin != rx)
uart_swap(uart, tx);
@ -827,7 +838,7 @@ uart_set_pins(uart_t* uart, int tx, int rx)
}
bool
bool
uart_tx_enabled(uart_t* uart)
{
if(uart == NULL)
@ -836,7 +847,7 @@ uart_tx_enabled(uart_t* uart)
return uart->tx_enabled;
}
bool
bool
uart_rx_enabled(uart_t* uart)
{
if(uart == NULL)
@ -845,7 +856,7 @@ uart_rx_enabled(uart_t* uart)
return uart->rx_enabled;
}
bool
bool
uart_has_overrun (uart_t* uart)
{
if (uart == NULL || !uart->rx_overrun)
@ -867,7 +878,7 @@ uart_has_rx_error (uart_t* uart)
return true;
}
static void
static void
uart_ignore_char(char c)
{
(void) c;
@ -883,34 +894,42 @@ uart_write_char_delay(const int uart_nr, char c)
}
static void
static void
uart0_write_char(char c)
{
uart_write_char_delay(0, c);
}
static void
static void
uart1_write_char(char c)
{
uart_write_char_delay(1, c);
}
void
void
uart_set_debug(int uart_nr)
{
s_uart_debug_nr = uart_nr;
void (*func)(char) = NULL;
fp_putc_t func = NULL;
switch(s_uart_debug_nr)
{
case UART0:
func = &uart0_write_char;
// This selects the UART for ROM ets_putc which is used by
// ::printf, ets_printf_P in core_esp_postmortem.cpp and others.
// Has a side effect of clearing RX FIFO for UART0
uart_buff_switch(0);
break;
case UART1:
func = &uart1_write_char;
uart_buff_switch(1);
break;
case UART_NO:
default:
func = &uart_ignore_char;
// There is no disable option for ets_putc,
// we switch to UART0 for disable case.
uart_buff_switch(0);
break;
}
if(gdbstub_has_putc1_control()) {
@ -921,11 +940,11 @@ uart_set_debug(int uart_nr)
} else {
system_set_os_print(0);
}
ets_install_putc1((void *) func);
ets_install_putc1(func);
}
}
int
int
uart_get_debug()
{
return s_uart_debug_nr;

View File

@ -147,6 +147,7 @@ int uart_get_debug();
void uart_start_detect_baudrate(int uart_nr);
int uart_detect_baudrate(int uart_nr);
uint8_t uart_get_bit_length(const int uart_nr);
#if defined (__cplusplus)
} // extern "C"

View File

@ -0,0 +1,251 @@
#if 0
/*
* This .h is nothing but comments about thoughts and observations made while
* updating the Arduino ESP8266 Core, with the new upstream umm_malloc. It is
* added as a .h so that it does not get lost and to avoid cluttering up the
* code with a huge block comment.
PR text description:
upstream version of `umm_malloc` customized for Arduino ESP8266 Core
This updates the heap management library, umm_malloc, to the current upstream
version at https://github.com/rhempel/umm_malloc. Some reorganizing and new code
was needed to use the new version.
This is a list of noteworthy changes:
UMM_POISON - now has a lite option as well as the previous intensive check
option. The code for running the full poison test at the call of the various
alloc functions was removed in the upstream version. In this port, the missing
code was added to heap.cpp and umm_local.cpp.
* UMM_POISON - appears to have been partially changed to UMM_POISON_CHECK,
I treat it as deprecated and used UMM_POISON_CHECK when needed.
However, the Arduino Core's references to UMM_POISON were replaced with
UMM_POISON_CHECK_LITE.
* UMM_POISON_CHECK_LITE - Less intense, it just checks poison on active
neighboring allocations.
* UMM_POISON_CHECK - Full heap intensive check of poison
A cautionary note, on the use of UMM_INTEGRITY_CHECK and UMM_POISON_CHECK, and
umm_info(). All of these run with IRQs disabled, for periods that can go into
100's of us. With umm_info(NULL, true) that may go into seconds, depending on
the serial interface speed and the number of memory allocations present. Use
UMM_INTEGRITY_CHECK, UMM_POISON_CHECK, and umm_info() sparingly. If you want to
see numbers for the disabled time, explore using UMM_CRITICAL_METRICS in
umm_malloc_cfg.h.
===============================================================================
New upstream umm_malloc feature delta's from the old umm_malloc we were using:
umm_posion check for a given *alloc - failure - no longer panics.
option to run full poison check at each *alloc call, not present
option to run full interity check at each *alloc call, not present
upstream code does not call panic from poison_check_block.
Defragmenting effect of realloc is gone. It now minimizes copy. This
may have been an accident during code cleanup.
In one form or another these features have been restored in the
reintegration of the upstream umm_malloc into the Arduino ESP8266 Core.
===============================================================================
A list of changes made for local adaptation of newer upstream umm_malloc.
In umm_malloc.c
Renamed to umm_malloc.cpp
Added `extern "C" { ... };` around code.
Surround DBGLOG_LEVEL with #ifndef... Define value of DBGLOG_LEVEL from
umm_malloc_cfg.h
umm_realloc() - Added UMM_CRITICAL_SUSPEND()/UMM_CRITICAL_RESUME() for when
lightweight locks are available. eg. sti/cli. Single threaded single CPU
case.
umm_realloc() - appears to have been refactored to minimize memmove and
memcpy. The old version would always combine an adjacent block in the
direction of the start of the heap when available and do a memmove. This
had a defragging effect. This appears to have been replaced with an attempt
to minimize copy when possible.
Added heap stats tracking.
In umm_info.c
umm_info() - Added UMM_CRITICAL_DECL(id_info), updated critical sections
with tag.
Carried forward: Added NULL ptr check at beginning (umm_malloc.c).
In umm_poison.c:
Resolved C++ compiler error reported on get_poisoned(), and get_unpoisoned().
They now take in void * arg instead of unsigned char *.
Added #if ... || defined(UMM_POISON_CHECK_LITE) to the conditional.
In umm_integrity.c:
Replaced printf with DBGLOG_FUNCTION. This needs to be a malloc free
function and ISR safe.
Added critical sections.
In umm_malloc_cfg.h:
Added macro UMM_CRITICAL_SUSPEND()/UMM_CRITICAL_RESUME()
Globally change across all files %i to %d: umm_info.c, umm_malloc.c,
Added a #ifdef BUILD_UMM_MALLOC_C fence to prevent Arduino IDE from building
the various .c files that are #included into umm_malloc.cpp. They are
normally enabled by #define <feature name> in umm_malloc_cfg.h. In this
case it builds fine; however, if the define is global, the IDE will try and
build the .c by itself.
Notes,
umm_integrity_check() is called by macro INTEGRITY_CHECK which returns 1
on success. No corruption. Does a time consuming scan of the whole heap.
It will call UMM_HEAP_CORRUPTION_CB if an error is found.
umm_poison_check(), formerly known as check_poison_all_blocks(),
is called by macro POISON_CHECK which returns 1 on success for no
corruption. Does a time consuming scan of all active allocations for
modified poison. The new upstream version does *NOT* call
UMM_HEAP_CORRUPTION_CB if an error is found. The option description says
it does!
umm_poison_realloc() and umm_poison_free() no longer call the macro
UMM_HEAP_CORRUPTION_CB on poison error. Just a printf message is
generated. I have added alternative functions umm_poison_free_fl,
umm_poison_realloc_fl, and get_unpoisoned_check_neighbors in
umm_local.cpp. These expand the poison check on the current allocation to
include its nearest allocated neighbors in the heap.
umm_malloc() has been extended to call check_poison_neighbors for the
allocation it selects, conditionally for UMM_POISON_CHECK_LITE.
For upstream umm_malloc "# define POISON_CHECK() 0" should have been 1
add to list to report.
==============================================================================
Notes from searching for the best print option
Printing from the malloc routines is tricky. Since a print library
might call *alloc. Then recursion may follow as each error call may fail
into another error and so on.
Objective: To be able to print "last gasp" diagnostic messages
when interrupts are disabled and w/o availability of heap resources.
It turns out things are more complicated than that. These are three cases for
printing from the heap and the current solution.:
1. Printing detailed heap info through `umm_info(NULL, 1);`. This function
resides in flash and can only be called from non-ISR context. It can use
PROGMEM strings. Because SPI bus will not be busy when called from foreground.
At this time it is believed that, while running from foreground, a cache-miss
at INTLEVEL 15 can be handled. The key factor being the SPI bus is not
busy at the time of the cache-miss. It is not clear what gets invoked to
process the cache-miss. A software vector call? A hardware assisted transfer?
In any case `umm_info_safe_printf_P()` is also in flash.
The focus here is to print w/o allocating memory and use strings
in flash to preserve DRAM.
2. Printing diagnostic messages possibly from from ISR context.
Use `ets_uart_printf()` in boot ROM.
3. Printing diagnostic messages from `heap.cpp` these printf's need to check
`system_get_os_print()` to confirm debug-output is enabled just as
`os_printf()` did.
Do test calls to `system_get_os_print()` and call `ets_uart_printf()`
in boot ROM when debug print allowed.
Considerations:
* can be called from ISR
* can be called from malloc code, cannot use malloc
* can be called from malloc code that was called from an ISR
* can be called from within a critical section, eg. xt_rsil(15);
* this may be effectively the same as being called from an ISR?
Update: Current thinking is that from foreground we have more leeway
than an ISR.
Knowns:
* ets_printf - For RTOS SDK they replaced this function with one in the SDK.
Most of the problems I can see with ets_printf center around not being
able to maintain a port to thread context. That is you cannot have one
thread using one port while another thread uses the other. In the no OS
case we cannot have one area of code using one port and another area of
code using the other port. Most of the ROM printf functions are not built
to support this kind of usage. Things get especially dangerous when you
try to use the ets_external_printf stuff.
* ets_vprintf - by itself is safe.
* newlibc printf - not safe - lives in flash.
* newlibc snprintf - not safe - lives in flash.
* builtin putc1 print function - Is installed when you use
ets_install_uart_printf. Which calls ets_install_putc1. The selection of UART
is performed by calling uart_buff_switch with 0 for UART0 and 1 for UART1.
This should work for our purpose here, if handled as follows:
* call uart_buff_switch at each printf call to reselect UART
* Update: uart_buff_switch is now updated by uart_set_debug() in uart.cpp
* use a stack buffer to hold a copy the PROGMEM string to print from.
* use ets_vprintf for printing with putc1 function.
* os_printf_plus looks interesting. It is in IRAM. If no heap is available it
will use up to 64 bytes of stack space to copy a PROGMEM fmt for printing.
Issues:
* Printing is turned off by system_set_os_print
* putc1 needs to be in IRAM - this is a uart.cpp issue
* Need to force system_get_free_heap_size to return 0 during critical periods.
* won't work for umm_info if it prints over 64 characters.
* along with umm_info there are other debug messages that exceed 64 characters.
* ets_uart_printf - Appears safe. Just no PROGMEM support. Uses
uart_buff_switch to select UART.
===============================================================================
heap.cpp is the entry point for most of the heap API calls.
It is a merge point for abstracted heap API calls, such as _malloc_r,
pvPortMalloc, and malloc. Thin wrappers are created here for these entry points
and others. The wrappers call through to equivalent umm_malloc entry-point.
These wrappers also provide the access points to do debug options, like OOM,
Integrity Check, and Poison Check.
-DEBUG_ESP_OOM or select `Debug Level: "OOM"` from the IDE.
This option will add extra code to save information on the last OOM event. If
your code is built with the `Debug port: "Serial"` option, debug messages will
print on OOM events. You do not have to do `Debug port: "Serial"` to get OOM
debug messages. From within your code, you can make a call to
`Serial.debugOutput(true);` to enable OOM printing. Of course for this to work
your code must be built with `Debug Level: "OOM"` or equal.
-DUUM_POISON is now the same as -DUMM_POISON_CHECK_LITE
This is new behavior with this updated. UMM_POISON_CHECK_LITE - checks the
allocation presented at realloc() and free(). Expands the poison check on the
current allocation to include its nearest allocated neighbors in the heap.
umm_malloc() will also check the neighbors of the selected allocation before
use.
For more details and options search on UMM_POISON_CHECK in `umm_malloc_cfg.h`
TODO: provide some interesting numbers on the time to perform:
* UMM_POISON_CHECK
* UMM_INTEGRITY_CHECK
* umm_info(NUll, 0) built with and without print capability
* umm_info(NUll, 1) printing a report to Serial device.
===============================================================================
Enhancement ideas:
1. Add tagging to heap allocations. Redefine UMM_POISONED_BLOCK_LEN_TYPE,
expand it to include an element for the calling address of allocating
requester. Expand umm_info(NULL, 1) to print the respective address with each
active allocation. The difficulty here will be the ever-growing complexity of
overlapping build options. I think it would be easiest to build this in with
and expand the UMM_POISON_CHECK_LITE option.
2. A build option to not have printing, from umm_info() compiled in. This can
save on the execution time spent with interrupts disabled.
*/
#endif

View File

@ -10,18 +10,18 @@ might get expensive.
## Acknowledgements
Joerg Wunsch and the avr-libc provided the first malloc() implementation
Joerg Wunsch and the avr-libc provided the first `malloc()` implementation
that I examined in detail.
http://www.nongnu.org/avr-libc
`http://www.nongnu.org/avr-libc`
Doug Lea's paper on malloc() was another excellent reference and provides
a lot of detail on advanced memory management techniques such as binning.
http://g.oswego.edu/dl/html/malloc.html
`http://g.oswego.edu/dl/html/malloc.html`
Bill Dittman provided excellent suggestions, including macros to support
using these functions in critical sections, and for optimizing realloc()
using these functions in critical sections, and for optimizing `realloc()`
further by checking to see if the previous block was free and could be
used for the new block size. This can help to reduce heap fragmentation
significantly.
@ -30,11 +30,73 @@ Yaniv Ankin suggested that a way to dump the current heap condition
might be useful. I combined this with an idea from plarroy to also
allow checking a free pointer to make sure it's valid.
Dimitry Frank contributed many helpful additions to make things more
robust including a user specified config file and a method of testing
the integrity of the data structures.
## Usage
Copy the `umm_malloc_cfg_example.h` file to `umm_malloc_cfg.h` and
make the changes required to support your application.
The following `#define`s must be set to something useful for the
library to work at all
- `UMM_MALLOC_CFG_HEAP_ADDR` must be set to the symbol representing
the starting address of the heap. The heap must be
aligned on the natural boundary size of the processor.
- `UMM_MALLOC_CFG_HEAP_SIZE` must be set to the size of the heap.
The heap size must be a multiple of the natural boundary size of
the processor.
The fit algorithm is defined as either:
- `UMM_BEST_FIT` which scans the entire free list and looks
for either an exact fit or the smallest block that will
satisfy the request. This is the default fit method.
- `UMM_FIRST_FIT` which scans the entire free list and looks
for the first block that satisfies the request.
The following `#define`s are disabled by default and should
remain disabled for production use. They are helpful when
testing allocation errors (which are normally due to bugs in
the application code) or for running the test suite when
making changes to the code.
You can define them in your compiler command line or uncomment
the corresponding entries is `umm_malloc_cfg.h`:
- `UMM_INFO` is used to include code that allows dumping
the entire heap structure (helpful when there's a problem).
- `UMM_INTEGRITY_CHECK` is used to include code that
performs an integrity check on the heap structure. It's
up to you to call the `umm_integrity_check()` function.
- `UMM_POISON_CHECK` is used to include code that
adds some bytes around the memory being allocated that
are filled with known data. If the data is not intact
when the block is checked, then somone has written outside
of the memory block they have been allocated. It is up
to you to call the `umm_poison_check()` function.
## API
The following functions are available for your application:
- `void *umm_malloc( size_t size );`
- `void *umm_calloc( size_t num, size_t size );`
- `void *umm_realloc( void *ptr, size_t size );`
- `void umm_free( void *ptr );`
They have exactly the same semantics as the corresponding standard library
functions.
## Background
The memory manager assumes the following things:
1. The standard POSIX compliant malloc/realloc/free semantics are used
1. The standard POSIX compliant malloc/calloc/realloc/free semantics are used
1. All memory used by the manager is allocated at link time, it is aligned
on a 32 bit boundary, it is contiguous, and its extent (start and end
address) is filled in by the linker.
@ -45,17 +107,17 @@ The fastest linked list implementations use doubly linked lists so that
its possible to insert and delete blocks in constant time. This memory
manager keeps track of both free and used blocks in a doubly linked list.
Most memory managers use some kind of list structure made up of pointers
Most memory managers use a list structure made up of pointers
to keep track of used - and sometimes free - blocks of memory. In an
embedded system, this can get pretty expensive as each pointer can use
up to 32 bits.
In most embedded systems there is no need for managing large blocks
of memory dynamically, so a full 32 bit pointer based data structure
In most embedded systems there is no need for managing a large quantity
of memory blocks dynamically, so a full 32 bit pointer based data structure
for the free and used block lists is wasteful. A block of memory on
the free list would use 16 bytes just for the pointers!
This memory management library sees the malloc heap as an array of blocks,
This memory management library sees the heap as an array of blocks,
and uses block numbers to keep track of locations. The block numbers are
15 bits - which allows for up to 32767 blocks of memory. The high order
bit marks a block as being either free or in use, which will be explained
@ -75,7 +137,7 @@ can always add more data bytes to the body of the memory block
at the expense of free block size overhead.
There are a lot of little features and optimizations in this memory
management system that makes it especially suited to small embedded, but
management system that makes it especially suited to small systems, and
the best way to appreciate them is to review the data structures and
algorithms used, so let's get started.
@ -124,10 +186,9 @@ Where:
- n is the index of the next block in the heap
- p is the index of the previous block in the heap
Note that the free list information is gone, because it's now being used to
store actual data for the application. It would have been nice to store
the next and previous free list indexes as well, but that would be a waste
of space. If we had even 500 items in use, that would be 2,000 bytes for
Note that the free list information is gone because it's now
being used to store actual data for the application. If we had
even 500 items in use, that would be 2,000 bytes for
free list information. We simply can't afford to waste that much.
The address of the `...` area is what is returned to the application
@ -143,7 +204,7 @@ described.
`...` between memory blocks indicates zero or more additional blocks are
allocated for use by the upper block.
And while we're talking about "upper" and "lower" blocks, we should make
While we're talking about "upper" and "lower" blocks, we should make
a comment about adresses. In the diagrams, a block higher up in the
picture is at a lower address. And the blocks grow downwards their
block index increases as does their physical address.
@ -166,24 +227,27 @@ we're at the end of the list!
At this point, the malloc has a special test that checks if the current
block index is 0, which it is. This special case initializes the free
list to point at block index 1.
list to point at block index 1 and then points block 1 to the
last block (lf) on the heap.
```
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+
1 | 0 | 0 | 0 | 0 |
1 |*lf | 0 | 0 | 0 |
+----+----+----+----+
...
+----+----+----+----+
lf | 0 | 1 | 0 | 0 |
+----+----+----+----+
```
The heap is now ready to complete the first malloc operation.
### Operation of malloc when we have reached the end of the free list and
there is no block large enough to accommodate the request.
### Operation of malloc when we have reached the end of the free list and there is no block large enough to accommodate the request.
This happens at the very first malloc operation, or any time the free
list is traversed and no free block large enough for the request is
@ -306,8 +370,7 @@ else
```
Step 1 of the free operation checks if the next block is free, and if it
is then insert this block into the free list and assimilate the next block
with this one.
is assimilate the next block with this one.
Note that c is the block we are freeing up, cf is the free block that
follows it.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Ralph Hempel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1 @@
Downloaded from: https://github.com/rhempel/c-helper-macros/tree/develop

View File

@ -0,0 +1,98 @@
/* ----------------------------------------------------------------------------
* dbglog.h - A set of macros that cleans up code that needs to produce debug
* or log information.
*
* Many embedded systems still put a premium on code space and therefore need
* a way to conditionally compile in debug code. Yes, it can lead to code that
* runs differently depending on whether the debug code is cmpiled in or not
* but you need to be able to evaluate the tradeoff.
*
* See copyright notice in LICENSE.TXT
* ----------------------------------------------------------------------------
* NOTE WELL that this file may be included multiple times - this allows you
* to set the trace level #define DBGLOG_LEVEL x
*
* To update which of the DBGLOG macros are compiled in, you must redefine the
* DBGLOG_LEVEL macro and the inlcude the dbglog.h file again, like this:
*
* #undef DBGLOG_LEVEL
* #define DBGLOG_LEVEL 6
* #include "dbglog/dbglog.txt"
*
* To handle multiple inclusion, we need to first undefine any macros we define
* so that the compiler does not warn us that we are changing a macro.
* ----------------------------------------------------------------------------
* The DBGLOG_LEVEL and DBGLOG_FUNCTION should be defined BEFORE this
* file is included or else the following defaults are used:
*
* #define DBGLOG_LEVEL 0
* #define DBGLOG_FUNCTION printf
* ----------------------------------------------------------------------------
* There are macros to handle the following decreasing levels of detail:
*
* 6 = TRACE
* 5 = DEBUG
* 4 = CRITICAL
* 3 = ERROR
* 2 = WARNING
* 1 = INFO
* 0 = FORCE - The DBGLOG_FUNCTION is always compiled in and is called only when
* the first parameter to the macro is non-0
* ----------------------------------------------------------------------------
*/
#undef DBGLOG_TRACE
#undef DBGLOG_DEBUG
#undef DBGLOG_CRITICAL
#undef DBGLOG_ERROR
#undef DBGLOG_WARNING
#undef DBGLOG_INFO
#undef DBGLOG_FORCE
#ifndef DBGLOG_LEVEL
# define DBGLOG_LEVEL 0
#endif
#ifndef DBGLOG_FUNCTION
# define DBGLOG_FUNCTION printf
#endif
/* ------------------------------------------------------------------------- */
#if DBGLOG_LEVEL >= 6
# define DBGLOG_TRACE(format, ...) DBGLOG_FUNCTION(format, ## __VA_ARGS__)
#else
# define DBGLOG_TRACE(format, ...)
#endif
#if DBGLOG_LEVEL >= 5
# define DBGLOG_DEBUG(format, ...) DBGLOG_FUNCTION(format, ## __VA_ARGS__)
#else
# define DBGLOG_DEBUG(format, ...)
#endif
#if DBGLOG_LEVEL >= 4
# define DBGLOG_CRITICAL(format, ...) DBGLOG_FUNCTION(format, ## __VA_ARGS__)
#else
# define DBGLOG_CRITICAL(format, ...)
#endif
#if DBGLOG_LEVEL >= 3
# define DBGLOG_ERROR(format, ...) DBGLOG_FUNCTION(format, ## __VA_ARGS__)
#else
# define DBGLOG_ERROR(format, ...)
#endif
#if DBGLOG_LEVEL >= 2
# define DBGLOG_WARNING(format, ...) DBGLOG_FUNCTION(format, ## __VA_ARGS__)
#else
# define DBGLOG_WARNING(format, ...)
#endif
#if DBGLOG_LEVEL >= 1
# define DBGLOG_INFO(format, ...) DBGLOG_FUNCTION(format, ## __VA_ARGS__)
#else
# define DBGLOG_INFO(format, ...)
#endif
#define DBGLOG_FORCE(force, format, ...) {if(force) {DBGLOG_FUNCTION(format, ## __VA_ARGS__);}}

View File

@ -0,0 +1,185 @@
#if defined(BUILD_UMM_MALLOC_C)
#ifdef UMM_INFO
/* ----------------------------------------------------------------------------
* One of the coolest things about this little library is that it's VERY
* easy to get debug information about the memory heap by simply iterating
* through all of the memory blocks.
*
* As you go through all the blocks, you can check to see if it's a free
* block by looking at the high order bit of the next block index. You can
* also see how big the block is by subtracting the next block index from
* the current block number.
*
* The umm_info function does all of that and makes the results available
* in the ummHeapInfo structure.
* ----------------------------------------------------------------------------
*/
UMM_HEAP_INFO ummHeapInfo;
void *umm_info( void *ptr, int force ) {
UMM_CRITICAL_DECL(id_info);
unsigned short int blockNo = 0;
if (umm_heap == NULL) {
umm_init();
}
/* Protect the critical section... */
UMM_CRITICAL_ENTRY(id_info);
/*
* Clear out all of the entries in the ummHeapInfo structure before doing
* any calculations..
*/
memset( &ummHeapInfo, 0, sizeof( ummHeapInfo ) );
DBGLOG_FORCE( force, "\n" );
DBGLOG_FORCE( force, "+----------+-------+--------+--------+-------+--------+--------+\n" );
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5d|NF %5d|PF %5d|\n",
(unsigned long)(&UMM_BLOCK(blockNo)),
blockNo,
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
UMM_PBLOCK(blockNo),
(UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK )-blockNo,
UMM_NFREE(blockNo),
UMM_PFREE(blockNo) );
/*
* Now loop through the block lists, and keep track of the number and size
* of used and free blocks. The terminating condition is an nb pointer with
* a value of zero...
*/
blockNo = UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK;
while( UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK ) {
size_t curBlocks = (UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK )-blockNo;
++ummHeapInfo.totalEntries;
ummHeapInfo.totalBlocks += curBlocks;
/* Is this a free block? */
if( UMM_NBLOCK(blockNo) & UMM_FREELIST_MASK ) {
++ummHeapInfo.freeEntries;
ummHeapInfo.freeBlocks += curBlocks;
ummHeapInfo.freeSize2 += (unsigned int)curBlocks
* (unsigned int)sizeof(umm_block)
* (unsigned int)curBlocks
* (unsigned int)sizeof(umm_block);
if (ummHeapInfo.maxFreeContiguousBlocks < curBlocks) {
ummHeapInfo.maxFreeContiguousBlocks = curBlocks;
}
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5u|NF %5d|PF %5d|\n",
(unsigned long)(&UMM_BLOCK(blockNo)),
blockNo,
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
UMM_PBLOCK(blockNo),
(unsigned int)curBlocks,
UMM_NFREE(blockNo),
UMM_PFREE(blockNo) );
/* Does this block address match the ptr we may be trying to free? */
if( ptr == &UMM_BLOCK(blockNo) ) {
/* Release the critical section... */
UMM_CRITICAL_EXIT(id_info);
return( ptr );
}
} else {
++ummHeapInfo.usedEntries;
ummHeapInfo.usedBlocks += curBlocks;
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5u|\n",
(unsigned long)(&UMM_BLOCK(blockNo)),
blockNo,
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
UMM_PBLOCK(blockNo),
(unsigned int)curBlocks );
}
blockNo = UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK;
}
/*
* Update the accounting totals with information from the last block, the
* rest must be free!
*/
{
size_t curBlocks = UMM_NUMBLOCKS-blockNo;
ummHeapInfo.freeBlocks += curBlocks;
ummHeapInfo.totalBlocks += curBlocks;
if (ummHeapInfo.maxFreeContiguousBlocks < curBlocks) {
ummHeapInfo.maxFreeContiguousBlocks = curBlocks;
}
}
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5d|NF %5d|PF %5d|\n",
(unsigned long)(&UMM_BLOCK(blockNo)),
blockNo,
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
UMM_PBLOCK(blockNo),
UMM_NUMBLOCKS-blockNo,
UMM_NFREE(blockNo),
UMM_PFREE(blockNo) );
DBGLOG_FORCE( force, "+----------+-------+--------+--------+-------+--------+--------+\n" );
DBGLOG_FORCE( force, "Total Entries %5d Used Entries %5d Free Entries %5d\n",
ummHeapInfo.totalEntries,
ummHeapInfo.usedEntries,
ummHeapInfo.freeEntries );
DBGLOG_FORCE( force, "Total Blocks %5d Used Blocks %5d Free Blocks %5d\n",
ummHeapInfo.totalBlocks,
ummHeapInfo.usedBlocks,
ummHeapInfo.freeBlocks );
DBGLOG_FORCE( force, "+--------------------------------------------------------------+\n" );
#if defined(UMM_STATS) || defined(UMM_STATS_FULL)
if (ummHeapInfo.freeBlocks == ummStats.free_blocks) {
DBGLOG_FORCE( force, "heap info Free blocks and heap statistics Free blocks match.\n");
} else {
DBGLOG_FORCE( force, "\nheap info Free blocks %5d != heap statistics Free Blocks %5d\n\n",
ummHeapInfo.freeBlocks,
ummStats.free_blocks );
}
DBGLOG_FORCE( force, "+--------------------------------------------------------------+\n" );
print_stats(force);
#endif
/* Release the critical section... */
UMM_CRITICAL_EXIT(id_info);
return( NULL );
}
/* ------------------------------------------------------------------------ */
size_t umm_free_heap_size( void ) {
umm_info(NULL, 0);
return (size_t)ummHeapInfo.freeBlocks * sizeof(umm_block);
}
size_t umm_max_block_size( void ) {
umm_info(NULL, 0);
return ummHeapInfo.maxFreeContiguousBlocks * sizeof(umm_block);
}
/* ------------------------------------------------------------------------ */
#endif
#endif // defined(BUILD_UMM_MALLOC_C)

View File

@ -0,0 +1,134 @@
#if defined(BUILD_UMM_MALLOC_C)
/* integrity check (UMM_INTEGRITY_CHECK) {{{ */
#if defined(UMM_INTEGRITY_CHECK)
/*
* Perform integrity check of the whole heap data. Returns 1 in case of
* success, 0 otherwise.
*
* First of all, iterate through all free blocks, and check that all backlinks
* match (i.e. if block X has next free block Y, then the block Y should have
* previous free block set to X).
*
* Additionally, we check that each free block is correctly marked with
* `UMM_FREELIST_MASK` on the `next` pointer: during iteration through free
* list, we mark each free block by the same flag `UMM_FREELIST_MASK`, but
* on `prev` pointer. We'll check and unmark it later.
*
* Then, we iterate through all blocks in the heap, and similarly check that
* all backlinks match (i.e. if block X has next block Y, then the block Y
* should have previous block set to X).
*
* But before checking each backlink, we check that the `next` and `prev`
* pointers are both marked with `UMM_FREELIST_MASK`, or both unmarked.
* This way, we ensure that the free flag is in sync with the free pointers
* chain.
*/
int umm_integrity_check(void) {
UMM_CRITICAL_DECL(id_integrity);
int ok = 1;
unsigned short int prev;
unsigned short int cur;
if (umm_heap == NULL) {
umm_init();
}
/* Iterate through all free blocks */
prev = 0;
UMM_CRITICAL_ENTRY(id_integrity);
while(1) {
cur = UMM_NFREE(prev);
/* Check that next free block number is valid */
if (cur >= UMM_NUMBLOCKS) {
DBGLOG_FUNCTION("heap integrity broken: too large next free num: %d "
"(in block %d, addr 0x%lx)\n", cur, prev,
(unsigned long)&UMM_NBLOCK(prev));
ok = 0;
goto clean;
}
if (cur == 0) {
/* No more free blocks */
break;
}
/* Check if prev free block number matches */
if (UMM_PFREE(cur) != prev) {
DBGLOG_FUNCTION("heap integrity broken: free links don't match: "
"%d -> %d, but %d -> %d\n",
prev, cur, cur, UMM_PFREE(cur));
ok = 0;
goto clean;
}
UMM_PBLOCK(cur) |= UMM_FREELIST_MASK;
prev = cur;
}
/* Iterate through all blocks */
prev = 0;
while(1) {
cur = UMM_NBLOCK(prev) & UMM_BLOCKNO_MASK;
/* Check that next block number is valid */
if (cur >= UMM_NUMBLOCKS) {
DBGLOG_FUNCTION("heap integrity broken: too large next block num: %d "
"(in block %d, addr 0x%lx)\n", cur, prev,
(unsigned long)&UMM_NBLOCK(prev));
ok = 0;
goto clean;
}
if (cur == 0) {
/* No more blocks */
break;
}
/* make sure the free mark is appropriate, and unmark it */
if ((UMM_NBLOCK(cur) & UMM_FREELIST_MASK)
!= (UMM_PBLOCK(cur) & UMM_FREELIST_MASK))
{
DBGLOG_FUNCTION("heap integrity broken: mask wrong at addr 0x%lx: n=0x%x, p=0x%x\n",
(unsigned long)&UMM_NBLOCK(cur),
(UMM_NBLOCK(cur) & UMM_FREELIST_MASK),
(UMM_PBLOCK(cur) & UMM_FREELIST_MASK)
);
ok = 0;
goto clean;
}
/* make sure the block list is sequential */
if (cur <= prev ) {
DBGLOG_FUNCTION("heap integrity broken: next block %d is before prev this one "
"(in block %d, addr 0x%lx)\n", cur, prev,
(unsigned long)&UMM_NBLOCK(prev));
ok = 0;
goto clean;
}
/* unmark */
UMM_PBLOCK(cur) &= UMM_BLOCKNO_MASK;
/* Check if prev block number matches */
if (UMM_PBLOCK(cur) != prev) {
DBGLOG_FUNCTION("heap integrity broken: block links don't match: "
"%d -> %d, but %d -> %d\n",
prev, cur, cur, UMM_PBLOCK(cur));
ok = 0;
goto clean;
}
prev = cur;
}
clean:
UMM_CRITICAL_EXIT(id_integrity);
if (!ok){
UMM_HEAP_CORRUPTION_CB();
}
return ok;
}
#endif
/* }}} */
#endif // defined(BUILD_UMM_MALLOC_C)

View File

@ -0,0 +1,215 @@
/*
* Local Additions/Enhancements
*
*/
#if defined(BUILD_UMM_MALLOC_C)
#if defined(UMM_CRITICAL_METRICS)
/*
* umm_malloc performance measurments for critical sections
*/
UMM_TIME_STATS time_stats = {
{0xFFFFFFFF, 0U, 0U, 0U},
{0xFFFFFFFF, 0U, 0U, 0U},
{0xFFFFFFFF, 0U, 0U, 0U},
#ifdef UMM_INFO
{0xFFFFFFFF, 0U, 0U, 0U},
#endif
#ifdef UMM_POISON_CHECK
{0xFFFFFFFF, 0U, 0U, 0U},
#endif
#ifdef UMM_INTEGRITY_CHECK
{0xFFFFFFFF, 0U, 0U, 0U},
#endif
{0xFFFFFFFF, 0U, 0U, 0U} };
bool ICACHE_FLASH_ATTR get_umm_get_perf_data(UMM_TIME_STATS *p, size_t size)
{
UMM_CRITICAL_DECL(id_no_tag);
if (p && sizeof(time_stats) == size)
{
UMM_CRITICAL_ENTRY(id_no_tag);
memcpy(p, &time_stats, size);
UMM_CRITICAL_EXIT(id_no_tag);
return true;
}
return false;
}
#endif
// Alternate Poison functions
#if defined(UMM_POISON_CHECK_LITE)
// We skip this when doing the full poison check.
static int check_poison_neighbors( unsigned short cur ) {
unsigned short int c;
if ( 0 == cur )
return 1;
c = UMM_PBLOCK(cur) & UMM_BLOCKNO_MASK;
while( c && (UMM_NBLOCK(c) & UMM_BLOCKNO_MASK) ) {
/*
There can be up to 1 free block neighbor in either direction.
This loop should self limit to 2 passes, due to heap design.
i.e. Adjacent free space is always consolidated.
*/
if ( !(UMM_NBLOCK(c) & UMM_FREELIST_MASK) ) {
if ( !check_poison_block(&UMM_BLOCK(c)) )
return 0;
break;
}
c = UMM_PBLOCK(c) & UMM_BLOCKNO_MASK;
}
c = UMM_NBLOCK(cur) & UMM_BLOCKNO_MASK;
while( (UMM_NBLOCK(c) & UMM_BLOCKNO_MASK) ) {
if ( !(UMM_NBLOCK(c) & UMM_FREELIST_MASK) ) {
if ( !check_poison_block(&UMM_BLOCK(c)) )
return 0;
break;
}
c = UMM_NBLOCK(c) & UMM_BLOCKNO_MASK;
}
return 1;
}
#endif
#if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE)
/* ------------------------------------------------------------------------ */
static void *get_unpoisoned_check_neighbors( void *v_ptr, const char* file, int line ) {
unsigned char *ptr = (unsigned char *)v_ptr;
if (ptr != NULL) {
ptr -= (sizeof(UMM_POISONED_BLOCK_LEN_TYPE) + UMM_POISON_SIZE_BEFORE);
#if defined(UMM_POISON_CHECK_LITE)
UMM_CRITICAL_DECL(id_poison);
unsigned short int c;
bool poison = false;
/* Figure out which block we're in. Note the use of truncated division... */
c = (((char *)ptr)-(char *)(&(umm_heap[0])))/sizeof(umm_block);
UMM_CRITICAL_ENTRY(id_poison);
poison = check_poison_block(&UMM_BLOCK(c)) && check_poison_neighbors(c);
UMM_CRITICAL_EXIT(id_poison);
if (!poison) {
if (file) {
__panic_func(file, line, "");
} else {
abort();
}
}
#else
/*
* No need to check poison here. POISON_CHECK() has already done a
* full heap check.
*/
(void)file;
(void)line;
#endif
}
return (void *)ptr;
}
/* ------------------------------------------------------------------------ */
void *umm_poison_realloc_fl(void *ptr, size_t size, const char* file, int line) {
void *ret;
ptr = get_unpoisoned_check_neighbors(ptr, file, line);
size += poison_size(size);
ret = umm_realloc(ptr, size);
ret = get_poisoned(ret, size);
return ret;
}
/* ------------------------------------------------------------------------ */
void umm_poison_free_fl(void *ptr, const char* file, int line) {
ptr = get_unpoisoned_check_neighbors(ptr, file, line);
umm_free(ptr);
}
#endif
/* ------------------------------------------------------------------------ */
#if defined(UMM_STATS) || defined(UMM_STATS_FULL) || defined(UMM_INFO)
size_t umm_block_size( void ) {
return sizeof(umm_block);
}
#endif
#if defined(UMM_STATS) || defined(UMM_STATS_FULL)
UMM_STATISTICS ummStats;
// Keep complete call path in IRAM
size_t umm_free_heap_size_lw( void ) {
return (size_t)ummStats.free_blocks * sizeof(umm_block);
}
#endif
/*
I assume xPortGetFreeHeapSize needs to be in IRAM. Since
system_get_free_heap_size is in IRAM. Which would mean, umm_free_heap_size()
in flash, was not a safe alternative for returning the same information.
*/
#if defined(UMM_STATS) || defined(UMM_STATS_FULL)
size_t xPortGetFreeHeapSize(void) __attribute__ ((alias("umm_free_heap_size_lw")));
#elif defined(UMM_INFO)
#warning "No ISR safe function available to implement xPortGetFreeHeapSize()"
size_t xPortGetFreeHeapSize(void) __attribute__ ((alias("umm_free_heap_size")));
#endif
#if defined(UMM_STATS) || defined(UMM_STATS_FULL)
void print_stats(int force) {
DBGLOG_FORCE( force, "umm heap statistics:\n");
DBGLOG_FORCE( force, " Free Space %5u\n", ummStats.free_blocks * sizeof(umm_block));
DBGLOG_FORCE( force, " OOM Count %5u\n", ummStats.oom_count);
#if defined(UMM_STATS_FULL)
DBGLOG_FORCE( force, " Low Watermark %5u\n", ummStats.free_blocks_min * sizeof(umm_block));
DBGLOG_FORCE( force, " Low Watermark ISR %5u\n", ummStats.free_blocks_isr_min * sizeof(umm_block));
DBGLOG_FORCE( force, " MAX Alloc Request %5u\n", ummStats.alloc_max_size);
#endif
DBGLOG_FORCE( force, " Size of umm_block %5u\n", sizeof(umm_block));
DBGLOG_FORCE( force, "+--------------------------------------------------------------+\n" );
}
#endif
int ICACHE_FLASH_ATTR umm_info_safe_printf_P(const char *fmt, ...) {
/*
To use ets_strlen() and ets_strcpy() safely with PROGMEM, flash storage,
the PROGMEM address must be word (4 bytes) aligned. The destination
address for ets_memcpy must also be word-aligned.
*/
char ram_buf[ets_strlen(fmt)] __attribute__ ((aligned(4)));
ets_strcpy(ram_buf, fmt);
va_list argPtr;
va_start(argPtr, fmt);
int result = ets_vprintf(ets_uart_putc1, ram_buf, argPtr);
va_end(argPtr);
return result;
}
#endif // BUILD_UMM_MALLOC_C

View File

@ -0,0 +1,54 @@
#ifndef _UMM_LOCAL_H
#define _UMM_LOCAL_H
/*
* A home for local items exclusive to umm_malloc.c and not to be shared in
* umm_malloc_cfg.h. And, not for upstream version.
* Also used to redefine defines made in upstream files we donet want to edit.
*
*/
#undef memcpy
#undef memmove
#undef memset
#define memcpy ets_memcpy
#define memmove ets_memmove
#define memset ets_memset
/*
* This redefines DBGLOG_FORCE defined in dbglog/dbglog.h
* Just for printing from umm_info() which is assumed to always be called from
* non-ISR. Thus SPI bus is available to handle cache-miss and reading a flash
* string while INTLEVEL is non-zero.
*/
#undef DBGLOG_FORCE
#define DBGLOG_FORCE(force, format, ...) {if(force) {UMM_INFO_PRINTF(format, ## __VA_ARGS__);}}
// #define DBGLOG_FORCE(force, format, ...) {if(force) {::printf(PSTR(format), ## __VA_ARGS__);}}
#if defined(DEBUG_ESP_OOM) || defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) || defined(UMM_INTEGRITY_CHECK)
#else
#define umm_malloc(s) malloc(s)
#define umm_calloc(n,s) calloc(n,s)
#define umm_realloc(p,s) realloc(p,s)
#define umm_free(p) free(p)
#endif
#if defined(UMM_POISON_CHECK_LITE)
static int check_poison_neighbors( unsigned short cur );
#endif
#if defined(UMM_STATS) || defined(UMM_STATS_FULL)
void ICACHE_FLASH_ATTR print_stats(int force);
#endif
int ICACHE_FLASH_ATTR umm_info_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
#define UMM_INFO_PRINTF(fmt, ...) umm_info_safe_printf_P(PSTR(fmt), ##__VA_ARGS__)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -10,41 +10,18 @@
/* ------------------------------------------------------------------------ */
//C This include is not in upstream neither are the #ifdef __cplusplus
#include "umm_malloc_cfg.h" /* user-dependent */
#ifdef __cplusplus
extern "C" {
#endif
typedef struct UMM_HEAP_INFO_t {
unsigned short int totalEntries;
unsigned short int usedEntries;
unsigned short int freeEntries;
unsigned short int totalBlocks;
unsigned short int usedBlocks;
unsigned short int freeBlocks;
unsigned short int maxFreeContiguousBlocks;
unsigned int freeSize2;
}
UMM_HEAP_INFO;
extern UMM_HEAP_INFO ummHeapInfo;
void umm_init( void );
void *umm_info( void *ptr, int force );
void umm_init( void );
void *umm_malloc( size_t size );
void *umm_calloc( size_t num, size_t size );
void *umm_realloc( void *ptr, size_t size );
void umm_free( void *ptr );
size_t umm_free_heap_size( void );
size_t umm_max_block_size( void );
size_t umm_block_size( void );
void umm_free( void *ptr );
#ifdef __cplusplus
}

View File

@ -1,11 +1,17 @@
/*
* Configuration for umm_malloc
* Configuration for umm_malloc - target Arduino ESP8266 core
*
* Changes specific to a target platform go here.
*
*/
#ifndef _UMM_MALLOC_CFG_H
#define _UMM_MALLOC_CFG_H
#include <debug.h>
#include <pgmspace.h>
#include <esp8266_undocumented.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -15,19 +21,6 @@ extern "C" {
#include <osapi.h>
#include "c_types.h"
#include "umm_performance.h"
#include "umm_stats.h"
#undef DBGLOG_FUNCTION
#if defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_ISR)
int _isr_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
// Note, _isr_safe_printf_P will not handle additional string arguments in
// PROGMEM. Only the 1st parameter, fmt, is supported in PROGMEM.
#define DBGLOG_FUNCTION(fmt, ...) _isr_safe_printf_P(PSTR(fmt), ##__VA_ARGS__)
#else
// Macro to place constant strings into PROGMEM and print them properly
#define DBGLOG_FUNCTION(fmt, ...) printf(PSTR(fmt), ## __VA_ARGS__ )
#endif
/*
* There are a number of defines you can set at compile time that affect how
@ -37,19 +30,7 @@ int _isr_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2)
*
* -D UMM_TEST_MAIN
*
* Set this if you want to compile in the test suite at the end of this file.
*
* If you leave this define unset, then you might want to set another one:
*
* -D UMM_REDEFINE_MEM_FUNCTIONS
*
* If you leave this define unset, then the function names are left alone as
* umm_malloc() umm_free() and umm_realloc() so that they cannot be confused
* with the C runtime functions malloc() free() and realloc()
*
* If you do set this define, then the function names become malloc()
* free() and realloc() so that they can be used as the C runtime functions
* in an embedded environment.
* Set this if you want to compile in the test suite
*
* -D UMM_BEST_FIT (defualt)
*
@ -75,46 +56,300 @@ int _isr_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2)
* ----------------------------------------------------------------------------
*/
/////////////////////////////////////////////////
#ifdef DEBUG_ESP_OOM
#define MEMLEAK_DEBUG
// umm_*alloc are not renamed to *alloc
void *umm_malloc( size_t size );
void *umm_calloc( size_t num, size_t size );
void *umm_realloc( void *ptr, size_t size );
#define umm_free free
#define umm_zalloc(s) umm_calloc(1,s)
void* malloc_loc (size_t s, const char* file, int line);
void* calloc_loc (size_t n, size_t s, const char* file, int line);
void* realloc_loc (void* p, size_t s, const char* file, int line);
// *alloc are macro calling *alloc_loc calling+checking umm_*alloc()
// they are defined at the bottom of this file
/////////////////////////////////////////////////
#else // !defined(ESP_DEBUG_OOM)
// umm_*alloc are renamed to *alloc
#define UMM_REDEFINE_MEM_FUNCTIONS
#ifdef TEST_BUILD
extern char test_umm_heap[];
#endif
#define UMM_BEST_FIT
#ifdef TEST_BUILD
/* Start addresses and the size of the heap */
#define UMM_MALLOC_CFG_HEAP_ADDR (test_umm_heap)
#define UMM_MALLOC_CFG_HEAP_SIZE 0x10000
#else
/* Start addresses and the size of the heap */
extern char _heap_start[];
#define UMM_MALLOC_CFG__HEAP_ADDR ((uint32_t)&_heap_start)
#define UMM_MALLOC_CFG__HEAP_SIZE ((size_t)(0x3fffc000 - UMM_MALLOC_CFG__HEAP_ADDR))
#define UMM_MALLOC_CFG_HEAP_ADDR ((uint32_t)&_heap_start[0])
#define UMM_MALLOC_CFG_HEAP_SIZE ((size_t)(0x3fffc000 - UMM_MALLOC_CFG_HEAP_ADDR))
#endif
/* A couple of macros to make packing structures less compiler dependent */
#define UMM_H_ATTPACKPRE
#define UMM_H_ATTPACKSUF __attribute__((__packed__))
#define UMM_BEST_FIT
#undef UMM_FIRST_FIT
/*
* -D UMM_INFO :
*
* Enables a dup of the heap contents and a function to return the total
* heap size that is unallocated - note this is not the same as the largest
* unallocated block on the heap!
*/
#define UMM_INFO
#ifdef UMM_INFO
typedef struct UMM_HEAP_INFO_t {
unsigned short int totalEntries;
unsigned short int usedEntries;
unsigned short int freeEntries;
unsigned short int totalBlocks;
unsigned short int usedBlocks;
unsigned short int freeBlocks;
unsigned short int maxFreeContiguousBlocks;
unsigned int freeSize2;
}
UMM_HEAP_INFO;
extern UMM_HEAP_INFO ummHeapInfo;
void ICACHE_FLASH_ATTR *umm_info( void *ptr, int force );
size_t ICACHE_FLASH_ATTR umm_free_heap_size( void );
size_t ICACHE_FLASH_ATTR umm_max_block_size( void );
#else
#endif
/*
* -D UMM_STATS :
* -D UMM_STATS_FULL
*
* This option provides a lightweight alternative to using `umm_info` just for
* getting `umm_free_heap_size`. With this option, a "free blocks" value is
* updated on each call to malloc/free/realloc. This option does not offer all
* the information that `umm_info` would have generated.
*
* This option is good for cases where the free heap is checked frequently. An
* example is when an app closely monitors free heap to detect memory leaks. In
* this case a single-core CPUs interrupt processing would have suffered the
* most.
*
* UMM_STATS_FULL provides additional heap statistics. It can be used to gain
* additional insight into heap usage. This option would add an additional 132
* bytes of IRAM.
*
* Status: TODO: Needs to be proposed for upstream.
*/
/*
#define UMM_STATS
#define UMM_STATS_FULL
*/
/*
* For the ESP8266 we want at lest UMM_STATS built, so we have an ISR safe
* function to call for implementing xPortGetFreeHeapSize(), because umm_info()
* is in flash.
*/
#if !defined(UMM_STATS) && !defined(UMM_STATS_FULL)
#define UMM_STATS
#endif
#if defined(UMM_STATS) && defined(UMM_STATS_FULL)
#undef UMM_STATS
#endif
#if defined(UMM_STATS) || defined(UMM_STATS_FULL)
typedef struct UMM_STATISTICS_t {
unsigned short int free_blocks;
size_t oom_count;
#ifdef UMM_STATS_FULL
unsigned short int free_blocks_min;
unsigned short int free_blocks_isr_min;
size_t alloc_max_size;
size_t last_alloc_size;
size_t id_malloc_count;
size_t id_malloc_zero_count;
size_t id_realloc_count;
size_t id_realloc_zero_count;
size_t id_free_count;
size_t id_free_null_count;
#endif
}
UMM_STATISTICS;
extern UMM_STATISTICS ummStats;
#define STATS__FREE_BLOCKS_UPDATE(s) ummStats.free_blocks += (s)
#define STATS__OOM_UPDATE() ummStats.oom_count += 1
size_t umm_free_heap_size_lw( void );
static inline size_t ICACHE_FLASH_ATTR umm_get_oom_count( void ) {
return ummStats.oom_count;
}
#else // not UMM_STATS or UMM_STATS_FULL
#define STATS__FREE_BLOCKS_UPDATE(s) (void)(s)
#define STATS__OOM_UPDATE() (void)0
#endif
#if defined(UMM_STATS) || defined(UMM_STATS_FULL) || defined(UMM_INFO)
size_t ICACHE_FLASH_ATTR umm_block_size( void );
#endif
#ifdef UMM_STATS_FULL
#define STATS__FREE_BLOCKS_MIN() \
do { \
if (ummStats.free_blocks < ummStats.free_blocks_min) \
ummStats.free_blocks_min = ummStats.free_blocks; \
} while(false)
#define STATS__FREE_BLOCKS_ISR_MIN() \
do { \
if (ummStats.free_blocks < ummStats.free_blocks_isr_min) \
ummStats.free_blocks_isr_min = ummStats.free_blocks; \
} while(false)
#define STATS__ALLOC_REQUEST(tag, s) \
do { \
ummStats.tag##_count += 1; \
ummStats.last_alloc_size = s; \
if (ummStats.alloc_max_size < s) \
ummStats.alloc_max_size = s; \
} while(false)
#define STATS__ZERO_ALLOC_REQUEST(tag, s) \
do { \
ummStats.tag##_zero_count += 1; \
} while(false)
#define STATS__NULL_FREE_REQUEST(tag) \
do { \
ummStats.tag##_null_count += 1; \
} while(false)
#define STATS__FREE_REQUEST(tag) \
do { \
ummStats.tag##_count += 1; \
} while(false)
static inline size_t ICACHE_FLASH_ATTR umm_free_heap_size_lw_min( void ) {
return (size_t)ummStats.free_blocks_min * umm_block_size();
}
static inline size_t ICACHE_FLASH_ATTR umm_free_heap_size_min_reset( void ) {
ummStats.free_blocks_min = ummStats.free_blocks;
return (size_t)ummStats.free_blocks_min * umm_block_size();
}
static inline size_t ICACHE_FLASH_ATTR umm_free_heap_size_min( void ) {
return ummStats.free_blocks_min * umm_block_size();
}
static inline size_t ICACHE_FLASH_ATTR umm_free_heap_size_isr_min( void ) {
return ummStats.free_blocks_isr_min * umm_block_size();
}
static inline size_t ICACHE_FLASH_ATTR umm_get_max_alloc_size( void ) {
return ummStats.alloc_max_size;
}
static inline size_t ICACHE_FLASH_ATTR umm_get_last_alloc_size( void ) {
return ummStats.last_alloc_size;
}
static inline size_t ICACHE_FLASH_ATTR umm_get_malloc_count( void ) {
return ummStats.id_malloc_count;
}
static inline size_t ICACHE_FLASH_ATTR umm_get_malloc_zero_count( void ) {
return ummStats.id_malloc_zero_count;
}
static inline size_t ICACHE_FLASH_ATTR umm_get_realloc_count( void ) {
return ummStats.id_realloc_count;
}
static inline size_t ICACHE_FLASH_ATTR umm_get_realloc_zero_count( void ) {
return ummStats.id_realloc_zero_count;
}
static inline size_t ICACHE_FLASH_ATTR umm_get_free_count( void ) {
return ummStats.id_free_count;
}
static inline size_t ICACHE_FLASH_ATTR umm_get_free_null_count( void ) {
return ummStats.id_free_null_count;
}
#else // Not UMM_STATS_FULL
#define STATS__FREE_BLOCKS_MIN() (void)0
#define STATS__FREE_BLOCKS_ISR_MIN() (void)0
#define STATS__ALLOC_REQUEST(tag, s) (void)(s)
#define STATS__ZERO_ALLOC_REQUEST(tag, s) (void)(s)
#define STATS__NULL_FREE_REQUEST(tag) (void)0
#define STATS__FREE_REQUEST(tag) (void)0
#endif
/*
Per Devyte, the core currently doesn't support masking a specific interrupt
level. That doesn't mean it can't be implemented, only that at this time
locking is implemented as all or nothing.
https://github.com/esp8266/Arduino/issues/6246#issuecomment-508612609
So for now we default to all, 15.
*/
#ifndef DEFAULT_CRITICAL_SECTION_INTLEVEL
#define DEFAULT_CRITICAL_SECTION_INTLEVEL 15
#endif
/*
* -D UMM_CRITICAL_METRICS
*
* Build option to collect timing usage data on critical section usage in
* functions: info, malloc, realloc. Collects MIN, MAX, and number of time IRQs
* were disabled at request time. Note, for realloc MAX disabled time will
* include the time spent in calling malloc and/or free. Examine code for
* specifics on what info is available and how to access.
*
* Status: TODO: Needs to be proposed for upstream. Also should include updates
* to UMM_POISON_CHECK and UMM_INTEGRITY_CHECK to include a critical section.
*/
/*
#define UMM_CRITICAL_METRICS
*/
#if defined(UMM_CRITICAL_METRICS)
// This option adds support for gathering time locked data
typedef struct UMM_TIME_STAT_t {
uint32_t min;
uint32_t max;
uint32_t start;
uint32_t intlevel;
}
UMM_TIME_STAT;
typedef struct UMM_TIME_STATS_t UMM_TIME_STATS;
extern UMM_TIME_STATS time_stats;
bool get_umm_get_perf_data(UMM_TIME_STATS *p, size_t size);
static inline void _critical_entry(UMM_TIME_STAT *p, uint32_t *saved_ps) {
*saved_ps = xt_rsil(DEFAULT_CRITICAL_SECTION_INTLEVEL);
if (0U != (*saved_ps & 0x0FU)) {
p->intlevel += 1U;
}
p->start = esp_get_cycle_count();
}
static inline void _critical_exit(UMM_TIME_STAT *p, uint32_t *saved_ps) {
uint32_t elapse = esp_get_cycle_count() - p->start;
if (elapse < p->min)
p->min = elapse;
if (elapse > p->max)
p->max = elapse;
xt_wsr_ps(*saved_ps);
}
#endif
/*
* A couple of macros to make it easier to protect the memory allocator
* in a multitasking system. You should set these macros up to use whatever
@ -125,23 +360,82 @@ extern char _heap_start[];
* called from within umm_malloc()
*/
#if defined(UMM_CRITICAL_PERIOD_ANALYZE)
#define UMM_CRITICAL_DECL(tag) uint32_t _saved_ps_##tag
#define UMM_CRITICAL_ENTRY(tag) _critical_entry(&time_stats.tag, &_saved_ps_##tag)
#define UMM_CRITICAL_EXIT(tag) _critical_exit(&time_stats.tag, &_saved_ps_##tag)
#ifdef TEST_BUILD
extern int umm_critical_depth;
extern int umm_max_critical_depth;
#define UMM_CRITICAL_ENTRY() {\
++umm_critical_depth; \
if (umm_critical_depth > umm_max_critical_depth) { \
umm_max_critical_depth = umm_critical_depth; \
} \
}
#define UMM_CRITICAL_EXIT() (umm_critical_depth--)
#else
#if defined(UMM_CRITICAL_METRICS)
#define UMM_CRITICAL_DECL(tag) uint32_t _saved_ps_##tag
#define UMM_CRITICAL_ENTRY(tag)_critical_entry(&time_stats.tag, &_saved_ps_##tag)
#define UMM_CRITICAL_EXIT(tag) _critical_exit(&time_stats.tag, &_saved_ps_##tag)
// This method preserves the intlevel on entry and restores the
// original intlevel at exit.
#define UMM_CRITICAL_DECL(tag) uint32_t _saved_ps_##tag
#define UMM_CRITICAL_ENTRY(tag) _saved_ps_##tag = xt_rsil(DEFAULT_CRITICAL_SECTION_INTLEVEL)
#define UMM_CRITICAL_EXIT(tag) xt_wsr_ps(_saved_ps_##tag)
#else // ! UMM_CRITICAL_METRICS
// This method preserves the intlevel on entry and restores the
// original intlevel at exit.
#define UMM_CRITICAL_DECL(tag) uint32_t _saved_ps_##tag
#define UMM_CRITICAL_ENTRY(tag) _saved_ps_##tag = xt_rsil(DEFAULT_CRITICAL_SECTION_INTLEVEL)
#define UMM_CRITICAL_EXIT(tag) xt_wsr_ps(_saved_ps_##tag)
#endif
#endif
/*
* -D UMM_LIGHTWEIGHT_CPU
*
* The use of this macro is hardware/application specific.
*
* With some CPUs, the only available method for locking are the instructions
* for interrupts disable/enable. These macros are meant for lightweight single
* CPU systems that are sensitive to interrupts being turned off for too long. A
* typically UMM_CRITICAL_ENTRY would save current IRQ state then disable IRQs.
* Then UMM_CRITICAL_EXIT would restore previous IRQ state. This option adds
* additional critical entry/exit points by the method of defining the macros
* UMM_CRITICAL_SUSPEND and UMM_CRITICAL_RESUME to the values of
* UMM_CRITICAL_EXIT and UMM_CRITICAL_ENTRY. These additional exit/entries
* allow time to service interrupts during the reentrant sections of the code.
*
* Performance may be impacked if used with multicore CPUs. The higher frquency
* of locking and unlocking may be an issue with locking methods that have a
* high overhead.
*
* Status: TODO: Needs to be proposed for upstream.
*/
/*
*/
#define UMM_LIGHTWEIGHT_CPU
#ifdef UMM_LIGHTWEIGHT_CPU
#define UMM_CRITICAL_SUSPEND(tag) UMM_CRITICAL_EXIT(tag)
#define UMM_CRITICAL_RESUME(tag) UMM_CRITICAL_ENTRY(tag)
#else
#define UMM_CRITICAL_SUSPEND(tag) do {} while(0)
#define UMM_CRITICAL_RESUME(tag) do {} while(0)
#endif
/*
* -D UMM_REALLOC_MINIMIZE_COPY or
* -D UMM_REALLOC_DEFRAG
*
* Pick one of these two stratagies. UMM_REALLOC_MINIMIZE_COPY grows upward or
* shrinks an allocation, avoiding copy when possible. UMM_REALLOC_DEFRAG gives
* priority with growing the revised allocation toward an adjacent hole in the
* direction of the beginning of the heap when possible.
*
* Status: TODO: These are new options introduced to optionally restore the
* previous defrag propery of realloc. The issue has been raised in the upstream
* repo. No response at this time. Based on response, may propose for upstream.
*/
/*
#define UMM_REALLOC_MINIMIZE_COPY
*/
#define UMM_REALLOC_DEFRAG
/*
* -D UMM_INTEGRITY_CHECK :
*
@ -155,12 +449,28 @@ extern char _heap_start[];
* 4 bytes, so there might be some trailing "extra" bytes which are not checked
* for corruption.
*/
/*
#define UMM_INTEGRITY_CHECK
*/
/*
* -D UMM_POISON :
* Not normally enabled. Full intergity check may exceed 10us.
*/
/*
#define UMM_INTEGRITY_CHECK
*/
#ifdef UMM_INTEGRITY_CHECK
int umm_integrity_check( void );
# define INTEGRITY_CHECK() umm_integrity_check()
extern void umm_corruption(void);
# define UMM_HEAP_CORRUPTION_CB() DBGLOG_FUNCTION( "Heap Corruption!" )
#else
# define INTEGRITY_CHECK() 0
#endif
/////////////////////////////////////////////////
/*
* -D UMM_POISON_CHECK :
* -D UMM_POISON_CHECK_LITE
*
* Enables heap poisoning: add predefined value (poison) before and after each
* allocation, and check before each heap operation that no poison is
@ -185,17 +495,135 @@ extern char _heap_start[];
*
* If poison corruption is detected, the message is printed and user-provided
* callback is called: `UMM_HEAP_CORRUPTION_CB()`
*
* UMM_POISON_CHECK - does a global heap check on all active allocation at
* every alloc API call. May exceed 10us due to critical section with IRQs
* disabled.
*
* UMM_POISON_CHECK_LITE - checks the allocation presented at realloc()
* and free(). Expands the poison check on the current allocation to
* include its nearest allocated neighbors in the heap.
* umm_malloc() will also checks the neighbors of the selected allocation
* before use.
*
* Status: TODO?: UMM_POISON_CHECK_LITE is a new option. We could propose for
* upstream; however, the upstream version has much of the framework for calling
* poison check on each alloc call refactored out. Not sure how this will be
* received.
*/
/*
* Compatibility for deprecated UMM_POISON
*/
#if defined(UMM_POISON) && !defined(UMM_POISON_CHECK)
#define UMM_POISON_CHECK_LITE
#endif
#if defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_CORE)
#define UMM_POISON
#if !defined(UMM_POISON_CHECK) && !defined(UMM_POISON_CHECK_LITE)
/*
#define UMM_POISON_CHECK
*/
#define UMM_POISON_CHECK_LITE
#endif
#endif
#define UMM_POISON_SIZE_BEFORE 4
#define UMM_POISON_SIZE_AFTER 4
#define UMM_POISON_SIZE_AFTER 4
#define UMM_POISONED_BLOCK_LEN_TYPE uint32_t
#define UMM_HEAP_CORRUPTION_CB() panic()
#if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE)
void *umm_poison_malloc( size_t size );
void *umm_poison_calloc( size_t num, size_t size );
void *umm_poison_realloc( void *ptr, size_t size );
void umm_poison_free( void *ptr );
int umm_poison_check( void );
// Local Additions to better report location in code of the caller.
void *umm_poison_realloc_fl( void *ptr, size_t size, const char* file, int line );
void umm_poison_free_fl( void *ptr, const char* file, int line );
#if defined(UMM_POISON_CHECK_LITE)
/*
* We can safely do individual poison checks at free and realloc and stay
* under 10us or close.
*/
# define POISON_CHECK() 1
# define POISON_CHECK_NEIGHBORS(c) \
do {\
if(!check_poison_neighbors(c)) \
panic();\
} while(false)
#else
/* Not normally enabled. A full heap poison check may exceed 10us. */
# define POISON_CHECK() umm_poison_check()
# define POISON_CHECK_NEIGHBORS(c) do{}while(false)
#endif
#else
# define POISON_CHECK() 1
# define POISON_CHECK_NEIGHBORS(c) do{}while(false)
#endif
/////////////////////////////////////////////////
#undef DBGLOG_FUNCTION
#undef DBGLOG_FUNCTION_P
#if defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_OOM) || \
defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) || \
defined(UMM_INTEGRITY_CHECK)
#define DBGLOG_FUNCTION(fmt, ...) ets_uart_printf(fmt, ##__VA_ARGS__)
#else
#define DBGLOG_FUNCTION(fmt, ...) do { (void)fmt; } while(false)
#endif
/////////////////////////////////////////////////
#if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) || defined(UMM_INTEGRITY_CHECK)
#if !defined(DBGLOG_LEVEL) || DBGLOG_LEVEL < 3
// All debug prints in UMM_POISON_CHECK are level 3
#undef DBGLOG_LEVEL
#define DBGLOG_LEVEL 3
#endif
#endif
#if defined(UMM_CRITICAL_METRICS)
struct UMM_TIME_STATS_t {
UMM_TIME_STAT id_malloc;
UMM_TIME_STAT id_realloc;
UMM_TIME_STAT id_free;
#ifdef UMM_INFO
UMM_TIME_STAT id_info;
#endif
#if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE)
UMM_TIME_STAT id_poison;
#endif
#ifdef UMM_INTEGRITY_CHECK
UMM_TIME_STAT id_integrity;
#endif
UMM_TIME_STAT id_no_tag;
};
#endif
/////////////////////////////////////////////////
#ifdef DEBUG_ESP_OOM
#define MEMLEAK_DEBUG
// umm_*alloc are not renamed to *alloc
// Assumes umm_malloc.h has already been included.
#define umm_zalloc(s) umm_calloc(1,s)
void* malloc_loc (size_t s, const char* file, int line);
void* calloc_loc (size_t n, size_t s, const char* file, int line);
void* realloc_loc (void* p, size_t s, const char* file, int line);
// *alloc are macro calling *alloc_loc calling+checking umm_*alloc()
// they are defined at the bottom of this file
/////////////////////////////////////////////////
#elif defined(UMM_POISON_CHECK)
void* realloc_loc (void* p, size_t s, const char* file, int line);
void free_loc (void* p, const char* file, int line);
#else // !defined(ESP_DEBUG_OOM)
#endif
#ifdef __cplusplus
}
@ -203,12 +631,57 @@ extern char _heap_start[];
#endif /* _UMM_MALLOC_CFG_H */
#ifdef __cplusplus
extern "C" {
#endif
#ifdef DEBUG_ESP_OOM
// this must be outside from "#ifndef _UMM_MALLOC_CFG_H"
// because Arduino.h's <cstdlib> does #undef *alloc
// Arduino.h recall us to redefine them
#include <pgmspace.h>
#define malloc(s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; malloc_loc(s, mem_debug_file, __LINE__); })
#define calloc(n,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; calloc_loc(n, s, mem_debug_file, __LINE__); })
#define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; realloc_loc(p, s, mem_debug_file, __LINE__); })
// Reuse pvPort* calls, since they already support passing location information.
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line);
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line);
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line);
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line);
void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line);
#define malloc(s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortMalloc(s, mem_debug_file, __LINE__); })
#define calloc(n,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortCalloc(n, s, mem_debug_file, __LINE__); })
#define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortRealloc(p, s, mem_debug_file, __LINE__); })
#if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE)
#define dbg_heap_free(p) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; vPortFree(p, mem_debug_file, __LINE__); })
#else
#define dbg_heap_free(p) free(p)
#endif
#elif defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE)
#include <pgmspace.h>
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line);
#define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortRealloc(p, s, mem_debug_file, __LINE__); })
void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line);
//C - to be discussed
/*
Problem, I would like to report the file and line number with the umm poison
event as close as possible to the event. The #define method works for malloc,
calloc, and realloc those names are not as generic as free. A #define free
captures too much. Classes with methods called free are included :(
Inline functions would report the address of the inline function in the .h
not where they are called.
Anybody know a trick to make this work?
Create dbg_heap_free() as an alternative for free() when you need a little
more help in debugging the more challenging problems.
*/
#define dbg_heap_free(p) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; vPortFree(p, mem_debug_file, __LINE__); })
#else
#define dbg_heap_free(p) free(p)
#endif /* DEBUG_ESP_OOM */
#ifdef __cplusplus
}
#endif

View File

@ -1,81 +0,0 @@
/*
* umm_malloc performance measurments and ESP specifics
*/
#include <stdio.h>
#include <string.h>
#include <pgmspace.h>
#include <core_esp8266_features.h>
#include "umm_performance.h"
#include "umm_stats.h"
extern "C" {
UMM_STATS ummStats = {0, 0, 0, 0};
#ifdef UMM_CRITICAL_PERIOD_ANALYZE
struct _UMM_TIME_STATS time_stats = {
{0xFFFFFFFF, 0U, 0U, 0U},
{0xFFFFFFFF, 0U, 0U, 0U},
{0xFFFFFFFF, 0U, 0U, 0U},
{0xFFFFFFFF, 0U, 0U, 0U} };
bool ICACHE_FLASH_ATTR get_umm_get_perf_data(struct _UMM_TIME_STATS *p, size_t size) {
if (p && sizeof(time_stats) == size) {
uint32_t save_ps = xt_rsil(DEFAULT_CRITICAL_SECTION_INTLEVEL);
memcpy(p, &time_stats, size);
xt_wsr_ps(save_ps);
return true;
}
return false;
}
#endif
#if defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_ISR)
/*
Printing from the malloc routines is tricky. Since a lot of library calls
will want to do malloc.
Objective: To be able to print "last gasp" diagnostic messages
when interrupts are disabled and w/o availability of heap resources.
*/
// ROM _putc1, ignores CRs and sends CR/LF for LF, newline.
// Always returns character sent.
int constexpr (*_rom_putc1)(int) = (int (*)(int))0x40001dcc;
void uart_buff_switch(uint8_t);
int _isr_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
int ICACHE_RAM_ATTR _isr_safe_printf_P(const char *fmt, ...) {
#ifdef DEBUG_ESP_PORT
#define VALUE(x) __STRINGIFY(x)
// Preprocessor and compiler together will optimize away the if.
if (strcmp("Serial1", VALUE(DEBUG_ESP_PORT)) == 0) {
uart_buff_switch(1U);
} else {
uart_buff_switch(0U);
}
#else
uart_buff_switch(0U); // Side effect, clears RX FIFO
#endif
/*
To use ets_strlen() and ets_memcpy() safely with PROGMEM, flash storage,
the PROGMEM address must be word (4 bytes) aligned. The destination
address for ets_memcpy must also be word-aligned. We also round the
buf_len up to the nearest word boundary. So that all transfers will be
whole words.
*/
size_t str_len = ets_strlen(fmt);
size_t buf_len = (str_len + 1 + 3) & ~0x03U;
char ram_buf[buf_len] __attribute__ ((aligned(4)));
ets_memcpy(ram_buf, fmt, buf_len);
va_list argPtr;
va_start(argPtr, fmt);
int result = ets_vprintf(_rom_putc1, ram_buf, argPtr);
va_end(argPtr);
return result;
}
#endif
};

View File

@ -1,85 +0,0 @@
/*
* umm_malloc performance measurments and ESP specifics
*/
#ifndef _UMM_PERFORMANCE_H
#define _UMM_PERFORMANCE_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* -D UMM_CRITICAL_PERIOD_ANALYZE :
*
* Build option to collect timing usage data on critical section usage in
* functions: info, malloc, realloc. Collects MIN, MAX, and number of time
* IRQs were disabled at request time. Note, for realloc MAX disabled time
* will not include the time from calling malloc and/or free.
* Examine code for specifics on what info is available and how to access.
*/
// #define UMM_CRITICAL_PERIOD_ANALYZE
/*
Per Devyte, the core currently doesn't support masking a specific interrupt
level. That doesn't mean it can't be implemented, only that at this time
locking is implemented as all or nothing.
https://github.com/esp8266/Arduino/issues/6246#issuecomment-508612609
So for now we default to all, 15.
*/
#ifndef DEFAULT_CRITICAL_SECTION_INTLEVEL
#define DEFAULT_CRITICAL_SECTION_INTLEVEL 15
#endif
#if defined(UMM_CRITICAL_PERIOD_ANALYZE)
// This option adds support for gathering time locked data
typedef struct _TIME_STAT {
uint32_t min;
uint32_t max;
uint32_t start;
uint32_t intlevel;
} time_stat_t;
struct _UMM_TIME_STATS {
time_stat_t id_malloc;
time_stat_t id_realloc;
time_stat_t id_free;
time_stat_t id_info;
};
extern struct _UMM_TIME_STATS time_stats;
bool get_umm_get_perf_data(struct _UMM_TIME_STATS *p, size_t size);
static inline void _critical_entry(time_stat_t *p, uint32_t *saved_ps) {
*saved_ps = xt_rsil(DEFAULT_CRITICAL_SECTION_INTLEVEL);
if (0U != (*saved_ps & 0x0FU)) {
p->intlevel += 1U;
}
p->start = esp_get_cycle_count();
}
static inline void _critical_exit(time_stat_t *p, uint32_t *saved_ps) {
uint32_t elapse = esp_get_cycle_count() - p->start;
if (elapse < p->min)
p->min = elapse;
if (elapse > p->max)
p->max = elapse;
xt_wsr_ps(*saved_ps);
}
#endif
#if defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_ISR)
int _isr_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
#endif
#ifdef __cplusplus
}
#endif
#endif /* _UMM_PERFORMANCE_H */

View File

@ -0,0 +1,241 @@
#if defined(BUILD_UMM_MALLOC_C)
/* poisoning (UMM_POISON_CHECK) {{{ */
#if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE)
#define POISON_BYTE (0xa5)
/*
* Yields a size of the poison for the block of size `s`.
* If `s` is 0, returns 0.
*/
static size_t poison_size(size_t s) {
return(s ? (UMM_POISON_SIZE_BEFORE +
sizeof(UMM_POISONED_BLOCK_LEN_TYPE) +
UMM_POISON_SIZE_AFTER)
: 0);
}
/*
* Print memory contents starting from given `ptr`
*/
static void dump_mem ( const unsigned char *ptr, size_t len ) {
while (len--) {
DBGLOG_ERROR(" 0x%.2x", (unsigned int)(*ptr++));
}
}
/*
* Put poison data at given `ptr` and `poison_size`
*/
static void put_poison( unsigned char *ptr, size_t poison_size ) {
memset(ptr, POISON_BYTE, poison_size);
}
/*
* Check poison data at given `ptr` and `poison_size`. `where` is a pointer to
* a string, either "before" or "after", meaning, before or after the block.
*
* If poison is there, returns 1.
* Otherwise, prints the appropriate message, and returns 0.
*/
static int check_poison( const unsigned char *ptr, size_t poison_size,
const char *where) {
size_t i;
int ok = 1;
for (i = 0; i < poison_size; i++) {
if (ptr[i] != POISON_BYTE) {
ok = 0;
break;
}
}
if (!ok) {
DBGLOG_ERROR( "No poison %s block at: 0x%lx, actual data:", where, (unsigned long)ptr);
dump_mem(ptr, poison_size);
DBGLOG_ERROR( "\n" );
}
return ok;
}
/*
* Check if a block is properly poisoned. Must be called only for non-free
* blocks.
*/
static int check_poison_block( umm_block *pblock ) {
int ok = 1;
if (pblock->header.used.next & UMM_FREELIST_MASK) {
DBGLOG_ERROR( "check_poison_block is called for free block 0x%lx\n", (unsigned long)pblock);
} else {
/* the block is used; let's check poison */
unsigned char *pc = (unsigned char *)pblock->body.data;
unsigned char *pc_cur;
pc_cur = pc + sizeof(UMM_POISONED_BLOCK_LEN_TYPE);
if (!check_poison(pc_cur, UMM_POISON_SIZE_BEFORE, "before")) {
ok = 0;
goto clean;
}
pc_cur = pc + *((UMM_POISONED_BLOCK_LEN_TYPE *)pc) - UMM_POISON_SIZE_AFTER;
if (!check_poison(pc_cur, UMM_POISON_SIZE_AFTER, "after")) {
ok = 0;
goto clean;
}
}
clean:
return ok;
}
/*
* Takes a pointer returned by actual allocator function (`umm_malloc` or
* `umm_realloc`), puts appropriate poison, and returns adjusted pointer that
* should be returned to the user.
*
* `size_w_poison` is a size of the whole block, including a poison.
*/
static void *get_poisoned( void *v_ptr, size_t size_w_poison ) {
unsigned char *ptr = (unsigned char *)v_ptr;
if (size_w_poison != 0 && ptr != NULL) {
/* Poison beginning and the end of the allocated chunk */
put_poison(ptr + sizeof(UMM_POISONED_BLOCK_LEN_TYPE),
UMM_POISON_SIZE_BEFORE);
put_poison(ptr + size_w_poison - UMM_POISON_SIZE_AFTER,
UMM_POISON_SIZE_AFTER);
/* Put exact length of the user's chunk of memory */
*(UMM_POISONED_BLOCK_LEN_TYPE *)ptr = (UMM_POISONED_BLOCK_LEN_TYPE)size_w_poison;
/* Return pointer at the first non-poisoned byte */
ptr += sizeof(UMM_POISONED_BLOCK_LEN_TYPE) + UMM_POISON_SIZE_BEFORE;
}
return (void *)ptr;
}
/*
* Takes "poisoned" pointer (i.e. pointer returned from `get_poisoned()`),
* and checks that the poison of this particular block is still there.
*
* Returns unpoisoned pointer, i.e. actual pointer to the allocated memory.
*/
static void *get_unpoisoned( void *v_ptr ) {
unsigned char *ptr = (unsigned char *)v_ptr;
if (ptr != NULL) {
unsigned short int c;
ptr -= (sizeof(UMM_POISONED_BLOCK_LEN_TYPE) + UMM_POISON_SIZE_BEFORE);
/* Figure out which block we're in. Note the use of truncated division... */
c = (((char *)ptr)-(char *)(&(umm_heap[0])))/sizeof(umm_block);
check_poison_block(&UMM_BLOCK(c));
}
return (void *)ptr;
}
/* }}} */
/* ------------------------------------------------------------------------ */
void *umm_poison_malloc( size_t size ) {
void *ret;
size += poison_size(size);
ret = umm_malloc( size );
ret = get_poisoned(ret, size);
return ret;
}
/* ------------------------------------------------------------------------ */
void *umm_poison_calloc( size_t num, size_t item_size ) {
void *ret;
size_t size = item_size * num;
size += poison_size(size);
ret = umm_malloc(size);
if (NULL != ret)
memset(ret, 0x00, size);
ret = get_poisoned(ret, size);
return ret;
}
/* ------------------------------------------------------------------------ */
void *umm_poison_realloc( void *ptr, size_t size ) {
void *ret;
ptr = get_unpoisoned(ptr);
size += poison_size(size);
ret = umm_realloc( ptr, size );
ret = get_poisoned(ret, size);
return ret;
}
/* ------------------------------------------------------------------------ */
void umm_poison_free( void *ptr ) {
ptr = get_unpoisoned(ptr);
umm_free( ptr );
}
/*
* Iterates through all blocks in the heap, and checks poison for all used
* blocks.
*/
int umm_poison_check(void) {
UMM_CRITICAL_DECL(id_poison);
int ok = 1;
unsigned short int cur;
if (umm_heap == NULL) {
umm_init();
}
UMM_CRITICAL_ENTRY(id_poison);
/* Now iterate through the blocks list */
cur = UMM_NBLOCK(0) & UMM_BLOCKNO_MASK;
while( UMM_NBLOCK(cur) & UMM_BLOCKNO_MASK ) {
if ( !(UMM_NBLOCK(cur) & UMM_FREELIST_MASK) ) {
/* This is a used block (not free), so, check its poison */
ok = check_poison_block(&UMM_BLOCK(cur));
if (!ok){
break;
}
}
cur = UMM_NBLOCK(cur) & UMM_BLOCKNO_MASK;
}
UMM_CRITICAL_EXIT(id_poison);
return ok;
}
/* ------------------------------------------------------------------------ */
#endif
#endif // defined(BUILD_UMM_MALLOC_C)

View File

@ -1,36 +0,0 @@
/*
* umm_malloc heap statistics
*/
#ifndef _UMM_STATS_H
#define _UMM_STATS_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct UMM_STATS_t {
unsigned short int free_blocks;
unsigned short int free_blocks_min;
size_t alloc_max_size;
size_t oom_count;
} UMM_STATS;
extern UMM_STATS ummStats;
size_t ICACHE_FLASH_ATTR umm_free_heap_size_min( void );
size_t ICACHE_FLASH_ATTR umm_free_heap_size_min_reset( void );
inline size_t umm_get_max_alloc_size( void ) {
return ummStats.alloc_max_size;
}
inline size_t umm_get_oom_count( void ) {
return ummStats.oom_count;
}
#ifdef __cplusplus
}
#endif
#endif /* _UMM_STATS_H */

View File

@ -175,16 +175,18 @@ use esptool.py.
- Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.4.0/ESP8266FS-0.4.0.zip
- In your Arduino sketchbook directory, create ``tools`` directory if
it doesn't exist yet
it doesn't exist yet.
- Unpack the tool into ``tools`` directory (the path will look like
``<home_dir>/Arduino/tools/ESP8266FS/tool/esp8266fs.jar``)
If upgrading, overwrite the existing JAR file with the newer version.
- Restart Arduino IDE
- Open a sketch (or create a new one and save it)
- Go to sketch directory (choose Sketch > Show Sketch Folder)
- Restart Arduino IDE.
- Open a sketch (or create a new one and save it).
- Go to sketch directory (choose Sketch > Show Sketch Folder).
- Create a directory named ``data`` and any files you want in the file
system there
- Make sure you have selected a board, port, and closed Serial Monitor
system there.
- Make sure you have selected a board, port, and closed Serial Monitor.
- If your board requires you to press a button (or other action) to enter
bootload mode for flashing a sketch, do that now.
- Select Tools > ESP8266 Sketch Data Upload. This should start
uploading the files into ESP8266 flash file system. When done, IDE
status bar will display ``SPIFFS Image Uploaded`` message.

View File

@ -12,6 +12,7 @@ Prerequisites
- Arduino 1.6.8, get it from `Arduino
website <https://www.arduino.cc/en/Main/OldSoftwareReleases#previous>`__.
- Internet connection
- Python 3 interpreter (Mac/Linux only, Windows installation supplies its own)
Instructions
~~~~~~~~~~~~
@ -46,10 +47,13 @@ Prerequisites
- Python 3.x (https://python.org)
- terminal, console, or command prompt (depending on your OS)
- Internet connection
- Uninstalling any core version installed via Board Manager
Instructions - Windows 10
~~~~~~~~~~~~~~~~~~~~~~~~~
- First, make sure you don't already have the ESP8266 library installed using the Board Manager (see above)
- First, make sure you don't already have an ESP8266 core version installed
using the Board Manager (see above). If you do, uninstall it from the
Board Manager before proceeding.
- Install git for Windows (if not already; see https://git-scm.com/download/win)
@ -130,9 +134,14 @@ Note that you could, in theory install in ``C:\Program Files (x86)\Arduino\hardw
Instructions - Other OS
~~~~~~~~~~~~~~~~~~~~~~~
- First, make sure you don't already have an ESP8266 core version installed
using the Board Manager (see above). If you do, uninstall it from the
Board Manager before proceeding.
- Open the console and go to Arduino directory. This can be either your
*sketchbook* directory (usually ``<Documents>/Arduino``), or the
directory of Arduino application itself, the choice is up to you.
- Clone this repository into hardware/esp8266com/esp8266 directory.
Alternatively, clone it elsewhere and create a symlink, if your OS
supports them.
@ -186,9 +195,33 @@ Instructions - Other OS
cd esp8266/tools
python3 get.py
If you get an error message stating that python3 is not found, you will need to install it (most modern UNIX-like OSes provide Python 3 as
part of the default install). To install you will need to use ``sudo yum install python3``, ``sudo apt install python3``, or ``brew install python3``
as appropriate. On the Mac you may get an error message like:
.. code:: bash
python3 get.py
Platform: x86_64-apple-darwin
Downloading python3-macosx-placeholder.tar.gz
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1317, in do_open
encode_chunked=req.has_header('Transfer-encoding'))
...
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 1117, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
This is because Homebrew on the Mac does not always install the required SSL certificates by default. Install them manually (adjust the Python 3.7 as needed) with:
.. code:: bash
cd "/Applications/Python 3.7/" && sudo "./Install Certificates.command"
- Restart Arduino
- When later updating your local library, goto the esp8266 directory and do a git pull
- When later updating your local library, goto the esp8266 directory and do a git pull
.. code:: bash

View File

@ -29,6 +29,8 @@ EEPROM library uses one sector of flash located just after the SPIFFS.
`Three examples <https://github.com/esp8266/Arduino/tree/master/libraries/EEPROM>`__ included.
Note that the sector needs to be re-flashed every time the changed EEPROM data needs to be saved, thus will wear out the flash memory very quickly even if small amounts of data are written. Consider using one of the EEPROM libraries mentioned down below.
I2C (Wire library)
------------------
@ -141,14 +143,6 @@ Servo
This library exposes the ability to control RC (hobby) servo motors. It will support up to 24 servos on any available output pin. By default the first 12 servos will use Timer0 and currently this will not interfere with any other support. Servo counts above 12 will use Timer1 and features that use it will be affected. While many RC servo motors will accept the 3.3V IO data pin from a ESP8266, most will not be able to run off 3.3v and will require another power source that matches their specifications. Make sure to connect the grounds between the ESP8266 and the servo motor power supply.
Improved EEPROM library for ESP (ESP_EEPROM)
--------------------------------------------
An improved EEPROM library for ESPxxxx. Uses flash memory as per the standard ESP EEPROM library but reduces reflash - so reducing wear and improving commit() performance.
As actions on the flash need to stop the interrupts, an EEPROM reflash could noticably affect anything using PWM, etc.
Other libraries (not included with the IDE)
-------------------------------------------
@ -189,3 +183,5 @@ Libraries that don't rely on low-level access to AVR registers should work well.
- `MFRC522 <https://github.com/miguelbalboa/rfid>`__ - A library for using the Mifare RC522 RFID-tag reader/writer.
- `Ping <https://github.com/dancol90/ESP8266Ping>`__ - lets the ESP8266 ping a remote machine.
- `AsyncPing <https://github.com/akaJes/AsyncPing>`__ - fully asynchronous Ping library (have full ping statistic and hardware MAC address).
- `ESP_EEPROM <https://github.com/jwrw/ESP_EEPROM>`__ - This library writes a new copy of your data when you save (commit) it and keeps track of where in the sector the most recent copy is kept using a bitmap. The flash sector only needs to be erased when there is no more space for copies in the flash sector.
- `EEPROM Rotate <https://github.com/xoseperez/eeprom_rotate>`__ - Instead of using a single sector to persist the data from the emulated EEPROM, this library uses a number of sectors to do so: a sector pool.

View File

@ -646,6 +646,8 @@ Update process - memory view
- the new sketch is now copied "over" the old one.
- the new sketch is started.
By default, filesystem updates are overriding the target flash directly. In order to use the same two step process set the `ATOMIC_FS_UPDATE` flag.
.. figure:: update_memory_copy.png
:alt: Memory layout for OTA updates

View File

@ -1,6 +1,42 @@
Reference
=========
Interrupts
----------
Interrupts can be used on the ESP8266, but they must be used with care
and have several limitations:
* Interrupt callback functions must be in IRAM, because the flash may be
in the middle of other operations when they occur. Do this by adding
the ``ICACHE_RAM_ATTR`` attribute on the function definition. If this
attribute is not present, the sketch will crash when it attempts to
``attachInterrupt`` with an error message.
.. code:: cpp
ICACHE_RAM_ATTR void gpio_change_handler(void *data) {...
* Interrupts must not call ``delay()`` or ``yield()``, or call any routines
which internally use ``delay()`` or ``yield()`` either.
* Long-running (>1ms) tasks in interrupts will cause instabilty or crashes.
WiFi and other portions of the core can become unstable if interrupts
are blocked by a long-running interrupt. If you have much to do, you can
set a volatile global flag that your main ``loop()`` can check each pass
or use a scheduled function (which will be called outside of the interrupt
context when it is safe) to do long-running work.
* Memory operations can be dangerous and should be avoided in interrupts.
Calls to ``new`` or ``malloc`` should be minimized because they may require
a long running time if memory is fragmented. Calls to ``realloc`` and
``free`` must NEVER be called. Using any routines or objects which call
``free`` or ``realloc`` themselves is also forbidden for the same reason.
This means that ``String``, ``std::string``, ``std::vector`` and other
classes which use contiguous memory that may be resized must be used with
extreme care (ensuring strings aren't changed, vector elements aren't
added, etc.).
Digital IO
----------

View File

@ -21,6 +21,7 @@
#include "Arduino.h"
#include "EEPROM.h"
#include "debug.h"
extern "C" {
#include "c_types.h"
@ -30,7 +31,7 @@ extern "C" {
#include "spi_flash.h"
}
extern "C" uint32_t _FS_end;
extern "C" uint32_t _EEPROM_start;
EEPROMClass::EEPROMClass(uint32_t sector)
: _sector(sector)
@ -41,7 +42,7 @@ EEPROMClass::EEPROMClass(uint32_t sector)
}
EEPROMClass::EEPROMClass(void)
: _sector((((uint32_t)&_FS_end - 0x40200000) / SPI_FLASH_SEC_SIZE))
: _sector((((uint32_t)&_EEPROM_start - 0x40200000) / SPI_FLASH_SEC_SIZE))
, _data(0)
, _size(0)
, _dirty(false)
@ -49,10 +50,14 @@ EEPROMClass::EEPROMClass(void)
}
void EEPROMClass::begin(size_t size) {
if (size <= 0)
if (size <= 0) {
DEBUGV("EEPROMClass::begin error, size == 0\n");
return;
if (size > SPI_FLASH_SEC_SIZE)
}
if (size > SPI_FLASH_SEC_SIZE) {
DEBUGV("EEPROMClass::begin error, %d > %d\n", size, SPI_FLASH_SEC_SIZE);
size = SPI_FLASH_SEC_SIZE;
}
size = (size + 3) & (~3);
@ -66,9 +71,9 @@ void EEPROMClass::begin(size_t size) {
_size = size;
noInterrupts();
spi_flash_read(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size);
interrupts();
if (!ESP.flashRead(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size)) {
DEBUGV("EEPROMClass::begin flash read failed\n");
}
_dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time
}
@ -88,19 +93,27 @@ void EEPROMClass::end() {
uint8_t EEPROMClass::read(int const address) {
if (address < 0 || (size_t)address >= _size)
if (address < 0 || (size_t)address >= _size) {
DEBUGV("EEPROMClass::read error, address %d > %d or %d < 0\n", address, _size, address);
return 0;
if(!_data)
}
if (!_data) {
DEBUGV("EEPROMClass::read without ::begin\n");
return 0;
}
return _data[address];
}
void EEPROMClass::write(int const address, uint8_t const value) {
if (address < 0 || (size_t)address >= _size)
if (address < 0 || (size_t)address >= _size) {
DEBUGV("EEPROMClass::write error, address %d > %d or %d < 0\n", address, _size, address);
return;
if(!_data)
}
if(!_data) {
DEBUGV("EEPROMClass::read without ::begin\n");
return;
}
// Optimise _dirty. Only flagged if data written is different.
uint8_t* pData = &_data[address];
@ -112,7 +125,6 @@ void EEPROMClass::write(int const address, uint8_t const value) {
}
bool EEPROMClass::commit() {
bool ret = false;
if (!_size)
return false;
if(!_dirty)
@ -120,16 +132,15 @@ bool EEPROMClass::commit() {
if(!_data)
return false;
noInterrupts();
if(spi_flash_erase_sector(_sector) == SPI_FLASH_RESULT_OK) {
if(spi_flash_write(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size) == SPI_FLASH_RESULT_OK) {
if (ESP.flashEraseSector(_sector)) {
if (ESP.flashWrite(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size)) {
_dirty = false;
ret = true;
return true;
}
}
interrupts();
return ret;
DEBUGV("EEPROMClass::commit failed\n");
return false;
}
uint8_t * EEPROMClass::getDataPtr() {

View File

@ -14,7 +14,7 @@ byte value;
void setup() {
// initialize serial and wait for port to open:
Serial.begin(9600);
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}

View File

@ -13,6 +13,7 @@
int addr = 0;
void setup() {
Serial.begin(115200);
EEPROM.begin(512);
}
@ -33,7 +34,11 @@ void loop() {
addr = addr + 1;
if (addr == 512) {
addr = 0;
EEPROM.commit();
if (EEPROM.commit()) {
Serial.println("EEPROM successfully committed");
} else {
Serial.println("ERROR! EEPROM commit failed");
}
}
delay(100);

View File

@ -113,8 +113,8 @@ protected:
* constructor
*/
HTTPClient::HTTPClient()
: _client(nullptr), _userAgent(F("ESP8266HTTPClient"))
{
_client = nullptr;
#if HTTPCLIENT_1_1_COMPATIBLE
_tcpDeprecated.reset(nullptr);
#endif
@ -536,8 +536,8 @@ void HTTPClient::setTimeout(uint16_t timeout)
bool HTTPClient::setURL(String url)
{
// if the new location is only a path then only update the URI
if (_location.startsWith("/")) {
_uri = _location;
if (url && url[0] == '/') {
_uri = url;
clear();
return true;
}
@ -1294,21 +1294,21 @@ int HTTPClient::handleHeaderResponse()
String headerValue = headerLine.substring(headerLine.indexOf(':') + 1);
headerValue.trim();
if(headerName.equalsIgnoreCase("Content-Length")) {
if(headerName.equalsIgnoreCase(F("Content-Length"))) {
_size = headerValue.toInt();
}
if(_canReuse && headerName.equalsIgnoreCase("Connection")) {
if(_canReuse && headerName.equalsIgnoreCase(F("Connection"))) {
if(headerValue.indexOf("close") >= 0 && headerValue.indexOf("keep-alive") < 0) {
_canReuse = false;
}
}
if(headerName.equalsIgnoreCase("Transfer-Encoding")) {
if(headerName.equalsIgnoreCase(F("Transfer-Encoding"))) {
transferEncoding = headerValue;
}
if(headerName.equalsIgnoreCase("Location")) {
if(headerName.equalsIgnoreCase(F("Location"))) {
_location = headerValue;
}
@ -1334,7 +1334,7 @@ int HTTPClient::handleHeaderResponse()
if(transferEncoding.length() > 0) {
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] Transfer-Encoding: %s\n", transferEncoding.c_str());
if(transferEncoding.equalsIgnoreCase("chunked")) {
if(transferEncoding.equalsIgnoreCase(F("chunked"))) {
_transferEncoding = HTTPC_TE_CHUNKED;
} else {
return HTTPC_ERROR_ENCODING;

View File

@ -242,7 +242,7 @@ protected:
String _uri;
String _protocol;
String _headers;
String _userAgent = "ESP8266HTTPClient";
String _userAgent;
String _base64Authorization;
/// Response handling

View File

@ -1,6 +1,6 @@
name=ESP8266HTTPUpdateServer
version=1.0
author=Ivan Grokhotkov, Miguel Ángel Ajo
author=Ivan Grokhotkov, Miguel Angel Ajo
maintainer=Ivan Grokhtkov <ivan@esp8266.com>
sentence=Simple HTTP Update server based on the ESP8266WebServer
paragraph=The library accepts HTTP post requests to the /update url, and updates the ESP8266 firmware.

View File

@ -3,6 +3,9 @@
#include <WiFiServer.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include <flash_hal.h>
#include <FS.h>
#include <LittleFS.h>
#include "StreamString.h"
#include "ESP8266HTTPUpdateServer.h"
@ -10,11 +13,25 @@ namespace esp8266httpupdateserver {
using namespace esp8266webserver;
static const char serverIndex[] PROGMEM =
R"(<html><body><form method='POST' action='' enctype='multipart/form-data'>
<input type='file' name='update'>
<input type='submit' value='Update'>
</form>
</body></html>)";
R"(<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'/>
</head>
<body>
<form method='POST' action='' enctype='multipart/form-data'>
Firmware:<br>
<input type='file' accept='.bin' name='firmware'>
<input type='submit' value='Update Firmware'>
</form>
<form method='POST' action='' enctype='multipart/form-data'>
FileSystem:<br>
<input type='file' accept='.bin' name='filesystem'>
<input type='submit' value='Update FileSystem'>
</form>
</body>
</html>)";
static const char successResponse[] PROGMEM =
"<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...";
@ -75,9 +92,18 @@ void ESP8266HTTPUpdateServerTemplate<ServerType>::setup(ESP8266WebServerTemplate
WiFiUDP::stopAll();
if (_serial_output)
Serial.printf("Update: %s\n", upload.filename.c_str());
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if(!Update.begin(maxSketchSpace)){//start with max available size
_setUpdaterError();
if (upload.name == "filesystem") {
size_t fsSize = ((size_t) &_FS_end - (size_t) &_FS_start);
SPIFFS.end();
LittleFS.end();
if (!Update.begin(fsSize, U_FS)){//start with max available size
if (_serial_output) Update.printError(Serial);
}
} else {
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if (!Update.begin(maxSketchSpace, U_FLASH)){//start with max available size
_setUpdaterError();
}
}
} else if(_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()){
if (_serial_output) Serial.printf(".");

View File

@ -238,7 +238,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName.equalsIgnoreCase("Host")){
if (headerName.equalsIgnoreCase(F("Host"))){
_hostHeader = headerValue;
}
}

View File

@ -85,8 +85,9 @@ void setup() {
Serial.swap();
// Hardware serial is now on RX:GPIO13 TX:GPIO15
// use SoftwareSerial on regular RX(3)/TX(1) for logging
logger = new SoftwareSerial(3, 1);
logger->begin(BAUD_LOGGER);
logger = new SoftwareSerial();
logger->begin(BAUD_LOGGER, 3, 1);
logger->enableIntTx(false);
logger->println("\n\nUsing SoftwareSerial for logging");
#else
logger->begin(BAUD_LOGGER);

View File

@ -49,24 +49,24 @@ extern "C" {
* @param p Print interface
*/
void ESP8266WiFiClass::printDiag(Print& p) {
const char* modes[] = { "NULL", "STA", "AP", "STA+AP" };
p.print("Mode: ");
const char* const modes[] = { "NULL", "STA", "AP", "STA+AP" };
p.print(F("Mode: "));
p.println(modes[wifi_get_opmode()]);
const char* phymodes[] = { "", "B", "G", "N" };
p.print("PHY mode: ");
const char* const phymodes[] = { "", "B", "G", "N" };
p.print(F("PHY mode: "));
p.println(phymodes[(int) wifi_get_phy_mode()]);
p.print("Channel: ");
p.print(F("Channel: "));
p.println(wifi_get_channel());
p.print("AP id: ");
p.print(F("AP id: "));
p.println(wifi_station_get_current_ap_id());
p.print("Status: ");
p.print(F("Status: "));
p.println(wifi_station_get_connect_status());
p.print("Auto connect: ");
p.print(F("Auto connect: "));
p.println(wifi_station_get_auto_connect());
struct station_config conf;
@ -75,22 +75,14 @@ void ESP8266WiFiClass::printDiag(Print& p) {
char ssid[33]; //ssid can be up to 32chars, => plus null term
memcpy(ssid, conf.ssid, sizeof(conf.ssid));
ssid[32] = 0; //nullterm in case of 32 char ssid
p.print("SSID (");
p.print(strlen(ssid));
p.print("): ");
p.println(ssid);
p.printf_P(PSTR("SSID (%d): %s\n"), strlen(ssid), ssid);
char passphrase[65];
memcpy(passphrase, conf.password, sizeof(conf.password));
passphrase[64] = 0;
p.printf_P(PSTR("Passphrase (%d): %s\n"), strlen(passphrase), passphrase);
p.print("Passphrase (");
p.print(strlen(passphrase));
p.print("): ");
p.println(passphrase);
p.print("BSSID set: ");
p.print(F("BSSID set: "));
p.println(conf.bssid_set);
}

View File

@ -43,7 +43,7 @@ ESP8266HTTPUpdate::~ESP8266HTTPUpdate(void)
{
}
#ifdef HTTPUPDATE_1_2_COMPATIBLE
#if HTTPUPDATE_1_2_COMPATIBLE
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion,
const String& httpsFingerprint, bool reboot)
{
@ -94,7 +94,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(WiFiClient& client, const String& url
return handleUpdate(http, currentVersion, false);
}
#ifdef HTTPUPDATE_1_2_COMPATIBLE
#if HTTPUPDATE_1_2_COMPATIBLE
HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion, const String& httpsFingerprint)
{
HTTPClient http;
@ -133,7 +133,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(WiFiClient& client, const Strin
return handleUpdate(http, currentVersion, true);
}
#ifdef HTTPUPDATE_1_2_COMPATIBLE
#if HTTPUPDATE_1_2_COMPATIBLE
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, const String& uri, const String& currentVersion,
bool https, const String& httpsFingerprint, bool reboot)
{
@ -263,6 +263,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
http.setTimeout(_httpClientTimeout);
http.setFollowRedirects(_followRedirects);
http.setUserAgent(F("ESP8266-http-Update"));
http.addHeader(F("x-ESP8266-Chip-ID"), String(ESP.getChipId()));
http.addHeader(F("x-ESP8266-STA-MAC"), WiFi.macAddress());
http.addHeader(F("x-ESP8266-AP-MAC"), WiFi.softAPmacAddress());
http.addHeader(F("x-ESP8266-free-space"), String(ESP.getFreeSketchSpace()));
@ -388,7 +389,11 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
http.end();
#ifdef ATOMIC_FS_UPDATE
if(_rebootOnUpdate) {
#else
if(_rebootOnUpdate && !spiffs) {
#endif
ESP.restart();
}

View File

@ -26,14 +26,16 @@
#ifndef ESP8266HTTPUPDATE_H_
#define ESP8266HTTPUPDATE_H_
#define HTTPUPDATE_1_2_COMPATIBLE
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <ESP8266HTTPClient.h>
#ifndef HTTPUPDATE_1_2_COMPATIBLE
#define HTTPUPDATE_1_2_COMPATIBLE HTTPCLIENT_1_1_COMPATIBLE
#endif
#ifdef DEBUG_ESP_HTTP_UPDATE
#ifdef DEBUG_ESP_PORT
#define DEBUG_HTTP_UPDATE(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ## __VA_ARGS__ )
@ -85,7 +87,7 @@ public:
_ledOn = ledOn;
}
#ifdef HTTPUPDATE_1_2_COMPATIBLE
#if HTTPUPDATE_1_2_COMPATIBLE
// This function is deprecated, use rebootOnUpdate and the next one instead
t_httpUpdate_return update(const String& url, const String& currentVersion,
const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
@ -97,7 +99,7 @@ public:
#endif
t_httpUpdate_return update(WiFiClient& client, const String& url, const String& currentVersion = "");
#ifdef HTTPUPDATE_1_2_COMPATIBLE
#if HTTPUPDATE_1_2_COMPATIBLE
// This function is deprecated, use one of the overloads below along with rebootOnUpdate
t_httpUpdate_return update(const String& host, uint16_t port, const String& uri, const String& currentVersion,
bool https, const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
@ -112,7 +114,7 @@ public:
t_httpUpdate_return update(WiFiClient& client, const String& host, uint16_t port, const String& uri = "/",
const String& currentVersion = "");
#ifdef HTTPUPDATE_1_2_COMPATIBLE
#if HTTPUPDATE_1_2_COMPATIBLE
// This function is deprecated, use rebootOnUpdate and the next one instead
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion,
const String& httpsFingerprint, bool reboot) __attribute__((deprecated));

View File

@ -1,10 +1,10 @@
#include <ESP8266mDNS.h>
/*
* MDNS responder global instance
*
* Class type that is instantiated depends on the type mapping in ESP8266mDNS.h
*/
MDNS responder global instance
Class type that is instantiated depends on the type mapping in ESP8266mDNS.h
*/
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
MDNSResponder MDNS;
#endif

View File

@ -1,44 +1,44 @@
/*
ESP8266mDNS.h - mDNSResponder for ESP8266 family
This file is part of the esp8266 core for Arduino environment.
ESP8266mDNS.h - mDNSResponder for ESP8266 family
This file is part of the esp8266 core for Arduino environment.
Legacy_ESP8266mDNS:
The well known, thouroughly tested (yet no flawless) default mDNS library for the ESP8266 family
Legacy_ESP8266mDNS:
The well known, thouroughly tested (yet no flawless) default mDNS library for the ESP8266 family
LEA_ESP8266mDNS:
An (currently) experimental mDNS implementation, that supports a lot more of mDNS features than Legacy_ESP8266mDNS, like:
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service
- Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented
- Probing host and service domains for uniqueness in the local network
- Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak)
- Announcing available services after successful probing
- Using fixed service TXT items or
- Using dynamic service TXT items for presented services (via callback)
- Remove services (and un-announcing them to the observers by sending goodbye-messages)
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period)
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications
- Support for multi-homed client host domains
LEA_ESP8266mDNS:
An (currently) experimental mDNS implementation, that supports a lot more of mDNS features than Legacy_ESP8266mDNS, like:
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service
- Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented
- Probing host and service domains for uniqueness in the local network
- Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak)
- Announcing available services after successful probing
- Using fixed service TXT items or
- Using dynamic service TXT items for presented services (via callback)
- Remove services (and un-announcing them to the observers by sending goodbye-messages)
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period)
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications
- Support for multi-homed client host domains
See 'LEA_ESP8266mDNS/EPS8266mDNS.h' for more implementation details and usage informations.
See 'examples/mDNS_Clock' and 'examples/mDNS_ServiceMonitor' for implementation examples of the advanced features.
See 'LEA_ESP8266mDNS/EPS8266mDNS.h' for more implementation details and usage informations.
See 'examples/mDNS_Clock' and 'examples/mDNS_ServiceMonitor' for implementation examples of the advanced features.
LEA_ESP8266mDNS is (mostly) client source code compatible to 'Legacy_ESP8266mDNS', so it could be
use as a 'drop-in' replacement in existing projects.
LEA_ESP8266mDNS is (mostly) client source code compatible to 'Legacy_ESP8266mDNS', so it could be
use as a 'drop-in' replacement in existing projects.
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
version 2.1 of the License, or (at your option) any later version.
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@ -47,10 +47,10 @@
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new
extern MDNSResponder MDNS;
// Maps the implementation to use to the global namespace type
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new
extern MDNSResponder MDNS;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +1,43 @@
/*
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
Version 1.1
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
Version 1.1
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
This is a simple implementation of multicast DNS query support for an Arduino
running on ESP8266 chip. Only support for resolving address queries is currently
implemented.
This is a simple implementation of multicast DNS query support for an Arduino
running on ESP8266 chip. Only support for resolving address queries is currently
implemented.
Requirements:
- ESP8266WiFi library
Requirements:
- ESP8266WiFi library
Usage:
- Include the ESP8266 Multicast DNS library in the sketch.
- Call the begin method in the sketch's setup and provide a domain name (without
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
for the DNS record--the default is 1 hour.
- Call the update method in each iteration of the sketch's loop function.
Usage:
- Include the ESP8266 Multicast DNS library in the sketch.
- Call the begin method in the sketch's setup and provide a domain name (without
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
for the DNS record--the default is 1 hour.
- Call the update method in each iteration of the sketch's loop function.
License (MIT license):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
License (MIT license):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ESP8266MDNS_LEGACY_H
@ -54,95 +54,108 @@ License (MIT license):
class UdpContext;
namespace Legacy_MDNSResponder {
namespace Legacy_MDNSResponder
{
struct MDNSService;
struct MDNSTxt;
struct MDNSAnswer;
class MDNSResponder {
class MDNSResponder
{
public:
MDNSResponder();
~MDNSResponder();
bool begin(const char* hostName);
bool begin(const String& hostName) {
return begin(hostName.c_str());
}
//for compatibility
bool begin(const char* hostName, IPAddress ip, uint32_t ttl=120){
(void) ip;
(void) ttl;
return begin(hostName);
}
bool begin(const String& hostName, IPAddress ip, uint32_t ttl=120) {
return begin(hostName.c_str(), ip, ttl);
}
/* Application should call this whenever AP is configured/disabled */
void notifyAPChange();
void update();
MDNSResponder();
~MDNSResponder();
bool begin(const char* hostName);
bool begin(const String& hostName)
{
return begin(hostName.c_str());
}
//for compatibility
bool begin(const char* hostName, IPAddress ip, uint32_t ttl = 120)
{
(void) ip;
(void) ttl;
return begin(hostName);
}
bool begin(const String& hostName, IPAddress ip, uint32_t ttl = 120)
{
return begin(hostName.c_str(), ip, ttl);
}
/* Application should call this whenever AP is configured/disabled */
void notifyAPChange();
void update();
void addService(char *service, char *proto, uint16_t port);
void addService(const char *service, const char *proto, uint16_t port){
addService((char *)service, (char *)proto, port);
}
void addService(const String& service, const String& proto, uint16_t port){
addService(service.c_str(), proto.c_str(), port);
}
bool addServiceTxt(char *name, char *proto, char * key, char * value);
bool addServiceTxt(const char *name, const char *proto, const char *key,const char * value){
return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
}
bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value){
return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
}
int queryService(char *service, char *proto);
int queryService(const char *service, const char *proto){
return queryService((char *)service, (char *)proto);
}
int queryService(const String& service, const String& proto){
return queryService(service.c_str(), proto.c_str());
}
String hostname(int idx);
IPAddress IP(int idx);
uint16_t port(int idx);
void enableArduino(uint16_t port, bool auth=false);
void addService(char *service, char *proto, uint16_t port);
void addService(const char *service, const char *proto, uint16_t port)
{
addService((char *)service, (char *)proto, port);
}
void addService(const String& service, const String& proto, uint16_t port)
{
addService(service.c_str(), proto.c_str(), port);
}
void setInstanceName(String name);
void setInstanceName(const char * name){
setInstanceName(String(name));
}
void setInstanceName(char * name){
setInstanceName(String(name));
}
bool addServiceTxt(char *name, char *proto, char * key, char * value);
bool addServiceTxt(const char *name, const char *proto, const char *key, const char * value)
{
return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
}
bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value)
{
return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
}
int queryService(char *service, char *proto);
int queryService(const char *service, const char *proto)
{
return queryService((char *)service, (char *)proto);
}
int queryService(const String& service, const String& proto)
{
return queryService(service.c_str(), proto.c_str());
}
String hostname(int idx);
IPAddress IP(int idx);
uint16_t port(int idx);
void enableArduino(uint16_t port, bool auth = false);
void setInstanceName(String name);
void setInstanceName(const char * name)
{
setInstanceName(String(name));
}
void setInstanceName(char * name)
{
setInstanceName(String(name));
}
private:
struct MDNSService * _services;
UdpContext* _conn;
String _hostName;
String _instanceName;
struct MDNSAnswer * _answers;
struct MDNSQuery * _query;
bool _newQuery;
bool _waitingForAnswers;
WiFiEventHandler _disconnectedHandler;
WiFiEventHandler _gotIPHandler;
struct MDNSService * _services;
UdpContext* _conn;
String _hostName;
String _instanceName;
struct MDNSAnswer * _answers;
struct MDNSQuery * _query;
bool _newQuery;
bool _waitingForAnswers;
WiFiEventHandler _disconnectedHandler;
WiFiEventHandler _gotIPHandler;
uint16_t _getServicePort(char *service, char *proto);
MDNSTxt * _getServiceTxt(char *name, char *proto);
uint16_t _getServiceTxtLen(char *name, char *proto);
IPAddress _getRequestMulticastInterface();
void _parsePacket();
void _replyToTypeEnumRequest(IPAddress multicastInterface);
void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface);
MDNSAnswer* _getAnswerFromIdx(int idx);
int _getNumAnswers();
bool _listen();
void _restart();
uint16_t _getServicePort(char *service, char *proto);
MDNSTxt * _getServiceTxt(char *name, char *proto);
uint16_t _getServiceTxtLen(char *name, char *proto);
IPAddress _getRequestMulticastInterface();
void _parsePacket();
void _replyToTypeEnumRequest(IPAddress multicastInterface);
void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface);
MDNSAnswer* _getAnswerFromIdx(int idx);
int _getNumAnswers();
bool _listen();
void _restart();
};
} // namespace Legacy_MDNSResponder

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,180 +1,182 @@
/*
* LEAmDNS_Priv.h
*
* License (MIT license):
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef MDNS_PRIV_H
#define MDNS_PRIV_H
namespace esp8266 {
/*
* LEAmDNS
*/
namespace MDNSImplementation {
// Enable class debug functions
#define ESP_8266_MDNS_INCLUDE
//#define DEBUG_ESP_MDNS_RESPONDER
#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS)
#define DEBUG_ESP_MDNS_RESPONDER
#endif
#ifndef LWIP_OPEN_SRC
#define LWIP_OPEN_SRC
#endif
//
// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing
// This allows to drive the responder in a environment, where 'update()' isn't called in the loop
//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
// Enable/disable debug trace macros
#ifdef DEBUG_ESP_MDNS_RESPONDER
#define DEBUG_ESP_MDNS_INFO
#define DEBUG_ESP_MDNS_ERR
#define DEBUG_ESP_MDNS_TX
#define DEBUG_ESP_MDNS_RX
#endif
#ifdef DEBUG_ESP_MDNS_RESPONDER
#ifdef DEBUG_ESP_MDNS_INFO
#define DEBUG_EX_INFO(A) A
#else
#define DEBUG_EX_INFO(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_MDNS_ERR
#define DEBUG_EX_ERR(A) A
#else
#define DEBUG_EX_ERR(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_MDNS_TX
#define DEBUG_EX_TX(A) A
#else
#define DEBUG_EX_TX(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_MDNS_RX
#define DEBUG_EX_RX(A) A
#else
#define DEBUG_EX_RX(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
#else
#define DEBUG_EX_INFO(A) do { (void)0; } while (0)
#define DEBUG_EX_ERR(A) do { (void)0; } while (0)
#define DEBUG_EX_TX(A) do { (void)0; } while (0)
#define DEBUG_EX_RX(A) do { (void)0; } while (0)
#endif
/* Replaced by 'lwip/prot/dns.h' definitions
#ifdef MDNS_IP4_SUPPORT
#define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT
#endif
#ifdef MDNS_IP6_SUPPORT
#define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT
#endif*/
//#define MDNS_MULTICAST_PORT 5353
/*
* This is NOT the TTL (Time-To-Live) for MDNS records, but the
* subnet level distance MDNS records should travel.
* 1 sets the subnet distance to 'local', which is default for MDNS.
* (Btw.: 255 would set it to 'as far as possible' -> internet)
*
* However, RFC 3171 seems to force 255 instead
*/
#define MDNS_MULTICAST_TTL 255/*1*/
/*
* This is the MDNS record TTL
* Host level records are set to 2min (120s)
* service level records are set to 75min (4500s)
*/
#define MDNS_HOST_TTL 120
#define MDNS_SERVICE_TTL 4500
/*
* Compressed labels are flaged by the two topmost bits of the length byte being set
*/
#define MDNS_DOMAIN_COMPRESS_MARK 0xC0
/*
* Avoid endless recursion because of malformed compressed labels
*/
#define MDNS_DOMAIN_MAX_REDIRCTION 6
/*
* Default service priority and weight in SRV answers
*/
#define MDNS_SRV_PRIORITY 0
#define MDNS_SRV_WEIGHT 0
/*
* Delay between and number of probes for host and service domains
* Delay between and number of announces for host and service domains
* Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache'
*/
#define MDNS_PROBE_DELAY 250
#define MDNS_PROBE_COUNT 3
#define MDNS_ANNOUNCE_DELAY 1000
#define MDNS_ANNOUNCE_COUNT 8
#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5
#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000
/*
* Force host domain to use only lowercase letters
*/
//#define MDNS_FORCE_LOWERCASE_HOSTNAME
/*
* Enable/disable the usage of the F() macro in debug trace printf calls.
* There needs to be an PGM comptible printf function to use this.
*
* USE_PGM_PRINTF and F
*/
#define USE_PGM_PRINTF
#ifdef USE_PGM_PRINTF
#else
#ifdef F
#undef F
#endif
#define F(A) A
#endif
} // namespace MDNSImplementation
} // namespace esp8266
// Include the main header, so the submodlues only need to include this header
#include "LEAmDNS.h"
#endif // MDNS_PRIV_H
/*
LEAmDNS_Priv.h
License (MIT license):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef MDNS_PRIV_H
#define MDNS_PRIV_H
namespace esp8266
{
/*
LEAmDNS
*/
namespace MDNSImplementation
{
// Enable class debug functions
#define ESP_8266_MDNS_INCLUDE
//#define DEBUG_ESP_MDNS_RESPONDER
#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS)
#define DEBUG_ESP_MDNS_RESPONDER
#endif
#ifndef LWIP_OPEN_SRC
#define LWIP_OPEN_SRC
#endif
//
// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing
// This allows to drive the responder in a environment, where 'update()' isn't called in the loop
//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
// Enable/disable debug trace macros
#ifdef DEBUG_ESP_MDNS_RESPONDER
#define DEBUG_ESP_MDNS_INFO
#define DEBUG_ESP_MDNS_ERR
#define DEBUG_ESP_MDNS_TX
#define DEBUG_ESP_MDNS_RX
#endif
#ifdef DEBUG_ESP_MDNS_RESPONDER
#ifdef DEBUG_ESP_MDNS_INFO
#define DEBUG_EX_INFO(A) A
#else
#define DEBUG_EX_INFO(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_MDNS_ERR
#define DEBUG_EX_ERR(A) A
#else
#define DEBUG_EX_ERR(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_MDNS_TX
#define DEBUG_EX_TX(A) A
#else
#define DEBUG_EX_TX(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_MDNS_RX
#define DEBUG_EX_RX(A) A
#else
#define DEBUG_EX_RX(A) do { (void)0; } while (0)
#endif
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
#else
#define DEBUG_EX_INFO(A) do { (void)0; } while (0)
#define DEBUG_EX_ERR(A) do { (void)0; } while (0)
#define DEBUG_EX_TX(A) do { (void)0; } while (0)
#define DEBUG_EX_RX(A) do { (void)0; } while (0)
#endif
/* Replaced by 'lwip/prot/dns.h' definitions
#ifdef MDNS_IP4_SUPPORT
#define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT
#endif
#ifdef MDNS_IP6_SUPPORT
#define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT
#endif*/
//#define MDNS_MULTICAST_PORT 5353
/*
This is NOT the TTL (Time-To-Live) for MDNS records, but the
subnet level distance MDNS records should travel.
1 sets the subnet distance to 'local', which is default for MDNS.
(Btw.: 255 would set it to 'as far as possible' -> internet)
However, RFC 3171 seems to force 255 instead
*/
#define MDNS_MULTICAST_TTL 255/*1*/
/*
This is the MDNS record TTL
Host level records are set to 2min (120s)
service level records are set to 75min (4500s)
*/
#define MDNS_HOST_TTL 120
#define MDNS_SERVICE_TTL 4500
/*
Compressed labels are flaged by the two topmost bits of the length byte being set
*/
#define MDNS_DOMAIN_COMPRESS_MARK 0xC0
/*
Avoid endless recursion because of malformed compressed labels
*/
#define MDNS_DOMAIN_MAX_REDIRCTION 6
/*
Default service priority and weight in SRV answers
*/
#define MDNS_SRV_PRIORITY 0
#define MDNS_SRV_WEIGHT 0
/*
Delay between and number of probes for host and service domains
Delay between and number of announces for host and service domains
Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache'
*/
#define MDNS_PROBE_DELAY 250
#define MDNS_PROBE_COUNT 3
#define MDNS_ANNOUNCE_DELAY 1000
#define MDNS_ANNOUNCE_COUNT 8
#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5
#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000
/*
Force host domain to use only lowercase letters
*/
//#define MDNS_FORCE_LOWERCASE_HOSTNAME
/*
Enable/disable the usage of the F() macro in debug trace printf calls.
There needs to be an PGM comptible printf function to use this.
USE_PGM_PRINTF and F
*/
#define USE_PGM_PRINTF
#ifdef USE_PGM_PRINTF
#else
#ifdef F
#undef F
#endif
#define F(A) A
#endif
} // namespace MDNSImplementation
} // namespace esp8266
// Include the main header, so the submodlues only need to include this header
#include "LEAmDNS.h"
#endif // MDNS_PRIV_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,26 @@
/*
* LEAmDNS_Priv.h
*
* License (MIT license):
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
LEAmDNS_Priv.h
License (MIT license):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef MDNS_LWIPDEFS_H
#define MDNS_LWIPDEFS_H

View File

@ -23,22 +23,18 @@
*/
#include <Arduino.h>
#include <bearssl/bearssl_hash.h>
#include "Hash.h"
extern "C" {
#include "sha1/sha1.h"
}
/**
* create a sha1 hash from data
* @param data uint8_t *
* @param size uint32_t
* @param hash uint8_t[20]
*/
void sha1(uint8_t * data, uint32_t size, uint8_t hash[20]) {
SHA1_CTX ctx;
void sha1(const uint8_t* data, uint32_t size, uint8_t hash[20]) {
br_sha1_context ctx;
#ifdef DEBUG_SHA1
os_printf("DATA:");
@ -53,9 +49,9 @@ void sha1(uint8_t * data, uint32_t size, uint8_t hash[20]) {
os_printf("\n");
#endif
SHA1Init(&ctx);
SHA1Update(&ctx, data, size);
SHA1Final(hash, &ctx);
br_sha1_init(&ctx);
br_sha1_update(&ctx, data, size);
br_sha1_out(&ctx, hash);
#ifdef DEBUG_SHA1
os_printf("SHA1:");
@ -66,52 +62,35 @@ void sha1(uint8_t * data, uint32_t size, uint8_t hash[20]) {
#endif
}
void sha1(char * data, uint32_t size, uint8_t hash[20]) {
sha1((uint8_t *) data, size, hash);
void sha1(const char* data, uint32_t size, uint8_t hash[20]) {
sha1((const uint8_t *) data, size, hash);
}
void sha1(const uint8_t * data, uint32_t size, uint8_t hash[20]) {
sha1((uint8_t *) data, size, hash);
}
void sha1(const char * data, uint32_t size, uint8_t hash[20]) {
sha1((uint8_t *) data, size, hash);
}
void sha1(String data, uint8_t hash[20]) {
void sha1(const String& data, uint8_t hash[20]) {
sha1(data.c_str(), data.length(), hash);
}
String sha1(uint8_t* data, uint32_t size) {
String sha1(const uint8_t* data, uint32_t size) {
uint8_t hash[20];
String hashStr = "";
String hashStr((const char*)nullptr);
hashStr.reserve(20 * 2 + 1);
sha1(&data[0], size, &hash[0]);
for(uint16_t i = 0; i < 20; i++) {
String hex = String(hash[i], HEX);
if(hex.length() < 2) {
hex = "0" + hex;
}
char hex[3];
snprintf(hex, sizeof(hex), "%02x", hash[i]);
hashStr += hex;
}
return hashStr;
}
String sha1(char* data, uint32_t size) {
return sha1((uint8_t*) data, size);
}
String sha1(const uint8_t* data, uint32_t size) {
return sha1((uint8_t*) data, size);
}
String sha1(const char* data, uint32_t size) {
return sha1((uint8_t*) data, size);
return sha1((const uint8_t*) data, size);
}
String sha1(String data) {
String sha1(const String& data) {
return sha1(data.c_str(), data.length());
}

View File

@ -27,16 +27,12 @@
//#define DEBUG_SHA1
void sha1(uint8_t * data, uint32_t size, uint8_t hash[20]);
void sha1(char * data, uint32_t size, uint8_t hash[20]);
void sha1(const uint8_t * data, uint32_t size, uint8_t hash[20]);
void sha1(const char * data, uint32_t size, uint8_t hash[20]);
void sha1(String data, uint8_t hash[20]);
void sha1(const uint8_t* data, uint32_t size, uint8_t hash[20]);
void sha1(const char* data, uint32_t size, uint8_t hash[20]);
void sha1(const String& data, uint8_t hash[20]);
String sha1(uint8_t* data, uint32_t size);
String sha1(char* data, uint32_t size);
String sha1(const uint8_t* data, uint32_t size);
String sha1(const char* data, uint32_t size);
String sha1(String data);
String sha1(const String& data);
#endif /* HASH_H_ */

View File

@ -1,208 +0,0 @@
/**
* @file sha1.c
* @date 20.05.2015
* @author Steve Reid <steve@edmweb.com>
*
* from: http://www.virtualbox.org/svn/vbox/trunk/src/recompiler/tests/sha1.c
*/
/* from valgrind tests */
/* ================ sha1.c ================ */
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#define SHA1HANDSOFF
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <c_types.h>
#include "sha1.h"
//#include <endian.h>
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if BYTE_ORDER == LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#elif BYTE_ORDER == BIG_ENDIAN
#define blk0(i) block->l[i]
#else
#error "Endianness not defined!"
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void ICACHE_FLASH_ATTR SHA1Transform(uint32_t state[5], uint8_t buffer[64])
{
uint32_t a, b, c, d, e;
typedef union {
unsigned char c[64];
uint32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
memcpy(block, buffer, 64);
#else
/* The following had better never be used because it causes the
* pointer-to-const buffer to be cast into a pointer to non-const.
* And the result is written through. I threw a "const" in, hoping
* this will cause a diagnostic.
*/
CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
memset(block, '\0', sizeof(block));
#endif
}
/* SHA1Init - Initialize new context */
void ICACHE_FLASH_ATTR SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void ICACHE_FLASH_ATTR SHA1Update(SHA1_CTX* context, uint8_t* data, uint32_t len)
{
uint32_t i;
uint32_t j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1]++;
context->count[1] += (len>>29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void ICACHE_FLASH_ATTR SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
unsigned i;
unsigned char finalcount[8];
unsigned char c;
#if 0 /* untested "improvement" by DHR */
/* Convert context->count to a sequence of bytes
* in finalcount. Second element first, but
* big-endian order within element.
* But we do it all backwards.
*/
unsigned char *fcp = &finalcount[8];
for (i = 0; i < 2; i++)
{
uint32_t t = context->count[i];
int j;
for (j = 0; j < 4; t >>= 8, j++)
*--fcp = (unsigned char) t;
}
#else
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
#endif
c = 0200;
SHA1Update(context, &c, 1);
while ((context->count[0] & 504) != 448) {
c = 0000;
SHA1Update(context, &c, 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
memset(context, '\0', sizeof(*context));
memset(&finalcount, '\0', sizeof(finalcount));
}
/* ================ end of sha1.c ================ */

View File

@ -1,32 +0,0 @@
/**
* @file sha1.h
* @date 20.05.2015
* @author Steve Reid <steve@edmweb.com>
*
* from: http://www.virtualbox.org/svn/vbox/trunk/src/recompiler/tests/sha1.c
*/
/* ================ sha1.h ================ */
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
*/
#ifndef SHA1_H_
#define SHA1_H_
typedef struct {
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
void SHA1Transform(uint32_t state[5], uint8_t buffer[64]);
void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, uint8_t* data, uint32_t len);
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
#endif /* SHA1_H_ */
/* ================ end of sha1.h ================ */

View File

@ -24,7 +24,7 @@
#include <Arduino.h>
#include <stdlib.h>
#define SPI_HAS_TRANSACTION
#define SPI_HAS_TRANSACTION 1
// This defines are not representing the real Divider of the ESP8266
// the Defines match to an AVR Arduino on 16MHz for better compatibility

@ -1 +1 @@
Subproject commit 776d49b2f570b93fe88ad7a082519b4fb56be817
Subproject commit 8f85d649000b5bbdde1862d879dba4f225dd3a51

View File

@ -1,31 +1,31 @@
/*
TwoWire.cpp - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
TwoWire.cpp - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
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
version 2.1 of the License, or (at your option) any later version.
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support
*/
extern "C" {
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
}
#include "twi.h"
@ -58,226 +58,273 @@ static int default_scl_pin = SCL;
// Constructors ////////////////////////////////////////////////////////////////
TwoWire::TwoWire(){}
TwoWire::TwoWire() {}
// Public Methods //////////////////////////////////////////////////////////////
void TwoWire::begin(int sda, int scl){
default_sda_pin = sda;
default_scl_pin = scl;
twi_init(sda, scl);
flush();
void TwoWire::begin(int sda, int scl)
{
default_sda_pin = sda;
default_scl_pin = scl;
twi_init(sda, scl);
flush();
}
void TwoWire::begin(int sda, int scl, uint8_t address){
default_sda_pin = sda;
default_scl_pin = scl;
twi_setAddress(address);
twi_init(sda, scl);
twi_attachSlaveTxEvent(onRequestService);
twi_attachSlaveRxEvent(onReceiveService);
flush();
void TwoWire::begin(int sda, int scl, uint8_t address)
{
default_sda_pin = sda;
default_scl_pin = scl;
twi_setAddress(address);
twi_init(sda, scl);
twi_attachSlaveTxEvent(onRequestService);
twi_attachSlaveRxEvent(onReceiveService);
flush();
}
void TwoWire::pins(int sda, int scl){
default_sda_pin = sda;
default_scl_pin = scl;
void TwoWire::pins(int sda, int scl)
{
default_sda_pin = sda;
default_scl_pin = scl;
}
void TwoWire::begin(void){
begin(default_sda_pin, default_scl_pin);
void TwoWire::begin(void)
{
begin(default_sda_pin, default_scl_pin);
}
void TwoWire::begin(uint8_t address){
twi_setAddress(address);
twi_attachSlaveTxEvent(onRequestService);
twi_attachSlaveRxEvent(onReceiveService);
begin();
void TwoWire::begin(uint8_t address)
{
twi_setAddress(address);
twi_attachSlaveTxEvent(onRequestService);
twi_attachSlaveRxEvent(onReceiveService);
begin();
}
uint8_t TwoWire::status(){
return twi_status();
uint8_t TwoWire::status()
{
return twi_status();
}
void TwoWire::begin(int address){
begin((uint8_t)address);
void TwoWire::begin(int address)
{
begin((uint8_t)address);
}
void TwoWire::setClock(uint32_t frequency){
twi_setClock(frequency);
void TwoWire::setClock(uint32_t frequency)
{
twi_setClock(frequency);
}
void TwoWire::setClockStretchLimit(uint32_t limit){
twi_setClockStretchLimit(limit);
void TwoWire::setClockStretchLimit(uint32_t limit)
{
twi_setClockStretchLimit(limit);
}
size_t TwoWire::requestFrom(uint8_t address, size_t size, bool sendStop){
if(size > BUFFER_LENGTH){
size = BUFFER_LENGTH;
}
size_t read = (twi_readFrom(address, rxBuffer, size, sendStop) == 0)?size:0;
rxBufferIndex = 0;
rxBufferLength = read;
return read;
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop){
return requestFrom(address, static_cast<size_t>(quantity), static_cast<bool>(sendStop));
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity){
return requestFrom(address, static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity){
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop){
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity), static_cast<bool>(sendStop));
}
void TwoWire::beginTransmission(uint8_t address){
transmitting = 1;
txAddress = address;
txBufferIndex = 0;
txBufferLength = 0;
}
void TwoWire::beginTransmission(int address){
beginTransmission((uint8_t)address);
}
uint8_t TwoWire::endTransmission(uint8_t sendStop){
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, sendStop);
txBufferIndex = 0;
txBufferLength = 0;
transmitting = 0;
return ret;
}
uint8_t TwoWire::endTransmission(void){
return endTransmission(true);
}
size_t TwoWire::write(uint8_t data){
if(transmitting){
if(txBufferLength >= BUFFER_LENGTH){
setWriteError();
return 0;
size_t TwoWire::requestFrom(uint8_t address, size_t size, bool sendStop)
{
if (size > BUFFER_LENGTH)
{
size = BUFFER_LENGTH;
}
txBuffer[txBufferIndex] = data;
++txBufferIndex;
txBufferLength = txBufferIndex;
} else {
twi_transmit(&data, 1);
}
return 1;
size_t read = (twi_readFrom(address, rxBuffer, size, sendStop) == 0) ? size : 0;
rxBufferIndex = 0;
rxBufferLength = read;
return read;
}
size_t TwoWire::write(const uint8_t *data, size_t quantity){
if(transmitting){
for(size_t i = 0; i < quantity; ++i){
if(!write(data[i])) return i;
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
{
return requestFrom(address, static_cast<size_t>(quantity), static_cast<bool>(sendStop));
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
return requestFrom(address, static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity)
{
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
{
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity), static_cast<bool>(sendStop));
}
void TwoWire::beginTransmission(uint8_t address)
{
transmitting = 1;
txAddress = address;
txBufferIndex = 0;
txBufferLength = 0;
}
void TwoWire::beginTransmission(int address)
{
beginTransmission((uint8_t)address);
}
uint8_t TwoWire::endTransmission(uint8_t sendStop)
{
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, sendStop);
txBufferIndex = 0;
txBufferLength = 0;
transmitting = 0;
return ret;
}
uint8_t TwoWire::endTransmission(void)
{
return endTransmission(true);
}
size_t TwoWire::write(uint8_t data)
{
if (transmitting)
{
if (txBufferLength >= BUFFER_LENGTH)
{
setWriteError();
return 0;
}
txBuffer[txBufferIndex] = data;
++txBufferIndex;
txBufferLength = txBufferIndex;
}
}else{
twi_transmit(data, quantity);
}
return quantity;
else
{
twi_transmit(&data, 1);
}
return 1;
}
int TwoWire::available(void){
int result = rxBufferLength - rxBufferIndex;
if (!result) {
// yielding here will not make more data "available",
// but it will prevent the system from going into WDT reset
optimistic_yield(1000);
}
return result;
size_t TwoWire::write(const uint8_t *data, size_t quantity)
{
if (transmitting)
{
for (size_t i = 0; i < quantity; ++i)
{
if (!write(data[i]))
{
return i;
}
}
}
else
{
twi_transmit(data, quantity);
}
return quantity;
}
int TwoWire::read(void){
int value = -1;
if(rxBufferIndex < rxBufferLength){
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
}
return value;
int TwoWire::available(void)
{
int result = rxBufferLength - rxBufferIndex;
if (!result)
{
// yielding here will not make more data "available",
// but it will prevent the system from going into WDT reset
optimistic_yield(1000);
}
return result;
}
int TwoWire::peek(void){
int value = -1;
if(rxBufferIndex < rxBufferLength){
value = rxBuffer[rxBufferIndex];
}
return value;
int TwoWire::read(void)
{
int value = -1;
if (rxBufferIndex < rxBufferLength)
{
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
}
return value;
}
void TwoWire::flush(void){
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
int TwoWire::peek(void)
{
int value = -1;
if (rxBufferIndex < rxBufferLength)
{
value = rxBuffer[rxBufferIndex];
}
return value;
}
void TwoWire::flush(void)
{
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
}
void TwoWire::onReceiveService(uint8_t* inBytes, size_t numBytes)
{
// don't bother if user hasn't registered a callback
if (!user_onReceive) {
return;
}
// // don't bother if rx buffer is in use by a master requestFrom() op
// // i know this drops data, but it allows for slight stupidity
// // meaning, they may not have read all the master requestFrom() data yet
// if(rxBufferIndex < rxBufferLength){
// return;
// }
// copy twi rx buffer into local read buffer
// this enables new reads to happen in parallel
for (uint8_t i = 0; i < numBytes; ++i) {
rxBuffer[i] = inBytes[i];
}
// set rx iterator vars
rxBufferIndex = 0;
rxBufferLength = numBytes;
// alert user program
user_onReceive(numBytes);
// don't bother if user hasn't registered a callback
if (!user_onReceive)
{
return;
}
// // don't bother if rx buffer is in use by a master requestFrom() op
// // i know this drops data, but it allows for slight stupidity
// // meaning, they may not have read all the master requestFrom() data yet
// if(rxBufferIndex < rxBufferLength){
// return;
// }
// copy twi rx buffer into local read buffer
// this enables new reads to happen in parallel
for (uint8_t i = 0; i < numBytes; ++i)
{
rxBuffer[i] = inBytes[i];
}
// set rx iterator vars
rxBufferIndex = 0;
rxBufferLength = numBytes;
// alert user program
user_onReceive(numBytes);
}
void TwoWire::onRequestService(void)
{
// don't bother if user hasn't registered a callback
if (!user_onRequest) {
return;
}
// reset tx buffer iterator vars
// !!! this will kill any pending pre-master sendTo() activity
txBufferIndex = 0;
txBufferLength = 0;
// alert user program
user_onRequest();
// don't bother if user hasn't registered a callback
if (!user_onRequest)
{
return;
}
// reset tx buffer iterator vars
// !!! this will kill any pending pre-master sendTo() activity
txBufferIndex = 0;
txBufferLength = 0;
// alert user program
user_onRequest();
}
void TwoWire::onReceive( void (*function)(int) ) {
// arduino api compatibility fixer:
// really hope size parameter will not exceed 2^31 :)
static_assert(sizeof(int) == sizeof(size_t), "something is wrong in Arduino kingdom");
user_onReceive = reinterpret_cast<void(*)(size_t)>(function);
void TwoWire::onReceive(void (*function)(int))
{
// arduino api compatibility fixer:
// really hope size parameter will not exceed 2^31 :)
static_assert(sizeof(int) == sizeof(size_t), "something is wrong in Arduino kingdom");
user_onReceive = reinterpret_cast<void(*)(size_t)>(function);
}
void TwoWire::onReceive( void (*function)(size_t) ) {
user_onReceive = function;
void TwoWire::onReceive(void (*function)(size_t))
{
user_onReceive = function;
twi_enableSlaveMode();
}
void TwoWire::onRequest( void (*function)(void) ){
user_onRequest = function;
void TwoWire::onRequest(void (*function)(void))
{
user_onRequest = function;
twi_enableSlaveMode();
}
// Preinstantiate Objects //////////////////////////////////////////////////////

View File

@ -1,24 +1,24 @@
/*
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
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
version 2.1 of the License, or (at your option) any later version.
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
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
*/
#ifndef TwoWire_h
@ -33,7 +33,7 @@
class TwoWire : public Stream
{
private:
private:
static uint8_t rxBuffer[];
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;
@ -48,10 +48,10 @@ class TwoWire : public Stream
static void (*user_onReceive)(size_t);
static void onRequestService(void);
static void onReceiveService(uint8_t*, size_t);
public:
public:
TwoWire();
void begin(int sda, int scl);
void begin(int sda, int scl, uint8_t address);
void begin(int sda, int scl, uint8_t address);
void pins(int sda, int scl) __attribute__((deprecated)); // use begin(sda, scl) in new code
void begin();
void begin(uint8_t);
@ -63,22 +63,22 @@ class TwoWire : public Stream
uint8_t endTransmission(void);
uint8_t endTransmission(uint8_t);
size_t requestFrom(uint8_t address, size_t size, bool sendStop);
uint8_t status();
uint8_t status();
uint8_t requestFrom(uint8_t, uint8_t);
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
uint8_t requestFrom(int, int);
uint8_t requestFrom(int, int, int);
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *, size_t);
virtual int available(void);
virtual int read(void);
virtual int peek(void);
virtual void flush(void);
void onReceive( void (*)(int) ); // arduino api
void onReceive( void (*)(size_t) ); // legacy esp8266 backward compatibility
void onRequest( void (*)(void) );
void onReceive(void (*)(int)); // arduino api
void onReceive(void (*)(size_t)); // legacy esp8266 backward compatibility
void onRequest(void (*)(void));
using Print::write;
};

View File

@ -1,80 +1,160 @@
/*
NTP-TZ-DST
NTP-TZ-DST (v2)
NetWork Time Protocol - Time Zone - Daylight Saving Time
This example shows how to read and set time,
and how to use NTP (set NTP0_OR_LOCAL1 to 0 below)
or an external RTC (set NTP0_OR_LOCAL1 to 1 below)
TZ and DST below have to be manually set
according to your local settings.
This example shows:
- how to read and set time
- how to set timezone per country/city
- how is local time automatically handled per official timezone definitions
- how to change internal sntp start and update delay
- how to use callbacks when time is updated
This example code is in the public domain.
*/
#include <ESP8266WiFi.h>
#include <time.h> // time() ctime()
#include <sys/time.h> // struct timeval
#include <coredecls.h> // settimeofday_cb()
////////////////////////////////////////////////////////
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
#define SSID STASSID
#define SSIDPWD STAPSK
#define TZ 1 // (utc+) TZ in hours
#define DST_MN 60 // use 60mn for summer time in some countries
// initial time (possibly given by an external RTC)
#define RTC_UTC_TEST 1510592825 // 1510592825 = Monday 13 November 2017 17:07:05 UTC
#define NTP0_OR_LOCAL1 1 // 0:use NTP 1:fake external RTC
#define RTC_TEST 1510592825 // 1510592825 = Monday 13 November 2017 17:07:05 UTC
// This database is autogenerated from IANA timezone database
// https://www.iana.org/time-zones
// and can be updated on demand in this repository
#include <TZ.h>
// "TZ_" macros follow DST change across seasons without source code change
// check for your nearest city in TZ.h
// espressif headquarter TZ
//#define MYTZ TZ_Asia_Shanghai
// example for "Not Only Whole Hours" timezones:
// Kolkata/Calcutta is shifted by 30mn
//#define MYTZ TZ_Asia_Kolkata
// example of a timezone with a variable Daylight-Saving-Time:
// demo: watch automatic time adjustment on Summer/Winter change (DST)
#define MYTZ TZ_Europe_London
////////////////////////////////////////////////////////
#define TZ_MN ((TZ)*60)
#define TZ_SEC ((TZ)*3600)
#define DST_SEC ((DST_MN)*60)
#include <ESP8266WiFi.h>
#include <coredecls.h> // settimeofday_cb()
#include <Schedule.h>
#include <PolledTimeout.h>
timeval cbtime; // time set in callback
bool cbtime_set = false;
#include <time.h> // time() ctime()
#include <sys/time.h> // struct timeval
void time_is_set(void) {
gettimeofday(&cbtime, NULL);
cbtime_set = true;
Serial.println("------------------ settimeofday() was called ------------------");
}
void setup() {
Serial.begin(115200);
settimeofday_cb(time_is_set);
#if NTP0_OR_LOCAL1
// local
ESP.eraseConfig();
time_t rtc = RTC_TEST;
timeval tv = { rtc, 0 };
timezone tz = { TZ_MN + DST_MN, 0 };
settimeofday(&tv, &tz);
#else // ntp
configTime(TZ_SEC, DST_SEC, "pool.ntp.org");
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, SSIDPWD);
// don't wait, observe time changing when ntp timestamp is received
#endif // ntp
}
#include <sntp.h> // sntp_servermode_dhcp()
// for testing purpose:
extern "C" int clock_gettime(clockid_t unused, struct timespec *tp);
////////////////////////////////////////////////////////
static timeval tv;
static timespec tp;
static time_t now;
static uint32_t now_ms, now_us;
static esp8266::polledTimeout::periodicMs showTimeNow(60000);
static int time_machine_days = 0; // 0 = now
static bool time_machine_running = false;
// OPTIONAL: change SNTP startup delay
// a weak function is already defined and returns 0 (RFC violation)
// it can be redefined:
//uint32_t sntp_startup_delay_MS_rfc_not_less_than_60000 ()
//{
// //info_sntp_startup_delay_MS_rfc_not_less_than_60000_has_been_called = true;
// return 60000; // 60s (or lwIP's original default: (random() % 5000))
//}
// OPTIONAL: change SNTP update delay
// a weak function is already defined and returns 1 hour
// it can be redefined:
//uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 ()
//{
// //info_sntp_update_delay_MS_rfc_not_less_than_15000_has_been_called = true;
// return 15000; // 15s
//}
void showTime() {
gettimeofday(&tv, nullptr);
clock_gettime(0, &tp);
now = time(nullptr);
now_ms = millis();
now_us = micros();
Serial.println();
printTm("localtime:", localtime(&now));
Serial.println();
printTm("gmtime: ", gmtime(&now));
Serial.println();
// time from boot
Serial.print("clock: ");
Serial.print((uint32_t)tp.tv_sec);
Serial.print("s / ");
Serial.print((uint32_t)tp.tv_nsec);
Serial.println("ns");
// time from boot
Serial.print("millis: ");
Serial.println(now_ms);
Serial.print("micros: ");
Serial.println(now_us);
// EPOCH+tz+dst
Serial.print("gtod: ");
Serial.print((uint32_t)tv.tv_sec);
Serial.print("s / ");
Serial.print((uint32_t)tv.tv_usec);
Serial.println("us");
// EPOCH+tz+dst
Serial.print("time: ");
Serial.println((uint32_t)now);
// timezone and demo in the future
Serial.printf("timezone: %s\n", MYTZ);
// human readable
Serial.print("ctime: ");
Serial.print(ctime(&now));
#if LWIP_VERSION_MAJOR > 1
// LwIP v2 is able to list more details about the currently configured SNTP servers
for (int i = 0; i < SNTP_MAX_SERVERS; i++) {
IPAddress sntp = *sntp_getserver(i);
const char* name = sntp_getservername(i);
if (sntp.isSet()) {
Serial.printf("sntp%d: ", i);
if (name) {
Serial.printf("%s (%s) ", name, sntp.toString().c_str());
} else {
Serial.printf("%s ", sntp.toString().c_str());
}
Serial.printf("IPv6: %s Reachability: %o\n",
sntp.isV6() ? "Yes" : "No",
sntp_getreachability(i));
}
}
#endif
Serial.println();
}
#define PTM(w) \
Serial.print(":" #w "="); \
Serial.print(" " #w "="); \
Serial.print(tm->tm_##w);
void printTm(const char* what, const tm* tm) {
@ -84,61 +164,74 @@ void printTm(const char* what, const tm* tm) {
PTM(hour); PTM(min); PTM(sec);
}
timeval tv;
timespec tp;
time_t now;
uint32_t now_ms, now_us;
void time_is_set_scheduled() {
// everything is allowed in this function
void loop() {
gettimeofday(&tv, nullptr);
clock_gettime(0, &tp);
now = time(nullptr);
now_ms = millis();
now_us = micros();
// localtime / gmtime every second change
static time_t lastv = 0;
if (lastv != tv.tv_sec) {
lastv = tv.tv_sec;
Serial.println();
printTm("localtime", localtime(&now));
Serial.println();
printTm("gmtime ", gmtime(&now));
Serial.println();
Serial.println();
if (time_machine_days == 0) {
time_machine_running = !time_machine_running;
}
// time from boot
Serial.print("clock:");
Serial.print((uint32_t)tp.tv_sec);
Serial.print("/");
Serial.print((uint32_t)tp.tv_nsec);
Serial.print("ns");
// time from boot
Serial.print(" millis:");
Serial.print(now_ms);
Serial.print(" micros:");
Serial.print(now_us);
// EPOCH+tz+dst
Serial.print(" gtod:");
Serial.print((uint32_t)tv.tv_sec);
Serial.print("/");
Serial.print((uint32_t)tv.tv_usec);
Serial.print("us");
// EPOCH+tz+dst
Serial.print(" time:");
Serial.print((uint32_t)now);
// human readable
Serial.print(" ctime:(UTC+");
Serial.print((uint32_t)(TZ * 60 + DST_MN));
Serial.print("mn)");
Serial.print(ctime(&now));
// simple drifting loop
delay(100);
// time machine demo
if (time_machine_running) {
if (time_machine_days == 0)
Serial.printf("---- settimeofday() has been called - possibly from SNTP\n"
" (starting time machine demo to show libc's automatic DST handling)\n\n");
now = time(nullptr);
const tm* tm = localtime(&now);
Serial.printf("future=%3ddays: DST=%s - ",
time_machine_days,
tm->tm_isdst ? "true " : "false");
Serial.print(ctime(&now));
gettimeofday(&tv, nullptr);
constexpr int days = 30;
time_machine_days += days;
if (time_machine_days > 360) {
tv.tv_sec -= (time_machine_days - days) * 60 * 60 * 24;
time_machine_days = 0;
} else {
tv.tv_sec += days * 60 * 60 * 24;
}
settimeofday(&tv, nullptr);
} else {
showTime();
}
}
void setup() {
Serial.begin(115200);
Serial.println("\nStarting...\n");
// setup RTC time
// it will be used until NTP server will send us real current time
time_t rtc = RTC_UTC_TEST;
timeval tv = { rtc, 0 };
timezone tz = { 0, 0 };
settimeofday(&tv, &tz);
// install callback - called when settimeofday is called (by SNTP or us)
// once enabled (by DHCP), SNTP is updated every hour
settimeofday_cb(time_is_set_scheduled);
// NTP servers may be overriden by your DHCP server for a more local one
// (see below)
configTime(MYTZ, "pool.ntp.org");
// OPTIONAL: disable obtaining SNTP servers from DHCP
//sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default)
// start network
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
// don't wait for network, observe time changing
// when NTP timestamp is received
Serial.printf("Time is currently set by a constant:\n");
showTime();
}
void loop() {
if (showTimeNow) {
showTime();
}
}

View File

@ -7,4 +7,4 @@ paragraph=
category=Other
url=
architectures=esp8266
dot_a_linkage=true
dot_a_linkage=false

View File

@ -107,18 +107,23 @@ Here is an overview of the release process. See the section below for detailed i
The following points assume work in a direct clone of the repository, and not in a personal fork.
2. Update `version` to the release in platform.txt and commit. E.g. `2.5.0`. Make a PR, wait for Travis CI, and merge.
2. Make a PR with the following, wait for Travis CI, and merge.
3. Tag the latest commit on the master branch. In this project, tags have form `X.Y.Z`, e.g. `2.4.0`, or `X.Y.Z-betaN` for release candiate versions. Notice that there's no `v`at the beginning of the tag. Tags must be annotated, not lightweight tags. To create a tag, use git command (assuming that the master branch is checked out):
* platform.txt: update `version` to the release E.g. `3.0.0`,
* `cores/esp8266/TZ.h`: import the latest database with the following shell command:\
`$ cd tools; sh TZupdate.sh`.
3. Tag the latest commit on the master branch. In this project, tags have form `X.Y.Z`, e.g. `3.0.0`, or `X.Y.Z-betaN` for release candiate versions. Notice that there's no `v`at the beginning of the tag. Tags must be annotated, not lightweight tags. To create a tag, use git command (assuming that the master branch is checked out):
```
git tag -a -m "Release 2.5.0" 2.5.0
git tag -a -m "Release 3.0.0" 3.0.0
```
then push the tag created in step 3 to esp8266/Arduino Github repository:
```
git push origin 2.5.0
git push origin 3.0.0
```
4. In case something goes wrong, release can be canceled at any time:
@ -141,7 +146,7 @@ The following points assume work in a direct clone of the repository, and not in
11. Create a commit to the master branch, updating:
* The version in platform.txt file. This should correspond to the version of the *next* milestone, plus `-dev` suffix. E.g. `2.5.0-dev`.
* The version in platform.txt file. This should correspond to the version of the *next* milestone, plus `-dev` suffix. E.g. `3.1.0-dev`.
* In main README.md:

View File

@ -3,25 +3,37 @@
#set -x
# Extract next version from platform.txt
next=`sed -n -E 's/version=([0-9.]+)/\1/p' ../platform.txt`
ver=`git describe --tag`
visiblever=$ver
if [ "$ver" = 0.0.1 ]; then
# Figure out how will the package be called
ver=`git describe --exact-match`
if [ $? -ne 0 ]; then
# not tagged version; generate nightly package
date_str=`date +"%Y%m%d"`
is_nightly=1
plain_ver="${next}-nightly"
ver="${plain_ver}+${date_str}"
else
git tag -d 0.0.1
ver=`git describe --tag HEAD`
plain_ver=$ver
else
# Extract next version from platform.txt
next=`sed -n -E 's/version=([0-9.]+)/\1/p' ../platform.txt`
# Figure out how will the package be called
ver=`git describe --exact-match`
if [ $? -ne 0 ]; then
# not tagged version; generate nightly package
date_str=`date +"%Y%m%d"`
is_nightly=1
plain_ver="${next}-nightly"
ver="${plain_ver}+${date_str}"
else
plain_ver=$ver
fi
visiblever=$ver
fi
set -e
package_name=esp8266-$ver
echo "Version: $ver"
package_name=esp8266-$visiblever
echo "Version: $visiblever ($ver)"
echo "Package name: $package_name"
# Set REMOTE_URL environment variable to the address where the package will be
@ -34,7 +46,7 @@ echo "Remote: $REMOTE_URL"
if [ -z "$PKG_URL" ]; then
if [ -z "$PKG_URL_PREFIX" ]; then
PKG_URL_PREFIX="$REMOTE_URL/versions/$ver"
PKG_URL_PREFIX="$REMOTE_URL/versions/$visiblever"
fi
PKG_URL="$PKG_URL_PREFIX/$package_name.zip"
fi
@ -43,9 +55,9 @@ echo "Docs: $DOC_URL"
pushd ..
# Create directory for the package
outdir=package/versions/$ver/$package_name
outdir=package/versions/$visiblever/$package_name
srcdir=$PWD
rm -rf package/versions/$ver
rm -rf package/versions/$visiblever
mkdir -p $outdir
# Some files should be excluded from the package
@ -96,7 +108,7 @@ echo \#define ARDUINO_ESP8266_RELEASE_$ver_define >>$outdir/cores/esp8266/core_v
echo \#define ARDUINO_ESP8266_RELEASE \"$ver_define\" >>$outdir/cores/esp8266/core_version.h
# Zip the package
pushd package/versions/$ver
pushd package/versions/$visiblever
echo "Making $package_name.zip"
zip -qr $package_name.zip $package_name
rm -rf $package_name
@ -109,7 +121,7 @@ echo SHA-256: $sha
echo "Making package_esp8266com_index.json"
jq_arg=".packages[0].platforms[0].version = \"$ver\" | \
jq_arg=".packages[0].platforms[0].version = \"$visiblever\" | \
.packages[0].platforms[0].url = \"$PKG_URL\" |\
.packages[0].platforms[0].archiveFileName = \"$package_name.zip\""

View File

@ -359,4 +359,4 @@
]
}
]
}
}

View File

@ -39,7 +39,7 @@ build.stdcpp_level=-std=gnu++11
build.float=-u _printf_float -u _scanf_float
build.led=
build.sdk=NONOSDK22y
build.sdk=NONOSDK22x_190703
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
compiler.sdk.path={runtime.platform.path}/tools/sdk
@ -137,7 +137,8 @@ tools.esptool.cmd={runtime.platform.path}/tools/python3/python3
tools.esptool.network_cmd={runtime.platform.path}/tools/python3/python3
tools.esptool.upload.protocol=esp
tools.esptool.upload.params.verbose=--trace
# esptool.py --trace option is a debug option, not a verbose option
tools.esptool.upload.params.verbose=
tools.esptool.upload.params.quiet=
# First, potentially perform an erase or nothing

View File

@ -9,6 +9,7 @@ ${org}/../restyle.sh
# Revert changes which astyle might have done to the submodules,
# as we don't want to fail the build because of the 3rd party libraries
git submodule foreach --recursive git reset --hard
git --version || true
git submodule foreach --recursive 'git reset --hard'
git diff --exit-code -- $TRAVIS_BUILD_DIR/libraries

View File

@ -153,19 +153,31 @@ function install_libraries()
function install_ide()
{
#local idever='nightly'
#local ideurl='https://www.arduino.cc/download.php?f=/arduino-nightly'
local idever='1.8.10'
local ideurl="https://downloads.arduino.cc/arduino-$idever"
echo "using Arduino IDE distribution ${idever}"
local ide_path=$1
local core_path=$2
local debug=$3
if [ "$WINDOWS" = "1" ]; then
# Acquire needed packages from Windows package manager
choco install --no-progress python3
export PATH="/c/Python37:$PATH" # Ensure it's live from now on...
cp /c/Python37/python.exe /c/Python37/python3.exe
choco install --no-progress python3 >& pylog.txt
# Parse the python instrall dir from the output log. Sorry, can't set it via choco on the free version
PYDIR=$(cat pylog.txt | grep "^Installed to:" | cut -f2 -d"'" | sed 's/C:\\/\/c\//')
echo "Detected python3 install dir: $PYDIR"
export PATH="$PYDIR:$PATH" # Ensure it's live from now on...
cp "$PYDIR/python.exe" "$PYDIR/python3.exe"
choco install --no-progress unzip
choco install --no-progress sed
#choco install --no-progress golang
test -r arduino-nightly-windows.zip || wget -nv -O arduino-nightly-windows.zip https://www.arduino.cc/download.php?f=/arduino-nightly-windows.zip
unzip -q arduino-nightly-windows.zip
test -r arduino-windows.zip || wget -nv -O arduino-windows.zip "${ideurl}-windows.zip"
unzip -q arduino-windows.zip
mv arduino-${idever} arduino-distrib
elif [ "$MACOSX" = "1" ]; then
# MACOS only has next-to-obsolete Python2 installed. Install Python 3 from python.org
wget https://www.python.org/ftp/python/3.7.4/python-3.7.4-macosx10.9.pkg
@ -173,15 +185,17 @@ function install_ide()
# Install the Python3 certificates, because SSL connections fail w/o them and of course they aren't installed by default.
( cd "/Applications/Python 3.7/" && sudo "./Install Certificates.command" )
# Hack to place arduino-builder in the same spot as sane OSes
test -r arduino.zip || wget -O arduino.zip https://downloads.arduino.cc/arduino-nightly-macosx.zip
unzip -q arduino.zip
mv Arduino.app arduino-nightly
mv arduino-nightly/Contents/Java/* arduino-nightly/.
test -r arduino-macos.zip || wget -O arduino-macos.zip "${ideurl}-macosx.zip"
unzip -q arduino-macos.zip
mv Arduino.app arduino-distrib
mv arduino-distrib/Contents/Java/* arduino-distrib/.
else
test -r arduino.tar.xz || wget -O arduino.tar.xz https://www.arduino.cc/download.php?f=/arduino-nightly-linux64.tar.xz
tar xf arduino.tar.xz
#test -r arduino.tar.xz || wget -O arduino.tar.xz https://www.arduino.cc/download.php?f=/arduino-nightly-linux64.tar.xz
test -r arduino-linux.tar.xz || wget -O arduino-linux.tar.xz "${ideurl}-linux64.tar.xz"
tar xf arduino-linux.tar.xz
mv arduino-${idever} arduino-distrib
fi
mv arduino-nightly $ide_path
mv arduino-distrib $ide_path
cd $ide_path/hardware
mkdir esp8266com
cd esp8266com

View File

@ -11,9 +11,9 @@ UPLOAD_PORT ?= $(shell ls /dev/tty* | grep -m 1 -i USB)
UPLOAD_BAUD ?= 460800
UPLOAD_BOARD ?= nodemcu
BS_DIR ?= libraries/BSTest
DEBUG_LEVEL ?= DebugLevel=None____
DEBUG_LEVEL ?= lvl=None____
#FQBN ?= esp8266com:esp8266:generic:CpuFrequency=80,FlashFreq=40,FlashMode=dio,UploadSpeed=115200,FlashSize=4M1M,LwIPVariant=v2mss536,ResetMethod=none,Debug=Serial,$(DEBUG_LEVEL)
FQBN ?= esp8266com:esp8266:generic:xtal=80,FlashFreq=40,FlashMode=dio,baud=115200,eesz=4M1M,ip=lm2f,ResetMethod=none,dbg=Serial,$(DEBUG_LEVEL)
FQBN ?= esp8266com:esp8266:generic:xtal=160,FlashFreq=40,FlashMode=dio,baud=115200,eesz=4M1M,ip=lm2f,ResetMethod=none,dbg=Serial,$(DEBUG_LEVEL)
BUILD_TOOL := $(ARDUINO_IDE_PATH)/arduino-builder
TEST_CONFIG := test_env.cfg
TEST_REPORT_XML := test_report.xml
@ -104,7 +104,7 @@ ifneq ("$(NO_RUN)","1")
endif
$(TEST_REPORT_XML): $(HARDWARE_DIR) virtualenv
$(SILENT)$(BS_DIR)/virtualenv/bin/xunitmerge $(shell find $(BUILD_DIR) -name 'test_result.xml' | xargs echo) $(TEST_REPORT_XML)
$(SILENT)$(BS_DIR)/xunitmerge $(shell find $(BUILD_DIR) -name 'test_result.xml' | xargs echo) $(TEST_REPORT_XML)
$(TEST_REPORT_HTML): $(TEST_REPORT_XML) | virtualenv
$(SILENT)$(BS_DIR)/virtualenv/bin/junit2html $< $@
@ -125,6 +125,7 @@ virtualenv:
clean:
rm -rf $(BUILD_DIR)
rm -rf $(HARDWARE_DIR)
rm -rf $(BS_DIR)/virtualenv
rm -f $(TEST_REPORT_HTML) $(TEST_REPORT_XML)
distclean: clean

View File

@ -3,6 +3,5 @@ junit-xml
MarkupSafe
pexpect
pyserial
xunitmerge
junit2html
poster
poster3

View File

@ -236,10 +236,10 @@ ser = None
def spawn_port(port_name, baudrate=115200):
global ser
ser = serial.serial_for_url(port_name, baudrate=baudrate)
return fdpexpect.fdspawn(ser, 'wb', timeout=0)
return fdpexpect.fdspawn(ser, 'wb', timeout=0, encoding='cp437')
def spawn_exec(name):
return pexpect.spawn(name, timeout=0)
return pexpect.spawn(name, timeout=0, encoding='cp437')
def run_tests(spawn, name, mocks, env_vars):
tw = BSTestRunner(spawn, name, mocks, env_vars)

View File

@ -0,0 +1,154 @@
# Cloned from https://github.com/miki725/xunitmerge
# to fix a Python3 error.
#
# xunitmerge is MIT licensed by Miroslav Shubernetskiy https://github.com/miki725
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from contextlib import contextmanager
from xml.etree import ElementTree as etree
from xml.sax.saxutils import quoteattr
import six
CNAME_TAGS = ('system-out', 'skipped', 'error', 'failure')
CNAME_PATTERN = '<![CDATA[{}]]>'
TAG_PATTERN = '<{tag}{attrs}>{text}</{tag}>'
@contextmanager
def patch_etree_cname(etree):
"""
Patch ElementTree's _serialize_xml function so that it will
write text as CDATA tag for tags tags defined in CNAME_TAGS.
>>> import re
>>> from xml.etree import ElementTree
>>> xml_string = '''
... <testsuite name="nosetests" tests="1" errors="0" failures="0" skip="0">
... <testcase classname="some.class.Foo" name="test_system_out" time="0.001">
... <system-out>Some output here</system-out>
... </testcase>
... <testcase classname="some.class.Foo" name="test_skipped" time="0.001">
... <skipped type="unittest.case.SkipTest" message="Skipped">Skipped</skipped>
... </testcase>
... <testcase classname="some.class.Foo" name="test_error" time="0.001">
... <error type="KeyError" message="Error here">Error here</error>
... </testcase>
... <testcase classname="some.class.Foo" name="test_failure" time="0.001">
... <failure type="AssertionError" message="Failure here">Failure here</failure>
... </testcase>
... </testsuite>
... '''
>>> tree = ElementTree.fromstring(xml_string)
>>> with patch_etree_cname(ElementTree):
... saved = str(ElementTree.tostring(tree))
>>> systemout = re.findall(r'(<system-out>.*?</system-out>)', saved)[0]
>>> print(systemout)
<system-out><![CDATA[Some output here]]></system-out>
>>> skipped = re.findall(r'(<skipped.*?</skipped>)', saved)[0]
>>> print(skipped)
<skipped message="Skipped" type="unittest.case.SkipTest"><![CDATA[Skipped]]></skipped>
>>> error = re.findall(r'(<error.*?</error>)', saved)[0]
>>> print(error)
<error message="Error here" type="KeyError"><![CDATA[Error here]]></error>
>>> failure = re.findall(r'(<failure.*?</failure>)', saved)[0]
>>> print(failure)
<failure message="Failure here" type="AssertionError"><![CDATA[Failure here]]></failure>
"""
original_serialize = etree._serialize_xml
def _serialize_xml(write, elem, *args, **kwargs):
if elem.tag in CNAME_TAGS:
attrs = ' '.join(
['{}={}'.format(k, quoteattr(v))
for k, v in sorted(elem.attrib.items())]
)
attrs = ' ' + attrs if attrs else ''
text = CNAME_PATTERN.format(elem.text)
write(TAG_PATTERN.format(
tag=elem.tag,
attrs=attrs,
text=text
))
else:
original_serialize(write, elem, *args, **kwargs)
etree._serialize_xml = etree._serialize['xml'] = _serialize_xml
yield
etree._serialize_xml = etree._serialize['xml'] = original_serialize
def merge_trees(*trees):
"""
Merge all given XUnit ElementTrees into a single ElementTree.
This combines all of the children test-cases and also merges
all of the metadata of how many tests were executed, etc.
"""
first_tree = trees[0]
first_root = first_tree.getroot()
if len(trees) == 0:
return first_tree
for tree in trees[1:]:
root = tree.getroot()
# append children elements (testcases)
first_root.extend(root.getchildren())
# combine root attributes which stores the number
# of executed tests, skipped tests, etc
for key, value in first_root.attrib.items():
if not value.isdigit():
continue
combined = six.text_type(int(value) + int(root.attrib.get(key, '0')))
first_root.set(key, combined)
return first_tree
def merge_xunit(files, output, callback=None):
"""
Merge the given xunit xml files into a single output xml file.
If callback is not None, it will be called with the merged ElementTree
before the output file is written (useful for applying other fixes to
the merged file). This can either modify the element tree in place (and
return None) or return a completely new ElementTree to be written.
"""
trees = []
for f in files:
trees.append(etree.parse(f))
merged = merge_trees(*trees)
if callback is not None:
result = callback(merged)
if result is not None:
merged = result
with patch_etree_cname(etree):
merged.write(output, encoding='utf-8', xml_declaration=True)

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
# Cloned from https://github.com/miki725/xunitmerge
# to fix a Python3 error.
#
# xunitmerge is MIT licensed by Miroslav Shubernetskiy https://github.com/miki725
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import argparse
from xmerge import merge_xunit
parser = argparse.ArgumentParser(
description='Utility for merging multiple XUnit xml reports '
'into a single xml report.',
)
parser.add_argument(
'report',
nargs='+',
type=argparse.FileType('r'),
help='Path of XUnit xml report. Multiple can be provided.',
)
parser.add_argument(
'output',
help='Path where merged of XUnit will be saved.',
)
if __name__ == '__main__':
args = parser.parse_args()
merge_xunit(args.report, args.output)

View File

@ -1,3 +1,5 @@
#!/usr/bin/env python3
from mock_decorators import setup, teardown
from flask import Flask, request
from threading import Thread
@ -21,7 +23,7 @@ def setup_tcpsrv(e):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
for port in range(8266, 8285 + 1):
try:
print >>sys.stderr, 'trying port', port
print ('trying port %d' %port, file=sys.stderr)
server_address = ("0.0.0.0", port)
sock.bind(server_address)
sock.listen(1)
@ -31,17 +33,17 @@ def setup_tcpsrv(e):
print >>sys.stderr, 'busy'
if not running:
return
print >>sys.stderr, 'starting up on %s port %s' % server_address
print >>sys.stderr, 'waiting for connections'
print ('starting up on %s port %s' % server_address, file=sys.stderr)
print ( 'waiting for connections', file=sys.stderr)
while running:
print >>sys.stderr, 'loop'
print ('loop', file=sys.stderr)
readable, writable, errored = select.select([sock], [], [], 1.0)
if readable:
connection, client_address = sock.accept()
try:
print >>sys.stderr, 'client connected:', client_address
print('client connected: %s' % str(client_address), file=sys.stderr)
finally:
print >>sys.stderr, 'close'
print ('close', file=sys.stderr)
connection.shutdown(socket.SHUT_RDWR)
connection.close()
@ -54,7 +56,7 @@ def teardown_tcpsrv(e):
global thread
global running
print >>sys.stderr, 'closing'
print ('closing', file=sys.stderr)
running = False
thread.join()
return 0

View File

@ -1,7 +1,7 @@
from mock_decorators import setup, teardown
from flask import Flask, request, redirect
from threading import Thread
import urllib2
import urllib
import os
import ssl
import time
@ -20,7 +20,7 @@ def setup_http_get(e):
return 'Server shutting down...'
@app.route("/", methods = ['GET', 'POST'])
def root():
print('Got data: ' + request.data);
print('Got data: ' + request.data.decode());
return 'hello!!!'
@app.route("/data")
def get_data():
@ -48,7 +48,7 @@ def setup_http_get(e):
@teardown('HTTP GET & POST requests')
def teardown_http_get(e):
response = urllib2.urlopen('http://localhost:8088/shutdown')
response = urllib.request.urlopen('http://localhost:8088/shutdown')
html = response.read()
time.sleep(1) # avoid address in use error on macOS
@ -86,6 +86,6 @@ def teardown_http_get(e):
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
p = os.path.dirname(os.path.abspath(__file__))
response = urllib2.urlopen('https://localhost:8088/shutdown', context=ctx)
response = urllib.request.urlopen('https://localhost:8088/shutdown', context=ctx)
html = response.read()

Some files were not shown because too many files have changed in this diff Show More