mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-19 23:22:16 +03:00
This reverts commit 98125f88605cd7e46e9be4e1b3ad0600dd5d2b51.
This commit is contained in:
parent
98125f8860
commit
eea9999dc5
@ -110,62 +110,23 @@ struct netifWrapper
|
||||
}
|
||||
|
||||
// address properties
|
||||
IPAddress addr() const
|
||||
{
|
||||
return ipFromNetifNum();
|
||||
}
|
||||
bool isLegacy() const
|
||||
{
|
||||
return _num == 0;
|
||||
}
|
||||
bool isLocal() const
|
||||
{
|
||||
return addr().isLocal();
|
||||
}
|
||||
bool isV4() const
|
||||
{
|
||||
return addr().isV4();
|
||||
}
|
||||
bool isV6() const
|
||||
{
|
||||
return !addr().isV4();
|
||||
}
|
||||
String toString() const
|
||||
{
|
||||
return addr().toString();
|
||||
}
|
||||
IPAddress addr () const { return ipFromNetifNum(); }
|
||||
bool isLegacy () const { return _num == 0; }
|
||||
bool isLocal () const { return addr().isLocal(); }
|
||||
bool isV4 () const { return addr().isV4(); }
|
||||
bool isV6 () const { return !addr().isV4(); }
|
||||
String toString() const { return addr().toString(); }
|
||||
|
||||
// related to legacy address (_num=0, ipv4)
|
||||
IPAddress ipv4() const
|
||||
{
|
||||
return _netif->ip_addr;
|
||||
}
|
||||
IPAddress netmask() const
|
||||
{
|
||||
return _netif->netmask;
|
||||
}
|
||||
IPAddress gw() const
|
||||
{
|
||||
return _netif->gw;
|
||||
}
|
||||
IPAddress ipv4 () const { return _netif->ip_addr; }
|
||||
IPAddress netmask () const { return _netif->netmask; }
|
||||
IPAddress gw () const { return _netif->gw; }
|
||||
|
||||
// common to all addresses of this interface
|
||||
String ifname() const
|
||||
{
|
||||
return String(_netif->name[0]) + _netif->name[1];
|
||||
}
|
||||
const char* ifhostname() const
|
||||
{
|
||||
return _netif->hostname ? : emptyString.c_str();
|
||||
}
|
||||
const char* ifmac() const
|
||||
{
|
||||
return (const char*)_netif->hwaddr;
|
||||
}
|
||||
int ifnumber() const
|
||||
{
|
||||
return _netif->num;
|
||||
}
|
||||
String ifname () const { return String(_netif->name[0]) + _netif->name[1]; }
|
||||
const char* ifhostname () const { return _netif->hostname?: emptyString.c_str(); }
|
||||
const char* ifmac () const { return (const char*)_netif->hwaddr; }
|
||||
int ifnumber () const { return _netif->num; }
|
||||
|
||||
const ip_addr_t* ipFromNetifNum () const
|
||||
{
|
||||
@ -199,29 +160,13 @@ public:
|
||||
(void)operator++();
|
||||
}
|
||||
|
||||
const netifWrapper& operator* () const
|
||||
{
|
||||
return netIf;
|
||||
}
|
||||
const netifWrapper* operator-> () const
|
||||
{
|
||||
return &netIf;
|
||||
}
|
||||
const netifWrapper& operator* () const { return netIf; }
|
||||
const netifWrapper* operator-> () const { return &netIf; }
|
||||
|
||||
bool operator== (AddressListIterator& o)
|
||||
{
|
||||
return netIf.equal(*o);
|
||||
}
|
||||
bool operator!= (AddressListIterator& o)
|
||||
{
|
||||
return !netIf.equal(*o);
|
||||
}
|
||||
bool operator== (AddressListIterator& o) { return netIf.equal(*o); }
|
||||
bool operator!= (AddressListIterator& o) { return !netIf.equal(*o); }
|
||||
|
||||
AddressListIterator& operator= (const AddressListIterator& o)
|
||||
{
|
||||
netIf = o.netIf;
|
||||
return *this;
|
||||
}
|
||||
AddressListIterator& operator= (const AddressListIterator& o) { netIf = o.netIf; return *this; }
|
||||
|
||||
AddressListIterator operator++ (int)
|
||||
{
|
||||
@ -243,10 +188,8 @@ public:
|
||||
}
|
||||
if (!ip_addr_isany(netIf.ipFromNetifNum()))
|
||||
// found an initialized address
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -259,25 +202,13 @@ class AddressList
|
||||
public:
|
||||
using const_iterator = const AddressListIterator;
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(netif_list);
|
||||
}
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(nullptr);
|
||||
}
|
||||
const_iterator begin () const { return const_iterator(netif_list); }
|
||||
const_iterator end () const { return const_iterator(nullptr); }
|
||||
|
||||
};
|
||||
|
||||
inline AddressList::const_iterator begin(const AddressList& a)
|
||||
{
|
||||
return a.begin();
|
||||
}
|
||||
inline AddressList::const_iterator end(const AddressList& a)
|
||||
{
|
||||
return a.end();
|
||||
}
|
||||
inline AddressList::const_iterator begin (const AddressList& a) { return a.begin(); }
|
||||
inline AddressList::const_iterator end (const AddressList& a) { return a.end(); }
|
||||
|
||||
|
||||
} // AddressListImplementation
|
||||
|
@ -86,8 +86,7 @@ extern "C" {
|
||||
#define EXTERNAL 0
|
||||
|
||||
//timer dividers
|
||||
enum TIM_DIV_ENUM
|
||||
{
|
||||
enum TIM_DIV_ENUM {
|
||||
TIM_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max)
|
||||
TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.4 us max)
|
||||
TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max)
|
||||
|
@ -23,8 +23,7 @@
|
||||
#include "Stream.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
class Client: public Stream
|
||||
{
|
||||
class Client: public Stream {
|
||||
|
||||
public:
|
||||
virtual int connect(IPAddress ip, uint16_t port) =0;
|
||||
@ -40,13 +39,11 @@ public:
|
||||
virtual uint8_t connected() = 0;
|
||||
virtual operator bool() = 0;
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr)
|
||||
{
|
||||
uint8_t* rawIPAddress(IPAddress& addr) {
|
||||
return addr.raw_address();
|
||||
}
|
||||
#if LWIP_VERSION_MAJOR != 1
|
||||
const uint8_t* rawIPAddress(const IPAddress& addr)
|
||||
{
|
||||
const uint8_t* rawIPAddress(const IPAddress& addr) {
|
||||
return addr.raw_address();
|
||||
}
|
||||
#endif
|
||||
|
@ -33,18 +33,12 @@ void EspClass::getHeapStats(uint32_t* hfree, uint16_t* hmax, uint8_t* hfrag)
|
||||
uint8_t block_size = umm_block_size();
|
||||
uint32_t fh = ummHeapInfo.freeBlocks * block_size;
|
||||
if (hfree)
|
||||
{
|
||||
*hfree = fh;
|
||||
}
|
||||
if (hmax)
|
||||
{
|
||||
*hmax = ummHeapInfo.maxFreeContiguousBlocks * block_size;
|
||||
}
|
||||
if (hfrag)
|
||||
{
|
||||
*hfrag = 100 - (sqrt32(ummHeapInfo.freeSize2) * 100) / fh;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t EspClass::getHeapFragmentation()
|
||||
{
|
||||
|
@ -38,54 +38,45 @@ extern "C" {
|
||||
|
||||
|
||||
/**
|
||||
User-defined Literals
|
||||
usage:
|
||||
|
||||
uint32_t = test = 10_MHz; // --> 10000000
|
||||
* User-defined Literals
|
||||
* usage:
|
||||
*
|
||||
* uint32_t = test = 10_MHz; // --> 10000000
|
||||
*/
|
||||
|
||||
unsigned long long operator"" _kHz(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _kHz(unsigned long long x) {
|
||||
return x * 1000;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _MHz(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _MHz(unsigned long long x) {
|
||||
return x * 1000 * 1000;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _GHz(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _GHz(unsigned long long x) {
|
||||
return x * 1000 * 1000 * 1000;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _kBit(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _kBit(unsigned long long x) {
|
||||
return x * 1024;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _MBit(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _MBit(unsigned long long x) {
|
||||
return x * 1024 * 1024;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _GBit(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _GBit(unsigned long long x) {
|
||||
return x * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _kB(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _kB(unsigned long long x) {
|
||||
return x * 1024;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _MB(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _MB(unsigned long long x) {
|
||||
return x * 1024 * 1024;
|
||||
}
|
||||
|
||||
unsigned long long operator"" _GB(unsigned long long x)
|
||||
{
|
||||
unsigned long long operator"" _GB(unsigned long long x) {
|
||||
return x * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
@ -177,24 +168,18 @@ uint64_t EspClass::deepSleepMax()
|
||||
|
||||
bool EspClass::rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size)
|
||||
{
|
||||
if (offset * 4 + size > 512 || size == 0)
|
||||
{
|
||||
if (offset * 4 + size > 512 || size == 0) {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return system_rtc_mem_read(64 + offset, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
bool EspClass::rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size)
|
||||
{
|
||||
if (offset * 4 + size > 512 || size == 0)
|
||||
{
|
||||
if (offset * 4 + size > 512 || size == 0) {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return system_rtc_mem_write(64 + offset, data, size);
|
||||
}
|
||||
}
|
||||
@ -250,8 +235,7 @@ extern "C" const char* core_release;
|
||||
|
||||
String EspClass::getCoreVersion()
|
||||
{
|
||||
if (core_release != NULL)
|
||||
{
|
||||
if (core_release != NULL) {
|
||||
return String(core_release);
|
||||
}
|
||||
char buf[12];
|
||||
@ -283,8 +267,7 @@ uint8_t EspClass::getCpuFreqMHz(void)
|
||||
uint32_t EspClass::getFlashChipId(void)
|
||||
{
|
||||
static uint32_t flash_chip_id = 0;
|
||||
if (flash_chip_id == 0)
|
||||
{
|
||||
if (flash_chip_id == 0) {
|
||||
flash_chip_id = spi_flash_get_id();
|
||||
}
|
||||
return flash_chip_id;
|
||||
@ -305,8 +288,7 @@ uint32_t EspClass::getFlashChipSize(void)
|
||||
uint32_t data;
|
||||
uint8_t * bytes = (uint8_t *) &data;
|
||||
// read first 4 byte (magic byte + flash config)
|
||||
if (spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
||||
return magicFlashChipSize((bytes[3] & 0xf0) >> 4);
|
||||
}
|
||||
return 0;
|
||||
@ -317,8 +299,7 @@ uint32_t EspClass::getFlashChipSpeed(void)
|
||||
uint32_t data;
|
||||
uint8_t * bytes = (uint8_t *) &data;
|
||||
// read first 4 byte (magic byte + flash config)
|
||||
if (spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
||||
return magicFlashChipSpeed(bytes[3] & 0x0F);
|
||||
}
|
||||
return 0;
|
||||
@ -330,17 +311,14 @@ FlashMode_t EspClass::getFlashChipMode(void)
|
||||
uint32_t data;
|
||||
uint8_t * bytes = (uint8_t *) &data;
|
||||
// read first 4 byte (magic byte + flash config)
|
||||
if (spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
||||
mode = magicFlashChipMode(bytes[2]);
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
uint32_t EspClass::magicFlashChipSize(uint8_t byte)
|
||||
{
|
||||
switch (byte & 0x0F)
|
||||
{
|
||||
uint32_t EspClass::magicFlashChipSize(uint8_t byte) {
|
||||
switch(byte & 0x0F) {
|
||||
case 0x0: // 4 Mbit (512KB)
|
||||
return (512_kB);
|
||||
case 0x1: // 2 MBit (256KB)
|
||||
@ -360,10 +338,8 @@ uint32_t EspClass::magicFlashChipSize(uint8_t byte)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EspClass::magicFlashChipSpeed(uint8_t byte)
|
||||
{
|
||||
switch (byte & 0x0F)
|
||||
{
|
||||
uint32_t EspClass::magicFlashChipSpeed(uint8_t byte) {
|
||||
switch(byte & 0x0F) {
|
||||
case 0x0: // 40 MHz
|
||||
return (40_MHz);
|
||||
case 0x1: // 26 MHz
|
||||
@ -377,34 +353,30 @@ uint32_t EspClass::magicFlashChipSpeed(uint8_t byte)
|
||||
}
|
||||
}
|
||||
|
||||
FlashMode_t EspClass::magicFlashChipMode(uint8_t byte)
|
||||
{
|
||||
FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) {
|
||||
FlashMode_t mode = (FlashMode_t) byte;
|
||||
if (mode > FM_DOUT)
|
||||
{
|
||||
if(mode > FM_DOUT) {
|
||||
mode = FM_UNKNOWN;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
Infos from
|
||||
http://www.wlxmall.com/images/stock_item/att/A1010004.pdf
|
||||
http://www.gigadevice.com/product-series/5.html?locale=en_US
|
||||
http://www.elinux.org/images/f/f5/Winbond-w25q32.pdf
|
||||
* Infos from
|
||||
* http://www.wlxmall.com/images/stock_item/att/A1010004.pdf
|
||||
* http://www.gigadevice.com/product-series/5.html?locale=en_US
|
||||
* http://www.elinux.org/images/f/f5/Winbond-w25q32.pdf
|
||||
*/
|
||||
uint32_t EspClass::getFlashChipSizeByChipId(void)
|
||||
{
|
||||
uint32_t EspClass::getFlashChipSizeByChipId(void) {
|
||||
uint32_t chipId = getFlashChipId();
|
||||
/**
|
||||
Chip ID
|
||||
00 - always 00 (Chip ID use only 3 byte)
|
||||
17 - ? looks like 2^xx is size in Byte ? //todo: find docu to this
|
||||
40 - ? may be Speed ? //todo: find docu to this
|
||||
C8 - manufacturer ID
|
||||
* Chip ID
|
||||
* 00 - always 00 (Chip ID use only 3 byte)
|
||||
* 17 - ? looks like 2^xx is size in Byte ? //todo: find docu to this
|
||||
* 40 - ? may be Speed ? //todo: find docu to this
|
||||
* C8 - manufacturer ID
|
||||
*/
|
||||
switch (chipId)
|
||||
{
|
||||
switch(chipId) {
|
||||
|
||||
// GigaDevice
|
||||
case 0x1740C8: // GD25Q64B
|
||||
@ -450,71 +422,47 @@ uint32_t EspClass::getFlashChipSizeByChipId(void)
|
||||
}
|
||||
|
||||
/**
|
||||
check the Flash settings from IDE against the Real flash size
|
||||
@param needsEquals (return only true it equals)
|
||||
@return ok or not
|
||||
* check the Flash settings from IDE against the Real flash size
|
||||
* @param needsEquals (return only true it equals)
|
||||
* @return ok or not
|
||||
*/
|
||||
bool EspClass::checkFlashConfig(bool needsEquals)
|
||||
{
|
||||
if (needsEquals)
|
||||
{
|
||||
if (getFlashChipRealSize() == getFlashChipSize())
|
||||
{
|
||||
bool EspClass::checkFlashConfig(bool needsEquals) {
|
||||
if(needsEquals) {
|
||||
if(getFlashChipRealSize() == getFlashChipSize()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getFlashChipRealSize() >= getFlashChipSize())
|
||||
{
|
||||
} else {
|
||||
if(getFlashChipRealSize() >= getFlashChipSize()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String EspClass::getResetReason(void)
|
||||
{
|
||||
String EspClass::getResetReason(void) {
|
||||
char buff[32];
|
||||
if (resetInfo.reason == REASON_DEFAULT_RST) // normal startup by power on
|
||||
{
|
||||
if (resetInfo.reason == REASON_DEFAULT_RST) { // normal startup by power on
|
||||
strcpy_P(buff, PSTR("Power on"));
|
||||
}
|
||||
else if (resetInfo.reason == REASON_WDT_RST) // hardware watch dog reset
|
||||
{
|
||||
} else if (resetInfo.reason == REASON_WDT_RST) { // hardware watch dog reset
|
||||
strcpy_P(buff, PSTR("Hardware Watchdog"));
|
||||
}
|
||||
else if (resetInfo.reason == REASON_EXCEPTION_RST) // exception reset, GPIO status won’t change
|
||||
{
|
||||
} else if (resetInfo.reason == REASON_EXCEPTION_RST) { // exception reset, GPIO status won’t change
|
||||
strcpy_P(buff, PSTR("Exception"));
|
||||
}
|
||||
else if (resetInfo.reason == REASON_SOFT_WDT_RST) // software watch dog reset, GPIO status won’t change
|
||||
{
|
||||
} else if (resetInfo.reason == REASON_SOFT_WDT_RST) { // software watch dog reset, GPIO status won’t change
|
||||
strcpy_P(buff, PSTR("Software Watchdog"));
|
||||
}
|
||||
else if (resetInfo.reason == REASON_SOFT_RESTART) // software restart ,system_restart , GPIO status won’t change
|
||||
{
|
||||
} else if (resetInfo.reason == REASON_SOFT_RESTART) { // software restart ,system_restart , GPIO status won’t change
|
||||
strcpy_P(buff, PSTR("Software/System restart"));
|
||||
}
|
||||
else if (resetInfo.reason == REASON_DEEP_SLEEP_AWAKE) // wake up from deep-sleep
|
||||
{
|
||||
} else if (resetInfo.reason == REASON_DEEP_SLEEP_AWAKE) { // wake up from deep-sleep
|
||||
strcpy_P(buff, PSTR("Deep-Sleep Wake"));
|
||||
}
|
||||
else if (resetInfo.reason == REASON_EXT_SYS_RST) // external system reset
|
||||
{
|
||||
} else if (resetInfo.reason == REASON_EXT_SYS_RST) { // external system reset
|
||||
strcpy_P(buff, PSTR("External System"));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
strcpy_P(buff, PSTR("Unknown"));
|
||||
}
|
||||
return String(buff);
|
||||
}
|
||||
|
||||
String EspClass::getResetInfo(void)
|
||||
{
|
||||
if (resetInfo.reason != 0)
|
||||
{
|
||||
String EspClass::getResetInfo(void) {
|
||||
if(resetInfo.reason != 0) {
|
||||
char buff[200];
|
||||
sprintf(&buff[0], "Fatal exception:%d flag:%d (%s) epc1:0x%08x epc2:0x%08x epc3:0x%08x excvaddr:0x%08x depc:0x%08x", resetInfo.exccause, resetInfo.reason, (resetInfo.reason == 0 ? "DEFAULT" : resetInfo.reason == 1 ? "WDT" : resetInfo.reason == 2 ? "EXCEPTION" : resetInfo.reason == 3 ? "SOFT_WDT" : resetInfo.reason == 4 ? "SOFT_RESTART" : resetInfo.reason == 5 ? "DEEP_SLEEP_AWAKE" : resetInfo.reason == 6 ? "EXT_SYS_RST" : "???"), resetInfo.epc1, resetInfo.epc2, resetInfo.epc3, resetInfo.excvaddr, resetInfo.depc);
|
||||
return String(buff);
|
||||
@ -522,20 +470,16 @@ String EspClass::getResetInfo(void)
|
||||
return String("flag: 0");
|
||||
}
|
||||
|
||||
struct rst_info * EspClass::getResetInfoPtr(void)
|
||||
{
|
||||
struct rst_info * EspClass::getResetInfoPtr(void) {
|
||||
return &resetInfo;
|
||||
}
|
||||
|
||||
bool EspClass::eraseConfig(void)
|
||||
{
|
||||
bool EspClass::eraseConfig(void) {
|
||||
const size_t cfgSize = 0x4000;
|
||||
size_t cfgAddr = ESP.getFlashChipSize() - cfgSize;
|
||||
|
||||
for (size_t offset = 0; offset < cfgSize; offset += SPI_FLASH_SEC_SIZE)
|
||||
{
|
||||
if (!flashEraseSector((cfgAddr + offset) / SPI_FLASH_SEC_SIZE))
|
||||
{
|
||||
for (size_t offset = 0; offset < cfgSize; offset += SPI_FLASH_SEC_SIZE) {
|
||||
if (!flashEraseSector((cfgAddr + offset) / SPI_FLASH_SEC_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -543,18 +487,14 @@ bool EspClass::eraseConfig(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getSketchSize()
|
||||
{
|
||||
uint32_t EspClass::getSketchSize() {
|
||||
static uint32_t result = 0;
|
||||
if (result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
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))) {
|
||||
return 0;
|
||||
}
|
||||
pos += sizeof(image_header);
|
||||
@ -566,8 +506,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))) {
|
||||
return 0;
|
||||
}
|
||||
pos += sizeof(section_header);
|
||||
@ -582,8 +521,7 @@ uint32_t EspClass::getSketchSize()
|
||||
|
||||
extern "C" uint32_t _SPIFFS_start;
|
||||
|
||||
uint32_t EspClass::getFreeSketchSpace()
|
||||
{
|
||||
uint32_t EspClass::getFreeSketchSpace() {
|
||||
|
||||
uint32_t usedSize = getSketchSize();
|
||||
// round one sector up
|
||||
@ -596,70 +534,51 @@ uint32_t EspClass::getFreeSketchSpace()
|
||||
return freeSpaceEnd - freeSpaceStart;
|
||||
}
|
||||
|
||||
bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail, bool restartOnSuccess)
|
||||
{
|
||||
if (!Update.begin(size))
|
||||
{
|
||||
bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail, bool restartOnSuccess) {
|
||||
if(!Update.begin(size)){
|
||||
#ifdef DEBUG_SERIAL
|
||||
DEBUG_SERIAL.print("Update ");
|
||||
Update.printError(DEBUG_SERIAL);
|
||||
#endif
|
||||
if (restartOnFail)
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
if(restartOnFail) ESP.restart();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Update.writeStream(in) != size)
|
||||
{
|
||||
if(Update.writeStream(in) != size){
|
||||
#ifdef DEBUG_SERIAL
|
||||
DEBUG_SERIAL.print("Update ");
|
||||
Update.printError(DEBUG_SERIAL);
|
||||
#endif
|
||||
if (restartOnFail)
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
if(restartOnFail) ESP.restart();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Update.end())
|
||||
{
|
||||
if(!Update.end()){
|
||||
#ifdef DEBUG_SERIAL
|
||||
DEBUG_SERIAL.print("Update ");
|
||||
Update.printError(DEBUG_SERIAL);
|
||||
#endif
|
||||
if (restartOnFail)
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
if(restartOnFail) ESP.restart();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SERIAL
|
||||
DEBUG_SERIAL.println("Update SUCCESS");
|
||||
#endif
|
||||
if (restartOnSuccess)
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
if(restartOnSuccess) ESP.restart();
|
||||
return true;
|
||||
}
|
||||
|
||||
static const int FLASH_INT_MASK = ((B10 << 8) | B00111010);
|
||||
|
||||
bool EspClass::flashEraseSector(uint32_t sector)
|
||||
{
|
||||
bool EspClass::flashEraseSector(uint32_t sector) {
|
||||
int rc = spi_flash_erase_sector(sector);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
#if PUYA_SUPPORT
|
||||
static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size)
|
||||
{
|
||||
if (data == nullptr)
|
||||
{
|
||||
static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) {
|
||||
if (data == nullptr) {
|
||||
return 1; // SPI_FLASH_RESULT_ERR
|
||||
}
|
||||
// PUYA flash chips need to read existing data, update in memory and write modified data again.
|
||||
@ -667,37 +586,29 @@ static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size)
|
||||
int rc = 0;
|
||||
uint32_t* ptr = data;
|
||||
|
||||
if (flash_write_puya_buf == nullptr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (flash_write_puya_buf == nullptr) {
|
||||
// Memory could not be allocated.
|
||||
return 1; // SPI_FLASH_RESULT_ERR
|
||||
}
|
||||
}
|
||||
size_t bytesLeft = size;
|
||||
uint32_t pos = offset;
|
||||
while (bytesLeft > 0 && rc == 0)
|
||||
{
|
||||
while (bytesLeft > 0 && rc == 0) {
|
||||
size_t bytesNow = bytesLeft;
|
||||
if (bytesNow > PUYA_BUFFER_SIZE)
|
||||
{
|
||||
if (bytesNow > PUYA_BUFFER_SIZE) {
|
||||
bytesNow = PUYA_BUFFER_SIZE;
|
||||
bytesLeft -= PUYA_BUFFER_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
bytesLeft = 0;
|
||||
}
|
||||
rc = spi_flash_read(pos, flash_write_puya_buf, bytesNow);
|
||||
if (rc != 0)
|
||||
{
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
for (size_t i = 0; i < bytesNow / 4; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < bytesNow / 4; ++i) {
|
||||
flash_write_puya_buf[i] &= *ptr;
|
||||
++ptr;
|
||||
}
|
||||
@ -708,12 +619,10 @@ 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)
|
||||
{
|
||||
bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
|
||||
int rc = 0;
|
||||
#if PUYA_SUPPORT
|
||||
if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA)
|
||||
{
|
||||
if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA) {
|
||||
rc = spi_flash_write_puya(offset, data, size);
|
||||
}
|
||||
else
|
||||
@ -724,8 +633,7 @@ bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size)
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -733,25 +641,21 @@ bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size)
|
||||
String EspClass::getSketchMD5()
|
||||
{
|
||||
static String result;
|
||||
if (result.length())
|
||||
{
|
||||
if (result.length()) {
|
||||
return result;
|
||||
}
|
||||
uint32_t lengthLeft = getSketchSize();
|
||||
const size_t bufSize = 512;
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
|
||||
uint32_t offset = 0;
|
||||
if (!buf.get())
|
||||
{
|
||||
if(!buf.get()) {
|
||||
return String();
|
||||
}
|
||||
MD5Builder md5;
|
||||
md5.begin();
|
||||
while (lengthLeft > 0)
|
||||
{
|
||||
while( lengthLeft > 0) {
|
||||
size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize;
|
||||
if (!flashRead(offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3))
|
||||
{
|
||||
if (!flashRead(offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3)) {
|
||||
return String();
|
||||
}
|
||||
md5.add(buf.get(), readBytes);
|
||||
|
@ -34,8 +34,7 @@
|
||||
|
||||
// Vendor IDs taken from Flashrom project
|
||||
// https://review.coreboot.org/cgit/flashrom.git/tree/flashchips.h?h=1.0.x
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
SPI_FLASH_VENDOR_ALLIANCE = 0x52, /* Alliance Semiconductor */
|
||||
SPI_FLASH_VENDOR_AMD = 0x01, /* AMD */
|
||||
SPI_FLASH_VENDOR_AMIC = 0x37, /* AMIC */
|
||||
@ -71,10 +70,9 @@ typedef enum
|
||||
} SPI_FLASH_VENDOR_t;
|
||||
|
||||
/**
|
||||
AVR macros for WDT managment
|
||||
* AVR macros for WDT managment
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
WDTO_0MS = 0, //!< WDTO_0MS
|
||||
WDTO_15MS = 15, //!< WDTO_15MS
|
||||
WDTO_30MS = 30, //!< WDTO_30MS
|
||||
@ -96,8 +94,7 @@ typedef enum
|
||||
#define cli() ets_intr_lock() // IRQ Disable
|
||||
#define sei() ets_intr_unlock() // IRQ Enable
|
||||
|
||||
enum RFMode
|
||||
{
|
||||
enum RFMode {
|
||||
RF_DEFAULT = 0, // RF_CAL or not after deep-sleep wake up, depends on init data byte 108.
|
||||
RF_CAL = 1, // RF_CAL after deep-sleep wake up, there will be large current.
|
||||
RF_NO_CAL = 2, // no RF_CAL after deep-sleep wake up, there will only be small current.
|
||||
@ -114,8 +111,7 @@ enum RFMode
|
||||
#define WAKE_NO_RFCAL RF_NO_CAL
|
||||
#define WAKE_RF_DISABLED RF_DISABLED
|
||||
|
||||
enum ADCMode
|
||||
{
|
||||
enum ADCMode {
|
||||
ADC_TOUT = 33,
|
||||
ADC_TOUT_3V3 = 33,
|
||||
ADC_VCC = 255,
|
||||
@ -124,8 +120,7 @@ enum ADCMode
|
||||
|
||||
#define ADC_MODE(mode) int __get_adc_mode(void) { return (int) (mode); }
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
FM_QIO = 0x00,
|
||||
FM_QOUT = 0x01,
|
||||
FM_DIO = 0x02,
|
||||
@ -133,8 +128,7 @@ typedef enum
|
||||
FM_UNKNOWN = 0xff
|
||||
} FlashMode_t;
|
||||
|
||||
class EspClass
|
||||
{
|
||||
class EspClass {
|
||||
public:
|
||||
// TODO: figure out how to set WDT timeout
|
||||
void wdtEnable(uint32_t timeout_ms = 0);
|
||||
|
@ -25,68 +25,49 @@ using namespace fs;
|
||||
|
||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am);
|
||||
|
||||
size_t File::write(uint8_t c)
|
||||
{
|
||||
size_t File::write(uint8_t c) {
|
||||
if (!_p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->write(&c, 1);
|
||||
}
|
||||
|
||||
size_t File::write(const uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t File::write(const uint8_t *buf, size_t size) {
|
||||
if (!_p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->write(buf, size);
|
||||
}
|
||||
|
||||
int File::available()
|
||||
{
|
||||
int File::available() {
|
||||
if (!_p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _p->size() - _p->position();
|
||||
}
|
||||
|
||||
int File::read()
|
||||
{
|
||||
int File::read() {
|
||||
if (!_p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t result;
|
||||
if (_p->read(&result, 1) != 1)
|
||||
{
|
||||
if (_p->read(&result, 1) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t File::read(uint8_t* buf, size_t size)
|
||||
{
|
||||
size_t File::read(uint8_t* buf, size_t size) {
|
||||
if (!_p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _p->read(buf, size);
|
||||
}
|
||||
|
||||
int File::peek()
|
||||
{
|
||||
int File::peek() {
|
||||
if (!_p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t curPos = _p->position();
|
||||
int result = read();
|
||||
@ -94,126 +75,90 @@ int File::peek()
|
||||
return result;
|
||||
}
|
||||
|
||||
void File::flush()
|
||||
{
|
||||
void File::flush() {
|
||||
if (!_p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_p->flush();
|
||||
}
|
||||
|
||||
bool File::seek(uint32_t pos, SeekMode mode)
|
||||
{
|
||||
bool File::seek(uint32_t pos, SeekMode mode) {
|
||||
if (!_p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _p->seek(pos, mode);
|
||||
}
|
||||
|
||||
size_t File::position() const
|
||||
{
|
||||
size_t File::position() const {
|
||||
if (!_p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->position();
|
||||
}
|
||||
|
||||
size_t File::size() const
|
||||
{
|
||||
size_t File::size() const {
|
||||
if (!_p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->size();
|
||||
}
|
||||
|
||||
void File::close()
|
||||
{
|
||||
if (_p)
|
||||
{
|
||||
void File::close() {
|
||||
if (_p) {
|
||||
_p->close();
|
||||
_p = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
File::operator bool() const
|
||||
{
|
||||
File::operator bool() const {
|
||||
return !!_p;
|
||||
}
|
||||
|
||||
bool File::truncate(uint32_t size)
|
||||
{
|
||||
bool File::truncate(uint32_t size) {
|
||||
if (!_p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _p->truncate(size);
|
||||
}
|
||||
|
||||
const char* File::name() const
|
||||
{
|
||||
const char* File::name() const {
|
||||
if (!_p)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _p->name();
|
||||
}
|
||||
|
||||
const char* File::fullName() const
|
||||
{
|
||||
const char* File::fullName() const {
|
||||
if (!_p)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _p->fullName();
|
||||
}
|
||||
|
||||
bool File::isFile() const
|
||||
{
|
||||
bool File::isFile() const {
|
||||
if (!_p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _p->isFile();
|
||||
}
|
||||
|
||||
bool File::isDirectory() const
|
||||
{
|
||||
bool File::isDirectory() const {
|
||||
if (!_p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _p->isDirectory();
|
||||
}
|
||||
|
||||
void File::rewindDirectory()
|
||||
{
|
||||
if (!_fakeDir)
|
||||
{
|
||||
void File::rewindDirectory() {
|
||||
if (!_fakeDir) {
|
||||
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_fakeDir->rewind();
|
||||
}
|
||||
}
|
||||
|
||||
File File::openNextFile()
|
||||
{
|
||||
if (!_fakeDir)
|
||||
{
|
||||
File File::openNextFile() {
|
||||
if (!_fakeDir) {
|
||||
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
||||
}
|
||||
_fakeDir->next();
|
||||
@ -235,17 +180,14 @@ String File::readString()
|
||||
return ret;
|
||||
}
|
||||
|
||||
File Dir::openFile(const char* mode)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
File Dir::openFile(const char* mode) {
|
||||
if (!_impl) {
|
||||
return File();
|
||||
}
|
||||
|
||||
OpenMode om;
|
||||
AccessMode am;
|
||||
if (!sflags(mode, om, am))
|
||||
{
|
||||
if (!sflags(mode, om, am)) {
|
||||
DEBUGV("Dir::openFile: invalid mode `%s`\r\n", mode);
|
||||
return File();
|
||||
}
|
||||
@ -253,233 +195,183 @@ File Dir::openFile(const char* mode)
|
||||
return File(_impl->openFile(om, am), _baseFS);
|
||||
}
|
||||
|
||||
String Dir::fileName()
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
String Dir::fileName() {
|
||||
if (!_impl) {
|
||||
return String();
|
||||
}
|
||||
|
||||
return _impl->fileName();
|
||||
}
|
||||
|
||||
size_t Dir::fileSize()
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
size_t Dir::fileSize() {
|
||||
if (!_impl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _impl->fileSize();
|
||||
}
|
||||
|
||||
bool Dir::isFile() const
|
||||
{
|
||||
bool Dir::isFile() const {
|
||||
if (!_impl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->isFile();
|
||||
}
|
||||
|
||||
bool Dir::isDirectory() const
|
||||
{
|
||||
bool Dir::isDirectory() const {
|
||||
if (!_impl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->isDirectory();
|
||||
}
|
||||
|
||||
bool Dir::next()
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool Dir::next() {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->next();
|
||||
}
|
||||
|
||||
bool Dir::rewind()
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool Dir::rewind() {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->rewind();
|
||||
}
|
||||
|
||||
bool FS::setConfig(const FSConfig &cfg)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::setConfig(const FSConfig &cfg) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _impl->setConfig(cfg);
|
||||
}
|
||||
|
||||
bool FS::begin()
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::begin() {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->begin();
|
||||
}
|
||||
|
||||
void FS::end()
|
||||
{
|
||||
if (_impl)
|
||||
{
|
||||
void FS::end() {
|
||||
if (_impl) {
|
||||
_impl->end();
|
||||
}
|
||||
}
|
||||
|
||||
bool FS::gc()
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::gc() {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->gc();
|
||||
}
|
||||
|
||||
bool FS::format()
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::format() {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->format();
|
||||
}
|
||||
|
||||
bool FS::info(FSInfo& info)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::info(FSInfo& info){
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->info(info);
|
||||
}
|
||||
|
||||
File FS::open(const String& path, const char* mode)
|
||||
{
|
||||
File FS::open(const String& path, const char* mode) {
|
||||
return open(path.c_str(), mode);
|
||||
}
|
||||
|
||||
File FS::open(const char* path, const char* mode)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
File FS::open(const char* path, const char* mode) {
|
||||
if (!_impl) {
|
||||
return File();
|
||||
}
|
||||
|
||||
OpenMode om;
|
||||
AccessMode am;
|
||||
if (!sflags(mode, om, am))
|
||||
{
|
||||
if (!sflags(mode, om, am)) {
|
||||
DEBUGV("FS::open: invalid mode `%s`\r\n", mode);
|
||||
return File();
|
||||
}
|
||||
return File(_impl->open(path, om, am), this);
|
||||
}
|
||||
|
||||
bool FS::exists(const char* path)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::exists(const char* path) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->exists(path);
|
||||
}
|
||||
|
||||
bool FS::exists(const String& path)
|
||||
{
|
||||
bool FS::exists(const String& path) {
|
||||
return exists(path.c_str());
|
||||
}
|
||||
|
||||
Dir FS::openDir(const char* path)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
Dir FS::openDir(const char* path) {
|
||||
if (!_impl) {
|
||||
return Dir();
|
||||
}
|
||||
DirImplPtr p = _impl->openDir(path);
|
||||
return Dir(p, this);
|
||||
}
|
||||
|
||||
Dir FS::openDir(const String& path)
|
||||
{
|
||||
Dir FS::openDir(const String& path) {
|
||||
return openDir(path.c_str());
|
||||
}
|
||||
|
||||
bool FS::remove(const char* path)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::remove(const char* path) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->remove(path);
|
||||
}
|
||||
|
||||
bool FS::remove(const String& path)
|
||||
{
|
||||
bool FS::remove(const String& path) {
|
||||
return remove(path.c_str());
|
||||
}
|
||||
|
||||
bool FS::rmdir(const char* path)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::rmdir(const char* path) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->rmdir(path);
|
||||
}
|
||||
|
||||
bool FS::rmdir(const String& path)
|
||||
{
|
||||
bool FS::rmdir(const String& path) {
|
||||
return rmdir(path.c_str());
|
||||
}
|
||||
|
||||
bool FS::mkdir(const char* path)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::mkdir(const char* path) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->mkdir(path);
|
||||
}
|
||||
|
||||
bool FS::mkdir(const String& path)
|
||||
{
|
||||
bool FS::mkdir(const String& path) {
|
||||
return mkdir(path.c_str());
|
||||
}
|
||||
|
||||
bool FS::rename(const char* pathFrom, const char* pathTo)
|
||||
{
|
||||
if (!_impl)
|
||||
{
|
||||
bool FS::rename(const char* pathFrom, const char* pathTo) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->rename(pathFrom, pathTo);
|
||||
}
|
||||
|
||||
bool FS::rename(const String& pathFrom, const String& pathTo)
|
||||
{
|
||||
bool FS::rename(const String& pathFrom, const String& pathTo) {
|
||||
return rename(pathFrom.c_str(), pathTo.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am)
|
||||
{
|
||||
switch (mode[0])
|
||||
{
|
||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
|
||||
switch (mode[0]) {
|
||||
case 'r':
|
||||
am = AM_READ;
|
||||
om = OM_DEFAULT;
|
||||
@ -495,8 +387,7 @@ static bool sflags(const char* mode, OpenMode& om, AccessMode& am)
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
switch (mode[1])
|
||||
{
|
||||
switch(mode[1]) {
|
||||
case '+':
|
||||
am = (AccessMode) (AM_WRITE | AM_READ);
|
||||
break;
|
||||
@ -526,8 +417,7 @@ bool mount<FS>(FS& fs, const char* mountPoint);
|
||||
*/
|
||||
|
||||
|
||||
struct MountEntry
|
||||
{
|
||||
struct MountEntry {
|
||||
FSImplPtr fs;
|
||||
String path;
|
||||
MountEntry* next;
|
||||
@ -536,11 +426,9 @@ struct MountEntry
|
||||
static MountEntry* s_mounted = nullptr;
|
||||
|
||||
template<>
|
||||
bool mount<FS>(FS& fs, const char* mountPoint)
|
||||
{
|
||||
bool mount<FS>(FS& fs, const char* mountPoint) {
|
||||
FSImplPtr p = fs._impl;
|
||||
if (!p || !p->mount())
|
||||
{
|
||||
if (!p || !p->mount()) {
|
||||
DEBUGV("FSImpl mount failed\r\n");
|
||||
return false;
|
||||
}
|
||||
@ -559,39 +447,31 @@ bool mount<FS>(FS& fs, const char* mountPoint)
|
||||
/*
|
||||
iterate over MountEntries and look for the ones which match the path
|
||||
*/
|
||||
File open(const char* path, const char* mode)
|
||||
{
|
||||
File open(const char* path, const char* mode) {
|
||||
OpenMode om;
|
||||
AccessMode am;
|
||||
if (!sflags(mode, om, am))
|
||||
{
|
||||
if (!sflags(mode, om, am)) {
|
||||
DEBUGV("open: invalid mode `%s`\r\n", mode);
|
||||
return File();
|
||||
}
|
||||
|
||||
for (MountEntry* entry = s_mounted; entry; entry = entry->next)
|
||||
{
|
||||
for (MountEntry* entry = s_mounted; entry; entry = entry->next) {
|
||||
size_t offset = entry->path.length();
|
||||
if (strstr(path, entry->path.c_str()))
|
||||
{
|
||||
if (strstr(path, entry->path.c_str())) {
|
||||
File result = entry->fs->open(path + offset);
|
||||
if (result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return File();
|
||||
}
|
||||
|
||||
File open(const String& path, const char* mode)
|
||||
{
|
||||
File open(const String& path, const char* mode) {
|
||||
return FS::open(path.c_str(), mode);
|
||||
}
|
||||
|
||||
Dir openDir(const String& path)
|
||||
{
|
||||
Dir openDir(const String& path) {
|
||||
return openDir(path.c_str());
|
||||
}
|
||||
#endif
|
||||
|
@ -24,8 +24,7 @@
|
||||
#include <memory>
|
||||
#include <Arduino.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
namespace fs {
|
||||
|
||||
class File;
|
||||
class Dir;
|
||||
@ -41,8 +40,7 @@ typedef std::shared_ptr<DirImpl> DirImplPtr;
|
||||
template <typename Tfs>
|
||||
bool mount(Tfs& fs, const char* mountPoint);
|
||||
|
||||
enum SeekMode
|
||||
{
|
||||
enum SeekMode {
|
||||
SeekSet = 0,
|
||||
SeekCur = 1,
|
||||
SeekEnd = 2
|
||||
@ -62,14 +60,12 @@ public:
|
||||
int read() override;
|
||||
int peek() override;
|
||||
void flush() override;
|
||||
size_t readBytes(char *buffer, size_t length) override
|
||||
{
|
||||
size_t readBytes(char *buffer, size_t length) override {
|
||||
return read((uint8_t*)buffer, length);
|
||||
}
|
||||
size_t read(uint8_t* buf, size_t size);
|
||||
bool seek(uint32_t pos, SeekMode mode);
|
||||
bool seek(uint32_t pos)
|
||||
{
|
||||
bool seek(uint32_t pos) {
|
||||
return seek(pos, SeekSet);
|
||||
}
|
||||
size_t position() const;
|
||||
@ -84,20 +80,17 @@ public:
|
||||
bool isDirectory() const;
|
||||
|
||||
// Arduino "class SD" methods for compatibility
|
||||
template<typename T> size_t write(T &src)
|
||||
{
|
||||
template<typename T> size_t write(T &src){
|
||||
uint8_t obuf[256];
|
||||
size_t doneLen = 0;
|
||||
size_t sentLen;
|
||||
int i;
|
||||
|
||||
while (src.available() > sizeof(obuf))
|
||||
{
|
||||
while (src.available() > sizeof(obuf)){
|
||||
src.read(obuf, sizeof(obuf));
|
||||
sentLen = write(obuf, sizeof(obuf));
|
||||
doneLen = doneLen + sentLen;
|
||||
if (sentLen != sizeof(obuf))
|
||||
{
|
||||
if(sentLen != sizeof(obuf)){
|
||||
return doneLen;
|
||||
}
|
||||
}
|
||||
@ -123,8 +116,7 @@ protected:
|
||||
FS *_baseFS;
|
||||
};
|
||||
|
||||
class Dir
|
||||
{
|
||||
class Dir {
|
||||
public:
|
||||
Dir(DirImplPtr impl = DirImplPtr(), FS *baseFS = nullptr): _impl(impl), _baseFS(baseFS) { }
|
||||
|
||||
@ -143,8 +135,7 @@ protected:
|
||||
FS *_baseFS;
|
||||
};
|
||||
|
||||
struct FSInfo
|
||||
{
|
||||
struct FSInfo {
|
||||
size_t totalBytes;
|
||||
size_t usedBytes;
|
||||
size_t blockSize;
|
||||
@ -156,15 +147,13 @@ struct FSInfo
|
||||
class FSConfig
|
||||
{
|
||||
public:
|
||||
FSConfig(bool autoFormat = true)
|
||||
{
|
||||
FSConfig(bool autoFormat = true) {
|
||||
_type = FSConfig::fsid::FSId;
|
||||
_autoFormat = autoFormat;
|
||||
}
|
||||
|
||||
enum fsid { FSId = 0x00000000 };
|
||||
FSConfig setAutoFormat(bool val = true)
|
||||
{
|
||||
FSConfig setAutoFormat(bool val = true) {
|
||||
_autoFormat = val;
|
||||
return *this;
|
||||
}
|
||||
@ -176,8 +165,7 @@ public:
|
||||
class SPIFFSConfig : public FSConfig
|
||||
{
|
||||
public:
|
||||
SPIFFSConfig(bool autoFormat = true)
|
||||
{
|
||||
SPIFFSConfig(bool autoFormat = true) {
|
||||
_type = SPIFFSConfig::fsid::FSId;
|
||||
_autoFormat = autoFormat;
|
||||
}
|
||||
|
@ -23,11 +23,9 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
namespace fs {
|
||||
|
||||
class FileImpl
|
||||
{
|
||||
class FileImpl {
|
||||
public:
|
||||
virtual ~FileImpl() { }
|
||||
virtual size_t write(const uint8_t *buf, size_t size) = 0;
|
||||
@ -44,23 +42,20 @@ public:
|
||||
virtual bool isDirectory() const = 0;
|
||||
};
|
||||
|
||||
enum OpenMode
|
||||
{
|
||||
enum OpenMode {
|
||||
OM_DEFAULT = 0,
|
||||
OM_CREATE = 1,
|
||||
OM_APPEND = 2,
|
||||
OM_TRUNCATE = 4
|
||||
};
|
||||
|
||||
enum AccessMode
|
||||
{
|
||||
enum AccessMode {
|
||||
AM_READ = 1,
|
||||
AM_WRITE = 2,
|
||||
AM_RW = AM_READ | AM_WRITE
|
||||
};
|
||||
|
||||
class DirImpl
|
||||
{
|
||||
class DirImpl {
|
||||
public:
|
||||
virtual ~DirImpl() { }
|
||||
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
|
||||
@ -72,8 +67,7 @@ public:
|
||||
virtual bool rewind() = 0;
|
||||
};
|
||||
|
||||
class FSImpl
|
||||
{
|
||||
class FSImpl {
|
||||
public:
|
||||
virtual ~FSImpl () { }
|
||||
virtual bool setConfig(const FSConfig &cfg) = 0;
|
||||
@ -88,10 +82,7 @@ public:
|
||||
virtual bool remove(const char* path) = 0;
|
||||
virtual bool mkdir(const char* path) = 0;
|
||||
virtual bool rmdir(const char* path) = 0;
|
||||
virtual bool gc()
|
||||
{
|
||||
return true; // May not be implemented in all file systems.
|
||||
}
|
||||
virtual bool gc() { return true; } // May not be implemented in all file systems.
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
@ -13,21 +13,18 @@ extern "C" {
|
||||
|
||||
// Structures for communication
|
||||
|
||||
struct InterruptInfo
|
||||
{
|
||||
struct InterruptInfo {
|
||||
uint8_t pin = 0;
|
||||
uint8_t value = 0;
|
||||
uint32_t micro = 0;
|
||||
};
|
||||
|
||||
struct FunctionInfo
|
||||
{
|
||||
struct FunctionInfo {
|
||||
std::function<void(void)> reqFunction = nullptr;
|
||||
std::function<void(InterruptInfo)> reqScheduledFunction = nullptr;
|
||||
};
|
||||
|
||||
struct ArgStructure
|
||||
{
|
||||
struct ArgStructure {
|
||||
InterruptInfo* interruptInfo = nullptr;
|
||||
FunctionInfo* functionInfo = nullptr;
|
||||
};
|
||||
|
@ -52,8 +52,7 @@ void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode m
|
||||
|
||||
void HardwareSerial::end()
|
||||
{
|
||||
if (uart_get_debug() == _uart_nr)
|
||||
{
|
||||
if(uart_get_debug() == _uart_nr) {
|
||||
uart_set_debug(UART_NO);
|
||||
}
|
||||
|
||||
@ -61,14 +60,10 @@ void HardwareSerial::end()
|
||||
_uart = NULL;
|
||||
}
|
||||
|
||||
size_t HardwareSerial::setRxBufferSize(size_t size)
|
||||
{
|
||||
if (_uart)
|
||||
{
|
||||
size_t HardwareSerial::setRxBufferSize(size_t size){
|
||||
if(_uart) {
|
||||
_rx_size = uart_resize_rx_buffer(_uart, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_rx_size = size;
|
||||
}
|
||||
return _rx_size;
|
||||
@ -76,26 +71,18 @@ size_t HardwareSerial::setRxBufferSize(size_t size)
|
||||
|
||||
void HardwareSerial::setDebugOutput(bool en)
|
||||
{
|
||||
if (!_uart)
|
||||
{
|
||||
if(!_uart) {
|
||||
return;
|
||||
}
|
||||
if (en)
|
||||
{
|
||||
if (uart_tx_enabled(_uart))
|
||||
{
|
||||
if(en) {
|
||||
if(uart_tx_enabled(_uart)) {
|
||||
uart_set_debug(_uart_nr);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uart_set_debug(UART_NO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// disable debug for this interface
|
||||
if (uart_get_debug() == _uart_nr)
|
||||
{
|
||||
if(uart_get_debug() == _uart_nr) {
|
||||
uart_set_debug(UART_NO);
|
||||
}
|
||||
}
|
||||
@ -104,8 +91,7 @@ void HardwareSerial::setDebugOutput(bool en)
|
||||
int HardwareSerial::available(void)
|
||||
{
|
||||
int result = static_cast<int>(uart_rx_available(_uart));
|
||||
if (!result)
|
||||
{
|
||||
if (!result) {
|
||||
optimistic_yield(10000);
|
||||
}
|
||||
return result;
|
||||
@ -113,8 +99,7 @@ int HardwareSerial::available(void)
|
||||
|
||||
void HardwareSerial::flush()
|
||||
{
|
||||
if (!_uart || !uart_tx_enabled(_uart))
|
||||
{
|
||||
if(!_uart || !uart_tx_enabled(_uart)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -138,10 +123,8 @@ unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
|
||||
{
|
||||
time_t startMillis = millis();
|
||||
unsigned long detectedBaudrate;
|
||||
while ((time_t) millis() - startMillis < timeoutMillis)
|
||||
{
|
||||
if ((detectedBaudrate = testBaudrate()))
|
||||
{
|
||||
while ((time_t) millis() - startMillis < timeoutMillis) {
|
||||
if ((detectedBaudrate = testBaudrate())) {
|
||||
break;
|
||||
}
|
||||
yield();
|
||||
@ -160,9 +143,7 @@ size_t HardwareSerial::readBytes(char* buffer, size_t size)
|
||||
size_t avail;
|
||||
while ((avail = available()) == 0 && !timeOut);
|
||||
if (avail == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
got += read(buffer + got, std::min(size - got, avail));
|
||||
}
|
||||
return got;
|
||||
|
@ -32,8 +32,7 @@
|
||||
#include "Stream.h"
|
||||
#include "uart.h"
|
||||
|
||||
enum SerialConfig
|
||||
{
|
||||
enum SerialConfig {
|
||||
SERIAL_5N1 = UART_5N1,
|
||||
SERIAL_6N1 = UART_6N1,
|
||||
SERIAL_7N1 = UART_7N1,
|
||||
@ -60,8 +59,7 @@ enum SerialConfig
|
||||
SERIAL_8O2 = UART_8O2,
|
||||
};
|
||||
|
||||
enum SerialMode
|
||||
{
|
||||
enum SerialMode {
|
||||
SERIAL_FULL = UART_FULL,
|
||||
SERIAL_RX_ONLY = UART_RX_ONLY,
|
||||
SERIAL_TX_ONLY = UART_TX_ONLY
|
||||
@ -106,8 +104,8 @@ public:
|
||||
}
|
||||
|
||||
/*
|
||||
Toggle between use of GPIO1 and GPIO2 as TX on UART 0.
|
||||
Note: UART 1 can't be used if GPIO2 is used with UART 0!
|
||||
* Toggle between use of GPIO1 and GPIO2 as TX on UART 0.
|
||||
* Note: UART 1 can't be used if GPIO2 is used with UART 0!
|
||||
*/
|
||||
void set_tx(uint8_t tx_pin)
|
||||
{
|
||||
@ -115,8 +113,8 @@ public:
|
||||
}
|
||||
|
||||
/*
|
||||
UART 0 possible options are (1, 3), (2, 3) or (15, 13)
|
||||
UART 1 allows only TX on 2 if UART 0 is not (2, 3)
|
||||
* UART 0 possible options are (1, 3), (2, 3) or (15, 13)
|
||||
* UART 1 allows only TX on 2 if UART 0 is not (2, 3)
|
||||
*/
|
||||
void pins(uint8_t tx, uint8_t rx)
|
||||
{
|
||||
|
@ -27,18 +27,15 @@ IPAddress::IPAddress(const IPAddress& from)
|
||||
ip_addr_copy(_ip, from._ip);
|
||||
}
|
||||
|
||||
IPAddress::IPAddress()
|
||||
{
|
||||
IPAddress::IPAddress() {
|
||||
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
|
||||
}
|
||||
|
||||
bool IPAddress::isSet() const
|
||||
{
|
||||
bool IPAddress::isSet () const {
|
||||
return !ip_addr_isany(&_ip);
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
|
||||
{
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
|
||||
setV4();
|
||||
(*this)[0] = first_octet;
|
||||
(*this)[1] = second_octet;
|
||||
@ -46,14 +43,12 @@ IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_oc
|
||||
(*this)[3] = fourth_octet;
|
||||
}
|
||||
|
||||
void IPAddress::ctor32(uint32_t address)
|
||||
{
|
||||
void IPAddress::ctor32(uint32_t address) {
|
||||
setV4();
|
||||
v4() = address;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const uint8_t *address)
|
||||
{
|
||||
IPAddress::IPAddress(const uint8_t *address) {
|
||||
setV4();
|
||||
(*this)[0] = address[0];
|
||||
(*this)[1] = address[1];
|
||||
@ -61,10 +56,8 @@ IPAddress::IPAddress(const uint8_t *address)
|
||||
(*this)[3] = address[3];
|
||||
}
|
||||
|
||||
bool IPAddress::fromString(const char *address)
|
||||
{
|
||||
if (!fromString4(address))
|
||||
{
|
||||
bool IPAddress::fromString(const char *address) {
|
||||
if (!fromString4(address)) {
|
||||
#if LWIP_IPV6
|
||||
return fromString6(address);
|
||||
#else
|
||||
@ -74,8 +67,7 @@ bool IPAddress::fromString(const char *address)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IPAddress::fromString4(const char *address)
|
||||
{
|
||||
bool IPAddress::fromString4(const char *address) {
|
||||
// TODO: (IPv4) add support for "a", "a.b", "a.b.c" formats
|
||||
|
||||
uint16_t acc = 0; // Accumulator
|
||||
@ -87,16 +79,14 @@ bool IPAddress::fromString4(const char *address)
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
acc = acc * 10 + (c - '0');
|
||||
if (acc > 255)
|
||||
{
|
||||
if (acc > 255) {
|
||||
// Value out of [0..255] range
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
if (dots == 3)
|
||||
{
|
||||
if (dots == 3) {
|
||||
// Too much dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
@ -110,8 +100,7 @@ bool IPAddress::fromString4(const char *address)
|
||||
}
|
||||
}
|
||||
|
||||
if (dots != 3)
|
||||
{
|
||||
if (dots != 3) {
|
||||
// Too few dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
@ -121,71 +110,52 @@ bool IPAddress::fromString4(const char *address)
|
||||
return true;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||
{
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address) {
|
||||
setV4();
|
||||
v4() = *reinterpret_cast<const uint32_t*>(address);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(uint32_t address)
|
||||
{
|
||||
IPAddress& IPAddress::operator=(uint32_t address) {
|
||||
setV4();
|
||||
v4() = address;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const uint8_t* addr) const
|
||||
{
|
||||
bool IPAddress::operator==(const uint8_t* addr) const {
|
||||
return isV4() && v4() == *reinterpret_cast<const uint32_t*>(addr);
|
||||
}
|
||||
|
||||
size_t IPAddress::printTo(Print& p) const
|
||||
{
|
||||
size_t IPAddress::printTo(Print& p) const {
|
||||
size_t n = 0;
|
||||
|
||||
if (!isSet())
|
||||
{
|
||||
return p.print(F("(IP unset)"));
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (isV6())
|
||||
{
|
||||
if (isV6()) {
|
||||
int count0 = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint16_t bit = PP_NTOHS(raw6()[i]);
|
||||
if (bit || count0 < 0)
|
||||
{
|
||||
if (bit || count0 < 0) {
|
||||
n += p.printf("%x", bit);
|
||||
if (count0 > 0)
|
||||
// no more hiding 0
|
||||
{
|
||||
count0 = -8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
count0++;
|
||||
}
|
||||
if ((i != 7 && count0 < 2) || count0 == 7)
|
||||
{
|
||||
n += p.print(':');
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
n += p.print((*this)[i], DEC);
|
||||
if (i != 3)
|
||||
{
|
||||
n += p.print('.');
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -194,9 +164,7 @@ String IPAddress::toString() const
|
||||
StreamString sstr;
|
||||
#if LWIP_IPV6
|
||||
if (isV6())
|
||||
{
|
||||
sstr.reserve(40); // 8 shorts x 4 chars each + 7 colons + nullterm
|
||||
}
|
||||
else
|
||||
#endif
|
||||
sstr.reserve(16); // 4 bytes with 3 chars max + 3 dots + nullterm, or '(IP unset)'
|
||||
@ -204,13 +172,11 @@ String IPAddress::toString() const
|
||||
return sstr;
|
||||
}
|
||||
|
||||
bool IPAddress::isValid(const String& arg)
|
||||
{
|
||||
bool IPAddress::isValid(const String& arg) {
|
||||
return IPAddress().fromString(arg);
|
||||
}
|
||||
|
||||
bool IPAddress::isValid(const char* arg)
|
||||
{
|
||||
bool IPAddress::isValid(const char* arg) {
|
||||
return IPAddress().fromString(arg);
|
||||
}
|
||||
|
||||
@ -221,8 +187,7 @@ const IPAddress INADDR_NONE(255, 255, 255, 255);
|
||||
|
||||
#if LWIP_IPV6
|
||||
|
||||
bool IPAddress::fromString6(const char *address)
|
||||
{
|
||||
bool IPAddress::fromString6(const char *address) {
|
||||
// TODO: test test test
|
||||
|
||||
uint32_t acc = 0; // Accumulator
|
||||
@ -231,65 +196,45 @@ bool IPAddress::fromString6(const char *address)
|
||||
while (*address)
|
||||
{
|
||||
char c = tolower(*address++);
|
||||
if (isalnum(c))
|
||||
{
|
||||
if (isalnum(c)) {
|
||||
if (c >= 'a')
|
||||
{
|
||||
c -= 'a' - '0' - 10;
|
||||
}
|
||||
acc = acc * 16 + (c - '0');
|
||||
if (acc > 0xffff)
|
||||
// Value out of range
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (c == ':')
|
||||
{
|
||||
if (*address == ':')
|
||||
{
|
||||
else if (c == ':') {
|
||||
if (*address == ':') {
|
||||
if (doubledots >= 0)
|
||||
// :: allowed once
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// remember location
|
||||
doubledots = dots + !!acc;
|
||||
address++;
|
||||
}
|
||||
if (dots == 7)
|
||||
// too many separators
|
||||
{
|
||||
return false;
|
||||
}
|
||||
raw6()[dots++] = PP_HTONS(acc);
|
||||
acc = 0;
|
||||
}
|
||||
else
|
||||
// Invalid char
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (doubledots == -1 && dots != 7)
|
||||
// Too few separators
|
||||
{
|
||||
return false;
|
||||
}
|
||||
raw6()[dots++] = PP_HTONS(acc);
|
||||
|
||||
if (doubledots != -1)
|
||||
{
|
||||
if (doubledots != -1) {
|
||||
for (int i = dots - doubledots - 1; i >= 0; i--)
|
||||
{
|
||||
raw6()[8 - dots + doubledots + i] = raw6()[doubledots + i];
|
||||
}
|
||||
for (int i = doubledots; i < 8 - dots + doubledots; i++)
|
||||
{
|
||||
raw6()[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
setV6();
|
||||
return true;
|
||||
|
@ -54,8 +54,7 @@ struct ip_addr: ipv4_addr { };
|
||||
// fully backward compatible with legacy IPv4-only Arduino's
|
||||
// with unchanged footprint when IPv6 is disabled
|
||||
|
||||
class IPAddress: public Printable
|
||||
{
|
||||
class IPAddress: public Printable {
|
||||
private:
|
||||
|
||||
ip_addr_t _ip;
|
||||
@ -64,12 +63,10 @@ private:
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t* raw_address()
|
||||
{
|
||||
uint8_t* raw_address() {
|
||||
return reinterpret_cast<uint8_t*>(&v4());
|
||||
}
|
||||
const uint8_t* raw_address() const
|
||||
{
|
||||
const uint8_t* raw_address() const {
|
||||
return reinterpret_cast<const uint8_t*>(&v4());
|
||||
}
|
||||
|
||||
@ -80,103 +77,58 @@ public:
|
||||
IPAddress();
|
||||
IPAddress(const IPAddress& from);
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
IPAddress(uint32_t address)
|
||||
{
|
||||
ctor32(address);
|
||||
}
|
||||
IPAddress(u32_t address)
|
||||
{
|
||||
ctor32(address);
|
||||
}
|
||||
IPAddress(int address)
|
||||
{
|
||||
ctor32(address);
|
||||
}
|
||||
IPAddress(uint32_t address) { ctor32(address); }
|
||||
IPAddress(u32_t address) { ctor32(address); }
|
||||
IPAddress(int address) { ctor32(address); }
|
||||
IPAddress(const uint8_t *address);
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const String &address)
|
||||
{
|
||||
return fromString(address.c_str());
|
||||
}
|
||||
bool fromString(const String &address) { return fromString(address.c_str()); }
|
||||
|
||||
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
|
||||
// to a four-byte uint8_t array is expected
|
||||
operator uint32_t() const
|
||||
{
|
||||
return isV4() ? v4() : (uint32_t)0;
|
||||
}
|
||||
operator uint32_t()
|
||||
{
|
||||
return isV4() ? v4() : (uint32_t)0;
|
||||
}
|
||||
operator u32_t() const
|
||||
{
|
||||
return isV4() ? v4() : (u32_t)0;
|
||||
}
|
||||
operator u32_t()
|
||||
{
|
||||
return isV4() ? v4() : (u32_t)0;
|
||||
}
|
||||
operator uint32_t() const { return isV4()? v4(): (uint32_t)0; }
|
||||
operator uint32_t() { return isV4()? v4(): (uint32_t)0; }
|
||||
operator u32_t() const { return isV4()? v4(): (u32_t)0; }
|
||||
operator u32_t() { return isV4()? v4(): (u32_t)0; }
|
||||
|
||||
bool isSet () const;
|
||||
operator bool () const
|
||||
{
|
||||
return isSet(); // <-
|
||||
}
|
||||
operator bool ()
|
||||
{
|
||||
return isSet(); // <- both are needed
|
||||
}
|
||||
operator bool () const { return isSet(); } // <-
|
||||
operator bool () { return isSet(); } // <- both are needed
|
||||
|
||||
// generic IPv4 wrapper to uint32-view like arduino loves to see it
|
||||
const u32_t& v4() const
|
||||
{
|
||||
return ip_2_ip4(&_ip)->addr; // for raw_address(const)
|
||||
}
|
||||
u32_t& v4()
|
||||
{
|
||||
return ip_2_ip4(&_ip)->addr;
|
||||
}
|
||||
const u32_t& v4() const { return ip_2_ip4(&_ip)->addr; } // for raw_address(const)
|
||||
u32_t& v4() { return ip_2_ip4(&_ip)->addr; }
|
||||
|
||||
bool operator==(const IPAddress& addr) const
|
||||
{
|
||||
bool operator==(const IPAddress& addr) const {
|
||||
return ip_addr_cmp(&_ip, &addr._ip);
|
||||
}
|
||||
bool operator!=(const IPAddress& addr) const
|
||||
{
|
||||
bool operator!=(const IPAddress& addr) const {
|
||||
return !ip_addr_cmp(&_ip, &addr._ip);
|
||||
}
|
||||
bool operator==(uint32_t addr) const
|
||||
{
|
||||
bool operator==(uint32_t addr) const {
|
||||
return isV4() && v4() == addr;
|
||||
}
|
||||
bool operator==(u32_t addr) const
|
||||
{
|
||||
bool operator==(u32_t addr) const {
|
||||
return isV4() && v4() == addr;
|
||||
}
|
||||
bool operator!=(uint32_t addr) const
|
||||
{
|
||||
bool operator!=(uint32_t addr) const {
|
||||
return !(isV4() && v4() == addr);
|
||||
}
|
||||
bool operator!=(u32_t addr) const
|
||||
{
|
||||
bool operator!=(u32_t addr) const {
|
||||
return !(isV4() && v4() == addr);
|
||||
}
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
int operator>>(int n) const
|
||||
{
|
||||
int operator>>(int n) const {
|
||||
return isV4()? v4() >> n: 0;
|
||||
}
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const
|
||||
{
|
||||
uint8_t operator[](int index) const {
|
||||
return isV4()? *(raw_address() + index): 0;
|
||||
}
|
||||
uint8_t& operator[](int index)
|
||||
{
|
||||
uint8_t& operator[](int index) {
|
||||
setV4();
|
||||
return *(raw_address() + index);
|
||||
}
|
||||
@ -206,78 +158,28 @@ public:
|
||||
/*
|
||||
lwIP address compatibility
|
||||
*/
|
||||
IPAddress(const ipv4_addr& fw_addr)
|
||||
{
|
||||
setV4();
|
||||
v4() = fw_addr.addr;
|
||||
}
|
||||
IPAddress(const ipv4_addr* fw_addr)
|
||||
{
|
||||
setV4();
|
||||
v4() = fw_addr->addr;
|
||||
}
|
||||
IPAddress(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; }
|
||||
IPAddress(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; }
|
||||
|
||||
IPAddress& operator=(const ipv4_addr& fw_addr)
|
||||
{
|
||||
setV4();
|
||||
v4() = fw_addr.addr;
|
||||
return *this;
|
||||
}
|
||||
IPAddress& operator=(const ipv4_addr* fw_addr)
|
||||
{
|
||||
setV4();
|
||||
v4() = fw_addr->addr;
|
||||
return *this;
|
||||
}
|
||||
IPAddress& operator=(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; return *this; }
|
||||
IPAddress& operator=(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; return *this; }
|
||||
|
||||
operator ip_addr_t () const
|
||||
{
|
||||
return _ip;
|
||||
}
|
||||
operator const ip_addr_t*() const
|
||||
{
|
||||
return &_ip;
|
||||
}
|
||||
operator ip_addr_t*()
|
||||
{
|
||||
return &_ip;
|
||||
}
|
||||
operator ip_addr_t () const { return _ip; }
|
||||
operator const ip_addr_t*() const { return &_ip; }
|
||||
operator ip_addr_t*() { return &_ip; }
|
||||
|
||||
bool isV4() const
|
||||
{
|
||||
return IP_IS_V4_VAL(_ip);
|
||||
}
|
||||
void setV4()
|
||||
{
|
||||
IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V4);
|
||||
}
|
||||
bool isV4() const { return IP_IS_V4_VAL(_ip); }
|
||||
void setV4() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V4); }
|
||||
|
||||
bool isLocal() const
|
||||
{
|
||||
return ip_addr_islinklocal(&_ip);
|
||||
}
|
||||
bool isLocal () const { return ip_addr_islinklocal(&_ip); }
|
||||
|
||||
#if LWIP_IPV6
|
||||
|
||||
IPAddress(const ip_addr_t& lwip_addr)
|
||||
{
|
||||
ip_addr_copy(_ip, lwip_addr);
|
||||
}
|
||||
IPAddress(const ip_addr_t* lwip_addr)
|
||||
{
|
||||
ip_addr_copy(_ip, *lwip_addr);
|
||||
}
|
||||
IPAddress(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); }
|
||||
IPAddress(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); }
|
||||
|
||||
IPAddress& operator=(const ip_addr_t& lwip_addr)
|
||||
{
|
||||
ip_addr_copy(_ip, lwip_addr);
|
||||
return *this;
|
||||
}
|
||||
IPAddress& operator=(const ip_addr_t* lwip_addr)
|
||||
{
|
||||
ip_addr_copy(_ip, *lwip_addr);
|
||||
return *this;
|
||||
}
|
||||
IPAddress& operator=(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); return *this; }
|
||||
IPAddress& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; }
|
||||
|
||||
uint16_t* raw6()
|
||||
{
|
||||
@ -292,19 +194,10 @@ public:
|
||||
|
||||
// when not IPv6, ip_addr_t == ip4_addr_t so this one would be ambiguous
|
||||
// required otherwise
|
||||
operator const ip4_addr_t*() const
|
||||
{
|
||||
return isV4() ? ip_2_ip4(&_ip) : nullptr;
|
||||
}
|
||||
operator const ip4_addr_t*() const { return isV4()? ip_2_ip4(&_ip): nullptr; }
|
||||
|
||||
bool isV6() const
|
||||
{
|
||||
return IP_IS_V6_VAL(_ip);
|
||||
}
|
||||
void setV6()
|
||||
{
|
||||
IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6);
|
||||
}
|
||||
bool isV6() const { return IP_IS_V6_VAL(_ip); }
|
||||
void setV6() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6); }
|
||||
|
||||
protected:
|
||||
bool fromString6(const char *address);
|
||||
@ -313,18 +206,9 @@ protected:
|
||||
|
||||
// allow portable code when IPv6 is not enabled
|
||||
|
||||
uint16_t* raw6()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
const uint16_t* raw6() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
bool isV6() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint16_t* raw6() { return nullptr; }
|
||||
const uint16_t* raw6() const { return nullptr; }
|
||||
bool isV6() const { return false; }
|
||||
void setV6() { }
|
||||
|
||||
#endif
|
||||
|
@ -1,34 +1,28 @@
|
||||
#include <Arduino.h>
|
||||
#include <MD5Builder.h>
|
||||
|
||||
uint8_t hex_char_to_byte(uint8_t c)
|
||||
{
|
||||
uint8_t hex_char_to_byte(uint8_t c){
|
||||
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
|
||||
(c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) :
|
||||
(c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0;
|
||||
}
|
||||
|
||||
void MD5Builder::begin(void)
|
||||
{
|
||||
void MD5Builder::begin(void){
|
||||
memset(_buf, 0x00, 16);
|
||||
MD5Init(&_ctx);
|
||||
}
|
||||
|
||||
void MD5Builder::add(const uint8_t * data, const uint16_t len)
|
||||
{
|
||||
void MD5Builder::add(const uint8_t * data, const uint16_t len){
|
||||
MD5Update(&_ctx, data, len);
|
||||
}
|
||||
|
||||
void MD5Builder::addHexString(const char * data)
|
||||
{
|
||||
void MD5Builder::addHexString(const char * data){
|
||||
uint16_t i, len = strlen(data);
|
||||
uint8_t * tmp = (uint8_t*)malloc(len/2);
|
||||
if (tmp == NULL)
|
||||
{
|
||||
if(tmp == NULL) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
for(i=0; i<len; i+=2) {
|
||||
uint8_t high = hex_char_to_byte(data[i]);
|
||||
uint8_t low = hex_char_to_byte(data[i+1]);
|
||||
tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F);
|
||||
@ -37,36 +31,30 @@ void MD5Builder::addHexString(const char * data)
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
bool MD5Builder::addStream(Stream & stream, const size_t maxLen)
|
||||
{
|
||||
bool MD5Builder::addStream(Stream & stream, const size_t maxLen){
|
||||
const int buf_size = 512;
|
||||
int maxLengthLeft = maxLen;
|
||||
uint8_t * buf = (uint8_t*) malloc(buf_size);
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
if(!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int bytesAvailable = stream.available();
|
||||
while ((bytesAvailable > 0) && (maxLengthLeft > 0))
|
||||
{
|
||||
while((bytesAvailable > 0) && (maxLengthLeft > 0)) {
|
||||
|
||||
// determine number of bytes to read
|
||||
int readBytes = bytesAvailable;
|
||||
if (readBytes > maxLengthLeft)
|
||||
{
|
||||
if(readBytes > maxLengthLeft) {
|
||||
readBytes = maxLengthLeft ; // read only until max_len
|
||||
}
|
||||
if (readBytes > buf_size)
|
||||
{
|
||||
if(readBytes > buf_size) {
|
||||
readBytes = buf_size; // not read more the buffer can handle
|
||||
}
|
||||
|
||||
// read data and check if we got something
|
||||
int numBytesRead = stream.readBytes(buf, readBytes);
|
||||
if (numBytesRead < 1)
|
||||
{
|
||||
if(numBytesRead< 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -83,26 +71,21 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen)
|
||||
return true;
|
||||
}
|
||||
|
||||
void MD5Builder::calculate(void)
|
||||
{
|
||||
void MD5Builder::calculate(void){
|
||||
MD5Final(_buf, &_ctx);
|
||||
}
|
||||
|
||||
void MD5Builder::getBytes(uint8_t * output)
|
||||
{
|
||||
void MD5Builder::getBytes(uint8_t * output){
|
||||
memcpy(output, _buf, 16);
|
||||
}
|
||||
|
||||
void MD5Builder::getChars(char * output)
|
||||
{
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
void MD5Builder::getChars(char * output){
|
||||
for(uint8_t i = 0; i < 16; i++) {
|
||||
sprintf(output + (i * 2), "%02x", _buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
String MD5Builder::toString(void)
|
||||
{
|
||||
String MD5Builder::toString(void){
|
||||
char out[33];
|
||||
getChars(out);
|
||||
return String(out);
|
||||
|
@ -25,35 +25,19 @@
|
||||
#include <Stream.h>
|
||||
#include "md5.h"
|
||||
|
||||
class MD5Builder
|
||||
{
|
||||
class MD5Builder {
|
||||
private:
|
||||
md5_context_t _ctx;
|
||||
uint8_t _buf[16];
|
||||
public:
|
||||
void begin(void);
|
||||
void add(const uint8_t * data, const uint16_t len);
|
||||
void add(const char * data)
|
||||
{
|
||||
add((const uint8_t*)data, strlen(data));
|
||||
}
|
||||
void add(char * data)
|
||||
{
|
||||
add((const char*)data);
|
||||
}
|
||||
void add(const String& data)
|
||||
{
|
||||
add(data.c_str());
|
||||
}
|
||||
void add(const char * data){ add((const uint8_t*)data, strlen(data)); }
|
||||
void add(char * data){ add((const char*)data); }
|
||||
void add(const String& data){ add(data.c_str()); }
|
||||
void addHexString(const char * data);
|
||||
void addHexString(char * data)
|
||||
{
|
||||
addHexString((const char*)data);
|
||||
}
|
||||
void addHexString(const String& data)
|
||||
{
|
||||
addHexString(data.c_str());
|
||||
}
|
||||
void addHexString(char * data){ addHexString((const char*)data); }
|
||||
void addHexString(const String& data){ addHexString(data.c_str()); }
|
||||
bool addStream(Stream & stream, const size_t maxLen);
|
||||
void calculate(void);
|
||||
void getBytes(uint8_t * output);
|
||||
|
@ -44,19 +44,13 @@ struct DoNothing
|
||||
|
||||
struct YieldOrSkip
|
||||
{
|
||||
static void execute()
|
||||
{
|
||||
delay(0);
|
||||
}
|
||||
static void execute() {delay(0);}
|
||||
};
|
||||
|
||||
template <unsigned long delayMs>
|
||||
struct YieldAndDelayMs
|
||||
{
|
||||
static void execute()
|
||||
{
|
||||
delay(delayMs);
|
||||
}
|
||||
static void execute() {delay(delayMs);}
|
||||
};
|
||||
|
||||
} //YieldPolicy
|
||||
@ -69,10 +63,7 @@ struct TimeSourceMillis
|
||||
// time policy in milli-seconds based on millis()
|
||||
|
||||
using timeType = decltype(millis());
|
||||
static timeType time()
|
||||
{
|
||||
return millis();
|
||||
}
|
||||
static timeType time() {return millis();}
|
||||
static constexpr timeType ticksPerSecond = 1000;
|
||||
static constexpr timeType ticksPerSecondMax = 1000;
|
||||
};
|
||||
@ -84,10 +75,7 @@ struct TimeSourceCycles
|
||||
// (every loop, every yield)
|
||||
|
||||
using timeType = decltype(ESP.getCycleCount());
|
||||
static timeType time()
|
||||
{
|
||||
return ESP.getCycleCount();
|
||||
}
|
||||
static timeType time() {return ESP.getCycleCount();}
|
||||
static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz
|
||||
static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz
|
||||
};
|
||||
@ -106,8 +94,7 @@ struct TimeUnit
|
||||
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
|
||||
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
|
||||
|
||||
return (
|
||||
{
|
||||
return ({
|
||||
fractional == 0?
|
||||
1: // no need for compensation
|
||||
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
||||
@ -119,8 +106,7 @@ struct TimeUnit
|
||||
#else
|
||||
static constexpr timeType computeRangeCompensation ()
|
||||
{
|
||||
return (
|
||||
{
|
||||
return ({
|
||||
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
|
||||
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
|
||||
fractional == 0?
|
||||
@ -139,18 +125,9 @@ struct TimeUnit
|
||||
// std::numeric_limits<timeType>::max() is reserved
|
||||
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
|
||||
|
||||
static timeType toTimeTypeUnit(const timeType userUnit)
|
||||
{
|
||||
return (userUnit * user2UnitMultiplier) / user2UnitDivider;
|
||||
}
|
||||
static timeType toUserUnit(const timeType internalUnit)
|
||||
{
|
||||
return (internalUnit * user2UnitDivider) / user2UnitMultiplier;
|
||||
}
|
||||
static timeType time()
|
||||
{
|
||||
return TimeSourceType::time();
|
||||
}
|
||||
static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;}
|
||||
static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;}
|
||||
static timeType time () {return TimeSourceType::time();}
|
||||
};
|
||||
|
||||
using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >;
|
||||
@ -181,9 +158,7 @@ public:
|
||||
{
|
||||
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
|
||||
if(PeriodicT) //in case of false: gets optimized away
|
||||
{
|
||||
return expiredRetrigger();
|
||||
}
|
||||
return expiredOneShot();
|
||||
}
|
||||
|
||||
@ -247,9 +222,7 @@ protected:
|
||||
bool expiredRetrigger()
|
||||
{
|
||||
if (!canWait())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
timeType current = TimePolicyT::time();
|
||||
if(checkExpired(current))
|
||||
@ -304,9 +277,9 @@ using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothi
|
||||
|
||||
|
||||
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
|
||||
using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
|
||||
|
||||
Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
|
||||
* using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
|
||||
*
|
||||
* Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
|
||||
*/
|
||||
|
||||
}//esp8266
|
||||
|
@ -32,25 +32,21 @@
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
/* default implementation: may be overridden */
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t Print::write(const uint8_t *buffer, size_t size) {
|
||||
|
||||
#ifdef DEBUG_ESP_CORE
|
||||
static char not_the_best_way [] PROGMEM STORE_ATTR = "Print::write(data,len) should be overridden for better efficiency\r\n";
|
||||
static bool once = false;
|
||||
if (!once)
|
||||
{
|
||||
if (!once) {
|
||||
once = true;
|
||||
os_printf_plus(not_the_best_way);
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t n = 0;
|
||||
while (size--)
|
||||
{
|
||||
while (size--) {
|
||||
size_t ret = write(*buffer++);
|
||||
if (ret == 0)
|
||||
{
|
||||
if (ret == 0) {
|
||||
// Write of last byte didn't complete, abort additional processing
|
||||
break;
|
||||
}
|
||||
@ -59,19 +55,16 @@ size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::printf(const char *format, ...)
|
||||
{
|
||||
size_t Print::printf(const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char temp[64];
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
||||
va_end(arg);
|
||||
if (len > sizeof(temp) - 1)
|
||||
{
|
||||
if (len > sizeof(temp) - 1) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer)
|
||||
{
|
||||
if (!buffer) {
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, format);
|
||||
@ -79,26 +72,22 @@ size_t Print::printf(const char *format, ...)
|
||||
va_end(arg);
|
||||
}
|
||||
len = write((const uint8_t*) buffer, len);
|
||||
if (buffer != temp)
|
||||
{
|
||||
if (buffer != temp) {
|
||||
delete[] buffer;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t Print::printf_P(PGM_P format, ...)
|
||||
{
|
||||
size_t Print::printf_P(PGM_P format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char temp[64];
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf_P(temp, sizeof(temp), format, arg);
|
||||
va_end(arg);
|
||||
if (len > sizeof(temp) - 1)
|
||||
{
|
||||
if (len > sizeof(temp) - 1) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer)
|
||||
{
|
||||
if (!buffer) {
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, format);
|
||||
@ -106,181 +95,143 @@ size_t Print::printf_P(PGM_P format, ...)
|
||||
va_end(arg);
|
||||
}
|
||||
len = write((const uint8_t*) buffer, len);
|
||||
if (buffer != temp)
|
||||
{
|
||||
if (buffer != temp) {
|
||||
delete[] buffer;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t Print::print(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
size_t Print::print(const __FlashStringHelper *ifsh) {
|
||||
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
|
||||
|
||||
size_t n = 0;
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
uint8_t c = pgm_read_byte(p++);
|
||||
if (c == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (c == 0) break;
|
||||
n += write(c);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::print(const String &s)
|
||||
{
|
||||
size_t Print::print(const String &s) {
|
||||
return write(s.c_str(), s.length());
|
||||
}
|
||||
|
||||
size_t Print::print(const char str[])
|
||||
{
|
||||
size_t Print::print(const char str[]) {
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::print(char c)
|
||||
{
|
||||
size_t Print::print(char c) {
|
||||
return write(c);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned char b, int base)
|
||||
{
|
||||
size_t Print::print(unsigned char b, int base) {
|
||||
return print((unsigned long) b, base);
|
||||
}
|
||||
|
||||
size_t Print::print(int n, int base)
|
||||
{
|
||||
size_t Print::print(int n, int base) {
|
||||
return print((long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned int n, int base)
|
||||
{
|
||||
size_t Print::print(unsigned int n, int base) {
|
||||
return print((unsigned long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(long n, int base)
|
||||
{
|
||||
if (base == 0)
|
||||
{
|
||||
size_t Print::print(long n, int base) {
|
||||
if(base == 0) {
|
||||
return write(n);
|
||||
}
|
||||
else if (base == 10)
|
||||
{
|
||||
if (n < 0)
|
||||
{
|
||||
} else if(base == 10) {
|
||||
if(n < 0) {
|
||||
int t = print('-');
|
||||
n = -n;
|
||||
return printNumber(n, 10) + t;
|
||||
}
|
||||
return printNumber(n, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long n, int base)
|
||||
{
|
||||
size_t Print::print(unsigned long n, int base) {
|
||||
if(base == 0)
|
||||
{
|
||||
return write(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(double n, int digits)
|
||||
{
|
||||
size_t Print::print(double n, int digits) {
|
||||
return printFloat(n, digits);
|
||||
}
|
||||
|
||||
size_t Print::println(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
size_t Print::println(const __FlashStringHelper *ifsh) {
|
||||
size_t n = print(ifsh);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::print(const Printable& x)
|
||||
{
|
||||
size_t Print::print(const Printable& x) {
|
||||
return x.printTo(*this);
|
||||
}
|
||||
|
||||
size_t Print::println(void)
|
||||
{
|
||||
size_t Print::println(void) {
|
||||
return print("\r\n");
|
||||
}
|
||||
|
||||
size_t Print::println(const String &s)
|
||||
{
|
||||
size_t Print::println(const String &s) {
|
||||
size_t n = print(s);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const char c[])
|
||||
{
|
||||
size_t Print::println(const char c[]) {
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(char c)
|
||||
{
|
||||
size_t Print::println(char c) {
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned char b, int base)
|
||||
{
|
||||
size_t Print::println(unsigned char b, int base) {
|
||||
size_t n = print(b, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(int num, int base)
|
||||
{
|
||||
size_t Print::println(int num, int base) {
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned int num, int base)
|
||||
{
|
||||
size_t Print::println(unsigned int num, int base) {
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(long num, int base)
|
||||
{
|
||||
size_t Print::println(long num, int base) {
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned long num, int base)
|
||||
{
|
||||
size_t Print::println(unsigned long num, int base) {
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(double num, int digits)
|
||||
{
|
||||
size_t Print::println(double num, int digits) {
|
||||
size_t n = print(num, digits);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const Printable& x)
|
||||
{
|
||||
size_t Print::println(const Printable& x) {
|
||||
size_t n = print(x);
|
||||
n += println();
|
||||
return n;
|
||||
@ -288,8 +239,7 @@ size_t Print::println(const Printable& x)
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base) {
|
||||
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
|
||||
@ -297,12 +247,9 @@ size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
|
||||
// prevent crash if called with base == 1
|
||||
if(base < 2)
|
||||
{
|
||||
base = 10;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
unsigned long m = n;
|
||||
n /= base;
|
||||
char c = m - base * n;
|
||||
@ -312,30 +259,20 @@ size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
size_t Print::printFloat(double number, uint8_t digits) {
|
||||
size_t n = 0;
|
||||
|
||||
if(isnan(number))
|
||||
{
|
||||
return print("nan");
|
||||
}
|
||||
if(isinf(number))
|
||||
{
|
||||
return print("inf");
|
||||
}
|
||||
if(number > 4294967040.0)
|
||||
{
|
||||
return print("ovf"); // constant determined empirically
|
||||
}
|
||||
if(number < -4294967040.0)
|
||||
{
|
||||
return print("ovf"); // constant determined empirically
|
||||
}
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0)
|
||||
{
|
||||
if(number < 0.0) {
|
||||
n += print('-');
|
||||
number = -number;
|
||||
}
|
||||
@ -343,9 +280,7 @@ size_t Print::printFloat(double number, uint8_t digits)
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for(uint8_t i = 0; i < digits; ++i)
|
||||
{
|
||||
rounding /= 10.0;
|
||||
}
|
||||
|
||||
number += rounding;
|
||||
|
||||
@ -355,14 +290,12 @@ size_t Print::printFloat(double number, uint8_t digits)
|
||||
n += print(int_part);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0)
|
||||
{
|
||||
if(digits > 0) {
|
||||
n += print(".");
|
||||
}
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while (digits-- > 0)
|
||||
{
|
||||
while(digits-- > 0) {
|
||||
remainder *= 10.0;
|
||||
int toPrint = int(remainder);
|
||||
n += print(toPrint);
|
||||
|
@ -31,71 +31,44 @@
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
|
||||
class Print
|
||||
{
|
||||
class Print {
|
||||
private:
|
||||
int write_error;
|
||||
size_t printNumber(unsigned long, uint8_t);
|
||||
size_t printFloat(double, uint8_t);
|
||||
protected:
|
||||
void setWriteError(int err = 1)
|
||||
{
|
||||
void setWriteError(int err = 1) {
|
||||
write_error = err;
|
||||
}
|
||||
public:
|
||||
Print() :
|
||||
write_error(0)
|
||||
{
|
||||
write_error(0) {
|
||||
}
|
||||
|
||||
int getWriteError()
|
||||
{
|
||||
int getWriteError() {
|
||||
return write_error;
|
||||
}
|
||||
void clearWriteError()
|
||||
{
|
||||
void clearWriteError() {
|
||||
setWriteError(0);
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
size_t write(const char *str)
|
||||
{
|
||||
size_t write(const char *str) {
|
||||
if(str == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return write((const uint8_t *) str, strlen(str));
|
||||
}
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
size_t write(const char *buffer, size_t size)
|
||||
{
|
||||
size_t write(const char *buffer, size_t size) {
|
||||
return write((const uint8_t *) buffer, size);
|
||||
}
|
||||
// These handle ambiguity for write(0) case, because (0) can be a pointer or an integer
|
||||
size_t write(short t)
|
||||
{
|
||||
return write((uint8_t)t);
|
||||
}
|
||||
size_t write(unsigned short t)
|
||||
{
|
||||
return write((uint8_t)t);
|
||||
}
|
||||
size_t write(int t)
|
||||
{
|
||||
return write((uint8_t)t);
|
||||
}
|
||||
size_t write(unsigned int t)
|
||||
{
|
||||
return write((uint8_t)t);
|
||||
}
|
||||
size_t write(long t)
|
||||
{
|
||||
return write((uint8_t)t);
|
||||
}
|
||||
size_t write(unsigned long t)
|
||||
{
|
||||
return write((uint8_t)t);
|
||||
}
|
||||
size_t write(short t) { return write((uint8_t)t); }
|
||||
size_t write(unsigned short t) { return write((uint8_t)t); }
|
||||
size_t write(int t) { return write((uint8_t)t); }
|
||||
size_t write(unsigned int t) { return write((uint8_t)t); }
|
||||
size_t write(long t) { return write((uint8_t)t); }
|
||||
size_t write(unsigned long t) { return write((uint8_t)t); }
|
||||
|
||||
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
@ -30,8 +30,7 @@ class Print;
|
||||
Print::print and Print::println methods.
|
||||
*/
|
||||
|
||||
class Printable
|
||||
{
|
||||
class Printable {
|
||||
public:
|
||||
virtual size_t printTo(Print& p) const = 0;
|
||||
};
|
||||
|
@ -14,22 +14,18 @@ static scheduled_fn_t* sLastUnused = 0;
|
||||
|
||||
static int sCount = 0;
|
||||
|
||||
static scheduled_fn_t* get_fn()
|
||||
{
|
||||
static scheduled_fn_t* get_fn() {
|
||||
scheduled_fn_t* result = NULL;
|
||||
// try to get an item from unused items list
|
||||
if (sFirstUnused)
|
||||
{
|
||||
if (sFirstUnused) {
|
||||
result = sFirstUnused;
|
||||
sFirstUnused = result->mNext;
|
||||
if (sFirstUnused == NULL)
|
||||
{
|
||||
if (sFirstUnused == NULL) {
|
||||
sLastUnused = NULL;
|
||||
}
|
||||
}
|
||||
// if no unused items, and count not too high, allocate a new one
|
||||
else if (sCount != SCHEDULED_FN_MAX_COUNT)
|
||||
{
|
||||
else if (sCount != SCHEDULED_FN_MAX_COUNT) {
|
||||
result = new scheduled_fn_t;
|
||||
result->mNext = NULL;
|
||||
++sCount;
|
||||
@ -39,12 +35,10 @@ static scheduled_fn_t* get_fn()
|
||||
|
||||
static void recycle_fn(scheduled_fn_t* fn)
|
||||
{
|
||||
if (!sLastUnused)
|
||||
{
|
||||
if (!sLastUnused) {
|
||||
sFirstUnused = fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
sLastUnused->mNext = fn;
|
||||
}
|
||||
fn->mNext = NULL;
|
||||
@ -54,18 +48,15 @@ static void recycle_fn(scheduled_fn_t* fn)
|
||||
bool schedule_function(std::function<void(void)> fn)
|
||||
{
|
||||
scheduled_fn_t* item = get_fn();
|
||||
if (!item)
|
||||
{
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
item->mFunc = fn;
|
||||
item->mNext = NULL;
|
||||
if (!sFirst)
|
||||
{
|
||||
if (!sFirst) {
|
||||
sFirst = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
sLast->mNext = item;
|
||||
}
|
||||
sLast = item;
|
||||
@ -77,8 +68,7 @@ void run_scheduled_functions()
|
||||
scheduled_fn_t* rFirst = sFirst;
|
||||
sFirst = NULL;
|
||||
sLast = NULL;
|
||||
while (rFirst)
|
||||
{
|
||||
while (rFirst) {
|
||||
scheduled_fn_t* item = rFirst;
|
||||
rFirst = item->mNext;
|
||||
item->mFunc();
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
ScheduledFunctions.cpp
|
||||
|
||||
Created on: 27 apr. 2018
|
||||
Author: Herman
|
||||
* ScheduledFunctions.cpp
|
||||
*
|
||||
* Created on: 27 apr. 2018
|
||||
* Author: Herman
|
||||
*/
|
||||
#include "ScheduledFunctions.h"
|
||||
|
||||
@ -18,8 +18,7 @@ ScheduledFunctions::ScheduledFunctions(unsigned int reqMax)
|
||||
maxElements = reqMax;
|
||||
}
|
||||
|
||||
ScheduledFunctions::~ScheduledFunctions()
|
||||
{
|
||||
ScheduledFunctions::~ScheduledFunctions() {
|
||||
}
|
||||
|
||||
ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front)
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
ScheduledFunctions.h
|
||||
|
||||
Created on: 27 apr. 2018
|
||||
Author: Herman
|
||||
* ScheduledFunctions.h
|
||||
*
|
||||
* Created on: 27 apr. 2018
|
||||
* Author: Herman
|
||||
*/
|
||||
#include "Arduino.h"
|
||||
#include "Schedule.h"
|
||||
@ -18,8 +18,7 @@
|
||||
typedef std::function<void(void)> ScheduledFunction;
|
||||
typedef std::shared_ptr<void> ScheduledRegistration;
|
||||
|
||||
class ScheduledFunctions
|
||||
{
|
||||
class ScheduledFunctions {
|
||||
|
||||
public:
|
||||
ScheduledFunctions();
|
||||
|
@ -22,8 +22,7 @@
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
class Server: public Print
|
||||
{
|
||||
class Server: public Print {
|
||||
public:
|
||||
virtual void begin() =0;
|
||||
};
|
||||
|
@ -43,8 +43,7 @@ extern "C" {
|
||||
void stack_thunk_add_ref()
|
||||
{
|
||||
stack_thunk_refcnt++;
|
||||
if (stack_thunk_refcnt == 1)
|
||||
{
|
||||
if (stack_thunk_refcnt == 1) {
|
||||
stack_thunk_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
|
||||
stack_thunk_top = stack_thunk_ptr + _stackSize - 1;
|
||||
stack_thunk_save = NULL;
|
||||
@ -55,14 +54,12 @@ extern "C" {
|
||||
/* Drop a reference, and free stack if no more in use */
|
||||
void stack_thunk_del_ref()
|
||||
{
|
||||
if (stack_thunk_refcnt == 0)
|
||||
{
|
||||
if (stack_thunk_refcnt == 0) {
|
||||
/* Error! */
|
||||
return;
|
||||
}
|
||||
stack_thunk_refcnt--;
|
||||
if (!stack_thunk_refcnt)
|
||||
{
|
||||
if (!stack_thunk_refcnt) {
|
||||
free(stack_thunk_ptr);
|
||||
stack_thunk_ptr = NULL;
|
||||
stack_thunk_top = NULL;
|
||||
@ -72,30 +69,25 @@ extern "C" {
|
||||
|
||||
void stack_thunk_repaint()
|
||||
{
|
||||
for (int i = 0; i < _stackSize; i++)
|
||||
{
|
||||
for (int i=0; i < _stackSize; i++) {
|
||||
stack_thunk_ptr[i] = _stackPaint;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple accessor functions used by postmortem */
|
||||
uint32_t stack_thunk_get_refcnt()
|
||||
{
|
||||
uint32_t stack_thunk_get_refcnt() {
|
||||
return stack_thunk_refcnt;
|
||||
}
|
||||
|
||||
uint32_t stack_thunk_get_stack_top()
|
||||
{
|
||||
uint32_t stack_thunk_get_stack_top() {
|
||||
return (uint32_t)stack_thunk_top;
|
||||
}
|
||||
|
||||
uint32_t stack_thunk_get_stack_bot()
|
||||
{
|
||||
uint32_t stack_thunk_get_stack_bot() {
|
||||
return (uint32_t)stack_thunk_ptr;
|
||||
}
|
||||
|
||||
uint32_t stack_thunk_get_cont_sp()
|
||||
{
|
||||
uint32_t stack_thunk_get_cont_sp() {
|
||||
return (uint32_t)stack_thunk_save;
|
||||
}
|
||||
|
||||
@ -105,13 +97,11 @@ extern "C" {
|
||||
uint32_t cnt = 0;
|
||||
|
||||
/* No stack == no usage by definition! */
|
||||
if (!stack_thunk_ptr)
|
||||
{
|
||||
if (!stack_thunk_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cnt = 0; (cnt < _stackSize) && (stack_thunk_ptr[cnt] == _stackPaint); cnt++)
|
||||
{
|
||||
for (cnt=0; (cnt < _stackSize) && (stack_thunk_ptr[cnt] == _stackPaint); cnt++) {
|
||||
/* Noop, all work done in for() */
|
||||
}
|
||||
return 4 * (_stackSize - cnt);
|
||||
@ -121,17 +111,13 @@ extern "C" {
|
||||
void stack_thunk_dump_stack()
|
||||
{
|
||||
uint32_t *pos = stack_thunk_top;
|
||||
while (pos < stack_thunk_ptr)
|
||||
{
|
||||
while (pos < stack_thunk_ptr) {
|
||||
if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint))
|
||||
{
|
||||
break;
|
||||
}
|
||||
pos += 4;
|
||||
}
|
||||
ets_printf(">>>stack>>>\n");
|
||||
while (pos < stack_thunk_ptr)
|
||||
{
|
||||
while (pos < stack_thunk_ptr) {
|
||||
ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]);
|
||||
pos += 4;
|
||||
}
|
||||
|
@ -26,34 +26,26 @@
|
||||
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
||||
|
||||
// private method to read stream with timeout
|
||||
int Stream::timedRead()
|
||||
{
|
||||
int Stream::timedRead() {
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do
|
||||
{
|
||||
do {
|
||||
c = read();
|
||||
if(c >= 0)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// private method to peek stream with timeout
|
||||
int Stream::timedPeek()
|
||||
{
|
||||
int Stream::timedPeek() {
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do
|
||||
{
|
||||
do {
|
||||
c = peek();
|
||||
if(c >= 0)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
@ -61,24 +53,16 @@ int Stream::timedPeek()
|
||||
|
||||
// returns peek of the next digit in the stream or -1 if timeout
|
||||
// discards non-numeric characters
|
||||
int Stream::peekNextDigit()
|
||||
{
|
||||
int Stream::peekNextDigit() {
|
||||
int c;
|
||||
while (1)
|
||||
{
|
||||
while(1) {
|
||||
c = timedPeek();
|
||||
if(c < 0)
|
||||
{
|
||||
return c; // timeout
|
||||
}
|
||||
if(c == '-')
|
||||
{
|
||||
return c;
|
||||
}
|
||||
if(c >= '0' && c <= '9')
|
||||
{
|
||||
return c;
|
||||
}
|
||||
read(); // discard non-numeric
|
||||
}
|
||||
}
|
||||
@ -92,81 +76,62 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(const char *target)
|
||||
{
|
||||
bool Stream::find(const char *target) {
|
||||
return findUntil(target, (char*) "");
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of given length is found
|
||||
// returns true if target string is found, false if timed out
|
||||
bool Stream::find(const char *target, size_t length)
|
||||
{
|
||||
bool Stream::find(const char *target, size_t length) {
|
||||
return findUntil(target, length, NULL, 0);
|
||||
}
|
||||
|
||||
// as find but search ends if the terminator string is found
|
||||
bool Stream::findUntil(const char *target, const char *terminator)
|
||||
{
|
||||
bool Stream::findUntil(const char *target, const char *terminator) {
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of the given length is found
|
||||
// search terminated if the terminator string is found
|
||||
// returns true if target string is found, false if terminated or timed out
|
||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen)
|
||||
{
|
||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) {
|
||||
size_t index = 0; // maximum target string length is 64k bytes!
|
||||
size_t termIndex = 0;
|
||||
int c;
|
||||
|
||||
if(*target == 0)
|
||||
{
|
||||
return true; // return true if target is a null string
|
||||
}
|
||||
while ((c = timedRead()) > 0)
|
||||
{
|
||||
while((c = timedRead()) > 0) {
|
||||
|
||||
if(c != target[index])
|
||||
{
|
||||
index = 0; // reset index if any char does not match
|
||||
}
|
||||
|
||||
if (c == target[index])
|
||||
{
|
||||
if(c == target[index]) {
|
||||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
|
||||
if (++index >= targetLen) // return true if all chars in the target match
|
||||
{
|
||||
if(++index >= targetLen) { // return true if all chars in the target match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (termLen > 0 && c == terminator[termIndex])
|
||||
{
|
||||
if(termLen > 0 && c == terminator[termIndex]) {
|
||||
if(++termIndex >= termLen)
|
||||
{
|
||||
return false; // return false if terminate string found before target string
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
termIndex = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// function is terminated by the first character that is not a digit.
|
||||
long Stream::parseInt()
|
||||
{
|
||||
long Stream::parseInt() {
|
||||
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
||||
}
|
||||
|
||||
// as above but a given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
long Stream::parseInt(char skipChar)
|
||||
{
|
||||
long Stream::parseInt(char skipChar) {
|
||||
boolean isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
@ -174,43 +139,32 @@ long Stream::parseInt(char skipChar)
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0)
|
||||
{
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
if(c == skipChar)
|
||||
; // ignore this charactor
|
||||
else if(c == '-')
|
||||
{
|
||||
isNegative = true;
|
||||
}
|
||||
else if(c >= '0' && c <= '9') // is c a digit?
|
||||
{
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == skipChar);
|
||||
|
||||
if(isNegative)
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// as parseInt but returns a floating point value
|
||||
float Stream::parseFloat()
|
||||
{
|
||||
float Stream::parseFloat() {
|
||||
return parseFloat(NO_SKIP_CHAR);
|
||||
}
|
||||
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
float Stream::parseFloat(char skipChar)
|
||||
{
|
||||
float Stream::parseFloat(char skipChar) {
|
||||
boolean isNegative = false;
|
||||
boolean isFraction = false;
|
||||
long value = 0;
|
||||
@ -220,63 +174,43 @@ float Stream::parseFloat(char skipChar)
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0)
|
||||
{
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
if(c == skipChar)
|
||||
; // ignore
|
||||
else if(c == '-')
|
||||
{
|
||||
isNegative = true;
|
||||
}
|
||||
else if(c == '.')
|
||||
{
|
||||
isFraction = true;
|
||||
}
|
||||
else if (c >= '0' && c <= '9') // is c a digit?
|
||||
{
|
||||
else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
if(isFraction)
|
||||
{
|
||||
fraction *= 0.1;
|
||||
}
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
||||
|
||||
if(isNegative)
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
if(isFraction)
|
||||
{
|
||||
return value * fraction;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// read characters from stream into buffer
|
||||
// terminates if length characters have been read, or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
//
|
||||
size_t Stream::readBytes(char *buffer, size_t length)
|
||||
{
|
||||
size_t Stream::readBytes(char *buffer, size_t length) {
|
||||
size_t count = 0;
|
||||
while (count < length)
|
||||
{
|
||||
while(count < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
count++;
|
||||
}
|
||||
@ -287,44 +221,34 @@ size_t Stream::readBytes(char *buffer, size_t length)
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
|
||||
{
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) {
|
||||
if(length < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
size_t index = 0;
|
||||
while (index < length)
|
||||
{
|
||||
while(index < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0 || c == terminator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
}
|
||||
|
||||
String Stream::readString()
|
||||
{
|
||||
String Stream::readString() {
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0)
|
||||
{
|
||||
while(c >= 0) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String Stream::readStringUntil(char terminator)
|
||||
{
|
||||
String Stream::readStringUntil(char terminator) {
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0 && c != terminator)
|
||||
{
|
||||
while(c >= 0 && c != terminator) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
|
@ -35,8 +35,7 @@
|
||||
readBytesBetween( pre_string, terminator, buffer, length)
|
||||
*/
|
||||
|
||||
class Stream: public Print
|
||||
{
|
||||
class Stream: public Print {
|
||||
protected:
|
||||
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
@ -49,8 +48,7 @@ public:
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
|
||||
Stream()
|
||||
{
|
||||
Stream() {
|
||||
_timeout = 1000;
|
||||
}
|
||||
|
||||
@ -59,33 +57,26 @@ public:
|
||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target)
|
||||
{
|
||||
bool find(uint8_t *target) {
|
||||
return find((char *) target);
|
||||
}
|
||||
// returns true if target string is found, false if timed out (see setTimeout)
|
||||
|
||||
bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found
|
||||
bool find(const uint8_t *target, size_t length)
|
||||
{
|
||||
bool find(const uint8_t *target, size_t length) {
|
||||
return find((char *) target, length);
|
||||
}
|
||||
// returns true if target string is found, false if timed out
|
||||
|
||||
bool find(char target)
|
||||
{
|
||||
return find(&target, 1);
|
||||
}
|
||||
bool find(char target) { return find (&target, 1); }
|
||||
|
||||
bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found
|
||||
bool findUntil(const uint8_t *target, const char *terminator)
|
||||
{
|
||||
bool findUntil(const uint8_t *target, const char *terminator) {
|
||||
return findUntil((char *) target, terminator);
|
||||
}
|
||||
|
||||
bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found
|
||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen)
|
||||
{
|
||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) {
|
||||
return findUntil((char *) target, targetLen, terminate, termLen);
|
||||
}
|
||||
|
||||
@ -96,16 +87,14 @@ public:
|
||||
float parseFloat(); // float version of parseInt
|
||||
|
||||
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length)
|
||||
{
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length) {
|
||||
return readBytes((char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character
|
||||
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length)
|
||||
{
|
||||
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) {
|
||||
return readBytesUntil(terminator, (char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
|
@ -23,13 +23,10 @@
|
||||
#include <Arduino.h>
|
||||
#include "StreamString.h"
|
||||
|
||||
size_t StreamString::write(const uint8_t *data, size_t size)
|
||||
{
|
||||
if (size && data)
|
||||
{
|
||||
size_t StreamString::write(const uint8_t *data, size_t size) {
|
||||
if(size && data) {
|
||||
const unsigned int newlen = length() + size;
|
||||
if (reserve(newlen + 1))
|
||||
{
|
||||
if(reserve(newlen + 1)) {
|
||||
memcpy((void *) (wbuffer() + len()), (const void *) data, size);
|
||||
setLen(newlen);
|
||||
*(wbuffer() + newlen) = 0x00; // add null for string end
|
||||
@ -39,20 +36,16 @@ size_t StreamString::write(const uint8_t *data, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t StreamString::write(uint8_t data)
|
||||
{
|
||||
size_t StreamString::write(uint8_t data) {
|
||||
return concat((char) data);
|
||||
}
|
||||
|
||||
int StreamString::available()
|
||||
{
|
||||
int StreamString::available() {
|
||||
return length();
|
||||
}
|
||||
|
||||
int StreamString::read()
|
||||
{
|
||||
if (length())
|
||||
{
|
||||
int StreamString::read() {
|
||||
if(length()) {
|
||||
char c = charAt(0);
|
||||
remove(0, 1);
|
||||
return c;
|
||||
@ -61,17 +54,14 @@ int StreamString::read()
|
||||
return -1;
|
||||
}
|
||||
|
||||
int StreamString::peek()
|
||||
{
|
||||
if (length())
|
||||
{
|
||||
int StreamString::peek() {
|
||||
if(length()) {
|
||||
char c = charAt(0);
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void StreamString::flush()
|
||||
{
|
||||
void StreamString::flush() {
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@
|
||||
#define STREAMSTRING_H_
|
||||
|
||||
|
||||
class StreamString: public Stream, public String
|
||||
{
|
||||
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;
|
||||
|
@ -28,10 +28,8 @@
|
||||
static uint32_t _toneMap = 0;
|
||||
|
||||
|
||||
static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long duration)
|
||||
{
|
||||
if (_pin > 16)
|
||||
{
|
||||
static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long duration) {
|
||||
if (_pin > 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -40,21 +38,16 @@ static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long
|
||||
high = std::max(high, (uint32_t)100);
|
||||
low = std::max(low, (uint32_t)100);
|
||||
|
||||
if (startWaveform(_pin, high, low, (uint32_t) duration * 1000))
|
||||
{
|
||||
if (startWaveform(_pin, high, low, (uint32_t) duration * 1000)) {
|
||||
_toneMap |= 1 << _pin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
if (frequency == 0)
|
||||
{
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
|
||||
if (frequency == 0) {
|
||||
noTone(_pin);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint32_t period = 1000000L / frequency;
|
||||
uint32_t high = period / 2;
|
||||
uint32_t low = period - high;
|
||||
@ -65,14 +58,10 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
|
||||
|
||||
// Separate tone(float) to hopefully not pull in floating point libs unless
|
||||
// it's called with a float.
|
||||
void tone(uint8_t _pin, double frequency, unsigned long duration)
|
||||
{
|
||||
if (frequency < 1.0) // FP means no exact comparisons
|
||||
{
|
||||
void tone(uint8_t _pin, double frequency, unsigned long duration) {
|
||||
if (frequency < 1.0) { // FP means no exact comparisons
|
||||
noTone(_pin);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
double period = 1000000.0 / frequency;
|
||||
uint32_t high = (uint32_t)((period / 2.0) + 0.5);
|
||||
uint32_t low = (uint32_t)(period + 0.5) - high;
|
||||
@ -82,17 +71,14 @@ void tone(uint8_t _pin, double frequency, unsigned long duration)
|
||||
|
||||
|
||||
// Fix ambiguous tone() binding when adding in a duration
|
||||
void tone(uint8_t _pin, int frequency, unsigned long duration)
|
||||
{
|
||||
void tone(uint8_t _pin, int frequency, unsigned long duration) {
|
||||
// Call the unsigned int version of the function explicitly
|
||||
tone(_pin, (unsigned int)frequency, duration);
|
||||
}
|
||||
|
||||
|
||||
void noTone(uint8_t _pin)
|
||||
{
|
||||
if (_pin > 16)
|
||||
{
|
||||
void noTone(uint8_t _pin) {
|
||||
if (_pin > 16) {
|
||||
return;
|
||||
}
|
||||
stopWaveform(_pin);
|
||||
|
@ -1,35 +1,35 @@
|
||||
/*
|
||||
Udp.cpp: Library to send/receive UDP packets.
|
||||
|
||||
NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
might not happen often in practice, but in larger network topologies, a UDP
|
||||
packet can be received out of sequence.
|
||||
2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
|
||||
MIT License:
|
||||
Copyright (c) 2008 Bjoern Hartmann
|
||||
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.
|
||||
|
||||
bjoern@cs.stanford.edu 12/30/2008
|
||||
* Udp.cpp: Library to send/receive UDP packets.
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* 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.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#ifndef udp_h
|
||||
@ -38,8 +38,7 @@
|
||||
#include <Stream.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
class UDP: public Stream
|
||||
{
|
||||
class UDP: public Stream {
|
||||
|
||||
public:
|
||||
virtual ~UDP() {};
|
||||
@ -84,13 +83,11 @@ public:
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
virtual uint16_t remotePort() =0;
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr)
|
||||
{
|
||||
uint8_t* rawIPAddress(IPAddress& addr) {
|
||||
return addr.raw_address();
|
||||
}
|
||||
#if LWIP_VERSION_MAJOR != 1
|
||||
const uint8_t* rawIPAddress(const IPAddress& addr)
|
||||
{
|
||||
const uint8_t* rawIPAddress(const IPAddress& addr) {
|
||||
return addr.raw_address();
|
||||
}
|
||||
#endif
|
||||
|
@ -44,18 +44,14 @@ UpdaterClass::UpdaterClass()
|
||||
#endif
|
||||
}
|
||||
|
||||
UpdaterClass& UpdaterClass::onProgress(THandlerFunction_Progress fn)
|
||||
{
|
||||
UpdaterClass& UpdaterClass::onProgress(THandlerFunction_Progress fn) {
|
||||
_progress_callback = fn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdaterClass::_reset()
|
||||
{
|
||||
void UpdaterClass::_reset() {
|
||||
if (_buffer)
|
||||
{
|
||||
delete[] _buffer;
|
||||
}
|
||||
_buffer = 0;
|
||||
_bufferLen = 0;
|
||||
_startAddress = 0;
|
||||
@ -63,16 +59,13 @@ void UpdaterClass::_reset()
|
||||
_size = 0;
|
||||
_command = U_FLASH;
|
||||
|
||||
if (_ledPin != -1)
|
||||
{
|
||||
if(_ledPin != -1) {
|
||||
digitalWrite(_ledPin, !_ledOn); // off
|
||||
}
|
||||
}
|
||||
|
||||
bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
|
||||
{
|
||||
if (_size > 0)
|
||||
{
|
||||
bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
|
||||
if(_size > 0){
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.println(F("[begin] already running"));
|
||||
#endif
|
||||
@ -88,27 +81,23 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
|
||||
https://github.com/esp8266/Arduino/issues/1017#issuecomment-200605576
|
||||
*/
|
||||
int boot_mode = (GPI >> 16) & 0xf;
|
||||
if (boot_mode == 1)
|
||||
{
|
||||
if (boot_mode == 1) {
|
||||
_setError(UPDATE_ERROR_BOOTSTRAP);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UPDATER
|
||||
if (command == U_SPIFFS)
|
||||
{
|
||||
if (command == U_SPIFFS) {
|
||||
DEBUG_UPDATER.println(F("[begin] Update SPIFFS."));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
if(size == 0) {
|
||||
_setError(UPDATE_ERROR_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ESP.checkFlashConfig(false))
|
||||
{
|
||||
if(!ESP.checkFlashConfig(false)) {
|
||||
_setError(UPDATE_ERROR_FLASH_CONFIG);
|
||||
return false;
|
||||
}
|
||||
@ -119,8 +108,7 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
|
||||
wifi_set_sleep_type(NONE_SLEEP_T);
|
||||
|
||||
uintptr_t updateStartAddress = 0;
|
||||
if (command == U_FLASH)
|
||||
{
|
||||
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
|
||||
@ -137,18 +125,15 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
|
||||
#endif
|
||||
|
||||
//make sure that the size of both sketches is less than the total space (updateEndAddress)
|
||||
if (updateStartAddress < currentSketchSize)
|
||||
{
|
||||
if(updateStartAddress < currentSketchSize) {
|
||||
_setError(UPDATE_ERROR_SPACE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (command == U_SPIFFS)
|
||||
{
|
||||
else if (command == U_SPIFFS) {
|
||||
updateStartAddress = (uintptr_t)&_SPIFFS_start - 0x40200000;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// unknown command
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.println(F("[begin] Unknown update command."));
|
||||
@ -160,12 +145,9 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
|
||||
_startAddress = updateStartAddress;
|
||||
_currentAddress = _startAddress;
|
||||
_size = size;
|
||||
if (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE)
|
||||
{
|
||||
if (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE) {
|
||||
_bufferSize = FLASH_SECTOR_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_bufferSize = 256;
|
||||
}
|
||||
_buffer = new uint8_t[_bufferSize];
|
||||
@ -177,15 +159,13 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
|
||||
DEBUG_UPDATER.printf_P(PSTR("[begin] _size: 0x%08zX (%zd)\n"), _size, _size);
|
||||
#endif
|
||||
|
||||
if (!_verify)
|
||||
{
|
||||
if (!_verify) {
|
||||
_md5.begin();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdaterClass::setMD5(const char * expected_md5)
|
||||
{
|
||||
bool UpdaterClass::setMD5(const char * expected_md5){
|
||||
if(strlen(expected_md5) != 32)
|
||||
{
|
||||
return false;
|
||||
@ -194,18 +174,15 @@ bool UpdaterClass::setMD5(const char * expected_md5)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdaterClass::end(bool evenIfRemaining)
|
||||
{
|
||||
if (_size == 0)
|
||||
{
|
||||
bool UpdaterClass::end(bool evenIfRemaining){
|
||||
if(_size == 0){
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.println(F("no update"));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasError() || (!isFinished() && !evenIfRemaining))
|
||||
{
|
||||
if(hasError() || (!isFinished() && !evenIfRemaining)){
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.printf_P(PSTR("premature end: res:%u, pos:%zu/%zu\n"), getError(), progress(), _size);
|
||||
#endif
|
||||
@ -214,24 +191,20 @@ bool UpdaterClass::end(bool evenIfRemaining)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (evenIfRemaining)
|
||||
{
|
||||
if (_bufferLen > 0)
|
||||
{
|
||||
if(evenIfRemaining) {
|
||||
if(_bufferLen > 0) {
|
||||
_writeBuffer();
|
||||
}
|
||||
_size = progress();
|
||||
}
|
||||
|
||||
uint32_t sigLen = 0;
|
||||
if (_verify)
|
||||
{
|
||||
if (_verify) {
|
||||
ESP.flashRead(_startAddress + _size - sizeof(uint32_t), &sigLen, sizeof(uint32_t));
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.printf_P(PSTR("[Updater] sigLen: %d\n"), sigLen);
|
||||
#endif
|
||||
if (sigLen != _verify->length())
|
||||
{
|
||||
if (sigLen != _verify->length()) {
|
||||
_setError(UPDATE_ERROR_SIGN);
|
||||
_reset();
|
||||
return false;
|
||||
@ -244,8 +217,7 @@ bool UpdaterClass::end(bool evenIfRemaining)
|
||||
#endif
|
||||
// Calculate the MD5 and hash using proper size
|
||||
uint8_t buff[128];
|
||||
for (int i = 0; i < binSize; i += sizeof(buff))
|
||||
{
|
||||
for(int i = 0; i < binSize; i += sizeof(buff)) {
|
||||
ESP.flashRead(_startAddress + i, (uint32_t *)buff, sizeof(buff));
|
||||
size_t read = std::min((int)sizeof(buff), binSize - i);
|
||||
_hash->add(buff, read);
|
||||
@ -254,15 +226,11 @@ bool UpdaterClass::end(bool evenIfRemaining)
|
||||
#ifdef DEBUG_UPDATER
|
||||
unsigned char *ret = (unsigned char *)_hash->hash();
|
||||
DEBUG_UPDATER.printf_P(PSTR("[Updater] Computed Hash:"));
|
||||
for (int i = 0; i < _hash->len(); i++)
|
||||
{
|
||||
DEBUG_UPDATER.printf(" %02x", ret[i]);
|
||||
}
|
||||
for (int i=0; i<_hash->len(); i++) DEBUG_UPDATER.printf(" %02x", ret[i]);
|
||||
DEBUG_UPDATER.printf("\n");
|
||||
#endif
|
||||
uint8_t *sig = (uint8_t*)malloc(sigLen);
|
||||
if (!sig)
|
||||
{
|
||||
if (!sig) {
|
||||
_setError(UPDATE_ERROR_SIGN);
|
||||
_reset();
|
||||
return false;
|
||||
@ -270,14 +238,12 @@ bool UpdaterClass::end(bool evenIfRemaining)
|
||||
ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen);
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.printf_P(PSTR("[Updater] Received Signature:"));
|
||||
for (size_t i = 0; i < sigLen; i++)
|
||||
{
|
||||
for (size_t i=0; i<sigLen; i++) {
|
||||
DEBUG_UPDATER.printf(" %02x", sig[i]);
|
||||
}
|
||||
DEBUG_UPDATER.printf("\n");
|
||||
#endif
|
||||
if (!_verify->verify(_hash, (void *)sig, sigLen))
|
||||
{
|
||||
if (!_verify->verify(_hash, (void *)sig, sigLen)) {
|
||||
_setError(UPDATE_ERROR_SIGN);
|
||||
_reset();
|
||||
return false;
|
||||
@ -285,32 +251,24 @@ bool UpdaterClass::end(bool evenIfRemaining)
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.printf_P(PSTR("[Updater] Signature matches\n"));
|
||||
#endif
|
||||
}
|
||||
else if (_target_md5.length())
|
||||
{
|
||||
} else if (_target_md5.length()) {
|
||||
_md5.calculate();
|
||||
if (strcasecmp(_target_md5.c_str(), _md5.toString().c_str()))
|
||||
{
|
||||
if (strcasecmp(_target_md5.c_str(), _md5.toString().c_str())) {
|
||||
_setError(UPDATE_ERROR_MD5);
|
||||
_reset();
|
||||
return false;
|
||||
}
|
||||
#ifdef DEBUG_UPDATER
|
||||
else
|
||||
{
|
||||
DEBUG_UPDATER.printf_P(PSTR("MD5 Success: %s\n"), _target_md5.c_str());
|
||||
}
|
||||
else DEBUG_UPDATER.printf_P(PSTR("MD5 Success: %s\n"), _target_md5.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!_verifyEnd())
|
||||
{
|
||||
if(!_verifyEnd()) {
|
||||
_reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_command == U_FLASH)
|
||||
{
|
||||
if (_command == U_FLASH) {
|
||||
eboot_command ebcmd;
|
||||
ebcmd.action = ACTION_COPY_RAW;
|
||||
ebcmd.args[0] = _startAddress;
|
||||
@ -321,8 +279,7 @@ bool UpdaterClass::end(bool evenIfRemaining)
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.printf_P(PSTR("Staged: address:0x%08X, size:0x%08zX\n"), _startAddress, _size);
|
||||
}
|
||||
else if (_command == U_SPIFFS)
|
||||
{
|
||||
else if (_command == U_SPIFFS) {
|
||||
DEBUG_UPDATER.printf_P(PSTR("SPIFFS: address:0x%08X, size:0x%08zX\n"), _startAddress, _size);
|
||||
#endif
|
||||
}
|
||||
@ -331,18 +288,13 @@ bool UpdaterClass::end(bool evenIfRemaining)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdaterClass::_writeBuffer()
|
||||
{
|
||||
bool UpdaterClass::_writeBuffer(){
|
||||
#define FLASH_MODE_PAGE 0
|
||||
#define FLASH_MODE_OFFSET 2
|
||||
|
||||
bool eraseResult = true, writeResult = true;
|
||||
if (_currentAddress % FLASH_SECTOR_SIZE == 0)
|
||||
{
|
||||
if (!_async)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
if (_currentAddress % FLASH_SECTOR_SIZE == 0) {
|
||||
if(!_async) yield();
|
||||
eraseResult = ESP.flashEraseSector(_currentAddress/FLASH_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
@ -352,15 +304,13 @@ bool UpdaterClass::_writeBuffer()
|
||||
bool modifyFlashMode = false;
|
||||
FlashMode_t flashMode = FM_QIO;
|
||||
FlashMode_t bufferFlashMode = FM_QIO;
|
||||
if (_currentAddress == _startAddress + FLASH_MODE_PAGE)
|
||||
{
|
||||
if (_currentAddress == _startAddress + FLASH_MODE_PAGE) {
|
||||
flashMode = ESP.getFlashChipMode();
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.printf_P(PSTR("Header: 0x%1X %1X %1X %1X\n"), _buffer[0], _buffer[1], _buffer[2], _buffer[3]);
|
||||
#endif
|
||||
bufferFlashMode = ESP.magicFlashChipMode(_buffer[FLASH_MODE_OFFSET]);
|
||||
if (bufferFlashMode != flashMode)
|
||||
{
|
||||
if (bufferFlashMode != flashMode) {
|
||||
#ifdef DEBUG_UPDATER
|
||||
DEBUG_UPDATER.printf_P(PSTR("Set flash mode from 0x%1X to 0x%1X\n"), bufferFlashMode, flashMode);
|
||||
#endif
|
||||
@ -370,16 +320,10 @@ bool UpdaterClass::_writeBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
if (eraseResult)
|
||||
{
|
||||
if (!_async)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
if (eraseResult) {
|
||||
if(!_async) yield();
|
||||
writeResult = ESP.flashWrite(_currentAddress, (uint32_t*) _buffer, _bufferLen);
|
||||
}
|
||||
else // if erase was unsuccessful
|
||||
{
|
||||
} else { // if erase was unsuccessful
|
||||
_currentAddress = (_startAddress + _size);
|
||||
_setError(UPDATE_ERROR_ERASE);
|
||||
return false;
|
||||
@ -387,19 +331,16 @@ bool UpdaterClass::_writeBuffer()
|
||||
|
||||
// Restore the old flash mode, if we modified it.
|
||||
// Ensures that the MD5 hash will still match what was sent.
|
||||
if (modifyFlashMode)
|
||||
{
|
||||
if (modifyFlashMode) {
|
||||
_buffer[FLASH_MODE_OFFSET] = bufferFlashMode;
|
||||
}
|
||||
|
||||
if (!writeResult)
|
||||
{
|
||||
if (!writeResult) {
|
||||
_currentAddress = (_startAddress + _size);
|
||||
_setError(UPDATE_ERROR_WRITE);
|
||||
return false;
|
||||
}
|
||||
if (!_verify)
|
||||
{
|
||||
if (!_verify) {
|
||||
_md5.add(_buffer, _bufferLen);
|
||||
}
|
||||
_currentAddress += _bufferLen;
|
||||
@ -407,15 +348,11 @@ bool UpdaterClass::_writeBuffer()
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t UpdaterClass::write(uint8_t *data, size_t len)
|
||||
{
|
||||
size_t UpdaterClass::write(uint8_t *data, size_t len) {
|
||||
if(hasError() || !isRunning())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > remaining())
|
||||
{
|
||||
if(len > remaining()){
|
||||
//len = remaining();
|
||||
//fail instead
|
||||
_setError(UPDATE_ERROR_SPACE);
|
||||
@ -424,72 +361,56 @@ size_t UpdaterClass::write(uint8_t *data, size_t len)
|
||||
|
||||
size_t left = len;
|
||||
|
||||
while ((_bufferLen + left) > _bufferSize)
|
||||
{
|
||||
while((_bufferLen + left) > _bufferSize) {
|
||||
size_t toBuff = _bufferSize - _bufferLen;
|
||||
memcpy(_buffer + _bufferLen, data + (len - left), toBuff);
|
||||
_bufferLen += toBuff;
|
||||
if (!_writeBuffer())
|
||||
{
|
||||
if(!_writeBuffer()){
|
||||
return len - left;
|
||||
}
|
||||
left -= toBuff;
|
||||
if (!_async)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
if(!_async) yield();
|
||||
}
|
||||
//lets see whats left
|
||||
memcpy(_buffer + _bufferLen, data + (len - left), left);
|
||||
_bufferLen += left;
|
||||
if (_bufferLen == remaining())
|
||||
{
|
||||
if(_bufferLen == remaining()){
|
||||
//we are at the end of the update, so should write what's left to flash
|
||||
if (!_writeBuffer())
|
||||
{
|
||||
if(!_writeBuffer()){
|
||||
return len - left;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool UpdaterClass::_verifyHeader(uint8_t data)
|
||||
{
|
||||
if (_command == U_FLASH)
|
||||
{
|
||||
bool UpdaterClass::_verifyHeader(uint8_t data) {
|
||||
if(_command == U_FLASH) {
|
||||
// check for valid first magic byte (is always 0xE9)
|
||||
if (data != 0xE9)
|
||||
{
|
||||
if(data != 0xE9) {
|
||||
_currentAddress = (_startAddress + _size);
|
||||
_setError(UPDATE_ERROR_MAGIC_BYTE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (_command == U_SPIFFS)
|
||||
{
|
||||
} else if(_command == U_SPIFFS) {
|
||||
// no check of SPIFFS possible with first byte.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UpdaterClass::_verifyEnd()
|
||||
{
|
||||
if (_command == U_FLASH)
|
||||
{
|
||||
bool UpdaterClass::_verifyEnd() {
|
||||
if(_command == U_FLASH) {
|
||||
|
||||
uint8_t buf[4];
|
||||
if (!ESP.flashRead(_startAddress, (uint32_t *) &buf[0], 4))
|
||||
{
|
||||
if(!ESP.flashRead(_startAddress, (uint32_t *) &buf[0], 4)) {
|
||||
_currentAddress = (_startAddress);
|
||||
_setError(UPDATE_ERROR_READ);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for valid first magic byte
|
||||
if (buf[0] != 0xE9)
|
||||
{
|
||||
if(buf[0] != 0xE9) {
|
||||
_currentAddress = (_startAddress);
|
||||
_setError(UPDATE_ERROR_MAGIC_BYTE);
|
||||
return false;
|
||||
@ -498,161 +419,113 @@ bool UpdaterClass::_verifyEnd()
|
||||
uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
|
||||
|
||||
// check if new bin fits to SPI flash
|
||||
if (bin_flash_size > ESP.getFlashChipRealSize())
|
||||
{
|
||||
if(bin_flash_size > ESP.getFlashChipRealSize()) {
|
||||
_currentAddress = (_startAddress);
|
||||
_setError(UPDATE_ERROR_NEW_FLASH_CONFIG);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (_command == U_SPIFFS)
|
||||
{
|
||||
} else if(_command == U_SPIFFS) {
|
||||
// SPIFFS is already over written checks make no sense any more.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t UpdaterClass::writeStream(Stream &data)
|
||||
{
|
||||
size_t UpdaterClass::writeStream(Stream &data) {
|
||||
size_t written = 0;
|
||||
size_t toRead = 0;
|
||||
if(hasError() || !isRunning())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_verifyHeader(data.peek()))
|
||||
{
|
||||
if(!_verifyHeader(data.peek())) {
|
||||
#ifdef DEBUG_UPDATER
|
||||
printError(DEBUG_UPDATER);
|
||||
#endif
|
||||
_reset();
|
||||
return 0;
|
||||
}
|
||||
if (_progress_callback)
|
||||
{
|
||||
if (_progress_callback) {
|
||||
_progress_callback(0, _size);
|
||||
}
|
||||
if (_ledPin != -1)
|
||||
{
|
||||
if(_ledPin != -1) {
|
||||
pinMode(_ledPin, OUTPUT);
|
||||
}
|
||||
|
||||
while (remaining())
|
||||
{
|
||||
if (_ledPin != -1)
|
||||
{
|
||||
while(remaining()) {
|
||||
if(_ledPin != -1) {
|
||||
digitalWrite(_ledPin, _ledOn); // Switch LED on
|
||||
}
|
||||
size_t bytesToRead = _bufferSize - _bufferLen;
|
||||
if (bytesToRead > remaining())
|
||||
{
|
||||
if(bytesToRead > remaining()) {
|
||||
bytesToRead = remaining();
|
||||
}
|
||||
toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
|
||||
if (toRead == 0) //Timeout
|
||||
{
|
||||
if(toRead == 0) { //Timeout
|
||||
delay(100);
|
||||
toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
|
||||
if (toRead == 0) //Timeout
|
||||
{
|
||||
if(toRead == 0) { //Timeout
|
||||
_currentAddress = (_startAddress + _size);
|
||||
_setError(UPDATE_ERROR_STREAM);
|
||||
_reset();
|
||||
return written;
|
||||
}
|
||||
}
|
||||
if (_ledPin != -1)
|
||||
{
|
||||
if(_ledPin != -1) {
|
||||
digitalWrite(_ledPin, !_ledOn); // Switch LED off
|
||||
}
|
||||
_bufferLen += toRead;
|
||||
if((_bufferLen == remaining() || _bufferLen == _bufferSize) && !_writeBuffer())
|
||||
{
|
||||
return written;
|
||||
}
|
||||
written += toRead;
|
||||
if (_progress_callback)
|
||||
{
|
||||
if(_progress_callback) {
|
||||
_progress_callback(progress(), _size);
|
||||
}
|
||||
yield();
|
||||
}
|
||||
if (_progress_callback)
|
||||
{
|
||||
if(_progress_callback) {
|
||||
_progress_callback(progress(), _size);
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
void UpdaterClass::_setError(int error)
|
||||
{
|
||||
void UpdaterClass::_setError(int error){
|
||||
_error = error;
|
||||
#ifdef DEBUG_UPDATER
|
||||
printError(DEBUG_UPDATER);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpdaterClass::printError(Print &out)
|
||||
{
|
||||
void UpdaterClass::printError(Print &out){
|
||||
out.printf_P(PSTR("ERROR[%u]: "), _error);
|
||||
if (_error == UPDATE_ERROR_OK)
|
||||
{
|
||||
if(_error == UPDATE_ERROR_OK){
|
||||
out.println(F("No Error"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_WRITE)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_WRITE){
|
||||
out.println(F("Flash Write Failed"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_ERASE)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_ERASE){
|
||||
out.println(F("Flash Erase Failed"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_READ)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_READ){
|
||||
out.println(F("Flash Read Failed"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_SPACE)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_SPACE){
|
||||
out.println(F("Not Enough Space"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_SIZE)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_SIZE){
|
||||
out.println(F("Bad Size Given"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_STREAM)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_STREAM){
|
||||
out.println(F("Stream Read Timeout"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_MD5)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_MD5){
|
||||
out.printf_P(PSTR("MD5 Failed: expected:%s, calculated:%s\n"), _target_md5.c_str(), _md5.toString().c_str());
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_SIGN)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_SIGN){
|
||||
out.println(F("Signature verification failed"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_FLASH_CONFIG)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_FLASH_CONFIG){
|
||||
out.printf_P(PSTR("Flash config wrong real: %d IDE: %d\n"), ESP.getFlashChipRealSize(), ESP.getFlashChipSize());
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_NEW_FLASH_CONFIG)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_NEW_FLASH_CONFIG){
|
||||
out.printf_P(PSTR("new Flash config wrong real: %d\n"), ESP.getFlashChipRealSize());
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_MAGIC_BYTE)
|
||||
{
|
||||
} else if(_error == UPDATE_ERROR_MAGIC_BYTE){
|
||||
out.println(F("Magic byte is wrong, not 0xE9"));
|
||||
}
|
||||
else if (_error == UPDATE_ERROR_BOOTSTRAP)
|
||||
{
|
||||
} else if (_error == UPDATE_ERROR_BOOTSTRAP){
|
||||
out.println(F("Invalid bootstrapping state, reset ESP8266 before updating"));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
out.println(F("UNKNOWN"));
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,7 @@
|
||||
#endif
|
||||
|
||||
// Abstract class to implement whatever signing hash desired
|
||||
class UpdaterHashClass
|
||||
{
|
||||
class UpdaterHashClass {
|
||||
public:
|
||||
virtual void begin() = 0;
|
||||
virtual void add(const void *data, uint32_t len) = 0;
|
||||
@ -42,26 +41,20 @@ public:
|
||||
};
|
||||
|
||||
// Abstract class to implement a signature verifier
|
||||
class UpdaterVerifyClass
|
||||
{
|
||||
class UpdaterVerifyClass {
|
||||
public:
|
||||
virtual uint32_t length() = 0; // How many bytes of signature are expected
|
||||
virtual bool verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) = 0; // Verify, return "true" on success
|
||||
};
|
||||
|
||||
class UpdaterClass
|
||||
{
|
||||
class UpdaterClass {
|
||||
public:
|
||||
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
|
||||
|
||||
UpdaterClass();
|
||||
|
||||
/* Optionally add a cryptographic signature verification hash and method */
|
||||
void installSignature(UpdaterHashClass *hash, UpdaterVerifyClass *verify)
|
||||
{
|
||||
_hash = hash;
|
||||
_verify = verify;
|
||||
}
|
||||
void installSignature(UpdaterHashClass *hash, UpdaterVerifyClass *verify) { _hash = hash; _verify = verify; }
|
||||
|
||||
/*
|
||||
Call this to check the space needed for the update
|
||||
@ -72,10 +65,7 @@ public:
|
||||
/*
|
||||
Run Updater from asynchronous callbacs
|
||||
*/
|
||||
void runAsync(bool async)
|
||||
{
|
||||
_async = async;
|
||||
}
|
||||
void runAsync(bool async){ _async = async; }
|
||||
|
||||
/*
|
||||
Writes a buffer to the flash and increments the address
|
||||
@ -117,18 +107,12 @@ public:
|
||||
/*
|
||||
returns the MD5 String of the sucessfully ended firmware
|
||||
*/
|
||||
String md5String(void)
|
||||
{
|
||||
return _md5.toString();
|
||||
}
|
||||
String md5String(void){ return _md5.toString(); }
|
||||
|
||||
/*
|
||||
populated the result with the md5 bytes of the sucessfully ended firmware
|
||||
*/
|
||||
void md5(uint8_t * result)
|
||||
{
|
||||
return _md5.getBytes(result);
|
||||
}
|
||||
void md5(uint8_t * result){ return _md5.getBytes(result); }
|
||||
|
||||
/*
|
||||
This callback will be called when Updater is receiving data
|
||||
@ -136,38 +120,14 @@ public:
|
||||
UpdaterClass& onProgress(THandlerFunction_Progress fn);
|
||||
|
||||
//Helpers
|
||||
uint8_t getError()
|
||||
{
|
||||
return _error;
|
||||
}
|
||||
void clearError()
|
||||
{
|
||||
_error = UPDATE_ERROR_OK;
|
||||
}
|
||||
bool hasError()
|
||||
{
|
||||
return _error != UPDATE_ERROR_OK;
|
||||
}
|
||||
bool isRunning()
|
||||
{
|
||||
return _size > 0;
|
||||
}
|
||||
bool isFinished()
|
||||
{
|
||||
return _currentAddress == (_startAddress + _size);
|
||||
}
|
||||
size_t size()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
size_t progress()
|
||||
{
|
||||
return _currentAddress - _startAddress;
|
||||
}
|
||||
size_t remaining()
|
||||
{
|
||||
return _size - (_currentAddress - _startAddress);
|
||||
}
|
||||
uint8_t getError(){ return _error; }
|
||||
void clearError(){ _error = UPDATE_ERROR_OK; }
|
||||
bool hasError(){ return _error != UPDATE_ERROR_OK; }
|
||||
bool isRunning(){ return _size > 0; }
|
||||
bool isFinished(){ return _currentAddress == (_startAddress + _size); }
|
||||
size_t size(){ return _size; }
|
||||
size_t progress(){ return _currentAddress - _startAddress; }
|
||||
size_t remaining(){ return _size - (_currentAddress - _startAddress); }
|
||||
|
||||
/*
|
||||
Template to write from objects that expose
|
||||
@ -176,49 +136,35 @@ public:
|
||||
writes only what is available
|
||||
*/
|
||||
template<typename T>
|
||||
size_t write(T &data)
|
||||
{
|
||||
size_t write(T &data){
|
||||
size_t written = 0;
|
||||
if (hasError() || !isRunning())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t available = data.available();
|
||||
while (available)
|
||||
{
|
||||
if (_bufferLen + available > remaining())
|
||||
{
|
||||
while(available) {
|
||||
if(_bufferLen + available > remaining()){
|
||||
available = remaining() - _bufferLen;
|
||||
}
|
||||
if (_bufferLen + available > _bufferSize)
|
||||
{
|
||||
if(_bufferLen + available > _bufferSize) {
|
||||
size_t toBuff = _bufferSize - _bufferLen;
|
||||
data.read(_buffer + _bufferLen, toBuff);
|
||||
_bufferLen += toBuff;
|
||||
if(!_writeBuffer())
|
||||
{
|
||||
return written;
|
||||
}
|
||||
written += toBuff;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
data.read(_buffer + _bufferLen, available);
|
||||
_bufferLen += available;
|
||||
written += available;
|
||||
if (_bufferLen == remaining())
|
||||
{
|
||||
if (!_writeBuffer())
|
||||
{
|
||||
if(_bufferLen == remaining()) {
|
||||
if(!_writeBuffer()) {
|
||||
return written;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(remaining() == 0)
|
||||
{
|
||||
return written;
|
||||
}
|
||||
delay(1);
|
||||
available = data.available();
|
||||
}
|
||||
|
@ -46,93 +46,79 @@ inline int toUpperCase(int c) __attribute__((always_inline));
|
||||
|
||||
// Checks for an alphanumeric character.
|
||||
// It is equivalent to (isalpha(c) || isdigit(c)).
|
||||
inline boolean isAlphaNumeric(int c)
|
||||
{
|
||||
inline boolean isAlphaNumeric(int c) {
|
||||
return (isalnum(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for an alphabetic character.
|
||||
// It is equivalent to (isupper(c) || islower(c)).
|
||||
inline boolean isAlpha(int c)
|
||||
{
|
||||
inline boolean isAlpha(int c) {
|
||||
return (isalpha(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks whether c is a 7-bit unsigned char value
|
||||
// that fits into the ASCII character set.
|
||||
inline boolean isAscii(int c)
|
||||
{
|
||||
inline boolean isAscii(int c) {
|
||||
return ( isascii (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for a blank character, that is, a space or a tab.
|
||||
inline boolean isWhitespace(int c)
|
||||
{
|
||||
inline boolean isWhitespace(int c) {
|
||||
return (isblank(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for a control character.
|
||||
inline boolean isControl(int c)
|
||||
{
|
||||
inline boolean isControl(int c) {
|
||||
return (iscntrl(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for a digit (0 through 9).
|
||||
inline boolean isDigit(int c)
|
||||
{
|
||||
inline boolean isDigit(int c) {
|
||||
return (isdigit(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for any printable character except space.
|
||||
inline boolean isGraph(int c)
|
||||
{
|
||||
inline boolean isGraph(int c) {
|
||||
return (isgraph(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for a lower-case character.
|
||||
inline boolean isLowerCase(int c)
|
||||
{
|
||||
inline boolean isLowerCase(int c) {
|
||||
return (islower(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for any printable character including space.
|
||||
inline boolean isPrintable(int c)
|
||||
{
|
||||
inline boolean isPrintable(int c) {
|
||||
return (isprint(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for any printable character which is not a space
|
||||
// or an alphanumeric character.
|
||||
inline boolean isPunct(int c)
|
||||
{
|
||||
inline boolean isPunct(int c) {
|
||||
return (ispunct(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for white-space characters. For the avr-libc library,
|
||||
// these are: space, formfeed ('\f'), newline ('\n'), carriage
|
||||
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
|
||||
inline boolean isSpace(int c)
|
||||
{
|
||||
inline boolean isSpace(int c) {
|
||||
return (isspace(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for an uppercase letter.
|
||||
inline boolean isUpperCase(int c)
|
||||
{
|
||||
inline boolean isUpperCase(int c) {
|
||||
return (isupper(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
|
||||
// 8 9 a b c d e f A B C D E F.
|
||||
inline boolean isHexadecimalDigit(int c)
|
||||
{
|
||||
inline boolean isHexadecimalDigit(int c) {
|
||||
return (isxdigit(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
// Converts c to a 7-bit unsigned char value that fits into the
|
||||
// ASCII character set, by clearing the high-order bits.
|
||||
inline int toAscii(int c)
|
||||
{
|
||||
inline int toAscii(int c) {
|
||||
return toascii(c);
|
||||
}
|
||||
|
||||
@ -142,14 +128,12 @@ inline int toAscii(int c)
|
||||
// characters.
|
||||
|
||||
// Converts the letter c to lower case, if possible.
|
||||
inline int toLowerCase(int c)
|
||||
{
|
||||
inline int toLowerCase(int c) {
|
||||
return tolower(c);
|
||||
}
|
||||
|
||||
// Converts the letter c to upper case, if possible.
|
||||
inline int toUpperCase(int c)
|
||||
{
|
||||
inline int toUpperCase(int c) {
|
||||
return toupper(c);
|
||||
}
|
||||
|
||||
|
@ -30,19 +30,15 @@ extern "C" {
|
||||
|
||||
static bool s_randomSeedCalled = false;
|
||||
|
||||
void randomSeed(unsigned long seed)
|
||||
{
|
||||
if (seed != 0)
|
||||
{
|
||||
void randomSeed(unsigned long seed) {
|
||||
if(seed != 0) {
|
||||
srand(seed);
|
||||
s_randomSeedCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
long random(long howbig)
|
||||
{
|
||||
if (howbig == 0)
|
||||
{
|
||||
long random(long howbig) {
|
||||
if(howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
// if randomSeed was called, fall back to software PRNG
|
||||
@ -50,51 +46,41 @@ long random(long howbig)
|
||||
return val % howbig;
|
||||
}
|
||||
|
||||
long random(long howsmall, long howbig)
|
||||
{
|
||||
if (howsmall >= howbig)
|
||||
{
|
||||
long random(long howsmall, long howbig) {
|
||||
if(howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
long diff = howbig - howsmall;
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
long secureRandom(long howbig)
|
||||
{
|
||||
if (howbig == 0)
|
||||
{
|
||||
long secureRandom(long howbig) {
|
||||
if(howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
return RANDOM_REG32 % howbig;
|
||||
}
|
||||
|
||||
long secureRandom(long howsmall, long howbig)
|
||||
{
|
||||
if (howsmall >= howbig)
|
||||
{
|
||||
long secureRandom(long howsmall, long howbig) {
|
||||
if(howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
long diff = howbig - howsmall;
|
||||
return secureRandom(diff) + howsmall;
|
||||
}
|
||||
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||
long divisor = (in_max - in_min);
|
||||
if (divisor == 0)
|
||||
{
|
||||
if(divisor == 0){
|
||||
return -1; //AVR returns -1, SAM returns 0
|
||||
}
|
||||
return (x - in_min) * (out_max - out_min) / divisor + out_min;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned int w)
|
||||
{
|
||||
unsigned int makeWord(unsigned int w) {
|
||||
return w;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned char h, unsigned char l)
|
||||
{
|
||||
unsigned int makeWord(unsigned char h, unsigned char l) {
|
||||
return (h << 8) | l;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,14 +39,12 @@ class __FlashStringHelper;
|
||||
#define F(string_literal) (FPSTR(PSTR(string_literal)))
|
||||
|
||||
// The string class
|
||||
class String
|
||||
{
|
||||
class String {
|
||||
// use a function pointer to allow for "if (s)" without the
|
||||
// complications of an operator bool(). for more information, see:
|
||||
// http://www.artima.com/cppsource/safebool.html
|
||||
typedef void (String::*StringIfHelperType)() const;
|
||||
void StringIfHelper() const
|
||||
{
|
||||
void StringIfHelper() const {
|
||||
}
|
||||
|
||||
public:
|
||||
@ -77,14 +75,10 @@ public:
|
||||
// is left unchanged). reserve(0), if successful, will validate an
|
||||
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||
unsigned char reserve(unsigned int size);
|
||||
inline unsigned int length(void) const
|
||||
{
|
||||
if (buffer())
|
||||
{
|
||||
inline unsigned int length(void) const {
|
||||
if(buffer()) {
|
||||
return len();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -119,58 +113,47 @@ public:
|
||||
|
||||
// if there's not enough memory for the concatenated value, the string
|
||||
// will be left unchanged (but this isn't signalled in any way)
|
||||
String & operator +=(const String &rhs)
|
||||
{
|
||||
String & operator +=(const String &rhs) {
|
||||
concat(rhs);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(const char *cstr)
|
||||
{
|
||||
String & operator +=(const char *cstr) {
|
||||
concat(cstr);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(char c)
|
||||
{
|
||||
String & operator +=(char c) {
|
||||
concat(c);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned char num)
|
||||
{
|
||||
String & operator +=(unsigned char num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(int num)
|
||||
{
|
||||
String & operator +=(int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned int num)
|
||||
{
|
||||
String & operator +=(unsigned int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(long num)
|
||||
{
|
||||
String & operator +=(long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned long num)
|
||||
{
|
||||
String & operator +=(unsigned long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(float num)
|
||||
{
|
||||
String & operator +=(float num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(double num)
|
||||
{
|
||||
String & operator +=(double num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator += (const __FlashStringHelper *str)
|
||||
{
|
||||
String & operator += (const __FlashStringHelper *str){
|
||||
concat(str);
|
||||
return (*this);
|
||||
}
|
||||
@ -188,27 +171,22 @@ public:
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
operator StringIfHelperType() const
|
||||
{
|
||||
operator StringIfHelperType() const {
|
||||
return buffer() ? &String::StringIfHelper : 0;
|
||||
}
|
||||
int compareTo(const String &s) const;
|
||||
unsigned char equals(const String &s) const;
|
||||
unsigned char equals(const char *cstr) const;
|
||||
unsigned char operator ==(const String &rhs) const
|
||||
{
|
||||
unsigned char operator ==(const String &rhs) const {
|
||||
return equals(rhs);
|
||||
}
|
||||
unsigned char operator ==(const char *cstr) const
|
||||
{
|
||||
unsigned char operator ==(const char *cstr) const {
|
||||
return equals(cstr);
|
||||
}
|
||||
unsigned char operator !=(const String &rhs) const
|
||||
{
|
||||
unsigned char operator !=(const String &rhs) const {
|
||||
return !equals(rhs);
|
||||
}
|
||||
unsigned char operator !=(const char *cstr) const
|
||||
{
|
||||
unsigned char operator !=(const char *cstr) const {
|
||||
return !equals(cstr);
|
||||
}
|
||||
unsigned char operator <(const String &rhs) const;
|
||||
@ -227,30 +205,14 @@ public:
|
||||
char operator [](unsigned int index) const;
|
||||
char& operator [](unsigned int index);
|
||||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const;
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const
|
||||
{
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const {
|
||||
getBytes((unsigned char *) buf, bufsize, index);
|
||||
}
|
||||
const char* c_str() const
|
||||
{
|
||||
return buffer();
|
||||
}
|
||||
char* begin()
|
||||
{
|
||||
return wbuffer();
|
||||
}
|
||||
char* end()
|
||||
{
|
||||
return wbuffer() + length();
|
||||
}
|
||||
const char* begin() const
|
||||
{
|
||||
return c_str();
|
||||
}
|
||||
const char* end() const
|
||||
{
|
||||
return c_str() + length();
|
||||
}
|
||||
const char* c_str() const { return buffer(); }
|
||||
char* begin() { return wbuffer(); }
|
||||
char* end() { return wbuffer() + length(); }
|
||||
const char* begin() const { return c_str(); }
|
||||
const char* end() const { return c_str() + length(); }
|
||||
|
||||
// search
|
||||
int indexOf(char ch) const;
|
||||
@ -261,8 +223,7 @@ public:
|
||||
int lastIndexOf(char ch, unsigned int fromIndex) const;
|
||||
int lastIndexOf(const String &str) const;
|
||||
int lastIndexOf(const String &str, unsigned int fromIndex) const;
|
||||
String substring(unsigned int beginIndex) const
|
||||
{
|
||||
String substring(unsigned int beginIndex) const {
|
||||
return substring(beginIndex, len());
|
||||
}
|
||||
;
|
||||
@ -284,8 +245,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Contains the string info when we're not in SSO mode
|
||||
struct _ptr
|
||||
{
|
||||
struct _ptr {
|
||||
char * buff;
|
||||
uint16_t cap;
|
||||
uint16_t len;
|
||||
@ -296,58 +256,21 @@ protected:
|
||||
// This allows strings up up to 12 (11 + \0 termination) without any extra space.
|
||||
enum { SSOSIZE = sizeof(struct _ptr) + 4 }; // Characters to allocate space for SSO, must be 12 or more
|
||||
enum { CAPACITY_MAX = 65535 }; // If size of capacity changed, be sure to update this enum
|
||||
union
|
||||
{
|
||||
union {
|
||||
struct _ptr ptr;
|
||||
char sso_buf[SSOSIZE];
|
||||
};
|
||||
// Accessor functions
|
||||
inline bool sso() const
|
||||
{
|
||||
return sso_buf[SSOSIZE - 1] == 0;
|
||||
}
|
||||
inline unsigned int len() const
|
||||
{
|
||||
return sso() ? strlen(sso_buf) : ptr.len;
|
||||
}
|
||||
inline unsigned int capacity() const
|
||||
{
|
||||
return sso() ? SSOSIZE - 1 : ptr.cap;
|
||||
}
|
||||
inline void setSSO(bool sso)
|
||||
{
|
||||
sso_buf[SSOSIZE - 1] = sso ? 0x00 : 0xff;
|
||||
}
|
||||
inline void setLen(int len)
|
||||
{
|
||||
if (!sso())
|
||||
{
|
||||
ptr.len = len;
|
||||
}
|
||||
}
|
||||
inline void setCapacity(int cap)
|
||||
{
|
||||
if (!sso())
|
||||
{
|
||||
ptr.cap = cap;
|
||||
}
|
||||
}
|
||||
inline void setBuffer(char *buff)
|
||||
{
|
||||
if (!sso())
|
||||
{
|
||||
ptr.buff = buff;
|
||||
}
|
||||
}
|
||||
inline bool sso() const { return sso_buf[SSOSIZE - 1] == 0; }
|
||||
inline unsigned int len() const { return sso() ? strlen(sso_buf) : ptr.len; }
|
||||
inline unsigned int capacity() const { return sso() ? SSOSIZE - 1 : ptr.cap; }
|
||||
inline void setSSO(bool sso) { sso_buf[SSOSIZE - 1] = sso ? 0x00 : 0xff; }
|
||||
inline void setLen(int len) { if (!sso()) ptr.len = len; }
|
||||
inline void setCapacity(int cap) { if (!sso()) ptr.cap = cap; }
|
||||
inline void setBuffer(char *buff) { if (!sso()) ptr.buff = buff; }
|
||||
// Buffer accessor functions
|
||||
inline const char *buffer() const
|
||||
{
|
||||
return (const char *)(sso() ? sso_buf : ptr.buff);
|
||||
}
|
||||
inline char *wbuffer() const
|
||||
{
|
||||
return sso() ? const_cast<char *>(sso_buf) : ptr.buff; // Writable version of buffer
|
||||
}
|
||||
inline const char *buffer() const { return (const char *)(sso() ? sso_buf : ptr.buff); }
|
||||
inline char *wbuffer() const { return sso() ? const_cast<char *>(sso_buf) : ptr.buff; } // Writable version of buffer
|
||||
|
||||
protected:
|
||||
void init(void);
|
||||
@ -363,48 +286,37 @@ protected:
|
||||
#endif
|
||||
};
|
||||
|
||||
class StringSumHelper: public String
|
||||
{
|
||||
class StringSumHelper: public String {
|
||||
public:
|
||||
StringSumHelper(const String &s) :
|
||||
String(s)
|
||||
{
|
||||
String(s) {
|
||||
}
|
||||
StringSumHelper(const char *p) :
|
||||
String(p)
|
||||
{
|
||||
String(p) {
|
||||
}
|
||||
StringSumHelper(char c) :
|
||||
String(c)
|
||||
{
|
||||
String(c) {
|
||||
}
|
||||
StringSumHelper(unsigned char num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(int num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(unsigned int num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(long num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(unsigned long num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(float num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(double num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -41,8 +41,7 @@ void __cxa_deleted_virtual(void)
|
||||
panic();
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t guard;
|
||||
uint8_t ps;
|
||||
} guard_t;
|
||||
@ -50,8 +49,7 @@ typedef struct
|
||||
extern "C" int __cxa_guard_acquire(__guard* pg)
|
||||
{
|
||||
uint8_t ps = xt_rsil(15);
|
||||
if (reinterpret_cast<guard_t*>(pg)->guard)
|
||||
{
|
||||
if (reinterpret_cast<guard_t*>(pg)->guard) {
|
||||
xt_wsr_ps(ps);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
/**
|
||||
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
|
||||
|
||||
* 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"
|
||||
@ -30,19 +30,17 @@ extern "C" {
|
||||
#include "base64.h"
|
||||
|
||||
/**
|
||||
convert input data to base64
|
||||
@param data uint8_t
|
||||
@param length size_t
|
||||
@return String
|
||||
* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if(buffer) {
|
||||
base64_encodestate _state;
|
||||
if(doNewLines)
|
||||
{
|
||||
@ -63,12 +61,11 @@ String base64::encode(uint8_t * data, size_t length, bool doNewLines)
|
||||
}
|
||||
|
||||
/**
|
||||
convert input data to base64
|
||||
@param text String
|
||||
@return String
|
||||
* convert input data to base64
|
||||
* @param text String
|
||||
* @return String
|
||||
*/
|
||||
String base64::encode(String text, bool doNewLines)
|
||||
{
|
||||
String base64::encode(String text, bool doNewLines) {
|
||||
return base64::encode((uint8_t *) text.c_str(), text.length(), doNewLines);
|
||||
}
|
||||
|
||||
|
@ -1,32 +1,31 @@
|
||||
/**
|
||||
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
|
||||
|
||||
* 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
|
||||
{
|
||||
class base64 {
|
||||
public:
|
||||
// NOTE: The default behaviour of backend (lib64)
|
||||
// is to add a newline every 72 (encoded) characters output.
|
||||
|
@ -22,42 +22,35 @@
|
||||
#include "c_types.h"
|
||||
|
||||
cbuf::cbuf(size_t size) :
|
||||
next(NULL), _size(size), _buf(new char[size]), _bufend(_buf + size), _begin(_buf), _end(_begin)
|
||||
{
|
||||
next(NULL), _size(size), _buf(new char[size]), _bufend(_buf + size), _begin(_buf), _end(_begin) {
|
||||
}
|
||||
|
||||
cbuf::~cbuf()
|
||||
{
|
||||
cbuf::~cbuf() {
|
||||
delete[] _buf;
|
||||
}
|
||||
|
||||
size_t cbuf::resizeAdd(size_t addSize)
|
||||
{
|
||||
size_t cbuf::resizeAdd(size_t addSize) {
|
||||
return resize(_size + addSize);
|
||||
}
|
||||
|
||||
size_t cbuf::resize(size_t newSize)
|
||||
{
|
||||
size_t cbuf::resize(size_t newSize) {
|
||||
|
||||
size_t bytes_available = available();
|
||||
|
||||
// not lose any data
|
||||
// if data can be lost use remove or flush before resize
|
||||
if ((newSize <= bytes_available) || (newSize == _size))
|
||||
{
|
||||
if((newSize <= bytes_available) || (newSize == _size)) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
char *newbuf = new char[newSize];
|
||||
char *oldbuf = _buf;
|
||||
|
||||
if (!newbuf)
|
||||
{
|
||||
if(!newbuf) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
if (_buf)
|
||||
{
|
||||
if(_buf) {
|
||||
read(newbuf, bytes_available);
|
||||
memset((newbuf + bytes_available), 0x00, (newSize - bytes_available));
|
||||
}
|
||||
@ -73,47 +66,37 @@ size_t cbuf::resize(size_t newSize)
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t ICACHE_RAM_ATTR cbuf::available() const
|
||||
{
|
||||
if (_end >= _begin)
|
||||
{
|
||||
size_t ICACHE_RAM_ATTR cbuf::available() const {
|
||||
if(_end >= _begin) {
|
||||
return _end - _begin;
|
||||
}
|
||||
return _size - (_begin - _end);
|
||||
}
|
||||
|
||||
size_t cbuf::size()
|
||||
{
|
||||
size_t cbuf::size() {
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t cbuf::room() const
|
||||
{
|
||||
if (_end >= _begin)
|
||||
{
|
||||
size_t cbuf::room() const {
|
||||
if(_end >= _begin) {
|
||||
return _size - (_end - _begin) - 1;
|
||||
}
|
||||
return _begin - _end - 1;
|
||||
}
|
||||
|
||||
int cbuf::peek()
|
||||
{
|
||||
int cbuf::peek() {
|
||||
if(empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<int>(*_begin);
|
||||
}
|
||||
|
||||
size_t cbuf::peek(char *dst, size_t size)
|
||||
{
|
||||
size_t cbuf::peek(char *dst, size_t size) {
|
||||
size_t bytes_available = available();
|
||||
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
||||
size_t size_read = size_to_read;
|
||||
char * begin = _begin;
|
||||
if (_end < _begin && size_to_read > (size_t)(_bufend - _begin))
|
||||
{
|
||||
if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) {
|
||||
size_t top_size = _bufend - _begin;
|
||||
memcpy(dst, _begin, top_size);
|
||||
begin = _buf;
|
||||
@ -124,25 +107,20 @@ size_t cbuf::peek(char *dst, size_t size)
|
||||
return size_read;
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR cbuf::read()
|
||||
{
|
||||
int ICACHE_RAM_ATTR cbuf::read() {
|
||||
if(empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char result = *_begin;
|
||||
_begin = wrap_if_bufend(_begin + 1);
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
size_t cbuf::read(char* dst, size_t size)
|
||||
{
|
||||
size_t cbuf::read(char* dst, size_t size) {
|
||||
size_t bytes_available = available();
|
||||
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
||||
size_t size_read = size_to_read;
|
||||
if (_end < _begin && size_to_read > (size_t)(_bufend - _begin))
|
||||
{
|
||||
if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) {
|
||||
size_t top_size = _bufend - _begin;
|
||||
memcpy(dst, _begin, top_size);
|
||||
_begin = _buf;
|
||||
@ -154,25 +132,20 @@ size_t cbuf::read(char* dst, size_t size)
|
||||
return size_read;
|
||||
}
|
||||
|
||||
size_t ICACHE_RAM_ATTR cbuf::write(char c)
|
||||
{
|
||||
size_t ICACHE_RAM_ATTR cbuf::write(char c) {
|
||||
if(full())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*_end = c;
|
||||
_end = wrap_if_bufend(_end + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t cbuf::write(const char* src, size_t size)
|
||||
{
|
||||
size_t cbuf::write(const char* src, size_t size) {
|
||||
size_t bytes_available = room();
|
||||
size_t size_to_write = (size < bytes_available) ? size : bytes_available;
|
||||
size_t size_written = size_to_write;
|
||||
if (_end >= _begin && size_to_write > (size_t)(_bufend - _end))
|
||||
{
|
||||
if(_end >= _begin && size_to_write > (size_t) (_bufend - _end)) {
|
||||
size_t top_size = _bufend - _end;
|
||||
memcpy(_end, src, top_size);
|
||||
_end = _buf;
|
||||
@ -184,23 +157,19 @@ size_t cbuf::write(const char* src, size_t size)
|
||||
return size_written;
|
||||
}
|
||||
|
||||
void cbuf::flush()
|
||||
{
|
||||
void cbuf::flush() {
|
||||
_begin = _buf;
|
||||
_end = _buf;
|
||||
}
|
||||
|
||||
size_t cbuf::remove(size_t size)
|
||||
{
|
||||
size_t cbuf::remove(size_t size) {
|
||||
size_t bytes_available = available();
|
||||
if (size >= bytes_available)
|
||||
{
|
||||
if(size >= bytes_available) {
|
||||
flush();
|
||||
return 0;
|
||||
}
|
||||
size_t size_to_remove = (size < bytes_available) ? size : bytes_available;
|
||||
if (_end < _begin && size_to_remove > (size_t)(_bufend - _begin))
|
||||
{
|
||||
if(_end < _begin && size_to_remove > (size_t) (_bufend - _begin)) {
|
||||
size_t top_size = _bufend - _begin;
|
||||
_begin = _buf;
|
||||
size_to_remove -= top_size;
|
||||
|
@ -25,8 +25,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
class cbuf
|
||||
{
|
||||
class cbuf {
|
||||
public:
|
||||
cbuf(size_t size);
|
||||
~cbuf();
|
||||
@ -38,13 +37,11 @@ public:
|
||||
|
||||
size_t room() const;
|
||||
|
||||
inline bool empty() const
|
||||
{
|
||||
inline bool empty() const {
|
||||
return _begin == _end;
|
||||
}
|
||||
|
||||
inline bool full() const
|
||||
{
|
||||
inline bool full() const {
|
||||
return wrap_if_bufend(_end + 1) == _begin;
|
||||
}
|
||||
|
||||
@ -63,8 +60,7 @@ public:
|
||||
cbuf *next;
|
||||
|
||||
private:
|
||||
inline char* wrap_if_bufend(char* ptr) const
|
||||
{
|
||||
inline char* wrap_if_bufend(char* ptr) const {
|
||||
return (ptr == _bufend) ? _buf : ptr;
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct cont_
|
||||
{
|
||||
typedef struct cont_ {
|
||||
void (*pc_ret)(void);
|
||||
unsigned* sp_ret;
|
||||
|
||||
|
@ -27,8 +27,7 @@ extern "C" {
|
||||
|
||||
#define CONT_STACKGUARD 0xfeefeffe
|
||||
|
||||
void cont_init(cont_t* cont)
|
||||
{
|
||||
void cont_init(cont_t* cont) {
|
||||
memset(cont, 0, sizeof(cont_t));
|
||||
|
||||
cont->stack_guard1 = CONT_STACKGUARD;
|
||||
@ -43,19 +42,14 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR cont_check(cont_t* cont)
|
||||
{
|
||||
if (cont->stack_guard1 != CONT_STACKGUARD || cont->stack_guard2 != CONT_STACKGUARD)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int ICACHE_RAM_ATTR cont_check(cont_t* cont) {
|
||||
if(cont->stack_guard1 != CONT_STACKGUARD || cont->stack_guard2 != CONT_STACKGUARD) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// No need for this to be in IRAM, not expected to be IRQ called
|
||||
int cont_get_free_stack(cont_t* cont)
|
||||
{
|
||||
int cont_get_free_stack(cont_t* cont) {
|
||||
uint32_t *head = cont->stack;
|
||||
int freeWords = 0;
|
||||
|
||||
@ -68,8 +62,7 @@ extern "C" {
|
||||
return freeWords * 4;
|
||||
}
|
||||
|
||||
bool ICACHE_RAM_ATTR cont_can_yield(cont_t* cont)
|
||||
{
|
||||
bool ICACHE_RAM_ATTR cont_can_yield(cont_t* cont) {
|
||||
return !ETS_INTR_WITHINISR() &&
|
||||
cont->pc_ret != 0 && cont->pc_yield == 0;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
This is the original app_entry() not providing extra 4K heap, but allowing
|
||||
the use of WPS.
|
||||
|
||||
see comments in core_esp8266_main.cpp's app_entry()
|
||||
|
||||
* This is the original app_entry() not providing extra 4K heap, but allowing
|
||||
* the use of WPS.
|
||||
*
|
||||
* see comments in core_esp8266_main.cpp's app_entry()
|
||||
*
|
||||
*/
|
||||
|
||||
#include <c_types.h>
|
||||
@ -13,10 +13,10 @@
|
||||
void disable_extra4k_at_link_time (void)
|
||||
{
|
||||
/*
|
||||
does nothing
|
||||
allows overriding the core_esp8266_main.cpp's app_entry()
|
||||
by this one below, at link time
|
||||
|
||||
* does nothing
|
||||
* allows overriding the core_esp8266_main.cpp's app_entry()
|
||||
* by this one below, at link time
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -31,19 +31,15 @@ extern "C" {
|
||||
bool bit;
|
||||
uint8_t c;
|
||||
|
||||
while (length--)
|
||||
{
|
||||
while (length--) {
|
||||
c = *data++;
|
||||
for (i = 0x80; i > 0; i >>= 1)
|
||||
{
|
||||
for (i = 0x80; i > 0; i >>= 1) {
|
||||
bit = crc & 0x80000000;
|
||||
if (c & i)
|
||||
{
|
||||
if (c & i) {
|
||||
bit = !bit;
|
||||
}
|
||||
crc <<= 1;
|
||||
if (bit)
|
||||
{
|
||||
if (bit) {
|
||||
crc ^= 0x04c11db7;
|
||||
}
|
||||
}
|
||||
@ -61,15 +57,13 @@ extern "C" {
|
||||
{
|
||||
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
|
||||
uint32_t* dst = (uint32_t *) cmd;
|
||||
for (uint32_t i = 0; i < dw_count; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < dw_count; ++i) {
|
||||
dst[i] = RTC_MEM[i];
|
||||
}
|
||||
|
||||
uint32_t crc32 = eboot_command_calculate_crc32(cmd);
|
||||
if ((cmd->magic & EBOOT_MAGIC_MASK) != EBOOT_MAGIC ||
|
||||
cmd->crc32 != crc32)
|
||||
{
|
||||
cmd->crc32 != crc32) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -83,8 +77,7 @@ extern "C" {
|
||||
|
||||
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
|
||||
const uint32_t* src = (const uint32_t *) cmd;
|
||||
for (uint32_t i = 0; i < dw_count; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < dw_count; ++i) {
|
||||
RTC_MEM[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,7 @@ extern "C" {
|
||||
|
||||
int SPIEraseAreaEx(const uint32_t start, const uint32_t size)
|
||||
{
|
||||
if ((start & (FLASH_SECTOR_SIZE - 1)) != 0)
|
||||
{
|
||||
if ((start & (FLASH_SECTOR_SIZE - 1)) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -40,29 +39,23 @@ extern "C" {
|
||||
const uint32_t end = current_sector + sector_count;
|
||||
|
||||
for (; current_sector < end && (current_sector & (sectors_per_block-1));
|
||||
++current_sector, --sector_count)
|
||||
{
|
||||
if (SPIEraseSector(current_sector))
|
||||
{
|
||||
++current_sector, --sector_count) {
|
||||
if (SPIEraseSector(current_sector)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (;current_sector + sectors_per_block <= end;
|
||||
current_sector += sectors_per_block,
|
||||
sector_count -= sectors_per_block)
|
||||
{
|
||||
if (SPIEraseBlock(current_sector / sectors_per_block))
|
||||
{
|
||||
sector_count -= sectors_per_block) {
|
||||
if (SPIEraseBlock(current_sector / sectors_per_block)) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
for (; current_sector < end;
|
||||
++current_sector, --sector_count)
|
||||
{
|
||||
if (SPIEraseSector(current_sector))
|
||||
{
|
||||
++current_sector, --sector_count) {
|
||||
if (SPIEraseSector(current_sector)) {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,7 @@ extern "C" {
|
||||
// For RX, it's a little different. The buffers in i2s_slc_queue are
|
||||
// placed onto the list when they're filled by DMA
|
||||
|
||||
typedef struct slc_queue_item
|
||||
{
|
||||
typedef struct slc_queue_item {
|
||||
uint32_t blocksize : 12;
|
||||
uint32_t datalen : 12;
|
||||
uint32_t unused : 5;
|
||||
@ -54,8 +53,7 @@ extern "C" {
|
||||
struct slc_queue_item * next_link_ptr;
|
||||
} slc_queue_item_t;
|
||||
|
||||
typedef struct i2s_state
|
||||
{
|
||||
typedef struct i2s_state {
|
||||
uint32_t * slc_queue[SLC_BUF_CNT];
|
||||
volatile uint8_t slc_queue_len;
|
||||
uint32_t * slc_buf_pntr[SLC_BUF_CNT]; // Pointer to the I2S DMA buffer data
|
||||
@ -85,150 +83,119 @@ extern "C" {
|
||||
#define I2SI_BCK 13
|
||||
#define I2SI_WS 14
|
||||
|
||||
static bool _i2s_is_full(const i2s_state_t *ch)
|
||||
{
|
||||
if (!ch)
|
||||
{
|
||||
static bool _i2s_is_full(const i2s_state_t *ch) {
|
||||
if (!ch) {
|
||||
return false;
|
||||
}
|
||||
return (ch->curr_slc_buf_pos==SLC_BUF_LEN || ch->curr_slc_buf==NULL) && (ch->slc_queue_len == 0);
|
||||
}
|
||||
|
||||
bool i2s_is_full()
|
||||
{
|
||||
bool i2s_is_full() {
|
||||
return _i2s_is_full( tx );
|
||||
}
|
||||
|
||||
bool i2s_rx_is_full()
|
||||
{
|
||||
bool i2s_rx_is_full() {
|
||||
return _i2s_is_full( rx );
|
||||
}
|
||||
|
||||
static bool _i2s_is_empty(const i2s_state_t *ch)
|
||||
{
|
||||
if (!ch)
|
||||
{
|
||||
static bool _i2s_is_empty(const i2s_state_t *ch) {
|
||||
if (!ch) {
|
||||
return false;
|
||||
}
|
||||
return (ch->slc_queue_len >= SLC_BUF_CNT-1);
|
||||
}
|
||||
|
||||
bool i2s_is_empty()
|
||||
{
|
||||
bool i2s_is_empty() {
|
||||
return _i2s_is_empty( tx );
|
||||
}
|
||||
|
||||
bool i2s_rx_is_empty()
|
||||
{
|
||||
bool i2s_rx_is_empty() {
|
||||
return _i2s_is_empty( rx );
|
||||
}
|
||||
|
||||
static uint16_t _i2s_available(const i2s_state_t *ch)
|
||||
{
|
||||
if (!ch)
|
||||
{
|
||||
static uint16_t _i2s_available(const i2s_state_t *ch) {
|
||||
if (!ch) {
|
||||
return 0;
|
||||
}
|
||||
return (SLC_BUF_CNT - ch->slc_queue_len) * SLC_BUF_LEN;
|
||||
}
|
||||
|
||||
uint16_t i2s_available()
|
||||
{
|
||||
uint16_t i2s_available(){
|
||||
return _i2s_available( tx );
|
||||
}
|
||||
|
||||
uint16_t i2s_rx_available()
|
||||
{
|
||||
uint16_t i2s_rx_available(){
|
||||
return _i2s_available( rx );
|
||||
}
|
||||
|
||||
// Pop the top off of the queue and return it
|
||||
static uint32_t * ICACHE_RAM_ATTR i2s_slc_queue_next_item(i2s_state_t *ch)
|
||||
{
|
||||
static uint32_t * ICACHE_RAM_ATTR i2s_slc_queue_next_item(i2s_state_t *ch) {
|
||||
uint8_t i;
|
||||
uint32_t *item = ch->slc_queue[0];
|
||||
ch->slc_queue_len--;
|
||||
for (i = 0; i < ch->slc_queue_len; i++)
|
||||
{
|
||||
for ( i = 0; i < ch->slc_queue_len; i++) {
|
||||
ch->slc_queue[i] = ch->slc_queue[i+1];
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
// Append an item to the end of the queue from receive
|
||||
static void ICACHE_RAM_ATTR i2s_slc_queue_append_item(i2s_state_t *ch, uint32_t *item)
|
||||
{
|
||||
static void ICACHE_RAM_ATTR i2s_slc_queue_append_item(i2s_state_t *ch, uint32_t *item) {
|
||||
// Shift everything up, except for the one corresponding to this item
|
||||
for (int i = 0, dest = 0; i < ch->slc_queue_len; i++)
|
||||
{
|
||||
if (ch->slc_queue[i] != item)
|
||||
{
|
||||
for (int i=0, dest=0; i < ch->slc_queue_len; i++) {
|
||||
if (ch->slc_queue[i] != item) {
|
||||
ch->slc_queue[dest++] = ch->slc_queue[i];
|
||||
}
|
||||
}
|
||||
if (ch->slc_queue_len < SLC_BUF_CNT - 1)
|
||||
{
|
||||
if (ch->slc_queue_len < SLC_BUF_CNT - 1) {
|
||||
ch->slc_queue[ch->slc_queue_len++] = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ch->slc_queue[ch->slc_queue_len] = item;
|
||||
}
|
||||
}
|
||||
|
||||
static void ICACHE_RAM_ATTR i2s_slc_isr(void)
|
||||
{
|
||||
static void ICACHE_RAM_ATTR i2s_slc_isr(void) {
|
||||
ETS_SLC_INTR_DISABLE();
|
||||
uint32_t slc_intr_status = SLCIS;
|
||||
SLCIC = 0xFFFFFFFF;
|
||||
if (slc_intr_status & SLCIRXEOF)
|
||||
{
|
||||
if (slc_intr_status & SLCIRXEOF) {
|
||||
slc_queue_item_t *finished_item = (slc_queue_item_t *)SLCRXEDA;
|
||||
// Zero the buffer so it is mute in case of underflow
|
||||
ets_memset((void *)finished_item->buf_ptr, 0x00, SLC_BUF_LEN * 4);
|
||||
if (tx->slc_queue_len >= SLC_BUF_CNT - 1)
|
||||
{
|
||||
if (tx->slc_queue_len >= SLC_BUF_CNT-1) {
|
||||
// All buffers are empty. This means we have an underflow
|
||||
i2s_slc_queue_next_item(tx); // Free space for finished_item
|
||||
}
|
||||
tx->slc_queue[tx->slc_queue_len++] = finished_item->buf_ptr;
|
||||
if (tx->callback)
|
||||
{
|
||||
if (tx->callback) {
|
||||
tx->callback();
|
||||
}
|
||||
}
|
||||
if (slc_intr_status & SLCITXEOF)
|
||||
{
|
||||
if (slc_intr_status & SLCITXEOF) {
|
||||
slc_queue_item_t *finished_item = (slc_queue_item_t *)SLCTXEDA;
|
||||
// Set owner back to 1 (SW) or else RX stops. TX has no such restriction.
|
||||
finished_item->owner = 1;
|
||||
i2s_slc_queue_append_item(rx, finished_item->buf_ptr);
|
||||
if (rx->callback)
|
||||
{
|
||||
if (rx->callback) {
|
||||
rx->callback();
|
||||
}
|
||||
}
|
||||
ETS_SLC_INTR_ENABLE();
|
||||
}
|
||||
|
||||
void i2s_set_callback(void (*callback)(void))
|
||||
{
|
||||
void i2s_set_callback(void (*callback) (void)) {
|
||||
tx->callback = callback;
|
||||
}
|
||||
|
||||
void i2s_rx_set_callback(void (*callback)(void))
|
||||
{
|
||||
void i2s_rx_set_callback(void (*callback) (void)) {
|
||||
rx->callback = callback;
|
||||
}
|
||||
|
||||
static bool _alloc_channel(i2s_state_t *ch)
|
||||
{
|
||||
static bool _alloc_channel(i2s_state_t *ch) {
|
||||
ch->slc_queue_len = 0;
|
||||
for (int x = 0; x < SLC_BUF_CNT; x++)
|
||||
{
|
||||
for (int x=0; x<SLC_BUF_CNT; x++) {
|
||||
ch->slc_buf_pntr[x] = (uint32_t *)malloc(SLC_BUF_LEN * sizeof(ch->slc_buf_pntr[0][0]));
|
||||
if (!ch->slc_buf_pntr[x])
|
||||
{
|
||||
if (!ch->slc_buf_pntr[x]) {
|
||||
// OOM, the upper layer will free up any partially allocated channels.
|
||||
return false;
|
||||
}
|
||||
@ -246,19 +213,14 @@ extern "C" {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool i2s_slc_begin()
|
||||
{
|
||||
if (tx)
|
||||
{
|
||||
if (!_alloc_channel(tx))
|
||||
{
|
||||
static bool i2s_slc_begin() {
|
||||
if (tx) {
|
||||
if (!_alloc_channel(tx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (rx)
|
||||
{
|
||||
if (!_alloc_channel(rx))
|
||||
{
|
||||
if (rx) {
|
||||
if (!_alloc_channel(rx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -280,20 +242,14 @@ extern "C" {
|
||||
//an error at us otherwise. Just feed it any random descriptor.
|
||||
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
|
||||
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
|
||||
if (!rx)
|
||||
{
|
||||
if (!rx) {
|
||||
SLCTXL |= (uint32)&tx->slc_items[1] << SLCTXLA; // Set fake (unused) RX descriptor address
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SLCTXL |= (uint32)&rx->slc_items[0] << SLCTXLA; // Set real RX address
|
||||
}
|
||||
if (!tx)
|
||||
{
|
||||
if (!tx) {
|
||||
SLCRXL |= (uint32)&rx->slc_items[1] << SLCRXLA; // Set fake (unused) TX descriptor address
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SLCRXL |= (uint32)&tx->slc_items[0] << SLCRXLA; // Set real TX address
|
||||
}
|
||||
|
||||
@ -304,31 +260,26 @@ extern "C" {
|
||||
|
||||
// Start transmission ("TX" DMA always needed to be enabled)
|
||||
SLCTXL |= SLCTXLS;
|
||||
if (tx)
|
||||
{
|
||||
if (tx) {
|
||||
SLCRXL |= SLCRXLS;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void i2s_slc_end()
|
||||
{
|
||||
static void i2s_slc_end(){
|
||||
ETS_SLC_INTR_DISABLE();
|
||||
SLCIC = 0xFFFFFFFF;
|
||||
SLCIE = 0;
|
||||
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
|
||||
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
|
||||
|
||||
for (int x = 0; x < SLC_BUF_CNT; x++)
|
||||
{
|
||||
if (tx)
|
||||
{
|
||||
for (int x = 0; x<SLC_BUF_CNT; x++) {
|
||||
if (tx) {
|
||||
free(tx->slc_buf_pntr[x]);
|
||||
tx->slc_buf_pntr[x] = NULL;
|
||||
}
|
||||
if (rx)
|
||||
{
|
||||
if (rx) {
|
||||
free(rx->slc_buf_pntr[x]);
|
||||
rx->slc_buf_pntr[x] = NULL;
|
||||
}
|
||||
@ -337,30 +288,21 @@ extern "C" {
|
||||
|
||||
// These routines push a single, 32-bit sample to the I2S buffers. Call at (on average)
|
||||
// at least the current sample rate.
|
||||
static bool _i2s_write_sample(uint32_t sample, bool nb)
|
||||
{
|
||||
if (!tx)
|
||||
{
|
||||
static bool _i2s_write_sample(uint32_t sample, bool nb) {
|
||||
if (!tx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tx->curr_slc_buf_pos == SLC_BUF_LEN || tx->curr_slc_buf == NULL)
|
||||
{
|
||||
if (tx->slc_queue_len == 0)
|
||||
{
|
||||
if (nb)
|
||||
{
|
||||
if (tx->curr_slc_buf_pos==SLC_BUF_LEN || tx->curr_slc_buf==NULL) {
|
||||
if (tx->slc_queue_len == 0) {
|
||||
if (nb) {
|
||||
// Don't wait if nonblocking, just notify upper levels
|
||||
return false;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
if (tx->slc_queue_len > 0)
|
||||
{
|
||||
while (1) {
|
||||
if (tx->slc_queue_len > 0) {
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
optimistic_yield(10000);
|
||||
}
|
||||
}
|
||||
@ -374,18 +316,15 @@ extern "C" {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool i2s_write_sample(uint32_t sample)
|
||||
{
|
||||
bool i2s_write_sample(uint32_t sample) {
|
||||
return _i2s_write_sample(sample, false);
|
||||
}
|
||||
|
||||
bool i2s_write_sample_nb(uint32_t sample)
|
||||
{
|
||||
bool i2s_write_sample_nb(uint32_t sample) {
|
||||
return _i2s_write_sample(sample, true);
|
||||
}
|
||||
|
||||
bool i2s_write_lr(int16_t left, int16_t right)
|
||||
{
|
||||
bool i2s_write_lr(int16_t left, int16_t right){
|
||||
int sample = right & 0xFFFF;
|
||||
sample = sample << 16;
|
||||
sample |= left & 0xFFFF;
|
||||
@ -394,34 +333,25 @@ extern "C" {
|
||||
|
||||
// writes a buffer of frames into the DMA memory, returns the amount of frames written
|
||||
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
|
||||
static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mono, bool nb)
|
||||
{
|
||||
static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mono, bool nb) {
|
||||
uint16_t frames_written=0;
|
||||
|
||||
while (frame_count > 0)
|
||||
{
|
||||
while(frame_count>0) {
|
||||
|
||||
// make sure we have room in the current buffer
|
||||
if (tx->curr_slc_buf_pos == SLC_BUF_LEN || tx->curr_slc_buf == NULL)
|
||||
{
|
||||
if (tx->curr_slc_buf_pos==SLC_BUF_LEN || tx->curr_slc_buf==NULL) {
|
||||
// no room in the current buffer? if there are no buffers available then exit
|
||||
if (tx->slc_queue_len == 0)
|
||||
{
|
||||
if (nb)
|
||||
{
|
||||
if (nb) {
|
||||
// if nonblocking just return the number of frames written so far
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (tx->slc_queue_len > 0)
|
||||
{
|
||||
else {
|
||||
while (1) {
|
||||
if (tx->slc_queue_len > 0) {
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
optimistic_yield(10000);
|
||||
}
|
||||
}
|
||||
@ -440,18 +370,15 @@ extern "C" {
|
||||
|
||||
uint16_t fc = (available < frame_count) ? available : frame_count;
|
||||
|
||||
if (mono)
|
||||
{
|
||||
for (uint16_t i = 0; i < fc; i++)
|
||||
{
|
||||
if (mono) {
|
||||
for(uint16_t i=0;i<fc;i++){
|
||||
uint16_t v = (uint16_t)(*frames++);
|
||||
tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v << 16) | v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint16_t i = 0; i < fc; i++)
|
||||
{
|
||||
for(uint16_t i=0;i<fc;i++){
|
||||
uint16_t v1 = (uint16_t)(*frames++);
|
||||
uint16_t v2 = (uint16_t)(*frames++);
|
||||
tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v1 << 16) | v2;
|
||||
@ -464,48 +391,27 @@ extern "C" {
|
||||
return frames_written;
|
||||
}
|
||||
|
||||
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count)
|
||||
{
|
||||
return _i2s_write_buffer(frames, frame_count, true, true);
|
||||
}
|
||||
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, true); }
|
||||
|
||||
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count)
|
||||
{
|
||||
return _i2s_write_buffer(frames, frame_count, true, false);
|
||||
}
|
||||
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, false); }
|
||||
|
||||
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count)
|
||||
{
|
||||
return _i2s_write_buffer(frames, frame_count, false, true);
|
||||
}
|
||||
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, true); }
|
||||
|
||||
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count)
|
||||
{
|
||||
return _i2s_write_buffer(frames, frame_count, false, false);
|
||||
}
|
||||
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, false); }
|
||||
|
||||
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking)
|
||||
{
|
||||
if (!rx)
|
||||
{
|
||||
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking) {
|
||||
if (!rx) {
|
||||
return false;
|
||||
}
|
||||
if (rx->curr_slc_buf_pos == SLC_BUF_LEN || rx->curr_slc_buf == NULL)
|
||||
{
|
||||
if (rx->slc_queue_len == 0)
|
||||
{
|
||||
if (!blocking)
|
||||
{
|
||||
if (rx->curr_slc_buf_pos==SLC_BUF_LEN || rx->curr_slc_buf==NULL) {
|
||||
if (rx->slc_queue_len == 0) {
|
||||
if (!blocking) {
|
||||
return false;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
if (rx->slc_queue_len > 0)
|
||||
{
|
||||
while (1) {
|
||||
if (rx->slc_queue_len > 0){
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
optimistic_yield(10000);
|
||||
}
|
||||
}
|
||||
@ -517,12 +423,10 @@ extern "C" {
|
||||
}
|
||||
|
||||
uint32_t sample = rx->curr_slc_buf[rx->curr_slc_buf_pos++];
|
||||
if (left)
|
||||
{
|
||||
if (left) {
|
||||
*left = sample & 0xffff;
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
if (right) {
|
||||
*right = sample >> 16;
|
||||
}
|
||||
|
||||
@ -530,10 +434,8 @@ extern "C" {
|
||||
}
|
||||
|
||||
|
||||
void i2s_set_rate(uint32_t rate) //Rate in HZ
|
||||
{
|
||||
if (rate == _i2s_sample_rate)
|
||||
{
|
||||
void i2s_set_rate(uint32_t rate) { //Rate in HZ
|
||||
if (rate == _i2s_sample_rate) {
|
||||
return;
|
||||
}
|
||||
_i2s_sample_rate = rate;
|
||||
@ -543,13 +445,10 @@ extern "C" {
|
||||
|
||||
uint8_t sbd_div_best=1;
|
||||
uint8_t scd_div_best=1;
|
||||
for (uint8_t i = 1; i < 64; i++)
|
||||
{
|
||||
for (uint8_t j = i; j < 64; j++)
|
||||
{
|
||||
for (uint8_t i=1; i<64; i++) {
|
||||
for (uint8_t j=i; j<64; j++) {
|
||||
float new_delta = fabs(((float)scaled_base_freq/i/j) - rate);
|
||||
if (new_delta < delta_best)
|
||||
{
|
||||
if (new_delta < delta_best){
|
||||
delta_best = new_delta;
|
||||
sbd_div_best = i;
|
||||
scd_div_best = j;
|
||||
@ -560,8 +459,7 @@ extern "C" {
|
||||
i2s_set_dividers( sbd_div_best, scd_div_best );
|
||||
}
|
||||
|
||||
void i2s_set_dividers(uint8_t div1, uint8_t div2)
|
||||
{
|
||||
void i2s_set_dividers(uint8_t div1, uint8_t div2) {
|
||||
// Ensure dividers fit in bit fields
|
||||
div1 &= I2SBDM;
|
||||
div2 &= I2SCDM;
|
||||
@ -576,23 +474,18 @@ extern "C" {
|
||||
I2SC |= I2SRF | I2SMR | I2SRMS | I2STMS | (div1 << I2SBD) | (div2 << I2SCD);
|
||||
}
|
||||
|
||||
float i2s_get_real_rate()
|
||||
{
|
||||
float i2s_get_real_rate(){
|
||||
return (float)I2SBASEFREQ/32/((I2SC>>I2SBD) & I2SBDM)/((I2SC >> I2SCD) & I2SCDM);
|
||||
}
|
||||
|
||||
bool i2s_rxtx_begin(bool enableRx, bool enableTx)
|
||||
{
|
||||
if (tx || rx)
|
||||
{
|
||||
bool i2s_rxtx_begin(bool enableRx, bool enableTx) {
|
||||
if (tx || rx) {
|
||||
i2s_end(); // Stop and free any ongoing stuff
|
||||
}
|
||||
|
||||
if (enableTx)
|
||||
{
|
||||
if (enableTx) {
|
||||
tx = (i2s_state_t*)calloc(1, sizeof(*tx));
|
||||
if (!tx)
|
||||
{
|
||||
if (!tx) {
|
||||
// Nothing to clean up yet
|
||||
return false; // OOM Error!
|
||||
}
|
||||
@ -600,11 +493,9 @@ extern "C" {
|
||||
pinMode(I2SO_DATA, FUNCTION_1);
|
||||
pinMode(I2SO_BCK, FUNCTION_1);
|
||||
}
|
||||
if (enableRx)
|
||||
{
|
||||
if (enableRx) {
|
||||
rx = (i2s_state_t*)calloc(1, sizeof(*rx));
|
||||
if (!rx)
|
||||
{
|
||||
if (!rx) {
|
||||
i2s_end(); // Clean up any TX or pin changes
|
||||
return false; // OOM error!
|
||||
}
|
||||
@ -617,8 +508,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
_i2s_sample_rate = 0;
|
||||
if (!i2s_slc_begin())
|
||||
{
|
||||
if (!i2s_slc_begin()) {
|
||||
// OOM in SLC memory allocations, tear it all down and abort!
|
||||
i2s_end();
|
||||
return false;
|
||||
@ -642,8 +532,7 @@ extern "C" {
|
||||
|
||||
i2s_set_rate(44100);
|
||||
|
||||
if (rx)
|
||||
{
|
||||
if (rx) {
|
||||
// Need to prime the # of samples to receive in the engine
|
||||
I2SRXEN = SLC_BUF_LEN;
|
||||
}
|
||||
@ -653,13 +542,11 @@ extern "C" {
|
||||
return true;
|
||||
}
|
||||
|
||||
void i2s_begin()
|
||||
{
|
||||
void i2s_begin() {
|
||||
i2s_rxtx_begin(false, true);
|
||||
}
|
||||
|
||||
void i2s_end()
|
||||
{
|
||||
void i2s_end() {
|
||||
// Disable any I2S send or receive
|
||||
// ? Maybe not needed since we're resetting on the next line...
|
||||
I2SC &= ~(I2STXS | I2SRXS);
|
||||
@ -671,16 +558,14 @@ extern "C" {
|
||||
|
||||
i2s_slc_end();
|
||||
|
||||
if (tx)
|
||||
{
|
||||
if (tx) {
|
||||
pinMode(I2SO_DATA, INPUT);
|
||||
pinMode(I2SO_BCK, INPUT);
|
||||
pinMode(I2SO_WS, INPUT);
|
||||
free(tx);
|
||||
tx = NULL;
|
||||
}
|
||||
if (rx)
|
||||
{
|
||||
if (rx) {
|
||||
pinMode(I2SI_DATA, INPUT);
|
||||
pinMode(I2SI_BCK, INPUT);
|
||||
pinMode(I2SI_WS, INPUT);
|
||||
|
@ -49,8 +49,8 @@ extern void (*__init_array_end)(void);
|
||||
struct rst_info resetInfo;
|
||||
|
||||
/* Not static, used in core_esp8266_postmortem.c and other places.
|
||||
Placed into noinit section because we assign value to this variable
|
||||
before .bss is zero-filled, and need to preserve the value.
|
||||
* Placed into noinit section because we assign value to this variable
|
||||
* before .bss is zero-filled, and need to preserve the value.
|
||||
*/
|
||||
cont_t* g_pcont __attribute__((section(".noinit")));
|
||||
|
||||
@ -72,13 +72,11 @@ extern "C" {
|
||||
} // extern "C"
|
||||
|
||||
void initVariant() __attribute__((weak));
|
||||
void initVariant()
|
||||
{
|
||||
void initVariant() {
|
||||
}
|
||||
|
||||
void preloop_update_frequency() __attribute__((weak));
|
||||
void preloop_update_frequency()
|
||||
{
|
||||
void preloop_update_frequency() {
|
||||
#if defined(F_CPU) && (F_CPU == 160000000L)
|
||||
REG_SET_BIT(0x3ff00014, BIT(0));
|
||||
ets_update_cpu_frequency(160);
|
||||
@ -86,36 +84,29 @@ void preloop_update_frequency()
|
||||
}
|
||||
|
||||
|
||||
extern "C" void esp_yield()
|
||||
{
|
||||
if (cont_can_yield(g_pcont))
|
||||
{
|
||||
extern "C" void esp_yield() {
|
||||
if (cont_can_yield(g_pcont)) {
|
||||
cont_yield(g_pcont);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void esp_schedule()
|
||||
{
|
||||
extern "C" void esp_schedule() {
|
||||
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
||||
}
|
||||
|
||||
extern "C" void __yield()
|
||||
{
|
||||
if (cont_can_yield(g_pcont))
|
||||
{
|
||||
extern "C" void __yield() {
|
||||
if (cont_can_yield(g_pcont)) {
|
||||
esp_schedule();
|
||||
esp_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void yield(void) __attribute__ ((weak, alias("__yield")));
|
||||
|
||||
extern "C" void optimistic_yield(uint32_t interval_us)
|
||||
{
|
||||
extern "C" void optimistic_yield(uint32_t interval_us) {
|
||||
if (cont_can_yield(g_pcont) &&
|
||||
(system_get_time() - s_micros_at_task_start) > interval_us)
|
||||
{
|
||||
@ -123,12 +114,10 @@ extern "C" void optimistic_yield(uint32_t interval_us)
|
||||
}
|
||||
}
|
||||
|
||||
static void loop_wrapper()
|
||||
{
|
||||
static void loop_wrapper() {
|
||||
static bool setup_done = false;
|
||||
preloop_update_frequency();
|
||||
if (!setup_done)
|
||||
{
|
||||
if(!setup_done) {
|
||||
setup();
|
||||
setup_done = true;
|
||||
}
|
||||
@ -137,37 +126,29 @@ static void loop_wrapper()
|
||||
esp_schedule();
|
||||
}
|
||||
|
||||
static void loop_task(os_event_t *events)
|
||||
{
|
||||
static void loop_task(os_event_t *events) {
|
||||
(void) events;
|
||||
s_micros_at_task_start = system_get_time();
|
||||
cont_run(g_pcont, &loop_wrapper);
|
||||
if (cont_check(g_pcont) != 0)
|
||||
{
|
||||
if (cont_check(g_pcont) != 0) {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
|
||||
struct object
|
||||
{
|
||||
long placeholder[ 10 ];
|
||||
};
|
||||
struct object { long placeholder[ 10 ]; };
|
||||
void __register_frame_info (const void *begin, struct object *ob);
|
||||
extern char __eh_frame[];
|
||||
}
|
||||
|
||||
static void do_global_ctors(void)
|
||||
{
|
||||
static void do_global_ctors(void) {
|
||||
static struct object ob;
|
||||
__register_frame_info( __eh_frame, &ob );
|
||||
|
||||
void (**p)(void) = &__init_array_end;
|
||||
while (p != &__init_array_start)
|
||||
{
|
||||
(*--p)();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
extern void __unhandled_exception(const char *str);
|
||||
@ -179,21 +160,14 @@ extern "C" {
|
||||
#else
|
||||
static bool terminating;
|
||||
if (terminating)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
terminating = true;
|
||||
/* Use a trick from vterminate.cc to get any std::exception what() */
|
||||
try
|
||||
{
|
||||
try {
|
||||
__throw_exception_again;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
} catch (const std::exception& e) {
|
||||
__unhandled_exception( e.what() );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
} catch (...) {
|
||||
__unhandled_exception( "" );
|
||||
}
|
||||
#endif
|
||||
@ -201,8 +175,7 @@ extern "C" {
|
||||
|
||||
}
|
||||
|
||||
void init_done()
|
||||
{
|
||||
void init_done() {
|
||||
system_set_os_print(1);
|
||||
gdb_init();
|
||||
std::set_terminate(__unhandled_exception_cpp);
|
||||
@ -211,12 +184,12 @@ void init_done()
|
||||
}
|
||||
|
||||
/* This is the entry point of the application.
|
||||
It gets called on the default stack, which grows down from the top
|
||||
of DRAM area.
|
||||
.bss has not been zeroed out yet, but .data and .rodata are in place.
|
||||
Cache is not enabled, so only ROM and IRAM functions can be called.
|
||||
Peripherals (except for SPI0 and UART0) are not initialized.
|
||||
This function does not return.
|
||||
* It gets called on the default stack, which grows down from the top
|
||||
* of DRAM area.
|
||||
* .bss has not been zeroed out yet, but .data and .rodata are in place.
|
||||
* Cache is not enabled, so only ROM and IRAM functions can be called.
|
||||
* Peripherals (except for SPI0 and UART0) are not initialized.
|
||||
* This function does not return.
|
||||
*/
|
||||
/*
|
||||
A bit of explanation for this entry point:
|
||||
@ -280,8 +253,7 @@ extern "C" void preinit(void)
|
||||
/* do nothing by default */
|
||||
}
|
||||
|
||||
extern "C" void user_init(void)
|
||||
{
|
||||
extern "C" void user_init(void) {
|
||||
struct rst_info *rtc_info_ptr = system_get_rst_info();
|
||||
memcpy((void *) &resetInfo, (void *) rtc_info_ptr, sizeof(resetInfo));
|
||||
|
||||
|
@ -31,27 +31,22 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
char* ltoa(long value, char* result, int base)
|
||||
{
|
||||
char* ltoa(long value, char* result, int base) {
|
||||
return itoa((int)value, result, base);
|
||||
}
|
||||
|
||||
char* ultoa(unsigned long value, char* result, int base)
|
||||
{
|
||||
char* ultoa(unsigned long value, char* result, int base) {
|
||||
return utoa((unsigned int)value, result, base);
|
||||
}
|
||||
|
||||
char * dtostrf(double number, signed char width, unsigned char prec, char *s)
|
||||
{
|
||||
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
|
||||
bool negative = false;
|
||||
|
||||
if (isnan(number))
|
||||
{
|
||||
if (isnan(number)) {
|
||||
strcpy(s, "nan");
|
||||
return s;
|
||||
}
|
||||
if (isinf(number))
|
||||
{
|
||||
if (isinf(number)) {
|
||||
strcpy(s, "inf");
|
||||
return s;
|
||||
}
|
||||
@ -59,14 +54,12 @@ extern "C" {
|
||||
char* out = s;
|
||||
|
||||
int fillme = width; // how many cells to fill for the integer part
|
||||
if (prec > 0)
|
||||
{
|
||||
if (prec > 0) {
|
||||
fillme -= (prec+1);
|
||||
}
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0)
|
||||
{
|
||||
if (number < 0.0) {
|
||||
negative = true;
|
||||
fillme--;
|
||||
number = -number;
|
||||
@ -76,9 +69,7 @@ extern "C" {
|
||||
// I optimized out most of the divisions
|
||||
double rounding = 2.0;
|
||||
for (uint8_t i = 0; i < prec; ++i)
|
||||
{
|
||||
rounding *= 10.0;
|
||||
}
|
||||
rounding = 1.0 / rounding;
|
||||
|
||||
number += rounding;
|
||||
@ -86,8 +77,7 @@ extern "C" {
|
||||
// Figure out how big our number really is
|
||||
double tenpow = 1.0;
|
||||
int digitcount = 1;
|
||||
while (number >= 10.0 * tenpow)
|
||||
{
|
||||
while (number >= 10.0 * tenpow) {
|
||||
tenpow *= 10.0;
|
||||
digitcount++;
|
||||
}
|
||||
@ -96,30 +86,21 @@ extern "C" {
|
||||
fillme -= digitcount;
|
||||
|
||||
// Pad unused cells with spaces
|
||||
while (fillme-- > 0)
|
||||
{
|
||||
while (fillme-- > 0) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
|
||||
// Handle negative sign
|
||||
if (negative)
|
||||
{
|
||||
*out++ = '-';
|
||||
}
|
||||
if (negative) *out++ = '-';
|
||||
|
||||
// Print the digits, and if necessary, the decimal point
|
||||
digitcount += prec;
|
||||
int8_t digit = 0;
|
||||
while (digitcount-- > 0)
|
||||
{
|
||||
while (digitcount-- > 0) {
|
||||
digit = (int8_t)number;
|
||||
if (digit > 9)
|
||||
{
|
||||
digit = 9; // insurance
|
||||
}
|
||||
if (digit > 9) digit = 9; // insurance
|
||||
*out++ = (char)('0' | digit);
|
||||
if ((digitcount == prec) && (prec > 0))
|
||||
{
|
||||
if ((digitcount == prec) && (prec > 0)) {
|
||||
*out++ = '.';
|
||||
}
|
||||
number -= digit;
|
||||
|
@ -305,8 +305,7 @@ extern "C" {
|
||||
|
||||
extern int ICACHE_RAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size)
|
||||
{
|
||||
if (!spoof_init_data || size != 128)
|
||||
{
|
||||
if (!spoof_init_data || size != 128) {
|
||||
return __real_spi_flash_read(addr, dst, size);
|
||||
}
|
||||
|
||||
@ -348,8 +347,7 @@ extern "C" {
|
||||
|
||||
system_set_os_print(0);
|
||||
int rf_mode = __get_rf_mode();
|
||||
if (rf_mode >= 0)
|
||||
{
|
||||
if (rf_mode >= 0) {
|
||||
system_phy_set_rfoption(rf_mode);
|
||||
}
|
||||
__run_user_rf_pre_init();
|
||||
|
@ -58,8 +58,7 @@ extern "C" {
|
||||
|
||||
static void raise_exception() __attribute__((noreturn));
|
||||
|
||||
extern void __custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end)
|
||||
{
|
||||
extern void __custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) {
|
||||
(void) rst_info;
|
||||
(void) stack;
|
||||
(void) stack_end;
|
||||
@ -71,27 +70,23 @@ extern "C" {
|
||||
// Prints need to use our library function to allow for file and function
|
||||
// to be safely accessed from flash. This function encapsulates snprintf()
|
||||
// [which by definition will 0-terminate] and dumping to the UART
|
||||
static void ets_printf_P(const char *str, ...)
|
||||
{
|
||||
static void ets_printf_P(const char *str, ...) {
|
||||
char destStr[160];
|
||||
char *c = destStr;
|
||||
va_list argPtr;
|
||||
va_start(argPtr, str);
|
||||
vsnprintf(destStr, sizeof(destStr), str, argPtr);
|
||||
va_end(argPtr);
|
||||
while (*c)
|
||||
{
|
||||
while (*c) {
|
||||
ets_putc(*(c++));
|
||||
}
|
||||
}
|
||||
|
||||
void __wrap_system_restart_local()
|
||||
{
|
||||
void __wrap_system_restart_local() {
|
||||
register uint32_t sp asm("a1");
|
||||
uint32_t sp_dump = sp;
|
||||
|
||||
if (gdb_present())
|
||||
{
|
||||
if (gdb_present()) {
|
||||
/* When GDBStub is present, exceptions are handled by GDBStub,
|
||||
but Soft WDT will still call this function.
|
||||
Trigger an exception to break into GDB.
|
||||
@ -113,30 +108,24 @@ extern "C" {
|
||||
// TODO: ets_install_putc1 definition is wrong in ets_sys.h, need cast
|
||||
ets_install_putc1((void *)&uart_write_char_d);
|
||||
|
||||
if (s_panic_line)
|
||||
{
|
||||
if (s_panic_line) {
|
||||
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
|
||||
if (s_panic_what)
|
||||
{
|
||||
if (s_panic_what) {
|
||||
ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
|
||||
}
|
||||
ets_putc('\n');
|
||||
}
|
||||
else if (s_unhandled_exception)
|
||||
{
|
||||
else if (s_unhandled_exception) {
|
||||
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
|
||||
}
|
||||
else if (s_abort_called)
|
||||
{
|
||||
else if (s_abort_called) {
|
||||
ets_printf_P(PSTR("\nAbort called\n"));
|
||||
}
|
||||
else if (rst_info.reason == REASON_EXCEPTION_RST)
|
||||
{
|
||||
else if (rst_info.reason == REASON_EXCEPTION_RST) {
|
||||
ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"),
|
||||
rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
|
||||
}
|
||||
else if (rst_info.reason == REASON_SOFT_WDT_RST)
|
||||
{
|
||||
else if (rst_info.reason == REASON_SOFT_WDT_RST) {
|
||||
ets_printf_P(PSTR("\nSoft WDT reset\n"));
|
||||
}
|
||||
|
||||
@ -148,23 +137,19 @@ extern "C" {
|
||||
// and everything up to __wrap_system_restart_local
|
||||
// (determined empirically, might break)
|
||||
uint32_t offset = 0;
|
||||
if (rst_info.reason == REASON_SOFT_WDT_RST)
|
||||
{
|
||||
if (rst_info.reason == REASON_SOFT_WDT_RST) {
|
||||
offset = 0x1b0;
|
||||
}
|
||||
else if (rst_info.reason == REASON_EXCEPTION_RST)
|
||||
{
|
||||
else if (rst_info.reason == REASON_EXCEPTION_RST) {
|
||||
offset = 0x1a0;
|
||||
}
|
||||
else if (rst_info.reason == REASON_WDT_RST)
|
||||
{
|
||||
else if (rst_info.reason == REASON_WDT_RST) {
|
||||
offset = 0x10;
|
||||
}
|
||||
|
||||
ets_printf_P(PSTR("\n>>>stack>>>\n"));
|
||||
|
||||
if (sp_dump > stack_thunk_get_stack_bot() && sp_dump <= stack_thunk_get_stack_top())
|
||||
{
|
||||
if (sp_dump > stack_thunk_get_stack_bot() && sp_dump <= stack_thunk_get_stack_top()) {
|
||||
// BearSSL we dump the BSSL second stack and then reset SP back to the main cont stack
|
||||
ets_printf_P(PSTR("\nctx: bearssl\nsp: %08x end: %08x offset: %04x\n"), sp_dump, stack_thunk_get_stack_top(), offset);
|
||||
print_stack(sp_dump + offset, stack_thunk_get_stack_top());
|
||||
@ -172,13 +157,11 @@ extern "C" {
|
||||
sp_dump = stack_thunk_get_cont_sp();
|
||||
}
|
||||
|
||||
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end)
|
||||
{
|
||||
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end) {
|
||||
ets_printf_P(PSTR("\nctx: cont\n"));
|
||||
stack_end = cont_stack_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ets_printf_P(PSTR("\nctx: sys\n"));
|
||||
stack_end = 0x3fffffb0;
|
||||
// it's actually 0x3ffffff0, but the stuff below ets_run
|
||||
@ -192,8 +175,7 @@ extern "C" {
|
||||
ets_printf_P(PSTR("<<<stack<<<\n"));
|
||||
|
||||
// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
|
||||
if (umm_last_fail_alloc_addr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -204,10 +186,8 @@ extern "C" {
|
||||
}
|
||||
|
||||
|
||||
static void print_stack(uint32_t start, uint32_t end)
|
||||
{
|
||||
for (uint32_t pos = start; pos < end; pos += 0x10)
|
||||
{
|
||||
static void print_stack(uint32_t start, uint32_t end) {
|
||||
for (uint32_t pos = start; pos < end; pos += 0x10) {
|
||||
uint32_t* values = (uint32_t*)(pos);
|
||||
|
||||
// rough indicator: stack frames usually have SP saved as the second word
|
||||
@ -218,54 +198,45 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_write_char_d(char c)
|
||||
{
|
||||
static void uart_write_char_d(char c) {
|
||||
uart0_write_char_d(c);
|
||||
uart1_write_char_d(c);
|
||||
}
|
||||
|
||||
static void uart0_write_char_d(char c)
|
||||
{
|
||||
static void uart0_write_char_d(char c) {
|
||||
while (((USS(0) >> USTXC) & 0xff)) { }
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
if (c == '\n') {
|
||||
USF(0) = '\r';
|
||||
}
|
||||
USF(0) = c;
|
||||
}
|
||||
|
||||
static void uart1_write_char_d(char c)
|
||||
{
|
||||
static void uart1_write_char_d(char c) {
|
||||
while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
if (c == '\n') {
|
||||
USF(1) = '\r';
|
||||
}
|
||||
USF(1) = c;
|
||||
}
|
||||
|
||||
static void raise_exception()
|
||||
{
|
||||
static void raise_exception() {
|
||||
__asm__ __volatile__ ("syscall");
|
||||
while (1); // never reached, needed to satisfy "noreturn" attribute
|
||||
}
|
||||
|
||||
void abort()
|
||||
{
|
||||
void abort() {
|
||||
s_abort_called = true;
|
||||
raise_exception();
|
||||
}
|
||||
|
||||
void __unhandled_exception(const char *str)
|
||||
{
|
||||
void __unhandled_exception(const char *str) {
|
||||
s_unhandled_exception = str;
|
||||
raise_exception();
|
||||
}
|
||||
|
||||
void __assert_func(const char *file, int line, const char *func, const char *what)
|
||||
{
|
||||
void __assert_func(const char *file, int line, const char *func, const char *what) {
|
||||
s_panic_file = file;
|
||||
s_panic_line = line;
|
||||
s_panic_func = func;
|
||||
@ -274,8 +245,7 @@ extern "C" {
|
||||
raise_exception();
|
||||
}
|
||||
|
||||
void __panic_func(const char* file, int line, const char* func)
|
||||
{
|
||||
void __panic_func(const char* file, int line, const char* func) {
|
||||
s_panic_file = file;
|
||||
s_panic_line = line;
|
||||
s_panic_func = func;
|
||||
|
@ -120,72 +120,28 @@ extern "C" {
|
||||
#define TWI_CLOCK_STRETCH_MULTIPLIER 6
|
||||
#endif
|
||||
|
||||
void twi_setClock(unsigned int freq)
|
||||
{
|
||||
void twi_setClock(unsigned int freq){
|
||||
preferred_si2c_clock = freq;
|
||||
#if F_CPU == FCPU80
|
||||
if (freq <= 50000)
|
||||
{
|
||||
twi_dcount = 38; //about 50KHz
|
||||
}
|
||||
else if (freq <= 100000)
|
||||
{
|
||||
twi_dcount = 19; //about 100KHz
|
||||
}
|
||||
else if (freq <= 200000)
|
||||
{
|
||||
twi_dcount = 8; //about 200KHz
|
||||
}
|
||||
else if (freq <= 300000)
|
||||
{
|
||||
twi_dcount = 3; //about 300KHz
|
||||
}
|
||||
else if (freq <= 400000)
|
||||
{
|
||||
twi_dcount = 1; //about 400KHz
|
||||
}
|
||||
else
|
||||
{
|
||||
twi_dcount = 1; //about 400KHz
|
||||
}
|
||||
if(freq <= 50000) twi_dcount = 38;//about 50KHz
|
||||
else if(freq <= 100000) twi_dcount = 19;//about 100KHz
|
||||
else if(freq <= 200000) twi_dcount = 8;//about 200KHz
|
||||
else if(freq <= 300000) twi_dcount = 3;//about 300KHz
|
||||
else if(freq <= 400000) twi_dcount = 1;//about 400KHz
|
||||
else twi_dcount = 1;//about 400KHz
|
||||
#else
|
||||
if (freq <= 50000)
|
||||
{
|
||||
twi_dcount = 64; //about 50KHz
|
||||
}
|
||||
else if (freq <= 100000)
|
||||
{
|
||||
twi_dcount = 32; //about 100KHz
|
||||
}
|
||||
else if (freq <= 200000)
|
||||
{
|
||||
twi_dcount = 14; //about 200KHz
|
||||
}
|
||||
else if (freq <= 300000)
|
||||
{
|
||||
twi_dcount = 8; //about 300KHz
|
||||
}
|
||||
else if (freq <= 400000)
|
||||
{
|
||||
twi_dcount = 5; //about 400KHz
|
||||
}
|
||||
else if (freq <= 500000)
|
||||
{
|
||||
twi_dcount = 3; //about 500KHz
|
||||
}
|
||||
else if (freq <= 600000)
|
||||
{
|
||||
twi_dcount = 2; //about 600KHz
|
||||
}
|
||||
else
|
||||
{
|
||||
twi_dcount = 1; //about 700KHz
|
||||
}
|
||||
if(freq <= 50000) twi_dcount = 64;//about 50KHz
|
||||
else if(freq <= 100000) twi_dcount = 32;//about 100KHz
|
||||
else if(freq <= 200000) twi_dcount = 14;//about 200KHz
|
||||
else if(freq <= 300000) twi_dcount = 8;//about 300KHz
|
||||
else if(freq <= 400000) twi_dcount = 5;//about 400KHz
|
||||
else if(freq <= 500000) twi_dcount = 3;//about 500KHz
|
||||
else if(freq <= 600000) twi_dcount = 2;//about 600KHz
|
||||
else twi_dcount = 1;//about 700KHz
|
||||
#endif
|
||||
}
|
||||
|
||||
void twi_setClockStretchLimit(uint32_t limit)
|
||||
{
|
||||
void twi_setClockStretchLimit(uint32_t limit){
|
||||
twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER;
|
||||
}
|
||||
|
||||
@ -217,26 +173,22 @@ extern "C" {
|
||||
twi_addr = address << 1;
|
||||
}
|
||||
|
||||
static void ICACHE_RAM_ATTR twi_delay(unsigned char v)
|
||||
{
|
||||
static void ICACHE_RAM_ATTR twi_delay(unsigned char v){
|
||||
unsigned int i;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
unsigned int reg;
|
||||
for (i = 0; i < v; i++)
|
||||
{
|
||||
for (i = 0; i < v; i++) {
|
||||
reg = GPI;
|
||||
}
|
||||
(void)reg;
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
static bool twi_write_start(void)
|
||||
{
|
||||
static bool twi_write_start(void) {
|
||||
SCL_HIGH();
|
||||
SDA_HIGH();
|
||||
if (SDA_READ() == 0)
|
||||
{
|
||||
if (SDA_READ() == 0) {
|
||||
return false;
|
||||
}
|
||||
twi_delay(twi_dcount);
|
||||
@ -245,8 +197,7 @@ extern "C" {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool twi_write_stop(void)
|
||||
{
|
||||
static bool twi_write_stop(void){
|
||||
uint32_t i = 0;
|
||||
SCL_LOW();
|
||||
SDA_LOW();
|
||||
@ -259,18 +210,11 @@ extern "C" {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool twi_write_bit(bool bit)
|
||||
{
|
||||
static bool twi_write_bit(bool bit) {
|
||||
uint32_t i = 0;
|
||||
SCL_LOW();
|
||||
if (bit)
|
||||
{
|
||||
SDA_HIGH();
|
||||
}
|
||||
else
|
||||
{
|
||||
SDA_LOW();
|
||||
}
|
||||
if (bit) SDA_HIGH();
|
||||
else SDA_LOW();
|
||||
twi_delay(twi_dcount+1);
|
||||
SCL_HIGH();
|
||||
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching
|
||||
@ -278,8 +222,7 @@ extern "C" {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool twi_read_bit(void)
|
||||
{
|
||||
static bool twi_read_bit(void) {
|
||||
uint32_t i = 0;
|
||||
SCL_LOW();
|
||||
SDA_HIGH();
|
||||
@ -291,62 +234,39 @@ extern "C" {
|
||||
return bit;
|
||||
}
|
||||
|
||||
static bool twi_write_byte(unsigned char byte)
|
||||
{
|
||||
static bool twi_write_byte(unsigned char byte) {
|
||||
unsigned char bit;
|
||||
for (bit = 0; bit < 8; bit++)
|
||||
{
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
twi_write_bit(byte & 0x80);
|
||||
byte <<= 1;
|
||||
}
|
||||
return !twi_read_bit();//NACK/ACK
|
||||
}
|
||||
|
||||
static unsigned char twi_read_byte(bool nack)
|
||||
{
|
||||
static unsigned char twi_read_byte(bool nack) {
|
||||
unsigned char byte = 0;
|
||||
unsigned char bit;
|
||||
for (bit = 0; bit < 8; bit++)
|
||||
{
|
||||
byte = (byte << 1) | twi_read_bit();
|
||||
}
|
||||
for (bit = 0; bit < 8; bit++) byte = (byte << 1) | twi_read_bit();
|
||||
twi_write_bit(nack);
|
||||
return byte;
|
||||
}
|
||||
|
||||
unsigned char twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop)
|
||||
{
|
||||
unsigned char twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop){
|
||||
unsigned int i;
|
||||
if (!twi_write_start())
|
||||
{
|
||||
return 4; //line busy
|
||||
}
|
||||
if (!twi_write_byte(((address << 1) | 0) & 0xFF))
|
||||
{
|
||||
if (sendStop)
|
||||
{
|
||||
twi_write_stop();
|
||||
}
|
||||
if(!twi_write_start()) return 4;//line busy
|
||||
if(!twi_write_byte(((address << 1) | 0) & 0xFF)) {
|
||||
if (sendStop) twi_write_stop();
|
||||
return 2; //received NACK on transmit of address
|
||||
}
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (!twi_write_byte(buf[i]))
|
||||
{
|
||||
if (sendStop)
|
||||
{
|
||||
twi_write_stop();
|
||||
}
|
||||
for(i=0; i<len; i++) {
|
||||
if(!twi_write_byte(buf[i])) {
|
||||
if (sendStop) twi_write_stop();
|
||||
return 3;//received NACK on transmit of data
|
||||
}
|
||||
}
|
||||
if (sendStop)
|
||||
{
|
||||
twi_write_stop();
|
||||
}
|
||||
if(sendStop) twi_write_stop();
|
||||
i = 0;
|
||||
while (SDA_READ() == 0 && (i++) < 10)
|
||||
{
|
||||
while(SDA_READ() == 0 && (i++) < 10){
|
||||
SCL_LOW();
|
||||
twi_delay(twi_dcount);
|
||||
SCL_HIGH();
|
||||
@ -356,33 +276,18 @@ extern "C" {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop)
|
||||
{
|
||||
unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop){
|
||||
unsigned int i;
|
||||
if (!twi_write_start())
|
||||
{
|
||||
return 4; //line busy
|
||||
}
|
||||
if (!twi_write_byte(((address << 1) | 1) & 0xFF))
|
||||
{
|
||||
if (sendStop)
|
||||
{
|
||||
twi_write_stop();
|
||||
}
|
||||
if(!twi_write_start()) return 4;//line busy
|
||||
if(!twi_write_byte(((address << 1) | 1) & 0xFF)) {
|
||||
if (sendStop) twi_write_stop();
|
||||
return 2;//received NACK on transmit of address
|
||||
}
|
||||
for (i = 0; i < (len - 1); i++)
|
||||
{
|
||||
buf[i] = twi_read_byte(false);
|
||||
}
|
||||
for(i=0; i<(len-1); i++) buf[i] = twi_read_byte(false);
|
||||
buf[len-1] = twi_read_byte(true);
|
||||
if (sendStop)
|
||||
{
|
||||
twi_write_stop();
|
||||
}
|
||||
if(sendStop) twi_write_stop();
|
||||
i = 0;
|
||||
while (SDA_READ() == 0 && (i++) < 10)
|
||||
{
|
||||
while(SDA_READ() == 0 && (i++) < 10){
|
||||
SCL_LOW();
|
||||
twi_delay(twi_dcount);
|
||||
SCL_HIGH();
|
||||
@ -392,31 +297,22 @@ extern "C" {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t twi_status()
|
||||
{
|
||||
uint8_t twi_status() {
|
||||
if (SCL_READ() == 0)
|
||||
{
|
||||
return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to recover
|
||||
}
|
||||
|
||||
int clockCount = 20;
|
||||
while (SDA_READ() == 0 && clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max
|
||||
{
|
||||
while (SDA_READ() == 0 && clockCount-- > 0) { // if SDA low, read the bits slaves have to sent to a max
|
||||
twi_read_bit();
|
||||
if (SCL_READ() == 0)
|
||||
{
|
||||
if (SCL_READ() == 0) {
|
||||
return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time
|
||||
}
|
||||
}
|
||||
if (SDA_READ() == 0)
|
||||
{
|
||||
return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits.
|
||||
}
|
||||
|
||||
if (!twi_write_start())
|
||||
{
|
||||
return I2C_SDA_HELD_LOW_AFTER_INIT; // line busy. SDA again held low by another device. 2nd master?
|
||||
}
|
||||
|
||||
return I2C_OK;
|
||||
}
|
||||
@ -426,21 +322,18 @@ extern "C" {
|
||||
uint8_t i;
|
||||
|
||||
// ensure data will fit into buffer
|
||||
if (length > TWI_BUFFER_LENGTH)
|
||||
{
|
||||
if (length > TWI_BUFFER_LENGTH) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ensure we are currently a slave transmitter
|
||||
if (twi_state != TWI_STX)
|
||||
{
|
||||
if (twi_state != TWI_STX) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// set length and copy data into tx buffer
|
||||
twi_txBufferLength = length;
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
for (i = 0; i < length; ++i) {
|
||||
twi_txBuffer[i] = data[i];
|
||||
}
|
||||
|
||||
@ -460,14 +353,11 @@ extern "C" {
|
||||
void ICACHE_RAM_ATTR twi_reply(uint8_t ack)
|
||||
{
|
||||
// transmit master read ready signal, with or without ack
|
||||
if (ack)
|
||||
{
|
||||
if (ack) {
|
||||
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
|
||||
SCL_HIGH(); // _BV(TWINT)
|
||||
twi_ack = 1; // _BV(TWEA)
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
|
||||
SCL_HIGH(); // _BV(TWINT)
|
||||
twi_ack = 0; // ~_BV(TWEA)
|
||||
@ -501,8 +391,7 @@ extern "C" {
|
||||
|
||||
void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
switch(status) {
|
||||
// Slave Receiver
|
||||
case TW_SR_SLA_ACK: // addressed, returned ack
|
||||
case TW_SR_GCALL_ACK: // addressed generally, returned ack
|
||||
@ -517,22 +406,18 @@ extern "C" {
|
||||
case TW_SR_DATA_ACK: // data received, returned ack
|
||||
case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
|
||||
// if there is still room in the rx buffer
|
||||
if (twi_rxBufferIndex < TWI_BUFFER_LENGTH)
|
||||
{
|
||||
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
|
||||
// put byte in buffer and ack
|
||||
twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
|
||||
twi_reply(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
}else{
|
||||
// otherwise nack
|
||||
twi_reply(0);
|
||||
}
|
||||
break;
|
||||
case TW_SR_STOP: // stop or repeated start condition received
|
||||
// put a null char after data if there's room
|
||||
if (twi_rxBufferIndex < TWI_BUFFER_LENGTH)
|
||||
{
|
||||
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
|
||||
twi_rxBuffer[twi_rxBufferIndex] = '\0';
|
||||
}
|
||||
// callback to user-defined callback over event task to allow for non-RAM-residing code
|
||||
@ -574,12 +459,9 @@ extern "C" {
|
||||
twi_data <<= 1;
|
||||
|
||||
// if there is more to send, ack, otherwise nack
|
||||
if (twi_txBufferIndex < twi_txBufferLength)
|
||||
{
|
||||
if(twi_txBufferIndex < twi_txBufferLength){
|
||||
twi_reply(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
}else{
|
||||
twi_reply(0);
|
||||
}
|
||||
break;
|
||||
@ -612,8 +494,7 @@ extern "C" {
|
||||
static void eventTask(ETSEvent *e)
|
||||
{
|
||||
|
||||
if (e == NULL)
|
||||
{
|
||||
if (e == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -623,8 +504,7 @@ extern "C" {
|
||||
twi_onSlaveTransmit();
|
||||
|
||||
// if they didn't change buffer & length, initialize it
|
||||
if (twi_txBufferLength == 0)
|
||||
{
|
||||
if (twi_txBufferLength == 0) {
|
||||
twi_txBufferLength = 1;
|
||||
twi_txBuffer[0] = 0x00;
|
||||
}
|
||||
@ -664,53 +544,35 @@ extern "C" {
|
||||
case TWIP_REP_START:
|
||||
case TWIP_SLA_W:
|
||||
case TWIP_READ:
|
||||
if (!scl)
|
||||
{
|
||||
if (!scl) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
bitCount--;
|
||||
twi_data <<= 1;
|
||||
twi_data |= sda;
|
||||
|
||||
if (bitCount != 0)
|
||||
{
|
||||
if (bitCount != 0) {
|
||||
// continue
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
twip_state = TWIP_SEND_ACK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TWIP_SEND_ACK:
|
||||
if (scl)
|
||||
{
|
||||
if (scl) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
if (twip_mode == TWIPM_IDLE)
|
||||
{
|
||||
if ((twi_data & 0xFE) != twi_addr)
|
||||
{
|
||||
} else {
|
||||
if (twip_mode == TWIPM_IDLE) {
|
||||
if ((twi_data & 0xFE) != twi_addr) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SDA_LOW();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!twi_ack)
|
||||
{
|
||||
} else {
|
||||
if (!twi_ack) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SDA_LOW();
|
||||
}
|
||||
}
|
||||
@ -719,52 +581,37 @@ extern "C" {
|
||||
break;
|
||||
|
||||
case TWIP_WAIT_ACK:
|
||||
if (scl)
|
||||
{
|
||||
if (scl) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
if (twip_mode == TWIPM_IDLE)
|
||||
{
|
||||
if ((twi_data & 0xFE) != twi_addr)
|
||||
{
|
||||
} else {
|
||||
if (twip_mode == TWIPM_IDLE) {
|
||||
if ((twi_data & 0xFE) != twi_addr) {
|
||||
SDA_HIGH();
|
||||
twip_state = TWIP_WAIT_STOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SCL_LOW(); // clock stretching
|
||||
SDA_HIGH();
|
||||
twip_mode = TWIPM_ADDRESSED;
|
||||
if (!(twi_data & 0x01))
|
||||
{
|
||||
if (!(twi_data & 0x01)) {
|
||||
twip_status = TW_SR_SLA_ACK;
|
||||
twi_onTwipEvent(twip_status);
|
||||
bitCount = 8;
|
||||
twip_state = TWIP_SLA_W;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
twip_status = TW_ST_SLA_ACK;
|
||||
twi_onTwipEvent(twip_status);
|
||||
twip_state = TWIP_SLA_R;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SCL_LOW(); // clock stretching
|
||||
SDA_HIGH();
|
||||
if (!twi_ack)
|
||||
{
|
||||
if (!twi_ack) {
|
||||
twip_status = TW_SR_DATA_NACK;
|
||||
twi_onTwipEvent(twip_status);
|
||||
twip_mode = TWIPM_WAIT;
|
||||
twip_state = TWIP_WAIT_STOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
twip_status = TW_SR_DATA_ACK;
|
||||
twi_onTwipEvent(twip_status);
|
||||
bitCount = 8;
|
||||
@ -776,67 +623,49 @@ extern "C" {
|
||||
|
||||
case TWIP_SLA_R:
|
||||
case TWIP_WRITE:
|
||||
if (scl)
|
||||
{
|
||||
if (scl) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
bitCount--;
|
||||
(twi_data & 0x80) ? SDA_HIGH() : SDA_LOW();
|
||||
twi_data <<= 1;
|
||||
|
||||
if (bitCount != 0)
|
||||
{
|
||||
if (bitCount != 0) {
|
||||
// continue
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
twip_state = TWIP_REC_ACK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TWIP_REC_ACK:
|
||||
if (scl)
|
||||
{
|
||||
if (scl) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SDA_HIGH();
|
||||
twip_state = TWIP_READ_ACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case TWIP_READ_ACK:
|
||||
if (!scl)
|
||||
{
|
||||
if (!scl) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
twi_ack_rec = !sda;
|
||||
twip_state = TWIP_RWAIT_ACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case TWIP_RWAIT_ACK:
|
||||
if (scl)
|
||||
{
|
||||
if (scl) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SCL_LOW(); // clock stretching
|
||||
if (twi_ack && twi_ack_rec)
|
||||
{
|
||||
if (twi_ack && twi_ack_rec) {
|
||||
twip_status = TW_ST_DATA_ACK;
|
||||
twi_onTwipEvent(twip_status);
|
||||
twip_state = TWIP_WRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// we have no more data to send and/or the master doesn't want anymore
|
||||
twip_status = twi_ack_rec ? TW_ST_LAST_DATA : TW_ST_DATA_NACK;
|
||||
twi_onTwipEvent(twip_status);
|
||||
@ -861,16 +690,11 @@ extern "C" {
|
||||
switch (twip_state)
|
||||
{
|
||||
case TWIP_IDLE:
|
||||
if (!scl)
|
||||
{
|
||||
if (!scl) {
|
||||
// DATA - ignore
|
||||
}
|
||||
else if (sda)
|
||||
{
|
||||
} else if (sda) {
|
||||
// STOP - ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// START
|
||||
bitCount = 8;
|
||||
twip_state = TWIP_START;
|
||||
@ -887,12 +711,9 @@ extern "C" {
|
||||
case TWIP_READ_ACK:
|
||||
case TWIP_RWAIT_ACK:
|
||||
case TWIP_WRITE:
|
||||
if (!scl)
|
||||
{
|
||||
if (!scl) {
|
||||
// DATA - ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// START or STOP
|
||||
SDA_HIGH(); // Should not be necessary
|
||||
twip_status = TW_BUS_ERROR;
|
||||
@ -904,30 +725,21 @@ extern "C" {
|
||||
|
||||
case TWIP_WAIT_STOP:
|
||||
case TWIP_BUS_ERR:
|
||||
if (!scl)
|
||||
{
|
||||
if (!scl) {
|
||||
// DATA - ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sda)
|
||||
{
|
||||
} else {
|
||||
if (sda) {
|
||||
// STOP
|
||||
SCL_LOW(); // clock stretching
|
||||
ets_timer_disarm(&timer);
|
||||
twip_state = TWIP_IDLE;
|
||||
twip_mode = TWIPM_IDLE;
|
||||
SCL_HIGH();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// START
|
||||
if (twip_state == TWIP_BUS_ERR)
|
||||
{
|
||||
if (twip_state == TWIP_BUS_ERR) {
|
||||
// ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
bitCount = 8;
|
||||
twip_state = TWIP_REP_START;
|
||||
ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms
|
||||
@ -938,36 +750,27 @@ extern "C" {
|
||||
|
||||
case TWIP_SLA_W:
|
||||
case TWIP_READ:
|
||||
if (!scl)
|
||||
{
|
||||
if (!scl) {
|
||||
// DATA - ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// START or STOP
|
||||
if (bitCount != 7)
|
||||
{
|
||||
if (bitCount != 7) {
|
||||
// inside byte transfer - error
|
||||
twip_status = TW_BUS_ERROR;
|
||||
twi_onTwipEvent(twip_status);
|
||||
twip_mode = TWIPM_WAIT;
|
||||
twip_state = TWIP_BUS_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// during first bit in byte transfer - ok
|
||||
SCL_LOW(); // clock stretching
|
||||
twip_status = TW_SR_STOP;
|
||||
twi_onTwipEvent(twip_status);
|
||||
if (sda)
|
||||
{
|
||||
if (sda) {
|
||||
// STOP
|
||||
ets_timer_disarm(&timer);
|
||||
twip_state = TWIP_IDLE;
|
||||
twip_mode = TWIPM_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// START
|
||||
bitCount = 8;
|
||||
ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms
|
||||
|
@ -32,10 +32,10 @@ extern "C" {
|
||||
void sigmaDeltaSetPrescaler(uint8_t prescaler); // avoids compiler warning
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaEnable
|
||||
Description : enable the internal sigma delta source
|
||||
Parameters : none
|
||||
Returns : none
|
||||
* FunctionName : sigmaDeltaEnable
|
||||
* Description : enable the internal sigma delta source
|
||||
* Parameters : none
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR sigmaDeltaEnable()
|
||||
{
|
||||
@ -43,10 +43,10 @@ extern "C" {
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaDisable
|
||||
Description : stop the internal sigma delta source
|
||||
Parameters : none
|
||||
Returns : none
|
||||
* FunctionName : sigmaDeltaDisable
|
||||
* Description : stop the internal sigma delta source
|
||||
* Parameters : none
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR sigmaDeltaDisable()
|
||||
{
|
||||
@ -54,63 +54,58 @@ extern "C" {
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaAttachPin
|
||||
Description : connects the sigma delta source to a physical output pin
|
||||
Parameters : pin (0..15), channel = unused, for compatibility with ESP32
|
||||
Returns : none
|
||||
* FunctionName : sigmaDeltaAttachPin
|
||||
* Description : connects the sigma delta source to a physical output pin
|
||||
* Parameters : pin (0..15), channel = unused, for compatibility with ESP32
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR sigmaDeltaAttachPin(uint8_t pin, uint8_t channel)
|
||||
{
|
||||
(void) channel;
|
||||
// make the chosen pin an output pin
|
||||
pinMode (pin, OUTPUT);
|
||||
if (pin < 16)
|
||||
{
|
||||
if (pin < 16) {
|
||||
// set its source to the sigma delta source
|
||||
GPC(pin) |= (1 << GPCS); //SOURCE 0:GPIO_DATA,1:SigmaDelta
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaDetachPin
|
||||
Description : disconnects the sigma delta source from a physical output pin
|
||||
Parameters : pin (0..16)
|
||||
Returns : none
|
||||
* FunctionName : sigmaDeltaDetachPin
|
||||
* Description : disconnects the sigma delta source from a physical output pin
|
||||
* Parameters : pin (0..16)
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR sigmaDeltaDetachPin(uint8_t pin)
|
||||
{
|
||||
if (pin < 16)
|
||||
{
|
||||
if (pin < 16) {
|
||||
// set its source to the sigma delta source
|
||||
GPC(pin) &= ~(1 << GPCS); //SOURCE 0:GPIO_DATA,1:SigmaDelta
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaIsPinAttached
|
||||
Description : query if pin is attached
|
||||
Parameters : pin (0..16)
|
||||
Returns : bool
|
||||
* FunctionName : sigmaDeltaIsPinAttached
|
||||
* Description : query if pin is attached
|
||||
* Parameters : pin (0..16)
|
||||
* Returns : bool
|
||||
*******************************************************************************/
|
||||
bool ICACHE_FLASH_ATTR sigmaDeltaIsPinAttached(uint8_t pin)
|
||||
{
|
||||
if (pin < 16)
|
||||
{
|
||||
if (pin < 16) {
|
||||
// set its source to the sigma delta source
|
||||
return (GPC(pin) & (1 << GPCS)); //SOURCE 0:GPIO_DATA,1:SigmaDelta
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaSetup
|
||||
Description : start the sigma delta generator with the chosen parameters
|
||||
Parameters : channel = unused (for compatibility with ESP32),
|
||||
freq : 1220-312500 (lowest frequency in the output signal's spectrum)
|
||||
Returns : uint32_t the actual frequency, closest to the input parameter
|
||||
* FunctionName : sigmaDeltaSetup
|
||||
* Description : start the sigma delta generator with the chosen parameters
|
||||
* Parameters : channel = unused (for compatibility with ESP32),
|
||||
* freq : 1220-312500 (lowest frequency in the output signal's spectrum)
|
||||
* Returns : uint32_t the actual frequency, closest to the input parameter
|
||||
*******************************************************************************/
|
||||
uint32_t ICACHE_FLASH_ATTR sigmaDeltaSetup(uint8_t channel, uint32_t freq)
|
||||
{
|
||||
@ -118,8 +113,7 @@ extern "C" {
|
||||
|
||||
uint32_t prescaler = ((uint32_t)10000000/(freq*32)) - 1;
|
||||
|
||||
if (prescaler > 0xFF)
|
||||
{
|
||||
if(prescaler > 0xFF) {
|
||||
prescaler = 0xFF;
|
||||
}
|
||||
sigmaDeltaEnable();
|
||||
@ -129,11 +123,11 @@ extern "C" {
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaWrite
|
||||
Description : set the duty cycle for the sigma-delta source
|
||||
Parameters : uint8 duty, 0-255, duty cycle = target/256,
|
||||
channel = unused, for compatibility with ESP32
|
||||
Returns : none
|
||||
* FunctionName : sigmaDeltaWrite
|
||||
* Description : set the duty cycle for the sigma-delta source
|
||||
* Parameters : uint8 duty, 0-255, duty cycle = target/256,
|
||||
* channel = unused, for compatibility with ESP32
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR sigmaDeltaWrite(uint8_t channel, uint8_t duty)
|
||||
{
|
||||
@ -145,10 +139,10 @@ extern "C" {
|
||||
|
||||
}
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaRead
|
||||
Description : get the duty cycle for the sigma-delta source
|
||||
Parameters : channel = unused, for compatibility with ESP32
|
||||
Returns : uint8_t duty cycle value 0..255
|
||||
* FunctionName : sigmaDeltaRead
|
||||
* Description : get the duty cycle for the sigma-delta source
|
||||
* Parameters : channel = unused, for compatibility with ESP32
|
||||
* Returns : uint8_t duty cycle value 0..255
|
||||
*******************************************************************************/
|
||||
uint8_t ICACHE_FLASH_ATTR sigmaDeltaRead(uint8_t channel)
|
||||
{
|
||||
@ -157,10 +151,10 @@ extern "C" {
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaSetPrescaler
|
||||
Description : set the clock divider for the sigma-delta source
|
||||
Parameters : uint8 prescaler, 0-255, divides the 80MHz base clock by this amount
|
||||
Returns : none
|
||||
* FunctionName : sigmaDeltaSetPrescaler
|
||||
* Description : set the clock divider for the sigma-delta source
|
||||
* Parameters : uint8 prescaler, 0-255, divides the 80MHz base clock by this amount
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR sigmaDeltaSetPrescaler(uint8_t prescaler)
|
||||
{
|
||||
@ -171,10 +165,10 @@ extern "C" {
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
FunctionName : sigmaDeltaGetPrescaler
|
||||
Description : get the prescaler value from the GPIO_SIGMA_DELTA register
|
||||
Parameters : none
|
||||
Returns : uint8 prescaler, CLK_DIV , 0-255
|
||||
* FunctionName : sigmaDeltaGetPrescaler
|
||||
* Description : get the prescaler value from the GPIO_SIGMA_DELTA register
|
||||
* Parameters : none
|
||||
* Returns : uint8 prescaler, CLK_DIV , 0-255
|
||||
*******************************************************************************/
|
||||
uint8_t ICACHE_FLASH_ATTR sigmaDeltaGetPrescaler(void)
|
||||
{
|
||||
|
@ -31,16 +31,11 @@ extern "C" {
|
||||
|
||||
static volatile timercallback timer1_user_cb = NULL;
|
||||
|
||||
void ICACHE_RAM_ATTR timer1_isr_handler(void *para)
|
||||
{
|
||||
void ICACHE_RAM_ATTR timer1_isr_handler(void *para){
|
||||
(void) para;
|
||||
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0)
|
||||
{
|
||||
TEIE &= ~TEIE1; //edge int disable
|
||||
}
|
||||
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
|
||||
T1I = 0;
|
||||
if (timer1_user_cb)
|
||||
{
|
||||
if (timer1_user_cb) {
|
||||
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
||||
// we disable them before we call the client ISR
|
||||
uint32_t savedPS = xt_rsil(15); // stop other interrupts
|
||||
@ -49,41 +44,32 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR timer1_isr_init()
|
||||
{
|
||||
void ICACHE_RAM_ATTR timer1_isr_init(){
|
||||
ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL);
|
||||
}
|
||||
|
||||
void timer1_attachInterrupt(timercallback userFunc)
|
||||
{
|
||||
void timer1_attachInterrupt(timercallback userFunc) {
|
||||
timer1_user_cb = userFunc;
|
||||
ETS_FRC1_INTR_ENABLE();
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR timer1_detachInterrupt()
|
||||
{
|
||||
void ICACHE_RAM_ATTR timer1_detachInterrupt() {
|
||||
timer1_user_cb = 0;
|
||||
TEIE &= ~TEIE1;//edge int disable
|
||||
ETS_FRC1_INTR_DISABLE();
|
||||
}
|
||||
|
||||
void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload)
|
||||
{
|
||||
void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload){
|
||||
T1C = (1 << TCTE) | ((divider & 3) << TCPD) | ((int_type & 1) << TCIT) | ((reload & 1) << TCAR);
|
||||
T1I = 0;
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR timer1_write(uint32_t ticks)
|
||||
{
|
||||
void ICACHE_RAM_ATTR timer1_write(uint32_t ticks){
|
||||
T1L = ((ticks)& 0x7FFFFF);
|
||||
if ((T1C & (1 << TCIT)) == 0)
|
||||
{
|
||||
TEIE |= TEIE1; //edge int enable
|
||||
}
|
||||
if ((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR timer1_disable()
|
||||
{
|
||||
void ICACHE_RAM_ATTR timer1_disable(){
|
||||
T1C = 0;
|
||||
T1I = 0;
|
||||
}
|
||||
@ -93,11 +79,9 @@ extern "C" {
|
||||
|
||||
static volatile timercallback timer0_user_cb = NULL;
|
||||
|
||||
void ICACHE_RAM_ATTR timer0_isr_handler(void* para)
|
||||
{
|
||||
void ICACHE_RAM_ATTR timer0_isr_handler(void* para){
|
||||
(void) para;
|
||||
if (timer0_user_cb)
|
||||
{
|
||||
if (timer0_user_cb) {
|
||||
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
||||
// we disable them before we call the client ISR
|
||||
uint32_t savedPS = xt_rsil(15); // stop other interrupts
|
||||
@ -106,19 +90,16 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
void timer0_isr_init()
|
||||
{
|
||||
void timer0_isr_init(){
|
||||
ETS_CCOMPARE0_INTR_ATTACH(timer0_isr_handler, NULL);
|
||||
}
|
||||
|
||||
void timer0_attachInterrupt(timercallback userFunc)
|
||||
{
|
||||
void timer0_attachInterrupt(timercallback userFunc) {
|
||||
timer0_user_cb = userFunc;
|
||||
ETS_CCOMPARE0_ENABLE();
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR timer0_detachInterrupt()
|
||||
{
|
||||
void ICACHE_RAM_ATTR timer0_detachInterrupt() {
|
||||
timer0_user_cb = NULL;
|
||||
ETS_CCOMPARE0_DISABLE();
|
||||
}
|
||||
|
@ -86,8 +86,7 @@ extern "C++"
|
||||
template<unsigned N> constexpr
|
||||
int atoi (const char (&arr) [N], unsigned i)
|
||||
{
|
||||
return ( // <= c++11 requires a "return statement"
|
||||
{
|
||||
return ({ // <= c++11 requires a "return statement"
|
||||
int ret = 0;
|
||||
int sign = 1;
|
||||
if (arr[i] == '-')
|
||||
@ -104,15 +103,12 @@ extern "C++"
|
||||
template<unsigned N> constexpr
|
||||
int parseNthInteger (const char (&arr) [N], unsigned f)
|
||||
{
|
||||
return ( // <= c++11 requires a "return statement"
|
||||
{
|
||||
return ({ // <= c++11 requires a "return statement"
|
||||
unsigned i = 0;
|
||||
while (f && arr[i])
|
||||
{
|
||||
if (isMinus(arr, i))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
for (; isDecimal(arr[i]); i++);
|
||||
f--;
|
||||
for (; arr[i] && !isMinus(arr, i) && !isDecimal(arr[i]); i++);
|
||||
@ -126,7 +122,7 @@ extern "C++"
|
||||
namespace esp8266 {
|
||||
|
||||
/*
|
||||
version major
|
||||
* version major
|
||||
*/
|
||||
constexpr
|
||||
int coreVersionMajor ()
|
||||
@ -135,7 +131,7 @@ extern "C++"
|
||||
}
|
||||
|
||||
/*
|
||||
version minor
|
||||
* version minor
|
||||
*/
|
||||
constexpr
|
||||
int coreVersionMinor ()
|
||||
@ -144,7 +140,7 @@ extern "C++"
|
||||
}
|
||||
|
||||
/*
|
||||
version revision
|
||||
* version revision
|
||||
*/
|
||||
constexpr
|
||||
int coreVersionRevision ()
|
||||
@ -153,8 +149,8 @@ extern "C++"
|
||||
}
|
||||
|
||||
/*
|
||||
git commit number since last tag (negative)
|
||||
or RC-number (positive)
|
||||
* git commit number since last tag (negative)
|
||||
* or RC-number (positive)
|
||||
*/
|
||||
constexpr
|
||||
int coreVersionSubRevision ()
|
||||
@ -163,7 +159,7 @@ extern "C++"
|
||||
}
|
||||
|
||||
/*
|
||||
unique revision indentifier (never decreases)
|
||||
* unique revision indentifier (never decreases)
|
||||
*/
|
||||
constexpr
|
||||
int coreVersionNumeric ()
|
||||
|
@ -51,8 +51,7 @@ extern "C" {
|
||||
#define ClearGPIO(a) do { GPOC = a; } while (0)
|
||||
|
||||
// Waveform generator can create tones, PWM, and servos
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint32_t nextServiceCycle; // ESP cycle timer when a transition required
|
||||
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
|
||||
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
|
||||
@ -73,8 +72,7 @@ extern "C" {
|
||||
// Non-speed critical bits
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCount()
|
||||
{
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCount() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
@ -84,8 +82,7 @@ extern "C" {
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt();
|
||||
static bool timerRunning = false;
|
||||
|
||||
static void initTimer()
|
||||
{
|
||||
static void initTimer() {
|
||||
timer1_disable();
|
||||
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
||||
@ -93,8 +90,7 @@ extern "C" {
|
||||
timerRunning = true;
|
||||
}
|
||||
|
||||
static void ICACHE_RAM_ATTR deinitTimer()
|
||||
{
|
||||
static void ICACHE_RAM_ATTR deinitTimer() {
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||
timer1_disable();
|
||||
timer1_isr_init();
|
||||
@ -102,16 +98,12 @@ extern "C" {
|
||||
}
|
||||
|
||||
// Set a callback. Pass in NULL to stop it
|
||||
void setTimer1Callback(uint32_t (*fn)())
|
||||
{
|
||||
void setTimer1Callback(uint32_t (*fn)()) {
|
||||
timer1CB = fn;
|
||||
if (!timerRunning && fn)
|
||||
{
|
||||
if (!timerRunning && fn) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
|
||||
}
|
||||
else if (timerRunning && !fn && !waveformEnabled)
|
||||
{
|
||||
} else if (timerRunning && !fn && !waveformEnabled) {
|
||||
deinitTimer();
|
||||
}
|
||||
}
|
||||
@ -119,10 +111,8 @@ extern "C" {
|
||||
// Start up a waveform on a pin, or change the current one. Will change to the new
|
||||
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
|
||||
// first, then it will immediately begin.
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS)
|
||||
{
|
||||
if ((pin > 16) || isFlashInterfacePin(pin))
|
||||
{
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
|
||||
if ((pin > 16) || isFlashInterfacePin(pin)) {
|
||||
return false;
|
||||
}
|
||||
Waveform *wave = &waveform[pin];
|
||||
@ -130,32 +120,25 @@ extern "C" {
|
||||
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
|
||||
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
|
||||
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
|
||||
if (runTimeUS && !wave->expiryCycle)
|
||||
{
|
||||
if (runTimeUS && !wave->expiryCycle) {
|
||||
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
||||
}
|
||||
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask))
|
||||
{
|
||||
if (!(waveformEnabled & mask)) {
|
||||
// Actually set the pin high or low in the IRQ service to guarantee times
|
||||
wave->nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1);
|
||||
waveformToEnable |= mask;
|
||||
if (!timerRunning)
|
||||
{
|
||||
if (!timerRunning) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10))
|
||||
{
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
}
|
||||
while (waveformToEnable)
|
||||
{
|
||||
while (waveformToEnable) {
|
||||
delay(0); // Wait for waveform to update
|
||||
}
|
||||
}
|
||||
@ -169,49 +152,40 @@ extern "C" {
|
||||
// optimization levels the inline attribute gets lost if we try the
|
||||
// other version.
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ()
|
||||
{
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a < b)
|
||||
{
|
||||
static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) {
|
||||
if (a < b) {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Stops a waveform on a pin
|
||||
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin)
|
||||
{
|
||||
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
|
||||
// Can't possibly need to stop anything if there is no timer active
|
||||
if (!timerRunning)
|
||||
{
|
||||
if (!timerRunning) {
|
||||
return false;
|
||||
}
|
||||
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
||||
// If they send >=32, then the shift will result in 0 and it will also return false
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask))
|
||||
{
|
||||
if (!(waveformEnabled & mask)) {
|
||||
return false; // It's not running, nothing to do here
|
||||
}
|
||||
waveformToDisable |= mask;
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10))
|
||||
{
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
while (waveformToDisable)
|
||||
{
|
||||
while (waveformToDisable) {
|
||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||
}
|
||||
if (!waveformEnabled && !timer1CB)
|
||||
{
|
||||
if (!waveformEnabled && !timer1CB) {
|
||||
deinitTimer();
|
||||
}
|
||||
return true;
|
||||
@ -227,8 +201,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt()
|
||||
{
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt() {
|
||||
// Optimize the NMI inner loop by keeping track of the min and max GPIO that we
|
||||
// are generating. In the common case (1 PWM) these may be the same pin and
|
||||
// we can avoid looking at the other pins.
|
||||
@ -238,8 +211,7 @@ extern "C" {
|
||||
uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14);
|
||||
|
||||
if (waveformToEnable || waveformToDisable)
|
||||
{
|
||||
if (waveformToEnable || waveformToDisable) {
|
||||
// Handle enable/disable requests from main app.
|
||||
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
|
||||
waveformState &= ~waveformToEnable; // And clear the state of any just started
|
||||
@ -252,18 +224,14 @@ extern "C" {
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
if (waveformEnabled)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (waveformEnabled) {
|
||||
do {
|
||||
nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
for (int i = startPin; i <= endPin; i++)
|
||||
{
|
||||
for (int i = startPin; i <= endPin; i++) {
|
||||
uint32_t mask = 1<<i;
|
||||
|
||||
// If it's not on, ignore!
|
||||
if (!(waveformEnabled & mask))
|
||||
{
|
||||
if (!(waveformEnabled & mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -271,19 +239,14 @@ extern "C" {
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
|
||||
// Disable any waveforms that are done
|
||||
if (wave->expiryCycle)
|
||||
{
|
||||
if (wave->expiryCycle) {
|
||||
int32_t expiryToGo = wave->expiryCycle - now;
|
||||
if (expiryToGo < 0)
|
||||
{
|
||||
if (expiryToGo < 0) {
|
||||
// Done, remove!
|
||||
waveformEnabled &= ~mask;
|
||||
if (i == 16)
|
||||
{
|
||||
if (i == 16) {
|
||||
GP16O &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
continue;
|
||||
@ -292,38 +255,26 @@ extern "C" {
|
||||
|
||||
// Check for toggles
|
||||
int32_t cyclesToGo = wave->nextServiceCycle - now;
|
||||
if (cyclesToGo < 0)
|
||||
{
|
||||
if (cyclesToGo < 0) {
|
||||
waveformState ^= mask;
|
||||
if (waveformState & mask)
|
||||
{
|
||||
if (i == 16)
|
||||
{
|
||||
if (waveformState & mask) {
|
||||
if (i == 16) {
|
||||
GP16O |= 1; // GPIO16 write slow as it's RMW
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SetGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeHighCycles;
|
||||
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeHighCycles);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i == 16)
|
||||
{
|
||||
} else {
|
||||
if (i == 16) {
|
||||
GP16O &= ~1; // GPIO16 write slow as it's RMW
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeLowCycles;
|
||||
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeLowCycles);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint32_t deltaCycles = wave->nextServiceCycle - now;
|
||||
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
|
||||
}
|
||||
@ -337,13 +288,11 @@ extern "C" {
|
||||
} while (!done);
|
||||
} // if (waveformEnabled)
|
||||
|
||||
if (timer1CB)
|
||||
{
|
||||
if (timer1CB) {
|
||||
nextEventCycles = min_u32(nextEventCycles, timer1CB());
|
||||
}
|
||||
|
||||
if (nextEventCycles < microsecondsToClockCycles(10))
|
||||
{
|
||||
if (nextEventCycles < microsecondsToClockCycles(10)) {
|
||||
nextEventCycles = microsecondsToClockCycles(10);
|
||||
}
|
||||
nextEventCycles -= DELTAIRQ;
|
||||
|
@ -38,38 +38,29 @@ extern "C" {
|
||||
#define ONCE 0
|
||||
#define REPEAT 1
|
||||
|
||||
void delay_end(void* arg)
|
||||
{
|
||||
void delay_end(void* arg) {
|
||||
(void) arg;
|
||||
esp_schedule();
|
||||
}
|
||||
|
||||
void delay(unsigned long ms)
|
||||
{
|
||||
if (ms)
|
||||
{
|
||||
void delay(unsigned long ms) {
|
||||
if(ms) {
|
||||
os_timer_setfn(&delay_timer, (os_timer_func_t*) &delay_end, 0);
|
||||
os_timer_arm(&delay_timer, ms, ONCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
esp_schedule();
|
||||
}
|
||||
esp_yield();
|
||||
if (ms)
|
||||
{
|
||||
if(ms) {
|
||||
os_timer_disarm(&delay_timer);
|
||||
}
|
||||
}
|
||||
|
||||
void micros_overflow_tick(void* arg)
|
||||
{
|
||||
void micros_overflow_tick(void* arg) {
|
||||
(void) arg;
|
||||
uint32_t m = system_get_time();
|
||||
if(m < micros_at_last_overflow_tick)
|
||||
{
|
||||
++micros_overflow_count;
|
||||
}
|
||||
micros_at_last_overflow_tick = m;
|
||||
}
|
||||
|
||||
@ -172,8 +163,7 @@ extern "C" {
|
||||
|
||||
unsigned long ICACHE_RAM_ATTR millis()
|
||||
{
|
||||
union
|
||||
{
|
||||
union {
|
||||
uint64_t q; // Accumulator, 64-bit, little endian
|
||||
uint32_t a[2]; // ..........., 32-bit segments
|
||||
} acc;
|
||||
@ -202,26 +192,22 @@ extern "C" {
|
||||
|
||||
} //millis
|
||||
|
||||
unsigned long ICACHE_RAM_ATTR micros()
|
||||
{
|
||||
unsigned long ICACHE_RAM_ATTR micros() {
|
||||
return system_get_time();
|
||||
}
|
||||
|
||||
uint64_t ICACHE_RAM_ATTR micros64()
|
||||
{
|
||||
uint64_t ICACHE_RAM_ATTR micros64() {
|
||||
uint32_t low32_us = system_get_time();
|
||||
uint32_t high32_us = micros_overflow_count + ((low32_us < micros_at_last_overflow_tick) ? 1 : 0);
|
||||
uint64_t duration64_us = (uint64_t)high32_us << 32 | low32_us;
|
||||
return duration64_us;
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR delayMicroseconds(unsigned int us)
|
||||
{
|
||||
void ICACHE_RAM_ATTR delayMicroseconds(unsigned int us) {
|
||||
os_delay_us(us);
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
void init() {
|
||||
initPins();
|
||||
timer1_isr_init();
|
||||
os_timer_setfn(µs_overflow_timer, (os_timer_func_t*) µs_overflow_tick, 0);
|
||||
|
@ -31,8 +31,7 @@ extern "C" {
|
||||
extern int __analogRead(uint8_t pin)
|
||||
{
|
||||
// accept both A0 constant and ADC channel number
|
||||
if (pin == 17 || pin == 0)
|
||||
{
|
||||
if(pin == 17 || pin == 0) {
|
||||
return system_adc_read();
|
||||
}
|
||||
return digitalRead(pin) * 1023;
|
||||
|
@ -31,120 +31,70 @@ extern "C" {
|
||||
|
||||
uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x04, 0x08, 0x0C, 0x10};
|
||||
|
||||
extern void __pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
if (pin < 16)
|
||||
{
|
||||
if (mode == SPECIAL)
|
||||
{
|
||||
extern void __pinMode(uint8_t pin, uint8_t mode) {
|
||||
if(pin < 16){
|
||||
if(mode == SPECIAL){
|
||||
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
||||
GPEC = (1 << pin); //Disable
|
||||
GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin)
|
||||
if (pin == 3)
|
||||
{
|
||||
GPF(pin) |= (1 << GPFPU); //enable pullup on RX
|
||||
}
|
||||
}
|
||||
else if (mode & FUNCTION_0)
|
||||
{
|
||||
if(pin == 3) GPF(pin) |= (1 << GPFPU);//enable pullup on RX
|
||||
} else if(mode & FUNCTION_0){
|
||||
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
||||
GPEC = (1 << pin); //Disable
|
||||
GPF(pin) = GPFFS((mode >> 4) & 0x07);
|
||||
if (pin == 13 && mode == FUNCTION_4)
|
||||
{
|
||||
GPF(pin) |= (1 << GPFPU); //enable pullup on RX
|
||||
}
|
||||
}
|
||||
else if (mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN)
|
||||
{
|
||||
if(pin == 13 && mode == FUNCTION_4) GPF(pin) |= (1 << GPFPU);//enable pullup on RX
|
||||
} else if(mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN){
|
||||
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
||||
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
||||
if (mode == OUTPUT_OPEN_DRAIN)
|
||||
{
|
||||
GPC(pin) |= (1 << GPCD);
|
||||
}
|
||||
if(mode == OUTPUT_OPEN_DRAIN) GPC(pin) |= (1 << GPCD);
|
||||
GPES = (1 << pin); //Enable
|
||||
}
|
||||
else if (mode == INPUT || mode == INPUT_PULLUP)
|
||||
{
|
||||
} else if(mode == INPUT || mode == INPUT_PULLUP){
|
||||
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
||||
GPEC = (1 << pin); //Disable
|
||||
GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
||||
if (mode == INPUT_PULLUP)
|
||||
{
|
||||
if(mode == INPUT_PULLUP) {
|
||||
GPF(pin) |= (1 << GPFPU); // Enable Pullup
|
||||
}
|
||||
}
|
||||
else if (mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN)
|
||||
{
|
||||
} else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){
|
||||
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
||||
GPEC = (1 << pin); //Disable
|
||||
if (mode == WAKEUP_PULLUP)
|
||||
{
|
||||
if(mode == WAKEUP_PULLUP) {
|
||||
GPF(pin) |= (1 << GPFPU); // Enable Pullup
|
||||
GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED)
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
GPF(pin) |= (1 << GPFPD); // Enable Pulldown
|
||||
GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pin == 16)
|
||||
{
|
||||
} else if(pin == 16){
|
||||
GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
||||
GPC16 = 0;
|
||||
if (mode == INPUT || mode == INPUT_PULLDOWN_16)
|
||||
{
|
||||
if (mode == INPUT_PULLDOWN_16)
|
||||
{
|
||||
if(mode == INPUT || mode == INPUT_PULLDOWN_16){
|
||||
if(mode == INPUT_PULLDOWN_16){
|
||||
GPF16 |= (1 << GP16FPD);//Enable Pulldown
|
||||
}
|
||||
GP16E &= ~1;
|
||||
}
|
||||
else if (mode == OUTPUT)
|
||||
{
|
||||
} else if(mode == OUTPUT){
|
||||
GP16E |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val)
|
||||
{
|
||||
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) {
|
||||
stopWaveform(pin);
|
||||
if (pin < 16)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
GPOS = (1 << pin);
|
||||
}
|
||||
else
|
||||
{
|
||||
GPOC = (1 << pin);
|
||||
}
|
||||
}
|
||||
else if (pin == 16)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
GP16O |= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
GP16O &= ~1;
|
||||
}
|
||||
if(pin < 16){
|
||||
if(val) GPOS = (1 << pin);
|
||||
else GPOC = (1 << pin);
|
||||
} else if(pin == 16){
|
||||
if(val) GP16O |= 1;
|
||||
else GP16O &= ~1;
|
||||
}
|
||||
}
|
||||
|
||||
extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin)
|
||||
{
|
||||
if (pin < 16)
|
||||
{
|
||||
extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) {
|
||||
if(pin < 16){
|
||||
return GPIP(pin);
|
||||
}
|
||||
else if (pin == 16)
|
||||
{
|
||||
} else if(pin == 16){
|
||||
return GP16I & 0x01;
|
||||
}
|
||||
return 0;
|
||||
@ -157,23 +107,20 @@ extern "C" {
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
typedef void (*voidFuncPtrArg)(void*);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t mode;
|
||||
void (*fn)(void);
|
||||
void * arg;
|
||||
} interrupt_handler_t;
|
||||
|
||||
//duplicate from functionalInterrupt.h keep in sync
|
||||
typedef struct InterruptInfo
|
||||
{
|
||||
typedef struct InterruptInfo {
|
||||
uint8_t pin;
|
||||
uint8_t value;
|
||||
uint32_t micro;
|
||||
} InterruptInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
InterruptInfo* interruptInfo;
|
||||
void* functionInfo;
|
||||
} ArgStructure;
|
||||
@ -181,31 +128,22 @@ extern "C" {
|
||||
static interrupt_handler_t interrupt_handlers[16];
|
||||
static uint32_t interrupt_reg = 0;
|
||||
|
||||
void ICACHE_RAM_ATTR interrupt_handler(void *arg)
|
||||
{
|
||||
void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
|
||||
(void) arg;
|
||||
uint32_t status = GPIE;
|
||||
GPIEC = status;//clear them interrupts
|
||||
uint32_t levels = GPI;
|
||||
if (status == 0 || interrupt_reg == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(status == 0 || interrupt_reg == 0) return;
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
int i = 0;
|
||||
uint32_t changedbits = status & interrupt_reg;
|
||||
while (changedbits)
|
||||
{
|
||||
while (!(changedbits & (1 << i)))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
while(changedbits){
|
||||
while(!(changedbits & (1 << i))) i++;
|
||||
changedbits &= ~(1 << i);
|
||||
interrupt_handler_t *handler = &interrupt_handlers[i];
|
||||
if (handler->fn &&
|
||||
(handler->mode == CHANGE ||
|
||||
(handler->mode & 1) == !!(levels & (1 << i))))
|
||||
{
|
||||
(handler->mode & 1) == !!(levels & (1 << i)))) {
|
||||
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
||||
// we disable them before we call the client ISR
|
||||
uint32_t savedPS = xt_rsil(15); // stop other interrupts
|
||||
@ -232,8 +170,7 @@ extern "C" {
|
||||
|
||||
extern void cleanupFunctional(void* arg);
|
||||
|
||||
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode)
|
||||
{
|
||||
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) {
|
||||
|
||||
// #5780
|
||||
// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
|
||||
@ -244,8 +181,7 @@ extern "C" {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (pin < 16)
|
||||
{
|
||||
if(pin < 16) {
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
interrupt_handler_t *handler = &interrupt_handlers[pin];
|
||||
handler->mode = mode;
|
||||
@ -269,10 +205,8 @@ extern "C" {
|
||||
__attachInterruptArg (pin, userFunc, 0, mode);
|
||||
}
|
||||
|
||||
extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin)
|
||||
{
|
||||
if (pin < 16)
|
||||
{
|
||||
extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
|
||||
if(pin < 16) {
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
|
||||
GPIEC = (1 << pin); //Clear Interrupt for this pin
|
||||
@ -286,26 +220,21 @@ extern "C" {
|
||||
}
|
||||
handler->arg = 0;
|
||||
if (interrupt_reg)
|
||||
{
|
||||
ETS_GPIO_INTR_ENABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initPins()
|
||||
{
|
||||
void initPins() {
|
||||
//Disable UART interrupts
|
||||
system_set_os_print(0);
|
||||
U0IE = 0;
|
||||
U1IE = 0;
|
||||
|
||||
for (int i = 0; i <= 5; ++i)
|
||||
{
|
||||
for (int i = 0; i <= 5; ++i) {
|
||||
pinMode(i, INPUT);
|
||||
}
|
||||
// pins 6-11 are used for the SPI flash interface
|
||||
for (int i = 12; i <= 16; ++i)
|
||||
{
|
||||
for (int i = 12; i <= 16; ++i) {
|
||||
pinMode(i, INPUT);
|
||||
}
|
||||
}
|
||||
|
@ -38,8 +38,7 @@ extern "C" {
|
||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
{
|
||||
const uint32_t max_timeout_us = clockCyclesToMicroseconds(UINT_MAX);
|
||||
if (timeout > max_timeout_us)
|
||||
{
|
||||
if (timeout > max_timeout_us) {
|
||||
timeout = max_timeout_us;
|
||||
}
|
||||
const uint32_t timeout_cycles = microsecondsToClockCycles(timeout);
|
||||
|
@ -30,43 +30,30 @@ extern "C" {
|
||||
static int32_t analogScale = PWMRANGE;
|
||||
static uint16_t analogFreq = 1000;
|
||||
|
||||
extern void __analogWriteRange(uint32_t range)
|
||||
{
|
||||
if (range > 0)
|
||||
{
|
||||
extern void __analogWriteRange(uint32_t range) {
|
||||
if (range > 0) {
|
||||
analogScale = range;
|
||||
}
|
||||
}
|
||||
|
||||
extern void __analogWriteFreq(uint32_t freq)
|
||||
{
|
||||
if (freq < 100)
|
||||
{
|
||||
extern void __analogWriteFreq(uint32_t freq) {
|
||||
if (freq < 100) {
|
||||
analogFreq = 100;
|
||||
}
|
||||
else if (freq > 40000)
|
||||
{
|
||||
} else if (freq > 40000) {
|
||||
analogFreq = 40000;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
analogFreq = freq;
|
||||
}
|
||||
}
|
||||
|
||||
extern void __analogWrite(uint8_t pin, int val)
|
||||
{
|
||||
if (pin > 16)
|
||||
{
|
||||
extern void __analogWrite(uint8_t pin, int val) {
|
||||
if (pin > 16) {
|
||||
return;
|
||||
}
|
||||
uint32_t analogPeriod = 1000000L / analogFreq;
|
||||
if (val < 0)
|
||||
{
|
||||
if (val < 0) {
|
||||
val = 0;
|
||||
}
|
||||
else if (val > analogScale)
|
||||
{
|
||||
} else if (val > analogScale) {
|
||||
val = analogScale;
|
||||
}
|
||||
|
||||
@ -74,20 +61,14 @@ extern "C" {
|
||||
uint32_t high = (analogPeriod * val) / analogScale;
|
||||
uint32_t low = analogPeriod - high;
|
||||
pinMode(pin, OUTPUT);
|
||||
if (low == 0)
|
||||
{
|
||||
if (low == 0) {
|
||||
stopWaveform(pin);
|
||||
digitalWrite(pin, HIGH);
|
||||
}
|
||||
else if (high == 0)
|
||||
{
|
||||
} else if (high == 0) {
|
||||
stopWaveform(pin);
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startWaveform(pin, high, low, 0))
|
||||
{
|
||||
} else {
|
||||
if (startWaveform(pin, high, low, 0)) {
|
||||
analogMap |= (1 << pin);
|
||||
}
|
||||
}
|
||||
|
@ -28,41 +28,29 @@
|
||||
#include "wiring_private.h"
|
||||
extern "C" {
|
||||
|
||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder)
|
||||
{
|
||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
|
||||
uint8_t value = 0;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
for(i = 0; i < 8; ++i) {
|
||||
digitalWrite(clockPin, HIGH);
|
||||
if(bitOrder == LSBFIRST)
|
||||
{
|
||||
value |= digitalRead(dataPin) << i;
|
||||
}
|
||||
else
|
||||
{
|
||||
value |= digitalRead(dataPin) << (7 - i);
|
||||
}
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
|
||||
{
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) {
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
for(i = 0; i < 8; i++) {
|
||||
if(bitOrder == LSBFIRST)
|
||||
{
|
||||
digitalWrite(dataPin, !!(val & (1 << i)));
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
|
||||
}
|
||||
|
||||
digitalWrite(clockPin, HIGH);
|
||||
digitalWrite(clockPin, LOW);
|
||||
|
@ -21,14 +21,11 @@
|
||||
#include "Arduino.h"
|
||||
#include "debug.h"
|
||||
|
||||
void ICACHE_RAM_ATTR hexdump(const void *mem, uint32_t len, uint8_t cols)
|
||||
{
|
||||
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)
|
||||
{
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
os_printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
yield();
|
||||
}
|
||||
|
@ -9,8 +9,7 @@ extern "C" {
|
||||
|
||||
#define RTC_MEM ((volatile uint32_t*)0x60001200)
|
||||
|
||||
enum action_t
|
||||
{
|
||||
enum action_t {
|
||||
ACTION_COPY_RAW = 0x00000001,
|
||||
ACTION_LOAD_APP = 0xffffffff
|
||||
};
|
||||
@ -18,8 +17,7 @@ enum action_t
|
||||
#define EBOOT_MAGIC 0xeb001000
|
||||
#define EBOOT_MAGIC_MASK 0xfffff000
|
||||
|
||||
struct eboot_command
|
||||
{
|
||||
struct eboot_command {
|
||||
uint32_t magic;
|
||||
enum action_t action;
|
||||
uint32_t args[29];
|
||||
|
@ -27,8 +27,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Definitions are placed in eboot. Include them here rather than duplicate them.
|
||||
Also, prefer to have eboot standalone as much as possible and have the core depend on it
|
||||
rather than have eboot depend on the core.
|
||||
* Also, prefer to have eboot standalone as much as possible and have the core depend on it
|
||||
* rather than have eboot depend on the core.
|
||||
*/
|
||||
#include <../../bootloaders/eboot/flash.h>
|
||||
|
||||
|
@ -24,96 +24,96 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
@brief Initialize GDB stub, if present
|
||||
|
||||
By default, this function is a no-op. When GDBStub library is linked,
|
||||
this function is overriden and does necessary initialization of that library.
|
||||
Called early at startup.
|
||||
* @brief Initialize GDB stub, if present
|
||||
*
|
||||
* By default, this function is a no-op. When GDBStub library is linked,
|
||||
* this function is overriden and does necessary initialization of that library.
|
||||
* Called early at startup.
|
||||
*/
|
||||
void gdb_init(void);
|
||||
|
||||
/**
|
||||
@brief Break into GDB, if present
|
||||
|
||||
By default, this function is a no-op. When GDBStub library is linked,
|
||||
this function is overriden and triggers entry into the debugger, which
|
||||
looks like a breakpoint hit.
|
||||
* @brief Break into GDB, if present
|
||||
*
|
||||
* By default, this function is a no-op. When GDBStub library is linked,
|
||||
* this function is overriden and triggers entry into the debugger, which
|
||||
* looks like a breakpoint hit.
|
||||
*/
|
||||
void gdb_do_break(void);
|
||||
|
||||
/**
|
||||
@brief Check if GDB stub is present.
|
||||
|
||||
By default, this function returns false. When GDBStub library is linked,
|
||||
this function is overriden and returns true. Can be used to check whether
|
||||
GDB is used.
|
||||
|
||||
@return true if GDB stub is present
|
||||
* @brief Check if GDB stub is present.
|
||||
*
|
||||
* By default, this function returns false. When GDBStub library is linked,
|
||||
* this function is overriden and returns true. Can be used to check whether
|
||||
* GDB is used.
|
||||
*
|
||||
* @return true if GDB stub is present
|
||||
*/
|
||||
bool gdb_present(void);
|
||||
|
||||
// If gdbstub has these set true, then we will disable our own
|
||||
// usage of them, but use gdbstub's callbacks for them instead
|
||||
/**
|
||||
@brief Check if GDB is installing a putc1 callback.
|
||||
|
||||
By default, this function returns false. When GDBStub library is linked,
|
||||
this function is overriden and returns true.
|
||||
|
||||
@return true if GDB is installing a putc1 callback
|
||||
* @brief Check if GDB is installing a putc1 callback.
|
||||
*
|
||||
* By default, this function returns false. When GDBStub library is linked,
|
||||
* this function is overriden and returns true.
|
||||
*
|
||||
* @return true if GDB is installing a putc1 callback
|
||||
*/
|
||||
bool gdbstub_has_putc1_control(void);
|
||||
|
||||
/**
|
||||
@brief Register a putc1 callback with GDB.
|
||||
@param func function GDB will proxy putc1 data to
|
||||
|
||||
By default, this function is a no-op. When GDBStub library is linked,
|
||||
this function is overriden and sets GDB stub's secondary putc1 callback to
|
||||
func. When GDB stub is linked, but a GDB session is not current attached,
|
||||
then GDB stub will pass putc1 chars directly to this function.
|
||||
* @brief Register a putc1 callback with GDB.
|
||||
* @param func function GDB will proxy putc1 data to
|
||||
*
|
||||
* By default, this function is a no-op. When GDBStub library is linked,
|
||||
* this function is overriden and sets GDB stub's secondary putc1 callback to
|
||||
* func. When GDB stub is linked, but a GDB session is not current attached,
|
||||
* then GDB stub will pass putc1 chars directly to this function.
|
||||
*/
|
||||
void gdbstub_set_putc1_callback(void (*func)(char));
|
||||
|
||||
/**
|
||||
@brief Check if GDB is installing a uart0 isr callback.
|
||||
|
||||
By default, this function returns false. When GDBStub library is linked,
|
||||
this function is overriden and returns true.
|
||||
|
||||
@return true if GDB is installing a uart0 isr callback
|
||||
* @brief Check if GDB is installing a uart0 isr callback.
|
||||
*
|
||||
* By default, this function returns false. When GDBStub library is linked,
|
||||
* this function is overriden and returns true.
|
||||
*
|
||||
* @return true if GDB is installing a uart0 isr callback
|
||||
*/
|
||||
bool gdbstub_has_uart_isr_control(void);
|
||||
|
||||
/**
|
||||
@brief Register a uart0 isr callback with GDB.
|
||||
@param func function GDB will proxy uart0 isr data to
|
||||
|
||||
By default, this function is a no-op. When GDBStub library is linked,
|
||||
this function is overriden and sets GDB stub's secondary uart0 isr callback
|
||||
to func. When GDB stub is linked, but a GDB session is not current attached,
|
||||
then GDB stub will pass uart0 isr data back to this function.
|
||||
* @brief Register a uart0 isr callback with GDB.
|
||||
* @param func function GDB will proxy uart0 isr data to
|
||||
*
|
||||
* By default, this function is a no-op. When GDBStub library is linked,
|
||||
* this function is overriden and sets GDB stub's secondary uart0 isr callback
|
||||
* to func. When GDB stub is linked, but a GDB session is not current attached,
|
||||
* then GDB stub will pass uart0 isr data back to this function.
|
||||
*/
|
||||
void gdbstub_set_uart_isr_callback(void (*func)(void*, uint8_t), void* arg);
|
||||
|
||||
/**
|
||||
@brief Write a character for output to a GDB session on uart0.
|
||||
@param c character to write
|
||||
|
||||
By default, this function is a no-op. When GDBStub library is linked,
|
||||
this function is overriden and writes a char to either the GDB session on
|
||||
uart0 or directly to uart0 if not GDB session is attached.
|
||||
* @brief Write a character for output to a GDB session on uart0.
|
||||
* @param c character to write
|
||||
*
|
||||
* By default, this function is a no-op. When GDBStub library is linked,
|
||||
* this function is overriden and writes a char to either the GDB session on
|
||||
* uart0 or directly to uart0 if not GDB session is attached.
|
||||
*/
|
||||
void gdbstub_write_char(char c);
|
||||
|
||||
/**
|
||||
@brief Write a char buffer for output to a GDB session on uart0.
|
||||
@param buf buffer of data to write
|
||||
@param size length of buffer
|
||||
|
||||
By default, this function is a no-op. When GDBStub library is linked,
|
||||
this function is overriden and writes a buffer to either the GDB session on
|
||||
uart0 or directly to uart0 if not GDB session is attached.
|
||||
* @brief Write a char buffer for output to a GDB session on uart0.
|
||||
* @param buf buffer of data to write
|
||||
* @param size length of buffer
|
||||
*
|
||||
* By default, this function is a no-op. When GDBStub library is linked,
|
||||
* this function is overriden and writes a buffer to either the GDB session on
|
||||
* uart0 or directly to uart0 if not GDB session is attached.
|
||||
*/
|
||||
void gdbstub_write(const char* buf, size_t size);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* heap.c - overrides of SDK heap handling functions
|
||||
Copyright (c) 2016 Ivan Grokhotkov. All rights reserved.
|
||||
This file is distributed under MIT license.
|
||||
* Copyright (c) 2016 Ivan Grokhotkov. All rights reserved.
|
||||
* This file is distributed under MIT license.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -18,8 +18,7 @@ extern "C" {
|
||||
{
|
||||
(void) unused;
|
||||
void *ret = malloc(size);
|
||||
if (0 != size && 0 == ret)
|
||||
{
|
||||
if (0 != size && 0 == ret) {
|
||||
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
||||
umm_last_fail_alloc_size = size;
|
||||
}
|
||||
@ -36,8 +35,7 @@ extern "C" {
|
||||
{
|
||||
(void) unused;
|
||||
void *ret = realloc(ptr, size);
|
||||
if (0 != size && 0 == ret)
|
||||
{
|
||||
if (0 != size && 0 == ret) {
|
||||
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
||||
umm_last_fail_alloc_size = size;
|
||||
}
|
||||
@ -48,8 +46,7 @@ extern "C" {
|
||||
{
|
||||
(void) unused;
|
||||
void *ret = calloc(count, size);
|
||||
if (0 != (count * size) && 0 == ret)
|
||||
{
|
||||
if (0 != (count * size) && 0 == ret) {
|
||||
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
||||
umm_last_fail_alloc_size = count * size;
|
||||
}
|
||||
@ -97,9 +94,7 @@ extern "C" {
|
||||
{
|
||||
void* ret = umm_malloc(s);
|
||||
if (!ret)
|
||||
{
|
||||
os_printf(oom_fmt, (int)s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -107,9 +102,7 @@ extern "C" {
|
||||
{
|
||||
void* ret = umm_calloc(n, s);
|
||||
if (!ret)
|
||||
{
|
||||
os_printf(oom_fmt, (int)s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -117,9 +110,7 @@ extern "C" {
|
||||
{
|
||||
void* ret = umm_realloc(p, s);
|
||||
if (!ret)
|
||||
{
|
||||
os_printf(oom_fmt, (int)s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -134,9 +125,7 @@ extern "C" {
|
||||
{
|
||||
void* ret = umm_malloc(s);
|
||||
if (!ret)
|
||||
{
|
||||
print_loc(s, file, line);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -144,9 +133,7 @@ extern "C" {
|
||||
{
|
||||
void* ret = umm_calloc(n, s);
|
||||
if (!ret)
|
||||
{
|
||||
print_loc(s, file, line);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -154,9 +141,7 @@ extern "C" {
|
||||
{
|
||||
void* ret = umm_realloc(p, s);
|
||||
if (!ret)
|
||||
{
|
||||
print_loc(s, file, line);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -21,21 +21,17 @@ extern "C" {
|
||||
//}
|
||||
//
|
||||
|
||||
class InterruptLock
|
||||
{
|
||||
class InterruptLock {
|
||||
public:
|
||||
InterruptLock()
|
||||
{
|
||||
InterruptLock() {
|
||||
_state = xt_rsil(15);
|
||||
}
|
||||
|
||||
~InterruptLock()
|
||||
{
|
||||
~InterruptLock() {
|
||||
xt_wsr_ps(_state);
|
||||
}
|
||||
|
||||
uint32_t savedInterruptLevel() const
|
||||
{
|
||||
uint32_t savedInterruptLevel() const {
|
||||
return _state & 0x0f;
|
||||
}
|
||||
|
||||
|
@ -11,41 +11,31 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
static int base64_decode_value_signed(int8_t value_in)
|
||||
{
|
||||
static int base64_decode_value_signed(int8_t value_in){
|
||||
static const int8_t decoding[] PROGMEM = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
|
||||
static const int8_t decoding_size = sizeof(decoding);
|
||||
value_in -= 43;
|
||||
if (value_in < 0 || value_in > decoding_size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (value_in < 0 || value_in > decoding_size) return -1;
|
||||
return pgm_read_byte( &decoding[(int)value_in] );
|
||||
}
|
||||
|
||||
void base64_init_decodestate(base64_decodestate* state_in)
|
||||
{
|
||||
void base64_init_decodestate(base64_decodestate* state_in){
|
||||
state_in->step = step_a;
|
||||
state_in->plainchar = 0;
|
||||
}
|
||||
|
||||
static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in)
|
||||
{
|
||||
static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in){
|
||||
const int8_t* codechar = code_in;
|
||||
int8_t* plainchar = plaintext_out;
|
||||
int8_t fragment;
|
||||
|
||||
*plainchar = state_in->plainchar;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
switch (state_in->step){
|
||||
while (1){
|
||||
case step_a:
|
||||
do
|
||||
{
|
||||
if (codechar == code_in + length_in)
|
||||
{
|
||||
do {
|
||||
if (codechar == code_in+length_in){
|
||||
state_in->step = step_a;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
@ -54,10 +44,8 @@ extern "C" {
|
||||
} while (fragment < 0);
|
||||
*plainchar = (fragment & 0x03f) << 2;
|
||||
case step_b:
|
||||
do
|
||||
{
|
||||
if (codechar == code_in + length_in)
|
||||
{
|
||||
do {
|
||||
if (codechar == code_in+length_in){
|
||||
state_in->step = step_b;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
@ -67,10 +55,8 @@ extern "C" {
|
||||
*plainchar++ |= (fragment & 0x030) >> 4;
|
||||
*plainchar = (fragment & 0x00f) << 4;
|
||||
case step_c:
|
||||
do
|
||||
{
|
||||
if (codechar == code_in + length_in)
|
||||
{
|
||||
do {
|
||||
if (codechar == code_in+length_in){
|
||||
state_in->step = step_c;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
@ -80,10 +66,8 @@ extern "C" {
|
||||
*plainchar++ |= (fragment & 0x03c) >> 2;
|
||||
*plainchar = (fragment & 0x003) << 6;
|
||||
case step_d:
|
||||
do
|
||||
{
|
||||
if (codechar == code_in + length_in)
|
||||
{
|
||||
do {
|
||||
if (codechar == code_in+length_in){
|
||||
state_in->step = step_d;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
@ -97,30 +81,23 @@ extern "C" {
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
|
||||
static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out)
|
||||
{
|
||||
static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out){
|
||||
base64_decodestate _state;
|
||||
base64_init_decodestate(&_state);
|
||||
int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state);
|
||||
if (len > 0)
|
||||
{
|
||||
plaintext_out[len] = 0;
|
||||
}
|
||||
if(len > 0) plaintext_out[len] = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
int base64_decode_value(char value_in)
|
||||
{
|
||||
int base64_decode_value(char value_in){
|
||||
return base64_decode_value_signed(*((int8_t *) &value_in));
|
||||
}
|
||||
|
||||
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
|
||||
{
|
||||
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){
|
||||
return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in);
|
||||
}
|
||||
|
||||
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out)
|
||||
{
|
||||
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){
|
||||
return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out);
|
||||
}
|
||||
|
||||
|
@ -14,13 +14,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
step_a, step_b, step_c, step_d
|
||||
} base64_decodestep;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
base64_decodestep step;
|
||||
char plainchar;
|
||||
} base64_decodestate;
|
||||
|
@ -10,8 +10,7 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in)
|
||||
{
|
||||
void base64_init_encodestate(base64_encodestate* state_in){
|
||||
state_in->step = step_A;
|
||||
state_in->result = 0;
|
||||
state_in->stepcount = 0;
|
||||
@ -19,24 +18,18 @@ extern "C" {
|
||||
}
|
||||
|
||||
|
||||
void base64_init_encodestate_nonewlines(base64_encodestate* state_in)
|
||||
{
|
||||
void base64_init_encodestate_nonewlines(base64_encodestate* state_in){
|
||||
base64_init_encodestate(state_in);
|
||||
state_in->stepsnewline = -1;
|
||||
}
|
||||
|
||||
char base64_encode_value(char value_in)
|
||||
{
|
||||
char base64_encode_value(char value_in){
|
||||
static const char encoding[] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
if (value_in > 63)
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
if (value_in > 63) return '=';
|
||||
return pgm_read_byte( &encoding[(int)value_in] );
|
||||
}
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in){
|
||||
const char* plainchar = plaintext_in;
|
||||
const char* const plaintextend = plaintext_in + length_in;
|
||||
char* codechar = code_out;
|
||||
@ -45,13 +38,10 @@ extern "C" {
|
||||
|
||||
result = state_in->result;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
switch (state_in->step){
|
||||
while (1){
|
||||
case step_A:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
if (plainchar == plaintextend){
|
||||
state_in->result = result;
|
||||
state_in->step = step_A;
|
||||
return codechar - code_out;
|
||||
@ -61,8 +51,7 @@ extern "C" {
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x003) << 4;
|
||||
case step_B:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
if (plainchar == plaintextend){
|
||||
state_in->result = result;
|
||||
state_in->step = step_B;
|
||||
return codechar - code_out;
|
||||
@ -72,8 +61,7 @@ extern "C" {
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x00f) << 2;
|
||||
case step_C:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
if (plainchar == plaintextend){
|
||||
state_in->result = result;
|
||||
state_in->step = step_C;
|
||||
return codechar - code_out;
|
||||
@ -85,8 +73,7 @@ extern "C" {
|
||||
*codechar++ = base64_encode_value(result);
|
||||
|
||||
++(state_in->stepcount);
|
||||
if ((state_in->stepcount == BASE64_CHARS_PER_LINE / 4) && (state_in->stepsnewline > 0))
|
||||
{
|
||||
if ((state_in->stepcount == BASE64_CHARS_PER_LINE/4) && (state_in->stepsnewline > 0)){
|
||||
*codechar++ = '\n';
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
@ -96,12 +83,10 @@ extern "C" {
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in){
|
||||
char* codechar = code_out;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
switch (state_in->step){
|
||||
case step_B:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
@ -119,8 +104,7 @@ extern "C" {
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
||||
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out)
|
||||
{
|
||||
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out){
|
||||
base64_encodestate _state;
|
||||
base64_init_encodestate(&_state);
|
||||
int len = base64_encode_block(plaintext_in, length_in, code_out, &_state);
|
||||
|
@ -19,13 +19,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
step_A, step_B, step_C
|
||||
} base64_encodestep;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
base64_encodestep step;
|
||||
char result;
|
||||
int stepcount;
|
||||
|
@ -47,31 +47,27 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
int ICACHE_RAM_ATTR _open_r(struct _reent* unused, const char *ptr, int mode)
|
||||
{
|
||||
int ICACHE_RAM_ATTR _open_r (struct _reent* unused, const char *ptr, int mode) {
|
||||
(void)unused;
|
||||
(void)ptr;
|
||||
(void)mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR _close_r(struct _reent* unused, int file)
|
||||
{
|
||||
int ICACHE_RAM_ATTR _close_r(struct _reent* unused, int file) {
|
||||
(void)unused;
|
||||
(void)file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR _fstat_r(struct _reent* unused, int file, struct stat *st)
|
||||
{
|
||||
int ICACHE_RAM_ATTR _fstat_r(struct _reent* unused, int file, struct stat *st) {
|
||||
(void)unused;
|
||||
(void)file;
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR _lseek_r(struct _reent* unused, int file, int ptr, int dir)
|
||||
{
|
||||
int ICACHE_RAM_ATTR _lseek_r(struct _reent* unused, int file, int ptr, int dir) {
|
||||
(void)unused;
|
||||
(void)file;
|
||||
(void)ptr;
|
||||
@ -79,8 +75,7 @@ extern "C" {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR _read_r(struct _reent* unused, int file, char *ptr, int len)
|
||||
{
|
||||
int ICACHE_RAM_ATTR _read_r(struct _reent* unused, int file, char *ptr, int len) {
|
||||
(void)unused;
|
||||
(void)file;
|
||||
(void)ptr;
|
||||
@ -88,14 +83,11 @@ extern "C" {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR _write_r(struct _reent* r, int file, char *ptr, int len)
|
||||
{
|
||||
int ICACHE_RAM_ATTR _write_r(struct _reent* r, int file, char *ptr, int len) {
|
||||
(void) r;
|
||||
int pos = len;
|
||||
if (file == STDOUT_FILENO)
|
||||
{
|
||||
while (pos--)
|
||||
{
|
||||
if (file == STDOUT_FILENO) {
|
||||
while(pos--) {
|
||||
ets_putc(*ptr);
|
||||
++ptr;
|
||||
}
|
||||
@ -105,21 +97,17 @@ extern "C" {
|
||||
|
||||
int ICACHE_RAM_ATTR _putc_r(struct _reent* r, int c, FILE* file) __attribute__((weak));
|
||||
|
||||
int ICACHE_RAM_ATTR _putc_r(struct _reent* r, int c, FILE* file)
|
||||
{
|
||||
int ICACHE_RAM_ATTR _putc_r(struct _reent* r, int c, FILE* file) {
|
||||
(void) r;
|
||||
if (file->_file == STDOUT_FILENO)
|
||||
{
|
||||
if (file->_file == STDOUT_FILENO) {
|
||||
return ets_putc(c);
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
|
||||
int ICACHE_RAM_ATTR puts(const char * str)
|
||||
{
|
||||
int ICACHE_RAM_ATTR puts(const char * str) {
|
||||
char c;
|
||||
while ((c = *str) != 0)
|
||||
{
|
||||
while((c = *str) != 0) {
|
||||
ets_putc(c);
|
||||
++str;
|
||||
}
|
||||
@ -128,20 +116,17 @@ extern "C" {
|
||||
}
|
||||
|
||||
#undef putchar
|
||||
int ICACHE_RAM_ATTR putchar(int c)
|
||||
{
|
||||
int ICACHE_RAM_ATTR putchar(int c) {
|
||||
ets_putc(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
void _exit(int status)
|
||||
{
|
||||
void _exit(int status) {
|
||||
(void) status;
|
||||
abort();
|
||||
}
|
||||
|
||||
int atexit(void (*func)())
|
||||
{
|
||||
int atexit(void (*func)()) {
|
||||
(void) func;
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,8 +27,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint32_t state[4];
|
||||
uint32_t count[2];
|
||||
uint8_t buffer[64];
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Info Sigma delta module
|
||||
* Info Sigma delta module
|
||||
|
||||
This module controls the esp8266 internal sigma delta source
|
||||
Each pin can be connected to the sigma delta source
|
||||
|
@ -1,40 +1,40 @@
|
||||
/*
|
||||
sntp-lwip2.c - ESP8266-specific functions for SNTP and lwIP-v2
|
||||
Copyright (c) 2015 Espressif (license is tools/sdk/lwip/src/core/sntp.c's)
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
|
||||
History:
|
||||
This code is extracted from lwip1.4-espressif's sntp.c
|
||||
which is a patched version of the original lwip1's sntp.
|
||||
(check the mix-up in tools/sdk/lwip/src/core/sntp.c)
|
||||
It is moved here as-is and cleaned for maintainability and
|
||||
because it does not belong to lwip.
|
||||
|
||||
TODOs:
|
||||
settimeofday(): handle tv->tv_usec
|
||||
sntp_mktm_r(): review, fix DST handling (this one is currently untouched from lwip-1.4)
|
||||
implement adjtime()
|
||||
* sntp-lwip2.c - ESP8266-specific functions for SNTP and lwIP-v2
|
||||
* Copyright (c) 2015 Espressif (license is tools/sdk/lwip/src/core/sntp.c's)
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* History:
|
||||
* This code is extracted from lwip1.4-espressif's sntp.c
|
||||
* which is a patched version of the original lwip1's sntp.
|
||||
* (check the mix-up in tools/sdk/lwip/src/core/sntp.c)
|
||||
* It is moved here as-is and cleaned for maintainability and
|
||||
* because it does not belong to lwip.
|
||||
*
|
||||
* TODOs:
|
||||
* settimeofday(): handle tv->tv_usec
|
||||
* sntp_mktm_r(): review, fix DST handling (this one is currently untouched from lwip-1.4)
|
||||
* implement adjtime()
|
||||
*/
|
||||
|
||||
#include <lwip/init.h>
|
||||
@ -118,14 +118,12 @@ extern "C" {
|
||||
int __tznorth;
|
||||
int __tzyear;
|
||||
char reult[100];
|
||||
static const int mon_lengths[2][12] =
|
||||
{
|
||||
static const int mon_lengths[2][12] = {
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
} ;
|
||||
|
||||
static const int year_lengths[2] =
|
||||
{
|
||||
static const int year_lengths[2] = {
|
||||
365,
|
||||
366
|
||||
} ;
|
||||
@ -188,9 +186,7 @@ extern "C" {
|
||||
|
||||
/* compute day of week */
|
||||
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
|
||||
{
|
||||
res->tm_wday += DAYSPERWEEK;
|
||||
}
|
||||
|
||||
/* compute year & day of year */
|
||||
y = EPOCH_YEAR;
|
||||
@ -200,9 +196,7 @@ extern "C" {
|
||||
{
|
||||
yleap = isleap(y);
|
||||
if (days < year_lengths[yleap])
|
||||
{
|
||||
break;
|
||||
}
|
||||
y++;
|
||||
days -= year_lengths[yleap];
|
||||
}
|
||||
@ -221,9 +215,7 @@ extern "C" {
|
||||
res->tm_yday = days;
|
||||
ip = mon_lengths[yleap];
|
||||
for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
|
||||
{
|
||||
days -= ip[res->tm_mon];
|
||||
}
|
||||
res->tm_mday = days + 1;
|
||||
|
||||
if (!is_gmtime)
|
||||
@ -281,9 +273,7 @@ extern "C" {
|
||||
++res->tm_yday;
|
||||
++res->tm_wday;
|
||||
if (res->tm_wday > 6)
|
||||
{
|
||||
res->tm_wday = 0;
|
||||
}
|
||||
++res->tm_mday;
|
||||
res->tm_hour -= HOURSPERDAY;
|
||||
if (res->tm_mday > ip[res->tm_mon])
|
||||
@ -303,9 +293,7 @@ extern "C" {
|
||||
res->tm_yday -= 1;
|
||||
res->tm_wday -= 1;
|
||||
if (res->tm_wday < 0)
|
||||
{
|
||||
res->tm_wday = 6;
|
||||
}
|
||||
res->tm_mday -= 1;
|
||||
res->tm_hour += 24;
|
||||
if (res->tm_mday == 0)
|
||||
@ -323,9 +311,7 @@ extern "C" {
|
||||
// TZ_UNLOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
res->tm_isdst = 0;
|
||||
}
|
||||
// os_printf("res %d %d %d %d %d\n",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour);
|
||||
return (res);
|
||||
}
|
||||
@ -348,9 +334,7 @@ extern "C" {
|
||||
int i, j;
|
||||
|
||||
if (year < EPOCH_YEAR)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tzyear = year;
|
||||
|
||||
@ -363,13 +347,9 @@ extern "C" {
|
||||
for (i = 0; i < 2; ++i)
|
||||
{
|
||||
if (sntp__tzrule[i].ch == 'J')
|
||||
{
|
||||
days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60);
|
||||
}
|
||||
else if (sntp__tzrule[i].ch == 'D')
|
||||
{
|
||||
days = year_days + sntp__tzrule[i].d;
|
||||
}
|
||||
else
|
||||
{
|
||||
int yleap = isleap(year);
|
||||
@ -379,23 +359,17 @@ extern "C" {
|
||||
days = year_days;
|
||||
|
||||
for (j = 1; j < sntp__tzrule[i].m; ++j)
|
||||
{
|
||||
days += ip[j-1];
|
||||
}
|
||||
|
||||
m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
|
||||
|
||||
wday_diff = sntp__tzrule[i].d - m_wday;
|
||||
if (wday_diff < 0)
|
||||
{
|
||||
wday_diff += DAYSPERWEEK;
|
||||
}
|
||||
m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
|
||||
|
||||
while (m_day >= ip[j-1])
|
||||
{
|
||||
m_day -= DAYSPERWEEK;
|
||||
}
|
||||
|
||||
days += m_day;
|
||||
}
|
||||
@ -411,12 +385,10 @@ extern "C" {
|
||||
|
||||
char* sntp_asctime_r(struct tm *tim_p ,char *result)
|
||||
{
|
||||
static const char day_name[7][4] =
|
||||
{
|
||||
static const char day_name[7][4] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
static const char mon_name[12][4] =
|
||||
{
|
||||
static const char mon_name[12][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
@ -458,8 +430,7 @@ extern "C" {
|
||||
/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */
|
||||
bool sntp_set_timezone_in_seconds(sint32 timezone)
|
||||
{
|
||||
if (timezone >= (-11 * (60 * 60)) || timezone <= (13 * (60 * 60)))
|
||||
{
|
||||
if(timezone >= (-11 * (60 * 60)) || timezone <= (13 * (60 * 60))) {
|
||||
time_zone = timezone;
|
||||
return true;
|
||||
}
|
||||
@ -507,10 +478,8 @@ extern "C" {
|
||||
sntp_set_system_time(tv->tv_sec);
|
||||
|
||||
if (_settimeofday_cb)
|
||||
{
|
||||
_settimeofday_cb();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
spiffs.h
|
||||
|
||||
Created on: May 26, 2013
|
||||
Author: petera
|
||||
* spiffs.h
|
||||
*
|
||||
* Created on: May 26, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_H_
|
||||
@ -99,16 +99,14 @@ typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system check callback report operation */
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_LOOKUP = 0,
|
||||
SPIFFS_CHECK_INDEX,
|
||||
SPIFFS_CHECK_PAGE
|
||||
} spiffs_check_type;
|
||||
|
||||
/* file system check callback report type */
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_PROGRESS = 0,
|
||||
SPIFFS_CHECK_ERROR,
|
||||
SPIFFS_CHECK_FIX_INDEX,
|
||||
@ -128,8 +126,7 @@ typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_repor
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system listener callback operation */
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
/* the file has been created */
|
||||
SPIFFS_CB_CREATED = 0,
|
||||
/* the file has been updated or moved to another page */
|
||||
@ -200,8 +197,7 @@ typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op,
|
||||
// phys structs
|
||||
|
||||
// spiffs spi configuration struct
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// physical read function
|
||||
spiffs_read hal_read_f;
|
||||
// physical write function
|
||||
@ -232,8 +228,7 @@ typedef struct
|
||||
#endif
|
||||
} spiffs_config;
|
||||
|
||||
typedef struct spiffs_t
|
||||
{
|
||||
typedef struct spiffs_t {
|
||||
// file system configuration
|
||||
spiffs_config cfg;
|
||||
// number of logical blocks
|
||||
@ -299,8 +294,7 @@ typedef struct spiffs_t
|
||||
} spiffs;
|
||||
|
||||
/* spiffs file status struct */
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
spiffs_obj_id obj_id;
|
||||
u32_t size;
|
||||
spiffs_obj_type type;
|
||||
@ -311,8 +305,7 @@ typedef struct
|
||||
#endif
|
||||
} spiffs_stat;
|
||||
|
||||
struct spiffs_dirent
|
||||
{
|
||||
struct spiffs_dirent {
|
||||
spiffs_obj_id obj_id;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
spiffs_obj_type type;
|
||||
@ -323,8 +316,7 @@ struct spiffs_dirent
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
spiffs *fs;
|
||||
spiffs_block_ix block;
|
||||
int entry;
|
||||
@ -332,8 +324,7 @@ typedef struct
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// buffer with looked up data pixes
|
||||
spiffs_page_ix *map_buf;
|
||||
// precise file byte offset
|
||||
@ -350,52 +341,52 @@ typedef struct
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
/**
|
||||
Special function. This takes a spiffs config struct and returns the number
|
||||
of blocks this file system was formatted with. This function relies on
|
||||
that following info is set correctly in given config struct:
|
||||
|
||||
phys_addr, log_page_size, and log_block_size.
|
||||
|
||||
Also, hal_read_f must be set in the config struct.
|
||||
|
||||
One must be sure of the correct page size and that the physical address is
|
||||
correct in the probed file system when calling this function. It is not
|
||||
checked if the phys_addr actually points to the start of the file system,
|
||||
so one might get a false positive if entering a phys_addr somewhere in the
|
||||
middle of the file system at block boundary. In addition, it is not checked
|
||||
if the page size is actually correct. If it is not, weird file system sizes
|
||||
will be returned.
|
||||
|
||||
If this function detects a file system it returns the assumed file system
|
||||
size, which can be used to set the phys_size.
|
||||
|
||||
Otherwise, it returns an error indicating why it is not regarded as a file
|
||||
system.
|
||||
|
||||
Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
|
||||
macros. It returns the error code directly, instead of as read by
|
||||
SPIFFS_errno.
|
||||
|
||||
@param config essential parts of the physical and logical
|
||||
configuration of the file system.
|
||||
* Special function. This takes a spiffs config struct and returns the number
|
||||
* of blocks this file system was formatted with. This function relies on
|
||||
* that following info is set correctly in given config struct:
|
||||
*
|
||||
* phys_addr, log_page_size, and log_block_size.
|
||||
*
|
||||
* Also, hal_read_f must be set in the config struct.
|
||||
*
|
||||
* One must be sure of the correct page size and that the physical address is
|
||||
* correct in the probed file system when calling this function. It is not
|
||||
* checked if the phys_addr actually points to the start of the file system,
|
||||
* so one might get a false positive if entering a phys_addr somewhere in the
|
||||
* middle of the file system at block boundary. In addition, it is not checked
|
||||
* if the page size is actually correct. If it is not, weird file system sizes
|
||||
* will be returned.
|
||||
*
|
||||
* If this function detects a file system it returns the assumed file system
|
||||
* size, which can be used to set the phys_size.
|
||||
*
|
||||
* Otherwise, it returns an error indicating why it is not regarded as a file
|
||||
* system.
|
||||
*
|
||||
* Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
|
||||
* macros. It returns the error code directly, instead of as read by
|
||||
* SPIFFS_errno.
|
||||
*
|
||||
* @param config essential parts of the physical and logical
|
||||
* configuration of the file system.
|
||||
*/
|
||||
s32_t SPIFFS_probe_fs(spiffs_config *config);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
|
||||
/**
|
||||
Initializes the file system dynamic parameters and mounts the filesystem.
|
||||
If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
|
||||
if the flash does not contain a recognizable file system.
|
||||
In this case, SPIFFS_format must be called prior to remounting.
|
||||
@param fs the file system struct
|
||||
@param config the physical and logical configuration of the file system
|
||||
@param work a memory work buffer comprising 2*config->log_page_size
|
||||
bytes used throughout all file system operations
|
||||
@param fd_space memory for file descriptors
|
||||
@param fd_space_size memory size of file descriptors
|
||||
@param cache memory for cache, may be null
|
||||
@param cache_size memory size of cache
|
||||
@param check_cb_f callback function for reporting during consistency checks
|
||||
* Initializes the file system dynamic parameters and mounts the filesystem.
|
||||
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
|
||||
* if the flash does not contain a recognizable file system.
|
||||
* In this case, SPIFFS_format must be called prior to remounting.
|
||||
* @param fs the file system struct
|
||||
* @param config the physical and logical configuration of the file system
|
||||
* @param work a memory work buffer comprising 2*config->log_page_size
|
||||
* bytes used throughout all file system operations
|
||||
* @param fd_space memory for file descriptors
|
||||
* @param fd_space_size memory size of file descriptors
|
||||
* @param cache memory for cache, may be null
|
||||
* @param cache_size memory size of cache
|
||||
* @param check_cb_f callback function for reporting during consistency checks
|
||||
*/
|
||||
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
u8_t *fd_space, u32_t fd_space_size,
|
||||
@ -403,389 +394,389 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
spiffs_check_callback check_cb_f);
|
||||
|
||||
/**
|
||||
Unmounts the file system. All file handles will be flushed of any
|
||||
cached writes and closed.
|
||||
@param fs the file system struct
|
||||
* Unmounts the file system. All file handles will be flushed of any
|
||||
* cached writes and closed.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_unmount(spiffs *fs);
|
||||
|
||||
/**
|
||||
Creates a new file.
|
||||
@param fs the file system struct
|
||||
@param path the path of the new file
|
||||
@param mode ignored, for posix compliance
|
||||
* Creates a new file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
Opens/creates a file.
|
||||
@param fs the file system struct
|
||||
@param path the path of the new file
|
||||
@param flags the flags for the open command, can be combinations of
|
||||
SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,
|
||||
SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL
|
||||
@param mode ignored, for posix compliance
|
||||
* Opens/creates a file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,
|
||||
* SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
Opens a file by given dir entry.
|
||||
Optimization purposes, when traversing a file system with SPIFFS_readdir
|
||||
a normal SPIFFS_open would need to traverse the filesystem again to find
|
||||
the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
|
||||
@param fs the file system struct
|
||||
@param e the dir entry to the file
|
||||
@param flags the flags for the open command, can be combinations of
|
||||
SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
SPIFFS_CREAT will have no effect in this case.
|
||||
@param mode ignored, for posix compliance
|
||||
* Opens a file by given dir entry.
|
||||
* Optimization purposes, when traversing a file system with SPIFFS_readdir
|
||||
* a normal SPIFFS_open would need to traverse the filesystem again to find
|
||||
* the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
|
||||
* @param fs the file system struct
|
||||
* @param e the dir entry to the file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
Opens a file by given page index.
|
||||
Optimization purposes, opens a file by directly pointing to the page
|
||||
index in the spi flash.
|
||||
If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
|
||||
is returned.
|
||||
@param fs the file system struct
|
||||
@param page_ix the page index
|
||||
@param flags the flags for the open command, can be combinations of
|
||||
SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
SPIFFS_CREAT will have no effect in this case.
|
||||
@param mode ignored, for posix compliance
|
||||
* Opens a file by given page index.
|
||||
* Optimization purposes, opens a file by directly pointing to the page
|
||||
* index in the spi flash.
|
||||
* If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
|
||||
* is returned.
|
||||
* @param fs the file system struct
|
||||
* @param page_ix the page index
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
Reads from given filehandle.
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle
|
||||
@param buf where to put read data
|
||||
@param len how much to read
|
||||
@returns number of bytes read, or -1 if error
|
||||
* Reads from given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf where to put read data
|
||||
* @param len how much to read
|
||||
* @returns number of bytes read, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
Writes to given filehandle.
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle
|
||||
@param buf the data to write
|
||||
@param len how much to write
|
||||
@returns number of bytes written, or -1 if error
|
||||
* Writes to given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf the data to write
|
||||
* @param len how much to write
|
||||
* @returns number of bytes written, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
Moves the read/write file offset. Resulting offset is returned or negative if error.
|
||||
lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle
|
||||
@param offs how much/where to move the offset
|
||||
@param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
|
||||
if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
|
||||
if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
|
||||
* Moves the read/write file offset. Resulting offset is returned or negative if error.
|
||||
* lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param offs how much/where to move the offset
|
||||
* @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
|
||||
* if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
|
||||
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
|
||||
*/
|
||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
|
||||
|
||||
/**
|
||||
Removes a file by path
|
||||
@param fs the file system struct
|
||||
@param path the path of the file to remove
|
||||
* Removes a file by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_remove(spiffs *fs, const char *path);
|
||||
|
||||
/**
|
||||
Removes a file by filehandle
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle of the file to remove
|
||||
* Removes a file by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
Gets file status by path
|
||||
@param fs the file system struct
|
||||
@param path the path of the file to stat
|
||||
@param s the stat struct to populate
|
||||
* Gets file status by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
Gets file status by filehandle
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle of the file to stat
|
||||
@param s the stat struct to populate
|
||||
* Gets file status by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
Flushes all pending write operations from cache for given file
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle of the file to flush
|
||||
* Flushes all pending write operations from cache for given file
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to flush
|
||||
*/
|
||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
Closes a filehandle. If there are pending write operations, these are finalized before closing.
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle of the file to close
|
||||
* Closes a filehandle. If there are pending write operations, these are finalized before closing.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to close
|
||||
*/
|
||||
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
Renames a file
|
||||
@param fs the file system struct
|
||||
@param old path of file to rename
|
||||
@param newPath new path of file
|
||||
* Renames a file
|
||||
* @param fs the file system struct
|
||||
* @param old path of file to rename
|
||||
* @param newPath new path of file
|
||||
*/
|
||||
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
|
||||
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
/**
|
||||
Updates file's metadata
|
||||
@param fs the file system struct
|
||||
@param path path to the file
|
||||
@param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param path path to the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);
|
||||
|
||||
/**
|
||||
Updates file's metadata
|
||||
@param fs the file system struct
|
||||
@param fh file handle of the file
|
||||
@param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param fh file handle of the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);
|
||||
#endif
|
||||
|
||||
/**
|
||||
Returns last error of last file operation.
|
||||
@param fs the file system struct
|
||||
* Returns last error of last file operation.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_errno(spiffs *fs);
|
||||
|
||||
/**
|
||||
Clears last error.
|
||||
@param fs the file system struct
|
||||
* Clears last error.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_clearerr(spiffs *fs);
|
||||
|
||||
/**
|
||||
Opens a directory stream corresponding to the given name.
|
||||
The stream is positioned at the first entry in the directory.
|
||||
On hydrogen builds the name argument is ignored as hydrogen builds always correspond
|
||||
to a flat file structure - no directories.
|
||||
@param fs the file system struct
|
||||
@param name the name of the directory
|
||||
@param d pointer the directory stream to be populated
|
||||
* Opens a directory stream corresponding to the given name.
|
||||
* The stream is positioned at the first entry in the directory.
|
||||
* On hydrogen builds the name argument is ignored as hydrogen builds always correspond
|
||||
* to a flat file structure - no directories.
|
||||
* @param fs the file system struct
|
||||
* @param name the name of the directory
|
||||
* @param d pointer the directory stream to be populated
|
||||
*/
|
||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
Closes a directory stream
|
||||
@param d the directory stream to close
|
||||
* Closes a directory stream
|
||||
* @param d the directory stream to close
|
||||
*/
|
||||
s32_t SPIFFS_closedir(spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
Reads a directory into given spifs_dirent struct.
|
||||
@param d pointer to the directory stream
|
||||
@param e the dirent struct to be populated
|
||||
@returns null if error or end of stream, else given dirent is returned
|
||||
* Reads a directory into given spifs_dirent struct.
|
||||
* @param d pointer to the directory stream
|
||||
* @param e the dirent struct to be populated
|
||||
* @returns null if error or end of stream, else given dirent is returned
|
||||
*/
|
||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
||||
|
||||
/**
|
||||
Runs a consistency check on given filesystem.
|
||||
@param fs the file system struct
|
||||
* Runs a consistency check on given filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_check(spiffs *fs);
|
||||
|
||||
/**
|
||||
Returns number of total bytes available and number of used bytes.
|
||||
This is an estimation, and depends on if there a many files with little
|
||||
data or few files with much data.
|
||||
NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
||||
run. This indicates a power loss in midst of things. In worst case
|
||||
(repeated powerlosses in mending or gc) you might have to delete some files.
|
||||
|
||||
@param fs the file system struct
|
||||
@param total total number of bytes in filesystem
|
||||
@param used used number of bytes in filesystem
|
||||
* Returns number of total bytes available and number of used bytes.
|
||||
* This is an estimation, and depends on if there a many files with little
|
||||
* data or few files with much data.
|
||||
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
||||
* run. This indicates a power loss in midst of things. In worst case
|
||||
* (repeated powerlosses in mending or gc) you might have to delete some files.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param total total number of bytes in filesystem
|
||||
* @param used used number of bytes in filesystem
|
||||
*/
|
||||
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
||||
|
||||
/**
|
||||
Formats the entire file system. All data will be lost.
|
||||
The filesystem must not be mounted when calling this.
|
||||
|
||||
NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
|
||||
MUST be called prior to formatting in order to configure the filesystem.
|
||||
If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
|
||||
SPIFFS_format.
|
||||
If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
||||
SPIFFS_unmount first.
|
||||
|
||||
@param fs the file system struct
|
||||
* Formats the entire file system. All data will be lost.
|
||||
* The filesystem must not be mounted when calling this.
|
||||
*
|
||||
* NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
|
||||
* MUST be called prior to formatting in order to configure the filesystem.
|
||||
* If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
|
||||
* SPIFFS_format.
|
||||
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
||||
* SPIFFS_unmount first.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_format(spiffs *fs);
|
||||
|
||||
/**
|
||||
Returns nonzero if spiffs is mounted, or zero if unmounted.
|
||||
@param fs the file system struct
|
||||
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
u8_t SPIFFS_mounted(spiffs *fs);
|
||||
|
||||
/**
|
||||
Tries to find a block where most or all pages are deleted, and erase that
|
||||
block if found. Does not care for wear levelling. Will not move pages
|
||||
around.
|
||||
If parameter max_free_pages are set to 0, only blocks with only deleted
|
||||
pages will be selected.
|
||||
|
||||
NB: the garbage collector is automatically called when spiffs needs free
|
||||
pages. The reason for this function is to give possibility to do background
|
||||
tidying when user knows the system is idle.
|
||||
|
||||
Use with care.
|
||||
|
||||
Setting max_free_pages to anything larger than zero will eventually wear
|
||||
flash more as a block containing free pages can be erased.
|
||||
|
||||
Will set err_no to SPIFFS_OK if a block was found and erased,
|
||||
SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
||||
or other error.
|
||||
|
||||
@param fs the file system struct
|
||||
@param max_free_pages maximum number allowed free pages in block
|
||||
* Tries to find a block where most or all pages are deleted, and erase that
|
||||
* block if found. Does not care for wear levelling. Will not move pages
|
||||
* around.
|
||||
* If parameter max_free_pages are set to 0, only blocks with only deleted
|
||||
* pages will be selected.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* Setting max_free_pages to anything larger than zero will eventually wear
|
||||
* flash more as a block containing free pages can be erased.
|
||||
*
|
||||
* Will set err_no to SPIFFS_OK if a block was found and erased,
|
||||
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
||||
* or other error.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param max_free_pages maximum number allowed free pages in block
|
||||
*/
|
||||
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
/**
|
||||
Will try to make room for given amount of bytes in the filesystem by moving
|
||||
pages and erasing blocks.
|
||||
If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
||||
there already is this amount (or more) of free space, SPIFFS_gc will
|
||||
silently return. It is recommended to call SPIFFS_info before invoking
|
||||
this method in order to determine what amount of bytes to give.
|
||||
|
||||
NB: the garbage collector is automatically called when spiffs needs free
|
||||
pages. The reason for this function is to give possibility to do background
|
||||
tidying when user knows the system is idle.
|
||||
|
||||
Use with care.
|
||||
|
||||
@param fs the file system struct
|
||||
@param size amount of bytes that should be freed
|
||||
* Will try to make room for given amount of bytes in the filesystem by moving
|
||||
* pages and erasing blocks.
|
||||
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
||||
* there already is this amount (or more) of free space, SPIFFS_gc will
|
||||
* silently return. It is recommended to call SPIFFS_info before invoking
|
||||
* this method in order to determine what amount of bytes to give.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param size amount of bytes that should be freed
|
||||
*/
|
||||
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
|
||||
|
||||
/**
|
||||
Check if EOF reached.
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle of the file to check
|
||||
* Check if EOF reached.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
Get position in file.
|
||||
@param fs the file system struct
|
||||
@param fh the filehandle of the file to check
|
||||
* Get position in file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
Registers a callback function that keeps track on operations on file
|
||||
headers. Do note, that this callback is called from within internal spiffs
|
||||
mechanisms. Any operations on the actual file system being callbacked from
|
||||
in this callback will mess things up for sure - do not do this.
|
||||
This can be used to track where files are and move around during garbage
|
||||
collection, which in turn can be used to build location tables in ram.
|
||||
Used in conjuction with SPIFFS_open_by_page this may improve performance
|
||||
when opening a lot of files.
|
||||
Must be invoked after mount.
|
||||
|
||||
@param fs the file system struct
|
||||
@param cb_func the callback on file operations
|
||||
* Registers a callback function that keeps track on operations on file
|
||||
* headers. Do note, that this callback is called from within internal spiffs
|
||||
* mechanisms. Any operations on the actual file system being callbacked from
|
||||
* in this callback will mess things up for sure - do not do this.
|
||||
* This can be used to track where files are and move around during garbage
|
||||
* collection, which in turn can be used to build location tables in ram.
|
||||
* Used in conjuction with SPIFFS_open_by_page this may improve performance
|
||||
* when opening a lot of files.
|
||||
* Must be invoked after mount.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param cb_func the callback on file operations
|
||||
*/
|
||||
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
/**
|
||||
Maps the first level index lookup to a given memory map.
|
||||
This will make reading big files faster, as the memory map will be used for
|
||||
looking up data pages instead of searching for the indices on the physical
|
||||
medium. When mapping, all affected indicies are found and the information is
|
||||
copied to the array.
|
||||
Whole file or only parts of it may be mapped. The index map will cover file
|
||||
contents from argument offset until and including arguments (offset+len).
|
||||
It is valid to map a longer range than the current file size. The map will
|
||||
then be populated when the file grows.
|
||||
On garbage collections and file data page movements, the map array will be
|
||||
automatically updated. Do not tamper with the map array, as this contains
|
||||
the references to the data pages. Modifying it from outside will corrupt any
|
||||
future readings using this file descriptor.
|
||||
The map will no longer be used when the file descriptor closed or the file
|
||||
is unmapped.
|
||||
This can be useful to get faster and more deterministic timing when reading
|
||||
large files, or when seeking and reading a lot within a file.
|
||||
@param fs the file system struct
|
||||
@param fh the file handle of the file to map
|
||||
@param map a spiffs_ix_map struct, describing the index map
|
||||
@param offset absolute file offset where to start the index map
|
||||
@param len length of the mapping in actual file bytes
|
||||
@param map_buf the array buffer for the look up data - number of required
|
||||
elements in the array can be derived from function
|
||||
SPIFFS_bytes_to_ix_map_entries given the length
|
||||
* Maps the first level index lookup to a given memory map.
|
||||
* This will make reading big files faster, as the memory map will be used for
|
||||
* looking up data pages instead of searching for the indices on the physical
|
||||
* medium. When mapping, all affected indicies are found and the information is
|
||||
* copied to the array.
|
||||
* Whole file or only parts of it may be mapped. The index map will cover file
|
||||
* contents from argument offset until and including arguments (offset+len).
|
||||
* It is valid to map a longer range than the current file size. The map will
|
||||
* then be populated when the file grows.
|
||||
* On garbage collections and file data page movements, the map array will be
|
||||
* automatically updated. Do not tamper with the map array, as this contains
|
||||
* the references to the data pages. Modifying it from outside will corrupt any
|
||||
* future readings using this file descriptor.
|
||||
* The map will no longer be used when the file descriptor closed or the file
|
||||
* is unmapped.
|
||||
* This can be useful to get faster and more deterministic timing when reading
|
||||
* large files, or when seeking and reading a lot within a file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to map
|
||||
* @param map a spiffs_ix_map struct, describing the index map
|
||||
* @param offset absolute file offset where to start the index map
|
||||
* @param len length of the mapping in actual file bytes
|
||||
* @param map_buf the array buffer for the look up data - number of required
|
||||
* elements in the array can be derived from function
|
||||
* SPIFFS_bytes_to_ix_map_entries given the length
|
||||
*/
|
||||
s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
|
||||
u32_t offset, u32_t len, spiffs_page_ix *map_buf);
|
||||
|
||||
/**
|
||||
Unmaps the index lookup from this filehandle. All future readings will
|
||||
proceed as normal, requiring reading of the first level indices from
|
||||
physical media.
|
||||
The map and map buffer given in function SPIFFS_ix_map will no longer be
|
||||
referenced by spiffs.
|
||||
It is not strictly necessary to unmap a file before closing it, as closing
|
||||
a file will automatically unmap it.
|
||||
@param fs the file system struct
|
||||
@param fh the file handle of the file to unmap
|
||||
* Unmaps the index lookup from this filehandle. All future readings will
|
||||
* proceed as normal, requiring reading of the first level indices from
|
||||
* physical media.
|
||||
* The map and map buffer given in function SPIFFS_ix_map will no longer be
|
||||
* referenced by spiffs.
|
||||
* It is not strictly necessary to unmap a file before closing it, as closing
|
||||
* a file will automatically unmap it.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to unmap
|
||||
*/
|
||||
s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
Moves the offset for the index map given in function SPIFFS_ix_map. Parts or
|
||||
all of the map buffer will repopulated.
|
||||
@param fs the file system struct
|
||||
@param fh the mapped file handle of the file to remap
|
||||
@param offset new absolute file offset where to start the index map
|
||||
* Moves the offset for the index map given in function SPIFFS_ix_map. Parts or
|
||||
* all of the map buffer will repopulated.
|
||||
* @param fs the file system struct
|
||||
* @param fh the mapped file handle of the file to remap
|
||||
* @param offset new absolute file offset where to start the index map
|
||||
*/
|
||||
s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);
|
||||
|
||||
/**
|
||||
Utility function to get number of spiffs_page_ix entries a map buffer must
|
||||
contain on order to map given amount of file data in bytes.
|
||||
See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.
|
||||
@param fs the file system struct
|
||||
@param bytes number of file data bytes to map
|
||||
@return needed number of elements in a spiffs_page_ix array needed to
|
||||
map given amount of bytes in a file
|
||||
* Utility function to get number of spiffs_page_ix entries a map buffer must
|
||||
* contain on order to map given amount of file data in bytes.
|
||||
* See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.
|
||||
* @param fs the file system struct
|
||||
* @param bytes number of file data bytes to map
|
||||
* @return needed number of elements in a spiffs_page_ix array needed to
|
||||
* map given amount of bytes in a file
|
||||
*/
|
||||
s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);
|
||||
|
||||
/**
|
||||
Utility function to amount of file data bytes that can be mapped when
|
||||
mapping a file with buffer having given number of spiffs_page_ix entries.
|
||||
See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.
|
||||
@param fs the file system struct
|
||||
@param map_page_ix_entries number of entries in a spiffs_page_ix array
|
||||
@return amount of file data in bytes that can be mapped given a map
|
||||
buffer having given amount of spiffs_page_ix entries
|
||||
* Utility function to amount of file data bytes that can be mapped when
|
||||
* mapping a file with buffer having given number of spiffs_page_ix entries.
|
||||
* See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.
|
||||
* @param fs the file system struct
|
||||
* @param map_page_ix_entries number of entries in a spiffs_page_ix array
|
||||
* @return amount of file data in bytes that can be mapped given a map
|
||||
* buffer having given amount of spiffs_page_ix entries
|
||||
*/
|
||||
s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
|
||||
|
||||
@ -794,23 +785,23 @@ s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
|
||||
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
/**
|
||||
Prints out a visualization of the filesystem.
|
||||
@param fs the file system struct
|
||||
* Prints out a visualization of the filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_vis(spiffs *fs);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_BUFFER_HELP
|
||||
/**
|
||||
Returns number of bytes needed for the filedescriptor buffer given
|
||||
amount of file descriptors.
|
||||
* Returns number of bytes needed for the filedescriptor buffer given
|
||||
* amount of file descriptors.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
/**
|
||||
Returns number of bytes needed for the cache buffer given
|
||||
amount of cache pages.
|
||||
* Returns number of bytes needed for the cache buffer given
|
||||
* amount of cache pages.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
|
||||
#endif
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
spiffs_cache.c
|
||||
|
||||
Created on: Jun 23, 2013
|
||||
Author: petera
|
||||
* spiffs_cache.c
|
||||
*
|
||||
* Created on: Jun 23, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "spiffs.h"
|
||||
@ -13,21 +13,15 @@
|
||||
extern "C" {
|
||||
|
||||
// returns cached page for give page index, or null if no such cached page
|
||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix)
|
||||
{
|
||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++)
|
||||
{
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
cp->pix == pix)
|
||||
{
|
||||
cp->pix == pix ) {
|
||||
//SPIFFS_CACHE_DBG("CACHE_GET: have cache page " _SPIPRIi " for " _SPIPRIpg"\n", i, pix);
|
||||
cp->last_access = cache->last_access;
|
||||
return cp;
|
||||
@ -38,28 +32,23 @@ extern "C" {
|
||||
}
|
||||
|
||||
// frees cached page
|
||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back)
|
||||
{
|
||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
|
||||
if (cache->cpage_use_map & (1 << ix))
|
||||
{
|
||||
if (cache->cpage_use_map & (1<<ix)) {
|
||||
if (write_back &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY))
|
||||
{
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: write cache page " _SPIPRIi " pix " _SPIPRIpg "\n", ix, cp->pix);
|
||||
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR)
|
||||
{
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " objid " _SPIPRIid "\n", ix, cp->obj_id);
|
||||
}
|
||||
else
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " pix " _SPIPRIpg "\n", ix, cp->pix);
|
||||
@ -72,13 +61,11 @@ extern "C" {
|
||||
}
|
||||
|
||||
// removes the oldest accessed cached page
|
||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags)
|
||||
{
|
||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask)
|
||||
{
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
||||
// at least one free cpage
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
@ -87,19 +74,16 @@ extern "C" {
|
||||
int i;
|
||||
int cand_ix = -1;
|
||||
u32_t oldest_val = 0;
|
||||
for (i = 0; i < cache->cpage_count; i++)
|
||||
{
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->last_access - cp->last_access) > oldest_val &&
|
||||
(cp->flags & flag_mask) == flags)
|
||||
{
|
||||
(cp->flags & flag_mask) == flags) {
|
||||
oldest_val = cache->last_access - cp->last_access;
|
||||
cand_ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cand_ix >= 0)
|
||||
{
|
||||
if (cand_ix >= 0) {
|
||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
||||
}
|
||||
|
||||
@ -107,19 +91,15 @@ extern "C" {
|
||||
}
|
||||
|
||||
// allocates a new cached page and returns it, or null if all cache pages are busy
|
||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs)
|
||||
{
|
||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if (cache->cpage_use_map == 0xffffffff)
|
||||
{
|
||||
if (cache->cpage_use_map == 0xffffffff) {
|
||||
// out of cache memory
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++)
|
||||
{
|
||||
if ((cache->cpage_use_map & (1 << i)) == 0)
|
||||
{
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
if ((cache->cpage_use_map & (1<<i)) == 0) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
cache->cpage_use_map |= (1<<i);
|
||||
cp->last_access = cache->last_access;
|
||||
@ -132,11 +112,9 @@ extern "C" {
|
||||
}
|
||||
|
||||
// drops the cache page for give page index
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix)
|
||||
{
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
if (cp)
|
||||
{
|
||||
if (cp) {
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
}
|
||||
}
|
||||
@ -150,15 +128,13 @@ extern "C" {
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst)
|
||||
{
|
||||
u8_t *dst) {
|
||||
(void)fh;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
|
||||
cache->last_access++;
|
||||
if (cp)
|
||||
{
|
||||
if (cp) {
|
||||
// we've already got one, you see
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_hits++;
|
||||
@ -166,11 +142,8 @@ extern "C" {
|
||||
cp->last_access = cache->last_access;
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
_SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2)
|
||||
{
|
||||
} else {
|
||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
}
|
||||
@ -182,8 +155,7 @@ extern "C" {
|
||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
|
||||
cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp)
|
||||
{
|
||||
if (cp) {
|
||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi " for pix " _SPIPRIpg "\n", cp->ix, cp->pix);
|
||||
@ -192,20 +164,16 @@ extern "C" {
|
||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
||||
spiffs_get_cache_page(fs, cache, cp->ix));
|
||||
if (res2 != SPIFFS_OK)
|
||||
{
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
_SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// this will never happen, last resort for sake of symmetry
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
if (res2 != SPIFFS_OK)
|
||||
{
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
@ -221,21 +189,18 @@ extern "C" {
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src)
|
||||
{
|
||||
u8_t *src) {
|
||||
(void)fh;
|
||||
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
|
||||
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU)
|
||||
{
|
||||
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {
|
||||
// have a cache page
|
||||
// copy in data to cache page
|
||||
|
||||
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
|
||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU)
|
||||
{
|
||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
@ -247,18 +212,13 @@ extern "C" {
|
||||
cache->last_access++;
|
||||
cp->last_access = cache->last_access;
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU)
|
||||
{
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
||||
// page is being updated, no write-cache, just pass thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// no cache page, no write cache - just write thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
@ -266,24 +226,20 @@ extern "C" {
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
// returns the cache page that this fd refers, or null if no cache page
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd)
|
||||
{
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0)
|
||||
{
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
||||
// all cpages free, no cpage cannot be assigned to obj_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++)
|
||||
{
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
|
||||
cp->obj_id == fd->obj_id)
|
||||
{
|
||||
cp->obj_id == fd->obj_id) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
@ -293,14 +249,12 @@ extern "C" {
|
||||
|
||||
// allocates a new cache page and refers this to given fd - flushes an old cache
|
||||
// page if all cache is busy
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd)
|
||||
{
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
// before this function is called, it is ensured that there is no already existing
|
||||
// cache page with same object id
|
||||
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp == 0)
|
||||
{
|
||||
if (cp == 0) {
|
||||
// could not get cache page
|
||||
return 0;
|
||||
}
|
||||
@ -313,19 +267,13 @@ extern "C" {
|
||||
}
|
||||
|
||||
// unrefers all fds that this cache page refers to and releases the cache page
|
||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp)
|
||||
{
|
||||
if (cp == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
|
||||
if (cp == 0) return;
|
||||
u32_t i;
|
||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
||||
for (i = 0; i < fs->fd_count; i++)
|
||||
{
|
||||
for (i = 0; i < fs->fd_count; i++) {
|
||||
spiffs_fd *cur_fd = &fds[i];
|
||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp)
|
||||
{
|
||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
||||
cur_fd->cache_page = 0;
|
||||
}
|
||||
}
|
||||
@ -337,24 +285,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
// initializes the cache
|
||||
void spiffs_cache_init(spiffs *fs)
|
||||
{
|
||||
if (fs->cache == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void spiffs_cache_init(spiffs *fs) {
|
||||
if (fs->cache == 0) return;
|
||||
u32_t sz = fs->cache_size;
|
||||
u32_t cache_mask = 0;
|
||||
int i;
|
||||
int cache_entries =
|
||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
if (cache_entries <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (cache_entries <= 0) return;
|
||||
|
||||
for (i = 0; i < cache_entries; i++)
|
||||
{
|
||||
for (i = 0; i < cache_entries; i++) {
|
||||
cache_mask <<= 1;
|
||||
cache_mask |= 1;
|
||||
}
|
||||
@ -373,8 +313,7 @@ extern "C" {
|
||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
|
||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
||||
for (i = 0; i < cache.cpage_count; i++)
|
||||
{
|
||||
for (i = 0; i < cache.cpage_count; i++) {
|
||||
spiffs_get_cache_page_hdr(fs, c, i)->ix = i;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
/*
|
||||
spiffs_config.h
|
||||
|
||||
Created on: Jul 3, 2013
|
||||
Author: petera
|
||||
* spiffs_config.h
|
||||
*
|
||||
* Created on: Jul 3, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
|
@ -10,8 +10,7 @@ extern "C" {
|
||||
// is dropped.
|
||||
static s32_t spiffs_gc_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix)
|
||||
{
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res;
|
||||
|
||||
SPIFFS_GC_DBG("gc: erase block " _SPIPRIbl "\n", bix);
|
||||
@ -21,8 +20,7 @@ extern "C" {
|
||||
#if SPIFFS_CACHE
|
||||
{
|
||||
u32_t i;
|
||||
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++)
|
||||
{
|
||||
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
|
||||
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);
|
||||
}
|
||||
}
|
||||
@ -34,8 +32,7 @@ extern "C" {
|
||||
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
||||
// that no updates are needed on existing objects on pages that are erased.
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages)
|
||||
{
|
||||
spiffs *fs, u16_t max_free_pages) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
@ -52,41 +49,32 @@ extern "C" {
|
||||
|
||||
// find fully deleted blocks
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--)
|
||||
{
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t free_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
{
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)))
|
||||
{
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_DELETED)
|
||||
{
|
||||
if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
}
|
||||
else if (obj_id == SPIFFS_OBJ_ID_FREE)
|
||||
{
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// kill scan, go for next block
|
||||
free_pages_in_block++;
|
||||
if (free_pages_in_block > max_free_pages)
|
||||
{
|
||||
if (free_pages_in_block > max_free_pages) {
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// kill scan, go for next block
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
@ -96,15 +84,11 @@ extern "C" {
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1)
|
||||
{
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
if (res == SPIFFS_OK &&
|
||||
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
|
||||
free_pages_in_block <= max_free_pages)
|
||||
{
|
||||
free_pages_in_block <= max_free_pages) {
|
||||
// found a fully deleted block
|
||||
fs->stats_p_deleted -= deleted_pages_in_block;
|
||||
res = spiffs_gc_erase_block(fs, cur_block);
|
||||
@ -116,8 +100,7 @@ extern "C" {
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
if (res == SPIFFS_OK)
|
||||
{
|
||||
if (res == SPIFFS_OK) {
|
||||
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
|
||||
}
|
||||
return res;
|
||||
@ -127,8 +110,7 @@ extern "C" {
|
||||
// cleansed and erased
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len)
|
||||
{
|
||||
u32_t len) {
|
||||
s32_t res;
|
||||
s32_t free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
|
||||
@ -136,8 +118,7 @@ extern "C" {
|
||||
int tries = 0;
|
||||
|
||||
if (fs->free_blocks > 3 &&
|
||||
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs))
|
||||
{
|
||||
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
@ -146,14 +127,12 @@ extern "C" {
|
||||
// SPIFFS_GC_DBG("gc: full freeblk:" _SPIPRIi " needed:" _SPIPRIi " free:" _SPIPRIi " dele:" _SPIPRIi "\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
// return SPIFFS_ERR_FULL;
|
||||
// }
|
||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted))
|
||||
{
|
||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
||||
SPIFFS_GC_DBG("gc_check: full freeblk:" _SPIPRIi " needed:" _SPIPRIi " free:" _SPIPRIi " dele:" _SPIPRIi "\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
return SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
SPIFFS_GC_DBG("\ngc_check #" _SPIPRIi": run gc free_blocks:" _SPIPRIi " pfree:" _SPIPRIi " pallo:" _SPIPRIi " pdele:" _SPIPRIi " [" _SPIPRIi"] len:" _SPIPRIi " of " _SPIPRIi "\n",
|
||||
tries,
|
||||
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
||||
@ -166,8 +145,7 @@ extern "C" {
|
||||
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
|
||||
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (count == 0)
|
||||
{
|
||||
if (count == 0) {
|
||||
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
|
||||
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
|
||||
}
|
||||
@ -179,12 +157,9 @@ extern "C" {
|
||||
//SPIFFS_GC_DBG("gcing: cleaning block " _SPIPRIi "\n", cand);
|
||||
res = spiffs_gc_clean(fs, cand);
|
||||
fs->cleaning = 0;
|
||||
if (res < 0)
|
||||
{
|
||||
if (res < 0) {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block " _SPIPRIi ", result " _SPIPRIi "\n", cand, res);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block " _SPIPRIi ", result " _SPIPRIi "\n", cand, res);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
@ -199,8 +174,7 @@ extern "C" {
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
|
||||
if (prev_free_pages <= 0 && prev_free_pages == free_pages)
|
||||
{
|
||||
if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
|
||||
// abort early to reduce wear, at least tried once
|
||||
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
|
||||
break;
|
||||
@ -212,8 +186,7 @@ extern "C" {
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
if ((s32_t)len > free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs))
|
||||
{
|
||||
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
res = SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
@ -227,8 +200,7 @@ extern "C" {
|
||||
// Updates page statistics for a block that is about to be erased
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix)
|
||||
{
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
int obj_lookup_page = 0;
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
@ -238,25 +210,18 @@ extern "C" {
|
||||
u32_t allo = 0;
|
||||
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
{
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)))
|
||||
{
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE)
|
||||
{
|
||||
}
|
||||
else if (obj_id == SPIFFS_OBJ_ID_DELETED)
|
||||
{
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
dele++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
allo++;
|
||||
}
|
||||
cur_entry++;
|
||||
@ -274,8 +239,7 @@ extern "C" {
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidates,
|
||||
int *candidate_count,
|
||||
char fs_crammed)
|
||||
{
|
||||
char fs_crammed) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
@ -300,51 +264,39 @@ extern "C" {
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--)
|
||||
{
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t used_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
{
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)))
|
||||
{
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE)
|
||||
{
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// when a free entry is encountered, scan logic ensures that all following entries are free also
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
else if (obj_id == SPIFFS_OBJ_ID_DELETED)
|
||||
{
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
used_pages_in_block++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1)
|
||||
{
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
// calculate score and insert into candidate table
|
||||
// stoneage sort, but probably not so many blocks
|
||||
if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/)
|
||||
{
|
||||
if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {
|
||||
// read erase count
|
||||
spiffs_obj_id erase_count;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
|
||||
@ -353,12 +305,9 @@ extern "C" {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_obj_id erase_age;
|
||||
if (fs->max_erase_count > erase_count)
|
||||
{
|
||||
if (fs->max_erase_count > erase_count) {
|
||||
erase_age = fs->max_erase_count - erase_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
|
||||
}
|
||||
|
||||
@ -368,19 +317,14 @@ extern "C" {
|
||||
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
||||
int cand_ix = 0;
|
||||
SPIFFS_GC_DBG("gc_check: bix:" _SPIPRIbl" del:" _SPIPRIi " use:" _SPIPRIi " score:" _SPIPRIi "\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
||||
while (cand_ix < max_candidates)
|
||||
{
|
||||
if (cand_blocks[cand_ix] == (spiffs_block_ix) - 1)
|
||||
{
|
||||
while (cand_ix < max_candidates) {
|
||||
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
}
|
||||
else if (cand_scores[cand_ix] < score)
|
||||
{
|
||||
} else if (cand_scores[cand_ix] < score) {
|
||||
int reorder_cand_ix = max_candidates - 2;
|
||||
while (reorder_cand_ix >= cand_ix)
|
||||
{
|
||||
while (reorder_cand_ix >= cand_ix) {
|
||||
cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
|
||||
cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
|
||||
reorder_cand_ix--;
|
||||
@ -402,16 +346,14 @@ extern "C" {
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
FIND_OBJ_DATA,
|
||||
MOVE_OBJ_DATA,
|
||||
MOVE_OBJ_IX,
|
||||
FINISHED
|
||||
} spiffs_gc_clean_state;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
spiffs_gc_clean_state state;
|
||||
spiffs_obj_id cur_obj_id;
|
||||
spiffs_span_ix cur_objix_spix;
|
||||
@ -434,8 +376,7 @@ extern "C" {
|
||||
// repeat loop until end of object lookup
|
||||
// scan object lookup again for remaining object index pages, move to new page in other block
|
||||
//
|
||||
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix)
|
||||
{
|
||||
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
// this is the global localizer being pushed and popped
|
||||
@ -451,16 +392,14 @@ extern "C" {
|
||||
memset(&gc, 0, sizeof(spiffs_gc));
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
|
||||
if (fs->free_cursor_block_ix == bix)
|
||||
{
|
||||
if (fs->free_cursor_block_ix == bix) {
|
||||
// move free cursor to next block, cannot use free pages from the block we want to clean
|
||||
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
||||
fs->free_cursor_obj_lu_entry = 0;
|
||||
SPIFFS_GC_DBG("gc_clean: move free cursor to block " _SPIPRIbl "\n", fs->free_cursor_block_ix);
|
||||
}
|
||||
|
||||
while (res == SPIFFS_OK && gc.state != FINISHED)
|
||||
{
|
||||
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
||||
SPIFFS_GC_DBG("gc_clean: state = " _SPIPRIi " entry:" _SPIPRIi "\n", gc.state, cur_entry);
|
||||
gc.obj_id_found = 0; // reset (to no found data page)
|
||||
|
||||
@ -468,27 +407,23 @@ extern "C" {
|
||||
int obj_lookup_page = cur_entry / entries_per_page;
|
||||
u8_t scan = 1;
|
||||
// check each object lookup page
|
||||
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
{
|
||||
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each object lookup entry
|
||||
while (scan && res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)))
|
||||
{
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
|
||||
|
||||
// act upon object id depending on gc state
|
||||
switch (gc.state)
|
||||
{
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
// find a data page
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0))
|
||||
{
|
||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
||||
// found a data page, stop scanning and handle in switch case below
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:" _SPIPRIi " - found obj id " _SPIPRIid"\n", gc.state, obj_id);
|
||||
gc.obj_id_found = 1;
|
||||
@ -500,22 +435,17 @@ extern "C" {
|
||||
case MOVE_OBJ_DATA:
|
||||
// evacuate found data pages for corresponding object index we have in memory,
|
||||
// update memory representation
|
||||
if (obj_id == gc.cur_obj_id)
|
||||
{
|
||||
if (obj_id == gc.cur_obj_id) {
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page " _SPIPRIid":" _SPIPRIsp" @ " _SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
|
||||
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix)
|
||||
{
|
||||
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
spiffs_page_ix new_data_pix;
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET)
|
||||
{
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg" to " _SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);
|
||||
@ -525,9 +455,7 @@ extern "C" {
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
@ -537,14 +465,11 @@ extern "C" {
|
||||
new_data_pix = SPIFFS_OBJ_ID_FREE;
|
||||
}
|
||||
// update memory representation of object index page with new data page
|
||||
if (gc.cur_objix_spix == 0)
|
||||
{
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// update object index header page
|
||||
((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page " _SPIPRIpg" to objix_hdr entry " _SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// update object index page
|
||||
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page " _SPIPRIpg" to objix entry " _SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
@ -555,8 +480,7 @@ extern "C" {
|
||||
case MOVE_OBJ_IX:
|
||||
// find and evacuate object index pages
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG))
|
||||
{
|
||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// found an index object id
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix new_pix;
|
||||
@ -564,8 +488,7 @@ extern "C" {
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET)
|
||||
{
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg" to " _SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
|
||||
@ -577,16 +500,13 @@ extern "C" {
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
if (res == SPIFFS_OK)
|
||||
{
|
||||
if (res == SPIFFS_OK) {
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
|
||||
SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
|
||||
}
|
||||
@ -602,17 +522,12 @@ extern "C" {
|
||||
} // per entry
|
||||
obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop
|
||||
} // per object lookup page
|
||||
if (res != SPIFFS_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (res != SPIFFS_OK) break;
|
||||
|
||||
// state finalization and switch
|
||||
switch (gc.state)
|
||||
{
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
if (gc.obj_id_found)
|
||||
{
|
||||
if (gc.obj_id_found) {
|
||||
// handle found data page -
|
||||
// find out corresponding obj ix page and load it to memory
|
||||
spiffs_page_header p_hdr;
|
||||
@ -626,8 +541,7 @@ extern "C" {
|
||||
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:" _SPIPRIsp"\n", gc.cur_objix_spix);
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND)
|
||||
{
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// on borked systems we might get an ERR_NOT_FOUND here -
|
||||
// this is handled by simply deleting the page as it is not referenced
|
||||
// from anywhere
|
||||
@ -648,31 +562,25 @@ extern "C" {
|
||||
// check must run or lot of data may be lost
|
||||
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);
|
||||
gc.cur_objix_pix = objix_pix;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// no more data pages found, passed thru all block, start evacuating object indices
|
||||
gc.state = MOVE_OBJ_IX;
|
||||
cur_entry = 0; // restart entry scan index
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA:
|
||||
{
|
||||
case MOVE_OBJ_DATA: {
|
||||
// store modified objix (hdr) page residing in memory now that all
|
||||
// data pages belonging to this object index and residing in the block
|
||||
// we want to evacuate
|
||||
spiffs_page_ix new_objix_pix;
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
cur_entry = gc.stored_scan_entry_index; // pop cursor
|
||||
if (gc.cur_objix_spix == 0)
|
||||
{
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// store object index header page
|
||||
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, " _SPIPRIpg":" _SPIPRIsp"\n", new_objix_pix, 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// store object index page
|
||||
res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, " _SPIPRIpg":" _SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,111 +1,111 @@
|
||||
/*
|
||||
spiffs_nucleus.h
|
||||
|
||||
Created on: Jun 15, 2013
|
||||
Author: petera
|
||||
* spiffs_nucleus.h
|
||||
*
|
||||
* Created on: Jun 15, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
/* SPIFFS layout
|
||||
|
||||
spiffs is designed for following spi flash characteristics:
|
||||
- only big areas of data (blocks) can be erased
|
||||
- erasing resets all bits in a block to ones
|
||||
- writing pulls ones to zeroes
|
||||
- zeroes cannot be pulled to ones, without erase
|
||||
- wear leveling
|
||||
|
||||
spiffs is also meant to be run on embedded, memory constraint devices.
|
||||
|
||||
Entire area is divided in blocks. Entire area is also divided in pages.
|
||||
Each block contains same number of pages. A page cannot be erased, but a
|
||||
block can be erased.
|
||||
|
||||
Entire area must be block_size * x
|
||||
page_size must be block_size / (2^y) where y > 2
|
||||
|
||||
ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||
|
||||
BLOCK 0 PAGE 0 object lookup 1
|
||||
PAGE 1 object lookup 2
|
||||
...
|
||||
PAGE n-1 object lookup n
|
||||
PAGE n object data 1
|
||||
PAGE n+1 object data 2
|
||||
...
|
||||
PAGE n+m-1 object data m
|
||||
|
||||
BLOCK 1 PAGE n+m object lookup 1
|
||||
PAGE n+m+1 object lookup 2
|
||||
...
|
||||
PAGE 2n+m-1 object lookup n
|
||||
PAGE 2n+m object data 1
|
||||
PAGE 2n+m object data 2
|
||||
...
|
||||
PAGE 2n+2m-1 object data m
|
||||
...
|
||||
|
||||
n is number of object lookup pages, which is number of pages needed to index all pages
|
||||
in a block by object id
|
||||
: block_size / page_size * sizeof(obj_id) / page_size
|
||||
m is number data pages, which is number of pages in block minus number of lookup pages
|
||||
: block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||
thus, n+m is total number of pages in a block
|
||||
: block_size / page_size
|
||||
|
||||
ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||
|
||||
Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||
data page.
|
||||
Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||
An object id being 0x0000 represents a deleted page.
|
||||
|
||||
ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||||
page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||||
page 2 : data : data for object id 0008
|
||||
page 3 : data : data for object id 0001
|
||||
page 4 : data : data for object id 0aaa
|
||||
...
|
||||
|
||||
|
||||
Object data pages can be either object index pages or object content.
|
||||
All object data pages contains a data page header, containing object id and span index.
|
||||
The span index denotes the object page ordering amongst data pages with same object id.
|
||||
This applies to both object index pages (when index spans more than one page of entries),
|
||||
and object data pages.
|
||||
An object index page contains page entries pointing to object content page. The entry index
|
||||
in a object index page correlates to the span index in the actual object data page.
|
||||
The first object index page (span index 0) is called object index header page, and also
|
||||
contains object flags (directory/file), size, object name etc.
|
||||
|
||||
ex:
|
||||
BLOCK 1
|
||||
PAGE 256: objectl lookup page 1
|
||||
[*123] [ 123] [ 123] [ 123]
|
||||
[ 123] [*123] [ 123] [ 123]
|
||||
[free] [free] [free] [free] ...
|
||||
PAGE 257: objectl lookup page 2
|
||||
[free] [free] [free] [free] ...
|
||||
PAGE 258: object index page (header)
|
||||
obj.id:0123 span.ix:0000 flags:INDEX
|
||||
size:1600 name:ex.txt type:file
|
||||
[259] [260] [261] [262]
|
||||
PAGE 259: object data page
|
||||
obj.id:0123 span.ix:0000 flags:DATA
|
||||
PAGE 260: object data page
|
||||
obj.id:0123 span.ix:0001 flags:DATA
|
||||
PAGE 261: object data page
|
||||
obj.id:0123 span.ix:0002 flags:DATA
|
||||
PAGE 262: object data page
|
||||
obj.id:0123 span.ix:0003 flags:DATA
|
||||
PAGE 263: object index page
|
||||
obj.id:0123 span.ix:0001 flags:INDEX
|
||||
[264] [265] [fre] [fre]
|
||||
[fre] [fre] [fre] [fre]
|
||||
PAGE 264: object data page
|
||||
obj.id:0123 span.ix:0004 flags:DATA
|
||||
PAGE 265: object data page
|
||||
obj.id:0123 span.ix:0005 flags:DATA
|
||||
|
||||
*
|
||||
* spiffs is designed for following spi flash characteristics:
|
||||
* - only big areas of data (blocks) can be erased
|
||||
* - erasing resets all bits in a block to ones
|
||||
* - writing pulls ones to zeroes
|
||||
* - zeroes cannot be pulled to ones, without erase
|
||||
* - wear leveling
|
||||
*
|
||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
||||
*
|
||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
||||
* Each block contains same number of pages. A page cannot be erased, but a
|
||||
* block can be erased.
|
||||
*
|
||||
* Entire area must be block_size * x
|
||||
* page_size must be block_size / (2^y) where y > 2
|
||||
*
|
||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||
*
|
||||
* BLOCK 0 PAGE 0 object lookup 1
|
||||
* PAGE 1 object lookup 2
|
||||
* ...
|
||||
* PAGE n-1 object lookup n
|
||||
* PAGE n object data 1
|
||||
* PAGE n+1 object data 2
|
||||
* ...
|
||||
* PAGE n+m-1 object data m
|
||||
*
|
||||
* BLOCK 1 PAGE n+m object lookup 1
|
||||
* PAGE n+m+1 object lookup 2
|
||||
* ...
|
||||
* PAGE 2n+m-1 object lookup n
|
||||
* PAGE 2n+m object data 1
|
||||
* PAGE 2n+m object data 2
|
||||
* ...
|
||||
* PAGE 2n+2m-1 object data m
|
||||
* ...
|
||||
*
|
||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
||||
* in a block by object id
|
||||
* : block_size / page_size * sizeof(obj_id) / page_size
|
||||
* m is number data pages, which is number of pages in block minus number of lookup pages
|
||||
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||
* thus, n+m is total number of pages in a block
|
||||
* : block_size / page_size
|
||||
*
|
||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||
*
|
||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||
* data page.
|
||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||
* An object id being 0x0000 represents a deleted page.
|
||||
*
|
||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||||
* page 2 : data : data for object id 0008
|
||||
* page 3 : data : data for object id 0001
|
||||
* page 4 : data : data for object id 0aaa
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* Object data pages can be either object index pages or object content.
|
||||
* All object data pages contains a data page header, containing object id and span index.
|
||||
* The span index denotes the object page ordering amongst data pages with same object id.
|
||||
* This applies to both object index pages (when index spans more than one page of entries),
|
||||
* and object data pages.
|
||||
* An object index page contains page entries pointing to object content page. The entry index
|
||||
* in a object index page correlates to the span index in the actual object data page.
|
||||
* The first object index page (span index 0) is called object index header page, and also
|
||||
* contains object flags (directory/file), size, object name etc.
|
||||
*
|
||||
* ex:
|
||||
* BLOCK 1
|
||||
* PAGE 256: objectl lookup page 1
|
||||
* [*123] [ 123] [ 123] [ 123]
|
||||
* [ 123] [*123] [ 123] [ 123]
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 257: objectl lookup page 2
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 258: object index page (header)
|
||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
||||
* size:1600 name:ex.txt type:file
|
||||
* [259] [260] [261] [262]
|
||||
* PAGE 259: object data page
|
||||
* obj.id:0123 span.ix:0000 flags:DATA
|
||||
* PAGE 260: object data page
|
||||
* obj.id:0123 span.ix:0001 flags:DATA
|
||||
* PAGE 261: object data page
|
||||
* obj.id:0123 span.ix:0002 flags:DATA
|
||||
* PAGE 262: object data page
|
||||
* obj.id:0123 span.ix:0003 flags:DATA
|
||||
* PAGE 263: object index page
|
||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
||||
* [264] [265] [fre] [fre]
|
||||
* [fre] [fre] [fre] [fre]
|
||||
* PAGE 264: object data page
|
||||
* obj.id:0123 span.ix:0004 flags:DATA
|
||||
* PAGE 265: object data page
|
||||
* obj.id:0123 span.ix:0005 flags:DATA
|
||||
*
|
||||
*/
|
||||
#ifndef SPIFFS_NUCLEUS_H_
|
||||
#define SPIFFS_NUCLEUS_H_
|
||||
@ -402,26 +402,22 @@ extern "C" {
|
||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||||
|
||||
// cache page struct
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// cache flags
|
||||
u8_t flags;
|
||||
// cache page index
|
||||
u8_t ix;
|
||||
// last access of this cache page
|
||||
u32_t last_access;
|
||||
union
|
||||
{
|
||||
union {
|
||||
// type read cache
|
||||
struct
|
||||
{
|
||||
struct {
|
||||
// read cache page index
|
||||
spiffs_page_ix pix;
|
||||
};
|
||||
#if SPIFFS_CACHE_WR
|
||||
// type write cache
|
||||
struct
|
||||
{
|
||||
struct {
|
||||
// write cache
|
||||
spiffs_obj_id obj_id;
|
||||
// offset in cache page
|
||||
@ -434,8 +430,7 @@ typedef struct
|
||||
} spiffs_cache_page;
|
||||
|
||||
// cache struct
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
u8_t cpage_count;
|
||||
u32_t last_access;
|
||||
u32_t cpage_use_map;
|
||||
@ -447,8 +442,7 @@ typedef struct
|
||||
|
||||
|
||||
// spiffs nucleus file descriptor
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// the filesystem of this descriptor
|
||||
spiffs *fs;
|
||||
// number of file descriptor - if 0, the file descriptor is closed
|
||||
@ -490,8 +484,7 @@ typedef struct
|
||||
// page header, part of each page except object lookup pages
|
||||
// NB: this is always aligned when the data page is an object index,
|
||||
// as in this case struct spiffs_page_object_ix is used
|
||||
typedef struct SPIFFS_PACKED
|
||||
{
|
||||
typedef struct SPIFFS_PACKED {
|
||||
// object id
|
||||
spiffs_obj_id obj_id;
|
||||
// object span index
|
||||
@ -523,8 +516,7 @@ __attribute((aligned(sizeof(spiffs_page_ix))))
|
||||
} spiffs_page_object_ix_header;
|
||||
|
||||
// object index page header
|
||||
typedef struct SPIFFS_PACKED
|
||||
{
|
||||
typedef struct SPIFFS_PACKED {
|
||||
spiffs_page_header p_hdr;
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
} spiffs_page_object_ix;
|
||||
|
@ -27,28 +27,24 @@ using namespace fs;
|
||||
|
||||
FileImplPtr SPIFFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode)
|
||||
{
|
||||
if (!isSpiffsFilenameValid(path))
|
||||
{
|
||||
if (!isSpiffsFilenameValid(path)) {
|
||||
DEBUGV("SPIFFSImpl::open: invalid path=`%s` \r\n", path);
|
||||
return FileImplPtr();
|
||||
}
|
||||
int mode = getSpiffsMode(openMode, accessMode);
|
||||
int fd = SPIFFS_open(&_fs, path, mode, 0);
|
||||
if (fd < 0 && _fs.err_code == SPIFFS_ERR_DELETED && (openMode & OM_CREATE))
|
||||
{
|
||||
if (fd < 0 && _fs.err_code == SPIFFS_ERR_DELETED && (openMode & OM_CREATE)) {
|
||||
DEBUGV("SPIFFSImpl::open: fd=%d path=`%s` openMode=%d accessMode=%d err=%d, trying to remove\r\n",
|
||||
fd, path, openMode, accessMode, _fs.err_code);
|
||||
auto rc = SPIFFS_remove(&_fs, path);
|
||||
if (rc != SPIFFS_OK)
|
||||
{
|
||||
if (rc != SPIFFS_OK) {
|
||||
DEBUGV("SPIFFSImpl::open: SPIFFS_ERR_DELETED, but failed to remove path=`%s` openMode=%d accessMode=%d err=%d\r\n",
|
||||
path, openMode, accessMode, _fs.err_code);
|
||||
return FileImplPtr();
|
||||
}
|
||||
fd = SPIFFS_open(&_fs, path, mode, 0);
|
||||
}
|
||||
if (fd < 0)
|
||||
{
|
||||
if (fd < 0) {
|
||||
DEBUGV("SPIFFSImpl::open: fd=%d path=`%s` openMode=%d accessMode=%d err=%d\r\n",
|
||||
fd, path, openMode, accessMode, _fs.err_code);
|
||||
return FileImplPtr();
|
||||
@ -58,8 +54,7 @@ FileImplPtr SPIFFSImpl::open(const char* path, OpenMode openMode, AccessMode acc
|
||||
|
||||
bool SPIFFSImpl::exists(const char* path)
|
||||
{
|
||||
if (!isSpiffsFilenameValid(path))
|
||||
{
|
||||
if (!isSpiffsFilenameValid(path)) {
|
||||
DEBUGV("SPIFFSImpl::exists: invalid path=`%s` \r\n", path);
|
||||
return false;
|
||||
}
|
||||
@ -70,15 +65,13 @@ bool SPIFFSImpl::exists(const char* path)
|
||||
|
||||
DirImplPtr SPIFFSImpl::openDir(const char* path)
|
||||
{
|
||||
if (strlen(path) > 0 && !isSpiffsFilenameValid(path))
|
||||
{
|
||||
if (strlen(path) > 0 && !isSpiffsFilenameValid(path)) {
|
||||
DEBUGV("SPIFFSImpl::openDir: invalid path=`%s` \r\n", path);
|
||||
return DirImplPtr();
|
||||
}
|
||||
spiffs_DIR dir;
|
||||
spiffs_DIR* result = SPIFFS_opendir(&_fs, path, &dir);
|
||||
if (!result)
|
||||
{
|
||||
if (!result) {
|
||||
DEBUGV("SPIFFSImpl::openDir: path=`%s` err=%d\r\n", path, _fs.err_code);
|
||||
return DirImplPtr();
|
||||
}
|
||||
@ -88,24 +81,19 @@ DirImplPtr SPIFFSImpl::openDir(const char* path)
|
||||
int getSpiffsMode(OpenMode openMode, AccessMode accessMode)
|
||||
{
|
||||
int mode = 0;
|
||||
if (openMode & OM_CREATE)
|
||||
{
|
||||
if (openMode & OM_CREATE) {
|
||||
mode |= SPIFFS_CREAT;
|
||||
}
|
||||
if (openMode & OM_APPEND)
|
||||
{
|
||||
if (openMode & OM_APPEND) {
|
||||
mode |= SPIFFS_APPEND;
|
||||
}
|
||||
if (openMode & OM_TRUNCATE)
|
||||
{
|
||||
if (openMode & OM_TRUNCATE) {
|
||||
mode |= SPIFFS_TRUNC;
|
||||
}
|
||||
if (accessMode & AM_READ)
|
||||
{
|
||||
if (accessMode & AM_READ) {
|
||||
mode |= SPIFFS_RDONLY;
|
||||
}
|
||||
if (accessMode & AM_WRITE)
|
||||
{
|
||||
if (accessMode & AM_WRITE) {
|
||||
mode |= SPIFFS_WRONLY;
|
||||
}
|
||||
return mode;
|
||||
@ -113,8 +101,7 @@ int getSpiffsMode(OpenMode openMode, AccessMode accessMode)
|
||||
|
||||
bool isSpiffsFilenameValid(const char* name)
|
||||
{
|
||||
if (name == nullptr)
|
||||
{
|
||||
if (name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto len = strlen(name);
|
||||
|
@ -79,19 +79,16 @@ public:
|
||||
|
||||
bool rename(const char* pathFrom, const char* pathTo) override
|
||||
{
|
||||
if (!isSpiffsFilenameValid(pathFrom))
|
||||
{
|
||||
if (!isSpiffsFilenameValid(pathFrom)) {
|
||||
DEBUGV("SPIFFSImpl::rename: invalid pathFrom=`%s`\r\n", pathFrom);
|
||||
return false;
|
||||
}
|
||||
if (!isSpiffsFilenameValid(pathTo))
|
||||
{
|
||||
if (!isSpiffsFilenameValid(pathTo)) {
|
||||
DEBUGV("SPIFFSImpl::rename: invalid pathTo=`%s` \r\n", pathTo);
|
||||
return false;
|
||||
}
|
||||
auto rc = SPIFFS_rename(&_fs, pathFrom, pathTo);
|
||||
if (rc != SPIFFS_OK)
|
||||
{
|
||||
if (rc != SPIFFS_OK) {
|
||||
DEBUGV("SPIFFS_rename: rc=%d, from=`%s`, to=`%s`\r\n", rc,
|
||||
pathFrom, pathTo);
|
||||
return false;
|
||||
@ -107,8 +104,7 @@ public:
|
||||
info.maxPathLength = SPIFFS_OBJ_NAME_LEN;
|
||||
uint32_t totalBytes, usedBytes;
|
||||
auto rc = SPIFFS_info(&_fs, &totalBytes, &usedBytes);
|
||||
if (rc != SPIFFS_OK)
|
||||
{
|
||||
if (rc != SPIFFS_OK) {
|
||||
DEBUGV("SPIFFS_info: rc=%d, err=%d\r\n", rc, _fs.err_code);
|
||||
return false;
|
||||
}
|
||||
@ -119,14 +115,12 @@ public:
|
||||
|
||||
bool remove(const char* path) override
|
||||
{
|
||||
if (!isSpiffsFilenameValid(path))
|
||||
{
|
||||
if (!isSpiffsFilenameValid(path)) {
|
||||
DEBUGV("SPIFFSImpl::remove: invalid path=`%s`\r\n", path);
|
||||
return false;
|
||||
}
|
||||
auto rc = SPIFFS_remove(&_fs, path);
|
||||
if (rc != SPIFFS_OK)
|
||||
{
|
||||
if (rc != SPIFFS_OK) {
|
||||
DEBUGV("SPIFFS_remove: rc=%d path=`%s`\r\n", rc, path);
|
||||
return false;
|
||||
}
|
||||
@ -147,8 +141,7 @@ public:
|
||||
|
||||
bool setConfig(const FSConfig &cfg) override
|
||||
{
|
||||
if ((cfg._type != SPIFFSConfig::fsid::FSId) || (SPIFFS_mounted(&_fs) != 0))
|
||||
{
|
||||
if ((cfg._type != SPIFFSConfig::fsid::FSId) || (SPIFFS_mounted(&_fs) != 0)) {
|
||||
return false;
|
||||
}
|
||||
_cfg = *static_cast<const SPIFFSConfig *>(&cfg);
|
||||
@ -157,39 +150,31 @@ public:
|
||||
|
||||
bool begin() override
|
||||
{
|
||||
if (SPIFFS_mounted(&_fs) != 0)
|
||||
{
|
||||
if (SPIFFS_mounted(&_fs) != 0) {
|
||||
return true;
|
||||
}
|
||||
if (_size == 0)
|
||||
{
|
||||
if (_size == 0) {
|
||||
DEBUGV("SPIFFS size is zero");
|
||||
return false;
|
||||
}
|
||||
if (_tryMount())
|
||||
{
|
||||
if (_tryMount()) {
|
||||
return true;
|
||||
}
|
||||
if (_cfg._autoFormat)
|
||||
{
|
||||
if (_cfg._autoFormat) {
|
||||
auto rc = SPIFFS_format(&_fs);
|
||||
if (rc != SPIFFS_OK)
|
||||
{
|
||||
if (rc != SPIFFS_OK) {
|
||||
DEBUGV("SPIFFS_format: rc=%d, err=%d\r\n", rc, _fs.err_code);
|
||||
return false;
|
||||
}
|
||||
return _tryMount();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void end() override
|
||||
{
|
||||
if (SPIFFS_mounted(&_fs) == 0)
|
||||
{
|
||||
if (SPIFFS_mounted(&_fs) == 0) {
|
||||
return;
|
||||
}
|
||||
SPIFFS_unmount(&_fs);
|
||||
@ -200,27 +185,23 @@ public:
|
||||
|
||||
bool format() override
|
||||
{
|
||||
if (_size == 0)
|
||||
{
|
||||
if (_size == 0) {
|
||||
DEBUGV("SPIFFS size is zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wasMounted = (SPIFFS_mounted(&_fs) != 0);
|
||||
|
||||
if (_tryMount())
|
||||
{
|
||||
if (_tryMount()) {
|
||||
SPIFFS_unmount(&_fs);
|
||||
}
|
||||
auto rc = SPIFFS_format(&_fs);
|
||||
if (rc != SPIFFS_OK)
|
||||
{
|
||||
if (rc != SPIFFS_OK) {
|
||||
DEBUGV("SPIFFS_format: rc=%d, err=%d\r\n", rc, _fs.err_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wasMounted)
|
||||
{
|
||||
if (wasMounted) {
|
||||
return _tryMount();
|
||||
}
|
||||
|
||||
@ -256,26 +237,22 @@ protected:
|
||||
config.log_page_size = _pageSize;
|
||||
|
||||
|
||||
if (((uint32_t) std::numeric_limits<spiffs_block_ix>::max()) < (_size / _blockSize))
|
||||
{
|
||||
if (((uint32_t) std::numeric_limits<spiffs_block_ix>::max()) < (_size / _blockSize)) {
|
||||
DEBUGV("spiffs_block_ix type too small");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (((uint32_t) std::numeric_limits<spiffs_page_ix>::max()) < (_size / _pageSize))
|
||||
{
|
||||
if (((uint32_t) std::numeric_limits<spiffs_page_ix>::max()) < (_size / _pageSize)) {
|
||||
DEBUGV("spiffs_page_ix type too small");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (((uint32_t) std::numeric_limits<spiffs_obj_id>::max()) < (2 + (_size / (2 * _pageSize)) * 2))
|
||||
{
|
||||
if (((uint32_t) std::numeric_limits<spiffs_obj_id>::max()) < (2 + (_size / (2*_pageSize))*2)) {
|
||||
DEBUGV("spiffs_obj_id type too small");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (((uint32_t) std::numeric_limits<spiffs_span_ix>::max()) < (_size / _pageSize - 1))
|
||||
{
|
||||
if (((uint32_t) std::numeric_limits<spiffs_span_ix>::max()) < (_size / _pageSize - 1)) {
|
||||
DEBUGV("spiffs_span_ix type too small");
|
||||
abort();
|
||||
}
|
||||
@ -290,8 +267,7 @@ protected:
|
||||
size_t fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&_fs, _maxOpenFds);
|
||||
size_t cacheBufSize = SPIFFS_buffer_bytes_for_cache(&_fs, _maxOpenFds);
|
||||
|
||||
if (!_workBuf)
|
||||
{
|
||||
if (!_workBuf) {
|
||||
DEBUGV("SPIFFSImpl: allocating %zd+%zd+%zd=%zd bytes\r\n",
|
||||
workBufSize, fdsBufSize, cacheBufSize,
|
||||
workBufSize + fdsBufSize + cacheBufSize);
|
||||
@ -364,8 +340,7 @@ public:
|
||||
CHECKFD();
|
||||
|
||||
auto result = SPIFFS_write(_fs->getFs(), _fd, (void*) buf, size);
|
||||
if (result < 0)
|
||||
{
|
||||
if (result < 0) {
|
||||
DEBUGV("SPIFFS_write rc=%d\r\n", result);
|
||||
return 0;
|
||||
}
|
||||
@ -377,8 +352,7 @@ public:
|
||||
{
|
||||
CHECKFD();
|
||||
auto result = SPIFFS_read(_fs->getFs(), _fd, (void*) buf, size);
|
||||
if (result < 0)
|
||||
{
|
||||
if (result < 0) {
|
||||
DEBUGV("SPIFFS_read rc=%d\r\n", result);
|
||||
return 0;
|
||||
}
|
||||
@ -391,8 +365,7 @@ public:
|
||||
CHECKFD();
|
||||
|
||||
auto rc = SPIFFS_fflush(_fs->getFs(), _fd);
|
||||
if (rc < 0)
|
||||
{
|
||||
if (rc < 0) {
|
||||
DEBUGV("SPIFFS_fflush rc=%d\r\n", rc);
|
||||
}
|
||||
_written = true;
|
||||
@ -403,13 +376,11 @@ public:
|
||||
CHECKFD();
|
||||
|
||||
int32_t offset = static_cast<int32_t>(pos);
|
||||
if (mode == SeekEnd)
|
||||
{
|
||||
if (mode == SeekEnd) {
|
||||
offset = -offset;
|
||||
}
|
||||
auto rc = SPIFFS_lseek(_fs->getFs(), _fd, offset, (int) mode);
|
||||
if (rc < 0)
|
||||
{
|
||||
if (rc < 0) {
|
||||
DEBUGV("SPIFFS_lseek rc=%d\r\n", rc);
|
||||
return false;
|
||||
}
|
||||
@ -422,8 +393,7 @@ public:
|
||||
CHECKFD();
|
||||
|
||||
auto result = SPIFFS_lseek(_fs->getFs(), _fd, 0, SPIFFS_SEEK_CUR);
|
||||
if (result < 0)
|
||||
{
|
||||
if (result < 0) {
|
||||
DEBUGV("SPIFFS_tell rc=%d\r\n", result);
|
||||
return 0;
|
||||
}
|
||||
@ -434,8 +404,7 @@ public:
|
||||
size_t size() const override
|
||||
{
|
||||
CHECKFD();
|
||||
if (_written)
|
||||
{
|
||||
if (_written) {
|
||||
_getStat();
|
||||
}
|
||||
return _stat.size;
|
||||
@ -445,12 +414,9 @@ public:
|
||||
{
|
||||
CHECKFD();
|
||||
spiffs_fd *sfd;
|
||||
if (spiffs_fd_get(_fs->getFs(), _fd, &sfd) == SPIFFS_OK)
|
||||
{
|
||||
if (spiffs_fd_get(_fs->getFs(), _fd, &sfd) == SPIFFS_OK) {
|
||||
return SPIFFS_OK == spiffs_object_truncate(sfd, size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -492,8 +458,7 @@ protected:
|
||||
{
|
||||
CHECKFD();
|
||||
auto rc = SPIFFS_fstat(_fs->getFs(), _fd, &_stat);
|
||||
if (rc != SPIFFS_OK)
|
||||
{
|
||||
if (rc != SPIFFS_OK) {
|
||||
DEBUGV("SPIFFS_fstat rc=%d\r\n", rc);
|
||||
memset(&_stat, 0, sizeof(_stat));
|
||||
}
|
||||
@ -525,15 +490,13 @@ public:
|
||||
|
||||
FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) override
|
||||
{
|
||||
if (!_valid)
|
||||
{
|
||||
if (!_valid) {
|
||||
return FileImplPtr();
|
||||
}
|
||||
int mode = getSpiffsMode(openMode, accessMode);
|
||||
auto fs = _fs->getFs();
|
||||
spiffs_file fd = SPIFFS_open_by_dirent(fs, &_dirent, mode, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (fd < 0) {
|
||||
DEBUGV("SPIFFSDirImpl::openFile: fd=%d path=`%s` openMode=%d accessMode=%d err=%d\r\n",
|
||||
fd, _dirent.name, openMode, accessMode, fs->err_code);
|
||||
return FileImplPtr();
|
||||
@ -543,8 +506,7 @@ public:
|
||||
|
||||
const char* fileName() override
|
||||
{
|
||||
if (!_valid)
|
||||
{
|
||||
if (!_valid) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -553,8 +515,7 @@ public:
|
||||
|
||||
size_t fileSize() override
|
||||
{
|
||||
if (!_valid)
|
||||
{
|
||||
if (!_valid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -576,8 +537,7 @@ public:
|
||||
bool next() override
|
||||
{
|
||||
const int n = _pattern.length();
|
||||
do
|
||||
{
|
||||
do {
|
||||
spiffs_dirent* result = SPIFFS_readdir(&_dir, &_dirent);
|
||||
_valid = (result != nullptr);
|
||||
} while(_valid && strncmp((const char*) _dirent.name, _pattern.c_str(), n) != 0);
|
||||
|
@ -42,24 +42,20 @@ extern "C" {
|
||||
alignedEnd: ^
|
||||
*/
|
||||
|
||||
int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst)
|
||||
{
|
||||
int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
|
||||
optimistic_yield(10000);
|
||||
|
||||
uint32_t result = SPIFFS_OK;
|
||||
uint32_t alignedBegin = (addr + 3) & (~3);
|
||||
uint32_t alignedEnd = (addr + size) & (~3);
|
||||
if (alignedEnd < alignedBegin)
|
||||
{
|
||||
if (alignedEnd < alignedBegin) {
|
||||
alignedEnd = alignedBegin;
|
||||
}
|
||||
|
||||
if (addr < alignedBegin)
|
||||
{
|
||||
if (addr < alignedBegin) {
|
||||
uint32_t nb = alignedBegin - addr;
|
||||
uint32_t tmp;
|
||||
if (!ESP.flashRead(alignedBegin - 4, &tmp, 4))
|
||||
{
|
||||
if (!ESP.flashRead(alignedBegin - 4, &tmp, 4)) {
|
||||
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
@ -67,23 +63,19 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst)
|
||||
memcpy(dst, ((uint8_t*) &tmp) + 4 - nb, nb);
|
||||
}
|
||||
|
||||
if (alignedEnd != alignedBegin)
|
||||
{
|
||||
if (alignedEnd != alignedBegin) {
|
||||
if (!ESP.flashRead(alignedBegin, (uint32_t*) (dst + alignedBegin - addr),
|
||||
alignedEnd - alignedBegin))
|
||||
{
|
||||
alignedEnd - alignedBegin)) {
|
||||
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr + size > alignedEnd)
|
||||
{
|
||||
if (addr + size > alignedEnd) {
|
||||
uint32_t nb = addr + size - alignedEnd;
|
||||
uint32_t tmp;
|
||||
if (!ESP.flashRead(alignedEnd, &tmp, 4))
|
||||
{
|
||||
if (!ESP.flashRead(alignedEnd, &tmp, 4)) {
|
||||
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
@ -107,55 +99,45 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst)
|
||||
|
||||
static const int UNALIGNED_WRITE_BUFFER_SIZE = 512;
|
||||
|
||||
int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src)
|
||||
{
|
||||
int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
|
||||
optimistic_yield(10000);
|
||||
|
||||
uint32_t alignedBegin = (addr + 3) & (~3);
|
||||
uint32_t alignedEnd = (addr + size) & (~3);
|
||||
if (alignedEnd < alignedBegin)
|
||||
{
|
||||
if (alignedEnd < alignedBegin) {
|
||||
alignedEnd = alignedBegin;
|
||||
}
|
||||
|
||||
if (addr < alignedBegin)
|
||||
{
|
||||
if (addr < alignedBegin) {
|
||||
uint32_t ofs = alignedBegin - addr;
|
||||
uint32_t nb = (size < ofs) ? size : ofs;
|
||||
uint8_t tmp[4] __attribute__((aligned(4))) = {0xff, 0xff, 0xff, 0xff};
|
||||
memcpy(tmp + 4 - ofs, src, nb);
|
||||
if (!ESP.flashWrite(alignedBegin - 4, (uint32_t*) tmp, 4))
|
||||
{
|
||||
if (!ESP.flashWrite(alignedBegin - 4, (uint32_t*) tmp, 4)) {
|
||||
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (alignedEnd != alignedBegin)
|
||||
{
|
||||
if (alignedEnd != alignedBegin) {
|
||||
uint32_t* srcLeftover = (uint32_t*) (src + alignedBegin - addr);
|
||||
uint32_t srcAlign = ((uint32_t) srcLeftover) & 3;
|
||||
if (!srcAlign)
|
||||
{
|
||||
if (!srcAlign) {
|
||||
if (!ESP.flashWrite(alignedBegin, (uint32_t*) srcLeftover,
|
||||
alignedEnd - alignedBegin))
|
||||
{
|
||||
alignedEnd - alignedBegin)) {
|
||||
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
uint8_t buf[UNALIGNED_WRITE_BUFFER_SIZE];
|
||||
for (uint32_t sizeLeft = alignedEnd - alignedBegin; sizeLeft;)
|
||||
{
|
||||
for (uint32_t sizeLeft = alignedEnd - alignedBegin; sizeLeft; ) {
|
||||
size_t willCopy = std::min(sizeLeft, sizeof(buf));
|
||||
memcpy(buf, srcLeftover, willCopy);
|
||||
|
||||
if (!ESP.flashWrite(alignedBegin, (uint32_t*) buf, willCopy))
|
||||
{
|
||||
if (!ESP.flashWrite(alignedBegin, (uint32_t*) buf, willCopy)) {
|
||||
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
@ -168,14 +150,12 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src)
|
||||
}
|
||||
}
|
||||
|
||||
if (addr + size > alignedEnd)
|
||||
{
|
||||
if (addr + size > alignedEnd) {
|
||||
uint32_t nb = addr + size - alignedEnd;
|
||||
uint32_t tmp = 0xffffffff;
|
||||
memcpy(&tmp, src + size - nb, nb);
|
||||
|
||||
if (!ESP.flashWrite(alignedEnd, &tmp, 4))
|
||||
{
|
||||
if (!ESP.flashWrite(alignedEnd, &tmp, 4)) {
|
||||
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
@ -185,21 +165,17 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src)
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
int32_t spiffs_hal_erase(uint32_t addr, uint32_t size)
|
||||
{
|
||||
int32_t spiffs_hal_erase(uint32_t addr, uint32_t size) {
|
||||
if ((size & (SPI_FLASH_SEC_SIZE - 1)) != 0 ||
|
||||
(addr & (SPI_FLASH_SEC_SIZE - 1)) != 0)
|
||||
{
|
||||
(addr & (SPI_FLASH_SEC_SIZE - 1)) != 0) {
|
||||
DEBUGV("_spif_erase called with addr=%x, size=%d\r\n", addr, size);
|
||||
abort();
|
||||
}
|
||||
const uint32_t sector = addr / SPI_FLASH_SEC_SIZE;
|
||||
const uint32_t sectorCount = size / SPI_FLASH_SEC_SIZE;
|
||||
for (uint32_t i = 0; i < sectorCount; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < sectorCount; ++i) {
|
||||
optimistic_yield(10000);
|
||||
if (!ESP.flashEraseSector(sector + i))
|
||||
{
|
||||
if (!ESP.flashEraseSector(sector + i)) {
|
||||
DEBUGV("_spif_erase addr=%x size=%d i=%d\r\n", addr, size, i);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
@ -18,21 +18,17 @@ extern "C" {
|
||||
for(;;)
|
||||
{
|
||||
if (g*g > n)
|
||||
{
|
||||
g ^= c;
|
||||
}
|
||||
c >>= 1;
|
||||
if (!c)
|
||||
{
|
||||
return g;
|
||||
}
|
||||
g |= c;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
tested with:
|
||||
|
||||
* tested with:
|
||||
*
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
@ -58,7 +54,7 @@ extern "C" {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
};
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
time.c - ESP8266-specific functions for SNTP
|
||||
Copyright (c) 2015 Peter Dobler. 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
|
||||
|
||||
* time.c - ESP8266-specific functions for SNTP
|
||||
* Copyright (c) 2015 Peter Dobler. 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 <time.h>
|
||||
@ -28,8 +28,7 @@ extern "C" {
|
||||
|
||||
#ifndef _TIMEVAL_DEFINED
|
||||
#define _TIMEVAL_DEFINED
|
||||
struct timeval
|
||||
{
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
@ -101,9 +100,7 @@ extern "C" {
|
||||
if (tp)
|
||||
{
|
||||
if (!timeshift64_is_set)
|
||||
{
|
||||
tune_timeshift64(sntp_get_current_timestamp() * 1000000ULL);
|
||||
}
|
||||
uint64_t currentTime_us = timeshift64 + micros64();
|
||||
tp->tv_sec = currentTime_us / 1000000ULL;
|
||||
tp->tv_usec = currentTime_us % 1000000ULL;
|
||||
|
@ -5,15 +5,15 @@
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
Neither the name of the copyright holders nor the names of
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
@ -206,18 +206,18 @@
|
||||
#if 0
|
||||
|
||||
/**
|
||||
\ingroup util_twi
|
||||
\def TW_STATUS_MASK
|
||||
The lower 3 bits of TWSR are reserved on the ATmega163.
|
||||
The 2 LSB carry the prescaler bits on the newer ATmegas.
|
||||
* \ingroup util_twi
|
||||
* \def TW_STATUS_MASK
|
||||
* The lower 3 bits of TWSR are reserved on the ATmega163.
|
||||
* The 2 LSB carry the prescaler bits on the newer ATmegas.
|
||||
*/
|
||||
#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|\
|
||||
_BV(TWS3))
|
||||
/**
|
||||
\ingroup util_twi
|
||||
\def TW_STATUS
|
||||
|
||||
TWSR, masked by TW_STATUS_MASK
|
||||
* \ingroup util_twi
|
||||
* \def TW_STATUS
|
||||
*
|
||||
* TWSR, masked by TW_STATUS_MASK
|
||||
*/
|
||||
#define TW_STATUS (TWSR & TW_STATUS_MASK)
|
||||
/*@}*/
|
||||
@ -225,7 +225,7 @@
|
||||
|
||||
|
||||
/**
|
||||
\name R/~W bit in SLA+R/W address field.
|
||||
* \name R/~W bit in SLA+R/W address field.
|
||||
*/
|
||||
|
||||
/*@{*/
|
||||
|
@ -22,23 +22,23 @@
|
||||
|
||||
|
||||
/**
|
||||
UART GPIOs
|
||||
|
||||
UART0 TX: 1 or 2
|
||||
UART0 RX: 3
|
||||
|
||||
UART0 SWAP TX: 15
|
||||
UART0 SWAP RX: 13
|
||||
|
||||
|
||||
UART1 TX: 7 (NC) or 2
|
||||
UART1 RX: 8 (NC)
|
||||
|
||||
UART1 SWAP TX: 11 (NC)
|
||||
UART1 SWAP RX: 6 (NC)
|
||||
|
||||
NC = Not Connected to Module Pads --> No Access
|
||||
|
||||
* UART GPIOs
|
||||
*
|
||||
* UART0 TX: 1 or 2
|
||||
* UART0 RX: 3
|
||||
*
|
||||
* UART0 SWAP TX: 15
|
||||
* UART0 SWAP RX: 13
|
||||
*
|
||||
*
|
||||
* UART1 TX: 7 (NC) or 2
|
||||
* UART1 RX: 8 (NC)
|
||||
*
|
||||
* UART1 SWAP TX: 11 (NC)
|
||||
* UART1 SWAP RX: 6 (NC)
|
||||
*
|
||||
* NC = Not Connected to Module Pads --> No Access
|
||||
*
|
||||
*/
|
||||
#include "Arduino.h"
|
||||
#include <pgmspace.h>
|
||||
@ -125,9 +125,7 @@ extern "C" {
|
||||
uart_rx_buffer_available_unsafe(const struct uart_rx_buffer_ * rx_buffer)
|
||||
{
|
||||
if(rx_buffer->wpos < rx_buffer->rpos)
|
||||
{
|
||||
return (rx_buffer->wpos + rx_buffer->size) - rx_buffer->rpos;
|
||||
}
|
||||
|
||||
return rx_buffer->wpos - rx_buffer->rpos;
|
||||
}
|
||||
@ -168,9 +166,7 @@ extern "C" {
|
||||
#else
|
||||
// discard oldest data
|
||||
if (++rx_buffer->rpos == rx_buffer->size)
|
||||
{
|
||||
rx_buffer->rpos = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
uint8_t data = USF(uart->uart_nr);
|
||||
@ -183,16 +179,12 @@ extern "C" {
|
||||
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];
|
||||
}
|
||||
@ -216,9 +208,7 @@ extern "C" {
|
||||
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);
|
||||
@ -231,9 +221,7 @@ extern "C" {
|
||||
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);
|
||||
@ -253,9 +241,7 @@ extern "C" {
|
||||
uart_read(uart_t* uart, char* userbuffer, size_t usersize)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ret = 0;
|
||||
ETS_UART_INTR_DISABLE();
|
||||
@ -266,9 +252,7 @@ extern "C" {
|
||||
{
|
||||
// no more data in sw buffer, take them from hw fifo
|
||||
while (ret < usersize && uart_rx_fifo_available(uart->uart_nr))
|
||||
{
|
||||
userbuffer[ret++] = USF(uart->uart_nr);
|
||||
}
|
||||
|
||||
// no more sw/hw data available
|
||||
break;
|
||||
@ -280,9 +264,7 @@ extern "C" {
|
||||
uart->rx_buffer->wpos - uart->rx_buffer->rpos:
|
||||
uart->rx_buffer->size - uart->rx_buffer->rpos;
|
||||
if (ret + chunk > usersize)
|
||||
{
|
||||
chunk = usersize - ret;
|
||||
}
|
||||
memcpy(userbuffer + ret, uart->rx_buffer->buffer + uart->rx_buffer->rpos, chunk);
|
||||
uart->rx_buffer->rpos = (uart->rx_buffer->rpos + chunk) % uart->rx_buffer->size;
|
||||
ret += chunk;
|
||||
@ -299,8 +281,7 @@ extern "C" {
|
||||
static void ICACHE_RAM_ATTR uart_isr_handle_data(void* arg, uint8_t data)
|
||||
{
|
||||
uart_t* uart = (uart_t*)arg;
|
||||
if (uart == NULL || !uart->rx_enabled)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -323,9 +304,7 @@ extern "C" {
|
||||
#else
|
||||
// discard oldest data
|
||||
if (++rx_buffer->rpos == rx_buffer->size)
|
||||
{
|
||||
rx_buffer->rpos = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
rx_buffer->buffer[rx_buffer->wpos] = data;
|
||||
@ -335,14 +314,10 @@ extern "C" {
|
||||
uint32_t usis = USIS(uart->uart_nr);
|
||||
|
||||
if(usis & (1 << UIOF))
|
||||
{
|
||||
uart->rx_overrun = true;
|
||||
}
|
||||
|
||||
if (usis & ((1 << UIFR) | (1 << UIPE) | (1 << UITO)))
|
||||
{
|
||||
uart->rx_error = true;
|
||||
}
|
||||
|
||||
USIC(uart->uart_nr) = usis;
|
||||
}
|
||||
@ -351,31 +326,21 @@ extern "C" {
|
||||
uart_resize_rx_buffer(uart_t* uart, size_t new_size)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -408,9 +373,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
if(usis & (1 << UIFF))
|
||||
{
|
||||
uart_rx_copy_fifo_to_buffer_unsafe(uart);
|
||||
}
|
||||
|
||||
if(usis & (1 << UIOF))
|
||||
{
|
||||
@ -419,9 +382,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
if (usis & ((1 << UIFR) | (1 << UIPE) | (1 << UITO)))
|
||||
{
|
||||
uart->rx_error = true;
|
||||
}
|
||||
|
||||
USIC(uart->uart_nr) = usis;
|
||||
}
|
||||
@ -430,12 +391,9 @@ extern "C" {
|
||||
uart_start_isr(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdbstub_has_uart_isr_control())
|
||||
{
|
||||
if(gdbstub_has_uart_isr_control()) {
|
||||
gdbstub_set_uart_isr_callback(uart_isr_handle_data, (void *)uart);
|
||||
return;
|
||||
}
|
||||
@ -468,12 +426,9 @@ extern "C" {
|
||||
uart_stop_isr(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdbstub_has_uart_isr_control())
|
||||
{
|
||||
if(gdbstub_has_uart_isr_control()) {
|
||||
gdbstub_set_uart_isr_callback(NULL, NULL);
|
||||
return;
|
||||
}
|
||||
@ -516,12 +471,9 @@ extern "C" {
|
||||
uart_write_char(uart_t* uart, char c)
|
||||
{
|
||||
if(uart == NULL || !uart->tx_enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gdbstub_has_uart_isr_control() && uart->uart_nr == UART0)
|
||||
{
|
||||
if(gdbstub_has_uart_isr_control() && uart->uart_nr == UART0) {
|
||||
gdbstub_write_char(c);
|
||||
return 1;
|
||||
}
|
||||
@ -533,12 +485,9 @@ extern "C" {
|
||||
uart_write(uart_t* uart, const char* buf, size_t size)
|
||||
{
|
||||
if(uart == NULL || !uart->tx_enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gdbstub_has_uart_isr_control() && uart->uart_nr == UART0)
|
||||
{
|
||||
if(gdbstub_has_uart_isr_control() && uart->uart_nr == UART0) {
|
||||
gdbstub_write(buf, size);
|
||||
return 0;
|
||||
}
|
||||
@ -546,9 +495,7 @@ extern "C" {
|
||||
size_t ret = size;
|
||||
const int uart_nr = uart->uart_nr;
|
||||
while (size--)
|
||||
{
|
||||
uart_do_write_char(uart_nr, *buf++);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -558,9 +505,7 @@ extern "C" {
|
||||
uart_tx_free(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->tx_enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return UART_TX_FIFO_SIZE - uart_tx_fifo_available(uart->uart_nr);
|
||||
}
|
||||
@ -569,14 +514,10 @@ extern "C" {
|
||||
uart_wait_tx_empty(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->tx_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while(uart_tx_fifo_available(uart->uart_nr) > 0)
|
||||
{
|
||||
delay(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -584,9 +525,7 @@ extern "C" {
|
||||
uart_flush(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t tmp = 0x00000000;
|
||||
if(uart->rx_enabled)
|
||||
@ -599,12 +538,9 @@ extern "C" {
|
||||
}
|
||||
|
||||
if(uart->tx_enabled)
|
||||
{
|
||||
tmp |= (1 << UCTXRST);
|
||||
}
|
||||
|
||||
if (!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0)
|
||||
{
|
||||
if(!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0) {
|
||||
USC0(uart->uart_nr) |= (tmp);
|
||||
USC0(uart->uart_nr) &= ~(tmp);
|
||||
}
|
||||
@ -614,9 +550,7 @@ extern "C" {
|
||||
uart_set_baudrate(uart_t* uart, int baud_rate)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uart->baud_rate = baud_rate;
|
||||
USD(uart->uart_nr) = (ESP8266_CLOCK / uart->baud_rate);
|
||||
@ -626,9 +560,7 @@ extern "C" {
|
||||
uart_get_baudrate(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return uart->baud_rate;
|
||||
}
|
||||
@ -638,9 +570,7 @@ extern "C" {
|
||||
{
|
||||
uart_t* uart = (uart_t*) malloc(sizeof(uart_t));
|
||||
if(uart == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uart->uart_nr = uart_nr;
|
||||
uart->rx_overrun = false;
|
||||
@ -650,8 +580,7 @@ extern "C" {
|
||||
{
|
||||
case UART0:
|
||||
ETS_UART_INTR_DISABLE();
|
||||
if (!gdbstub_has_uart_isr_control())
|
||||
{
|
||||
if(!gdbstub_has_uart_isr_control()) {
|
||||
ETS_UART_INTR_ATTACH(NULL, NULL);
|
||||
}
|
||||
uart->rx_enabled = (mode != UART_TX_ONLY);
|
||||
@ -705,9 +634,7 @@ extern "C" {
|
||||
uart->rx_pin = 255;
|
||||
uart->tx_pin = (uart->tx_enabled)?2:255; // GPIO7 as TX not possible! See GPIO pins used by UART
|
||||
if(uart->tx_enabled)
|
||||
{
|
||||
pinMode(uart->tx_pin, SPECIAL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -721,21 +648,17 @@ extern "C" {
|
||||
uart_set_baudrate(uart, baudrate);
|
||||
USC0(uart->uart_nr) = config;
|
||||
|
||||
if (!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0)
|
||||
{
|
||||
if(!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0) {
|
||||
uart_flush(uart);
|
||||
USC1(uart->uart_nr) = 0;
|
||||
USIC(uart->uart_nr) = 0xffff;
|
||||
USIE(uart->uart_nr) = 0;
|
||||
}
|
||||
if (uart->uart_nr == UART0)
|
||||
{
|
||||
if (uart->rx_enabled)
|
||||
{
|
||||
if(uart->uart_nr == UART0) {
|
||||
if(uart->rx_enabled) {
|
||||
uart_start_isr(uart);
|
||||
}
|
||||
if (gdbstub_has_uart_isr_control())
|
||||
{
|
||||
if(gdbstub_has_uart_isr_control()) {
|
||||
ETS_UART_INTR_ENABLE(); // Undo the disable in the switch() above
|
||||
}
|
||||
}
|
||||
@ -747,14 +670,11 @@ extern "C" {
|
||||
uart_uninit(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uart_stop_isr(uart);
|
||||
|
||||
if (uart->tx_enabled && (!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0))
|
||||
{
|
||||
if(uart->tx_enabled && (!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0)) {
|
||||
switch(uart->tx_pin)
|
||||
{
|
||||
case 1:
|
||||
@ -769,12 +689,10 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
if (uart->rx_enabled)
|
||||
{
|
||||
if(uart->rx_enabled) {
|
||||
free(uart->rx_buffer->buffer);
|
||||
free(uart->rx_buffer);
|
||||
if (!gdbstub_has_uart_isr_control())
|
||||
{
|
||||
if(!gdbstub_has_uart_isr_control()) {
|
||||
switch(uart->rx_pin)
|
||||
{
|
||||
case 3:
|
||||
@ -793,9 +711,7 @@ extern "C" {
|
||||
uart_swap(uart_t* uart, int tx_pin)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(uart->uart_nr)
|
||||
{
|
||||
@ -813,14 +729,10 @@ extern "C" {
|
||||
uart->rx_pin = 13;
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -837,14 +749,10 @@ extern "C" {
|
||||
uart->rx_pin = 3;
|
||||
}
|
||||
if(uart->tx_enabled)
|
||||
{
|
||||
pinMode(uart->tx_pin, (tx_pin == 2)?FUNCTION_4:SPECIAL); //TX
|
||||
}
|
||||
|
||||
if(uart->rx_enabled)
|
||||
{
|
||||
pinMode(3, SPECIAL); //RX
|
||||
}
|
||||
|
||||
IOSWAP &= ~(1 << IOSWAPU0);
|
||||
}
|
||||
@ -861,9 +769,7 @@ extern "C" {
|
||||
uart_set_tx(uart_t* uart, int tx_pin)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(uart->uart_nr)
|
||||
{
|
||||
@ -897,9 +803,7 @@ extern "C" {
|
||||
uart_set_pins(uart_t* uart, int tx, int rx)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(uart->uart_nr == UART0) // Only UART0 allows pin changes
|
||||
{
|
||||
@ -912,30 +816,22 @@ extern "C" {
|
||||
else if (rx == 3 && (tx == 1 || tx == 2))
|
||||
{
|
||||
if (uart->rx_pin != rx)
|
||||
{
|
||||
uart_swap(uart, tx);
|
||||
}
|
||||
else
|
||||
{
|
||||
uart_set_tx(uart, tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(uart->rx_enabled && uart->rx_pin != rx && rx == 13 && tx == 15)
|
||||
{
|
||||
uart_swap(uart, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
uart_tx_enabled(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return uart->tx_enabled;
|
||||
}
|
||||
@ -944,9 +840,7 @@ extern "C" {
|
||||
uart_rx_enabled(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return uart->rx_enabled;
|
||||
}
|
||||
@ -955,9 +849,7 @@ extern "C" {
|
||||
uart_has_overrun (uart_t* uart)
|
||||
{
|
||||
if (uart == NULL || !uart->rx_overrun)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear flag
|
||||
uart->rx_overrun = false;
|
||||
@ -968,9 +860,7 @@ extern "C" {
|
||||
uart_has_rx_error (uart_t* uart)
|
||||
{
|
||||
if (uart == NULL || !uart->rx_error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear flag
|
||||
uart->rx_error = false;
|
||||
@ -987,9 +877,7 @@ extern "C" {
|
||||
uart_write_char_delay(const int uart_nr, char c)
|
||||
{
|
||||
while(uart_tx_fifo_full(uart_nr))
|
||||
{
|
||||
delay(0);
|
||||
}
|
||||
|
||||
USF(uart_nr) = c;
|
||||
|
||||
@ -1025,18 +913,12 @@ extern "C" {
|
||||
func = &uart_ignore_char;
|
||||
break;
|
||||
}
|
||||
if (gdbstub_has_putc1_control())
|
||||
{
|
||||
if(gdbstub_has_putc1_control()) {
|
||||
gdbstub_set_putc1_callback(func);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uart_nr == UART0 || uart_nr == UART1)
|
||||
{
|
||||
} else {
|
||||
if (uart_nr == UART0 || uart_nr == UART1) {
|
||||
system_set_os_print(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
system_set_os_print(0);
|
||||
}
|
||||
ets_install_putc1((void *) func);
|
||||
@ -1071,8 +953,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
int32_t divisor = uart_baudrate_detect(uart_nr, 1);
|
||||
if (!divisor)
|
||||
{
|
||||
if (!divisor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1086,8 +967,7 @@ extern "C" {
|
||||
{
|
||||
if (baudrate <= default_rates[i])
|
||||
{
|
||||
if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate)
|
||||
{
|
||||
if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) {
|
||||
i--;
|
||||
}
|
||||
break;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
umm_malloc.h - a memory allocator for embedded systems (microcontrollers)
|
||||
|
||||
See copyright notice in LICENSE.TXT
|
||||
----------------------------------------------------------------------------
|
||||
* umm_malloc.h - a memory allocator for embedded systems (microcontrollers)
|
||||
*
|
||||
* See copyright notice in LICENSE.TXT
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef UMM_MALLOC_H
|
||||
@ -16,8 +16,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct UMM_HEAP_INFO_t
|
||||
{
|
||||
typedef struct UMM_HEAP_INFO_t {
|
||||
unsigned short int totalEntries;
|
||||
unsigned short int usedEntries;
|
||||
unsigned short int freeEntries;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Configuration for umm_malloc
|
||||
* Configuration for umm_malloc
|
||||
*/
|
||||
|
||||
#ifndef _UMM_MALLOC_CFG_H
|
||||
@ -15,49 +15,49 @@ extern "C" {
|
||||
|
||||
#include "c_types.h"
|
||||
/*
|
||||
There are a number of defines you can set at compile time that affect how
|
||||
the memory allocator will operate.
|
||||
You can set them in your config file umm_malloc_cfg.h.
|
||||
In GNU C, you also can set these compile time defines like this:
|
||||
|
||||
-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.
|
||||
|
||||
-D UMM_BEST_FIT (defualt)
|
||||
|
||||
Set this if you want to use a best-fit algorithm for allocating new
|
||||
blocks
|
||||
|
||||
-D UMM_FIRST_FIT
|
||||
|
||||
Set this if you want to use a first-fit algorithm for allocating new
|
||||
blocks
|
||||
|
||||
-D UMM_DBG_LOG_LEVEL=n
|
||||
|
||||
Set n to a value from 0 to 6 depending on how verbose you want the debug
|
||||
log to be
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Support for this library in a multitasking environment is provided when
|
||||
you add bodies to the UMM_CRITICAL_ENTRY and UMM_CRITICAL_EXIT macros
|
||||
(see below)
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
* There are a number of defines you can set at compile time that affect how
|
||||
* the memory allocator will operate.
|
||||
* You can set them in your config file umm_malloc_cfg.h.
|
||||
* In GNU C, you also can set these compile time defines like this:
|
||||
*
|
||||
* -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.
|
||||
*
|
||||
* -D UMM_BEST_FIT (defualt)
|
||||
*
|
||||
* Set this if you want to use a best-fit algorithm for allocating new
|
||||
* blocks
|
||||
*
|
||||
* -D UMM_FIRST_FIT
|
||||
*
|
||||
* Set this if you want to use a first-fit algorithm for allocating new
|
||||
* blocks
|
||||
*
|
||||
* -D UMM_DBG_LOG_LEVEL=n
|
||||
*
|
||||
* Set n to a value from 0 to 6 depending on how verbose you want the debug
|
||||
* log to be
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Support for this library in a multitasking environment is provided when
|
||||
* you add bodies to the UMM_CRITICAL_ENTRY and UMM_CRITICAL_EXIT macros
|
||||
* (see below)
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
@ -101,61 +101,61 @@ extern char _heap_start;
|
||||
#define UMM_H_ATTPACKSUF __attribute__((__packed__))
|
||||
|
||||
/*
|
||||
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
|
||||
your system uses for this purpose. You can disable interrupts entirely, or
|
||||
just disable task switching - it's up to you
|
||||
|
||||
NOTE WELL that these macros MUST be allowed to nest, because umm_free() is
|
||||
called from within umm_malloc()
|
||||
* 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
|
||||
* your system uses for this purpose. You can disable interrupts entirely, or
|
||||
* just disable task switching - it's up to you
|
||||
*
|
||||
* NOTE WELL that these macros MUST be allowed to nest, because umm_free() is
|
||||
* called from within umm_malloc()
|
||||
*/
|
||||
|
||||
#define UMM_CRITICAL_ENTRY() ets_intr_lock()
|
||||
#define UMM_CRITICAL_EXIT() ets_intr_unlock()
|
||||
|
||||
/*
|
||||
-D UMM_INTEGRITY_CHECK :
|
||||
|
||||
Enables heap integrity check before any heap operation. It affects
|
||||
performance, but does NOT consume extra memory.
|
||||
|
||||
If integrity violation is detected, the message is printed and user-provided
|
||||
callback is called: `UMM_HEAP_CORRUPTION_CB()`
|
||||
|
||||
Note that not all buffer overruns are detected: each buffer is aligned by
|
||||
4 bytes, so there might be some trailing "extra" bytes which are not checked
|
||||
for corruption.
|
||||
* -D UMM_INTEGRITY_CHECK :
|
||||
*
|
||||
* Enables heap integrity check before any heap operation. It affects
|
||||
* performance, but does NOT consume extra memory.
|
||||
*
|
||||
* If integrity violation is detected, the message is printed and user-provided
|
||||
* callback is called: `UMM_HEAP_CORRUPTION_CB()`
|
||||
*
|
||||
* Note that not all buffer overruns are detected: each buffer is aligned by
|
||||
* 4 bytes, so there might be some trailing "extra" bytes which are not checked
|
||||
* for corruption.
|
||||
*/
|
||||
/*
|
||||
#define UMM_INTEGRITY_CHECK
|
||||
*/
|
||||
|
||||
/*
|
||||
-D UMM_POISON :
|
||||
|
||||
Enables heap poisoning: add predefined value (poison) before and after each
|
||||
allocation, and check before each heap operation that no poison is
|
||||
corrupted.
|
||||
|
||||
Other than the poison itself, we need to store exact user-requested length
|
||||
for each buffer, so that overrun by just 1 byte will be always noticed.
|
||||
|
||||
Customizations:
|
||||
|
||||
UMM_POISON_SIZE_BEFORE:
|
||||
Number of poison bytes before each block, e.g. 2
|
||||
UMM_POISON_SIZE_AFTER:
|
||||
Number of poison bytes after each block e.g. 2
|
||||
UMM_POISONED_BLOCK_LEN_TYPE
|
||||
Type of the exact buffer length, e.g. `short`
|
||||
|
||||
NOTE: each allocated buffer is aligned by 4 bytes. But when poisoning is
|
||||
enabled, actual pointer returned to user is shifted by
|
||||
`(sizeof(UMM_POISONED_BLOCK_LEN_TYPE) + UMM_POISON_SIZE_BEFORE)`.
|
||||
It's your responsibility to make resulting pointers aligned appropriately.
|
||||
|
||||
If poison corruption is detected, the message is printed and user-provided
|
||||
callback is called: `UMM_HEAP_CORRUPTION_CB()`
|
||||
* -D UMM_POISON :
|
||||
*
|
||||
* Enables heap poisoning: add predefined value (poison) before and after each
|
||||
* allocation, and check before each heap operation that no poison is
|
||||
* corrupted.
|
||||
*
|
||||
* Other than the poison itself, we need to store exact user-requested length
|
||||
* for each buffer, so that overrun by just 1 byte will be always noticed.
|
||||
*
|
||||
* Customizations:
|
||||
*
|
||||
* UMM_POISON_SIZE_BEFORE:
|
||||
* Number of poison bytes before each block, e.g. 2
|
||||
* UMM_POISON_SIZE_AFTER:
|
||||
* Number of poison bytes after each block e.g. 2
|
||||
* UMM_POISONED_BLOCK_LEN_TYPE
|
||||
* Type of the exact buffer length, e.g. `short`
|
||||
*
|
||||
* NOTE: each allocated buffer is aligned by 4 bytes. But when poisoning is
|
||||
* enabled, actual pointer returned to user is shifted by
|
||||
* `(sizeof(UMM_POISONED_BLOCK_LEN_TYPE) + UMM_POISON_SIZE_BEFORE)`.
|
||||
* It's your responsibility to make resulting pointers aligned appropriately.
|
||||
*
|
||||
* If poison corruption is detected, the message is printed and user-provided
|
||||
* callback is called: `UMM_HEAP_CORRUPTION_CB()`
|
||||
*/
|
||||
|
||||
#if defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_CORE)
|
||||
|
@ -47,60 +47,47 @@ ArduinoOTAClass::ArduinoOTAClass()
|
||||
{
|
||||
}
|
||||
|
||||
ArduinoOTAClass::~ArduinoOTAClass()
|
||||
{
|
||||
if (_udp_ota)
|
||||
{
|
||||
ArduinoOTAClass::~ArduinoOTAClass(){
|
||||
if(_udp_ota){
|
||||
_udp_ota->unref();
|
||||
_udp_ota = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onStart(THandlerFunction fn)
|
||||
{
|
||||
void ArduinoOTAClass::onStart(THandlerFunction fn) {
|
||||
_start_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onEnd(THandlerFunction fn)
|
||||
{
|
||||
void ArduinoOTAClass::onEnd(THandlerFunction fn) {
|
||||
_end_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onProgress(THandlerFunction_Progress fn)
|
||||
{
|
||||
void ArduinoOTAClass::onProgress(THandlerFunction_Progress fn) {
|
||||
_progress_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onError(THandlerFunction_Error fn)
|
||||
{
|
||||
void ArduinoOTAClass::onError(THandlerFunction_Error fn) {
|
||||
_error_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setPort(uint16_t port)
|
||||
{
|
||||
if (!_initialized && !_port && port)
|
||||
{
|
||||
void ArduinoOTAClass::setPort(uint16_t port) {
|
||||
if (!_initialized && !_port && port) {
|
||||
_port = port;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setHostname(const char * hostname)
|
||||
{
|
||||
if (!_initialized && !_hostname.length() && hostname)
|
||||
{
|
||||
void ArduinoOTAClass::setHostname(const char * hostname) {
|
||||
if (!_initialized && !_hostname.length() && hostname) {
|
||||
_hostname = hostname;
|
||||
}
|
||||
}
|
||||
|
||||
String ArduinoOTAClass::getHostname()
|
||||
{
|
||||
String ArduinoOTAClass::getHostname() {
|
||||
return _hostname;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setPassword(const char * password)
|
||||
{
|
||||
if (!_initialized && !_password.length() && password)
|
||||
{
|
||||
void ArduinoOTAClass::setPassword(const char * password) {
|
||||
if (!_initialized && !_password.length() && password) {
|
||||
MD5Builder passmd5;
|
||||
passmd5.begin();
|
||||
passmd5.add(password);
|
||||
@ -109,41 +96,32 @@ void ArduinoOTAClass::setPassword(const char * password)
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setPasswordHash(const char * password)
|
||||
{
|
||||
if (!_initialized && !_password.length() && password)
|
||||
{
|
||||
void ArduinoOTAClass::setPasswordHash(const char * password) {
|
||||
if (!_initialized && !_password.length() && password) {
|
||||
_password = password;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setRebootOnSuccess(bool reboot)
|
||||
{
|
||||
void ArduinoOTAClass::setRebootOnSuccess(bool reboot){
|
||||
_rebootOnSuccess = reboot;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::begin(bool useMDNS)
|
||||
{
|
||||
void ArduinoOTAClass::begin(bool useMDNS) {
|
||||
if (_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_useMDNS = useMDNS;
|
||||
|
||||
if (!_hostname.length())
|
||||
{
|
||||
if (!_hostname.length()) {
|
||||
char tmp[15];
|
||||
sprintf(tmp, "esp8266-%06x", ESP.getChipId());
|
||||
_hostname = tmp;
|
||||
}
|
||||
if (!_port)
|
||||
{
|
||||
if (!_port) {
|
||||
_port = 8266;
|
||||
}
|
||||
|
||||
if (_udp_ota)
|
||||
{
|
||||
if(_udp_ota){
|
||||
_udp_ota->unref();
|
||||
_udp_ota = 0;
|
||||
}
|
||||
@ -152,22 +130,16 @@ void ArduinoOTAClass::begin(bool useMDNS)
|
||||
_udp_ota->ref();
|
||||
|
||||
if(!_udp_ota->listen(IP_ADDR_ANY, _port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_udp_ota->onRx(std::bind(&ArduinoOTAClass::_onRx, this));
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
|
||||
if (_useMDNS)
|
||||
{
|
||||
if(_useMDNS) {
|
||||
MDNS.begin(_hostname.c_str());
|
||||
|
||||
if (_password.length())
|
||||
{
|
||||
if (_password.length()) {
|
||||
MDNS.enableArduino(_port, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
MDNS.enableArduino(_port);
|
||||
}
|
||||
}
|
||||
@ -179,20 +151,14 @@ void ArduinoOTAClass::begin(bool useMDNS)
|
||||
#endif
|
||||
}
|
||||
|
||||
int ArduinoOTAClass::parseInt()
|
||||
{
|
||||
int ArduinoOTAClass::parseInt(){
|
||||
char data[16];
|
||||
uint8_t index;
|
||||
char value;
|
||||
while (_udp_ota->peek() == ' ')
|
||||
{
|
||||
_udp_ota->read();
|
||||
}
|
||||
for (index = 0; index < sizeof(data); ++index)
|
||||
{
|
||||
while(_udp_ota->peek() == ' ') _udp_ota->read();
|
||||
for(index = 0; index < sizeof(data); ++index){
|
||||
value = _udp_ota->peek();
|
||||
if (value < '0' || value > '9')
|
||||
{
|
||||
if(value < '0' || value > '9'){
|
||||
data[index] = '\0';
|
||||
return atoi(data);
|
||||
}
|
||||
@ -201,15 +167,12 @@ int ArduinoOTAClass::parseInt()
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ArduinoOTAClass::readStringUntil(char end)
|
||||
{
|
||||
String ArduinoOTAClass::readStringUntil(char end){
|
||||
String res = "";
|
||||
int value;
|
||||
while (true)
|
||||
{
|
||||
while(true){
|
||||
value = _udp_ota->read();
|
||||
if (value < 0 || value == '\0' || value == end)
|
||||
{
|
||||
if(value < 0 || value == '\0' || value == end){
|
||||
return res;
|
||||
}
|
||||
res += static_cast<char>(value);
|
||||
@ -217,21 +180,14 @@ String ArduinoOTAClass::readStringUntil(char end)
|
||||
return res;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::_onRx()
|
||||
{
|
||||
if (!_udp_ota->next())
|
||||
{
|
||||
return;
|
||||
}
|
||||
void ArduinoOTAClass::_onRx(){
|
||||
if(!_udp_ota->next()) return;
|
||||
IPAddress ota_ip;
|
||||
|
||||
if (_state == OTA_IDLE)
|
||||
{
|
||||
if (_state == OTA_IDLE) {
|
||||
int cmd = parseInt();
|
||||
if (cmd != U_FLASH && cmd != U_SPIFFS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ota_ip = _udp_ota->getRemoteAddress();
|
||||
_cmd = cmd;
|
||||
_ota_port = parseInt();
|
||||
@ -241,14 +197,11 @@ void ArduinoOTAClass::_onRx()
|
||||
_md5 = readStringUntil('\n');
|
||||
_md5.trim();
|
||||
if(_md5.length() != 32)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ota_ip = _ota_ip;
|
||||
|
||||
if (_password.length())
|
||||
{
|
||||
if (_password.length()){
|
||||
MD5Builder nonce_md5;
|
||||
nonce_md5.begin();
|
||||
nonce_md5.add(String(micros()));
|
||||
@ -261,25 +214,19 @@ void ArduinoOTAClass::_onRx()
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
_state = OTA_WAITAUTH;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_state = OTA_RUNUPDATE;
|
||||
}
|
||||
}
|
||||
else if (_state == OTA_WAITAUTH)
|
||||
{
|
||||
} else if (_state == OTA_WAITAUTH) {
|
||||
int cmd = parseInt();
|
||||
if (cmd != U_AUTH)
|
||||
{
|
||||
if (cmd != U_AUTH) {
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
_udp_ota->read();
|
||||
String cnonce = readStringUntil(' ');
|
||||
String response = readStringUntil('\n');
|
||||
if (cnonce.length() != 32 || response.length() != 32)
|
||||
{
|
||||
if (cnonce.length() != 32 || response.length() != 32) {
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
@ -292,39 +239,27 @@ void ArduinoOTAClass::_onRx()
|
||||
String result = _challengemd5.toString();
|
||||
|
||||
ota_ip = _ota_ip;
|
||||
if (result.equalsConstantTime(response))
|
||||
{
|
||||
if(result.equalsConstantTime(response)) {
|
||||
_state = OTA_RUNUPDATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_udp_ota->append("Authentication Failed", 21);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
if (_error_callback)
|
||||
{
|
||||
_error_callback(OTA_AUTH_ERROR);
|
||||
}
|
||||
if (_error_callback) _error_callback(OTA_AUTH_ERROR);
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
while (_udp_ota->next())
|
||||
{
|
||||
_udp_ota->flush();
|
||||
}
|
||||
while(_udp_ota->next()) _udp_ota->flush();
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::_runUpdate()
|
||||
{
|
||||
void ArduinoOTAClass::_runUpdate() {
|
||||
IPAddress ota_ip = _ota_ip;
|
||||
|
||||
if (!Update.begin(_size, _cmd))
|
||||
{
|
||||
if (!Update.begin(_size, _cmd)) {
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.println("Update Begin Error");
|
||||
#endif
|
||||
if (_error_callback)
|
||||
{
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_BEGIN_ERROR);
|
||||
}
|
||||
|
||||
@ -346,24 +281,20 @@ void ArduinoOTAClass::_runUpdate()
|
||||
WiFiUDP::stopAll();
|
||||
WiFiClient::stopAll();
|
||||
|
||||
if (_start_callback)
|
||||
{
|
||||
if (_start_callback) {
|
||||
_start_callback();
|
||||
}
|
||||
if (_progress_callback)
|
||||
{
|
||||
if (_progress_callback) {
|
||||
_progress_callback(0, _size);
|
||||
}
|
||||
|
||||
WiFiClient client;
|
||||
if (!client.connect(_ota_ip, _ota_port))
|
||||
{
|
||||
if (!client.connect(_ota_ip, _ota_port)) {
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Connect Failed\n");
|
||||
#endif
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback)
|
||||
{
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_CONNECT_ERROR);
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
@ -372,51 +303,41 @@ void ArduinoOTAClass::_runUpdate()
|
||||
client.setNoDelay(true);
|
||||
|
||||
uint32_t written, total = 0;
|
||||
while (!Update.isFinished() && client.connected())
|
||||
{
|
||||
while (!Update.isFinished() && client.connected()) {
|
||||
int waited = 1000;
|
||||
while (!client.available() && waited--)
|
||||
{
|
||||
delay(1);
|
||||
}
|
||||
if (!waited)
|
||||
{
|
||||
if (!waited){
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Receive Failed\n");
|
||||
#endif
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback)
|
||||
{
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_RECEIVE_ERROR);
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
written = Update.write(client);
|
||||
if (written > 0)
|
||||
{
|
||||
if (written > 0) {
|
||||
client.print(written, DEC);
|
||||
total += written;
|
||||
if (_progress_callback)
|
||||
{
|
||||
if(_progress_callback) {
|
||||
_progress_callback(total, _size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Update.end())
|
||||
{
|
||||
if (Update.end()) {
|
||||
client.print("OK");
|
||||
client.stop();
|
||||
delay(10);
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Update Success\n");
|
||||
#endif
|
||||
if (_end_callback)
|
||||
{
|
||||
if (_end_callback) {
|
||||
_end_callback();
|
||||
}
|
||||
if (_rebootOnSuccess)
|
||||
{
|
||||
if(_rebootOnSuccess){
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Rebooting...\n");
|
||||
#endif
|
||||
@ -424,12 +345,9 @@ void ArduinoOTAClass::_runUpdate()
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback)
|
||||
{
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_END_ERROR);
|
||||
}
|
||||
Update.printError(client);
|
||||
@ -441,24 +359,19 @@ void ArduinoOTAClass::_runUpdate()
|
||||
}
|
||||
|
||||
//this needs to be called in the loop()
|
||||
void ArduinoOTAClass::handle()
|
||||
{
|
||||
if (_state == OTA_RUNUPDATE)
|
||||
{
|
||||
void ArduinoOTAClass::handle() {
|
||||
if (_state == OTA_RUNUPDATE) {
|
||||
_runUpdate();
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
|
||||
if(_useMDNS)
|
||||
{
|
||||
MDNS.update(); //handle MDNS update as well, given that ArduinoOTA relies on it anyways
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int ArduinoOTAClass::getCommand()
|
||||
{
|
||||
int ArduinoOTAClass::getCommand() {
|
||||
return _cmd;
|
||||
}
|
||||
|
||||
|
@ -7,15 +7,13 @@
|
||||
|
||||
class UdpContext;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
OTA_IDLE,
|
||||
OTA_WAITAUTH,
|
||||
OTA_RUNUPDATE
|
||||
} ota_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
OTA_AUTH_ERROR,
|
||||
OTA_BEGIN_ERROR,
|
||||
OTA_CONNECT_ERROR,
|
||||
|
@ -50,10 +50,8 @@ void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
|
||||
{
|
||||
domainName.toLowerCase();
|
||||
if (domainName.startsWith("www."))
|
||||
{
|
||||
domainName.remove(0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
{
|
||||
@ -67,52 +65,39 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
|
||||
// Must be a query for us to do anything with it
|
||||
if (dnsHeader->QR != DNS_QR_QUERY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If operation is anything other than query, we don't do it
|
||||
if (dnsHeader->OPCode != DNS_OPCODE_QUERY)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
|
||||
}
|
||||
|
||||
// Only support requests containing single queries - everything else
|
||||
// is badly defined
|
||||
if (dnsHeader->QDCount != lwip_htons(1))
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
|
||||
// We must return a FormError in the case of a non-zero ARCount to
|
||||
// be minimally compatible with EDNS resolvers
|
||||
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|
||||
|| dnsHeader->ARCount != 0)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
|
||||
// Even if we're not going to use the query, we need to parse it
|
||||
// so we can check the address type that's being queried
|
||||
|
||||
query = start = buffer + DNS_HEADER_SIZE;
|
||||
remaining = length - DNS_HEADER_SIZE;
|
||||
while (remaining != 0 && *start != 0)
|
||||
{
|
||||
while (remaining != 0 && *start != 0) {
|
||||
labelLength = *start;
|
||||
if (labelLength + 1 > remaining)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
remaining -= (labelLength + 1);
|
||||
start += (labelLength + 1);
|
||||
}
|
||||
|
||||
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
|
||||
if (remaining < 5)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
|
||||
start += 1; // Skip the 0 length label that we found above
|
||||
|
||||
@ -140,9 +125,7 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
|
||||
// If we're running with a wildcard we can just return a result now
|
||||
if (_domainName == "*")
|
||||
{
|
||||
return replyWithIP(dnsHeader, query, queryLength);
|
||||
}
|
||||
|
||||
matchString = _domainName.c_str();
|
||||
|
||||
@ -150,16 +133,12 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
|
||||
// If there's a leading 'www', skip it
|
||||
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0)
|
||||
{
|
||||
start += 4;
|
||||
}
|
||||
|
||||
while (*start != 0)
|
||||
{
|
||||
while (*start != 0) {
|
||||
labelLength = *start;
|
||||
start += 1;
|
||||
while (labelLength > 0)
|
||||
{
|
||||
while (labelLength > 0) {
|
||||
if (tolower(*start) != *matchString)
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
@ -168,9 +147,7 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
--labelLength;
|
||||
}
|
||||
if (*start == 0 && *matchString == '\0')
|
||||
{
|
||||
return replyWithIP(dnsHeader, query, queryLength);
|
||||
}
|
||||
|
||||
if (*matchString != '.')
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
@ -188,30 +165,22 @@ void DNSServer::processNextRequest()
|
||||
|
||||
currentPacketSize = _udp.parsePacket();
|
||||
if (currentPacketSize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
|
||||
// so just discard them if they are larger
|
||||
if (currentPacketSize > MAX_DNS_PACKETSIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the packet size is smaller than the DNS header, then someone is
|
||||
// messing with us
|
||||
if (currentPacketSize < DNS_HEADER_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_udp.read(buffer.get(), currentPacketSize);
|
||||
respondToRequest(buffer.get(), currentPacketSize);
|
||||
@ -266,13 +235,9 @@ void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->RCode = (unsigned char) rcode;
|
||||
if (query)
|
||||
{
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dnsHeader->QDCount = 0;
|
||||
}
|
||||
dnsHeader->ANCount = 0;
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
@ -280,9 +245,7 @@ void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
|
||||
if (query != NULL)
|
||||
{
|
||||
_udp.write(query, queryLength);
|
||||
}
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,7 @@ class DNSServer
|
||||
{
|
||||
public:
|
||||
DNSServer();
|
||||
~DNSServer()
|
||||
{
|
||||
~DNSServer() {
|
||||
stop();
|
||||
};
|
||||
void processNextRequest();
|
||||
|
@ -48,27 +48,19 @@ EEPROMClass::EEPROMClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
void EEPROMClass::begin(size_t size)
|
||||
{
|
||||
void EEPROMClass::begin(size_t size) {
|
||||
if (size <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (size > SPI_FLASH_SEC_SIZE)
|
||||
{
|
||||
size = SPI_FLASH_SEC_SIZE;
|
||||
}
|
||||
|
||||
size = (size + 3) & (~3);
|
||||
|
||||
//In case begin() is called a 2nd+ time, don't reallocate if size is the same
|
||||
if (_data && size != _size)
|
||||
{
|
||||
if(_data && size != _size) {
|
||||
delete[] _data;
|
||||
_data = new uint8_t[size];
|
||||
}
|
||||
else if (!_data)
|
||||
{
|
||||
} else if(!_data) {
|
||||
_data = new uint8_t[size];
|
||||
}
|
||||
|
||||
@ -81,16 +73,12 @@ void EEPROMClass::begin(size_t size)
|
||||
_dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time
|
||||
}
|
||||
|
||||
void EEPROMClass::end()
|
||||
{
|
||||
void EEPROMClass::end() {
|
||||
if (!_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
commit();
|
||||
if (_data)
|
||||
{
|
||||
if(_data) {
|
||||
delete[] _data;
|
||||
}
|
||||
_data = 0;
|
||||
@ -99,30 +87,20 @@ void EEPROMClass::end()
|
||||
}
|
||||
|
||||
|
||||
uint8_t EEPROMClass::read(int const address)
|
||||
{
|
||||
uint8_t EEPROMClass::read(int const address) {
|
||||
if (address < 0 || (size_t)address >= _size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(!_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _data[address];
|
||||
}
|
||||
|
||||
void EEPROMClass::write(int const address, uint8_t const value)
|
||||
{
|
||||
void EEPROMClass::write(int const address, uint8_t const value) {
|
||||
if (address < 0 || (size_t)address >= _size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(!_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Optimise _dirty. Only flagged if data written is different.
|
||||
uint8_t* pData = &_data[address];
|
||||
@ -133,27 +111,18 @@ void EEPROMClass::write(int const address, uint8_t const value)
|
||||
}
|
||||
}
|
||||
|
||||
bool EEPROMClass::commit()
|
||||
{
|
||||
bool EEPROMClass::commit() {
|
||||
bool ret = false;
|
||||
if (!_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!_dirty)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
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(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) {
|
||||
_dirty = false;
|
||||
ret = true;
|
||||
}
|
||||
@ -163,14 +132,12 @@ bool EEPROMClass::commit()
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t * EEPROMClass::getDataPtr()
|
||||
{
|
||||
uint8_t * EEPROMClass::getDataPtr() {
|
||||
_dirty = true;
|
||||
return &_data[0];
|
||||
}
|
||||
|
||||
uint8_t const * EEPROMClass::getConstDataPtr() const
|
||||
{
|
||||
uint8_t const * EEPROMClass::getConstDataPtr() const {
|
||||
return &_data[0];
|
||||
}
|
||||
|
||||
|
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