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:
commit
b0ef9195b5
17
.travis.yml
17
.travis.yml
@ -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
|
||||
|
32
README.md
32
README.md
@ -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
|
||||
[](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
|
||||
|
||||
|
20
boards.txt
20
boards.txt
@ -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
|
||||
|
@ -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
|
||||
|
@ -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*) §ion_header, sizeof(section_header))) {
|
||||
if (spi_flash_read(pos, (uint32_t*) §ion_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()
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
475
cores/esp8266/TZ.h
Normal 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
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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__
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
251
cores/esp8266/umm_malloc/Notes.h
Normal file
251
cores/esp8266/umm_malloc/Notes.h
Normal 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
|
@ -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.
|
||||
|
21
cores/esp8266/umm_malloc/dbglog/LICENSE
Normal file
21
cores/esp8266/umm_malloc/dbglog/LICENSE
Normal 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.
|
1
cores/esp8266/umm_malloc/dbglog/README.txt
Normal file
1
cores/esp8266/umm_malloc/dbglog/README.txt
Normal file
@ -0,0 +1 @@
|
||||
Downloaded from: https://github.com/rhempel/c-helper-macros/tree/develop
|
98
cores/esp8266/umm_malloc/dbglog/dbglog.h
Normal file
98
cores/esp8266/umm_malloc/dbglog/dbglog.h
Normal 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__);}}
|
185
cores/esp8266/umm_malloc/umm_info.c
Normal file
185
cores/esp8266/umm_malloc/umm_info.c
Normal 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)
|
134
cores/esp8266/umm_malloc/umm_integrity.c
Normal file
134
cores/esp8266/umm_malloc/umm_integrity.c
Normal 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)
|
215
cores/esp8266/umm_malloc/umm_local.c
Normal file
215
cores/esp8266/umm_malloc/umm_local.c
Normal 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
|
||||
|
||||
|
54
cores/esp8266/umm_malloc/umm_local.h
Normal file
54
cores/esp8266/umm_malloc/umm_local.h
Normal 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
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
};
|
@ -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 */
|
241
cores/esp8266/umm_malloc/umm_poison.c
Normal file
241
cores/esp8266/umm_malloc/umm_poison.c
Normal 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)
|
@ -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 */
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
----------
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -242,7 +242,7 @@ protected:
|
||||
String _uri;
|
||||
String _protocol;
|
||||
String _headers;
|
||||
String _userAgent = "ESP8266HTTPClient";
|
||||
String _userAgent;
|
||||
String _base64Authorization;
|
||||
|
||||
/// Response handling
|
||||
|
@ -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.
|
||||
|
@ -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(".");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
@ -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
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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 ================ */
|
@ -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 ================ */
|
@ -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
|
@ -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 //////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -7,4 +7,4 @@ paragraph=
|
||||
category=Other
|
||||
url=
|
||||
architectures=esp8266
|
||||
dot_a_linkage=true
|
||||
dot_a_linkage=false
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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\""
|
||||
|
||||
|
@ -359,4 +359,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -3,6 +3,5 @@ junit-xml
|
||||
MarkupSafe
|
||||
pexpect
|
||||
pyserial
|
||||
xunitmerge
|
||||
junit2html
|
||||
poster
|
||||
poster3
|
||||
|
@ -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)
|
||||
|
154
tests/device/libraries/BSTest/xmerge.py
Normal file
154
tests/device/libraries/BSTest/xmerge.py
Normal 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)
|
50
tests/device/libraries/BSTest/xunitmerge
Executable file
50
tests/device/libraries/BSTest/xunitmerge
Executable 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)
|
@ -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
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user