mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-19 23:22:16 +03:00
Allman now (#6080)
* switch restyle script for CI * remove confirmation * restyle with allman
This commit is contained in:
parent
625c3a62c4
commit
98125f8860
@ -1,27 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
AddrList.h - cycle through lwIP netif's ip addresses like a c++ list
|
AddrList.h - cycle through lwIP netif's ip addresses like a c++ list
|
||||||
Copyright (c) 2018 david gauchard. All right reserved.
|
Copyright (c) 2018 david gauchard. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This class allows to explore all configured IP addresses
|
This class allows to explore all configured IP addresses
|
||||||
in lwIP netifs, with that kind of c++ loop:
|
in lwIP netifs, with that kind of c++ loop:
|
||||||
|
|
||||||
for (auto a: addrList)
|
for (auto a: addrList)
|
||||||
out.printf("IF='%s' index=%d legacy=%d IPv4=%d local=%d hostname='%s' addr= %s\n",
|
out.printf("IF='%s' index=%d legacy=%d IPv4=%d local=%d hostname='%s' addr= %s\n",
|
||||||
a.iface().c_str(),
|
a.iface().c_str(),
|
||||||
a.ifnumber(),
|
a.ifnumber(),
|
||||||
@ -31,14 +31,14 @@
|
|||||||
a.hostname().c_str(),
|
a.hostname().c_str(),
|
||||||
a.addr().toString().c_str());
|
a.addr().toString().c_str());
|
||||||
|
|
||||||
This loop:
|
This loop:
|
||||||
|
|
||||||
while (WiFi.status() != WL_CONNECTED()) {
|
while (WiFi.status() != WL_CONNECTED()) {
|
||||||
Serial.print('.');
|
Serial.print('.');
|
||||||
delay(500);
|
delay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
can be replaced by:
|
can be replaced by:
|
||||||
|
|
||||||
for (bool configured = false; !configured; ) {
|
for (bool configured = false; !configured; ) {
|
||||||
for (auto iface: addrList)
|
for (auto iface: addrList)
|
||||||
@ -48,7 +48,7 @@
|
|||||||
delay(500);
|
delay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
waiting for an IPv6 global address:
|
waiting for an IPv6 global address:
|
||||||
|
|
||||||
for (bool configured = false; !configured; ) {
|
for (bool configured = false; !configured; ) {
|
||||||
for (auto iface: addrList)
|
for (auto iface: addrList)
|
||||||
@ -59,7 +59,7 @@
|
|||||||
delay(500);
|
delay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
waiting for an IPv6 global address, on a specific interface:
|
waiting for an IPv6 global address, on a specific interface:
|
||||||
|
|
||||||
for (bool configured = false; !configured; ) {
|
for (bool configured = false; !configured; ) {
|
||||||
for (auto iface: addrList)
|
for (auto iface: addrList)
|
||||||
@ -94,8 +94,8 @@ namespace AddressListImplementation
|
|||||||
|
|
||||||
struct netifWrapper
|
struct netifWrapper
|
||||||
{
|
{
|
||||||
netifWrapper (netif* netif) : _netif(netif), _num(-1) {}
|
netifWrapper(netif* netif) : _netif(netif), _num(-1) {}
|
||||||
netifWrapper (const netifWrapper& o) : _netif(o._netif), _num(o._num) {}
|
netifWrapper(const netifWrapper& o) : _netif(o._netif), _num(o._num) {}
|
||||||
|
|
||||||
netifWrapper& operator= (const netifWrapper& o)
|
netifWrapper& operator= (const netifWrapper& o)
|
||||||
{
|
{
|
||||||
@ -110,25 +110,64 @@ struct netifWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// address properties
|
// address properties
|
||||||
IPAddress addr () const { return ipFromNetifNum(); }
|
IPAddress addr() const
|
||||||
bool isLegacy () const { return _num == 0; }
|
{
|
||||||
bool isLocal () const { return addr().isLocal(); }
|
return ipFromNetifNum();
|
||||||
bool isV4 () const { return addr().isV4(); }
|
}
|
||||||
bool isV6 () const { return !addr().isV4(); }
|
bool isLegacy() const
|
||||||
String toString() const { return addr().toString(); }
|
{
|
||||||
|
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)
|
// related to legacy address (_num=0, ipv4)
|
||||||
IPAddress ipv4 () const { return _netif->ip_addr; }
|
IPAddress ipv4() const
|
||||||
IPAddress netmask () const { return _netif->netmask; }
|
{
|
||||||
IPAddress gw () const { return _netif->gw; }
|
return _netif->ip_addr;
|
||||||
|
}
|
||||||
|
IPAddress netmask() const
|
||||||
|
{
|
||||||
|
return _netif->netmask;
|
||||||
|
}
|
||||||
|
IPAddress gw() const
|
||||||
|
{
|
||||||
|
return _netif->gw;
|
||||||
|
}
|
||||||
|
|
||||||
// common to all addresses of this interface
|
// common to all addresses of this interface
|
||||||
String ifname () const { return String(_netif->name[0]) + _netif->name[1]; }
|
String ifname() const
|
||||||
const char* ifhostname () const { return _netif->hostname?: emptyString.c_str(); }
|
{
|
||||||
const char* ifmac () const { return (const char*)_netif->hwaddr; }
|
return String(_netif->name[0]) + _netif->name[1];
|
||||||
int ifnumber () const { return _netif->num; }
|
}
|
||||||
|
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
|
const ip_addr_t* ipFromNetifNum() const
|
||||||
{
|
{
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
return _num ? &_netif->ip6_addr[_num - 1] : &_netif->ip_addr;
|
return _num ? &_netif->ip6_addr[_num - 1] : &_netif->ip_addr;
|
||||||
@ -150,8 +189,8 @@ struct netifWrapper
|
|||||||
class AddressListIterator
|
class AddressListIterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AddressListIterator (const netifWrapper& o) : netIf(o) {}
|
AddressListIterator(const netifWrapper& o) : netIf(o) {}
|
||||||
AddressListIterator (netif* netif) : netIf(netif)
|
AddressListIterator(netif* netif) : netIf(netif)
|
||||||
{
|
{
|
||||||
// This constructor is called with lwIP's global netif_list, or
|
// This constructor is called with lwIP's global netif_list, or
|
||||||
// nullptr. operator++() is designed to loop through _configured_
|
// nullptr. operator++() is designed to loop through _configured_
|
||||||
@ -160,13 +199,29 @@ public:
|
|||||||
(void)operator++();
|
(void)operator++();
|
||||||
}
|
}
|
||||||
|
|
||||||
const netifWrapper& operator* () const { return netIf; }
|
const netifWrapper& operator* () const
|
||||||
const netifWrapper* operator-> () const { return &netIf; }
|
{
|
||||||
|
return netIf;
|
||||||
|
}
|
||||||
|
const netifWrapper* operator-> () const
|
||||||
|
{
|
||||||
|
return &netIf;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator== (AddressListIterator& o) { return netIf.equal(*o); }
|
bool operator== (AddressListIterator& o)
|
||||||
bool operator!= (AddressListIterator& o) { return !netIf.equal(*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)
|
AddressListIterator operator++ (int)
|
||||||
{
|
{
|
||||||
@ -188,7 +243,9 @@ public:
|
|||||||
}
|
}
|
||||||
if (!ip_addr_isany(netIf.ipFromNetifNum()))
|
if (!ip_addr_isany(netIf.ipFromNetifNum()))
|
||||||
// found an initialized address
|
// found an initialized address
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -200,15 +257,27 @@ public:
|
|||||||
class AddressList
|
class AddressList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using const_iterator = const AddressListIterator;
|
using const_iterator = const AddressListIterator;
|
||||||
|
|
||||||
const_iterator begin () const { return const_iterator(netif_list); }
|
const_iterator begin() const
|
||||||
const_iterator end () const { return const_iterator(nullptr); }
|
{
|
||||||
|
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 begin(const AddressList& a)
|
||||||
inline AddressList::const_iterator end (const AddressList& a) { return a.end(); }
|
{
|
||||||
|
return a.begin();
|
||||||
|
}
|
||||||
|
inline AddressList::const_iterator end(const AddressList& a)
|
||||||
|
{
|
||||||
|
return a.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // AddressListImplementation
|
} // AddressListImplementation
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
Arduino.h - Main include file for the Arduino SDK
|
Arduino.h - Main include file for the Arduino SDK
|
||||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef Arduino_h
|
#ifndef Arduino_h
|
||||||
#define Arduino_h
|
#define Arduino_h
|
||||||
@ -86,10 +86,11 @@ extern "C" {
|
|||||||
#define EXTERNAL 0
|
#define EXTERNAL 0
|
||||||
|
|
||||||
//timer dividers
|
//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_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max)
|
||||||
TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 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)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -295,7 +296,7 @@ long secureRandom(long, long);
|
|||||||
long map(long, long, long, long, long);
|
long map(long, long, long, long, long);
|
||||||
|
|
||||||
extern "C" void configTime(long timezone, int daylightOffset_sec,
|
extern "C" void configTime(long timezone, int daylightOffset_sec,
|
||||||
const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
|
const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
Client.h - Base class that provides Client
|
Client.h - Base class that provides Client
|
||||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef client_h
|
#ifndef client_h
|
||||||
#define client_h
|
#define client_h
|
||||||
@ -23,29 +23,32 @@
|
|||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "IPAddress.h"
|
#include "IPAddress.h"
|
||||||
|
|
||||||
class Client: public Stream {
|
class Client: public Stream
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int connect(IPAddress ip, uint16_t port) =0;
|
virtual int connect(IPAddress ip, uint16_t port) = 0;
|
||||||
virtual int connect(const char *host, uint16_t port) =0;
|
virtual int connect(const char *host, uint16_t port) = 0;
|
||||||
virtual size_t write(uint8_t) =0;
|
virtual size_t write(uint8_t) = 0;
|
||||||
virtual size_t write(const uint8_t *buf, size_t size) =0;
|
virtual size_t write(const uint8_t *buf, size_t size) = 0;
|
||||||
virtual int available() = 0;
|
virtual int available() = 0;
|
||||||
virtual int read() = 0;
|
virtual int read() = 0;
|
||||||
virtual int read(uint8_t *buf, size_t size) = 0;
|
virtual int read(uint8_t *buf, size_t size) = 0;
|
||||||
virtual int peek() = 0;
|
virtual int peek() = 0;
|
||||||
virtual void flush() = 0;
|
virtual void flush() = 0;
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
virtual uint8_t connected() = 0;
|
virtual uint8_t connected() = 0;
|
||||||
virtual operator bool() = 0;
|
virtual operator bool() = 0;
|
||||||
protected:
|
protected:
|
||||||
uint8_t* rawIPAddress(IPAddress& addr) {
|
uint8_t* rawIPAddress(IPAddress& addr)
|
||||||
return addr.raw_address();
|
{
|
||||||
}
|
return addr.raw_address();
|
||||||
|
}
|
||||||
#if LWIP_VERSION_MAJOR != 1
|
#if LWIP_VERSION_MAJOR != 1
|
||||||
const uint8_t* rawIPAddress(const IPAddress& addr) {
|
const uint8_t* rawIPAddress(const IPAddress& addr)
|
||||||
return addr.raw_address();
|
{
|
||||||
}
|
return addr.raw_address();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
Esp.cpp - ESP8266-specific APIs
|
Esp.cpp - ESP8266-specific APIs
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "umm_malloc/umm_malloc.h"
|
#include "umm_malloc/umm_malloc.h"
|
||||||
#include "umm_malloc/umm_malloc_cfg.h"
|
#include "umm_malloc/umm_malloc_cfg.h"
|
||||||
@ -33,11 +33,17 @@ void EspClass::getHeapStats(uint32_t* hfree, uint16_t* hmax, uint8_t* hfrag)
|
|||||||
uint8_t block_size = umm_block_size();
|
uint8_t block_size = umm_block_size();
|
||||||
uint32_t fh = ummHeapInfo.freeBlocks * block_size;
|
uint32_t fh = ummHeapInfo.freeBlocks * block_size;
|
||||||
if (hfree)
|
if (hfree)
|
||||||
|
{
|
||||||
*hfree = fh;
|
*hfree = fh;
|
||||||
|
}
|
||||||
if (hmax)
|
if (hmax)
|
||||||
|
{
|
||||||
*hmax = ummHeapInfo.maxFreeContiguousBlocks * block_size;
|
*hmax = ummHeapInfo.maxFreeContiguousBlocks * block_size;
|
||||||
|
}
|
||||||
if (hfrag)
|
if (hfrag)
|
||||||
|
{
|
||||||
*hfrag = 100 - (sqrt32(ummHeapInfo.freeSize2) * 100) / fh;
|
*hfrag = 100 - (sqrt32(ummHeapInfo.freeSize2) * 100) / fh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t EspClass::getHeapFragmentation()
|
uint8_t EspClass::getHeapFragmentation()
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
Esp.cpp - ESP8266-specific APIs
|
Esp.cpp - ESP8266-specific APIs
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <user_interface.h>
|
#include <user_interface.h>
|
||||||
@ -34,10 +34,10 @@ static const char bearssl_version [] PROGMEM = "/BearSSL:" STR(BEARSSL_GIT);
|
|||||||
String EspClass::getFullVersion()
|
String EspClass::getFullVersion()
|
||||||
{
|
{
|
||||||
return String(F("SDK:")) + system_get_sdk_version()
|
return String(F("SDK:")) + system_get_sdk_version()
|
||||||
+ F("/Core:") + FPSTR(arduino_esp8266_git_ver)
|
+ F("/Core:") + FPSTR(arduino_esp8266_git_ver)
|
||||||
+ F("=") + String(esp8266::coreVersionNumeric())
|
+ F("=") + String(esp8266::coreVersionNumeric())
|
||||||
#if LWIP_VERSION_MAJOR == 1
|
#if LWIP_VERSION_MAJOR == 1
|
||||||
+ F("/lwIP:") + String(LWIP_VERSION_MAJOR) + "." + String(LWIP_VERSION_MINOR) + "." + String(LWIP_VERSION_REVISION)
|
+ F("/lwIP:") + String(LWIP_VERSION_MAJOR) + "." + String(LWIP_VERSION_MINOR) + "." + String(LWIP_VERSION_REVISION)
|
||||||
#if LWIP_VERSION_IS_DEVELOPMENT
|
#if LWIP_VERSION_IS_DEVELOPMENT
|
||||||
+ F("-dev")
|
+ F("-dev")
|
||||||
#endif
|
#endif
|
||||||
@ -52,5 +52,5 @@ String EspClass::getFullVersion()
|
|||||||
+ F(LWIP_HASH_STR)
|
+ F(LWIP_HASH_STR)
|
||||||
#endif // LWIP_VERSION_MAJOR != 1
|
#endif // LWIP_VERSION_MAJOR != 1
|
||||||
+ FPSTR(bearssl_version)
|
+ FPSTR(bearssl_version)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
Esp.cpp - ESP8266-specific APIs
|
Esp.cpp - ESP8266-specific APIs
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "flash_utils.h"
|
#include "flash_utils.h"
|
||||||
@ -30,7 +30,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include "user_interface.h"
|
#include "user_interface.h"
|
||||||
|
|
||||||
extern struct rst_info resetInfo;
|
extern struct rst_info resetInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -38,45 +38,54 @@ extern struct rst_info resetInfo;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User-defined Literals
|
User-defined Literals
|
||||||
* usage:
|
usage:
|
||||||
*
|
|
||||||
* uint32_t = test = 10_MHz; // --> 10000000
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned long long operator"" _kHz(unsigned long long x) {
|
uint32_t = test = 10_MHz; // --> 10000000
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned long long operator"" _kHz(unsigned long long x)
|
||||||
|
{
|
||||||
return x * 1000;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
return x * 1024 * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,59 +136,65 @@ void EspClass::deepSleepInstant(uint64_t time_us, WakeMode mode)
|
|||||||
//Note: system_rtc_clock_cali_proc() returns a uint32_t, even though system_deep_sleep() takes a uint64_t.
|
//Note: system_rtc_clock_cali_proc() returns a uint32_t, even though system_deep_sleep() takes a uint64_t.
|
||||||
uint64_t EspClass::deepSleepMax()
|
uint64_t EspClass::deepSleepMax()
|
||||||
{
|
{
|
||||||
//cali*(2^31-1)/(2^12)
|
//cali*(2^31-1)/(2^12)
|
||||||
return (uint64_t)system_rtc_clock_cali_proc()*(0x80000000-1)/(0x1000);
|
return (uint64_t)system_rtc_clock_cali_proc() * (0x80000000 - 1) / (0x1000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Layout of RTC Memory is as follows:
|
Layout of RTC Memory is as follows:
|
||||||
Ref: Espressif doc 2C-ESP8266_Non_OS_SDK_API_Reference, section 3.3.23 (system_rtc_mem_write)
|
Ref: Espressif doc 2C-ESP8266_Non_OS_SDK_API_Reference, section 3.3.23 (system_rtc_mem_write)
|
||||||
|
|
||||||
|<------system data (256 bytes)------->|<-----------------user data (512 bytes)--------------->|
|
|<------system data (256 bytes)------->|<-----------------user data (512 bytes)--------------->|
|
||||||
|
|
||||||
SDK function signature:
|
SDK function signature:
|
||||||
bool system_rtc_mem_read (
|
bool system_rtc_mem_read (
|
||||||
uint32 des_addr,
|
uint32 des_addr,
|
||||||
void * src_addr,
|
void * src_addr,
|
||||||
uint32 save_size
|
uint32 save_size
|
||||||
)
|
)
|
||||||
|
|
||||||
The system data section can't be used by the user, so:
|
The system data section can't be used by the user, so:
|
||||||
des_addr must be >=64 (i.e.: 256/4) and <192 (i.e.: 768/4)
|
des_addr must be >=64 (i.e.: 256/4) and <192 (i.e.: 768/4)
|
||||||
src_addr is a pointer to data
|
src_addr is a pointer to data
|
||||||
save_size is the number of bytes to write
|
save_size is the number of bytes to write
|
||||||
|
|
||||||
For the method interface:
|
For the method interface:
|
||||||
offset is the user block number (block size is 4 bytes) must be >= 0 and <128
|
offset is the user block number (block size is 4 bytes) must be >= 0 and <128
|
||||||
data is a pointer to data, 4-byte aligned
|
data is a pointer to data, 4-byte aligned
|
||||||
size is number of bytes in the block pointed to by data
|
size is number of bytes in the block pointed to by data
|
||||||
|
|
||||||
Same for write
|
Same for write
|
||||||
|
|
||||||
Note: If the Updater class is in play, e.g.: the application uses OTA, the eboot
|
Note: If the Updater class is in play, e.g.: the application uses OTA, the eboot
|
||||||
command will be stored into the first 128 bytes of user data, then it will be
|
command will be stored into the first 128 bytes of user data, then it will be
|
||||||
retrieved by eboot on boot. That means that user data present there will be lost.
|
retrieved by eboot on boot. That means that user data present there will be lost.
|
||||||
Ref:
|
Ref:
|
||||||
- discussion in PR #5330.
|
- discussion in PR #5330.
|
||||||
- https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map#memmory-mapped-io-registers
|
- https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map#memmory-mapped-io-registers
|
||||||
- Arduino/bootloaders/eboot/eboot_command.h RTC_MEM definition
|
- Arduino/bootloaders/eboot/eboot_command.h RTC_MEM definition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool EspClass::rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size)
|
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;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return system_rtc_mem_read(64 + offset, data, size);
|
return system_rtc_mem_read(64 + offset, data, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EspClass::rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t 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;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return system_rtc_mem_write(64 + offset, data, size);
|
return system_rtc_mem_write(64 + offset, data, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +250,8 @@ extern "C" const char* core_release;
|
|||||||
|
|
||||||
String EspClass::getCoreVersion()
|
String EspClass::getCoreVersion()
|
||||||
{
|
{
|
||||||
if (core_release != NULL) {
|
if (core_release != NULL)
|
||||||
|
{
|
||||||
return String(core_release);
|
return String(core_release);
|
||||||
}
|
}
|
||||||
char buf[12];
|
char buf[12];
|
||||||
@ -267,7 +283,8 @@ uint8_t EspClass::getCpuFreqMHz(void)
|
|||||||
uint32_t EspClass::getFlashChipId(void)
|
uint32_t EspClass::getFlashChipId(void)
|
||||||
{
|
{
|
||||||
static uint32_t flash_chip_id = 0;
|
static uint32_t flash_chip_id = 0;
|
||||||
if (flash_chip_id == 0) {
|
if (flash_chip_id == 0)
|
||||||
|
{
|
||||||
flash_chip_id = spi_flash_get_id();
|
flash_chip_id = spi_flash_get_id();
|
||||||
}
|
}
|
||||||
return flash_chip_id;
|
return flash_chip_id;
|
||||||
@ -288,7 +305,8 @@ uint32_t EspClass::getFlashChipSize(void)
|
|||||||
uint32_t data;
|
uint32_t data;
|
||||||
uint8_t * bytes = (uint8_t *) &data;
|
uint8_t * bytes = (uint8_t *) &data;
|
||||||
// read first 4 byte (magic byte + flash config)
|
// 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 magicFlashChipSize((bytes[3] & 0xf0) >> 4);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -299,7 +317,8 @@ uint32_t EspClass::getFlashChipSpeed(void)
|
|||||||
uint32_t data;
|
uint32_t data;
|
||||||
uint8_t * bytes = (uint8_t *) &data;
|
uint8_t * bytes = (uint8_t *) &data;
|
||||||
// read first 4 byte (magic byte + flash config)
|
// 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 magicFlashChipSpeed(bytes[3] & 0x0F);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -311,158 +330,191 @@ FlashMode_t EspClass::getFlashChipMode(void)
|
|||||||
uint32_t data;
|
uint32_t data;
|
||||||
uint8_t * bytes = (uint8_t *) &data;
|
uint8_t * bytes = (uint8_t *) &data;
|
||||||
// read first 4 byte (magic byte + flash config)
|
// 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]);
|
mode = magicFlashChipMode(bytes[2]);
|
||||||
}
|
}
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EspClass::magicFlashChipSize(uint8_t byte) {
|
uint32_t EspClass::magicFlashChipSize(uint8_t byte)
|
||||||
switch(byte & 0x0F) {
|
{
|
||||||
case 0x0: // 4 Mbit (512KB)
|
switch (byte & 0x0F)
|
||||||
return (512_kB);
|
{
|
||||||
case 0x1: // 2 MBit (256KB)
|
case 0x0: // 4 Mbit (512KB)
|
||||||
return (256_kB);
|
return (512_kB);
|
||||||
case 0x2: // 8 MBit (1MB)
|
case 0x1: // 2 MBit (256KB)
|
||||||
return (1_MB);
|
return (256_kB);
|
||||||
case 0x3: // 16 MBit (2MB)
|
case 0x2: // 8 MBit (1MB)
|
||||||
return (2_MB);
|
return (1_MB);
|
||||||
case 0x4: // 32 MBit (4MB)
|
case 0x3: // 16 MBit (2MB)
|
||||||
return (4_MB);
|
return (2_MB);
|
||||||
case 0x8: // 64 MBit (8MB)
|
case 0x4: // 32 MBit (4MB)
|
||||||
return (8_MB);
|
return (4_MB);
|
||||||
case 0x9: // 128 MBit (16MB)
|
case 0x8: // 64 MBit (8MB)
|
||||||
return (16_MB);
|
return (8_MB);
|
||||||
default: // fail?
|
case 0x9: // 128 MBit (16MB)
|
||||||
return 0;
|
return (16_MB);
|
||||||
|
default: // fail?
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EspClass::magicFlashChipSpeed(uint8_t byte) {
|
uint32_t EspClass::magicFlashChipSpeed(uint8_t byte)
|
||||||
switch(byte & 0x0F) {
|
{
|
||||||
case 0x0: // 40 MHz
|
switch (byte & 0x0F)
|
||||||
return (40_MHz);
|
{
|
||||||
case 0x1: // 26 MHz
|
case 0x0: // 40 MHz
|
||||||
return (26_MHz);
|
return (40_MHz);
|
||||||
case 0x2: // 20 MHz
|
case 0x1: // 26 MHz
|
||||||
return (20_MHz);
|
return (26_MHz);
|
||||||
case 0xf: // 80 MHz
|
case 0x2: // 20 MHz
|
||||||
return (80_MHz);
|
return (20_MHz);
|
||||||
default: // fail?
|
case 0xf: // 80 MHz
|
||||||
return 0;
|
return (80_MHz);
|
||||||
|
default: // fail?
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) {
|
FlashMode_t EspClass::magicFlashChipMode(uint8_t byte)
|
||||||
|
{
|
||||||
FlashMode_t mode = (FlashMode_t) byte;
|
FlashMode_t mode = (FlashMode_t) byte;
|
||||||
if(mode > FM_DOUT) {
|
if (mode > FM_DOUT)
|
||||||
|
{
|
||||||
mode = FM_UNKNOWN;
|
mode = FM_UNKNOWN;
|
||||||
}
|
}
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infos from
|
Infos from
|
||||||
* http://www.wlxmall.com/images/stock_item/att/A1010004.pdf
|
http://www.wlxmall.com/images/stock_item/att/A1010004.pdf
|
||||||
* http://www.gigadevice.com/product-series/5.html?locale=en_US
|
http://www.gigadevice.com/product-series/5.html?locale=en_US
|
||||||
* http://www.elinux.org/images/f/f5/Winbond-w25q32.pdf
|
http://www.elinux.org/images/f/f5/Winbond-w25q32.pdf
|
||||||
*/
|
*/
|
||||||
uint32_t EspClass::getFlashChipSizeByChipId(void) {
|
uint32_t EspClass::getFlashChipSizeByChipId(void)
|
||||||
|
{
|
||||||
uint32_t chipId = getFlashChipId();
|
uint32_t chipId = getFlashChipId();
|
||||||
/**
|
/**
|
||||||
* Chip ID
|
Chip ID
|
||||||
* 00 - always 00 (Chip ID use only 3 byte)
|
00 - always 00 (Chip ID use only 3 byte)
|
||||||
* 17 - ? looks like 2^xx is size in Byte ? //todo: find docu to this
|
17 - ? looks like 2^xx is size in Byte ? //todo: find docu to this
|
||||||
* 40 - ? may be Speed ? //todo: find docu to this
|
40 - ? may be Speed ? //todo: find docu to this
|
||||||
* C8 - manufacturer ID
|
C8 - manufacturer ID
|
||||||
*/
|
*/
|
||||||
switch(chipId) {
|
switch (chipId)
|
||||||
|
{
|
||||||
|
|
||||||
// GigaDevice
|
// GigaDevice
|
||||||
case 0x1740C8: // GD25Q64B
|
case 0x1740C8: // GD25Q64B
|
||||||
return (8_MB);
|
return (8_MB);
|
||||||
case 0x1640C8: // GD25Q32B
|
case 0x1640C8: // GD25Q32B
|
||||||
return (4_MB);
|
return (4_MB);
|
||||||
case 0x1540C8: // GD25Q16B
|
case 0x1540C8: // GD25Q16B
|
||||||
return (2_MB);
|
return (2_MB);
|
||||||
case 0x1440C8: // GD25Q80
|
case 0x1440C8: // GD25Q80
|
||||||
return (1_MB);
|
return (1_MB);
|
||||||
case 0x1340C8: // GD25Q40
|
case 0x1340C8: // GD25Q40
|
||||||
return (512_kB);
|
return (512_kB);
|
||||||
case 0x1240C8: // GD25Q20
|
case 0x1240C8: // GD25Q20
|
||||||
return (256_kB);
|
return (256_kB);
|
||||||
case 0x1140C8: // GD25Q10
|
case 0x1140C8: // GD25Q10
|
||||||
return (128_kB);
|
return (128_kB);
|
||||||
case 0x1040C8: // GD25Q12
|
case 0x1040C8: // GD25Q12
|
||||||
return (64_kB);
|
return (64_kB);
|
||||||
|
|
||||||
// Winbond
|
// Winbond
|
||||||
case 0x1640EF: // W25Q32
|
case 0x1640EF: // W25Q32
|
||||||
return (4_MB);
|
return (4_MB);
|
||||||
case 0x1540EF: // W25Q16
|
case 0x1540EF: // W25Q16
|
||||||
return (2_MB);
|
return (2_MB);
|
||||||
case 0x1440EF: // W25Q80
|
case 0x1440EF: // W25Q80
|
||||||
return (1_MB);
|
return (1_MB);
|
||||||
case 0x1340EF: // W25Q40
|
case 0x1340EF: // W25Q40
|
||||||
return (512_kB);
|
return (512_kB);
|
||||||
|
|
||||||
// BergMicro
|
// BergMicro
|
||||||
case 0x1640E0: // BG25Q32
|
case 0x1640E0: // BG25Q32
|
||||||
return (4_MB);
|
return (4_MB);
|
||||||
case 0x1540E0: // BG25Q16
|
case 0x1540E0: // BG25Q16
|
||||||
return (2_MB);
|
return (2_MB);
|
||||||
case 0x1440E0: // BG25Q80
|
case 0x1440E0: // BG25Q80
|
||||||
return (1_MB);
|
return (1_MB);
|
||||||
case 0x1340E0: // BG25Q40
|
case 0x1340E0: // BG25Q40
|
||||||
return (512_kB);
|
return (512_kB);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check the Flash settings from IDE against the Real flash size
|
check the Flash settings from IDE against the Real flash size
|
||||||
* @param needsEquals (return only true it equals)
|
@param needsEquals (return only true it equals)
|
||||||
* @return ok or not
|
@return ok or not
|
||||||
*/
|
*/
|
||||||
bool EspClass::checkFlashConfig(bool needsEquals) {
|
bool EspClass::checkFlashConfig(bool needsEquals)
|
||||||
if(needsEquals) {
|
{
|
||||||
if(getFlashChipRealSize() == getFlashChipSize()) {
|
if (needsEquals)
|
||||||
|
{
|
||||||
|
if (getFlashChipRealSize() == getFlashChipSize())
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if(getFlashChipRealSize() >= getFlashChipSize()) {
|
else
|
||||||
|
{
|
||||||
|
if (getFlashChipRealSize() >= getFlashChipSize())
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String EspClass::getResetReason(void) {
|
String EspClass::getResetReason(void)
|
||||||
|
{
|
||||||
char buff[32];
|
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
|
strcpy_P(buff, PSTR("Power on"));
|
||||||
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_WDT_RST) // hardware watch dog reset
|
||||||
strcpy_P(buff, PSTR("Exception"));
|
{
|
||||||
} else if (resetInfo.reason == REASON_SOFT_WDT_RST) { // software watch dog reset, GPIO status won’t change
|
strcpy_P(buff, PSTR("Hardware Watchdog"));
|
||||||
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_EXCEPTION_RST) // exception reset, 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
|
strcpy_P(buff, PSTR("Exception"));
|
||||||
strcpy_P(buff, PSTR("Deep-Sleep Wake"));
|
}
|
||||||
} else if (resetInfo.reason == REASON_EXT_SYS_RST) { // external system reset
|
else if (resetInfo.reason == REASON_SOFT_WDT_RST) // software watch dog reset, GPIO status won’t change
|
||||||
strcpy_P(buff, PSTR("External System"));
|
{
|
||||||
} else {
|
strcpy_P(buff, PSTR("Software Watchdog"));
|
||||||
strcpy_P(buff, PSTR("Unknown"));
|
}
|
||||||
|
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
|
||||||
|
{
|
||||||
|
strcpy_P(buff, PSTR("Deep-Sleep Wake"));
|
||||||
|
}
|
||||||
|
else if (resetInfo.reason == REASON_EXT_SYS_RST) // external system reset
|
||||||
|
{
|
||||||
|
strcpy_P(buff, PSTR("External System"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy_P(buff, PSTR("Unknown"));
|
||||||
}
|
}
|
||||||
return String(buff);
|
return String(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
String EspClass::getResetInfo(void) {
|
String EspClass::getResetInfo(void)
|
||||||
if(resetInfo.reason != 0) {
|
{
|
||||||
|
if (resetInfo.reason != 0)
|
||||||
|
{
|
||||||
char buff[200];
|
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);
|
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);
|
return String(buff);
|
||||||
@ -470,16 +522,20 @@ String EspClass::getResetInfo(void) {
|
|||||||
return String("flag: 0");
|
return String("flag: 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rst_info * EspClass::getResetInfoPtr(void) {
|
struct rst_info * EspClass::getResetInfoPtr(void)
|
||||||
|
{
|
||||||
return &resetInfo;
|
return &resetInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EspClass::eraseConfig(void) {
|
bool EspClass::eraseConfig(void)
|
||||||
|
{
|
||||||
const size_t cfgSize = 0x4000;
|
const size_t cfgSize = 0x4000;
|
||||||
size_t cfgAddr = ESP.getFlashChipSize() - cfgSize;
|
size_t cfgAddr = ESP.getFlashChipSize() - cfgSize;
|
||||||
|
|
||||||
for (size_t offset = 0; offset < cfgSize; 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)) {
|
{
|
||||||
|
if (!flashEraseSector((cfgAddr + offset) / SPI_FLASH_SEC_SIZE))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -487,14 +543,18 @@ bool EspClass::eraseConfig(void) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EspClass::getSketchSize() {
|
uint32_t EspClass::getSketchSize()
|
||||||
|
{
|
||||||
static uint32_t result = 0;
|
static uint32_t result = 0;
|
||||||
if (result)
|
if (result)
|
||||||
|
{
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
image_header_t image_header;
|
image_header_t image_header;
|
||||||
uint32_t pos = APP_START_OFFSET;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
pos += sizeof(image_header);
|
pos += sizeof(image_header);
|
||||||
@ -502,11 +562,12 @@ uint32_t EspClass::getSketchSize() {
|
|||||||
DEBUG_SERIAL.printf("num_segments=%u\r\n", image_header.num_segments);
|
DEBUG_SERIAL.printf("num_segments=%u\r\n", image_header.num_segments);
|
||||||
#endif
|
#endif
|
||||||
for (uint32_t section_index = 0;
|
for (uint32_t section_index = 0;
|
||||||
section_index < image_header.num_segments;
|
section_index < image_header.num_segments;
|
||||||
++section_index)
|
++section_index)
|
||||||
{
|
{
|
||||||
section_header_t section_header = {0, 0};
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
pos += sizeof(section_header);
|
pos += sizeof(section_header);
|
||||||
@ -521,7 +582,8 @@ uint32_t EspClass::getSketchSize() {
|
|||||||
|
|
||||||
extern "C" uint32_t _SPIFFS_start;
|
extern "C" uint32_t _SPIFFS_start;
|
||||||
|
|
||||||
uint32_t EspClass::getFreeSketchSpace() {
|
uint32_t EspClass::getFreeSketchSpace()
|
||||||
|
{
|
||||||
|
|
||||||
uint32_t usedSize = getSketchSize();
|
uint32_t usedSize = getSketchSize();
|
||||||
// round one sector up
|
// round one sector up
|
||||||
@ -534,81 +596,108 @@ uint32_t EspClass::getFreeSketchSpace() {
|
|||||||
return freeSpaceEnd - freeSpaceStart;
|
return freeSpaceEnd - freeSpaceStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail, bool restartOnSuccess) {
|
bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail, bool restartOnSuccess)
|
||||||
if(!Update.begin(size)){
|
{
|
||||||
|
if (!Update.begin(size))
|
||||||
|
{
|
||||||
#ifdef DEBUG_SERIAL
|
#ifdef DEBUG_SERIAL
|
||||||
DEBUG_SERIAL.print("Update ");
|
DEBUG_SERIAL.print("Update ");
|
||||||
Update.printError(DEBUG_SERIAL);
|
Update.printError(DEBUG_SERIAL);
|
||||||
#endif
|
#endif
|
||||||
if(restartOnFail) ESP.restart();
|
if (restartOnFail)
|
||||||
return false;
|
{
|
||||||
}
|
ESP.restart();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(Update.writeStream(in) != size){
|
if (Update.writeStream(in) != size)
|
||||||
|
{
|
||||||
#ifdef DEBUG_SERIAL
|
#ifdef DEBUG_SERIAL
|
||||||
DEBUG_SERIAL.print("Update ");
|
DEBUG_SERIAL.print("Update ");
|
||||||
Update.printError(DEBUG_SERIAL);
|
Update.printError(DEBUG_SERIAL);
|
||||||
#endif
|
#endif
|
||||||
if(restartOnFail) ESP.restart();
|
if (restartOnFail)
|
||||||
return false;
|
{
|
||||||
}
|
ESP.restart();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(!Update.end()){
|
if (!Update.end())
|
||||||
|
{
|
||||||
#ifdef DEBUG_SERIAL
|
#ifdef DEBUG_SERIAL
|
||||||
DEBUG_SERIAL.print("Update ");
|
DEBUG_SERIAL.print("Update ");
|
||||||
Update.printError(DEBUG_SERIAL);
|
Update.printError(DEBUG_SERIAL);
|
||||||
#endif
|
#endif
|
||||||
if(restartOnFail) ESP.restart();
|
if (restartOnFail)
|
||||||
return false;
|
{
|
||||||
}
|
ESP.restart();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_SERIAL
|
#ifdef DEBUG_SERIAL
|
||||||
DEBUG_SERIAL.println("Update SUCCESS");
|
DEBUG_SERIAL.println("Update SUCCESS");
|
||||||
#endif
|
#endif
|
||||||
if(restartOnSuccess) ESP.restart();
|
if (restartOnSuccess)
|
||||||
|
{
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int FLASH_INT_MASK = ((B10 << 8) | B00111010);
|
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);
|
int rc = spi_flash_erase_sector(sector);
|
||||||
return rc == 0;
|
return rc == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PUYA_SUPPORT
|
#if PUYA_SUPPORT
|
||||||
static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) {
|
static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size)
|
||||||
if (data == nullptr) {
|
{
|
||||||
return 1; // SPI_FLASH_RESULT_ERR
|
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.
|
// PUYA flash chips need to read existing data, update in memory and write modified data again.
|
||||||
static uint32_t *flash_write_puya_buf = nullptr;
|
static uint32_t *flash_write_puya_buf = nullptr;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
uint32_t* ptr = data;
|
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);
|
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.
|
// 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.
|
// Memory could not be allocated.
|
||||||
return 1; // SPI_FLASH_RESULT_ERR
|
return 1; // SPI_FLASH_RESULT_ERR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t bytesLeft = size;
|
size_t bytesLeft = size;
|
||||||
uint32_t pos = offset;
|
uint32_t pos = offset;
|
||||||
while (bytesLeft > 0 && rc == 0) {
|
while (bytesLeft > 0 && rc == 0)
|
||||||
|
{
|
||||||
size_t bytesNow = bytesLeft;
|
size_t bytesNow = bytesLeft;
|
||||||
if (bytesNow > PUYA_BUFFER_SIZE) {
|
if (bytesNow > PUYA_BUFFER_SIZE)
|
||||||
|
{
|
||||||
bytesNow = PUYA_BUFFER_SIZE;
|
bytesNow = PUYA_BUFFER_SIZE;
|
||||||
bytesLeft -= PUYA_BUFFER_SIZE;
|
bytesLeft -= PUYA_BUFFER_SIZE;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
bytesLeft = 0;
|
bytesLeft = 0;
|
||||||
}
|
}
|
||||||
rc = spi_flash_read(pos, flash_write_puya_buf, bytesNow);
|
rc = spi_flash_read(pos, flash_write_puya_buf, bytesNow);
|
||||||
if (rc != 0) {
|
if (rc != 0)
|
||||||
|
{
|
||||||
return rc;
|
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;
|
flash_write_puya_buf[i] &= *ptr;
|
||||||
++ptr;
|
++ptr;
|
||||||
}
|
}
|
||||||
@ -619,10 +708,12 @@ static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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;
|
int rc = 0;
|
||||||
#if PUYA_SUPPORT
|
#if PUYA_SUPPORT
|
||||||
if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA) {
|
if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA)
|
||||||
|
{
|
||||||
rc = spi_flash_write_puya(offset, data, size);
|
rc = spi_flash_write_puya(offset, data, size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -633,7 +724,8 @@ bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
|
|||||||
return rc == 0;
|
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);
|
int rc = spi_flash_read(offset, (uint32_t*) data, size);
|
||||||
return rc == 0;
|
return rc == 0;
|
||||||
}
|
}
|
||||||
@ -641,21 +733,25 @@ bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size) {
|
|||||||
String EspClass::getSketchMD5()
|
String EspClass::getSketchMD5()
|
||||||
{
|
{
|
||||||
static String result;
|
static String result;
|
||||||
if (result.length()) {
|
if (result.length())
|
||||||
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
uint32_t lengthLeft = getSketchSize();
|
uint32_t lengthLeft = getSketchSize();
|
||||||
const size_t bufSize = 512;
|
const size_t bufSize = 512;
|
||||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
|
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
if(!buf.get()) {
|
if (!buf.get())
|
||||||
|
{
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
MD5Builder md5;
|
MD5Builder md5;
|
||||||
md5.begin();
|
md5.begin();
|
||||||
while( lengthLeft > 0) {
|
while (lengthLeft > 0)
|
||||||
|
{
|
||||||
size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize;
|
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();
|
return String();
|
||||||
}
|
}
|
||||||
md5.add(buf.get(), readBytes);
|
md5.add(buf.get(), readBytes);
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
Esp.h - ESP8266-specific APIs
|
Esp.h - ESP8266-specific APIs
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ESP_H
|
#ifndef ESP_H
|
||||||
#define ESP_H
|
#define ESP_H
|
||||||
@ -24,17 +24,18 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#ifndef PUYA_SUPPORT
|
#ifndef PUYA_SUPPORT
|
||||||
#define PUYA_SUPPORT 0
|
#define PUYA_SUPPORT 0
|
||||||
#endif
|
#endif
|
||||||
#ifndef PUYA_BUFFER_SIZE
|
#ifndef PUYA_BUFFER_SIZE
|
||||||
// Good alternative for buffer size is: SPI_FLASH_SEC_SIZE (= 4k)
|
// Good alternative for buffer size is: SPI_FLASH_SEC_SIZE (= 4k)
|
||||||
// Always use a multiple of flash page size (256 bytes)
|
// Always use a multiple of flash page size (256 bytes)
|
||||||
#define PUYA_BUFFER_SIZE 256
|
#define PUYA_BUFFER_SIZE 256
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Vendor IDs taken from Flashrom project
|
// Vendor IDs taken from Flashrom project
|
||||||
// https://review.coreboot.org/cgit/flashrom.git/tree/flashchips.h?h=1.0.x
|
// 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_ALLIANCE = 0x52, /* Alliance Semiconductor */
|
||||||
SPI_FLASH_VENDOR_AMD = 0x01, /* AMD */
|
SPI_FLASH_VENDOR_AMD = 0x01, /* AMD */
|
||||||
SPI_FLASH_VENDOR_AMIC = 0x37, /* AMIC */
|
SPI_FLASH_VENDOR_AMIC = 0x37, /* AMIC */
|
||||||
@ -70,9 +71,10 @@ typedef enum {
|
|||||||
} SPI_FLASH_VENDOR_t;
|
} SPI_FLASH_VENDOR_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AVR macros for WDT managment
|
AVR macros for WDT managment
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
WDTO_0MS = 0, //!< WDTO_0MS
|
WDTO_0MS = 0, //!< WDTO_0MS
|
||||||
WDTO_15MS = 15, //!< WDTO_15MS
|
WDTO_15MS = 15, //!< WDTO_15MS
|
||||||
WDTO_30MS = 30, //!< WDTO_30MS
|
WDTO_30MS = 30, //!< WDTO_30MS
|
||||||
@ -94,7 +96,8 @@ typedef enum {
|
|||||||
#define cli() ets_intr_lock() // IRQ Disable
|
#define cli() ets_intr_lock() // IRQ Disable
|
||||||
#define sei() ets_intr_unlock() // IRQ Enable
|
#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_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_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.
|
RF_NO_CAL = 2, // no RF_CAL after deep-sleep wake up, there will only be small current.
|
||||||
@ -111,7 +114,8 @@ enum RFMode {
|
|||||||
#define WAKE_NO_RFCAL RF_NO_CAL
|
#define WAKE_NO_RFCAL RF_NO_CAL
|
||||||
#define WAKE_RF_DISABLED RF_DISABLED
|
#define WAKE_RF_DISABLED RF_DISABLED
|
||||||
|
|
||||||
enum ADCMode {
|
enum ADCMode
|
||||||
|
{
|
||||||
ADC_TOUT = 33,
|
ADC_TOUT = 33,
|
||||||
ADC_TOUT_3V3 = 33,
|
ADC_TOUT_3V3 = 33,
|
||||||
ADC_VCC = 255,
|
ADC_VCC = 255,
|
||||||
@ -120,97 +124,99 @@ enum ADCMode {
|
|||||||
|
|
||||||
#define ADC_MODE(mode) int __get_adc_mode(void) { return (int) (mode); }
|
#define ADC_MODE(mode) int __get_adc_mode(void) { return (int) (mode); }
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
FM_QIO = 0x00,
|
{
|
||||||
FM_QOUT = 0x01,
|
FM_QIO = 0x00,
|
||||||
FM_DIO = 0x02,
|
FM_QOUT = 0x01,
|
||||||
FM_DOUT = 0x03,
|
FM_DIO = 0x02,
|
||||||
FM_UNKNOWN = 0xff
|
FM_DOUT = 0x03,
|
||||||
|
FM_UNKNOWN = 0xff
|
||||||
} FlashMode_t;
|
} FlashMode_t;
|
||||||
|
|
||||||
class EspClass {
|
class EspClass
|
||||||
public:
|
{
|
||||||
// TODO: figure out how to set WDT timeout
|
public:
|
||||||
void wdtEnable(uint32_t timeout_ms = 0);
|
// TODO: figure out how to set WDT timeout
|
||||||
// note: setting the timeout value is not implemented at the moment
|
void wdtEnable(uint32_t timeout_ms = 0);
|
||||||
void wdtEnable(WDTO_t timeout_ms = WDTO_0MS);
|
// note: setting the timeout value is not implemented at the moment
|
||||||
|
void wdtEnable(WDTO_t timeout_ms = WDTO_0MS);
|
||||||
|
|
||||||
void wdtDisable();
|
void wdtDisable();
|
||||||
void wdtFeed();
|
void wdtFeed();
|
||||||
|
|
||||||
void deepSleep(uint64_t time_us, RFMode mode = RF_DEFAULT);
|
void deepSleep(uint64_t time_us, RFMode mode = RF_DEFAULT);
|
||||||
void deepSleepInstant(uint64_t time_us, RFMode mode = RF_DEFAULT);
|
void deepSleepInstant(uint64_t time_us, RFMode mode = RF_DEFAULT);
|
||||||
uint64_t deepSleepMax();
|
uint64_t deepSleepMax();
|
||||||
|
|
||||||
bool rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size);
|
bool rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size);
|
||||||
bool rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size);
|
bool rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void restart();
|
void restart();
|
||||||
|
|
||||||
uint16_t getVcc();
|
uint16_t getVcc();
|
||||||
uint32_t getChipId();
|
uint32_t getChipId();
|
||||||
|
|
||||||
uint32_t getFreeHeap();
|
uint32_t getFreeHeap();
|
||||||
uint16_t getMaxFreeBlockSize();
|
uint16_t getMaxFreeBlockSize();
|
||||||
uint8_t getHeapFragmentation(); // in %
|
uint8_t getHeapFragmentation(); // in %
|
||||||
void getHeapStats(uint32_t* free = nullptr, uint16_t* max = nullptr, uint8_t* frag = nullptr);
|
void getHeapStats(uint32_t* free = nullptr, uint16_t* max = nullptr, uint8_t* frag = nullptr);
|
||||||
|
|
||||||
uint32_t getFreeContStack();
|
uint32_t getFreeContStack();
|
||||||
void resetFreeContStack();
|
void resetFreeContStack();
|
||||||
|
|
||||||
const char * getSdkVersion();
|
const char * getSdkVersion();
|
||||||
String getCoreVersion();
|
String getCoreVersion();
|
||||||
String getFullVersion();
|
String getFullVersion();
|
||||||
|
|
||||||
uint8_t getBootVersion();
|
uint8_t getBootVersion();
|
||||||
uint8_t getBootMode();
|
uint8_t getBootMode();
|
||||||
|
|
||||||
uint8_t getCpuFreqMHz();
|
uint8_t getCpuFreqMHz();
|
||||||
|
|
||||||
uint32_t getFlashChipId();
|
uint32_t getFlashChipId();
|
||||||
uint8_t getFlashChipVendorId();
|
uint8_t getFlashChipVendorId();
|
||||||
|
|
||||||
//gets the actual chip size based on the flash id
|
//gets the actual chip size based on the flash id
|
||||||
uint32_t getFlashChipRealSize();
|
uint32_t getFlashChipRealSize();
|
||||||
//gets the size of the flash as set by the compiler
|
//gets the size of the flash as set by the compiler
|
||||||
uint32_t getFlashChipSize();
|
uint32_t getFlashChipSize();
|
||||||
uint32_t getFlashChipSpeed();
|
uint32_t getFlashChipSpeed();
|
||||||
FlashMode_t getFlashChipMode();
|
FlashMode_t getFlashChipMode();
|
||||||
uint32_t getFlashChipSizeByChipId();
|
uint32_t getFlashChipSizeByChipId();
|
||||||
|
|
||||||
uint32_t magicFlashChipSize(uint8_t byte);
|
uint32_t magicFlashChipSize(uint8_t byte);
|
||||||
uint32_t magicFlashChipSpeed(uint8_t byte);
|
uint32_t magicFlashChipSpeed(uint8_t byte);
|
||||||
FlashMode_t magicFlashChipMode(uint8_t byte);
|
FlashMode_t magicFlashChipMode(uint8_t byte);
|
||||||
|
|
||||||
bool checkFlashConfig(bool needsEquals = false);
|
bool checkFlashConfig(bool needsEquals = false);
|
||||||
|
|
||||||
bool flashEraseSector(uint32_t sector);
|
bool flashEraseSector(uint32_t sector);
|
||||||
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
|
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
|
||||||
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
|
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
|
||||||
|
|
||||||
uint32_t getSketchSize();
|
uint32_t getSketchSize();
|
||||||
String getSketchMD5();
|
String getSketchMD5();
|
||||||
uint32_t getFreeSketchSpace();
|
uint32_t getFreeSketchSpace();
|
||||||
bool updateSketch(Stream& in, uint32_t size, bool restartOnFail = false, bool restartOnSuccess = true);
|
bool updateSketch(Stream& in, uint32_t size, bool restartOnFail = false, bool restartOnSuccess = true);
|
||||||
|
|
||||||
String getResetReason();
|
String getResetReason();
|
||||||
String getResetInfo();
|
String getResetInfo();
|
||||||
struct rst_info * getResetInfoPtr();
|
struct rst_info * getResetInfoPtr();
|
||||||
|
|
||||||
bool eraseConfig();
|
bool eraseConfig();
|
||||||
|
|
||||||
#ifndef CORE_MOCK
|
#ifndef CORE_MOCK
|
||||||
inline
|
inline
|
||||||
#endif
|
#endif
|
||||||
uint32_t getCycleCount();
|
uint32_t getCycleCount();
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef CORE_MOCK
|
#ifndef CORE_MOCK
|
||||||
uint32_t EspClass::getCycleCount()
|
uint32_t EspClass::getCycleCount()
|
||||||
{
|
{
|
||||||
uint32_t ccount;
|
uint32_t ccount;
|
||||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
|
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
|
||||||
return ccount;
|
return ccount;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
FS.cpp - file system wrapper
|
FS.cpp - file system wrapper
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "FSImpl.h"
|
#include "FSImpl.h"
|
||||||
@ -25,49 +25,68 @@ using namespace fs;
|
|||||||
|
|
||||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am);
|
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)
|
if (!_p)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->write(&c, 1);
|
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)
|
if (!_p)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->write(buf, size);
|
return _p->write(buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::available() {
|
int File::available()
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->size() - _p->position();
|
return _p->size() - _p->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::read() {
|
int File::read()
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t result;
|
uint8_t result;
|
||||||
if (_p->read(&result, 1) != 1) {
|
if (_p->read(&result, 1) != 1)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t File::read(uint8_t* buf, size_t size) {
|
size_t File::read(uint8_t* buf, size_t size)
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->read(buf, size);
|
return _p->read(buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::peek() {
|
int File::peek()
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t curPos = _p->position();
|
size_t curPos = _p->position();
|
||||||
int result = read();
|
int result = read();
|
||||||
@ -75,90 +94,126 @@ int File::peek() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::flush() {
|
void File::flush()
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_p->flush();
|
_p->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::seek(uint32_t pos, SeekMode mode) {
|
bool File::seek(uint32_t pos, SeekMode mode)
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->seek(pos, mode);
|
return _p->seek(pos, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t File::position() const {
|
size_t File::position() const
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->position();
|
return _p->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t File::size() const {
|
size_t File::size() const
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->size();
|
return _p->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::close() {
|
void File::close()
|
||||||
if (_p) {
|
{
|
||||||
|
if (_p)
|
||||||
|
{
|
||||||
_p->close();
|
_p->close();
|
||||||
_p = nullptr;
|
_p = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File::operator bool() const {
|
File::operator bool() const
|
||||||
|
{
|
||||||
return !!_p;
|
return !!_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::truncate(uint32_t size) {
|
bool File::truncate(uint32_t size)
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->truncate(size);
|
return _p->truncate(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* File::name() const {
|
const char* File::name() const
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->name();
|
return _p->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* File::fullName() const {
|
const char* File::fullName() const
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->fullName();
|
return _p->fullName();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::isFile() const {
|
bool File::isFile() const
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->isFile();
|
return _p->isFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::isDirectory() const {
|
bool File::isDirectory() const
|
||||||
|
{
|
||||||
if (!_p)
|
if (!_p)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->isDirectory();
|
return _p->isDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::rewindDirectory() {
|
void File::rewindDirectory()
|
||||||
if (!_fakeDir) {
|
{
|
||||||
|
if (!_fakeDir)
|
||||||
|
{
|
||||||
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_fakeDir->rewind();
|
_fakeDir->rewind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File File::openNextFile() {
|
File File::openNextFile()
|
||||||
if (!_fakeDir) {
|
{
|
||||||
|
if (!_fakeDir)
|
||||||
|
{
|
||||||
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
||||||
}
|
}
|
||||||
_fakeDir->next();
|
_fakeDir->next();
|
||||||
@ -169,25 +224,28 @@ String File::readString()
|
|||||||
{
|
{
|
||||||
String ret;
|
String ret;
|
||||||
ret.reserve(size() - position());
|
ret.reserve(size() - position());
|
||||||
char temp[256+1];
|
char temp[256 + 1];
|
||||||
int countRead = readBytes(temp, sizeof(temp)-1);
|
int countRead = readBytes(temp, sizeof(temp) - 1);
|
||||||
while (countRead > 0)
|
while (countRead > 0)
|
||||||
{
|
{
|
||||||
temp[countRead] = 0;
|
temp[countRead] = 0;
|
||||||
ret += temp;
|
ret += temp;
|
||||||
countRead = readBytes(temp, sizeof(temp)-1);
|
countRead = readBytes(temp, sizeof(temp) - 1);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
File Dir::openFile(const char* mode) {
|
File Dir::openFile(const char* mode)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return File();
|
return File();
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenMode om;
|
OpenMode om;
|
||||||
AccessMode am;
|
AccessMode am;
|
||||||
if (!sflags(mode, om, am)) {
|
if (!sflags(mode, om, am))
|
||||||
|
{
|
||||||
DEBUGV("Dir::openFile: invalid mode `%s`\r\n", mode);
|
DEBUGV("Dir::openFile: invalid mode `%s`\r\n", mode);
|
||||||
return File();
|
return File();
|
||||||
}
|
}
|
||||||
@ -195,206 +253,257 @@ File Dir::openFile(const char* mode) {
|
|||||||
return File(_impl->openFile(om, am), _baseFS);
|
return File(_impl->openFile(om, am), _baseFS);
|
||||||
}
|
}
|
||||||
|
|
||||||
String Dir::fileName() {
|
String Dir::fileName()
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _impl->fileName();
|
return _impl->fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Dir::fileSize() {
|
size_t Dir::fileSize()
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _impl->fileSize();
|
return _impl->fileSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dir::isFile() const {
|
bool Dir::isFile() const
|
||||||
|
{
|
||||||
if (!_impl)
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _impl->isFile();
|
return _impl->isFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dir::isDirectory() const {
|
bool Dir::isDirectory() const
|
||||||
|
{
|
||||||
if (!_impl)
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _impl->isDirectory();
|
return _impl->isDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dir::next() {
|
bool Dir::next()
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _impl->next();
|
return _impl->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dir::rewind() {
|
bool Dir::rewind()
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _impl->rewind();
|
return _impl->rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::setConfig(const FSConfig &cfg) {
|
bool FS::setConfig(const FSConfig &cfg)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _impl->setConfig(cfg);
|
return _impl->setConfig(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::begin() {
|
bool FS::begin()
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->begin();
|
return _impl->begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FS::end() {
|
void FS::end()
|
||||||
if (_impl) {
|
{
|
||||||
|
if (_impl)
|
||||||
|
{
|
||||||
_impl->end();
|
_impl->end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::gc() {
|
bool FS::gc()
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->gc();
|
return _impl->gc();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::format() {
|
bool FS::format()
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->format();
|
return _impl->format();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::info(FSInfo& info){
|
bool FS::info(FSInfo& info)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->info(info);
|
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);
|
return open(path.c_str(), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
File FS::open(const char* path, const char* mode) {
|
File FS::open(const char* path, const char* mode)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return File();
|
return File();
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenMode om;
|
OpenMode om;
|
||||||
AccessMode am;
|
AccessMode am;
|
||||||
if (!sflags(mode, om, am)) {
|
if (!sflags(mode, om, am))
|
||||||
|
{
|
||||||
DEBUGV("FS::open: invalid mode `%s`\r\n", mode);
|
DEBUGV("FS::open: invalid mode `%s`\r\n", mode);
|
||||||
return File();
|
return File();
|
||||||
}
|
}
|
||||||
return File(_impl->open(path, om, am), this);
|
return File(_impl->open(path, om, am), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::exists(const char* path) {
|
bool FS::exists(const char* path)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->exists(path);
|
return _impl->exists(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::exists(const String& path) {
|
bool FS::exists(const String& path)
|
||||||
|
{
|
||||||
return exists(path.c_str());
|
return exists(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Dir FS::openDir(const char* path) {
|
Dir FS::openDir(const char* path)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return Dir();
|
return Dir();
|
||||||
}
|
}
|
||||||
DirImplPtr p = _impl->openDir(path);
|
DirImplPtr p = _impl->openDir(path);
|
||||||
return Dir(p, this);
|
return Dir(p, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dir FS::openDir(const String& path) {
|
Dir FS::openDir(const String& path)
|
||||||
|
{
|
||||||
return openDir(path.c_str());
|
return openDir(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::remove(const char* path) {
|
bool FS::remove(const char* path)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->remove(path);
|
return _impl->remove(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::remove(const String& path) {
|
bool FS::remove(const String& path)
|
||||||
|
{
|
||||||
return remove(path.c_str());
|
return remove(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::rmdir(const char* path) {
|
bool FS::rmdir(const char* path)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->rmdir(path);
|
return _impl->rmdir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::rmdir(const String& path) {
|
bool FS::rmdir(const String& path)
|
||||||
|
{
|
||||||
return rmdir(path.c_str());
|
return rmdir(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::mkdir(const char* path) {
|
bool FS::mkdir(const char* path)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->mkdir(path);
|
return _impl->mkdir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::mkdir(const String& path) {
|
bool FS::mkdir(const String& path)
|
||||||
|
{
|
||||||
return mkdir(path.c_str());
|
return mkdir(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::rename(const char* pathFrom, const char* pathTo) {
|
bool FS::rename(const char* pathFrom, const char* pathTo)
|
||||||
if (!_impl) {
|
{
|
||||||
|
if (!_impl)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->rename(pathFrom, pathTo);
|
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());
|
return rename(pathFrom.c_str(), pathTo.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
|
static bool sflags(const char* mode, OpenMode& om, AccessMode& am)
|
||||||
switch (mode[0]) {
|
{
|
||||||
case 'r':
|
switch (mode[0])
|
||||||
am = AM_READ;
|
{
|
||||||
om = OM_DEFAULT;
|
case 'r':
|
||||||
break;
|
am = AM_READ;
|
||||||
case 'w':
|
om = OM_DEFAULT;
|
||||||
am = AM_WRITE;
|
break;
|
||||||
om = (OpenMode) (OM_CREATE | OM_TRUNCATE);
|
case 'w':
|
||||||
break;
|
am = AM_WRITE;
|
||||||
case 'a':
|
om = (OpenMode)(OM_CREATE | OM_TRUNCATE);
|
||||||
am = AM_WRITE;
|
break;
|
||||||
om = (OpenMode) (OM_CREATE | OM_APPEND);
|
case 'a':
|
||||||
break;
|
am = AM_WRITE;
|
||||||
default:
|
om = (OpenMode)(OM_CREATE | OM_APPEND);
|
||||||
return false;
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
switch(mode[1]) {
|
switch (mode[1])
|
||||||
case '+':
|
{
|
||||||
am = (AccessMode) (AM_WRITE | AM_READ);
|
case '+':
|
||||||
break;
|
am = (AccessMode)(AM_WRITE | AM_READ);
|
||||||
case 0:
|
break;
|
||||||
break;
|
case 0:
|
||||||
default:
|
break;
|
||||||
return false;
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -403,7 +512,7 @@ static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
|
|||||||
#if defined(FS_FREESTANDING_FUNCTIONS)
|
#if defined(FS_FREESTANDING_FUNCTIONS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: move these functions to public API:
|
TODO: move these functions to public API:
|
||||||
*/
|
*/
|
||||||
File open(const char* path, const char* mode);
|
File open(const char* path, const char* mode);
|
||||||
File open(String& path, const char* mode);
|
File open(String& path, const char* mode);
|
||||||
@ -417,7 +526,8 @@ bool mount<FS>(FS& fs, const char* mountPoint);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
struct MountEntry {
|
struct MountEntry
|
||||||
|
{
|
||||||
FSImplPtr fs;
|
FSImplPtr fs;
|
||||||
String path;
|
String path;
|
||||||
MountEntry* next;
|
MountEntry* next;
|
||||||
@ -426,9 +536,11 @@ struct MountEntry {
|
|||||||
static MountEntry* s_mounted = nullptr;
|
static MountEntry* s_mounted = nullptr;
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
bool mount<FS>(FS& fs, const char* mountPoint) {
|
bool mount<FS>(FS& fs, const char* mountPoint)
|
||||||
|
{
|
||||||
FSImplPtr p = fs._impl;
|
FSImplPtr p = fs._impl;
|
||||||
if (!p || !p->mount()) {
|
if (!p || !p->mount())
|
||||||
|
{
|
||||||
DEBUGV("FSImpl mount failed\r\n");
|
DEBUGV("FSImpl mount failed\r\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -447,31 +559,39 @@ bool mount<FS>(FS& fs, const char* mountPoint) {
|
|||||||
/*
|
/*
|
||||||
iterate over MountEntries and look for the ones which match the path
|
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;
|
OpenMode om;
|
||||||
AccessMode am;
|
AccessMode am;
|
||||||
if (!sflags(mode, om, am)) {
|
if (!sflags(mode, om, am))
|
||||||
|
{
|
||||||
DEBUGV("open: invalid mode `%s`\r\n", mode);
|
DEBUGV("open: invalid mode `%s`\r\n", mode);
|
||||||
return File();
|
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();
|
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);
|
File result = entry->fs->open(path + offset);
|
||||||
if (result)
|
if (result)
|
||||||
|
{
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return File();
|
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);
|
return FS::open(path.c_str(), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dir openDir(const String& path) {
|
Dir openDir(const String& path)
|
||||||
|
{
|
||||||
return openDir(path.c_str());
|
return openDir(path.c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
FS.h - file system wrapper
|
FS.h - file system wrapper
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FS_H
|
#ifndef FS_H
|
||||||
#define FS_H
|
#define FS_H
|
||||||
@ -24,7 +24,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
namespace fs {
|
namespace fs
|
||||||
|
{
|
||||||
|
|
||||||
class File;
|
class File;
|
||||||
class Dir;
|
class Dir;
|
||||||
@ -40,7 +41,8 @@ typedef std::shared_ptr<DirImpl> DirImplPtr;
|
|||||||
template <typename Tfs>
|
template <typename Tfs>
|
||||||
bool mount(Tfs& fs, const char* mountPoint);
|
bool mount(Tfs& fs, const char* mountPoint);
|
||||||
|
|
||||||
enum SeekMode {
|
enum SeekMode
|
||||||
|
{
|
||||||
SeekSet = 0,
|
SeekSet = 0,
|
||||||
SeekCur = 1,
|
SeekCur = 1,
|
||||||
SeekEnd = 2
|
SeekEnd = 2
|
||||||
@ -60,12 +62,14 @@ public:
|
|||||||
int read() override;
|
int read() override;
|
||||||
int peek() override;
|
int peek() override;
|
||||||
void flush() 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);
|
return read((uint8_t*)buffer, length);
|
||||||
}
|
}
|
||||||
size_t read(uint8_t* buf, size_t size);
|
size_t read(uint8_t* buf, size_t size);
|
||||||
bool seek(uint32_t pos, SeekMode mode);
|
bool seek(uint32_t pos, SeekMode mode);
|
||||||
bool seek(uint32_t pos) {
|
bool seek(uint32_t pos)
|
||||||
|
{
|
||||||
return seek(pos, SeekSet);
|
return seek(pos, SeekSet);
|
||||||
}
|
}
|
||||||
size_t position() const;
|
size_t position() const;
|
||||||
@ -80,26 +84,29 @@ public:
|
|||||||
bool isDirectory() const;
|
bool isDirectory() const;
|
||||||
|
|
||||||
// Arduino "class SD" methods for compatibility
|
// 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;
|
uint8_t obuf[256];
|
||||||
size_t sentLen;
|
size_t doneLen = 0;
|
||||||
int i;
|
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));
|
src.read(obuf, sizeof(obuf));
|
||||||
doneLen = doneLen + sentLen;
|
sentLen = write(obuf, sizeof(obuf));
|
||||||
if(sentLen != sizeof(obuf)){
|
doneLen = doneLen + sentLen;
|
||||||
return doneLen;
|
if (sentLen != sizeof(obuf))
|
||||||
|
{
|
||||||
|
return doneLen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
size_t leftLen = src.available();
|
size_t leftLen = src.available();
|
||||||
src.read(obuf, leftLen);
|
src.read(obuf, leftLen);
|
||||||
sentLen = write(obuf, leftLen);
|
sentLen = write(obuf, leftLen);
|
||||||
doneLen = doneLen + sentLen;
|
doneLen = doneLen + sentLen;
|
||||||
return doneLen;
|
return doneLen;
|
||||||
}
|
}
|
||||||
using Print::write;
|
using Print::write;
|
||||||
|
|
||||||
@ -116,7 +123,8 @@ protected:
|
|||||||
FS *_baseFS;
|
FS *_baseFS;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dir {
|
class Dir
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Dir(DirImplPtr impl = DirImplPtr(), FS *baseFS = nullptr): _impl(impl), _baseFS(baseFS) { }
|
Dir(DirImplPtr impl = DirImplPtr(), FS *baseFS = nullptr): _impl(impl), _baseFS(baseFS) { }
|
||||||
|
|
||||||
@ -135,7 +143,8 @@ protected:
|
|||||||
FS *_baseFS;
|
FS *_baseFS;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FSInfo {
|
struct FSInfo
|
||||||
|
{
|
||||||
size_t totalBytes;
|
size_t totalBytes;
|
||||||
size_t usedBytes;
|
size_t usedBytes;
|
||||||
size_t blockSize;
|
size_t blockSize;
|
||||||
@ -147,13 +156,15 @@ struct FSInfo {
|
|||||||
class FSConfig
|
class FSConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FSConfig(bool autoFormat = true) {
|
FSConfig(bool autoFormat = true)
|
||||||
|
{
|
||||||
_type = FSConfig::fsid::FSId;
|
_type = FSConfig::fsid::FSId;
|
||||||
_autoFormat = autoFormat;
|
_autoFormat = autoFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum fsid { FSId = 0x00000000 };
|
enum fsid { FSId = 0x00000000 };
|
||||||
FSConfig setAutoFormat(bool val = true) {
|
FSConfig setAutoFormat(bool val = true)
|
||||||
|
{
|
||||||
_autoFormat = val;
|
_autoFormat = val;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -165,9 +176,10 @@ public:
|
|||||||
class SPIFFSConfig : public FSConfig
|
class SPIFFSConfig : public FSConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SPIFFSConfig(bool autoFormat = true) {
|
SPIFFSConfig(bool autoFormat = true)
|
||||||
|
{
|
||||||
_type = SPIFFSConfig::fsid::FSId;
|
_type = SPIFFSConfig::fsid::FSId;
|
||||||
_autoFormat = autoFormat;
|
_autoFormat = autoFormat;
|
||||||
}
|
}
|
||||||
enum fsid { FSId = 0x53504946 };
|
enum fsid { FSId = 0x53504946 };
|
||||||
};
|
};
|
||||||
|
@ -1,31 +1,33 @@
|
|||||||
/*
|
/*
|
||||||
FSImpl.h - base file system interface
|
FSImpl.h - base file system interface
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#ifndef FSIMPL_H
|
#ifndef FSIMPL_H
|
||||||
#define FSIMPL_H
|
#define FSIMPL_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace fs {
|
namespace fs
|
||||||
|
{
|
||||||
|
|
||||||
class FileImpl {
|
class FileImpl
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~FileImpl() { }
|
virtual ~FileImpl() { }
|
||||||
virtual size_t write(const uint8_t *buf, size_t size) = 0;
|
virtual size_t write(const uint8_t *buf, size_t size) = 0;
|
||||||
@ -42,20 +44,23 @@ public:
|
|||||||
virtual bool isDirectory() const = 0;
|
virtual bool isDirectory() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OpenMode {
|
enum OpenMode
|
||||||
|
{
|
||||||
OM_DEFAULT = 0,
|
OM_DEFAULT = 0,
|
||||||
OM_CREATE = 1,
|
OM_CREATE = 1,
|
||||||
OM_APPEND = 2,
|
OM_APPEND = 2,
|
||||||
OM_TRUNCATE = 4
|
OM_TRUNCATE = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AccessMode {
|
enum AccessMode
|
||||||
|
{
|
||||||
AM_READ = 1,
|
AM_READ = 1,
|
||||||
AM_WRITE = 2,
|
AM_WRITE = 2,
|
||||||
AM_RW = AM_READ | AM_WRITE
|
AM_RW = AM_READ | AM_WRITE
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirImpl {
|
class DirImpl
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~DirImpl() { }
|
virtual ~DirImpl() { }
|
||||||
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
|
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
|
||||||
@ -67,9 +72,10 @@ public:
|
|||||||
virtual bool rewind() = 0;
|
virtual bool rewind() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FSImpl {
|
class FSImpl
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~FSImpl () { }
|
virtual ~FSImpl() { }
|
||||||
virtual bool setConfig(const FSConfig &cfg) = 0;
|
virtual bool setConfig(const FSConfig &cfg) = 0;
|
||||||
virtual bool begin() = 0;
|
virtual bool begin() = 0;
|
||||||
virtual void end() = 0;
|
virtual void end() = 0;
|
||||||
@ -82,7 +88,10 @@ public:
|
|||||||
virtual bool remove(const char* path) = 0;
|
virtual bool remove(const char* path) = 0;
|
||||||
virtual bool mkdir(const char* path) = 0;
|
virtual bool mkdir(const char* path) = 0;
|
||||||
virtual bool rmdir(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
|
} // namespace fs
|
||||||
|
@ -8,64 +8,64 @@ typedef void (*voidFuncPtr)(void);
|
|||||||
typedef void (*voidFuncPtrArg)(void*);
|
typedef void (*voidFuncPtrArg)(void*);
|
||||||
|
|
||||||
// Helper functions for Functional interrupt routines
|
// Helper functions for Functional interrupt routines
|
||||||
extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp , int mode);
|
extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp, int mode);
|
||||||
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR interruptFunctional(void* arg)
|
void ICACHE_RAM_ATTR interruptFunctional(void* arg)
|
||||||
{
|
{
|
||||||
ArgStructure* localArg = (ArgStructure*)arg;
|
ArgStructure* localArg = (ArgStructure*)arg;
|
||||||
if (localArg->functionInfo->reqScheduledFunction)
|
if (localArg->functionInfo->reqScheduledFunction)
|
||||||
{
|
{
|
||||||
schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))));
|
schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction, InterruptInfo(*(localArg->interruptInfo))));
|
||||||
// scheduledInterrupts->scheduleFunctionReg(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))), false, true);
|
// scheduledInterrupts->scheduleFunctionReg(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))), false, true);
|
||||||
}
|
}
|
||||||
if (localArg->functionInfo->reqFunction)
|
if (localArg->functionInfo->reqFunction)
|
||||||
{
|
{
|
||||||
localArg->functionInfo->reqFunction();
|
localArg->functionInfo->reqFunction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
void cleanupFunctional(void* arg)
|
void cleanupFunctional(void* arg)
|
||||||
{
|
{
|
||||||
ArgStructure* localArg = (ArgStructure*)arg;
|
ArgStructure* localArg = (ArgStructure*)arg;
|
||||||
delete (FunctionInfo*)localArg->functionInfo;
|
delete (FunctionInfo*)localArg->functionInfo;
|
||||||
delete (InterruptInfo*)localArg->interruptInfo;
|
delete (InterruptInfo*)localArg->interruptInfo;
|
||||||
delete localArg;
|
delete localArg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
|
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
|
||||||
{
|
{
|
||||||
// use the local interrupt routine which takes the ArgStructure as argument
|
// use the local interrupt routine which takes the ArgStructure as argument
|
||||||
|
|
||||||
InterruptInfo* ii = nullptr;
|
InterruptInfo* ii = nullptr;
|
||||||
|
|
||||||
FunctionInfo* fi = new FunctionInfo;
|
FunctionInfo* fi = new FunctionInfo;
|
||||||
fi->reqFunction = intRoutine;
|
fi->reqFunction = intRoutine;
|
||||||
|
|
||||||
ArgStructure* as = new ArgStructure;
|
ArgStructure* as = new ArgStructure;
|
||||||
as->interruptInfo = ii;
|
as->interruptInfo = ii;
|
||||||
as->functionInfo = fi;
|
as->functionInfo = fi;
|
||||||
|
|
||||||
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
|
__attachInterruptArg(pin, (voidFuncPtr)interruptFunctional, as, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode)
|
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode)
|
||||||
{
|
{
|
||||||
if (!scheduledInterrupts)
|
if (!scheduledInterrupts)
|
||||||
{
|
{
|
||||||
scheduledInterrupts = new ScheduledFunctions(32);
|
scheduledInterrupts = new ScheduledFunctions(32);
|
||||||
}
|
}
|
||||||
InterruptInfo* ii = new InterruptInfo;
|
InterruptInfo* ii = new InterruptInfo;
|
||||||
|
|
||||||
FunctionInfo* fi = new FunctionInfo;
|
FunctionInfo* fi = new FunctionInfo;
|
||||||
fi->reqScheduledFunction = scheduledIntRoutine;
|
fi->reqScheduledFunction = scheduledIntRoutine;
|
||||||
|
|
||||||
ArgStructure* as = new ArgStructure;
|
ArgStructure* as = new ArgStructure;
|
||||||
as->interruptInfo = ii;
|
as->interruptInfo = ii;
|
||||||
as->functionInfo = fi;
|
as->functionInfo = fi;
|
||||||
|
|
||||||
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
|
__attachInterruptArg(pin, (voidFuncPtr)interruptFunctional, as, mode);
|
||||||
}
|
}
|
||||||
|
@ -13,20 +13,23 @@ extern "C" {
|
|||||||
|
|
||||||
// Structures for communication
|
// Structures for communication
|
||||||
|
|
||||||
struct InterruptInfo {
|
struct InterruptInfo
|
||||||
uint8_t pin = 0;
|
{
|
||||||
uint8_t value = 0;
|
uint8_t pin = 0;
|
||||||
uint32_t micro = 0;
|
uint8_t value = 0;
|
||||||
|
uint32_t micro = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FunctionInfo {
|
struct FunctionInfo
|
||||||
|
{
|
||||||
std::function<void(void)> reqFunction = nullptr;
|
std::function<void(void)> reqFunction = nullptr;
|
||||||
std::function<void(InterruptInfo)> reqScheduledFunction = nullptr;
|
std::function<void(InterruptInfo)> reqScheduledFunction = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArgStructure {
|
struct ArgStructure
|
||||||
InterruptInfo* interruptInfo = nullptr;
|
{
|
||||||
FunctionInfo* functionInfo = nullptr;
|
InterruptInfo* interruptInfo = nullptr;
|
||||||
|
FunctionInfo* functionInfo = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ScheduledFunctions* scheduledInterrupts;
|
static ScheduledFunctions* scheduledInterrupts;
|
||||||
|
@ -1,157 +1,176 @@
|
|||||||
/*
|
/*
|
||||||
HardwareSerial.cpp - esp8266 UART support
|
HardwareSerial.cpp - esp8266 UART support
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266)
|
Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266)
|
||||||
Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266)
|
Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266)
|
||||||
Modified 3 May 2015 by Hristo Gochkov (change register access methods)
|
Modified 3 May 2015 by Hristo Gochkov (change register access methods)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <PolledTimeout.h>
|
#include <PolledTimeout.h>
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "HardwareSerial.h"
|
#include "HardwareSerial.h"
|
||||||
#include "Esp.h"
|
#include "Esp.h"
|
||||||
|
|
||||||
HardwareSerial::HardwareSerial(int uart_nr)
|
HardwareSerial::HardwareSerial(int uart_nr)
|
||||||
: _uart_nr(uart_nr), _rx_size(256)
|
: _uart_nr(uart_nr), _rx_size(256)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
|
void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
|
||||||
{
|
{
|
||||||
end();
|
end();
|
||||||
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size);
|
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size);
|
||||||
#if defined(DEBUG_ESP_PORT) && !defined(NDEBUG)
|
#if defined(DEBUG_ESP_PORT) && !defined(NDEBUG)
|
||||||
if (static_cast<void*>(this) == static_cast<void*>(&DEBUG_ESP_PORT))
|
if (static_cast<void*>(this) == static_cast<void*>(&DEBUG_ESP_PORT))
|
||||||
{
|
{
|
||||||
setDebugOutput(true);
|
setDebugOutput(true);
|
||||||
println();
|
println();
|
||||||
println(ESP.getFullVersion());
|
println(ESP.getFullVersion());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void HardwareSerial::end()
|
void HardwareSerial::end()
|
||||||
{
|
{
|
||||||
if(uart_get_debug() == _uart_nr) {
|
if (uart_get_debug() == _uart_nr)
|
||||||
uart_set_debug(UART_NO);
|
{
|
||||||
}
|
uart_set_debug(UART_NO);
|
||||||
|
}
|
||||||
uart_uninit(_uart);
|
|
||||||
_uart = NULL;
|
uart_uninit(_uart);
|
||||||
}
|
_uart = NULL;
|
||||||
|
}
|
||||||
size_t HardwareSerial::setRxBufferSize(size_t size){
|
|
||||||
if(_uart) {
|
size_t HardwareSerial::setRxBufferSize(size_t size)
|
||||||
_rx_size = uart_resize_rx_buffer(_uart, size);
|
{
|
||||||
} else {
|
if (_uart)
|
||||||
_rx_size = size;
|
{
|
||||||
}
|
_rx_size = uart_resize_rx_buffer(_uart, size);
|
||||||
return _rx_size;
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
void HardwareSerial::setDebugOutput(bool en)
|
_rx_size = size;
|
||||||
{
|
}
|
||||||
if(!_uart) {
|
return _rx_size;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
if(en) {
|
void HardwareSerial::setDebugOutput(bool en)
|
||||||
if(uart_tx_enabled(_uart)) {
|
{
|
||||||
uart_set_debug(_uart_nr);
|
if (!_uart)
|
||||||
} else {
|
{
|
||||||
uart_set_debug(UART_NO);
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
if (en)
|
||||||
// disable debug for this interface
|
{
|
||||||
if(uart_get_debug() == _uart_nr) {
|
if (uart_tx_enabled(_uart))
|
||||||
uart_set_debug(UART_NO);
|
{
|
||||||
}
|
uart_set_debug(_uart_nr);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
int HardwareSerial::available(void)
|
uart_set_debug(UART_NO);
|
||||||
{
|
}
|
||||||
int result = static_cast<int>(uart_rx_available(_uart));
|
}
|
||||||
if (!result) {
|
else
|
||||||
optimistic_yield(10000);
|
{
|
||||||
}
|
// disable debug for this interface
|
||||||
return result;
|
if (uart_get_debug() == _uart_nr)
|
||||||
}
|
{
|
||||||
|
uart_set_debug(UART_NO);
|
||||||
void HardwareSerial::flush()
|
}
|
||||||
{
|
}
|
||||||
if(!_uart || !uart_tx_enabled(_uart)) {
|
}
|
||||||
return;
|
|
||||||
}
|
int HardwareSerial::available(void)
|
||||||
|
{
|
||||||
uart_wait_tx_empty(_uart);
|
int result = static_cast<int>(uart_rx_available(_uart));
|
||||||
//Workaround for a bug in serial not actually being finished yet
|
if (!result)
|
||||||
//Wait for 8 data bits, 1 parity and 2 stop bits, just in case
|
{
|
||||||
delayMicroseconds(11000000 / uart_get_baudrate(_uart) + 1);
|
optimistic_yield(10000);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
void HardwareSerial::startDetectBaudrate()
|
}
|
||||||
{
|
|
||||||
uart_start_detect_baudrate(_uart_nr);
|
void HardwareSerial::flush()
|
||||||
}
|
{
|
||||||
|
if (!_uart || !uart_tx_enabled(_uart))
|
||||||
unsigned long HardwareSerial::testBaudrate()
|
{
|
||||||
{
|
return;
|
||||||
return uart_detect_baudrate(_uart_nr);
|
}
|
||||||
}
|
|
||||||
|
uart_wait_tx_empty(_uart);
|
||||||
unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
|
//Workaround for a bug in serial not actually being finished yet
|
||||||
{
|
//Wait for 8 data bits, 1 parity and 2 stop bits, just in case
|
||||||
time_t startMillis = millis();
|
delayMicroseconds(11000000 / uart_get_baudrate(_uart) + 1);
|
||||||
unsigned long detectedBaudrate;
|
}
|
||||||
while ((time_t) millis() - startMillis < timeoutMillis) {
|
|
||||||
if ((detectedBaudrate = testBaudrate())) {
|
void HardwareSerial::startDetectBaudrate()
|
||||||
break;
|
{
|
||||||
}
|
uart_start_detect_baudrate(_uart_nr);
|
||||||
yield();
|
}
|
||||||
delay(100);
|
|
||||||
}
|
unsigned long HardwareSerial::testBaudrate()
|
||||||
return detectedBaudrate;
|
{
|
||||||
}
|
return uart_detect_baudrate(_uart_nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
|
||||||
|
{
|
||||||
|
time_t startMillis = millis();
|
||||||
|
unsigned long detectedBaudrate;
|
||||||
|
while ((time_t) millis() - startMillis < timeoutMillis)
|
||||||
|
{
|
||||||
|
if ((detectedBaudrate = testBaudrate()))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
return detectedBaudrate;
|
||||||
|
}
|
||||||
|
|
||||||
size_t HardwareSerial::readBytes(char* buffer, size_t size)
|
size_t HardwareSerial::readBytes(char* buffer, size_t size)
|
||||||
{
|
{
|
||||||
size_t got = 0;
|
size_t got = 0;
|
||||||
|
|
||||||
while (got < size)
|
while (got < size)
|
||||||
{
|
{
|
||||||
esp8266::polledTimeout::oneShotFastMs timeOut(_timeout);
|
esp8266::polledTimeout::oneShotFastMs timeOut(_timeout);
|
||||||
size_t avail;
|
size_t avail;
|
||||||
while ((avail = available()) == 0 && !timeOut);
|
while ((avail = available()) == 0 && !timeOut);
|
||||||
if (avail == 0)
|
if (avail == 0)
|
||||||
break;
|
{
|
||||||
got += read(buffer + got, std::min(size - got, avail));
|
break;
|
||||||
}
|
}
|
||||||
return got;
|
got += read(buffer + got, std::min(size - got, avail));
|
||||||
|
}
|
||||||
|
return got;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||||
HardwareSerial Serial(UART0);
|
HardwareSerial Serial(UART0);
|
||||||
#endif
|
#endif
|
||||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL1)
|
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL1)
|
||||||
HardwareSerial Serial1(UART1);
|
HardwareSerial Serial1(UART1);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
/*
|
/*
|
||||||
HardwareSerial.h - Hardware serial library for Wiring
|
HardwareSerial.h - Hardware serial library for Wiring
|
||||||
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
Modified 28 September 2010 by Mark Sproul
|
Modified 28 September 2010 by Mark Sproul
|
||||||
Modified 14 August 2012 by Alarus
|
Modified 14 August 2012 by Alarus
|
||||||
Modified 3 December 2013 by Matthijs Kooijman
|
Modified 3 December 2013 by Matthijs Kooijman
|
||||||
Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support)
|
Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support)
|
||||||
Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266)
|
Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266)
|
||||||
Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266)
|
Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HardwareSerial_h
|
#ifndef HardwareSerial_h
|
||||||
#define HardwareSerial_h
|
#define HardwareSerial_h
|
||||||
@ -32,7 +32,8 @@
|
|||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
|
||||||
enum SerialConfig {
|
enum SerialConfig
|
||||||
|
{
|
||||||
SERIAL_5N1 = UART_5N1,
|
SERIAL_5N1 = UART_5N1,
|
||||||
SERIAL_6N1 = UART_6N1,
|
SERIAL_6N1 = UART_6N1,
|
||||||
SERIAL_7N1 = UART_7N1,
|
SERIAL_7N1 = UART_7N1,
|
||||||
@ -59,7 +60,8 @@ enum SerialConfig {
|
|||||||
SERIAL_8O2 = UART_8O2,
|
SERIAL_8O2 = UART_8O2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SerialMode {
|
enum SerialMode
|
||||||
|
{
|
||||||
SERIAL_FULL = UART_FULL,
|
SERIAL_FULL = UART_FULL,
|
||||||
SERIAL_RX_ONLY = UART_RX_ONLY,
|
SERIAL_RX_ONLY = UART_RX_ONLY,
|
||||||
SERIAL_TX_ONLY = UART_TX_ONLY
|
SERIAL_TX_ONLY = UART_TX_ONLY
|
||||||
@ -104,18 +106,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Toggle between use of GPIO1 and GPIO2 as TX on 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!
|
Note: UART 1 can't be used if GPIO2 is used with UART 0!
|
||||||
*/
|
*/
|
||||||
void set_tx(uint8_t tx_pin)
|
void set_tx(uint8_t tx_pin)
|
||||||
{
|
{
|
||||||
uart_set_tx(_uart, tx_pin);
|
uart_set_tx(_uart, tx_pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UART 0 possible options are (1, 3), (2, 3) or (15, 13)
|
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 1 allows only TX on 2 if UART 0 is not (2, 3)
|
||||||
*/
|
*/
|
||||||
void pins(uint8_t tx, uint8_t rx)
|
void pins(uint8_t tx, uint8_t rx)
|
||||||
{
|
{
|
||||||
uart_set_pins(_uart, tx, rx);
|
uart_set_pins(_uart, tx, rx);
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
IPAddress.cpp - Base class that provides IPAddress
|
IPAddress.cpp - Base class that provides IPAddress
|
||||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
@ -27,15 +27,18 @@ IPAddress::IPAddress(const IPAddress& from)
|
|||||||
ip_addr_copy(_ip, from._ip);
|
ip_addr_copy(_ip, from._ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress::IPAddress() {
|
IPAddress::IPAddress()
|
||||||
|
{
|
||||||
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
|
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPAddress::isSet () const {
|
bool IPAddress::isSet() const
|
||||||
|
{
|
||||||
return !ip_addr_isany(&_ip);
|
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();
|
setV4();
|
||||||
(*this)[0] = first_octet;
|
(*this)[0] = first_octet;
|
||||||
(*this)[1] = second_octet;
|
(*this)[1] = second_octet;
|
||||||
@ -43,12 +46,14 @@ IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_oc
|
|||||||
(*this)[3] = fourth_octet;
|
(*this)[3] = fourth_octet;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPAddress::ctor32(uint32_t address) {
|
void IPAddress::ctor32(uint32_t address)
|
||||||
|
{
|
||||||
setV4();
|
setV4();
|
||||||
v4() = address;
|
v4() = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress::IPAddress(const uint8_t *address) {
|
IPAddress::IPAddress(const uint8_t *address)
|
||||||
|
{
|
||||||
setV4();
|
setV4();
|
||||||
(*this)[0] = address[0];
|
(*this)[0] = address[0];
|
||||||
(*this)[1] = address[1];
|
(*this)[1] = address[1];
|
||||||
@ -56,8 +61,10 @@ IPAddress::IPAddress(const uint8_t *address) {
|
|||||||
(*this)[3] = address[3];
|
(*this)[3] = address[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPAddress::fromString(const char *address) {
|
bool IPAddress::fromString(const char *address)
|
||||||
if (!fromString4(address)) {
|
{
|
||||||
|
if (!fromString4(address))
|
||||||
|
{
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
return fromString6(address);
|
return fromString6(address);
|
||||||
#else
|
#else
|
||||||
@ -67,7 +74,8 @@ bool IPAddress::fromString(const char *address) {
|
|||||||
return true;
|
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
|
// TODO: (IPv4) add support for "a", "a.b", "a.b.c" formats
|
||||||
|
|
||||||
uint16_t acc = 0; // Accumulator
|
uint16_t acc = 0; // Accumulator
|
||||||
@ -79,14 +87,16 @@ bool IPAddress::fromString4(const char *address) {
|
|||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
{
|
{
|
||||||
acc = acc * 10 + (c - '0');
|
acc = acc * 10 + (c - '0');
|
||||||
if (acc > 255) {
|
if (acc > 255)
|
||||||
|
{
|
||||||
// Value out of [0..255] range
|
// Value out of [0..255] range
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == '.')
|
else if (c == '.')
|
||||||
{
|
{
|
||||||
if (dots == 3) {
|
if (dots == 3)
|
||||||
|
{
|
||||||
// Too much dots (there must be 3 dots)
|
// Too much dots (there must be 3 dots)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -100,7 +110,8 @@ bool IPAddress::fromString4(const char *address) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dots != 3) {
|
if (dots != 3)
|
||||||
|
{
|
||||||
// Too few dots (there must be 3 dots)
|
// Too few dots (there must be 3 dots)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -110,51 +121,70 @@ bool IPAddress::fromString4(const char *address) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress& IPAddress::operator=(const uint8_t *address) {
|
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||||
|
{
|
||||||
setV4();
|
setV4();
|
||||||
v4() = *reinterpret_cast<const uint32_t*>(address);
|
v4() = *reinterpret_cast<const uint32_t*>(address);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress& IPAddress::operator=(uint32_t address) {
|
IPAddress& IPAddress::operator=(uint32_t address)
|
||||||
|
{
|
||||||
setV4();
|
setV4();
|
||||||
v4() = address;
|
v4() = address;
|
||||||
return *this;
|
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);
|
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;
|
size_t n = 0;
|
||||||
|
|
||||||
if (!isSet())
|
if (!isSet())
|
||||||
|
{
|
||||||
return p.print(F("(IP unset)"));
|
return p.print(F("(IP unset)"));
|
||||||
|
}
|
||||||
|
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
if (isV6()) {
|
if (isV6())
|
||||||
|
{
|
||||||
int count0 = 0;
|
int count0 = 0;
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
uint16_t bit = PP_NTOHS(raw6()[i]);
|
uint16_t bit = PP_NTOHS(raw6()[i]);
|
||||||
if (bit || count0 < 0) {
|
if (bit || count0 < 0)
|
||||||
|
{
|
||||||
n += p.printf("%x", bit);
|
n += p.printf("%x", bit);
|
||||||
if (count0 > 0)
|
if (count0 > 0)
|
||||||
// no more hiding 0
|
// no more hiding 0
|
||||||
|
{
|
||||||
count0 = -8;
|
count0 = -8;
|
||||||
} else
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
count0++;
|
count0++;
|
||||||
|
}
|
||||||
if ((i != 7 && count0 < 2) || count0 == 7)
|
if ((i != 7 && count0 < 2) || count0 == 7)
|
||||||
|
{
|
||||||
n += p.print(':');
|
n += p.print(':');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
n += p.print((*this)[i], DEC);
|
n += p.print((*this)[i], DEC);
|
||||||
if (i != 3)
|
if (i != 3)
|
||||||
|
{
|
||||||
n += p.print('.');
|
n += p.print('.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -164,7 +194,9 @@ String IPAddress::toString() const
|
|||||||
StreamString sstr;
|
StreamString sstr;
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
if (isV6())
|
if (isV6())
|
||||||
sstr.reserve(40); // 8 shorts x 4 chars each + 7 colons + nullterm
|
{
|
||||||
|
sstr.reserve(40); // 8 shorts x 4 chars each + 7 colons + nullterm
|
||||||
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
sstr.reserve(16); // 4 bytes with 3 chars max + 3 dots + nullterm, or '(IP unset)'
|
sstr.reserve(16); // 4 bytes with 3 chars max + 3 dots + nullterm, or '(IP unset)'
|
||||||
@ -172,22 +204,25 @@ String IPAddress::toString() const
|
|||||||
return sstr;
|
return sstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPAddress::isValid(const String& arg) {
|
bool IPAddress::isValid(const String& arg)
|
||||||
return IPAddress().fromString(arg);
|
{
|
||||||
|
return IPAddress().fromString(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IPAddress::isValid(const char* arg) {
|
bool IPAddress::isValid(const char* arg)
|
||||||
return IPAddress().fromString(arg);
|
{
|
||||||
|
return IPAddress().fromString(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
CONST IPAddress INADDR_ANY; // generic "0.0.0.0" for IPv4 & IPv6
|
CONST IPAddress INADDR_ANY; // generic "0.0.0.0" for IPv4 & IPv6
|
||||||
const IPAddress INADDR_NONE(255,255,255,255);
|
const IPAddress INADDR_NONE(255, 255, 255, 255);
|
||||||
|
|
||||||
/**************************************/
|
/**************************************/
|
||||||
|
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
|
|
||||||
bool IPAddress::fromString6(const char *address) {
|
bool IPAddress::fromString6(const char *address)
|
||||||
|
{
|
||||||
// TODO: test test test
|
// TODO: test test test
|
||||||
|
|
||||||
uint32_t acc = 0; // Accumulator
|
uint32_t acc = 0; // Accumulator
|
||||||
@ -196,44 +231,64 @@ bool IPAddress::fromString6(const char *address) {
|
|||||||
while (*address)
|
while (*address)
|
||||||
{
|
{
|
||||||
char c = tolower(*address++);
|
char c = tolower(*address++);
|
||||||
if (isalnum(c)) {
|
if (isalnum(c))
|
||||||
|
{
|
||||||
if (c >= 'a')
|
if (c >= 'a')
|
||||||
|
{
|
||||||
c -= 'a' - '0' - 10;
|
c -= 'a' - '0' - 10;
|
||||||
|
}
|
||||||
acc = acc * 16 + (c - '0');
|
acc = acc * 16 + (c - '0');
|
||||||
if (acc > 0xffff)
|
if (acc > 0xffff)
|
||||||
// Value out of range
|
// Value out of range
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (c == ':') {
|
else if (c == ':')
|
||||||
if (*address == ':') {
|
{
|
||||||
|
if (*address == ':')
|
||||||
|
{
|
||||||
if (doubledots >= 0)
|
if (doubledots >= 0)
|
||||||
// :: allowed once
|
// :: allowed once
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
// remember location
|
// remember location
|
||||||
doubledots = dots + !!acc;
|
doubledots = dots + !!acc;
|
||||||
address++;
|
address++;
|
||||||
}
|
}
|
||||||
if (dots == 7)
|
if (dots == 7)
|
||||||
// too many separators
|
// too many separators
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
raw6()[dots++] = PP_HTONS(acc);
|
raw6()[dots++] = PP_HTONS(acc);
|
||||||
acc = 0;
|
acc = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// Invalid char
|
// Invalid char
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doubledots == -1 && dots != 7)
|
if (doubledots == -1 && dots != 7)
|
||||||
// Too few separators
|
// Too few separators
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
raw6()[dots++] = PP_HTONS(acc);
|
raw6()[dots++] = PP_HTONS(acc);
|
||||||
|
|
||||||
if (doubledots != -1) {
|
if (doubledots != -1)
|
||||||
|
{
|
||||||
for (int i = dots - doubledots - 1; i >= 0; i--)
|
for (int i = dots - doubledots - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
raw6()[8 - dots + doubledots + i] = raw6()[doubledots + i];
|
raw6()[8 - dots + doubledots + i] = raw6()[doubledots + i];
|
||||||
|
}
|
||||||
for (int i = doubledots; i < 8 - dots + doubledots; i++)
|
for (int i = doubledots; i < 8 - dots + doubledots; i++)
|
||||||
|
{
|
||||||
raw6()[i] = 0;
|
raw6()[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setV6();
|
setV6();
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
IPAddress.h - Base class that provides IPAddress
|
IPAddress.h - Base class that provides IPAddress
|
||||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IPAddress_h
|
#ifndef IPAddress_h
|
||||||
#define IPAddress_h
|
#define IPAddress_h
|
||||||
@ -54,167 +54,283 @@ struct ip_addr: ipv4_addr { };
|
|||||||
// fully backward compatible with legacy IPv4-only Arduino's
|
// fully backward compatible with legacy IPv4-only Arduino's
|
||||||
// with unchanged footprint when IPv6 is disabled
|
// with unchanged footprint when IPv6 is disabled
|
||||||
|
|
||||||
class IPAddress: public Printable {
|
class IPAddress: public Printable
|
||||||
private:
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
ip_addr_t _ip;
|
ip_addr_t _ip;
|
||||||
|
|
||||||
// Access the raw byte array containing the address. Because this returns a pointer
|
// Access the raw byte array containing the address. Because this returns a pointer
|
||||||
// to the internal structure rather than a copy of the address this function should only
|
// 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
|
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||||
// stored.
|
// stored.
|
||||||
uint8_t* raw_address() {
|
uint8_t* raw_address()
|
||||||
return reinterpret_cast<uint8_t*>(&v4());
|
{
|
||||||
}
|
return reinterpret_cast<uint8_t*>(&v4());
|
||||||
const uint8_t* raw_address() const {
|
}
|
||||||
return reinterpret_cast<const uint8_t*>(&v4());
|
const uint8_t* raw_address() const
|
||||||
}
|
{
|
||||||
|
return reinterpret_cast<const uint8_t*>(&v4());
|
||||||
|
}
|
||||||
|
|
||||||
void ctor32 (uint32_t);
|
void ctor32(uint32_t);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructors
|
// Constructors
|
||||||
IPAddress();
|
IPAddress();
|
||||||
IPAddress(const IPAddress& from);
|
IPAddress(const IPAddress& from);
|
||||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||||
IPAddress(uint32_t address) { ctor32(address); }
|
IPAddress(uint32_t address)
|
||||||
IPAddress(u32_t address) { ctor32(address); }
|
{
|
||||||
IPAddress(int address) { ctor32(address); }
|
ctor32(address);
|
||||||
IPAddress(const uint8_t *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 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
|
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
|
||||||
// to a four-byte uint8_t array is expected
|
// to a four-byte uint8_t array is expected
|
||||||
operator uint32_t() const { return isV4()? v4(): (uint32_t)0; }
|
operator uint32_t() const
|
||||||
operator uint32_t() { return isV4()? v4(): (uint32_t)0; }
|
{
|
||||||
operator u32_t() const { return isV4()? v4(): (u32_t)0; }
|
return isV4() ? v4() : (uint32_t)0;
|
||||||
operator u32_t() { return isV4()? v4(): (u32_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;
|
bool isSet() const;
|
||||||
operator bool () const { return isSet(); } // <-
|
operator bool () const
|
||||||
operator bool () { return isSet(); } // <- both are needed
|
{
|
||||||
|
return isSet(); // <-
|
||||||
|
}
|
||||||
|
operator bool ()
|
||||||
|
{
|
||||||
|
return isSet(); // <- both are needed
|
||||||
|
}
|
||||||
|
|
||||||
// generic IPv4 wrapper to uint32-view like arduino loves to see it
|
// 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)
|
const u32_t& v4() const
|
||||||
u32_t& v4() { return ip_2_ip4(&_ip)->addr; }
|
{
|
||||||
|
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);
|
{
|
||||||
}
|
return ip_addr_cmp(&_ip, &addr._ip);
|
||||||
bool operator!=(const IPAddress& addr) const {
|
}
|
||||||
return !ip_addr_cmp(&_ip, &addr._ip);
|
bool operator!=(const IPAddress& addr) const
|
||||||
}
|
{
|
||||||
bool operator==(uint32_t addr) const {
|
return !ip_addr_cmp(&_ip, &addr._ip);
|
||||||
return isV4() && v4() == addr;
|
}
|
||||||
}
|
bool operator==(uint32_t addr) const
|
||||||
bool operator==(u32_t addr) const {
|
{
|
||||||
return isV4() && v4() == addr;
|
return isV4() && v4() == addr;
|
||||||
}
|
}
|
||||||
bool operator!=(uint32_t addr) const {
|
bool operator==(u32_t addr) const
|
||||||
return !(isV4() && v4() == addr);
|
{
|
||||||
}
|
return isV4() && v4() == addr;
|
||||||
bool operator!=(u32_t addr) const {
|
}
|
||||||
return !(isV4() && v4() == addr);
|
bool operator!=(uint32_t addr) const
|
||||||
}
|
{
|
||||||
bool operator==(const uint8_t* addr) const;
|
return !(isV4() && v4() == addr);
|
||||||
|
}
|
||||||
|
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;
|
{
|
||||||
}
|
return isV4() ? v4() >> n : 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
// 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;
|
{
|
||||||
}
|
return isV4() ? *(raw_address() + index) : 0;
|
||||||
uint8_t& operator[](int index) {
|
}
|
||||||
setV4();
|
uint8_t& operator[](int index)
|
||||||
return *(raw_address() + index);
|
{
|
||||||
}
|
setV4();
|
||||||
|
return *(raw_address() + index);
|
||||||
|
}
|
||||||
|
|
||||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
||||||
IPAddress& operator=(const uint8_t *address);
|
IPAddress& operator=(const uint8_t *address);
|
||||||
IPAddress& operator=(uint32_t address);
|
IPAddress& operator=(uint32_t address);
|
||||||
|
|
||||||
virtual size_t printTo(Print& p) const;
|
virtual size_t printTo(Print& p) const;
|
||||||
String toString() const;
|
String toString() const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
check if input string(arg) is a valid IPV4 address or not.
|
check if input string(arg) is a valid IPV4 address or not.
|
||||||
return true on valid.
|
return true on valid.
|
||||||
return false on invalid.
|
return false on invalid.
|
||||||
*/
|
*/
|
||||||
static bool isValid(const String& arg);
|
static bool isValid(const String& arg);
|
||||||
static bool isValid(const char* arg);
|
static bool isValid(const char* arg);
|
||||||
|
|
||||||
friend class EthernetClass;
|
friend class EthernetClass;
|
||||||
friend class UDP;
|
friend class UDP;
|
||||||
friend class Client;
|
friend class Client;
|
||||||
friend class Server;
|
friend class Server;
|
||||||
friend class DhcpClass;
|
friend class DhcpClass;
|
||||||
friend class DNSClient;
|
friend class DNSClient;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
lwIP address compatibility
|
lwIP address compatibility
|
||||||
*/
|
*/
|
||||||
IPAddress(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; }
|
IPAddress(const ipv4_addr& fw_addr)
|
||||||
IPAddress(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->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)
|
||||||
IPAddress& operator=(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; return *this; }
|
{
|
||||||
|
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 ip_addr_t () const
|
||||||
operator const ip_addr_t*() const { return &_ip; }
|
{
|
||||||
operator ip_addr_t*() { return &_ip; }
|
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); }
|
bool isV4() const
|
||||||
void setV4() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V4); }
|
{
|
||||||
|
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
|
#if LWIP_IPV6
|
||||||
|
|
||||||
IPAddress(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); }
|
IPAddress(const ip_addr_t& lwip_addr)
|
||||||
IPAddress(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *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)
|
||||||
IPAddress& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; }
|
{
|
||||||
|
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()
|
uint16_t* raw6()
|
||||||
{
|
{
|
||||||
setV6();
|
setV6();
|
||||||
return reinterpret_cast<uint16_t*>(ip_2_ip6(&_ip));
|
return reinterpret_cast<uint16_t*>(ip_2_ip6(&_ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint16_t* raw6() const
|
const uint16_t* raw6() const
|
||||||
{
|
{
|
||||||
return isV6()? reinterpret_cast<const uint16_t*>(ip_2_ip6(&_ip)): nullptr;
|
return isV6() ? reinterpret_cast<const uint16_t*>(ip_2_ip6(&_ip)) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// when not IPv6, ip_addr_t == ip4_addr_t so this one would be ambiguous
|
// when not IPv6, ip_addr_t == ip4_addr_t so this one would be ambiguous
|
||||||
// required otherwise
|
// 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); }
|
bool isV6() const
|
||||||
void setV6() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6); }
|
{
|
||||||
|
return IP_IS_V6_VAL(_ip);
|
||||||
|
}
|
||||||
|
void setV6()
|
||||||
|
{
|
||||||
|
IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool fromString6(const char *address);
|
bool fromString6(const char *address);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// allow portable code when IPv6 is not enabled
|
// allow portable code when IPv6 is not enabled
|
||||||
|
|
||||||
uint16_t* raw6() { return nullptr; }
|
uint16_t* raw6()
|
||||||
const uint16_t* raw6() const { return nullptr; }
|
{
|
||||||
bool isV6() const { return false; }
|
return nullptr;
|
||||||
void setV6() { }
|
}
|
||||||
|
const uint16_t* raw6() const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool isV6() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void setV6() { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool fromString4(const char *address);
|
bool fromString4(const char *address);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,60 +1,72 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <MD5Builder.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)) :
|
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
|
||||||
(c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0;
|
(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);
|
memset(_buf, 0x00, 16);
|
||||||
MD5Init(&_ctx);
|
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);
|
MD5Update(&_ctx, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MD5Builder::addHexString(const char * data){
|
void MD5Builder::addHexString(const char * data)
|
||||||
|
{
|
||||||
uint16_t i, len = strlen(data);
|
uint16_t i, len = strlen(data);
|
||||||
uint8_t * tmp = (uint8_t*)malloc(len/2);
|
uint8_t * tmp = (uint8_t*)malloc(len / 2);
|
||||||
if(tmp == NULL) {
|
if (tmp == NULL)
|
||||||
|
{
|
||||||
return;
|
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 high = hex_char_to_byte(data[i]);
|
||||||
uint8_t low = hex_char_to_byte(data[i+1]);
|
uint8_t low = hex_char_to_byte(data[i + 1]);
|
||||||
tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F);
|
tmp[i / 2] = (high & 0x0F) << 4 | (low & 0x0F);
|
||||||
}
|
}
|
||||||
add(tmp, len/2);
|
add(tmp, len / 2);
|
||||||
free(tmp);
|
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;
|
const int buf_size = 512;
|
||||||
int maxLengthLeft = maxLen;
|
int maxLengthLeft = maxLen;
|
||||||
uint8_t * buf = (uint8_t*) malloc(buf_size);
|
uint8_t * buf = (uint8_t*) malloc(buf_size);
|
||||||
|
|
||||||
if(!buf) {
|
if (!buf)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytesAvailable = stream.available();
|
int bytesAvailable = stream.available();
|
||||||
while((bytesAvailable > 0) && (maxLengthLeft > 0)) {
|
while ((bytesAvailable > 0) && (maxLengthLeft > 0))
|
||||||
|
{
|
||||||
|
|
||||||
// determine number of bytes to read
|
// determine number of bytes to read
|
||||||
int readBytes = bytesAvailable;
|
int readBytes = bytesAvailable;
|
||||||
if(readBytes > maxLengthLeft) {
|
if (readBytes > maxLengthLeft)
|
||||||
|
{
|
||||||
readBytes = maxLengthLeft ; // read only until max_len
|
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
|
readBytes = buf_size; // not read more the buffer can handle
|
||||||
}
|
}
|
||||||
|
|
||||||
// read data and check if we got something
|
// read data and check if we got something
|
||||||
int numBytesRead = stream.readBytes(buf, readBytes);
|
int numBytesRead = stream.readBytes(buf, readBytes);
|
||||||
if(numBytesRead< 1) {
|
if (numBytesRead < 1)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,21 +83,26 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MD5Builder::calculate(void){
|
void MD5Builder::calculate(void)
|
||||||
|
{
|
||||||
MD5Final(_buf, &_ctx);
|
MD5Final(_buf, &_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MD5Builder::getBytes(uint8_t * output){
|
void MD5Builder::getBytes(uint8_t * output)
|
||||||
|
{
|
||||||
memcpy(output, _buf, 16);
|
memcpy(output, _buf, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MD5Builder::getChars(char * output){
|
void MD5Builder::getChars(char * output)
|
||||||
for(uint8_t i = 0; i < 16; i++) {
|
{
|
||||||
|
for (uint8_t i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
sprintf(output + (i * 2), "%02x", _buf[i]);
|
sprintf(output + (i * 2), "%02x", _buf[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String MD5Builder::toString(void){
|
String MD5Builder::toString(void)
|
||||||
|
{
|
||||||
char out[33];
|
char out[33];
|
||||||
getChars(out);
|
getChars(out);
|
||||||
return String(out);
|
return String(out);
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
md5.h - exposed md5 ROM functions for esp8266
|
md5.h - exposed md5 ROM functions for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#ifndef __ESP8266_MD5_BUILDER__
|
#ifndef __ESP8266_MD5_BUILDER__
|
||||||
#define __ESP8266_MD5_BUILDER__
|
#define __ESP8266_MD5_BUILDER__
|
||||||
@ -25,19 +25,35 @@
|
|||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
|
|
||||||
class MD5Builder {
|
class MD5Builder
|
||||||
private:
|
{
|
||||||
|
private:
|
||||||
md5_context_t _ctx;
|
md5_context_t _ctx;
|
||||||
uint8_t _buf[16];
|
uint8_t _buf[16];
|
||||||
public:
|
public:
|
||||||
void begin(void);
|
void begin(void);
|
||||||
void add(const uint8_t * data, const uint16_t len);
|
void add(const uint8_t * data, const uint16_t len);
|
||||||
void add(const char * data){ add((const uint8_t*)data, strlen(data)); }
|
void add(const char * data)
|
||||||
void add(char * data){ add((const char*)data); }
|
{
|
||||||
void add(const String& data){ add(data.c_str()); }
|
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(const char * data);
|
||||||
void addHexString(char * data){ addHexString((const char*)data); }
|
void addHexString(char * data)
|
||||||
void addHexString(const String& data){ addHexString(data.c_str()); }
|
{
|
||||||
|
addHexString((const char*)data);
|
||||||
|
}
|
||||||
|
void addHexString(const String& data)
|
||||||
|
{
|
||||||
|
addHexString(data.c_str());
|
||||||
|
}
|
||||||
bool addStream(Stream & stream, const size_t maxLen);
|
bool addStream(Stream & stream, const size_t maxLen);
|
||||||
void calculate(void);
|
void calculate(void);
|
||||||
void getBytes(uint8_t * output);
|
void getBytes(uint8_t * output);
|
||||||
|
@ -3,25 +3,25 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PolledTimeout.h - Encapsulation of a polled Timeout
|
PolledTimeout.h - Encapsulation of a polled Timeout
|
||||||
|
|
||||||
Copyright (c) 2018 Daniel Salazar. 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
|
Copyright (c) 2018 Daniel Salazar. All rights reserved.
|
||||||
modify it under the terms of the GNU Lesser General Public
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 <limits>
|
#include <limits>
|
||||||
|
|
||||||
@ -39,18 +39,24 @@ namespace YieldPolicy
|
|||||||
|
|
||||||
struct DoNothing
|
struct DoNothing
|
||||||
{
|
{
|
||||||
static void execute() {}
|
static void execute() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct YieldOrSkip
|
struct YieldOrSkip
|
||||||
{
|
{
|
||||||
static void execute() {delay(0);}
|
static void execute()
|
||||||
|
{
|
||||||
|
delay(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <unsigned long delayMs>
|
template <unsigned long delayMs>
|
||||||
struct YieldAndDelayMs
|
struct YieldAndDelayMs
|
||||||
{
|
{
|
||||||
static void execute() {delay(delayMs);}
|
static void execute()
|
||||||
|
{
|
||||||
|
delay(delayMs);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} //YieldPolicy
|
} //YieldPolicy
|
||||||
@ -60,74 +66,91 @@ namespace TimePolicy
|
|||||||
|
|
||||||
struct TimeSourceMillis
|
struct TimeSourceMillis
|
||||||
{
|
{
|
||||||
// time policy in milli-seconds based on millis()
|
// time policy in milli-seconds based on millis()
|
||||||
|
|
||||||
using timeType = decltype(millis());
|
using timeType = decltype(millis());
|
||||||
static timeType time() {return millis();}
|
static timeType time()
|
||||||
static constexpr timeType ticksPerSecond = 1000;
|
{
|
||||||
static constexpr timeType ticksPerSecondMax = 1000;
|
return millis();
|
||||||
|
}
|
||||||
|
static constexpr timeType ticksPerSecond = 1000;
|
||||||
|
static constexpr timeType ticksPerSecondMax = 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimeSourceCycles
|
struct TimeSourceCycles
|
||||||
{
|
{
|
||||||
// time policy based on ESP.getCycleCount()
|
// time policy based on ESP.getCycleCount()
|
||||||
// this particular time measurement is intended to be called very often
|
// this particular time measurement is intended to be called very often
|
||||||
// (every loop, every yield)
|
// (every loop, every yield)
|
||||||
|
|
||||||
using timeType = decltype(ESP.getCycleCount());
|
using timeType = decltype(ESP.getCycleCount());
|
||||||
static timeType time() {return ESP.getCycleCount();}
|
static timeType time()
|
||||||
static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz
|
{
|
||||||
static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz
|
return ESP.getCycleCount();
|
||||||
|
}
|
||||||
|
static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz
|
||||||
|
static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TimeSourceType, unsigned long long second_th>
|
template <typename TimeSourceType, unsigned long long second_th>
|
||||||
// "second_th" units of timeType for one second
|
// "second_th" units of timeType for one second
|
||||||
struct TimeUnit
|
struct TimeUnit
|
||||||
{
|
{
|
||||||
using timeType = typename TimeSourceType::timeType;
|
using timeType = typename TimeSourceType::timeType;
|
||||||
|
|
||||||
#if __GNUC__ < 5
|
#if __GNUC__ < 5
|
||||||
// gcc-4.8 cannot compile the constexpr-only version of this function
|
// gcc-4.8 cannot compile the constexpr-only version of this function
|
||||||
// using #defines instead luckily works
|
// using #defines instead luckily works
|
||||||
static constexpr timeType computeRangeCompensation ()
|
static constexpr timeType computeRangeCompensation()
|
||||||
{
|
{
|
||||||
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
|
#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)
|
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
|
||||||
|
|
||||||
return ({
|
return (
|
||||||
fractional == 0?
|
{
|
||||||
1: // no need for compensation
|
fractional == 0 ?
|
||||||
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
1 : // no need for compensation
|
||||||
});
|
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
||||||
|
});
|
||||||
|
|
||||||
#undef number_of_secondTh_in_one_tick
|
#undef number_of_secondTh_in_one_tick
|
||||||
#undef fractional
|
#undef fractional
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static constexpr timeType computeRangeCompensation ()
|
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;
|
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
|
||||||
fractional == 0?
|
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
|
||||||
1: // no need for compensation
|
fractional == 0 ?
|
||||||
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
1 : // no need for compensation
|
||||||
});
|
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
||||||
}
|
});
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
|
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
|
||||||
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
|
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
|
||||||
static constexpr timeType rangeCompensate = computeRangeCompensation();
|
static constexpr timeType rangeCompensate = computeRangeCompensation();
|
||||||
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
|
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
|
||||||
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
|
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
|
||||||
static constexpr timeType user2UnitDivider = rangeCompensate;
|
static constexpr timeType user2UnitDivider = rangeCompensate;
|
||||||
// std::numeric_limits<timeType>::max() is reserved
|
// std::numeric_limits<timeType>::max() is reserved
|
||||||
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
|
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
|
||||||
|
|
||||||
static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;}
|
static timeType toTimeTypeUnit(const timeType userUnit)
|
||||||
static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;}
|
{
|
||||||
static timeType time () {return TimeSourceType::time();}
|
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 >;
|
using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >;
|
||||||
@ -141,109 +164,113 @@ template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typena
|
|||||||
class timeoutTemplate
|
class timeoutTemplate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using timeType = typename TimePolicyT::timeType;
|
using timeType = typename TimePolicyT::timeType;
|
||||||
static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
|
static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
|
||||||
|
|
||||||
static constexpr timeType alwaysExpired = 0;
|
static constexpr timeType alwaysExpired = 0;
|
||||||
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
|
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
|
||||||
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
|
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
|
||||||
|
|
||||||
timeoutTemplate(const timeType userTimeout)
|
timeoutTemplate(const timeType userTimeout)
|
||||||
{
|
{
|
||||||
reset(userTimeout);
|
reset(userTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
ICACHE_RAM_ATTR
|
ICACHE_RAM_ATTR
|
||||||
bool expired()
|
bool expired()
|
||||||
{
|
{
|
||||||
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
|
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
|
||||||
if(PeriodicT) //in case of false: gets optimized away
|
if (PeriodicT) //in case of false: gets optimized away
|
||||||
return expiredRetrigger();
|
{
|
||||||
return expiredOneShot();
|
return expiredRetrigger();
|
||||||
}
|
}
|
||||||
|
return expiredOneShot();
|
||||||
ICACHE_RAM_ATTR
|
}
|
||||||
operator bool()
|
|
||||||
{
|
|
||||||
return expired();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canExpire () const
|
|
||||||
{
|
|
||||||
return !_neverExpires;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canWait () const
|
ICACHE_RAM_ATTR
|
||||||
{
|
operator bool()
|
||||||
return _timeout != alwaysExpired;
|
{
|
||||||
}
|
return expired();
|
||||||
|
}
|
||||||
|
|
||||||
void reset(const timeType newUserTimeout)
|
bool canExpire() const
|
||||||
{
|
{
|
||||||
reset();
|
return !_neverExpires;
|
||||||
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
|
}
|
||||||
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
bool canWait() const
|
||||||
{
|
{
|
||||||
_start = TimePolicyT::time();
|
return _timeout != alwaysExpired;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetToNeverExpires ()
|
void reset(const timeType newUserTimeout)
|
||||||
{
|
{
|
||||||
_timeout = alwaysExpired + 1; // because canWait() has precedence
|
reset();
|
||||||
_neverExpires = true;
|
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
|
||||||
}
|
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
|
||||||
|
}
|
||||||
|
|
||||||
timeType getTimeout() const
|
void reset()
|
||||||
{
|
{
|
||||||
return TimePolicyT::toUserUnit(_timeout);
|
_start = TimePolicyT::time();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr timeType timeMax()
|
void resetToNeverExpires()
|
||||||
{
|
{
|
||||||
return TimePolicyT::timeMax;
|
_timeout = alwaysExpired + 1; // because canWait() has precedence
|
||||||
}
|
_neverExpires = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType getTimeout() const
|
||||||
|
{
|
||||||
|
return TimePolicyT::toUserUnit(_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr timeType timeMax()
|
||||||
|
{
|
||||||
|
return TimePolicyT::timeMax;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ICACHE_RAM_ATTR
|
ICACHE_RAM_ATTR
|
||||||
bool checkExpired(const timeType internalUnit) const
|
bool checkExpired(const timeType internalUnit) const
|
||||||
{
|
{
|
||||||
// canWait() is not checked here
|
// canWait() is not checked here
|
||||||
// returns "can expire" and "time expired"
|
// returns "can expire" and "time expired"
|
||||||
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
|
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
ICACHE_RAM_ATTR
|
ICACHE_RAM_ATTR
|
||||||
bool expiredRetrigger()
|
bool expiredRetrigger()
|
||||||
{
|
|
||||||
if (!canWait())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
timeType current = TimePolicyT::time();
|
|
||||||
if(checkExpired(current))
|
|
||||||
{
|
{
|
||||||
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
|
if (!canWait())
|
||||||
_start += n * _timeout;
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType current = TimePolicyT::time();
|
||||||
|
if (checkExpired(current))
|
||||||
|
{
|
||||||
|
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
|
||||||
|
_start += n * _timeout;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
ICACHE_RAM_ATTR
|
||||||
|
bool expiredOneShot() const
|
||||||
ICACHE_RAM_ATTR
|
{
|
||||||
bool expiredOneShot() const
|
// returns "always expired" or "has expired"
|
||||||
{
|
return !canWait() || checkExpired(TimePolicyT::time());
|
||||||
// returns "always expired" or "has expired"
|
}
|
||||||
return !canWait() || checkExpired(TimePolicyT::time());
|
|
||||||
}
|
timeType _timeout;
|
||||||
|
timeType _start;
|
||||||
timeType _timeout;
|
bool _neverExpires;
|
||||||
timeType _start;
|
|
||||||
bool _neverExpires;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// legacy type names, deprecated (unit is milliseconds)
|
// legacy type names, deprecated (unit is milliseconds)
|
||||||
@ -276,11 +303,11 @@ using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothi
|
|||||||
} //polledTimeout
|
} //polledTimeout
|
||||||
|
|
||||||
|
|
||||||
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
|
/* 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>;
|
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.
|
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
|
}//esp8266
|
||||||
|
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
/*
|
/*
|
||||||
Print.cpp - Base class that provides print() and println()
|
Print.cpp - Base class that provides print() and println()
|
||||||
Copyright (c) 2008 David A. Mellis. All right reserved.
|
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
Modified 23 November 2006 by David A. Mellis
|
Modified 23 November 2006 by David A. Mellis
|
||||||
Modified December 2014 by Ivan Grokhotkov
|
Modified December 2014 by Ivan Grokhotkov
|
||||||
Modified May 2015 by Michael C. Miller - esp8266 progmem support
|
Modified May 2015 by Michael C. Miller - esp8266 progmem support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -32,21 +32,25 @@
|
|||||||
// Public Methods //////////////////////////////////////////////////////////////
|
// Public Methods //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/* default implementation: may be overridden */
|
/* 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
|
#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 char not_the_best_way [] PROGMEM STORE_ATTR = "Print::write(data,len) should be overridden for better efficiency\r\n";
|
||||||
static bool once = false;
|
static bool once = false;
|
||||||
if (!once) {
|
if (!once)
|
||||||
|
{
|
||||||
once = true;
|
once = true;
|
||||||
os_printf_plus(not_the_best_way);
|
os_printf_plus(not_the_best_way);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
while (size--) {
|
while (size--)
|
||||||
|
{
|
||||||
size_t ret = write(*buffer++);
|
size_t ret = write(*buffer++);
|
||||||
if (ret == 0) {
|
if (ret == 0)
|
||||||
|
{
|
||||||
// Write of last byte didn't complete, abort additional processing
|
// Write of last byte didn't complete, abort additional processing
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -55,16 +59,19 @@ size_t Print::write(const uint8_t *buffer, size_t size) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::printf(const char *format, ...) {
|
size_t Print::printf(const char *format, ...)
|
||||||
|
{
|
||||||
va_list arg;
|
va_list arg;
|
||||||
va_start(arg, format);
|
va_start(arg, format);
|
||||||
char temp[64];
|
char temp[64];
|
||||||
char* buffer = temp;
|
char* buffer = temp;
|
||||||
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
if (len > sizeof(temp) - 1) {
|
if (len > sizeof(temp) - 1)
|
||||||
|
{
|
||||||
buffer = new char[len + 1];
|
buffer = new char[len + 1];
|
||||||
if (!buffer) {
|
if (!buffer)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
va_start(arg, format);
|
va_start(arg, format);
|
||||||
@ -72,22 +79,26 @@ size_t Print::printf(const char *format, ...) {
|
|||||||
va_end(arg);
|
va_end(arg);
|
||||||
}
|
}
|
||||||
len = write((const uint8_t*) buffer, len);
|
len = write((const uint8_t*) buffer, len);
|
||||||
if (buffer != temp) {
|
if (buffer != temp)
|
||||||
|
{
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::printf_P(PGM_P format, ...) {
|
size_t Print::printf_P(PGM_P format, ...)
|
||||||
|
{
|
||||||
va_list arg;
|
va_list arg;
|
||||||
va_start(arg, format);
|
va_start(arg, format);
|
||||||
char temp[64];
|
char temp[64];
|
||||||
char* buffer = temp;
|
char* buffer = temp;
|
||||||
size_t len = vsnprintf_P(temp, sizeof(temp), format, arg);
|
size_t len = vsnprintf_P(temp, sizeof(temp), format, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
if (len > sizeof(temp) - 1) {
|
if (len > sizeof(temp) - 1)
|
||||||
|
{
|
||||||
buffer = new char[len + 1];
|
buffer = new char[len + 1];
|
||||||
if (!buffer) {
|
if (!buffer)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
va_start(arg, format);
|
va_start(arg, format);
|
||||||
@ -95,143 +106,181 @@ size_t Print::printf_P(PGM_P format, ...) {
|
|||||||
va_end(arg);
|
va_end(arg);
|
||||||
}
|
}
|
||||||
len = write((const uint8_t*) buffer, len);
|
len = write((const uint8_t*) buffer, len);
|
||||||
if (buffer != temp) {
|
if (buffer != temp)
|
||||||
|
{
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::print(const __FlashStringHelper *ifsh) {
|
size_t Print::print(const __FlashStringHelper *ifsh)
|
||||||
|
{
|
||||||
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
|
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
while (1) {
|
while (1)
|
||||||
|
{
|
||||||
uint8_t c = pgm_read_byte(p++);
|
uint8_t c = pgm_read_byte(p++);
|
||||||
if (c == 0) break;
|
if (c == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
n += write(c);
|
n += write(c);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::print(const String &s) {
|
size_t Print::print(const String &s)
|
||||||
|
{
|
||||||
return write(s.c_str(), s.length());
|
return write(s.c_str(), s.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::print(const char str[]) {
|
size_t Print::print(const char str[])
|
||||||
|
{
|
||||||
return write(str);
|
return write(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::print(char c) {
|
size_t Print::print(char c)
|
||||||
|
{
|
||||||
return write(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);
|
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);
|
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);
|
return print((unsigned long) n, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::print(long n, int base) {
|
size_t Print::print(long n, int base)
|
||||||
if(base == 0) {
|
{
|
||||||
|
if (base == 0)
|
||||||
|
{
|
||||||
return write(n);
|
return write(n);
|
||||||
} else if(base == 10) {
|
}
|
||||||
if(n < 0) {
|
else if (base == 10)
|
||||||
|
{
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
int t = print('-');
|
int t = print('-');
|
||||||
n = -n;
|
n = -n;
|
||||||
return printNumber(n, 10) + t;
|
return printNumber(n, 10) + t;
|
||||||
}
|
}
|
||||||
return printNumber(n, 10);
|
return printNumber(n, 10);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return printNumber(n, base);
|
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)
|
{
|
||||||
|
if (base == 0)
|
||||||
|
{
|
||||||
return write(n);
|
return write(n);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return printNumber(n, base);
|
return printNumber(n, base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::print(double n, int digits) {
|
size_t Print::print(double n, int digits)
|
||||||
|
{
|
||||||
return printFloat(n, digits);
|
return printFloat(n, digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(const __FlashStringHelper *ifsh) {
|
size_t Print::println(const __FlashStringHelper *ifsh)
|
||||||
|
{
|
||||||
size_t n = print(ifsh);
|
size_t n = print(ifsh);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::print(const Printable& x) {
|
size_t Print::print(const Printable& x)
|
||||||
|
{
|
||||||
return x.printTo(*this);
|
return x.printTo(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(void) {
|
size_t Print::println(void)
|
||||||
|
{
|
||||||
return print("\r\n");
|
return print("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(const String &s) {
|
size_t Print::println(const String &s)
|
||||||
|
{
|
||||||
size_t n = print(s);
|
size_t n = print(s);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(const char c[]) {
|
size_t Print::println(const char c[])
|
||||||
|
{
|
||||||
size_t n = print(c);
|
size_t n = print(c);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(char c) {
|
size_t Print::println(char c)
|
||||||
|
{
|
||||||
size_t n = print(c);
|
size_t n = print(c);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
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);
|
size_t n = print(b, base);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(int num, int base) {
|
size_t Print::println(int num, int base)
|
||||||
|
{
|
||||||
size_t n = print(num, base);
|
size_t n = print(num, base);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
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);
|
size_t n = print(num, base);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(long num, int base) {
|
size_t Print::println(long num, int base)
|
||||||
|
{
|
||||||
size_t n = print(num, base);
|
size_t n = print(num, base);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
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);
|
size_t n = print(num, base);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(double num, int digits) {
|
size_t Print::println(double num, int digits)
|
||||||
|
{
|
||||||
size_t n = print(num, digits);
|
size_t n = print(num, digits);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Print::println(const Printable& x) {
|
size_t Print::println(const Printable& x)
|
||||||
|
{
|
||||||
size_t n = print(x);
|
size_t n = print(x);
|
||||||
n += println();
|
n += println();
|
||||||
return n;
|
return n;
|
||||||
@ -239,48 +288,64 @@ size_t Print::println(const Printable& x) {
|
|||||||
|
|
||||||
// Private Methods /////////////////////////////////////////////////////////////
|
// 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 buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||||
char *str = &buf[sizeof(buf) - 1];
|
char *str = &buf[sizeof(buf) - 1];
|
||||||
|
|
||||||
*str = '\0';
|
*str = '\0';
|
||||||
|
|
||||||
// prevent crash if called with base == 1
|
// prevent crash if called with base == 1
|
||||||
if(base < 2)
|
if (base < 2)
|
||||||
|
{
|
||||||
base = 10;
|
base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
unsigned long m = n;
|
unsigned long m = n;
|
||||||
n /= base;
|
n /= base;
|
||||||
char c = m - base * n;
|
char c = m - base * n;
|
||||||
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||||
} while(n);
|
} while (n);
|
||||||
|
|
||||||
return write(str);
|
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;
|
size_t n = 0;
|
||||||
|
|
||||||
if(isnan(number))
|
if (isnan(number))
|
||||||
|
{
|
||||||
return print("nan");
|
return print("nan");
|
||||||
if(isinf(number))
|
}
|
||||||
|
if (isinf(number))
|
||||||
|
{
|
||||||
return print("inf");
|
return print("inf");
|
||||||
if(number > 4294967040.0)
|
}
|
||||||
return print("ovf"); // constant determined empirically
|
if (number > 4294967040.0)
|
||||||
if(number < -4294967040.0)
|
{
|
||||||
return print("ovf"); // constant determined empirically
|
return print("ovf"); // constant determined empirically
|
||||||
|
}
|
||||||
|
if (number < -4294967040.0)
|
||||||
|
{
|
||||||
|
return print("ovf"); // constant determined empirically
|
||||||
|
}
|
||||||
|
|
||||||
// Handle negative numbers
|
// Handle negative numbers
|
||||||
if(number < 0.0) {
|
if (number < 0.0)
|
||||||
|
{
|
||||||
n += print('-');
|
n += print('-');
|
||||||
number = -number;
|
number = -number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||||
double rounding = 0.5;
|
double rounding = 0.5;
|
||||||
for(uint8_t i = 0; i < digits; ++i)
|
for (uint8_t i = 0; i < digits; ++i)
|
||||||
|
{
|
||||||
rounding /= 10.0;
|
rounding /= 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
number += rounding;
|
number += rounding;
|
||||||
|
|
||||||
@ -290,12 +355,14 @@ size_t Print::printFloat(double number, uint8_t digits) {
|
|||||||
n += print(int_part);
|
n += print(int_part);
|
||||||
|
|
||||||
// Print the decimal point, but only if there are digits beyond
|
// Print the decimal point, but only if there are digits beyond
|
||||||
if(digits > 0) {
|
if (digits > 0)
|
||||||
|
{
|
||||||
n += print(".");
|
n += print(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract digits from the remainder one at a time
|
// Extract digits from the remainder one at a time
|
||||||
while(digits-- > 0) {
|
while (digits-- > 0)
|
||||||
|
{
|
||||||
remainder *= 10.0;
|
remainder *= 10.0;
|
||||||
int toPrint = int(remainder);
|
int toPrint = int(remainder);
|
||||||
n += print(toPrint);
|
n += print(toPrint);
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
Print.h - Base class that provides print() and println()
|
Print.h - Base class that provides print() and println()
|
||||||
Copyright (c) 2008 David A. Mellis. All right reserved.
|
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef Print_h
|
#ifndef Print_h
|
||||||
#define Print_h
|
#define Print_h
|
||||||
@ -31,73 +31,100 @@
|
|||||||
#define OCT 8
|
#define OCT 8
|
||||||
#define BIN 2
|
#define BIN 2
|
||||||
|
|
||||||
class Print {
|
class Print
|
||||||
private:
|
{
|
||||||
int write_error;
|
private:
|
||||||
size_t printNumber(unsigned long, uint8_t);
|
int write_error;
|
||||||
size_t printFloat(double, uint8_t);
|
size_t printNumber(unsigned long, uint8_t);
|
||||||
protected:
|
size_t printFloat(double, uint8_t);
|
||||||
void setWriteError(int err = 1) {
|
protected:
|
||||||
write_error = err;
|
void setWriteError(int err = 1)
|
||||||
}
|
{
|
||||||
public:
|
write_error = err;
|
||||||
Print() :
|
}
|
||||||
write_error(0) {
|
public:
|
||||||
}
|
Print() :
|
||||||
|
write_error(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int getWriteError() {
|
int getWriteError()
|
||||||
return write_error;
|
{
|
||||||
}
|
return write_error;
|
||||||
void clearWriteError() {
|
}
|
||||||
setWriteError(0);
|
void clearWriteError()
|
||||||
}
|
{
|
||||||
|
setWriteError(0);
|
||||||
|
}
|
||||||
|
|
||||||
virtual size_t write(uint8_t) = 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;
|
if (str == NULL)
|
||||||
return write((const uint8_t *) str, strlen(str));
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
return write((const uint8_t *) str, strlen(str));
|
||||||
size_t write(const char *buffer, size_t size) {
|
}
|
||||||
return write((const uint8_t *) buffer, size);
|
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||||
}
|
size_t write(const char *buffer, size_t 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); }
|
return write((const uint8_t *) buffer, size);
|
||||||
size_t write(unsigned short t) { return write((uint8_t)t); }
|
}
|
||||||
size_t write(int t) { return write((uint8_t)t); }
|
// These handle ambiguity for write(0) case, because (0) can be a pointer or an integer
|
||||||
size_t write(unsigned int t) { return write((uint8_t)t); }
|
size_t write(short t)
|
||||||
size_t write(long t) { return write((uint8_t)t); }
|
{
|
||||||
size_t write(unsigned long t) { return write((uint8_t)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(const char * format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));
|
size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
size_t print(const __FlashStringHelper *);
|
size_t print(const __FlashStringHelper *);
|
||||||
size_t print(const String &);
|
size_t print(const String &);
|
||||||
size_t print(const char[]);
|
size_t print(const char[]);
|
||||||
size_t print(char);
|
size_t print(char);
|
||||||
size_t print(unsigned char, int = DEC);
|
size_t print(unsigned char, int = DEC);
|
||||||
size_t print(int, int = DEC);
|
size_t print(int, int = DEC);
|
||||||
size_t print(unsigned int, int = DEC);
|
size_t print(unsigned int, int = DEC);
|
||||||
size_t print(long, int = DEC);
|
size_t print(long, int = DEC);
|
||||||
size_t print(unsigned long, int = DEC);
|
size_t print(unsigned long, int = DEC);
|
||||||
size_t print(double, int = 2);
|
size_t print(double, int = 2);
|
||||||
size_t print(const Printable&);
|
size_t print(const Printable&);
|
||||||
|
|
||||||
size_t println(const __FlashStringHelper *);
|
size_t println(const __FlashStringHelper *);
|
||||||
size_t println(const String &s);
|
size_t println(const String &s);
|
||||||
size_t println(const char[]);
|
size_t println(const char[]);
|
||||||
size_t println(char);
|
size_t println(char);
|
||||||
size_t println(unsigned char, int = DEC);
|
size_t println(unsigned char, int = DEC);
|
||||||
size_t println(int, int = DEC);
|
size_t println(int, int = DEC);
|
||||||
size_t println(unsigned int, int = DEC);
|
size_t println(unsigned int, int = DEC);
|
||||||
size_t println(long, int = DEC);
|
size_t println(long, int = DEC);
|
||||||
size_t println(unsigned long, int = DEC);
|
size_t println(unsigned long, int = DEC);
|
||||||
size_t println(double, int = 2);
|
size_t println(double, int = 2);
|
||||||
size_t println(const Printable&);
|
size_t println(const Printable&);
|
||||||
size_t println(void);
|
size_t println(void);
|
||||||
|
|
||||||
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
Printable.h - Interface class that allows printing of complex types
|
Printable.h - Interface class that allows printing of complex types
|
||||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef Printable_h
|
#ifndef Printable_h
|
||||||
#define Printable_h
|
#define Printable_h
|
||||||
@ -25,14 +25,15 @@
|
|||||||
class Print;
|
class Print;
|
||||||
|
|
||||||
/** The Printable class provides a way for new classes to allow themselves to be printed.
|
/** The Printable class provides a way for new classes to allow themselves to be printed.
|
||||||
By deriving from Printable and implementing the printTo method, it will then be possible
|
By deriving from Printable and implementing the printTo method, it will then be possible
|
||||||
for users to print out instances of this class by passing them into the usual
|
for users to print out instances of this class by passing them into the usual
|
||||||
Print::print and Print::println methods.
|
Print::print and Print::println methods.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Printable {
|
class Printable
|
||||||
public:
|
{
|
||||||
virtual size_t printTo(Print& p) const = 0;
|
public:
|
||||||
|
virtual size_t printTo(Print& p) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,18 +14,22 @@ static scheduled_fn_t* sLastUnused = 0;
|
|||||||
|
|
||||||
static int sCount = 0;
|
static int sCount = 0;
|
||||||
|
|
||||||
static scheduled_fn_t* get_fn() {
|
static scheduled_fn_t* get_fn()
|
||||||
|
{
|
||||||
scheduled_fn_t* result = NULL;
|
scheduled_fn_t* result = NULL;
|
||||||
// try to get an item from unused items list
|
// try to get an item from unused items list
|
||||||
if (sFirstUnused) {
|
if (sFirstUnused)
|
||||||
|
{
|
||||||
result = sFirstUnused;
|
result = sFirstUnused;
|
||||||
sFirstUnused = result->mNext;
|
sFirstUnused = result->mNext;
|
||||||
if (sFirstUnused == NULL) {
|
if (sFirstUnused == NULL)
|
||||||
|
{
|
||||||
sLastUnused = NULL;
|
sLastUnused = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if no unused items, and count not too high, allocate a new one
|
// 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 = new scheduled_fn_t;
|
||||||
result->mNext = NULL;
|
result->mNext = NULL;
|
||||||
++sCount;
|
++sCount;
|
||||||
@ -35,10 +39,12 @@ static scheduled_fn_t* get_fn() {
|
|||||||
|
|
||||||
static void recycle_fn(scheduled_fn_t* fn)
|
static void recycle_fn(scheduled_fn_t* fn)
|
||||||
{
|
{
|
||||||
if (!sLastUnused) {
|
if (!sLastUnused)
|
||||||
|
{
|
||||||
sFirstUnused = fn;
|
sFirstUnused = fn;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
sLastUnused->mNext = fn;
|
sLastUnused->mNext = fn;
|
||||||
}
|
}
|
||||||
fn->mNext = NULL;
|
fn->mNext = NULL;
|
||||||
@ -48,15 +54,18 @@ static void recycle_fn(scheduled_fn_t* fn)
|
|||||||
bool schedule_function(std::function<void(void)> fn)
|
bool schedule_function(std::function<void(void)> fn)
|
||||||
{
|
{
|
||||||
scheduled_fn_t* item = get_fn();
|
scheduled_fn_t* item = get_fn();
|
||||||
if (!item) {
|
if (!item)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
item->mFunc = fn;
|
item->mFunc = fn;
|
||||||
item->mNext = NULL;
|
item->mNext = NULL;
|
||||||
if (!sFirst) {
|
if (!sFirst)
|
||||||
|
{
|
||||||
sFirst = item;
|
sFirst = item;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
sLast->mNext = item;
|
sLast->mNext = item;
|
||||||
}
|
}
|
||||||
sLast = item;
|
sLast = item;
|
||||||
@ -65,10 +74,11 @@ bool schedule_function(std::function<void(void)> fn)
|
|||||||
|
|
||||||
void run_scheduled_functions()
|
void run_scheduled_functions()
|
||||||
{
|
{
|
||||||
scheduled_fn_t* rFirst = sFirst;
|
scheduled_fn_t* rFirst = sFirst;
|
||||||
sFirst = NULL;
|
sFirst = NULL;
|
||||||
sLast = NULL;
|
sLast = NULL;
|
||||||
while (rFirst) {
|
while (rFirst)
|
||||||
|
{
|
||||||
scheduled_fn_t* item = rFirst;
|
scheduled_fn_t* item = rFirst;
|
||||||
rFirst = item->mNext;
|
rFirst = item->mNext;
|
||||||
item->mFunc();
|
item->mFunc();
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
#define SCHEDULED_FN_MAX_COUNT 32
|
#define SCHEDULED_FN_MAX_COUNT 32
|
||||||
#define SCHEDULED_FN_INITIAL_COUNT 4
|
#define SCHEDULED_FN_INITIAL_COUNT 4
|
||||||
|
|
||||||
// Warning
|
// Warning
|
||||||
// This API is not considered stable.
|
// This API is not considered stable.
|
||||||
// Function signatures will change.
|
// Function signatures will change.
|
||||||
// You have been warned.
|
// You have been warned.
|
||||||
|
|
||||||
// Run given function next time `loop` function returns,
|
// Run given function next time `loop` function returns,
|
||||||
// or `run_scheduled_functions` is called.
|
// or `run_scheduled_functions` is called.
|
||||||
// Use std::bind to pass arguments to a function, or call a class member function.
|
// Use std::bind to pass arguments to a function, or call a class member function.
|
||||||
// Note: there is no mechanism for cancelling scheduled functions.
|
// Note: there is no mechanism for cancelling scheduled functions.
|
||||||
@ -19,7 +19,7 @@
|
|||||||
// Returns false if the number of scheduled functions exceeds SCHEDULED_FN_MAX_COUNT.
|
// Returns false if the number of scheduled functions exceeds SCHEDULED_FN_MAX_COUNT.
|
||||||
bool schedule_function(std::function<void(void)> fn);
|
bool schedule_function(std::function<void(void)> fn);
|
||||||
|
|
||||||
// Run all scheduled functions.
|
// Run all scheduled functions.
|
||||||
// Use this function if your are not using `loop`, or `loop` does not return
|
// Use this function if your are not using `loop`, or `loop` does not return
|
||||||
// on a regular basis.
|
// on a regular basis.
|
||||||
void run_scheduled_functions();
|
void run_scheduled_functions();
|
||||||
|
@ -1,117 +1,118 @@
|
|||||||
/*
|
/*
|
||||||
* ScheduledFunctions.cpp
|
ScheduledFunctions.cpp
|
||||||
*
|
|
||||||
* Created on: 27 apr. 2018
|
Created on: 27 apr. 2018
|
||||||
* Author: Herman
|
Author: Herman
|
||||||
*/
|
*/
|
||||||
#include "ScheduledFunctions.h"
|
#include "ScheduledFunctions.h"
|
||||||
|
|
||||||
std::list<ScheduledFunctions::ScheduledElement> ScheduledFunctions::scheduledFunctions;
|
std::list<ScheduledFunctions::ScheduledElement> ScheduledFunctions::scheduledFunctions;
|
||||||
|
|
||||||
ScheduledFunctions::ScheduledFunctions()
|
ScheduledFunctions::ScheduledFunctions()
|
||||||
:ScheduledFunctions(UINT_MAX)
|
: ScheduledFunctions(UINT_MAX)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduledFunctions::ScheduledFunctions(unsigned int reqMax)
|
ScheduledFunctions::ScheduledFunctions(unsigned int reqMax)
|
||||||
{
|
{
|
||||||
maxElements = reqMax;
|
maxElements = reqMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduledFunctions::~ScheduledFunctions() {
|
ScheduledFunctions::~ScheduledFunctions()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front)
|
ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front)
|
||||||
{
|
{
|
||||||
if (countElements >= maxElements)
|
if (countElements >= maxElements)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
countElements++;
|
countElements++;
|
||||||
if (front)
|
if (front)
|
||||||
{
|
{
|
||||||
scheduledFunctions.push_front(se);
|
scheduledFunctions.push_front(se);
|
||||||
return scheduledFunctions.begin()->registration;
|
return scheduledFunctions.begin()->registration;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
scheduledFunctions.push_back(se);
|
scheduledFunctions.push_back(se);
|
||||||
return scheduledFunctions.rbegin()->registration;
|
return scheduledFunctions.rbegin()->registration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<ScheduledFunctions::ScheduledElement>::iterator ScheduledFunctions::eraseElement(std::list<ScheduledFunctions::ScheduledElement>::iterator it)
|
std::list<ScheduledFunctions::ScheduledElement>::iterator ScheduledFunctions::eraseElement(std::list<ScheduledFunctions::ScheduledElement>::iterator it)
|
||||||
{
|
{
|
||||||
countElements--;
|
countElements--;
|
||||||
return scheduledFunctions.erase(it);
|
return scheduledFunctions.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front)
|
bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front)
|
||||||
{
|
{
|
||||||
return (insertElement({this,continuous,nullptr,sf}, front) == nullptr);
|
return (insertElement({this, continuous, nullptr, sf}, front) == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf)
|
bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf)
|
||||||
{
|
{
|
||||||
return scheduleFunction(sf, false, false);
|
return scheduleFunction(sf, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front)
|
ScheduledRegistration ScheduledFunctions::scheduleFunctionReg(ScheduledFunction sf, bool continuous, bool front)
|
||||||
{
|
{
|
||||||
return insertElement({this,continuous,std::make_shared<int>(1),sf},front);
|
return insertElement({this, continuous, std::make_shared<int>(1), sf}, front);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledFunctions::runScheduledFunctions()
|
void ScheduledFunctions::runScheduledFunctions()
|
||||||
{
|
{
|
||||||
auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions
|
auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions
|
||||||
auto it = scheduledFunctions.begin();
|
auto it = scheduledFunctions.begin();
|
||||||
while (it != lastElement)
|
while (it != lastElement)
|
||||||
{
|
{
|
||||||
bool erase = false;
|
bool erase = false;
|
||||||
if (it->registration == nullptr)
|
if (it->registration == nullptr)
|
||||||
{
|
{
|
||||||
it->function();
|
it->function();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (it->registration.use_count() > 1)
|
if (it->registration.use_count() > 1)
|
||||||
{
|
{
|
||||||
it->function();
|
it->function();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
erase = true;
|
erase = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((!it->continuous) || (erase))
|
if ((!it->continuous) || (erase))
|
||||||
{
|
{
|
||||||
it = it->_this->eraseElement(it);
|
it = it->_this->eraseElement(it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledFunctions::removeFunction(ScheduledRegistration sr)
|
void ScheduledFunctions::removeFunction(ScheduledRegistration sr)
|
||||||
{
|
{
|
||||||
auto it = scheduledFunctions.begin();
|
auto it = scheduledFunctions.begin();
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
while ((!removed) && (it != scheduledFunctions.end()))
|
while ((!removed) && (it != scheduledFunctions.end()))
|
||||||
{
|
{
|
||||||
if (it->registration == sr)
|
if (it->registration == sr)
|
||||||
{
|
{
|
||||||
it = eraseElement(it);
|
it = eraseElement(it);
|
||||||
removed = true;
|
removed = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* ScheduledFunctions.h
|
ScheduledFunctions.h
|
||||||
*
|
|
||||||
* Created on: 27 apr. 2018
|
Created on: 27 apr. 2018
|
||||||
* Author: Herman
|
Author: Herman
|
||||||
*/
|
*/
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "Schedule.h"
|
#include "Schedule.h"
|
||||||
|
|
||||||
@ -18,33 +18,34 @@
|
|||||||
typedef std::function<void(void)> ScheduledFunction;
|
typedef std::function<void(void)> ScheduledFunction;
|
||||||
typedef std::shared_ptr<void> ScheduledRegistration;
|
typedef std::shared_ptr<void> ScheduledRegistration;
|
||||||
|
|
||||||
class ScheduledFunctions {
|
class ScheduledFunctions
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScheduledFunctions();
|
ScheduledFunctions();
|
||||||
ScheduledFunctions(unsigned int reqMax);
|
ScheduledFunctions(unsigned int reqMax);
|
||||||
virtual ~ScheduledFunctions();
|
virtual ~ScheduledFunctions();
|
||||||
|
|
||||||
struct ScheduledElement
|
struct ScheduledElement
|
||||||
{
|
{
|
||||||
ScheduledFunctions* _this;
|
ScheduledFunctions* _this;
|
||||||
bool continuous;
|
bool continuous;
|
||||||
ScheduledRegistration registration;
|
ScheduledRegistration registration;
|
||||||
ScheduledFunction function;
|
ScheduledFunction function;
|
||||||
};
|
};
|
||||||
|
|
||||||
ScheduledRegistration insertElement(ScheduledElement se, bool front);
|
ScheduledRegistration insertElement(ScheduledElement se, bool front);
|
||||||
std::list<ScheduledElement>::iterator eraseElement(std::list<ScheduledElement>::iterator);
|
std::list<ScheduledElement>::iterator eraseElement(std::list<ScheduledElement>::iterator);
|
||||||
bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front);
|
bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front);
|
||||||
bool scheduleFunction(ScheduledFunction sf);
|
bool scheduleFunction(ScheduledFunction sf);
|
||||||
ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front);
|
ScheduledRegistration scheduleFunctionReg(ScheduledFunction sf, bool continuous, bool front);
|
||||||
static void runScheduledFunctions();
|
static void runScheduledFunctions();
|
||||||
void removeFunction(ScheduledRegistration sr);
|
void removeFunction(ScheduledRegistration sr);
|
||||||
|
|
||||||
|
|
||||||
static std::list<ScheduledElement> scheduledFunctions;
|
static std::list<ScheduledElement> scheduledFunctions;
|
||||||
unsigned int maxElements;
|
unsigned int maxElements;
|
||||||
unsigned int countElements = 0;
|
unsigned int countElements = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,30 +1,31 @@
|
|||||||
/*
|
/*
|
||||||
Server.h - Base class that provides Server
|
Server.h - Base class that provides Server
|
||||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef server_h
|
#ifndef server_h
|
||||||
#define server_h
|
#define server_h
|
||||||
|
|
||||||
#include "Print.h"
|
#include "Print.h"
|
||||||
|
|
||||||
class Server: public Print {
|
class Server: public Print
|
||||||
public:
|
{
|
||||||
virtual void begin() =0;
|
public:
|
||||||
|
virtual void begin() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
StackThunk.c - Allow use second stack for BearSSL calls
|
StackThunk.c - Allow use second stack for BearSSL calls
|
||||||
|
|
||||||
BearSSL uses a significant amount of stack space, much larger than
|
BearSSL uses a significant amount of stack space, much larger than
|
||||||
the default Arduino core stack. These routines handle swapping
|
the default Arduino core stack. These routines handle swapping
|
||||||
between a secondary, user-allocated stack on the heap and the real
|
between a secondary, user-allocated stack on the heap and the real
|
||||||
stack.
|
stack.
|
||||||
|
|
||||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -31,97 +31,111 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
uint32_t *stack_thunk_ptr = NULL;
|
uint32_t *stack_thunk_ptr = NULL;
|
||||||
uint32_t *stack_thunk_top = NULL;
|
uint32_t *stack_thunk_top = NULL;
|
||||||
uint32_t *stack_thunk_save = NULL; /* Saved A1 while in BearSSL */
|
uint32_t *stack_thunk_save = NULL; /* Saved A1 while in BearSSL */
|
||||||
uint32_t stack_thunk_refcnt = 0;
|
uint32_t stack_thunk_refcnt = 0;
|
||||||
|
|
||||||
#define _stackSize (5600/4)
|
#define _stackSize (5600/4)
|
||||||
#define _stackPaint 0xdeadbeef
|
#define _stackPaint 0xdeadbeef
|
||||||
|
|
||||||
/* Add a reference, and allocate the stack if necessary */
|
/* Add a reference, and allocate the stack if necessary */
|
||||||
void stack_thunk_add_ref()
|
void stack_thunk_add_ref()
|
||||||
{
|
{
|
||||||
stack_thunk_refcnt++;
|
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_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
|
||||||
stack_thunk_save = NULL;
|
stack_thunk_top = stack_thunk_ptr + _stackSize - 1;
|
||||||
stack_thunk_repaint();
|
stack_thunk_save = NULL;
|
||||||
}
|
stack_thunk_repaint();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Drop a reference, and free stack if no more in use */
|
/* Drop a reference, and free stack if no more in use */
|
||||||
void stack_thunk_del_ref()
|
void stack_thunk_del_ref()
|
||||||
{
|
{
|
||||||
if (stack_thunk_refcnt == 0) {
|
if (stack_thunk_refcnt == 0)
|
||||||
/* Error! */
|
{
|
||||||
return;
|
/* Error! */
|
||||||
}
|
return;
|
||||||
stack_thunk_refcnt--;
|
}
|
||||||
if (!stack_thunk_refcnt) {
|
stack_thunk_refcnt--;
|
||||||
free(stack_thunk_ptr);
|
if (!stack_thunk_refcnt)
|
||||||
stack_thunk_ptr = NULL;
|
{
|
||||||
stack_thunk_top = NULL;
|
free(stack_thunk_ptr);
|
||||||
stack_thunk_save = NULL;
|
stack_thunk_ptr = NULL;
|
||||||
}
|
stack_thunk_top = NULL;
|
||||||
}
|
stack_thunk_save = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void stack_thunk_repaint()
|
void stack_thunk_repaint()
|
||||||
{
|
{
|
||||||
for (int i=0; i < _stackSize; i++) {
|
for (int i = 0; i < _stackSize; i++)
|
||||||
stack_thunk_ptr[i] = _stackPaint;
|
{
|
||||||
}
|
stack_thunk_ptr[i] = _stackPaint;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Simple accessor functions used by postmortem */
|
/* Simple accessor functions used by postmortem */
|
||||||
uint32_t stack_thunk_get_refcnt() {
|
uint32_t stack_thunk_get_refcnt()
|
||||||
return stack_thunk_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;
|
{
|
||||||
}
|
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;
|
{
|
||||||
}
|
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;
|
{
|
||||||
}
|
return (uint32_t)stack_thunk_save;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the number of bytes ever used since the stack was created */
|
/* Return the number of bytes ever used since the stack was created */
|
||||||
uint32_t stack_thunk_get_max_usage()
|
uint32_t stack_thunk_get_max_usage()
|
||||||
{
|
{
|
||||||
uint32_t cnt = 0;
|
uint32_t cnt = 0;
|
||||||
|
|
||||||
/* No stack == no usage by definition! */
|
/* No stack == no usage by definition! */
|
||||||
if (!stack_thunk_ptr) {
|
if (!stack_thunk_ptr)
|
||||||
return 0;
|
{
|
||||||
}
|
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() */
|
{
|
||||||
}
|
/* Noop, all work done in for() */
|
||||||
return 4 * (_stackSize - cnt);
|
}
|
||||||
}
|
return 4 * (_stackSize - cnt);
|
||||||
|
}
|
||||||
|
|
||||||
/* Print the stack from the first used 16-byte chunk to the top, decodable by the exception decoder */
|
/* Print the stack from the first used 16-byte chunk to the top, decodable by the exception decoder */
|
||||||
void stack_thunk_dump_stack()
|
void stack_thunk_dump_stack()
|
||||||
{
|
{
|
||||||
uint32_t *pos = stack_thunk_top;
|
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;
|
if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint))
|
||||||
pos += 4;
|
{
|
||||||
}
|
break;
|
||||||
ets_printf(">>>stack>>>\n");
|
}
|
||||||
while (pos < stack_thunk_ptr) {
|
pos += 4;
|
||||||
ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]);
|
}
|
||||||
pos += 4;
|
ets_printf(">>>stack>>>\n");
|
||||||
}
|
while (pos < stack_thunk_ptr)
|
||||||
ets_printf("<<<stack<<<\n");
|
{
|
||||||
}
|
ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]);
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
ets_printf("<<<stack<<<\n");
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
StackThunk.h - Allow use second stack for BearSSL calls
|
StackThunk.h - Allow use second stack for BearSSL calls
|
||||||
|
|
||||||
BearSSL uses a significant amount of stack space, much larger than
|
BearSSL uses a significant amount of stack space, much larger than
|
||||||
the default Arduino core stack. These routines handle swapping
|
the default Arduino core stack. These routines handle swapping
|
||||||
between a secondary, user-allocated stack on the heap and the real
|
between a secondary, user-allocated stack on the heap and the real
|
||||||
stack.
|
stack.
|
||||||
|
|
||||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _STACKTHUNK_H
|
#ifndef _STACKTHUNK_H
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
Stream.cpp - adds parsing methods to Stream class
|
Stream.cpp - adds parsing methods to Stream class
|
||||||
Copyright (c) 2008 David A. Mellis. All right reserved.
|
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
Created July 2011
|
Created July 2011
|
||||||
parsing functions based on TextFinder library by Michael Margolis
|
parsing functions based on TextFinder library by Michael Margolis
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
@ -26,43 +26,59 @@
|
|||||||
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
||||||
|
|
||||||
// private method to read stream with timeout
|
// private method to read stream with timeout
|
||||||
int Stream::timedRead() {
|
int Stream::timedRead()
|
||||||
|
{
|
||||||
int c;
|
int c;
|
||||||
_startMillis = millis();
|
_startMillis = millis();
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
c = read();
|
c = read();
|
||||||
if(c >= 0)
|
if (c >= 0)
|
||||||
|
{
|
||||||
return c;
|
return c;
|
||||||
|
}
|
||||||
yield();
|
yield();
|
||||||
} while(millis() - _startMillis < _timeout);
|
} while (millis() - _startMillis < _timeout);
|
||||||
return -1; // -1 indicates timeout
|
return -1; // -1 indicates timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// private method to peek stream with timeout
|
// private method to peek stream with timeout
|
||||||
int Stream::timedPeek() {
|
int Stream::timedPeek()
|
||||||
|
{
|
||||||
int c;
|
int c;
|
||||||
_startMillis = millis();
|
_startMillis = millis();
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
c = peek();
|
c = peek();
|
||||||
if(c >= 0)
|
if (c >= 0)
|
||||||
|
{
|
||||||
return c;
|
return c;
|
||||||
|
}
|
||||||
yield();
|
yield();
|
||||||
} while(millis() - _startMillis < _timeout);
|
} while (millis() - _startMillis < _timeout);
|
||||||
return -1; // -1 indicates timeout
|
return -1; // -1 indicates timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns peek of the next digit in the stream or -1 if timeout
|
// returns peek of the next digit in the stream or -1 if timeout
|
||||||
// discards non-numeric characters
|
// discards non-numeric characters
|
||||||
int Stream::peekNextDigit() {
|
int Stream::peekNextDigit()
|
||||||
|
{
|
||||||
int c;
|
int c;
|
||||||
while(1) {
|
while (1)
|
||||||
|
{
|
||||||
c = timedPeek();
|
c = timedPeek();
|
||||||
if(c < 0)
|
if (c < 0)
|
||||||
return c; // timeout
|
{
|
||||||
if(c == '-')
|
return c; // timeout
|
||||||
|
}
|
||||||
|
if (c == '-')
|
||||||
|
{
|
||||||
return c;
|
return c;
|
||||||
if(c >= '0' && c <= '9')
|
}
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
return c;
|
return c;
|
||||||
|
}
|
||||||
read(); // discard non-numeric
|
read(); // discard non-numeric
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,48 +92,65 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find returns true if the target string is found
|
// 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*) "");
|
return findUntil(target, (char*) "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads data from the stream until the target string of given length is found
|
// 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
|
// 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);
|
return findUntil(target, length, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// as find but search ends if the terminator string is found
|
// 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));
|
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads data from the stream until the target string of the given length is found
|
// reads data from the stream until the target string of the given length is found
|
||||||
// search terminated if the terminator string is found
|
// search terminated if the terminator string is found
|
||||||
// returns true if target string is found, false if terminated or timed out
|
// 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 index = 0; // maximum target string length is 64k bytes!
|
||||||
size_t termIndex = 0;
|
size_t termIndex = 0;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if(*target == 0)
|
if (*target == 0)
|
||||||
return true; // return true if target is a null string
|
{
|
||||||
while((c = timedRead()) > 0) {
|
return true; // return true if target is a null string
|
||||||
|
}
|
||||||
|
while ((c = timedRead()) > 0)
|
||||||
|
{
|
||||||
|
|
||||||
if(c != target[index])
|
if (c != target[index])
|
||||||
index = 0; // reset index if any char does not match
|
{
|
||||||
|
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);
|
//////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;
|
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
|
if (++termIndex >= termLen)
|
||||||
} else
|
{
|
||||||
|
return false; // return false if terminate string found before target string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
termIndex = 0;
|
termIndex = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -125,46 +158,59 @@ bool Stream::findUntil(const char *target, size_t targetLen, const char *termina
|
|||||||
// returns the first valid (long) integer value from the current position.
|
// returns the first valid (long) integer value from the current position.
|
||||||
// initial characters that are not digits (or the minus sign) are skipped
|
// initial characters that are not digits (or the minus sign) are skipped
|
||||||
// function is terminated by the first character that is not a digit.
|
// 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)
|
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// as above but a given skipChar is ignored
|
// as above but a given skipChar is ignored
|
||||||
// this allows format characters (typically commas) in values to be 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;
|
boolean isNegative = false;
|
||||||
long value = 0;
|
long value = 0;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
c = peekNextDigit();
|
c = peekNextDigit();
|
||||||
// ignore non numeric leading characters
|
// ignore non numeric leading characters
|
||||||
if(c < 0)
|
if (c < 0)
|
||||||
return 0; // zero returned if timeout
|
{
|
||||||
|
return 0; // zero returned if timeout
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do
|
||||||
if(c == skipChar)
|
{
|
||||||
|
if (c == skipChar)
|
||||||
; // ignore this charactor
|
; // ignore this charactor
|
||||||
else if(c == '-')
|
else if (c == '-')
|
||||||
|
{
|
||||||
isNegative = true;
|
isNegative = 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';
|
value = value * 10 + c - '0';
|
||||||
|
}
|
||||||
read(); // consume the character we got with peek
|
read(); // consume the character we got with peek
|
||||||
c = timedPeek();
|
c = timedPeek();
|
||||||
} while((c >= '0' && c <= '9') || c == skipChar);
|
} while ((c >= '0' && c <= '9') || c == skipChar);
|
||||||
|
|
||||||
if(isNegative)
|
if (isNegative)
|
||||||
|
{
|
||||||
value = -value;
|
value = -value;
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// as parseInt but returns a floating point value
|
// as parseInt but returns a floating point value
|
||||||
float Stream::parseFloat() {
|
float Stream::parseFloat()
|
||||||
|
{
|
||||||
return parseFloat(NO_SKIP_CHAR);
|
return parseFloat(NO_SKIP_CHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// as above but the given skipChar is ignored
|
// as above but the given skipChar is ignored
|
||||||
// this allows format characters (typically commas) in values to be 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 isNegative = false;
|
||||||
boolean isFraction = false;
|
boolean isFraction = false;
|
||||||
long value = 0;
|
long value = 0;
|
||||||
@ -173,31 +219,47 @@ float Stream::parseFloat(char skipChar) {
|
|||||||
|
|
||||||
c = peekNextDigit();
|
c = peekNextDigit();
|
||||||
// ignore non numeric leading characters
|
// ignore non numeric leading characters
|
||||||
if(c < 0)
|
if (c < 0)
|
||||||
return 0; // zero returned if timeout
|
{
|
||||||
|
return 0; // zero returned if timeout
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do
|
||||||
if(c == skipChar)
|
{
|
||||||
|
if (c == skipChar)
|
||||||
; // ignore
|
; // ignore
|
||||||
else if(c == '-')
|
else if (c == '-')
|
||||||
|
{
|
||||||
isNegative = true;
|
isNegative = true;
|
||||||
else if(c == '.')
|
}
|
||||||
|
else if (c == '.')
|
||||||
|
{
|
||||||
isFraction = true;
|
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';
|
value = value * 10 + c - '0';
|
||||||
if(isFraction)
|
if (isFraction)
|
||||||
|
{
|
||||||
fraction *= 0.1;
|
fraction *= 0.1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
read(); // consume the character we got with peek
|
read(); // consume the character we got with peek
|
||||||
c = timedPeek();
|
c = timedPeek();
|
||||||
} while((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
} while ((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
||||||
|
|
||||||
if(isNegative)
|
if (isNegative)
|
||||||
|
{
|
||||||
value = -value;
|
value = -value;
|
||||||
if(isFraction)
|
}
|
||||||
|
if (isFraction)
|
||||||
|
{
|
||||||
return value * fraction;
|
return value * fraction;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return value;
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read characters from stream into buffer
|
// read characters from stream into buffer
|
||||||
@ -205,12 +267,16 @@ float Stream::parseFloat(char skipChar) {
|
|||||||
// returns the number of characters placed in the buffer
|
// returns the number of characters placed in the buffer
|
||||||
// the buffer is NOT null terminated.
|
// 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;
|
size_t count = 0;
|
||||||
while(count < length) {
|
while (count < length)
|
||||||
|
{
|
||||||
int c = timedRead();
|
int c = timedRead();
|
||||||
if(c < 0)
|
if (c < 0)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
*buffer++ = (char) c;
|
*buffer++ = (char) c;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -221,34 +287,44 @@ size_t Stream::readBytes(char *buffer, size_t length) {
|
|||||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
// 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)
|
// 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)
|
{
|
||||||
|
if (length < 1)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
while(index < length) {
|
while (index < length)
|
||||||
|
{
|
||||||
int c = timedRead();
|
int c = timedRead();
|
||||||
if(c < 0 || c == terminator)
|
if (c < 0 || c == terminator)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
*buffer++ = (char) c;
|
*buffer++ = (char) c;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
return index; // return number of characters, not including null terminator
|
return index; // return number of characters, not including null terminator
|
||||||
}
|
}
|
||||||
|
|
||||||
String Stream::readString() {
|
String Stream::readString()
|
||||||
|
{
|
||||||
String ret;
|
String ret;
|
||||||
int c = timedRead();
|
int c = timedRead();
|
||||||
while(c >= 0) {
|
while (c >= 0)
|
||||||
|
{
|
||||||
ret += (char) c;
|
ret += (char) c;
|
||||||
c = timedRead();
|
c = timedRead();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
String Stream::readStringUntil(char terminator) {
|
String Stream::readStringUntil(char terminator)
|
||||||
|
{
|
||||||
String ret;
|
String ret;
|
||||||
int c = timedRead();
|
int c = timedRead();
|
||||||
while(c >= 0 && c != terminator) {
|
while (c >= 0 && c != terminator)
|
||||||
|
{
|
||||||
ret += (char) c;
|
ret += (char) c;
|
||||||
c = timedRead();
|
c = timedRead();
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
Stream.h - base class for character-based streams.
|
Stream.h - base class for character-based streams.
|
||||||
Copyright (c) 2010 David A. Mellis. All right reserved.
|
Copyright (c) 2010 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
parsing functions based on TextFinder library by Michael Margolis
|
parsing functions based on TextFinder library by Michael Margolis
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef Stream_h
|
#ifndef Stream_h
|
||||||
#define Stream_h
|
#define Stream_h
|
||||||
@ -27,89 +27,100 @@
|
|||||||
|
|
||||||
// compatability macros for testing
|
// compatability macros for testing
|
||||||
/*
|
/*
|
||||||
#define getInt() parseInt()
|
#define getInt() parseInt()
|
||||||
#define getInt(skipChar) parseInt(skipchar)
|
#define getInt(skipChar) parseInt(skipchar)
|
||||||
#define getFloat() parseFloat()
|
#define getFloat() parseFloat()
|
||||||
#define getFloat(skipChar) parseFloat(skipChar)
|
#define getFloat(skipChar) parseFloat(skipChar)
|
||||||
#define getString( pre_string, post_string, buffer, length)
|
#define getString( pre_string, post_string, buffer, length)
|
||||||
readBytesBetween( pre_string, terminator, buffer, length)
|
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
|
protected:
|
||||||
unsigned long _startMillis; // used for timeout measurement
|
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||||
int timedRead(); // private method to read stream with timeout
|
unsigned long _startMillis; // used for timeout measurement
|
||||||
int timedPeek(); // private method to peek stream with timeout
|
int timedRead(); // private method to read stream with timeout
|
||||||
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
|
int timedPeek(); // private method to peek stream with timeout
|
||||||
|
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int available() = 0;
|
virtual int available() = 0;
|
||||||
virtual int read() = 0;
|
virtual int read() = 0;
|
||||||
virtual int peek() = 0;
|
virtual int peek() = 0;
|
||||||
|
|
||||||
Stream() {
|
Stream()
|
||||||
_timeout = 1000;
|
{
|
||||||
}
|
_timeout = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
// parsing methods
|
// parsing methods
|
||||||
|
|
||||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
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(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);
|
{
|
||||||
}
|
return find((char *) target);
|
||||||
// returns true if target string is found, false if timed out (see setTimeout)
|
}
|
||||||
|
// 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 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);
|
{
|
||||||
}
|
return find((char *) target, length);
|
||||||
// returns true if target string is found, false if timed out
|
}
|
||||||
|
// 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 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);
|
{
|
||||||
}
|
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 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);
|
{
|
||||||
}
|
return findUntil((char *) target, targetLen, terminate, termLen);
|
||||||
|
}
|
||||||
|
|
||||||
long parseInt(); // returns the first valid (long) integer value from the current position.
|
long parseInt(); // returns the first valid (long) integer value from the current position.
|
||||||
// initial characters that are not digits (or the minus sign) are skipped
|
// initial characters that are not digits (or the minus sign) are skipped
|
||||||
// integer is terminated by the first character that is not a digit.
|
// integer is terminated by the first character that is not a digit.
|
||||||
|
|
||||||
float parseFloat(); // float version of parseInt
|
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(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);
|
{
|
||||||
}
|
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)
|
// 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, 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);
|
{
|
||||||
}
|
return readBytesUntil(terminator, (char *) buffer, 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)
|
// 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)
|
||||||
|
|
||||||
// Arduino String functions to be added here
|
// Arduino String functions to be added here
|
||||||
virtual String readString();
|
virtual String readString();
|
||||||
String readStringUntil(char terminator);
|
String readStringUntil(char terminator);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
long parseInt(char skipChar); // as above but the given skipChar is ignored
|
long parseInt(char skipChar); // as above but the given skipChar is ignored
|
||||||
// as above but the given skipChar is ignored
|
// as above but the given skipChar is ignored
|
||||||
// this allows format characters (typically commas) in values to be ignored
|
// this allows format characters (typically commas) in values to be ignored
|
||||||
|
|
||||||
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,33 +1,36 @@
|
|||||||
/**
|
/**
|
||||||
StreamString.cpp
|
StreamString.cpp
|
||||||
|
|
||||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "StreamString.h"
|
#include "StreamString.h"
|
||||||
|
|
||||||
size_t StreamString::write(const uint8_t *data, size_t size) {
|
size_t StreamString::write(const uint8_t *data, size_t size)
|
||||||
if(size && data) {
|
{
|
||||||
|
if (size && data)
|
||||||
|
{
|
||||||
const unsigned int newlen = length() + size;
|
const unsigned int newlen = length() + size;
|
||||||
if(reserve(newlen + 1)) {
|
if (reserve(newlen + 1))
|
||||||
memcpy((void *) (wbuffer() + len()), (const void *) data, size);
|
{
|
||||||
|
memcpy((void *)(wbuffer() + len()), (const void *) data, size);
|
||||||
setLen(newlen);
|
setLen(newlen);
|
||||||
*(wbuffer() + newlen) = 0x00; // add null for string end
|
*(wbuffer() + newlen) = 0x00; // add null for string end
|
||||||
return size;
|
return size;
|
||||||
@ -36,16 +39,20 @@ size_t StreamString::write(const uint8_t *data, size_t size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t StreamString::write(uint8_t data) {
|
size_t StreamString::write(uint8_t data)
|
||||||
|
{
|
||||||
return concat((char) data);
|
return concat((char) data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamString::available() {
|
int StreamString::available()
|
||||||
|
{
|
||||||
return length();
|
return length();
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamString::read() {
|
int StreamString::read()
|
||||||
if(length()) {
|
{
|
||||||
|
if (length())
|
||||||
|
{
|
||||||
char c = charAt(0);
|
char c = charAt(0);
|
||||||
remove(0, 1);
|
remove(0, 1);
|
||||||
return c;
|
return c;
|
||||||
@ -54,14 +61,17 @@ int StreamString::read() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamString::peek() {
|
int StreamString::peek()
|
||||||
if(length()) {
|
{
|
||||||
|
if (length())
|
||||||
|
{
|
||||||
char c = charAt(0);
|
char c = charAt(0);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamString::flush() {
|
void StreamString::flush()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,39 +1,40 @@
|
|||||||
/**
|
/**
|
||||||
StreamString.h
|
StreamString.h
|
||||||
|
|
||||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef STREAMSTRING_H_
|
#ifndef STREAMSTRING_H_
|
||||||
#define STREAMSTRING_H_
|
#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;
|
public:
|
||||||
size_t write(uint8_t data) override;
|
size_t write(const uint8_t *buffer, size_t size) override;
|
||||||
|
size_t write(uint8_t data) override;
|
||||||
int available() override;
|
|
||||||
int read() override;
|
int available() override;
|
||||||
int peek() override;
|
int read() override;
|
||||||
void flush() override;
|
int peek() override;
|
||||||
};
|
void flush() override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* STREAMSTRING_H_ */
|
|
||||||
|
#endif /* STREAMSTRING_H_ */
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
Tone.cpp
|
Tone.cpp
|
||||||
|
|
||||||
A Tone Generator Library for the ESP8266
|
A Tone Generator Library for the ESP8266
|
||||||
|
|
||||||
Original Copyright (c) 2016 Ben Pirt. All rights reserved.
|
Original Copyright (c) 2016 Ben Pirt. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
@ -28,60 +28,74 @@
|
|||||||
static uint32_t _toneMap = 0;
|
static uint32_t _toneMap = 0;
|
||||||
|
|
||||||
|
|
||||||
static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long duration) {
|
static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long duration)
|
||||||
if (_pin > 16) {
|
{
|
||||||
return;
|
if (_pin > 16)
|
||||||
}
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pinMode(_pin, OUTPUT);
|
pinMode(_pin, OUTPUT);
|
||||||
|
|
||||||
high = std::max(high, (uint32_t)100);
|
high = std::max(high, (uint32_t)100);
|
||||||
low = std::max(low, (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;
|
{
|
||||||
}
|
_toneMap |= 1 << _pin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
|
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
|
||||||
if (frequency == 0) {
|
{
|
||||||
noTone(_pin);
|
if (frequency == 0)
|
||||||
} else {
|
{
|
||||||
uint32_t period = 1000000L / frequency;
|
noTone(_pin);
|
||||||
uint32_t high = period / 2;
|
}
|
||||||
uint32_t low = period - high;
|
else
|
||||||
_startTone(_pin, high, low, duration);
|
{
|
||||||
}
|
uint32_t period = 1000000L / frequency;
|
||||||
|
uint32_t high = period / 2;
|
||||||
|
uint32_t low = period - high;
|
||||||
|
_startTone(_pin, high, low, duration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Separate tone(float) to hopefully not pull in floating point libs unless
|
// Separate tone(float) to hopefully not pull in floating point libs unless
|
||||||
// it's called with a float.
|
// it's called with a float.
|
||||||
void tone(uint8_t _pin, double frequency, unsigned long duration) {
|
void tone(uint8_t _pin, double frequency, unsigned long duration)
|
||||||
if (frequency < 1.0) { // FP means no exact comparisons
|
{
|
||||||
noTone(_pin);
|
if (frequency < 1.0) // FP means no exact comparisons
|
||||||
} else {
|
{
|
||||||
double period = 1000000.0 / frequency;
|
noTone(_pin);
|
||||||
uint32_t high = (uint32_t)((period / 2.0) + 0.5);
|
}
|
||||||
uint32_t low = (uint32_t)(period + 0.5) - high;
|
else
|
||||||
_startTone(_pin, high, low, duration);
|
{
|
||||||
}
|
double period = 1000000.0 / frequency;
|
||||||
|
uint32_t high = (uint32_t)((period / 2.0) + 0.5);
|
||||||
|
uint32_t low = (uint32_t)(period + 0.5) - high;
|
||||||
|
_startTone(_pin, high, low, duration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Fix ambiguous tone() binding when adding in a 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);
|
// Call the unsigned int version of the function explicitly
|
||||||
|
tone(_pin, (unsigned int)frequency, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void noTone(uint8_t _pin) {
|
void noTone(uint8_t _pin)
|
||||||
if (_pin > 16) {
|
{
|
||||||
return;
|
if (_pin > 16)
|
||||||
}
|
{
|
||||||
stopWaveform(_pin);
|
return;
|
||||||
_toneMap &= ~(1 << _pin);
|
}
|
||||||
digitalWrite(_pin, 0);
|
stopWaveform(_pin);
|
||||||
|
_toneMap &= ~(1 << _pin);
|
||||||
|
digitalWrite(_pin, 0);
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,36 @@
|
|||||||
/*
|
/*
|
||||||
* Udp.cpp: Library to send/receive UDP packets.
|
Udp.cpp: Library to send/receive UDP packets.
|
||||||
*
|
|
||||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
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
|
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
|
might not happen often in practice, but in larger network topologies, a UDP
|
||||||
* packet can be received out of sequence.
|
packet can be received out of sequence.
|
||||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
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.
|
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
|
For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||||
*
|
|
||||||
* MIT License:
|
MIT License:
|
||||||
* Copyright (c) 2008 Bjoern Hartmann
|
Copyright (c) 2008 Bjoern Hartmann
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
* in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*
|
|
||||||
* bjoern@cs.stanford.edu 12/30/2008
|
bjoern@cs.stanford.edu 12/30/2008
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef udp_h
|
#ifndef udp_h
|
||||||
#define udp_h
|
#define udp_h
|
||||||
@ -38,58 +38,61 @@
|
|||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
|
|
||||||
class UDP: public Stream {
|
class UDP: public Stream
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~UDP() {};
|
virtual ~UDP() {};
|
||||||
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
virtual uint8_t begin(uint16_t) = 0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||||
virtual void stop() =0; // Finish with the UDP socket
|
virtual void stop() = 0; // Finish with the UDP socket
|
||||||
|
|
||||||
// Sending UDP packets
|
// Sending UDP packets
|
||||||
|
|
||||||
// Start building up a packet to send to the remote host specific in ip and port
|
// Start building up a packet to send to the remote host specific in ip and port
|
||||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||||
virtual int beginPacket(IPAddress ip, uint16_t port) =0;
|
virtual int beginPacket(IPAddress ip, uint16_t port) = 0;
|
||||||
// Start building up a packet to send to the remote host specific in host and port
|
// Start building up a packet to send to the remote host specific in host and port
|
||||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||||
virtual int beginPacket(const char *host, uint16_t port) =0;
|
virtual int beginPacket(const char *host, uint16_t port) = 0;
|
||||||
// Finish off this packet and send it
|
// Finish off this packet and send it
|
||||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||||
virtual int endPacket() =0;
|
virtual int endPacket() = 0;
|
||||||
// Write a single byte into the packet
|
// Write a single byte into the packet
|
||||||
virtual size_t write(uint8_t) =0;
|
virtual size_t write(uint8_t) = 0;
|
||||||
// Write size bytes from buffer into the packet
|
// Write size bytes from buffer into the packet
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size) =0;
|
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
||||||
|
|
||||||
// Start processing the next available incoming packet
|
// Start processing the next available incoming packet
|
||||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||||
virtual int parsePacket() =0;
|
virtual int parsePacket() = 0;
|
||||||
// Number of bytes remaining in the current packet
|
// Number of bytes remaining in the current packet
|
||||||
virtual int available() =0;
|
virtual int available() = 0;
|
||||||
// Read a single byte from the current packet
|
// Read a single byte from the current packet
|
||||||
virtual int read() =0;
|
virtual int read() = 0;
|
||||||
// Read up to len bytes from the current packet and place them into buffer
|
// Read up to len bytes from the current packet and place them into buffer
|
||||||
// Returns the number of bytes read, or 0 if none are available
|
// Returns the number of bytes read, or 0 if none are available
|
||||||
virtual int read(unsigned char* buffer, size_t len) =0;
|
virtual int read(unsigned char* buffer, size_t len) = 0;
|
||||||
// Read up to len characters from the current packet and place them into buffer
|
// Read up to len characters from the current packet and place them into buffer
|
||||||
// Returns the number of characters read, or 0 if none are available
|
// Returns the number of characters read, or 0 if none are available
|
||||||
virtual int read(char* buffer, size_t len) =0;
|
virtual int read(char* buffer, size_t len) = 0;
|
||||||
// Return the next byte from the current packet without moving on to the next byte
|
// Return the next byte from the current packet without moving on to the next byte
|
||||||
virtual int peek() =0;
|
virtual int peek() = 0;
|
||||||
virtual void flush() =0; // Finish reading the current packet
|
virtual void flush() = 0; // Finish reading the current packet
|
||||||
|
|
||||||
// Return the IP address of the host who sent the current incoming packet
|
// Return the IP address of the host who sent the current incoming packet
|
||||||
virtual IPAddress remoteIP() =0;
|
virtual IPAddress remoteIP() = 0;
|
||||||
// Return the port of the host who sent the current incoming packet
|
// Return the port of the host who sent the current incoming packet
|
||||||
virtual uint16_t remotePort() =0;
|
virtual uint16_t remotePort() = 0;
|
||||||
protected:
|
protected:
|
||||||
uint8_t* rawIPAddress(IPAddress& addr) {
|
uint8_t* rawIPAddress(IPAddress& addr)
|
||||||
return addr.raw_address();
|
{
|
||||||
}
|
return addr.raw_address();
|
||||||
|
}
|
||||||
#if LWIP_VERSION_MAJOR != 1
|
#if LWIP_VERSION_MAJOR != 1
|
||||||
const uint8_t* rawIPAddress(const IPAddress& addr) {
|
const uint8_t* rawIPAddress(const IPAddress& addr)
|
||||||
return addr.raw_address();
|
{
|
||||||
}
|
return addr.raw_address();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -31,8 +31,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Abstract class to implement whatever signing hash desired
|
// Abstract class to implement whatever signing hash desired
|
||||||
class UpdaterHashClass {
|
class UpdaterHashClass
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
virtual void begin() = 0;
|
virtual void begin() = 0;
|
||||||
virtual void add(const void *data, uint32_t len) = 0;
|
virtual void add(const void *data, uint32_t len) = 0;
|
||||||
virtual void end() = 0;
|
virtual void end() = 0;
|
||||||
@ -41,144 +42,197 @@ class UpdaterHashClass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Abstract class to implement a signature verifier
|
// Abstract class to implement a signature verifier
|
||||||
class UpdaterVerifyClass {
|
class UpdaterVerifyClass
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
virtual uint32_t length() = 0; // How many bytes of signature are expected
|
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
|
virtual bool verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) = 0; // Verify, return "true" on success
|
||||||
};
|
};
|
||||||
|
|
||||||
class UpdaterClass {
|
class UpdaterClass
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
|
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
|
||||||
|
|
||||||
UpdaterClass();
|
UpdaterClass();
|
||||||
|
|
||||||
/* Optionally add a cryptographic signature verification hash and method */
|
/* 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
|
Call this to check the space needed for the update
|
||||||
Will return false if there is not enough space
|
Will return false if there is not enough space
|
||||||
*/
|
*/
|
||||||
bool begin(size_t size, int command = U_FLASH, int ledPin = -1, uint8_t ledOn = LOW);
|
bool begin(size_t size, int command = U_FLASH, int ledPin = -1, uint8_t ledOn = LOW);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Run Updater from asynchronous callbacs
|
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
|
Writes a buffer to the flash and increments the address
|
||||||
Returns the amount written
|
Returns the amount written
|
||||||
*/
|
*/
|
||||||
size_t write(uint8_t *data, size_t len);
|
size_t write(uint8_t *data, size_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Writes the remaining bytes from the Stream to the flash
|
Writes the remaining bytes from the Stream to the flash
|
||||||
Uses readBytes() and sets UPDATE_ERROR_STREAM on timeout
|
Uses readBytes() and sets UPDATE_ERROR_STREAM on timeout
|
||||||
Returns the bytes written
|
Returns the bytes written
|
||||||
Should be equal to the remaining bytes when called
|
Should be equal to the remaining bytes when called
|
||||||
Usable for slow streams like Serial
|
Usable for slow streams like Serial
|
||||||
*/
|
*/
|
||||||
size_t writeStream(Stream &data);
|
size_t writeStream(Stream &data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If all bytes are written
|
If all bytes are written
|
||||||
this call will write the config to eboot
|
this call will write the config to eboot
|
||||||
and return true
|
and return true
|
||||||
If there is already an update running but is not finished and !evenIfRemaining
|
If there is already an update running but is not finished and !evenIfRemaining
|
||||||
or there is an error
|
or there is an error
|
||||||
this will clear everything and return false
|
this will clear everything and return false
|
||||||
the last error is available through getError()
|
the last error is available through getError()
|
||||||
evenIfRemaining is helpful when you update without knowing the final size first
|
evenIfRemaining is helpful when you update without knowing the final size first
|
||||||
*/
|
*/
|
||||||
bool end(bool evenIfRemaining = false);
|
bool end(bool evenIfRemaining = false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Prints the last error to an output stream
|
Prints the last error to an output stream
|
||||||
*/
|
*/
|
||||||
void printError(Print &out);
|
void printError(Print &out);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sets the expected MD5 for the firmware (hexString)
|
sets the expected MD5 for the firmware (hexString)
|
||||||
*/
|
*/
|
||||||
bool setMD5(const char * expected_md5);
|
bool setMD5(const char * expected_md5);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
returns the MD5 String of the sucessfully ended firmware
|
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
|
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
|
This callback will be called when Updater is receiving data
|
||||||
*/
|
*/
|
||||||
UpdaterClass& onProgress(THandlerFunction_Progress fn);
|
UpdaterClass& onProgress(THandlerFunction_Progress fn);
|
||||||
|
|
||||||
//Helpers
|
//Helpers
|
||||||
uint8_t getError(){ return _error; }
|
uint8_t getError()
|
||||||
void clearError(){ _error = UPDATE_ERROR_OK; }
|
{
|
||||||
bool hasError(){ return _error != UPDATE_ERROR_OK; }
|
return _error;
|
||||||
bool isRunning(){ return _size > 0; }
|
}
|
||||||
bool isFinished(){ return _currentAddress == (_startAddress + _size); }
|
void clearError()
|
||||||
size_t size(){ return _size; }
|
{
|
||||||
size_t progress(){ return _currentAddress - _startAddress; }
|
_error = UPDATE_ERROR_OK;
|
||||||
size_t remaining(){ return _size - (_currentAddress - _startAddress); }
|
}
|
||||||
|
bool hasError()
|
||||||
/*
|
{
|
||||||
Template to write from objects that expose
|
return _error != UPDATE_ERROR_OK;
|
||||||
available() and read(uint8_t*, size_t) methods
|
}
|
||||||
faster than the writeStream method
|
bool isRunning()
|
||||||
writes only what is available
|
{
|
||||||
*/
|
return _size > 0;
|
||||||
template<typename T>
|
}
|
||||||
size_t write(T &data){
|
bool isFinished()
|
||||||
size_t written = 0;
|
{
|
||||||
if (hasError() || !isRunning())
|
return _currentAddress == (_startAddress + _size);
|
||||||
return 0;
|
}
|
||||||
|
size_t size()
|
||||||
size_t available = data.available();
|
{
|
||||||
while(available) {
|
return _size;
|
||||||
if(_bufferLen + available > remaining()){
|
}
|
||||||
available = remaining() - _bufferLen;
|
size_t progress()
|
||||||
}
|
{
|
||||||
if(_bufferLen + available > _bufferSize) {
|
return _currentAddress - _startAddress;
|
||||||
size_t toBuff = _bufferSize - _bufferLen;
|
}
|
||||||
data.read(_buffer + _bufferLen, toBuff);
|
size_t remaining()
|
||||||
_bufferLen += toBuff;
|
{
|
||||||
if(!_writeBuffer())
|
return _size - (_currentAddress - _startAddress);
|
||||||
return written;
|
|
||||||
written += toBuff;
|
|
||||||
} else {
|
|
||||||
data.read(_buffer + _bufferLen, available);
|
|
||||||
_bufferLen += available;
|
|
||||||
written += available;
|
|
||||||
if(_bufferLen == remaining()) {
|
|
||||||
if(!_writeBuffer()) {
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(remaining() == 0)
|
|
||||||
return written;
|
|
||||||
delay(1);
|
|
||||||
available = data.available();
|
|
||||||
}
|
|
||||||
return written;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/*
|
||||||
|
Template to write from objects that expose
|
||||||
|
available() and read(uint8_t*, size_t) methods
|
||||||
|
faster than the writeStream method
|
||||||
|
writes only what is available
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
available = remaining() - _bufferLen;
|
||||||
|
}
|
||||||
|
if (_bufferLen + available > _bufferSize)
|
||||||
|
{
|
||||||
|
size_t toBuff = _bufferSize - _bufferLen;
|
||||||
|
data.read(_buffer + _bufferLen, toBuff);
|
||||||
|
_bufferLen += toBuff;
|
||||||
|
if (!_writeBuffer())
|
||||||
|
{
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
written += toBuff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.read(_buffer + _bufferLen, available);
|
||||||
|
_bufferLen += available;
|
||||||
|
written += available;
|
||||||
|
if (_bufferLen == remaining())
|
||||||
|
{
|
||||||
|
if (!_writeBuffer())
|
||||||
|
{
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (remaining() == 0)
|
||||||
|
{
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
delay(1);
|
||||||
|
available = data.available();
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
void _reset();
|
void _reset();
|
||||||
bool _writeBuffer();
|
bool _writeBuffer();
|
||||||
|
|
||||||
bool _verifyHeader(uint8_t data);
|
bool _verifyHeader(uint8_t data);
|
||||||
bool _verifyEnd();
|
bool _verifyEnd();
|
||||||
|
|
||||||
void _setError(int error);
|
void _setError(int error);
|
||||||
|
|
||||||
bool _async;
|
bool _async;
|
||||||
uint8_t _error;
|
uint8_t _error;
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
WCharacter.h - Character utility functions for Wiring & Arduino
|
WCharacter.h - Character utility functions for Wiring & Arduino
|
||||||
Copyright (c) 2010 Hernando Barragan. All right reserved.
|
Copyright (c) 2010 Hernando Barragan. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef Character_h
|
#ifndef Character_h
|
||||||
#define Character_h
|
#define Character_h
|
||||||
@ -44,96 +44,112 @@ inline int toAscii(int c) __attribute__((always_inline));
|
|||||||
inline int toLowerCase(int c) __attribute__((always_inline));
|
inline int toLowerCase(int c) __attribute__((always_inline));
|
||||||
inline int toUpperCase(int c) __attribute__((always_inline));
|
inline int toUpperCase(int c) __attribute__((always_inline));
|
||||||
|
|
||||||
// Checks for an alphanumeric character.
|
// Checks for an alphanumeric character.
|
||||||
// It is equivalent to (isalpha(c) || isdigit(c)).
|
// It is equivalent to (isalpha(c) || isdigit(c)).
|
||||||
inline boolean isAlphaNumeric(int c) {
|
inline boolean isAlphaNumeric(int c)
|
||||||
|
{
|
||||||
return (isalnum(c) == 0 ? false : true);
|
return (isalnum(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for an alphabetic character.
|
// Checks for an alphabetic character.
|
||||||
// It is equivalent to (isupper(c) || islower(c)).
|
// It is equivalent to (isupper(c) || islower(c)).
|
||||||
inline boolean isAlpha(int c) {
|
inline boolean isAlpha(int c)
|
||||||
|
{
|
||||||
return (isalpha(c) == 0 ? false : true);
|
return (isalpha(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether c is a 7-bit unsigned char value
|
// Checks whether c is a 7-bit unsigned char value
|
||||||
// that fits into the ASCII character set.
|
// that fits into the ASCII character set.
|
||||||
inline boolean isAscii(int c) {
|
inline boolean isAscii(int c)
|
||||||
return ( isascii (c) == 0 ? false : true);
|
{
|
||||||
|
return (isascii(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for a blank character, that is, a space or a tab.
|
// 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);
|
return (isblank(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for a control character.
|
// Checks for a control character.
|
||||||
inline boolean isControl(int c) {
|
inline boolean isControl(int c)
|
||||||
|
{
|
||||||
return (iscntrl(c) == 0 ? false : true);
|
return (iscntrl(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for a digit (0 through 9).
|
// Checks for a digit (0 through 9).
|
||||||
inline boolean isDigit(int c) {
|
inline boolean isDigit(int c)
|
||||||
|
{
|
||||||
return (isdigit(c) == 0 ? false : true);
|
return (isdigit(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for any printable character except space.
|
// Checks for any printable character except space.
|
||||||
inline boolean isGraph(int c) {
|
inline boolean isGraph(int c)
|
||||||
|
{
|
||||||
return (isgraph(c) == 0 ? false : true);
|
return (isgraph(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for a lower-case character.
|
// Checks for a lower-case character.
|
||||||
inline boolean isLowerCase(int c) {
|
inline boolean isLowerCase(int c)
|
||||||
|
{
|
||||||
return (islower(c) == 0 ? false : true);
|
return (islower(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for any printable character including space.
|
// Checks for any printable character including space.
|
||||||
inline boolean isPrintable(int c) {
|
inline boolean isPrintable(int c)
|
||||||
|
{
|
||||||
return (isprint(c) == 0 ? false : true);
|
return (isprint(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for any printable character which is not a space
|
// Checks for any printable character which is not a space
|
||||||
// or an alphanumeric character.
|
// or an alphanumeric character.
|
||||||
inline boolean isPunct(int c) {
|
inline boolean isPunct(int c)
|
||||||
|
{
|
||||||
return (ispunct(c) == 0 ? false : true);
|
return (ispunct(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for white-space characters. For the avr-libc library,
|
// Checks for white-space characters. For the avr-libc library,
|
||||||
// these are: space, formfeed ('\f'), newline ('\n'), carriage
|
// these are: space, formfeed ('\f'), newline ('\n'), carriage
|
||||||
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
|
// 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);
|
return (isspace(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for an uppercase letter.
|
// Checks for an uppercase letter.
|
||||||
inline boolean isUpperCase(int c) {
|
inline boolean isUpperCase(int c)
|
||||||
|
{
|
||||||
return (isupper(c) == 0 ? false : true);
|
return (isupper(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
|
// 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.
|
// 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);
|
return (isxdigit(c) == 0 ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts c to a 7-bit unsigned char value that fits into the
|
// Converts c to a 7-bit unsigned char value that fits into the
|
||||||
// ASCII character set, by clearing the high-order bits.
|
// ASCII character set, by clearing the high-order bits.
|
||||||
inline int toAscii(int c) {
|
inline int toAscii(int c)
|
||||||
|
{
|
||||||
return toascii(c);
|
return toascii(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning:
|
// Warning:
|
||||||
// Many people will be unhappy if you use this function.
|
// Many people will be unhappy if you use this function.
|
||||||
// This function will convert accented letters into random
|
// This function will convert accented letters into random
|
||||||
// characters.
|
// characters.
|
||||||
|
|
||||||
// Converts the letter c to lower case, if possible.
|
// Converts the letter c to lower case, if possible.
|
||||||
inline int toLowerCase(int c) {
|
inline int toLowerCase(int c)
|
||||||
|
{
|
||||||
return tolower(c);
|
return tolower(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the letter c to upper case, if possible.
|
// Converts the letter c to upper case, if possible.
|
||||||
inline int toUpperCase(int c) {
|
inline int toUpperCase(int c)
|
||||||
|
{
|
||||||
return toupper(c);
|
return toupper(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Part of the Wiring project - http://wiring.org.co
|
Part of the Wiring project - http://wiring.org.co
|
||||||
Copyright (c) 2004-06 Hernando Barragan
|
Copyright (c) 2004-06 Hernando Barragan
|
||||||
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
|
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
|
||||||
|
|
||||||
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General
|
This library is distributed in the hope that it will be useful,
|
||||||
Public License along with this library; if not, write to the
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Boston, MA 02111-1307 USA
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
$Id$
|
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., 59 Temple Place, Suite 330,
|
||||||
|
Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -30,15 +30,19 @@ extern "C" {
|
|||||||
|
|
||||||
static bool s_randomSeedCalled = false;
|
static bool s_randomSeedCalled = false;
|
||||||
|
|
||||||
void randomSeed(unsigned long seed) {
|
void randomSeed(unsigned long seed)
|
||||||
if(seed != 0) {
|
{
|
||||||
|
if (seed != 0)
|
||||||
|
{
|
||||||
srand(seed);
|
srand(seed);
|
||||||
s_randomSeedCalled = true;
|
s_randomSeedCalled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long random(long howbig) {
|
long random(long howbig)
|
||||||
if(howbig == 0) {
|
{
|
||||||
|
if (howbig == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// if randomSeed was called, fall back to software PRNG
|
// if randomSeed was called, fall back to software PRNG
|
||||||
@ -46,41 +50,51 @@ long random(long howbig) {
|
|||||||
return val % howbig;
|
return val % howbig;
|
||||||
}
|
}
|
||||||
|
|
||||||
long random(long howsmall, long howbig) {
|
long random(long howsmall, long howbig)
|
||||||
if(howsmall >= howbig) {
|
{
|
||||||
|
if (howsmall >= howbig)
|
||||||
|
{
|
||||||
return howsmall;
|
return howsmall;
|
||||||
}
|
}
|
||||||
long diff = howbig - howsmall;
|
long diff = howbig - howsmall;
|
||||||
return random(diff) + howsmall;
|
return random(diff) + howsmall;
|
||||||
}
|
}
|
||||||
|
|
||||||
long secureRandom(long howbig) {
|
long secureRandom(long howbig)
|
||||||
if(howbig == 0) {
|
{
|
||||||
|
if (howbig == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return RANDOM_REG32 % howbig;
|
return RANDOM_REG32 % howbig;
|
||||||
}
|
}
|
||||||
|
|
||||||
long secureRandom(long howsmall, long howbig) {
|
long secureRandom(long howsmall, long howbig)
|
||||||
if(howsmall >= howbig) {
|
{
|
||||||
|
if (howsmall >= howbig)
|
||||||
|
{
|
||||||
return howsmall;
|
return howsmall;
|
||||||
}
|
}
|
||||||
long diff = howbig - howsmall;
|
long diff = howbig - howsmall;
|
||||||
return secureRandom(diff) + 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);
|
long divisor = (in_max - in_min);
|
||||||
if(divisor == 0){
|
if (divisor == 0)
|
||||||
|
{
|
||||||
return -1; //AVR returns -1, SAM returns 0
|
return -1; //AVR returns -1, SAM returns 0
|
||||||
}
|
}
|
||||||
return (x - in_min) * (out_max - out_min) / divisor + out_min;
|
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;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int makeWord(unsigned char h, unsigned char l) {
|
unsigned int makeWord(unsigned char h, unsigned char l)
|
||||||
|
{
|
||||||
return (h << 8) | l;
|
return (h << 8) | l;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
WString.h - String library for Wiring & Arduino
|
WString.h - String library for Wiring & Arduino
|
||||||
...mostly rewritten by Paul Stoffregen...
|
...mostly rewritten by Paul Stoffregen...
|
||||||
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
|
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
|
||||||
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef String_class_h
|
#ifndef String_class_h
|
||||||
#define String_class_h
|
#define String_class_h
|
||||||
@ -39,285 +39,373 @@ class __FlashStringHelper;
|
|||||||
#define F(string_literal) (FPSTR(PSTR(string_literal)))
|
#define F(string_literal) (FPSTR(PSTR(string_literal)))
|
||||||
|
|
||||||
// The string class
|
// 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:
|
// use a function pointer to allow for "if (s)" without the
|
||||||
// http://www.artima.com/cppsource/safebool.html
|
// complications of an operator bool(). for more information, see:
|
||||||
typedef void (String::*StringIfHelperType)() const;
|
// http://www.artima.com/cppsource/safebool.html
|
||||||
void StringIfHelper() const {
|
typedef void (String::*StringIfHelperType)() const;
|
||||||
}
|
void StringIfHelper() const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// constructors
|
// constructors
|
||||||
// creates a copy of the initial value.
|
// creates a copy of the initial value.
|
||||||
// if the initial value is null or invalid, or if memory allocation
|
// if the initial value is null or invalid, or if memory allocation
|
||||||
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||||
// be false).
|
// be false).
|
||||||
String(const char *cstr = "");
|
String(const char *cstr = "");
|
||||||
String(const String &str);
|
String(const String &str);
|
||||||
String(const __FlashStringHelper *str);
|
String(const __FlashStringHelper *str);
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||||
String(String &&rval);
|
String(String &&rval);
|
||||||
String(StringSumHelper &&rval);
|
String(StringSumHelper &&rval);
|
||||||
#endif
|
#endif
|
||||||
explicit String(char c);
|
explicit String(char c);
|
||||||
explicit String(unsigned char, unsigned char base = 10);
|
explicit String(unsigned char, unsigned char base = 10);
|
||||||
explicit String(int, unsigned char base = 10);
|
explicit String(int, unsigned char base = 10);
|
||||||
explicit String(unsigned int, unsigned char base = 10);
|
explicit String(unsigned int, unsigned char base = 10);
|
||||||
explicit String(long, unsigned char base = 10);
|
explicit String(long, unsigned char base = 10);
|
||||||
explicit String(unsigned long, unsigned char base = 10);
|
explicit String(unsigned long, unsigned char base = 10);
|
||||||
explicit String(float, unsigned char decimalPlaces = 2);
|
explicit String(float, unsigned char decimalPlaces = 2);
|
||||||
explicit String(double, unsigned char decimalPlaces = 2);
|
explicit String(double, unsigned char decimalPlaces = 2);
|
||||||
~String(void);
|
~String(void);
|
||||||
|
|
||||||
// memory management
|
// memory management
|
||||||
// return true on success, false on failure (in which case, the string
|
// return true on success, false on failure (in which case, the string
|
||||||
// is left unchanged). reserve(0), if successful, will validate an
|
// is left unchanged). reserve(0), if successful, will validate an
|
||||||
// invalid string (i.e., "if (s)" will be true afterwards)
|
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||||
unsigned char reserve(unsigned int size);
|
unsigned char reserve(unsigned int size);
|
||||||
inline unsigned int length(void) const {
|
inline unsigned int length(void) const
|
||||||
if(buffer()) {
|
{
|
||||||
return len();
|
if (buffer())
|
||||||
} else {
|
{
|
||||||
return 0;
|
return len();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// creates a copy of the assigned value. if the value is null or
|
// creates a copy of the assigned value. if the value is null or
|
||||||
// invalid, or if the memory allocation fails, the string will be
|
// invalid, or if the memory allocation fails, the string will be
|
||||||
// marked as invalid ("if (s)" will be false).
|
// marked as invalid ("if (s)" will be false).
|
||||||
String & operator =(const String &rhs);
|
String & operator =(const String &rhs);
|
||||||
String & operator =(const char *cstr);
|
String & operator =(const char *cstr);
|
||||||
String & operator = (const __FlashStringHelper *str);
|
String & operator = (const __FlashStringHelper *str);
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||||
String & operator =(String &&rval);
|
String & operator =(String &&rval);
|
||||||
String & operator =(StringSumHelper &&rval);
|
String & operator =(StringSumHelper &&rval);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// concatenate (works w/ built-in types)
|
// concatenate (works w/ built-in types)
|
||||||
|
|
||||||
// returns true on success, false on failure (in which case, the string
|
// returns true on success, false on failure (in which case, the string
|
||||||
// is left unchanged). if the argument is null or invalid, the
|
// is left unchanged). if the argument is null or invalid, the
|
||||||
// concatenation is considered unsuccessful.
|
// concatenation is considered unsuccessful.
|
||||||
unsigned char concat(const String &str);
|
unsigned char concat(const String &str);
|
||||||
unsigned char concat(const char *cstr);
|
unsigned char concat(const char *cstr);
|
||||||
unsigned char concat(char c);
|
unsigned char concat(char c);
|
||||||
unsigned char concat(unsigned char c);
|
unsigned char concat(unsigned char c);
|
||||||
unsigned char concat(int num);
|
unsigned char concat(int num);
|
||||||
unsigned char concat(unsigned int num);
|
unsigned char concat(unsigned int num);
|
||||||
unsigned char concat(long num);
|
unsigned char concat(long num);
|
||||||
unsigned char concat(unsigned long num);
|
unsigned char concat(unsigned long num);
|
||||||
unsigned char concat(float num);
|
unsigned char concat(float num);
|
||||||
unsigned char concat(double num);
|
unsigned char concat(double num);
|
||||||
unsigned char concat(const __FlashStringHelper * str);
|
unsigned char concat(const __FlashStringHelper * str);
|
||||||
|
|
||||||
// if there's not enough memory for the concatenated value, the string
|
// if there's not enough memory for the concatenated value, the string
|
||||||
// will be left unchanged (but this isn't signalled in any way)
|
// 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);
|
concat(rhs);
|
||||||
}
|
return (*this);
|
||||||
String & operator +=(const char *cstr) {
|
}
|
||||||
concat(cstr);
|
String & operator +=(const char *cstr)
|
||||||
return (*this);
|
{
|
||||||
}
|
concat(cstr);
|
||||||
String & operator +=(char c) {
|
return (*this);
|
||||||
concat(c);
|
}
|
||||||
return (*this);
|
String & operator +=(char c)
|
||||||
}
|
{
|
||||||
String & operator +=(unsigned char num) {
|
concat(c);
|
||||||
concat(num);
|
return (*this);
|
||||||
return (*this);
|
}
|
||||||
}
|
String & operator +=(unsigned char num)
|
||||||
String & operator +=(int num) {
|
{
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(unsigned int num) {
|
String & operator +=(int num)
|
||||||
concat(num);
|
{
|
||||||
return (*this);
|
concat(num);
|
||||||
}
|
return (*this);
|
||||||
String & operator +=(long num) {
|
}
|
||||||
concat(num);
|
String & operator +=(unsigned int num)
|
||||||
return (*this);
|
{
|
||||||
}
|
concat(num);
|
||||||
String & operator +=(unsigned long num) {
|
return (*this);
|
||||||
concat(num);
|
}
|
||||||
return (*this);
|
String & operator +=(long num)
|
||||||
}
|
{
|
||||||
String & operator +=(float num) {
|
concat(num);
|
||||||
concat(num);
|
return (*this);
|
||||||
return (*this);
|
}
|
||||||
}
|
String & operator +=(unsigned long num)
|
||||||
String & operator +=(double num) {
|
{
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator += (const __FlashStringHelper *str){
|
String & operator +=(float num)
|
||||||
concat(str);
|
{
|
||||||
return (*this);
|
concat(num);
|
||||||
}
|
return (*this);
|
||||||
|
}
|
||||||
|
String & operator +=(double num)
|
||||||
|
{
|
||||||
|
concat(num);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
String & operator += (const __FlashStringHelper *str)
|
||||||
|
{
|
||||||
|
concat(str);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, char c);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, char c);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, int num);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, int num);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, long num);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, long num);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num);
|
||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||||
|
|
||||||
// comparison (only works w/ Strings and "strings")
|
// comparison (only works w/ Strings and "strings")
|
||||||
operator StringIfHelperType() const {
|
operator StringIfHelperType() const
|
||||||
return buffer() ? &String::StringIfHelper : 0;
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
return equals(rhs);
|
||||||
|
}
|
||||||
|
unsigned char operator ==(const char *cstr) const
|
||||||
|
{
|
||||||
|
return equals(cstr);
|
||||||
|
}
|
||||||
|
unsigned char operator !=(const String &rhs) const
|
||||||
|
{
|
||||||
|
return !equals(rhs);
|
||||||
|
}
|
||||||
|
unsigned char operator !=(const char *cstr) const
|
||||||
|
{
|
||||||
|
return !equals(cstr);
|
||||||
|
}
|
||||||
|
unsigned char operator <(const String &rhs) const;
|
||||||
|
unsigned char operator >(const String &rhs) const;
|
||||||
|
unsigned char operator <=(const String &rhs) const;
|
||||||
|
unsigned char operator >=(const String &rhs) const;
|
||||||
|
unsigned char equalsIgnoreCase(const String &s) const;
|
||||||
|
unsigned char equalsConstantTime(const String &s) const;
|
||||||
|
unsigned char startsWith(const String &prefix) const;
|
||||||
|
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||||
|
unsigned char endsWith(const String &suffix) const;
|
||||||
|
|
||||||
|
// character access
|
||||||
|
char charAt(unsigned int index) const;
|
||||||
|
void setCharAt(unsigned int index, char c);
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// search
|
||||||
|
int indexOf(char ch) const;
|
||||||
|
int indexOf(char ch, unsigned int fromIndex) const;
|
||||||
|
int indexOf(const String &str) const;
|
||||||
|
int indexOf(const String &str, unsigned int fromIndex) const;
|
||||||
|
int lastIndexOf(char ch) const;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
return substring(beginIndex, len());
|
||||||
|
}
|
||||||
|
;
|
||||||
|
String substring(unsigned int beginIndex, unsigned int endIndex) const;
|
||||||
|
|
||||||
|
// modification
|
||||||
|
void replace(char find, char replace);
|
||||||
|
void replace(const String& find, const String& replace);
|
||||||
|
void remove(unsigned int index);
|
||||||
|
void remove(unsigned int index, unsigned int count);
|
||||||
|
void toLowerCase(void);
|
||||||
|
void toUpperCase(void);
|
||||||
|
void trim(void);
|
||||||
|
|
||||||
|
// parsing/conversion
|
||||||
|
long toInt(void) const;
|
||||||
|
float toFloat(void) const;
|
||||||
|
double toDouble(void) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Contains the string info when we're not in SSO mode
|
||||||
|
struct _ptr
|
||||||
|
{
|
||||||
|
char * buff;
|
||||||
|
uint16_t cap;
|
||||||
|
uint16_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
// SSO is handled by checking the last byte of sso_buff.
|
||||||
|
// When not in SSO mode, that byte is set to 0xff, while when in SSO mode it is always 0x00 (so it can serve as the string terminator as well as a flag)
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
int compareTo(const String &s) const;
|
}
|
||||||
unsigned char equals(const String &s) const;
|
inline void setCapacity(int cap)
|
||||||
unsigned char equals(const char *cstr) const;
|
{
|
||||||
unsigned char operator ==(const String &rhs) const {
|
if (!sso())
|
||||||
return equals(rhs);
|
{
|
||||||
|
ptr.cap = cap;
|
||||||
}
|
}
|
||||||
unsigned char operator ==(const char *cstr) const {
|
}
|
||||||
return equals(cstr);
|
inline void setBuffer(char *buff)
|
||||||
|
{
|
||||||
|
if (!sso())
|
||||||
|
{
|
||||||
|
ptr.buff = buff;
|
||||||
}
|
}
|
||||||
unsigned char operator !=(const String &rhs) const {
|
}
|
||||||
return !equals(rhs);
|
// Buffer accessor functions
|
||||||
}
|
inline const char *buffer() const
|
||||||
unsigned char operator !=(const char *cstr) const {
|
{
|
||||||
return !equals(cstr);
|
return (const char *)(sso() ? sso_buf : ptr.buff);
|
||||||
}
|
}
|
||||||
unsigned char operator <(const String &rhs) const;
|
inline char *wbuffer() const
|
||||||
unsigned char operator >(const String &rhs) const;
|
{
|
||||||
unsigned char operator <=(const String &rhs) const;
|
return sso() ? const_cast<char *>(sso_buf) : ptr.buff; // Writable version of buffer
|
||||||
unsigned char operator >=(const String &rhs) const;
|
}
|
||||||
unsigned char equalsIgnoreCase(const String &s) const;
|
|
||||||
unsigned char equalsConstantTime(const String &s) const;
|
|
||||||
unsigned char startsWith(const String &prefix) const;
|
|
||||||
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
|
||||||
unsigned char endsWith(const String &suffix) const;
|
|
||||||
|
|
||||||
// character access
|
protected:
|
||||||
char charAt(unsigned int index) const;
|
void init(void);
|
||||||
void setCharAt(unsigned int index, char c);
|
void invalidate(void);
|
||||||
char operator [](unsigned int index) const;
|
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||||
char& operator [](unsigned int index);
|
unsigned char concat(const char *cstr, unsigned int length);
|
||||||
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 {
|
|
||||||
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(); }
|
|
||||||
|
|
||||||
// search
|
// copy and move
|
||||||
int indexOf(char ch) const;
|
String & copy(const char *cstr, unsigned int length);
|
||||||
int indexOf(char ch, unsigned int fromIndex) const;
|
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
||||||
int indexOf(const String &str) const;
|
|
||||||
int indexOf(const String &str, unsigned int fromIndex) const;
|
|
||||||
int lastIndexOf(char ch) const;
|
|
||||||
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 {
|
|
||||||
return substring(beginIndex, len());
|
|
||||||
}
|
|
||||||
;
|
|
||||||
String substring(unsigned int beginIndex, unsigned int endIndex) const;
|
|
||||||
|
|
||||||
// modification
|
|
||||||
void replace(char find, char replace);
|
|
||||||
void replace(const String& find, const String& replace);
|
|
||||||
void remove(unsigned int index);
|
|
||||||
void remove(unsigned int index, unsigned int count);
|
|
||||||
void toLowerCase(void);
|
|
||||||
void toUpperCase(void);
|
|
||||||
void trim(void);
|
|
||||||
|
|
||||||
// parsing/conversion
|
|
||||||
long toInt(void) const;
|
|
||||||
float toFloat(void) const;
|
|
||||||
double toDouble(void) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Contains the string info when we're not in SSO mode
|
|
||||||
struct _ptr {
|
|
||||||
char * buff;
|
|
||||||
uint16_t cap;
|
|
||||||
uint16_t len;
|
|
||||||
};
|
|
||||||
|
|
||||||
// SSO is handled by checking the last byte of sso_buff.
|
|
||||||
// When not in SSO mode, that byte is set to 0xff, while when in SSO mode it is always 0x00 (so it can serve as the string terminator as well as a flag)
|
|
||||||
// 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 {
|
|
||||||
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; }
|
|
||||||
// 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
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void init(void);
|
|
||||||
void invalidate(void);
|
|
||||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
|
||||||
unsigned char concat(const char *cstr, unsigned int length);
|
|
||||||
|
|
||||||
// copy and move
|
|
||||||
String & copy(const char *cstr, unsigned int length);
|
|
||||||
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||||
void move(String &rhs);
|
void move(String &rhs);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class StringSumHelper: public String {
|
class StringSumHelper: public String
|
||||||
public:
|
{
|
||||||
StringSumHelper(const String &s) :
|
public:
|
||||||
String(s) {
|
StringSumHelper(const String &s) :
|
||||||
}
|
String(s)
|
||||||
StringSumHelper(const char *p) :
|
{
|
||||||
String(p) {
|
}
|
||||||
}
|
StringSumHelper(const char *p) :
|
||||||
StringSumHelper(char c) :
|
String(p)
|
||||||
String(c) {
|
{
|
||||||
}
|
}
|
||||||
StringSumHelper(unsigned char num) :
|
StringSumHelper(char c) :
|
||||||
String(num) {
|
String(c)
|
||||||
}
|
{
|
||||||
StringSumHelper(int num) :
|
}
|
||||||
String(num) {
|
StringSumHelper(unsigned char num) :
|
||||||
}
|
String(num)
|
||||||
StringSumHelper(unsigned int num) :
|
{
|
||||||
String(num) {
|
}
|
||||||
}
|
StringSumHelper(int num) :
|
||||||
StringSumHelper(long num) :
|
String(num)
|
||||||
String(num) {
|
{
|
||||||
}
|
}
|
||||||
StringSumHelper(unsigned long num) :
|
StringSumHelper(unsigned int num) :
|
||||||
String(num) {
|
String(num)
|
||||||
}
|
{
|
||||||
StringSumHelper(float num) :
|
}
|
||||||
String(num) {
|
StringSumHelper(long num) :
|
||||||
}
|
String(num)
|
||||||
StringSumHelper(double num) :
|
{
|
||||||
String(num) {
|
}
|
||||||
}
|
StringSumHelper(unsigned long num) :
|
||||||
|
String(num)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
StringSumHelper(float num) :
|
||||||
|
String(num)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
StringSumHelper(double num) :
|
||||||
|
String(num)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const String emptyString;
|
extern const String emptyString;
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2014 Arduino. All right reserved.
|
Copyright (c) 2014 Arduino. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
See the GNU Lesser General Public License for more details.
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -28,8 +28,8 @@ using __cxxabiv1::__guard;
|
|||||||
extern void *umm_last_fail_alloc_addr;
|
extern void *umm_last_fail_alloc_addr;
|
||||||
extern int umm_last_fail_alloc_size;
|
extern int umm_last_fail_alloc_size;
|
||||||
|
|
||||||
extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
|
extern "C" void __cxa_pure_virtual(void) __attribute__((__noreturn__));
|
||||||
extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
|
extern "C" void __cxa_deleted_virtual(void) __attribute__((__noreturn__));
|
||||||
|
|
||||||
void __cxa_pure_virtual(void)
|
void __cxa_pure_virtual(void)
|
||||||
{
|
{
|
||||||
@ -41,7 +41,8 @@ void __cxa_deleted_virtual(void)
|
|||||||
panic();
|
panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint8_t guard;
|
uint8_t guard;
|
||||||
uint8_t ps;
|
uint8_t ps;
|
||||||
} guard_t;
|
} guard_t;
|
||||||
@ -49,7 +50,8 @@ typedef struct {
|
|||||||
extern "C" int __cxa_guard_acquire(__guard* pg)
|
extern "C" int __cxa_guard_acquire(__guard* pg)
|
||||||
{
|
{
|
||||||
uint8_t ps = xt_rsil(15);
|
uint8_t ps = xt_rsil(15);
|
||||||
if (reinterpret_cast<guard_t*>(pg)->guard) {
|
if (reinterpret_cast<guard_t*>(pg)->guard)
|
||||||
|
{
|
||||||
xt_wsr_ps(ps);
|
xt_wsr_ps(ps);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,71 +1,74 @@
|
|||||||
/**
|
/**
|
||||||
* base64.cpp
|
base64.cpp
|
||||||
*
|
|
||||||
* Created on: 09.12.2015
|
Created on: 09.12.2015
|
||||||
*
|
|
||||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
* This file is part of the ESP8266 core for Arduino.
|
This file is part of the ESP8266 core for Arduino.
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "libb64/cdecode.h"
|
#include "libb64/cdecode.h"
|
||||||
#include "libb64/cencode.h"
|
#include "libb64/cencode.h"
|
||||||
}
|
}
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert input data to base64
|
convert input data to base64
|
||||||
* @param data uint8_t *
|
@param data uint8_t
|
||||||
* @param length size_t
|
@param length size_t
|
||||||
* @return String
|
@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 needs more size then the source data, use cencode.h macros
|
||||||
: base64_encode_expected_len_nonewlines(length)) + 1);
|
size_t size = ((doNewLines ? base64_encode_expected_len(length)
|
||||||
char * buffer = (char *) malloc(size);
|
: base64_encode_expected_len_nonewlines(length)) + 1);
|
||||||
if(buffer) {
|
char * buffer = (char *) malloc(size);
|
||||||
base64_encodestate _state;
|
if (buffer)
|
||||||
if(doNewLines)
|
{
|
||||||
{
|
base64_encodestate _state;
|
||||||
base64_init_encodestate(&_state);
|
if (doNewLines)
|
||||||
}
|
{
|
||||||
else
|
base64_init_encodestate(&_state);
|
||||||
{
|
}
|
||||||
base64_init_encodestate_nonewlines(&_state);
|
else
|
||||||
}
|
{
|
||||||
int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state);
|
base64_init_encodestate_nonewlines(&_state);
|
||||||
len = base64_encode_blockend((buffer + len), &_state);
|
}
|
||||||
|
int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state);
|
||||||
String base64 = String(buffer);
|
len = base64_encode_blockend((buffer + len), &_state);
|
||||||
free(buffer);
|
|
||||||
return base64;
|
String base64 = String(buffer);
|
||||||
}
|
free(buffer);
|
||||||
return String("-FAIL-");
|
return base64;
|
||||||
}
|
}
|
||||||
|
return String("-FAIL-");
|
||||||
/**
|
}
|
||||||
* convert input data to base64
|
|
||||||
* @param text String
|
/**
|
||||||
* @return String
|
convert input data to base64
|
||||||
*/
|
@param text String
|
||||||
String base64::encode(String text, bool doNewLines) {
|
@return String
|
||||||
return base64::encode((uint8_t *) text.c_str(), text.length(), doNewLines);
|
*/
|
||||||
}
|
String base64::encode(String text, bool doNewLines)
|
||||||
|
{
|
||||||
|
return base64::encode((uint8_t *) text.c_str(), text.length(), doNewLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,39 +1,40 @@
|
|||||||
/**
|
/**
|
||||||
* base64.h
|
base64.h
|
||||||
*
|
|
||||||
* Created on: 09.12.2015
|
Created on: 09.12.2015
|
||||||
*
|
|
||||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
* This file is part of the ESP8266 core for Arduino.
|
This file is part of the ESP8266 core for Arduino.
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CORE_BASE64_H_
|
#ifndef CORE_BASE64_H_
|
||||||
#define CORE_BASE64_H_
|
#define CORE_BASE64_H_
|
||||||
|
|
||||||
class base64 {
|
class base64
|
||||||
public:
|
{
|
||||||
// NOTE: The default behaviour of backend (lib64)
|
public:
|
||||||
// is to add a newline every 72 (encoded) characters output.
|
// NOTE: The default behaviour of backend (lib64)
|
||||||
// This may 'break' longer uris and json variables
|
// is to add a newline every 72 (encoded) characters output.
|
||||||
static String encode(uint8_t * data, size_t length, bool doNewLines = true);
|
// This may 'break' longer uris and json variables
|
||||||
static String encode(String text, bool doNewLines = true);
|
static String encode(uint8_t * data, size_t length, bool doNewLines = true);
|
||||||
private:
|
static String encode(String text, bool doNewLines = true);
|
||||||
};
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* CORE_BASE64_H_ */
|
|
||||||
|
#endif /* CORE_BASE64_H_ */
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
binary.h - Definitions for binary constants
|
binary.h - Definitions for binary constants
|
||||||
Copyright (c) 2006 David A. Mellis. All right reserved.
|
Copyright (c) 2006 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef Binary_h
|
#ifndef Binary_h
|
||||||
#define Binary_h
|
#define Binary_h
|
||||||
|
@ -1,56 +1,63 @@
|
|||||||
/*
|
/*
|
||||||
cbuf.cpp - Circular buffer implementation
|
cbuf.cpp - Circular buffer implementation
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 "cbuf.h"
|
#include "cbuf.h"
|
||||||
#include "c_types.h"
|
#include "c_types.h"
|
||||||
|
|
||||||
cbuf::cbuf(size_t size) :
|
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;
|
delete[] _buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t cbuf::resizeAdd(size_t addSize) {
|
size_t cbuf::resizeAdd(size_t addSize)
|
||||||
|
{
|
||||||
return resize(_size + addSize);
|
return resize(_size + addSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t cbuf::resize(size_t newSize) {
|
size_t cbuf::resize(size_t newSize)
|
||||||
|
{
|
||||||
|
|
||||||
size_t bytes_available = available();
|
size_t bytes_available = available();
|
||||||
|
|
||||||
// not lose any data
|
// not lose any data
|
||||||
// if data can be lost use remove or flush before resize
|
// 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;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *newbuf = new char[newSize];
|
char *newbuf = new char[newSize];
|
||||||
char *oldbuf = _buf;
|
char *oldbuf = _buf;
|
||||||
|
|
||||||
if(!newbuf) {
|
if (!newbuf)
|
||||||
|
{
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_buf) {
|
if (_buf)
|
||||||
|
{
|
||||||
read(newbuf, bytes_available);
|
read(newbuf, bytes_available);
|
||||||
memset((newbuf + bytes_available), 0x00, (newSize - bytes_available));
|
memset((newbuf + bytes_available), 0x00, (newSize - bytes_available));
|
||||||
}
|
}
|
||||||
@ -66,37 +73,47 @@ size_t cbuf::resize(size_t newSize) {
|
|||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ICACHE_RAM_ATTR cbuf::available() const {
|
size_t ICACHE_RAM_ATTR cbuf::available() const
|
||||||
if(_end >= _begin) {
|
{
|
||||||
|
if (_end >= _begin)
|
||||||
|
{
|
||||||
return _end - _begin;
|
return _end - _begin;
|
||||||
}
|
}
|
||||||
return _size - (_begin - _end);
|
return _size - (_begin - _end);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t cbuf::size() {
|
size_t cbuf::size()
|
||||||
|
{
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t cbuf::room() const {
|
size_t cbuf::room() const
|
||||||
if(_end >= _begin) {
|
{
|
||||||
|
if (_end >= _begin)
|
||||||
|
{
|
||||||
return _size - (_end - _begin) - 1;
|
return _size - (_end - _begin) - 1;
|
||||||
}
|
}
|
||||||
return _begin - _end - 1;
|
return _begin - _end - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cbuf::peek() {
|
int cbuf::peek()
|
||||||
if(empty())
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<int>(*_begin);
|
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 bytes_available = available();
|
||||||
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
||||||
size_t size_read = size_to_read;
|
size_t size_read = size_to_read;
|
||||||
char * begin = _begin;
|
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;
|
size_t top_size = _bufend - _begin;
|
||||||
memcpy(dst, _begin, top_size);
|
memcpy(dst, _begin, top_size);
|
||||||
begin = _buf;
|
begin = _buf;
|
||||||
@ -107,20 +124,25 @@ size_t cbuf::peek(char *dst, size_t size) {
|
|||||||
return size_read;
|
return size_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ICACHE_RAM_ATTR cbuf::read() {
|
int ICACHE_RAM_ATTR cbuf::read()
|
||||||
if(empty())
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char result = *_begin;
|
char result = *_begin;
|
||||||
_begin = wrap_if_bufend(_begin + 1);
|
_begin = wrap_if_bufend(_begin + 1);
|
||||||
return static_cast<int>(result);
|
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 bytes_available = available();
|
||||||
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
||||||
size_t size_read = size_to_read;
|
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;
|
size_t top_size = _bufend - _begin;
|
||||||
memcpy(dst, _begin, top_size);
|
memcpy(dst, _begin, top_size);
|
||||||
_begin = _buf;
|
_begin = _buf;
|
||||||
@ -132,20 +154,25 @@ size_t cbuf::read(char* dst, size_t size) {
|
|||||||
return size_read;
|
return size_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ICACHE_RAM_ATTR cbuf::write(char c) {
|
size_t ICACHE_RAM_ATTR cbuf::write(char c)
|
||||||
if(full())
|
{
|
||||||
|
if (full())
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
*_end = c;
|
*_end = c;
|
||||||
_end = wrap_if_bufend(_end + 1);
|
_end = wrap_if_bufend(_end + 1);
|
||||||
return 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 bytes_available = room();
|
||||||
size_t size_to_write = (size < bytes_available) ? size : bytes_available;
|
size_t size_to_write = (size < bytes_available) ? size : bytes_available;
|
||||||
size_t size_written = size_to_write;
|
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;
|
size_t top_size = _bufend - _end;
|
||||||
memcpy(_end, src, top_size);
|
memcpy(_end, src, top_size);
|
||||||
_end = _buf;
|
_end = _buf;
|
||||||
@ -157,19 +184,23 @@ size_t cbuf::write(const char* src, size_t size) {
|
|||||||
return size_written;
|
return size_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbuf::flush() {
|
void cbuf::flush()
|
||||||
|
{
|
||||||
_begin = _buf;
|
_begin = _buf;
|
||||||
_end = _buf;
|
_end = _buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t cbuf::remove(size_t size) {
|
size_t cbuf::remove(size_t size)
|
||||||
|
{
|
||||||
size_t bytes_available = available();
|
size_t bytes_available = available();
|
||||||
if(size >= bytes_available) {
|
if (size >= bytes_available)
|
||||||
|
{
|
||||||
flush();
|
flush();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t size_to_remove = (size < bytes_available) ? size : bytes_available;
|
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;
|
size_t top_size = _bufend - _begin;
|
||||||
_begin = _buf;
|
_begin = _buf;
|
||||||
size_to_remove -= top_size;
|
size_to_remove -= top_size;
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
cbuf.h - Circular buffer implementation
|
cbuf.h - Circular buffer implementation
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 __cbuf_h
|
#ifndef __cbuf_h
|
||||||
#define __cbuf_h
|
#define __cbuf_h
|
||||||
@ -25,50 +25,54 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
class cbuf {
|
class cbuf
|
||||||
public:
|
{
|
||||||
cbuf(size_t size);
|
public:
|
||||||
~cbuf();
|
cbuf(size_t size);
|
||||||
|
~cbuf();
|
||||||
|
|
||||||
size_t resizeAdd(size_t addSize);
|
size_t resizeAdd(size_t addSize);
|
||||||
size_t resize(size_t newSize);
|
size_t resize(size_t newSize);
|
||||||
size_t available() const;
|
size_t available() const;
|
||||||
size_t size();
|
size_t size();
|
||||||
|
|
||||||
size_t room() const;
|
size_t room() const;
|
||||||
|
|
||||||
inline bool empty() const {
|
inline bool empty() const
|
||||||
return _begin == _end;
|
{
|
||||||
}
|
return _begin == _end;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool full() const {
|
inline bool full() const
|
||||||
return wrap_if_bufend(_end + 1) == _begin;
|
{
|
||||||
}
|
return wrap_if_bufend(_end + 1) == _begin;
|
||||||
|
}
|
||||||
|
|
||||||
int peek();
|
int peek();
|
||||||
size_t peek(char *dst, size_t size);
|
size_t peek(char *dst, size_t size);
|
||||||
|
|
||||||
int read();
|
int read();
|
||||||
size_t read(char* dst, size_t size);
|
size_t read(char* dst, size_t size);
|
||||||
|
|
||||||
size_t write(char c);
|
size_t write(char c);
|
||||||
size_t write(const char* src, size_t size);
|
size_t write(const char* src, size_t size);
|
||||||
|
|
||||||
void flush();
|
void flush();
|
||||||
size_t remove(size_t size);
|
size_t remove(size_t size);
|
||||||
|
|
||||||
cbuf *next;
|
cbuf *next;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline char* wrap_if_bufend(char* ptr) const {
|
inline char* wrap_if_bufend(char* ptr) const
|
||||||
return (ptr == _bufend) ? _buf : ptr;
|
{
|
||||||
}
|
return (ptr == _bufend) ? _buf : ptr;
|
||||||
|
}
|
||||||
|
|
||||||
size_t _size;
|
size_t _size;
|
||||||
char* _buf;
|
char* _buf;
|
||||||
const char* _bufend;
|
const char* _bufend;
|
||||||
char* _begin;
|
char* _begin;
|
||||||
char* _end;
|
char* _end;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
cont.h - continuations support for Xtensa call0 ABI
|
cont.h - continuations support for Xtensa call0 ABI
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CONT_H_
|
#ifndef CONT_H_
|
||||||
#define CONT_H_
|
#define CONT_H_
|
||||||
@ -31,22 +31,23 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct cont_ {
|
typedef struct cont_
|
||||||
void (*pc_ret)(void);
|
{
|
||||||
unsigned* sp_ret;
|
void (*pc_ret)(void);
|
||||||
|
unsigned* sp_ret;
|
||||||
|
|
||||||
void (*pc_yield)(void);
|
void (*pc_yield)(void);
|
||||||
unsigned* sp_yield;
|
unsigned* sp_yield;
|
||||||
|
|
||||||
unsigned* stack_end;
|
unsigned* stack_end;
|
||||||
unsigned unused1;
|
unsigned unused1;
|
||||||
unsigned unused2;
|
unsigned unused2;
|
||||||
unsigned stack_guard1;
|
unsigned stack_guard1;
|
||||||
|
|
||||||
unsigned stack[CONT_STACKSIZE / 4];
|
unsigned stack[CONT_STACKSIZE / 4];
|
||||||
|
|
||||||
unsigned stack_guard2;
|
unsigned stack_guard2;
|
||||||
unsigned* struct_start;
|
unsigned* struct_start;
|
||||||
} cont_t;
|
} cont_t;
|
||||||
|
|
||||||
extern cont_t* g_pcont;
|
extern cont_t* g_pcont;
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
cont_util.s - continuations support for Xtensa call0 ABI
|
cont_util.s - continuations support for Xtensa call0 ABI
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cont.h"
|
#include "cont.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -27,57 +27,64 @@ extern "C" {
|
|||||||
|
|
||||||
#define CONT_STACKGUARD 0xfeefeffe
|
#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;
|
|
||||||
cont->stack_guard2 = CONT_STACKGUARD;
|
|
||||||
cont->stack_end = cont->stack + (sizeof(cont->stack) / 4);
|
|
||||||
cont->struct_start = (unsigned*) cont;
|
|
||||||
|
|
||||||
// fill stack with magic values to check high water mark
|
|
||||||
for(int pos = 0; pos < (int)(sizeof(cont->stack) / 4); pos++)
|
|
||||||
{
|
{
|
||||||
cont->stack[pos] = CONT_STACKGUARD;
|
memset(cont, 0, sizeof(cont_t));
|
||||||
|
|
||||||
|
cont->stack_guard1 = CONT_STACKGUARD;
|
||||||
|
cont->stack_guard2 = CONT_STACKGUARD;
|
||||||
|
cont->stack_end = cont->stack + (sizeof(cont->stack) / 4);
|
||||||
|
cont->struct_start = (unsigned*) cont;
|
||||||
|
|
||||||
|
// fill stack with magic values to check high water mark
|
||||||
|
for (int pos = 0; pos < (int)(sizeof(cont->stack) / 4); pos++)
|
||||||
|
{
|
||||||
|
cont->stack[pos] = CONT_STACKGUARD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int ICACHE_RAM_ATTR cont_check(cont_t* cont) {
|
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) {
|
|
||||||
uint32_t *head = cont->stack;
|
|
||||||
int freeWords = 0;
|
|
||||||
|
|
||||||
while(*head == CONT_STACKGUARD)
|
|
||||||
{
|
{
|
||||||
head++;
|
if (cont->stack_guard1 != CONT_STACKGUARD || cont->stack_guard2 != CONT_STACKGUARD)
|
||||||
freeWords++;
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return freeWords * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICACHE_RAM_ATTR cont_can_yield(cont_t* cont) {
|
// No need for this to be in IRAM, not expected to be IRQ called
|
||||||
return !ETS_INTR_WITHINISR() &&
|
int cont_get_free_stack(cont_t* cont)
|
||||||
cont->pc_ret != 0 && cont->pc_yield == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need for this to be in IRAM, not expected to be IRQ called
|
|
||||||
void cont_repaint_stack(cont_t *cont)
|
|
||||||
{
|
|
||||||
register uint32_t *sp asm("a1");
|
|
||||||
// Ensure 64 bytes adjacent to the current SP don't get touched to endure
|
|
||||||
// we don't accidentally trounce over locals or IRQ temps.
|
|
||||||
// Fill stack with magic values
|
|
||||||
for ( uint32_t *pos = sp - 16; pos >= &cont->stack[0]; pos-- )
|
|
||||||
{
|
{
|
||||||
*pos = CONT_STACKGUARD;
|
uint32_t *head = cont->stack;
|
||||||
|
int freeWords = 0;
|
||||||
|
|
||||||
|
while (*head == CONT_STACKGUARD)
|
||||||
|
{
|
||||||
|
head++;
|
||||||
|
freeWords++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freeWords * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICACHE_RAM_ATTR cont_can_yield(cont_t* cont)
|
||||||
|
{
|
||||||
|
return !ETS_INTR_WITHINISR() &&
|
||||||
|
cont->pc_ret != 0 && cont->pc_yield == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need for this to be in IRAM, not expected to be IRQ called
|
||||||
|
void cont_repaint_stack(cont_t *cont)
|
||||||
|
{
|
||||||
|
register uint32_t *sp asm("a1");
|
||||||
|
// Ensure 64 bytes adjacent to the current SP don't get touched to endure
|
||||||
|
// we don't accidentally trounce over locals or IRQ temps.
|
||||||
|
// Fill stack with magic values
|
||||||
|
for (uint32_t *pos = sp - 16; pos >= &cont->stack[0]; pos--)
|
||||||
|
{
|
||||||
|
*pos = CONT_STACKGUARD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* This is the original app_entry() not providing extra 4K heap, but allowing
|
This is the original app_entry() not providing extra 4K heap, but allowing
|
||||||
* the use of WPS.
|
the use of WPS.
|
||||||
*
|
|
||||||
* see comments in core_esp8266_main.cpp's app_entry()
|
see comments in core_esp8266_main.cpp's app_entry()
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <c_types.h>
|
#include <c_types.h>
|
||||||
#include "cont.h"
|
#include "cont.h"
|
||||||
#include "coredecls.h"
|
#include "coredecls.h"
|
||||||
|
|
||||||
void disable_extra4k_at_link_time (void)
|
void disable_extra4k_at_link_time(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* does nothing
|
does nothing
|
||||||
* allows overriding the core_esp8266_main.cpp's app_entry()
|
allows overriding the core_esp8266_main.cpp's app_entry()
|
||||||
* by this one below, at link time
|
by this one below, at link time
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the following code is linked only if a call to the above function is made somewhere */
|
/* the following code is linked only if a call to the above function is made somewhere */
|
||||||
@ -25,7 +25,7 @@ void disable_extra4k_at_link_time (void)
|
|||||||
extern "C" void call_user_start();
|
extern "C" void call_user_start();
|
||||||
|
|
||||||
/* this is the default NONOS-SDK user's heap location */
|
/* this is the default NONOS-SDK user's heap location */
|
||||||
static cont_t g_cont __attribute__ ((aligned (16)));
|
static cont_t g_cont __attribute__((aligned(16)));
|
||||||
|
|
||||||
extern "C" void ICACHE_RAM_ATTR app_entry_redefinable(void)
|
extern "C" void ICACHE_RAM_ATTR app_entry_redefinable(void)
|
||||||
{
|
{
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
core_esp8266_eboot_command.c - interface to the eboot bootloader
|
core_esp8266_eboot_command.c - interface to the eboot bootloader
|
||||||
|
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -25,67 +25,74 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length)
|
static uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
bool bit;
|
bool bit;
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
|
|
||||||
while (length--) {
|
while (length--)
|
||||||
c = *data++;
|
{
|
||||||
for (i = 0x80; i > 0; i >>= 1) {
|
c = *data++;
|
||||||
bit = crc & 0x80000000;
|
for (i = 0x80; i > 0; i >>= 1)
|
||||||
if (c & i) {
|
{
|
||||||
bit = !bit;
|
bit = crc & 0x80000000;
|
||||||
}
|
if (c & i)
|
||||||
crc <<= 1;
|
{
|
||||||
if (bit) {
|
bit = !bit;
|
||||||
crc ^= 0x04c11db7;
|
}
|
||||||
|
crc <<= 1;
|
||||||
|
if (bit)
|
||||||
|
{
|
||||||
|
crc ^= 0x04c11db7;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return crc;
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd)
|
|
||||||
{
|
|
||||||
return crc_update(0xffffffff, (const uint8_t*) cmd,
|
|
||||||
offsetof(struct eboot_command, crc32));
|
|
||||||
}
|
|
||||||
|
|
||||||
int eboot_command_read(struct eboot_command* cmd)
|
|
||||||
{
|
|
||||||
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) {
|
|
||||||
dst[i] = RTC_MEM[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t crc32 = eboot_command_calculate_crc32(cmd);
|
static uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd)
|
||||||
if ((cmd->magic & EBOOT_MAGIC_MASK) != EBOOT_MAGIC ||
|
{
|
||||||
cmd->crc32 != crc32) {
|
return crc_update(0xffffffff, (const uint8_t*) cmd,
|
||||||
return 1;
|
offsetof(struct eboot_command, crc32));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
int eboot_command_read(struct eboot_command* cmd)
|
||||||
}
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
dst[i] = RTC_MEM[i];
|
||||||
|
}
|
||||||
|
|
||||||
void eboot_command_write(struct eboot_command* cmd)
|
uint32_t crc32 = eboot_command_calculate_crc32(cmd);
|
||||||
{
|
if ((cmd->magic & EBOOT_MAGIC_MASK) != EBOOT_MAGIC ||
|
||||||
cmd->magic = EBOOT_MAGIC;
|
cmd->crc32 != crc32)
|
||||||
cmd->crc32 = eboot_command_calculate_crc32(cmd);
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
|
return 0;
|
||||||
const uint32_t* src = (const uint32_t *) cmd;
|
|
||||||
for (uint32_t i = 0; i < dw_count; ++i) {
|
|
||||||
RTC_MEM[i] = src[i];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void eboot_command_clear()
|
void eboot_command_write(struct eboot_command* cmd)
|
||||||
{
|
{
|
||||||
RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0;
|
cmd->magic = EBOOT_MAGIC;
|
||||||
RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0;
|
cmd->crc32 = eboot_command_calculate_crc32(cmd);
|
||||||
}
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
RTC_MEM[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eboot_command_clear()
|
||||||
|
{
|
||||||
|
RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0;
|
||||||
|
RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
/*
|
/*
|
||||||
core_esp8266_features.h - list of features integrated in to ESP8266 core
|
core_esp8266_features.h - list of features integrated in to ESP8266 core
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef CORE_ESP8266_FEATURES_H
|
#ifndef CORE_ESP8266_FEATURES_H
|
||||||
#define CORE_ESP8266_FEATURES_H
|
#define CORE_ESP8266_FEATURES_H
|
||||||
|
|
||||||
|
|
||||||
#define CORE_HAS_LIBB64
|
#define CORE_HAS_LIBB64
|
||||||
#define CORE_HAS_BASE64_CLASS
|
#define CORE_HAS_BASE64_CLASS
|
||||||
#define CORE_HAS_CXA_GUARD
|
#define CORE_HAS_CXA_GUARD
|
||||||
#define CORE_HAS_UMM
|
#define CORE_HAS_UMM
|
||||||
|
|
||||||
#define WIFI_HAS_EVENT_CALLBACK
|
#define WIFI_HAS_EVENT_CALLBACK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
core_esp8266_flash_utils.c - flash and binary image helpers
|
core_esp8266_flash_utils.c - flash and binary image helpers
|
||||||
|
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 <stddef.h>
|
#include <stddef.h>
|
||||||
@ -27,40 +27,47 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
int SPIEraseAreaEx(const uint32_t start, const uint32_t size)
|
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;
|
{
|
||||||
}
|
return 1;
|
||||||
|
|
||||||
const uint32_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
|
|
||||||
uint32_t current_sector = start / FLASH_SECTOR_SIZE;
|
|
||||||
uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
|
|
||||||
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)) {
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (;current_sector + sectors_per_block <= end;
|
const uint32_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
|
||||||
current_sector += sectors_per_block,
|
uint32_t current_sector = start / FLASH_SECTOR_SIZE;
|
||||||
sector_count -= sectors_per_block) {
|
uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
|
||||||
if (SPIEraseBlock(current_sector / sectors_per_block)) {
|
const uint32_t end = current_sector + sector_count;
|
||||||
return 3;
|
|
||||||
|
for (; current_sector < end && (current_sector & (sectors_per_block - 1));
|
||||||
|
++current_sector, --sector_count)
|
||||||
|
{
|
||||||
|
if (SPIEraseSector(current_sector))
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (; current_sector < end;
|
for (; current_sector + sectors_per_block <= end;
|
||||||
++current_sector, --sector_count) {
|
current_sector += sectors_per_block,
|
||||||
if (SPIEraseSector(current_sector)) {
|
sector_count -= sectors_per_block)
|
||||||
return 4;
|
{
|
||||||
|
if (SPIEraseBlock(current_sector / sectors_per_block))
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
for (; current_sector < end;
|
||||||
}
|
++current_sector, --sector_count)
|
||||||
|
{
|
||||||
|
if (SPIEraseSector(current_sector))
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
main.cpp - platform initialization and context switching
|
main.cpp - platform initialization and context switching
|
||||||
emulation
|
emulation
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//This may be used to change user task stack size:
|
//This may be used to change user task stack size:
|
||||||
//#define CONT_STACKSIZE 4096
|
//#define CONT_STACKSIZE 4096
|
||||||
@ -48,10 +48,10 @@ extern void (*__init_array_end)(void);
|
|||||||
/* Not static, used in Esp.cpp */
|
/* Not static, used in Esp.cpp */
|
||||||
struct rst_info resetInfo;
|
struct rst_info resetInfo;
|
||||||
|
|
||||||
/* Not static, used in core_esp8266_postmortem.c and other places.
|
/* Not static, used in core_esp8266_postmortem.c and other places.
|
||||||
* Placed into noinit section because we assign value to this variable
|
Placed into noinit section because we assign value to this variable
|
||||||
* before .bss is zero-filled, and need to preserve the value.
|
before .bss is zero-filled, and need to preserve the value.
|
||||||
*/
|
*/
|
||||||
cont_t* g_pcont __attribute__((section(".noinit")));
|
cont_t* g_pcont __attribute__((section(".noinit")));
|
||||||
|
|
||||||
/* Event queue used by the main (arduino) task */
|
/* Event queue used by the main (arduino) task */
|
||||||
@ -62,21 +62,23 @@ static uint32_t s_micros_at_task_start;
|
|||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern const uint32_t __attribute__((section(".ver_number"))) core_version = ARDUINO_ESP8266_GIT_VER;
|
extern const uint32_t __attribute__((section(".ver_number"))) core_version = ARDUINO_ESP8266_GIT_VER;
|
||||||
const char* core_release =
|
const char* core_release =
|
||||||
#ifdef ARDUINO_ESP8266_RELEASE
|
#ifdef ARDUINO_ESP8266_RELEASE
|
||||||
ARDUINO_ESP8266_RELEASE;
|
ARDUINO_ESP8266_RELEASE;
|
||||||
#else
|
#else
|
||||||
NULL;
|
NULL;
|
||||||
#endif
|
#endif
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
void initVariant() __attribute__((weak));
|
void initVariant() __attribute__((weak));
|
||||||
void initVariant() {
|
void initVariant()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void preloop_update_frequency() __attribute__((weak));
|
void preloop_update_frequency() __attribute__((weak));
|
||||||
void preloop_update_frequency() {
|
void preloop_update_frequency()
|
||||||
|
{
|
||||||
#if defined(F_CPU) && (F_CPU == 160000000L)
|
#if defined(F_CPU) && (F_CPU == 160000000L)
|
||||||
REG_SET_BIT(0x3ff00014, BIT(0));
|
REG_SET_BIT(0x3ff00014, BIT(0));
|
||||||
ets_update_cpu_frequency(160);
|
ets_update_cpu_frequency(160);
|
||||||
@ -84,40 +86,49 @@ void preloop_update_frequency() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void esp_yield() {
|
extern "C" void esp_yield()
|
||||||
if (cont_can_yield(g_pcont)) {
|
{
|
||||||
|
if (cont_can_yield(g_pcont))
|
||||||
|
{
|
||||||
cont_yield(g_pcont);
|
cont_yield(g_pcont);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void esp_schedule() {
|
extern "C" void esp_schedule()
|
||||||
|
{
|
||||||
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void __yield() {
|
extern "C" void __yield()
|
||||||
if (cont_can_yield(g_pcont)) {
|
{
|
||||||
|
if (cont_can_yield(g_pcont))
|
||||||
|
{
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
esp_yield();
|
esp_yield();
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
panic();
|
panic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void yield(void) __attribute__ ((weak, alias("__yield")));
|
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) &&
|
if (cont_can_yield(g_pcont) &&
|
||||||
(system_get_time() - s_micros_at_task_start) > interval_us)
|
(system_get_time() - s_micros_at_task_start) > interval_us)
|
||||||
{
|
{
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loop_wrapper() {
|
static void loop_wrapper()
|
||||||
|
{
|
||||||
static bool setup_done = false;
|
static bool setup_done = false;
|
||||||
preloop_update_frequency();
|
preloop_update_frequency();
|
||||||
if(!setup_done) {
|
if (!setup_done)
|
||||||
|
{
|
||||||
setup();
|
setup();
|
||||||
setup_done = true;
|
setup_done = true;
|
||||||
}
|
}
|
||||||
@ -126,56 +137,72 @@ static void loop_wrapper() {
|
|||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loop_task(os_event_t *events) {
|
static void loop_task(os_event_t *events)
|
||||||
|
{
|
||||||
(void) events;
|
(void) events;
|
||||||
s_micros_at_task_start = system_get_time();
|
s_micros_at_task_start = system_get_time();
|
||||||
cont_run(g_pcont, &loop_wrapper);
|
cont_run(g_pcont, &loop_wrapper);
|
||||||
if (cont_check(g_pcont) != 0) {
|
if (cont_check(g_pcont) != 0)
|
||||||
|
{
|
||||||
panic();
|
panic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
struct object { long placeholder[ 10 ]; };
|
struct object
|
||||||
void __register_frame_info (const void *begin, struct object *ob);
|
{
|
||||||
extern char __eh_frame[];
|
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;
|
static struct object ob;
|
||||||
__register_frame_info( __eh_frame, &ob );
|
__register_frame_info(__eh_frame, &ob);
|
||||||
|
|
||||||
void (**p)(void) = &__init_array_end;
|
void (**p)(void) = &__init_array_end;
|
||||||
while (p != &__init_array_start)
|
while (p != &__init_array_start)
|
||||||
|
{
|
||||||
(*--p)();
|
(*--p)();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern void __unhandled_exception(const char *str);
|
extern void __unhandled_exception(const char *str);
|
||||||
|
|
||||||
static void __unhandled_exception_cpp()
|
static void __unhandled_exception_cpp()
|
||||||
{
|
{
|
||||||
#ifndef __EXCEPTIONS
|
#ifndef __EXCEPTIONS
|
||||||
abort();
|
|
||||||
#else
|
|
||||||
static bool terminating;
|
|
||||||
if (terminating)
|
|
||||||
abort();
|
abort();
|
||||||
terminating = true;
|
#else
|
||||||
/* Use a trick from vterminate.cc to get any std::exception what() */
|
static bool terminating;
|
||||||
try {
|
if (terminating)
|
||||||
__throw_exception_again;
|
{
|
||||||
} catch (const std::exception& e) {
|
abort();
|
||||||
__unhandled_exception( e.what() );
|
}
|
||||||
} catch (...) {
|
terminating = true;
|
||||||
__unhandled_exception( "" );
|
/* Use a trick from vterminate.cc to get any std::exception what() */
|
||||||
}
|
try
|
||||||
|
{
|
||||||
|
__throw_exception_again;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
__unhandled_exception(e.what());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
__unhandled_exception("");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_done() {
|
void init_done()
|
||||||
|
{
|
||||||
system_set_os_print(1);
|
system_set_os_print(1);
|
||||||
gdb_init();
|
gdb_init();
|
||||||
std::set_terminate(__unhandled_exception_cpp);
|
std::set_terminate(__unhandled_exception_cpp);
|
||||||
@ -183,56 +210,56 @@ void init_done() {
|
|||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the entry point of the application.
|
/* This is the entry point of the application.
|
||||||
* It gets called on the default stack, which grows down from the top
|
It gets called on the default stack, which grows down from the top
|
||||||
* of DRAM area.
|
of DRAM area.
|
||||||
* .bss has not been zeroed out yet, but .data and .rodata are in place.
|
.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.
|
Cache is not enabled, so only ROM and IRAM functions can be called.
|
||||||
* Peripherals (except for SPI0 and UART0) are not initialized.
|
Peripherals (except for SPI0 and UART0) are not initialized.
|
||||||
* This function does not return.
|
This function does not return.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
A bit of explanation for this entry point:
|
A bit of explanation for this entry point:
|
||||||
|
|
||||||
SYS is the SDK task/context used by the upperlying system to run its
|
SYS is the SDK task/context used by the upperlying system to run its
|
||||||
administrative tasks (at least WLAN and lwip's receive callbacks and
|
administrative tasks (at least WLAN and lwip's receive callbacks and
|
||||||
Ticker). NONOS-SDK is designed to run user's non-threaded code in
|
Ticker). NONOS-SDK is designed to run user's non-threaded code in
|
||||||
another specific task/context with its own stack in BSS.
|
another specific task/context with its own stack in BSS.
|
||||||
|
|
||||||
Some clever fellows found that the SYS stack was a large and quite unused
|
Some clever fellows found that the SYS stack was a large and quite unused
|
||||||
piece of ram that we could use for the user's stack instead of using user's
|
piece of ram that we could use for the user's stack instead of using user's
|
||||||
main memory, thus saving around 4KB on ram/heap.
|
main memory, thus saving around 4KB on ram/heap.
|
||||||
|
|
||||||
A problem arose later, which is that this stack can heavily be used by
|
A problem arose later, which is that this stack can heavily be used by
|
||||||
the SDK for some features. One of these features is WPS. We still don't
|
the SDK for some features. One of these features is WPS. We still don't
|
||||||
know if other features are using this, or if this memory is going to be
|
know if other features are using this, or if this memory is going to be
|
||||||
used in future SDK releases.
|
used in future SDK releases.
|
||||||
|
|
||||||
WPS beeing flawed by its poor security, or not beeing used by lots of
|
WPS beeing flawed by its poor security, or not beeing used by lots of
|
||||||
users, it has been decided that we are still going to use that memory for
|
users, it has been decided that we are still going to use that memory for
|
||||||
user's stack and disable the use of WPS.
|
user's stack and disable the use of WPS.
|
||||||
|
|
||||||
app_entry() jumps to app_entry_custom() defined as "weakref" calling
|
app_entry() jumps to app_entry_custom() defined as "weakref" calling
|
||||||
itself a weak customizable function, allowing to use another one when
|
itself a weak customizable function, allowing to use another one when
|
||||||
this is required (see core_esp8266_app_entry_noextra4k.cpp, used by WPS).
|
this is required (see core_esp8266_app_entry_noextra4k.cpp, used by WPS).
|
||||||
|
|
||||||
(note: setting app_entry() itself as "weak" is not sufficient and always
|
(note: setting app_entry() itself as "weak" is not sufficient and always
|
||||||
ends up with the other "noextra4k" one linked, maybe because it has a
|
ends up with the other "noextra4k" one linked, maybe because it has a
|
||||||
default ENTRY(app_entry) value in linker scripts).
|
default ENTRY(app_entry) value in linker scripts).
|
||||||
|
|
||||||
References:
|
References:
|
||||||
https://github.com/esp8266/Arduino/pull/4553
|
https://github.com/esp8266/Arduino/pull/4553
|
||||||
https://github.com/esp8266/Arduino/pull/4622
|
https://github.com/esp8266/Arduino/pull/4622
|
||||||
https://github.com/esp8266/Arduino/issues/4779
|
https://github.com/esp8266/Arduino/issues/4779
|
||||||
https://github.com/esp8266/Arduino/pull/4889
|
https://github.com/esp8266/Arduino/pull/4889
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern "C" void ICACHE_RAM_ATTR app_entry_redefinable(void) __attribute__((weak));
|
extern "C" void ICACHE_RAM_ATTR app_entry_redefinable(void) __attribute__((weak));
|
||||||
extern "C" void ICACHE_RAM_ATTR app_entry_redefinable(void)
|
extern "C" void ICACHE_RAM_ATTR app_entry_redefinable(void)
|
||||||
{
|
{
|
||||||
/* Allocate continuation context on this SYS stack,
|
/* Allocate continuation context on this SYS stack,
|
||||||
and save pointer to it. */
|
and save pointer to it. */
|
||||||
cont_t s_cont __attribute__((aligned(16)));
|
cont_t s_cont __attribute__((aligned(16)));
|
||||||
g_pcont = &s_cont;
|
g_pcont = &s_cont;
|
||||||
|
|
||||||
@ -240,20 +267,21 @@ extern "C" void ICACHE_RAM_ATTR app_entry_redefinable(void)
|
|||||||
call_user_start();
|
call_user_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ICACHE_RAM_ATTR app_entry_custom (void) __attribute__((weakref("app_entry_redefinable")));
|
static void ICACHE_RAM_ATTR app_entry_custom(void) __attribute__((weakref("app_entry_redefinable")));
|
||||||
|
|
||||||
extern "C" void ICACHE_RAM_ATTR app_entry (void)
|
extern "C" void ICACHE_RAM_ATTR app_entry(void)
|
||||||
{
|
{
|
||||||
return app_entry_custom();
|
return app_entry_custom();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void preinit (void) __attribute__((weak));
|
extern "C" void preinit(void) __attribute__((weak));
|
||||||
extern "C" void preinit (void)
|
extern "C" void preinit(void)
|
||||||
{
|
{
|
||||||
/* do nothing by default */
|
/* 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();
|
struct rst_info *rtc_info_ptr = system_get_rst_info();
|
||||||
memcpy((void *) &resetInfo, (void *) rtc_info_ptr, sizeof(resetInfo));
|
memcpy((void *) &resetInfo, (void *) rtc_info_ptr, sizeof(resetInfo));
|
||||||
|
|
||||||
@ -268,8 +296,8 @@ extern "C" void user_init(void) {
|
|||||||
preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable.
|
preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable.
|
||||||
|
|
||||||
ets_task(loop_task,
|
ets_task(loop_task,
|
||||||
LOOP_TASK_PRIORITY, s_loop_queue,
|
LOOP_TASK_PRIORITY, s_loop_queue,
|
||||||
LOOP_QUEUE_SIZE);
|
LOOP_QUEUE_SIZE);
|
||||||
|
|
||||||
system_init_done_cb(&init_done);
|
system_init_done_cb(&init_done);
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
core_esp8266_noniso.c - nonstandard (but usefull) conversion functions
|
core_esp8266_noniso.c - nonstandard (but usefull) conversion functions
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
Modified 03 April 2015 by Markus Sattler
|
Modified 03 April 2015 by Markus Sattler
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -31,85 +31,104 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
char* ltoa(long value, char* result, int base) {
|
char* ltoa(long value, char* result, int base)
|
||||||
return itoa((int)value, result, base);
|
{
|
||||||
}
|
return itoa((int)value, result, 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) {
|
|
||||||
bool negative = false;
|
|
||||||
|
|
||||||
if (isnan(number)) {
|
|
||||||
strcpy(s, "nan");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
if (isinf(number)) {
|
|
||||||
strcpy(s, "inf");
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* out = s;
|
char* ultoa(unsigned long value, char* result, int base)
|
||||||
|
{
|
||||||
int fillme = width; // how many cells to fill for the integer part
|
return utoa((unsigned int)value, result, base);
|
||||||
if (prec > 0) {
|
|
||||||
fillme -= (prec+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle negative numbers
|
char * dtostrf(double number, signed char width, unsigned char prec, char *s)
|
||||||
if (number < 0.0) {
|
{
|
||||||
negative = true;
|
bool negative = false;
|
||||||
fillme--;
|
|
||||||
number = -number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
if (isnan(number))
|
||||||
// I optimized out most of the divisions
|
{
|
||||||
double rounding = 2.0;
|
strcpy(s, "nan");
|
||||||
for (uint8_t i = 0; i < prec; ++i)
|
return s;
|
||||||
rounding *= 10.0;
|
}
|
||||||
rounding = 1.0 / rounding;
|
if (isinf(number))
|
||||||
|
{
|
||||||
number += rounding;
|
strcpy(s, "inf");
|
||||||
|
return s;
|
||||||
// Figure out how big our number really is
|
|
||||||
double tenpow = 1.0;
|
|
||||||
int digitcount = 1;
|
|
||||||
while (number >= 10.0 * tenpow) {
|
|
||||||
tenpow *= 10.0;
|
|
||||||
digitcount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
number /= tenpow;
|
|
||||||
fillme -= digitcount;
|
|
||||||
|
|
||||||
// Pad unused cells with spaces
|
|
||||||
while (fillme-- > 0) {
|
|
||||||
*out++ = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle negative sign
|
|
||||||
if (negative) *out++ = '-';
|
|
||||||
|
|
||||||
// Print the digits, and if necessary, the decimal point
|
|
||||||
digitcount += prec;
|
|
||||||
int8_t digit = 0;
|
|
||||||
while (digitcount-- > 0) {
|
|
||||||
digit = (int8_t)number;
|
|
||||||
if (digit > 9) digit = 9; // insurance
|
|
||||||
*out++ = (char)('0' | digit);
|
|
||||||
if ((digitcount == prec) && (prec > 0)) {
|
|
||||||
*out++ = '.';
|
|
||||||
}
|
}
|
||||||
number -= digit;
|
|
||||||
number *= 10.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the string is terminated
|
char* out = s;
|
||||||
*out = 0;
|
|
||||||
return s;
|
int fillme = width; // how many cells to fill for the integer part
|
||||||
}
|
if (prec > 0)
|
||||||
|
{
|
||||||
|
fillme -= (prec + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle negative numbers
|
||||||
|
if (number < 0.0)
|
||||||
|
{
|
||||||
|
negative = true;
|
||||||
|
fillme--;
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Figure out how big our number really is
|
||||||
|
double tenpow = 1.0;
|
||||||
|
int digitcount = 1;
|
||||||
|
while (number >= 10.0 * tenpow)
|
||||||
|
{
|
||||||
|
tenpow *= 10.0;
|
||||||
|
digitcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
number /= tenpow;
|
||||||
|
fillme -= digitcount;
|
||||||
|
|
||||||
|
// Pad unused cells with spaces
|
||||||
|
while (fillme-- > 0)
|
||||||
|
{
|
||||||
|
*out++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle negative sign
|
||||||
|
if (negative)
|
||||||
|
{
|
||||||
|
*out++ = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the digits, and if necessary, the decimal point
|
||||||
|
digitcount += prec;
|
||||||
|
int8_t digit = 0;
|
||||||
|
while (digitcount-- > 0)
|
||||||
|
{
|
||||||
|
digit = (int8_t)number;
|
||||||
|
if (digit > 9)
|
||||||
|
{
|
||||||
|
digit = 9; // insurance
|
||||||
|
}
|
||||||
|
*out++ = (char)('0' | digit);
|
||||||
|
if ((digitcount == prec) && (prec > 0))
|
||||||
|
{
|
||||||
|
*out++ = '.';
|
||||||
|
}
|
||||||
|
number -= digit;
|
||||||
|
number *= 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the string is terminated
|
||||||
|
*out = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
phy.c - ESP8266 PHY initialization data
|
phy.c - ESP8266 PHY initialization data
|
||||||
|
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -30,330 +30,332 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static const uint8_t ICACHE_FLASH_ATTR phy_init_data[128] =
|
static const uint8_t ICACHE_FLASH_ATTR phy_init_data[128] =
|
||||||
{
|
{
|
||||||
/*[0] =*/ 5, // Reserved, do not change
|
/*[0] =*/ 5, // Reserved, do not change
|
||||||
/*[1] =*/ 8, // Reserved, do not change
|
/*[1] =*/ 8, // Reserved, do not change
|
||||||
/*[2] =*/ 4, // Reserved, do not change
|
/*[2] =*/ 4, // Reserved, do not change
|
||||||
/*[3] =*/ 2, // Reserved, do not change
|
/*[3] =*/ 2, // Reserved, do not change
|
||||||
/*[4] =*/ 5, // Reserved, do not change
|
/*[4] =*/ 5, // Reserved, do not change
|
||||||
/*[5] =*/ 5, // Reserved, do not change
|
/*[5] =*/ 5, // Reserved, do not change
|
||||||
/*[6] =*/ 5, // Reserved, do not change
|
/*[6] =*/ 5, // Reserved, do not change
|
||||||
/*[7] =*/ 2, // Reserved, do not change
|
/*[7] =*/ 2, // Reserved, do not change
|
||||||
/*[8] =*/ 5, // Reserved, do not change
|
/*[8] =*/ 5, // Reserved, do not change
|
||||||
/*[9] =*/ 0, // Reserved, do not change
|
/*[9] =*/ 0, // Reserved, do not change
|
||||||
/*[10] =*/ 4, // Reserved, do not change
|
/*[10] =*/ 4, // Reserved, do not change
|
||||||
/*[11] =*/ 5, // Reserved, do not change
|
/*[11] =*/ 5, // Reserved, do not change
|
||||||
/*[12] =*/ 5, // Reserved, do not change
|
/*[12] =*/ 5, // Reserved, do not change
|
||||||
/*[13] =*/ 4, // Reserved, do not change
|
/*[13] =*/ 4, // Reserved, do not change
|
||||||
/*[14] =*/ 5, // Reserved, do not change
|
/*[14] =*/ 5, // Reserved, do not change
|
||||||
/*[15] =*/ 5, // Reserved, do not change
|
/*[15] =*/ 5, // Reserved, do not change
|
||||||
/*[16] =*/ 4, // Reserved, do not change
|
/*[16] =*/ 4, // Reserved, do not change
|
||||||
/*[17] =*/ (uint8_t)-2, // Reserved, do not change
|
/*[17] =*/ (uint8_t) -2, // Reserved, do not change
|
||||||
/*[18] =*/ (uint8_t)-3, // Reserved, do not change
|
/*[18] =*/ (uint8_t) -3, // Reserved, do not change
|
||||||
/*[19] =*/ (uint8_t)-1, // Reserved, do not change
|
/*[19] =*/ (uint8_t) -1, // Reserved, do not change
|
||||||
/*[20] =*/ (uint8_t)-16, // Reserved, do not change
|
/*[20] =*/ (uint8_t) -16, // Reserved, do not change
|
||||||
/*[21] =*/ (uint8_t)-16, // Reserved, do not change
|
/*[21] =*/ (uint8_t) -16, // Reserved, do not change
|
||||||
/*[22] =*/ (uint8_t)-16, // Reserved, do not change
|
/*[22] =*/ (uint8_t) -16, // Reserved, do not change
|
||||||
/*[23] =*/ (uint8_t)-32, // Reserved, do not change
|
/*[23] =*/ (uint8_t) -32, // Reserved, do not change
|
||||||
/*[24] =*/ (uint8_t)-32, // Reserved, do not change
|
/*[24] =*/ (uint8_t) -32, // Reserved, do not change
|
||||||
/*[25] =*/ (uint8_t)-32, // Reserved, do not change
|
/*[25] =*/ (uint8_t) -32, // Reserved, do not change
|
||||||
|
|
||||||
/*[26] =*/ 225, // spur_freq_cfg, spur_freq=spur_freq_cfg/spur_freq_cfg_div
|
/*[26] =*/ 225, // spur_freq_cfg, spur_freq=spur_freq_cfg/spur_freq_cfg_div
|
||||||
/*[27] =*/ 10, // spur_freq_cfg_div
|
/*[27] =*/ 10, // spur_freq_cfg_div
|
||||||
// each bit for 1 channel, 1 to select the spur_freq if in band, else 40
|
// each bit for 1 channel, 1 to select the spur_freq if in band, else 40
|
||||||
/*[28] =*/ 0xff, // spur_freq_en_h
|
/*[28] =*/ 0xff, // spur_freq_en_h
|
||||||
/*[29] =*/ 0xff, // spur_freq_en_l
|
/*[29] =*/ 0xff, // spur_freq_en_l
|
||||||
|
|
||||||
/*[30] =*/ 0xf8, // Reserved, do not change
|
/*[30] =*/ 0xf8, // Reserved, do not change
|
||||||
/*[31] =*/ 0, // Reserved, do not change
|
/*[31] =*/ 0, // Reserved, do not change
|
||||||
/*[32] =*/ 0xf8, // Reserved, do not change
|
/*[32] =*/ 0xf8, // Reserved, do not change
|
||||||
/*[33] =*/ 0xf8, // Reserved, do not change
|
/*[33] =*/ 0xf8, // Reserved, do not change
|
||||||
|
|
||||||
/*[34] =*/ 78, // target_power_qdb_0, target power is 78/4=19.5dbm
|
/*[34] =*/ 78, // target_power_qdb_0, target power is 78/4=19.5dbm
|
||||||
/*[35] =*/ 74, // target_power_qdb_1, target power is 74/4=18.5dbm
|
/*[35] =*/ 74, // target_power_qdb_1, target power is 74/4=18.5dbm
|
||||||
/*[36] =*/ 70, // target_power_qdb_2, target power is 70/4=17.5dbm
|
/*[36] =*/ 70, // target_power_qdb_2, target power is 70/4=17.5dbm
|
||||||
/*[37] =*/ 64, // target_power_qdb_3, target power is 64/4=16dbm
|
/*[37] =*/ 64, // target_power_qdb_3, target power is 64/4=16dbm
|
||||||
/*[38] =*/ 60, // target_power_qdb_4, target power is 60/4=15dbm
|
/*[38] =*/ 60, // target_power_qdb_4, target power is 60/4=15dbm
|
||||||
/*[39] =*/ 56, // target_power_qdb_5, target power is 56/4=14dbm
|
/*[39] =*/ 56, // target_power_qdb_5, target power is 56/4=14dbm
|
||||||
|
|
||||||
/*[40] =*/ 0, // target_power_index_mcs0
|
/*[40] =*/ 0, // target_power_index_mcs0
|
||||||
/*[41] =*/ 0, // target_power_index_mcs1
|
/*[41] =*/ 0, // target_power_index_mcs1
|
||||||
/*[42] =*/ 1, // target_power_index_mcs2
|
/*[42] =*/ 1, // target_power_index_mcs2
|
||||||
/*[43] =*/ 1, // target_power_index_mcs3
|
/*[43] =*/ 1, // target_power_index_mcs3
|
||||||
/*[44] =*/ 2, // target_power_index_mcs4
|
/*[44] =*/ 2, // target_power_index_mcs4
|
||||||
/*[45] =*/ 3, // target_power_index_mcs5
|
/*[45] =*/ 3, // target_power_index_mcs5
|
||||||
/*[46] =*/ 4, // target_power_index_mcs6
|
/*[46] =*/ 4, // target_power_index_mcs6
|
||||||
/*[47] =*/ 5, // target_power_index_mcs7
|
/*[47] =*/ 5, // target_power_index_mcs7
|
||||||
|
|
||||||
// crystal_26m_en
|
// crystal_26m_en
|
||||||
// 0: 40MHz
|
// 0: 40MHz
|
||||||
// 1: 26MHz
|
// 1: 26MHz
|
||||||
// 2: 24MHz
|
// 2: 24MHz
|
||||||
#if F_CRYSTAL == 40000000
|
#if F_CRYSTAL == 40000000
|
||||||
/*[48] =*/ 0,
|
/*[48] =*/ 0,
|
||||||
#else
|
#else
|
||||||
/*[48] =*/ 1,
|
/*[48] =*/ 1,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*[49] =*/ 0,
|
/*[49] =*/ 0,
|
||||||
|
|
||||||
// sdio_configure
|
// sdio_configure
|
||||||
// 0: Auto by pin strapping
|
// 0: Auto by pin strapping
|
||||||
// 1: SDIO dataoutput is at negative edges (SDIO V1.1)
|
// 1: SDIO dataoutput is at negative edges (SDIO V1.1)
|
||||||
// 2: SDIO dataoutput is at positive edges (SDIO V2.0)
|
// 2: SDIO dataoutput is at positive edges (SDIO V2.0)
|
||||||
/*[50] =*/ 0,
|
/*[50] =*/ 0,
|
||||||
|
|
||||||
// bt_configure
|
// bt_configure
|
||||||
// 0: None,no bluetooth
|
// 0: None,no bluetooth
|
||||||
// 1: GPIO0 -> WLAN_ACTIVE/ANT_SEL_WIFI
|
// 1: GPIO0 -> WLAN_ACTIVE/ANT_SEL_WIFI
|
||||||
// MTMS -> BT_ACTIVE
|
// MTMS -> BT_ACTIVE
|
||||||
// MTCK -> BT_PRIORITY
|
// MTCK -> BT_PRIORITY
|
||||||
// U0RXD -> ANT_SEL_BT
|
// U0RXD -> ANT_SEL_BT
|
||||||
// 2: None, have bluetooth
|
// 2: None, have bluetooth
|
||||||
// 3: GPIO0 -> WLAN_ACTIVE/ANT_SEL_WIFI
|
// 3: GPIO0 -> WLAN_ACTIVE/ANT_SEL_WIFI
|
||||||
// MTMS -> BT_PRIORITY
|
// MTMS -> BT_PRIORITY
|
||||||
// MTCK -> BT_ACTIVE
|
// MTCK -> BT_ACTIVE
|
||||||
// U0RXD -> ANT_SEL_BT
|
// U0RXD -> ANT_SEL_BT
|
||||||
/*[51] =*/ 0,
|
/*[51] =*/ 0,
|
||||||
|
|
||||||
// bt_protocol
|
// bt_protocol
|
||||||
// 0: WiFi-BT are not enabled. Antenna is for WiFi
|
// 0: WiFi-BT are not enabled. Antenna is for WiFi
|
||||||
// 1: WiFi-BT are not enabled. Antenna is for BT
|
// 1: WiFi-BT are not enabled. Antenna is for BT
|
||||||
// 2: WiFi-BT 2-wire are enabled, (only use BT_ACTIVE), independent ant
|
// 2: WiFi-BT 2-wire are enabled, (only use BT_ACTIVE), independent ant
|
||||||
// 3: WiFi-BT 3-wire are enabled, (when BT_ACTIVE = 0, BT_PRIORITY must be 0), independent ant
|
// 3: WiFi-BT 3-wire are enabled, (when BT_ACTIVE = 0, BT_PRIORITY must be 0), independent ant
|
||||||
// 4: WiFi-BT 2-wire are enabled, (only use BT_ACTIVE), share ant
|
// 4: WiFi-BT 2-wire are enabled, (only use BT_ACTIVE), share ant
|
||||||
// 5: WiFi-BT 3-wire are enabled, (when BT_ACTIVE = 0, BT_PRIORITY must be 0), share ant
|
// 5: WiFi-BT 3-wire are enabled, (when BT_ACTIVE = 0, BT_PRIORITY must be 0), share ant
|
||||||
/*[52] =*/ 0,
|
/*[52] =*/ 0,
|
||||||
|
|
||||||
// dual_ant_configure
|
// dual_ant_configure
|
||||||
// 0: None
|
// 0: None
|
||||||
// 1: dual_ant (antenna diversity for WiFi-only): GPIO0 + U0RXD
|
// 1: dual_ant (antenna diversity for WiFi-only): GPIO0 + U0RXD
|
||||||
// 2: T/R switch for External PA/LNA: GPIO0 is high and U0RXD is low during Tx
|
// 2: T/R switch for External PA/LNA: GPIO0 is high and U0RXD is low during Tx
|
||||||
// 3: T/R switch for External PA/LNA: GPIO0 is low and U0RXD is high during Tx
|
// 3: T/R switch for External PA/LNA: GPIO0 is low and U0RXD is high during Tx
|
||||||
/*[53] =*/ 0,
|
/*[53] =*/ 0,
|
||||||
|
|
||||||
/*[54] =*/ 2, // Reserved, do not change
|
/*[54] =*/ 2, // Reserved, do not change
|
||||||
|
|
||||||
// share_xtal
|
// share_xtal
|
||||||
// This option is to share crystal clock for BT
|
// This option is to share crystal clock for BT
|
||||||
// The state of Crystal during sleeping
|
// The state of Crystal during sleeping
|
||||||
// 0: Off
|
// 0: Off
|
||||||
// 1: Forcely On
|
// 1: Forcely On
|
||||||
// 2: Automatically On according to XPD_DCDC
|
// 2: Automatically On according to XPD_DCDC
|
||||||
// 3: Automatically On according to GPIO2
|
// 3: Automatically On according to GPIO2
|
||||||
/*[55] =*/ 0,
|
/*[55] =*/ 0,
|
||||||
|
|
||||||
/*[56] =*/ 0,
|
/*[56] =*/ 0,
|
||||||
/*[57] =*/ 0,
|
/*[57] =*/ 0,
|
||||||
/*[58] =*/ 0,
|
/*[58] =*/ 0,
|
||||||
/*[59] =*/ 0,
|
/*[59] =*/ 0,
|
||||||
/*[60] =*/ 0,
|
/*[60] =*/ 0,
|
||||||
/*[61] =*/ 0,
|
/*[61] =*/ 0,
|
||||||
/*[62] =*/ 0,
|
/*[62] =*/ 0,
|
||||||
/*[63] =*/ 0,
|
/*[63] =*/ 0,
|
||||||
|
|
||||||
/*[64] =*/ 225, // spur_freq_cfg_2, spur_freq_2=spur_freq_cfg_2/spur_freq_cfg_div_2
|
/*[64] =*/ 225, // spur_freq_cfg_2, spur_freq_2=spur_freq_cfg_2/spur_freq_cfg_div_2
|
||||||
/*[65] =*/ 10, // spur_freq_cfg_div_2
|
/*[65] =*/ 10, // spur_freq_cfg_div_2
|
||||||
/*[66] =*/ 0, // spur_freq_en_h_2
|
/*[66] =*/ 0, // spur_freq_en_h_2
|
||||||
/*[67] =*/ 0, // spur_freq_en_l_2
|
/*[67] =*/ 0, // spur_freq_en_l_2
|
||||||
/*[68] =*/ 0, // spur_freq_cfg_msb
|
/*[68] =*/ 0, // spur_freq_cfg_msb
|
||||||
/*[69] =*/ 0, // spur_freq_cfg_2_msb
|
/*[69] =*/ 0, // spur_freq_cfg_2_msb
|
||||||
/*[70] =*/ 0, // spur_freq_cfg_3_low
|
/*[70] =*/ 0, // spur_freq_cfg_3_low
|
||||||
/*[71] =*/ 0, // spur_freq_cfg_3_high
|
/*[71] =*/ 0, // spur_freq_cfg_3_high
|
||||||
/*[72] =*/ 0, // spur_freq_cfg_4_low
|
/*[72] =*/ 0, // spur_freq_cfg_4_low
|
||||||
/*[73] =*/ 0, // spur_freq_cfg_4_high
|
/*[73] =*/ 0, // spur_freq_cfg_4_high
|
||||||
|
|
||||||
/*[74] =*/ 1, // Reserved, do not change
|
/*[74] =*/ 1, // Reserved, do not change
|
||||||
/*[75] =*/ 0x93, // Reserved, do not change
|
/*[75] =*/ 0x93, // Reserved, do not change
|
||||||
/*[76] =*/ 0x43, // Reserved, do not change
|
/*[76] =*/ 0x43, // Reserved, do not change
|
||||||
/*[77] =*/ 0x00, // Reserved, do not change
|
/*[77] =*/ 0x00, // Reserved, do not change
|
||||||
|
|
||||||
/*[78] =*/ 0,
|
/*[78] =*/ 0,
|
||||||
/*[79] =*/ 0,
|
/*[79] =*/ 0,
|
||||||
/*[80] =*/ 0,
|
/*[80] =*/ 0,
|
||||||
/*[81] =*/ 0,
|
/*[81] =*/ 0,
|
||||||
/*[82] =*/ 0,
|
/*[82] =*/ 0,
|
||||||
/*[83] =*/ 0,
|
/*[83] =*/ 0,
|
||||||
/*[84] =*/ 0,
|
/*[84] =*/ 0,
|
||||||
/*[85] =*/ 0,
|
/*[85] =*/ 0,
|
||||||
/*[86] =*/ 0,
|
/*[86] =*/ 0,
|
||||||
/*[87] =*/ 0,
|
/*[87] =*/ 0,
|
||||||
/*[88] =*/ 0,
|
/*[88] =*/ 0,
|
||||||
/*[89] =*/ 0,
|
/*[89] =*/ 0,
|
||||||
/*[90] =*/ 0,
|
/*[90] =*/ 0,
|
||||||
/*[91] =*/ 0,
|
/*[91] =*/ 0,
|
||||||
/*[92] =*/ 0,
|
/*[92] =*/ 0,
|
||||||
|
|
||||||
// low_power_en
|
// low_power_en
|
||||||
// 0: disable low power mode
|
// 0: disable low power mode
|
||||||
// 1: enable low power mode
|
// 1: enable low power mode
|
||||||
/*[93] =*/ 0,
|
/*[93] =*/ 0,
|
||||||
|
|
||||||
// lp_rf_stg10
|
// lp_rf_stg10
|
||||||
// the attenuation of RF gain stage 0 and 1,
|
// the attenuation of RF gain stage 0 and 1,
|
||||||
// 0xf: 0db,
|
// 0xf: 0db,
|
||||||
// 0xe: -2.5db,
|
// 0xe: -2.5db,
|
||||||
// 0xd: -6db,
|
// 0xd: -6db,
|
||||||
// 0x9: -8.5db,
|
// 0x9: -8.5db,
|
||||||
// 0xc: -11.5db,
|
// 0xc: -11.5db,
|
||||||
// 0x8: -14db,
|
// 0x8: -14db,
|
||||||
// 0x4: -17.5,
|
// 0x4: -17.5,
|
||||||
// 0x0: -23
|
// 0x0: -23
|
||||||
/*[94] =*/ 0x00,
|
/*[94] =*/ 0x00,
|
||||||
|
|
||||||
|
|
||||||
// lp_bb_att_ext
|
// lp_bb_att_ext
|
||||||
// the attenuation of BB gain,
|
// the attenuation of BB gain,
|
||||||
// 0: 0db,
|
// 0: 0db,
|
||||||
// 1: -0.25db,
|
// 1: -0.25db,
|
||||||
// 2: -0.5db,
|
// 2: -0.5db,
|
||||||
// 3: -0.75db,
|
// 3: -0.75db,
|
||||||
// 4: -1db,
|
// 4: -1db,
|
||||||
// 5: -1.25db,
|
// 5: -1.25db,
|
||||||
// 6: -1.5db,
|
// 6: -1.5db,
|
||||||
// 7: -1.75db,
|
// 7: -1.75db,
|
||||||
// 8: -2db
|
// 8: -2db
|
||||||
// max valve is 24(-6db)
|
// max valve is 24(-6db)
|
||||||
/*[95] =*/ 0,
|
/*[95] =*/ 0,
|
||||||
|
|
||||||
// pwr_ind_11b_en
|
// pwr_ind_11b_en
|
||||||
// 0: 11b power is same as mcs0 and 6m
|
// 0: 11b power is same as mcs0 and 6m
|
||||||
// 1: enable 11b power different with ofdm
|
// 1: enable 11b power different with ofdm
|
||||||
/*[96] =*/ 0,
|
/*[96] =*/ 0,
|
||||||
|
|
||||||
// pwr_ind_11b_0
|
// pwr_ind_11b_0
|
||||||
// 1m, 2m power index [0~5]
|
// 1m, 2m power index [0~5]
|
||||||
/*[97] =*/ 0,
|
/*[97] =*/ 0,
|
||||||
|
|
||||||
// pwr_ind_11b_1
|
// pwr_ind_11b_1
|
||||||
// 5.5m, 11m power index [0~5]
|
// 5.5m, 11m power index [0~5]
|
||||||
/*[98] =*/ 0,
|
/*[98] =*/ 0,
|
||||||
|
|
||||||
/*[99] =*/ 0,
|
/*[99] =*/ 0,
|
||||||
/*[100] =*/ 0,
|
/*[100] =*/ 0,
|
||||||
/*[101] =*/ 0,
|
/*[101] =*/ 0,
|
||||||
/*[102] =*/ 0,
|
/*[102] =*/ 0,
|
||||||
/*[103] =*/ 0,
|
/*[103] =*/ 0,
|
||||||
/*[104] =*/ 0,
|
/*[104] =*/ 0,
|
||||||
/*[105] =*/ 0,
|
/*[105] =*/ 0,
|
||||||
/*[106] =*/ 0,
|
/*[106] =*/ 0,
|
||||||
|
|
||||||
// vdd33_const
|
// vdd33_const
|
||||||
// the voltage of PA_VDD
|
// the voltage of PA_VDD
|
||||||
// x=0xff: it can measure VDD33,
|
// x=0xff: it can measure VDD33,
|
||||||
// 18<=x<=36: use input voltage,
|
// 18<=x<=36: use input voltage,
|
||||||
// the value is voltage*10, 33 is 3.3V, 30 is 3.0V,
|
// the value is voltage*10, 33 is 3.3V, 30 is 3.0V,
|
||||||
// x<18 or x>36: default voltage is 3.3V
|
// x<18 or x>36: default voltage is 3.3V
|
||||||
//
|
//
|
||||||
// the value of this byte depend from the TOUT pin usage (1 or 2):
|
// the value of this byte depend from the TOUT pin usage (1 or 2):
|
||||||
// 1)
|
// 1)
|
||||||
// analogRead function (system_adc_read()):
|
// analogRead function (system_adc_read()):
|
||||||
// is only available when wire TOUT pin17 to external circuitry, Input Voltage Range restricted to 0 ~ 1.0V.
|
// is only available when wire TOUT pin17 to external circuitry, Input Voltage Range restricted to 0 ~ 1.0V.
|
||||||
// For this function the vdd33_const must be set as real power voltage of VDD3P3 pin 3 and 4
|
// For this function the vdd33_const must be set as real power voltage of VDD3P3 pin 3 and 4
|
||||||
// The range of operating voltage of ESP8266 is 1.8V~3.6V,the unit of vdd33_const is 0.1V,so effective value range of vdd33_const is [18,36]
|
// The range of operating voltage of ESP8266 is 1.8V~3.6V,the unit of vdd33_const is 0.1V,so effective value range of vdd33_const is [18,36]
|
||||||
// 2)
|
// 2)
|
||||||
// getVcc function (system_get_vdd33):
|
// getVcc function (system_get_vdd33):
|
||||||
// is only available when TOUT pin17 is suspended (floating), this function measure the power voltage of VDD3P3 pin 3 and 4
|
// is only available when TOUT pin17 is suspended (floating), this function measure the power voltage of VDD3P3 pin 3 and 4
|
||||||
// For this function the vdd33_const must be set to 255 (0xFF).
|
// For this function the vdd33_const must be set to 255 (0xFF).
|
||||||
/*[107] =*/ 33,
|
/*[107] =*/ 33,
|
||||||
|
|
||||||
// disable RF calibration for certain number of times
|
// disable RF calibration for certain number of times
|
||||||
/*[108] =*/ 0,
|
/*[108] =*/ 0,
|
||||||
|
|
||||||
/*[109] =*/ 0,
|
/*[109] =*/ 0,
|
||||||
/*[110] =*/ 0,
|
/*[110] =*/ 0,
|
||||||
/*[111] =*/ 0,
|
/*[111] =*/ 0,
|
||||||
|
|
||||||
// freq_correct_en
|
// freq_correct_en
|
||||||
// bit[0]:0->do not correct frequency offset, 1->correct frequency offset.
|
// bit[0]:0->do not correct frequency offset, 1->correct frequency offset.
|
||||||
// bit[1]:0->bbpll is 168M, it can correct + and - frequency offset, 1->bbpll is 160M, it only can correct + frequency offset
|
// bit[1]:0->bbpll is 168M, it can correct + and - frequency offset, 1->bbpll is 160M, it only can correct + frequency offset
|
||||||
// bit[2]:0->auto measure frequency offset and correct it, 1->use 113 byte force_freq_offset to correct frequency offset.
|
// bit[2]:0->auto measure frequency offset and correct it, 1->use 113 byte force_freq_offset to correct frequency offset.
|
||||||
// 0: do not correct frequency offset.
|
// 0: do not correct frequency offset.
|
||||||
// 1: auto measure frequency offset and correct it, bbpll is 168M, it can correct + and - frequency offset.
|
// 1: auto measure frequency offset and correct it, bbpll is 168M, it can correct + and - frequency offset.
|
||||||
// 3: auto measure frequency offset and correct it, bbpll is 160M, it only can correct + frequency offset.
|
// 3: auto measure frequency offset and correct it, bbpll is 160M, it only can correct + frequency offset.
|
||||||
// 5: use 113 byte force_freq_offset to correct frequency offset, bbpll is 168M, it can correct + and - frequency offset.
|
// 5: use 113 byte force_freq_offset to correct frequency offset, bbpll is 168M, it can correct + and - frequency offset.
|
||||||
// 7: use 113 byte force_freq_offset to correct frequency offset, bbpll is 160M , it only can correct + frequency offset.
|
// 7: use 113 byte force_freq_offset to correct frequency offset, bbpll is 160M , it only can correct + frequency offset.
|
||||||
/*[112] =*/ 0,
|
/*[112] =*/ 0,
|
||||||
|
|
||||||
// force_freq_offset
|
// force_freq_offset
|
||||||
// signed, unit is 8kHz
|
// signed, unit is 8kHz
|
||||||
/*[113] =*/ 0,
|
/*[113] =*/ 0,
|
||||||
|
|
||||||
// rf_cal_use_flash
|
// rf_cal_use_flash
|
||||||
// 0: RF init no RF CAL, using all RF CAL data in flash, it takes about 2ms for RF init
|
// 0: RF init no RF CAL, using all RF CAL data in flash, it takes about 2ms for RF init
|
||||||
// 1: RF init only do TX power control CAL, others using RF CAL data in flash, it takes about 20ms for RF init
|
// 1: RF init only do TX power control CAL, others using RF CAL data in flash, it takes about 20ms for RF init
|
||||||
// 2: RF init no RF CAL, using all RF CAL data in flash, it takes about 2ms for RF init (same as 0?!)
|
// 2: RF init no RF CAL, using all RF CAL data in flash, it takes about 2ms for RF init (same as 0?!)
|
||||||
// 3: RF init do all RF CAL, it takes about 200ms for RF init
|
// 3: RF init do all RF CAL, it takes about 200ms for RF init
|
||||||
/*[114] =*/ 1
|
/*[114] =*/ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// These functions will be overriden from C++ code.
|
// These functions will be overriden from C++ code.
|
||||||
// Unfortunately, we can't use extern "C" because Arduino preprocessor
|
// Unfortunately, we can't use extern "C" because Arduino preprocessor
|
||||||
// doesn't generate forward declarations for extern "C" functions correctly,
|
// doesn't generate forward declarations for extern "C" functions correctly,
|
||||||
// so we use mangled names here.
|
// so we use mangled names here.
|
||||||
#define __get_adc_mode _Z14__get_adc_modev
|
#define __get_adc_mode _Z14__get_adc_modev
|
||||||
#define __get_rf_mode _Z13__get_rf_modev
|
#define __get_rf_mode _Z13__get_rf_modev
|
||||||
#define __run_user_rf_pre_init _Z22__run_user_rf_pre_initv
|
#define __run_user_rf_pre_init _Z22__run_user_rf_pre_initv
|
||||||
|
|
||||||
static bool spoof_init_data = false;
|
static bool spoof_init_data = false;
|
||||||
|
|
||||||
extern int __real_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size);
|
extern int __real_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size);
|
||||||
extern int ICACHE_RAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size);
|
extern int ICACHE_RAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size);
|
||||||
extern int __get_adc_mode();
|
extern int __get_adc_mode();
|
||||||
|
|
||||||
extern int ICACHE_RAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size)
|
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);
|
{
|
||||||
|
return __real_spi_flash_read(addr, dst, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst, phy_init_data, sizeof(phy_init_data));
|
||||||
|
((uint8_t*)dst)[107] = __get_adc_mode();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dst, phy_init_data, sizeof(phy_init_data));
|
extern int __get_rf_mode(void) __attribute__((weak));
|
||||||
((uint8_t*)dst)[107] = __get_adc_mode();
|
extern int __get_rf_mode(void)
|
||||||
return 0;
|
{
|
||||||
}
|
return -1; // mode not set
|
||||||
|
}
|
||||||
extern int __get_rf_mode(void) __attribute__((weak));
|
|
||||||
extern int __get_rf_mode(void)
|
extern int __get_adc_mode(void) __attribute__((weak));
|
||||||
{
|
extern int __get_adc_mode(void)
|
||||||
return -1; // mode not set
|
{
|
||||||
}
|
return 33; // default ADC mode
|
||||||
|
}
|
||||||
extern int __get_adc_mode(void) __attribute__((weak));
|
|
||||||
extern int __get_adc_mode(void)
|
extern void __run_user_rf_pre_init(void) __attribute__((weak));
|
||||||
{
|
extern void __run_user_rf_pre_init(void)
|
||||||
return 33; // default ADC mode
|
{
|
||||||
}
|
return; // default do noting
|
||||||
|
}
|
||||||
extern void __run_user_rf_pre_init(void) __attribute__((weak));
|
|
||||||
extern void __run_user_rf_pre_init(void)
|
uint32_t user_rf_cal_sector_set(void)
|
||||||
{
|
{
|
||||||
return; // default do noting
|
spoof_init_data = true;
|
||||||
}
|
return flashchip->chip_size / SPI_FLASH_SEC_SIZE - 4;
|
||||||
|
}
|
||||||
uint32_t user_rf_cal_sector_set(void)
|
|
||||||
{
|
void user_rf_pre_init()
|
||||||
spoof_init_data = true;
|
{
|
||||||
return flashchip->chip_size/SPI_FLASH_SEC_SIZE - 4;
|
// *((volatile uint32_t*) 0x60000710) = 0;
|
||||||
}
|
spoof_init_data = false;
|
||||||
|
volatile uint32_t* rtc_reg = (volatile uint32_t*) 0x60001000;
|
||||||
void user_rf_pre_init()
|
rtc_reg[30] = 0;
|
||||||
{
|
|
||||||
// *((volatile uint32_t*) 0x60000710) = 0;
|
system_set_os_print(0);
|
||||||
spoof_init_data = false;
|
int rf_mode = __get_rf_mode();
|
||||||
volatile uint32_t* rtc_reg = (volatile uint32_t*) 0x60001000;
|
if (rf_mode >= 0)
|
||||||
rtc_reg[30] = 0;
|
{
|
||||||
|
system_phy_set_rfoption(rf_mode);
|
||||||
system_set_os_print(0);
|
}
|
||||||
int rf_mode = __get_rf_mode();
|
__run_user_rf_pre_init();
|
||||||
if (rf_mode >= 0) {
|
|
||||||
system_phy_set_rfoption(rf_mode);
|
|
||||||
}
|
}
|
||||||
__run_user_rf_pre_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR user_spi_flash_dio_to_qio_pre_init() {}
|
void ICACHE_RAM_ATTR user_spi_flash_dio_to_qio_pre_init() {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
postmortem.c - output of debug info on sketch crash
|
postmortem.c - output of debug info on sketch crash
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -35,223 +35,253 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
extern void __real_system_restart_local();
|
extern void __real_system_restart_local();
|
||||||
|
|
||||||
// These will be pointers to PROGMEM const strings
|
// These will be pointers to PROGMEM const strings
|
||||||
static const char* s_panic_file = 0;
|
static const char* s_panic_file = 0;
|
||||||
static int s_panic_line = 0;
|
static int s_panic_line = 0;
|
||||||
static const char* s_panic_func = 0;
|
static const char* s_panic_func = 0;
|
||||||
static const char* s_panic_what = 0;
|
static const char* s_panic_what = 0;
|
||||||
|
|
||||||
static bool s_abort_called = false;
|
static bool s_abort_called = false;
|
||||||
static const char* s_unhandled_exception = NULL;
|
static const char* s_unhandled_exception = NULL;
|
||||||
|
|
||||||
void abort() __attribute__((noreturn));
|
void abort() __attribute__((noreturn));
|
||||||
static void uart_write_char_d(char c);
|
static void uart_write_char_d(char c);
|
||||||
static void uart0_write_char_d(char c);
|
static void uart0_write_char_d(char c);
|
||||||
static void uart1_write_char_d(char c);
|
static void uart1_write_char_d(char c);
|
||||||
static void print_stack(uint32_t start, uint32_t end);
|
static void print_stack(uint32_t start, uint32_t end);
|
||||||
|
|
||||||
// From UMM, the last caller of a malloc/realloc/calloc which failed:
|
// From UMM, the last caller of a malloc/realloc/calloc which failed:
|
||||||
extern void *umm_last_fail_alloc_addr;
|
extern void *umm_last_fail_alloc_addr;
|
||||||
extern int umm_last_fail_alloc_size;
|
extern int umm_last_fail_alloc_size;
|
||||||
|
|
||||||
static void raise_exception() __attribute__((noreturn));
|
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) rst_info;
|
||||||
(void) stack_end;
|
(void) stack;
|
||||||
}
|
(void) stack_end;
|
||||||
|
|
||||||
extern void custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) __attribute__ ((weak, alias("__custom_crash_callback")));
|
|
||||||
|
|
||||||
|
|
||||||
// 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, ...) {
|
|
||||||
char destStr[160];
|
|
||||||
char *c = destStr;
|
|
||||||
va_list argPtr;
|
|
||||||
va_start(argPtr, str);
|
|
||||||
vsnprintf(destStr, sizeof(destStr), str, argPtr);
|
|
||||||
va_end(argPtr);
|
|
||||||
while (*c) {
|
|
||||||
ets_putc(*(c++));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void __wrap_system_restart_local() {
|
extern void custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end) __attribute__((weak, alias("__custom_crash_callback")));
|
||||||
register uint32_t sp asm("a1");
|
|
||||||
uint32_t sp_dump = sp;
|
|
||||||
|
|
||||||
if (gdb_present()) {
|
|
||||||
/* When GDBStub is present, exceptions are handled by GDBStub,
|
// Prints need to use our library function to allow for file and function
|
||||||
but Soft WDT will still call this function.
|
// to be safely accessed from flash. This function encapsulates snprintf()
|
||||||
Trigger an exception to break into GDB.
|
// [which by definition will 0-terminate] and dumping to the UART
|
||||||
TODO: check why gdb_do_break() or asm("break.n 0") do not
|
static void ets_printf_P(const char *str, ...)
|
||||||
break into GDB here. */
|
{
|
||||||
|
char destStr[160];
|
||||||
|
char *c = destStr;
|
||||||
|
va_list argPtr;
|
||||||
|
va_start(argPtr, str);
|
||||||
|
vsnprintf(destStr, sizeof(destStr), str, argPtr);
|
||||||
|
va_end(argPtr);
|
||||||
|
while (*c)
|
||||||
|
{
|
||||||
|
ets_putc(*(c++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_system_restart_local()
|
||||||
|
{
|
||||||
|
register uint32_t sp asm("a1");
|
||||||
|
uint32_t sp_dump = sp;
|
||||||
|
|
||||||
|
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.
|
||||||
|
TODO: check why gdb_do_break() or asm("break.n 0") do not
|
||||||
|
break into GDB here. */
|
||||||
|
raise_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rst_info rst_info;
|
||||||
|
memset(&rst_info, 0, sizeof(rst_info));
|
||||||
|
system_rtc_mem_read(0, &rst_info, sizeof(rst_info));
|
||||||
|
if (rst_info.reason != REASON_SOFT_WDT_RST &&
|
||||||
|
rst_info.reason != REASON_EXCEPTION_RST &&
|
||||||
|
rst_info.reason != REASON_WDT_RST)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
|
||||||
|
if (s_panic_what)
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
|
||||||
|
}
|
||||||
|
ets_putc('\n');
|
||||||
|
}
|
||||||
|
else if (s_unhandled_exception)
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
|
||||||
|
}
|
||||||
|
else if (s_abort_called)
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR("\nAbort called\n"));
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR("\nSoft WDT reset\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cont_stack_start = (uint32_t) & (g_pcont->stack);
|
||||||
|
uint32_t cont_stack_end = (uint32_t) g_pcont->stack_end;
|
||||||
|
uint32_t stack_end;
|
||||||
|
|
||||||
|
// amount of stack taken by interrupt or exception handler
|
||||||
|
// and everything up to __wrap_system_restart_local
|
||||||
|
// (determined empirically, might break)
|
||||||
|
uint32_t offset = 0;
|
||||||
|
if (rst_info.reason == REASON_SOFT_WDT_RST)
|
||||||
|
{
|
||||||
|
offset = 0x1b0;
|
||||||
|
}
|
||||||
|
else if (rst_info.reason == REASON_EXCEPTION_RST)
|
||||||
|
{
|
||||||
|
offset = 0x1a0;
|
||||||
|
}
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
// 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());
|
||||||
|
offset = 0; // No offset needed anymore, the exception info was stored in the bssl stack
|
||||||
|
sp_dump = stack_thunk_get_cont_sp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end)
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR("\nctx: cont\n"));
|
||||||
|
stack_end = cont_stack_end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR("\nctx: sys\n"));
|
||||||
|
stack_end = 0x3fffffb0;
|
||||||
|
// it's actually 0x3ffffff0, but the stuff below ets_run
|
||||||
|
// is likely not really relevant to the crash
|
||||||
|
}
|
||||||
|
|
||||||
|
ets_printf_P(PSTR("sp: %08x end: %08x offset: %04x\n"), sp_dump, stack_end, offset);
|
||||||
|
|
||||||
|
print_stack(sp_dump + offset, stack_end);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_crash_callback(&rst_info, sp_dump + offset, stack_end);
|
||||||
|
|
||||||
|
ets_delay_us(10000);
|
||||||
|
__real_system_restart_local();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
bool looksLikeStackFrame = (values[2] == pos + 0x10);
|
||||||
|
|
||||||
|
ets_printf_P(PSTR("%08x: %08x %08x %08x %08x %c\n"),
|
||||||
|
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame) ? '<' : ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
while (((USS(0) >> USTXC) & 0xff)) { }
|
||||||
|
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
USF(0) = '\r';
|
||||||
|
}
|
||||||
|
USF(0) = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uart1_write_char_d(char c)
|
||||||
|
{
|
||||||
|
while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
|
||||||
|
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
USF(1) = '\r';
|
||||||
|
}
|
||||||
|
USF(1) = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void raise_exception()
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("syscall");
|
||||||
|
while (1); // never reached, needed to satisfy "noreturn" attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
void abort()
|
||||||
|
{
|
||||||
|
s_abort_called = true;
|
||||||
raise_exception();
|
raise_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rst_info rst_info;
|
void __unhandled_exception(const char *str)
|
||||||
memset(&rst_info, 0, sizeof(rst_info));
|
|
||||||
system_rtc_mem_read(0, &rst_info, sizeof(rst_info));
|
|
||||||
if (rst_info.reason != REASON_SOFT_WDT_RST &&
|
|
||||||
rst_info.reason != REASON_EXCEPTION_RST &&
|
|
||||||
rst_info.reason != REASON_WDT_RST)
|
|
||||||
{
|
{
|
||||||
return;
|
s_unhandled_exception = str;
|
||||||
|
raise_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ets_install_putc1 definition is wrong in ets_sys.h, need cast
|
void __assert_func(const char *file, int line, const char *func, const char *what)
|
||||||
ets_install_putc1((void *)&uart_write_char_d);
|
{
|
||||||
|
s_panic_file = file;
|
||||||
if (s_panic_line) {
|
s_panic_line = line;
|
||||||
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
|
s_panic_func = func;
|
||||||
if (s_panic_what) {
|
s_panic_what = what;
|
||||||
ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
|
gdb_do_break(); /* if GDB is not present, this is a no-op */
|
||||||
}
|
raise_exception();
|
||||||
ets_putc('\n');
|
|
||||||
}
|
|
||||||
else if (s_unhandled_exception) {
|
|
||||||
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
|
|
||||||
}
|
|
||||||
else if (s_abort_called) {
|
|
||||||
ets_printf_P(PSTR("\nAbort called\n"));
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
ets_printf_P(PSTR("\nSoft WDT reset\n"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cont_stack_start = (uint32_t) &(g_pcont->stack);
|
void __panic_func(const char* file, int line, const char* func)
|
||||||
uint32_t cont_stack_end = (uint32_t) g_pcont->stack_end;
|
{
|
||||||
uint32_t stack_end;
|
s_panic_file = file;
|
||||||
|
s_panic_line = line;
|
||||||
// amount of stack taken by interrupt or exception handler
|
s_panic_func = func;
|
||||||
// and everything up to __wrap_system_restart_local
|
s_panic_what = 0;
|
||||||
// (determined empirically, might break)
|
gdb_do_break(); /* if GDB is not present, this is a no-op */
|
||||||
uint32_t offset = 0;
|
raise_exception();
|
||||||
if (rst_info.reason == REASON_SOFT_WDT_RST) {
|
|
||||||
offset = 0x1b0;
|
|
||||||
}
|
}
|
||||||
else if (rst_info.reason == REASON_EXCEPTION_RST) {
|
|
||||||
offset = 0x1a0;
|
|
||||||
}
|
|
||||||
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()) {
|
|
||||||
// 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());
|
|
||||||
offset = 0; // No offset needed anymore, the exception info was stored in the bssl stack
|
|
||||||
sp_dump = stack_thunk_get_cont_sp();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end) {
|
|
||||||
ets_printf_P(PSTR("\nctx: cont\n"));
|
|
||||||
stack_end = cont_stack_end;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ets_printf_P(PSTR("\nctx: sys\n"));
|
|
||||||
stack_end = 0x3fffffb0;
|
|
||||||
// it's actually 0x3ffffff0, but the stuff below ets_run
|
|
||||||
// is likely not really relevant to the crash
|
|
||||||
}
|
|
||||||
|
|
||||||
ets_printf_P(PSTR("sp: %08x end: %08x offset: %04x\n"), sp_dump, stack_end, offset);
|
|
||||||
|
|
||||||
print_stack(sp_dump + offset, stack_end);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
custom_crash_callback( &rst_info, sp_dump + offset, stack_end );
|
|
||||||
|
|
||||||
ets_delay_us(10000);
|
|
||||||
__real_system_restart_local();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
bool looksLikeStackFrame = (values[2] == pos + 0x10);
|
|
||||||
|
|
||||||
ets_printf_P(PSTR("%08x: %08x %08x %08x %08x %c\n"),
|
|
||||||
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
while (((USS(0) >> USTXC) & 0xff)) { }
|
|
||||||
|
|
||||||
if (c == '\n') {
|
|
||||||
USF(0) = '\r';
|
|
||||||
}
|
|
||||||
USF(0) = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uart1_write_char_d(char c) {
|
|
||||||
while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
|
|
||||||
|
|
||||||
if (c == '\n') {
|
|
||||||
USF(1) = '\r';
|
|
||||||
}
|
|
||||||
USF(1) = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void raise_exception() {
|
|
||||||
__asm__ __volatile__ ("syscall");
|
|
||||||
while (1); // never reached, needed to satisfy "noreturn" attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
void abort() {
|
|
||||||
s_abort_called = true;
|
|
||||||
raise_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
s_panic_file = file;
|
|
||||||
s_panic_line = line;
|
|
||||||
s_panic_func = func;
|
|
||||||
s_panic_what = what;
|
|
||||||
gdb_do_break(); /* if GDB is not present, this is a no-op */
|
|
||||||
raise_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
void __panic_func(const char* file, int line, const char* func) {
|
|
||||||
s_panic_file = file;
|
|
||||||
s_panic_line = line;
|
|
||||||
s_panic_func = func;
|
|
||||||
s_panic_what = 0;
|
|
||||||
gdb_do_break(); /* if GDB is not present, this is a no-op */
|
|
||||||
raise_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,178 +1,184 @@
|
|||||||
/*
|
/*
|
||||||
core_esp8266_sigma_delta.c - sigma delta library for esp8266
|
core_esp8266_sigma_delta.c - sigma delta library for esp8266
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
modify it under the terms of the GNU Lesser General Public
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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" // using pinMode
|
#include "Arduino.h" // using pinMode
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
// definitions in esp8266_peri.h style
|
// definitions in esp8266_peri.h style
|
||||||
#define GPSD ESP8266_REG(0x368) // GPIO_SIGMA_DELTA register @ 0x600000368
|
#define GPSD ESP8266_REG(0x368) // GPIO_SIGMA_DELTA register @ 0x600000368
|
||||||
#define GPSDT 0 // target, 8 bits
|
#define GPSDT 0 // target, 8 bits
|
||||||
#define GPSDP 8 // prescaler, 8 bits
|
#define GPSDP 8 // prescaler, 8 bits
|
||||||
#define GPSDE 16 // enable
|
#define GPSDE 16 // enable
|
||||||
|
|
||||||
void sigmaDeltaSetPrescaler(uint8_t prescaler); // avoids compiler warning
|
void sigmaDeltaSetPrescaler(uint8_t prescaler); // avoids compiler warning
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : sigmaDeltaEnable
|
FunctionName : sigmaDeltaEnable
|
||||||
* Description : enable the internal sigma delta source
|
Description : enable the internal sigma delta source
|
||||||
* Parameters : none
|
Parameters : none
|
||||||
* Returns : none
|
Returns : none
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
void ICACHE_FLASH_ATTR sigmaDeltaEnable()
|
void ICACHE_FLASH_ATTR sigmaDeltaEnable()
|
||||||
{
|
{
|
||||||
GPSD = (0 << GPSDT) | (0 << GPSDP) | (1 << GPSDE); //SIGMA_DELTA_TARGET(0) | SIGMA_DELTA_PRESCALER(0) | SIGMA_DELTA_ENABLE(ENABLED)
|
GPSD = (0 << GPSDT) | (0 << GPSDP) | (1 << GPSDE); //SIGMA_DELTA_TARGET(0) | SIGMA_DELTA_PRESCALER(0) | SIGMA_DELTA_ENABLE(ENABLED)
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : sigmaDeltaDisable
|
FunctionName : sigmaDeltaDisable
|
||||||
* Description : stop the internal sigma delta source
|
Description : stop the internal sigma delta source
|
||||||
* Parameters : none
|
Parameters : none
|
||||||
* Returns : none
|
Returns : none
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
void ICACHE_FLASH_ATTR sigmaDeltaDisable()
|
void ICACHE_FLASH_ATTR sigmaDeltaDisable()
|
||||||
{
|
{
|
||||||
GPSD = (0 << GPSDT) | (0 << GPSDP) | (0 << GPSDE); //SIGMA_DELTA_TARGET(0) | SIGMA_DELTA_PRESCALER(0) | SIGMA_DELTA_ENABLE(DISABLED)
|
GPSD = (0 << GPSDT) | (0 << GPSDP) | (0 << GPSDE); //SIGMA_DELTA_TARGET(0) | SIGMA_DELTA_PRESCALER(0) | SIGMA_DELTA_ENABLE(DISABLED)
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : sigmaDeltaAttachPin
|
FunctionName : sigmaDeltaAttachPin
|
||||||
* Description : connects the sigma delta source to a physical output pin
|
Description : connects the sigma delta source to a physical output pin
|
||||||
* Parameters : pin (0..15), channel = unused, for compatibility with ESP32
|
Parameters : pin (0..15), channel = unused, for compatibility with ESP32
|
||||||
* Returns : none
|
Returns : none
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
void ICACHE_FLASH_ATTR sigmaDeltaAttachPin(uint8_t pin, uint8_t channel)
|
void ICACHE_FLASH_ATTR sigmaDeltaAttachPin(uint8_t pin, uint8_t channel)
|
||||||
{
|
{
|
||||||
(void) channel;
|
(void) channel;
|
||||||
// make the chosen pin an output pin
|
// make the chosen pin an output pin
|
||||||
pinMode (pin, OUTPUT);
|
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
|
// set its source to the sigma delta source
|
||||||
}
|
GPC(pin) |= (1 << GPCS); //SOURCE 0:GPIO_DATA,1:SigmaDelta
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : sigmaDeltaDetachPin
|
FunctionName : sigmaDeltaDetachPin
|
||||||
* Description : disconnects the sigma delta source from a physical output pin
|
Description : disconnects the sigma delta source from a physical output pin
|
||||||
* Parameters : pin (0..16)
|
Parameters : pin (0..16)
|
||||||
* Returns : none
|
Returns : none
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
void ICACHE_FLASH_ATTR sigmaDeltaDetachPin(uint8_t pin)
|
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
|
// set its source to the sigma delta source
|
||||||
}
|
GPC(pin) &= ~(1 << GPCS); //SOURCE 0:GPIO_DATA,1:SigmaDelta
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : sigmaDeltaIsPinAttached
|
FunctionName : sigmaDeltaIsPinAttached
|
||||||
* Description : query if pin is attached
|
Description : query if pin is attached
|
||||||
* Parameters : pin (0..16)
|
Parameters : pin (0..16)
|
||||||
* Returns : bool
|
Returns : bool
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
bool ICACHE_FLASH_ATTR sigmaDeltaIsPinAttached(uint8_t pin)
|
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
|
// set its source to the sigma delta source
|
||||||
}
|
return (GPC(pin) & (1 << GPCS)); //SOURCE 0:GPIO_DATA,1:SigmaDelta
|
||||||
else
|
}
|
||||||
return false;
|
else
|
||||||
}
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : sigmaDeltaSetup
|
FunctionName : sigmaDeltaSetup
|
||||||
* Description : start the sigma delta generator with the chosen parameters
|
Description : start the sigma delta generator with the chosen parameters
|
||||||
* Parameters : channel = unused (for compatibility with ESP32),
|
Parameters : channel = unused (for compatibility with ESP32),
|
||||||
* freq : 1220-312500 (lowest frequency in the output signal's spectrum)
|
freq : 1220-312500 (lowest frequency in the output signal's spectrum)
|
||||||
* Returns : uint32_t the actual frequency, closest to the input parameter
|
Returns : uint32_t the actual frequency, closest to the input parameter
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
uint32_t ICACHE_FLASH_ATTR sigmaDeltaSetup(uint8_t channel, uint32_t freq)
|
uint32_t ICACHE_FLASH_ATTR sigmaDeltaSetup(uint8_t channel, uint32_t freq)
|
||||||
{
|
{
|
||||||
(void) channel;
|
(void) channel;
|
||||||
|
|
||||||
uint32_t prescaler = ((uint32_t)10000000/(freq*32)) - 1;
|
|
||||||
|
|
||||||
if(prescaler > 0xFF) {
|
|
||||||
prescaler = 0xFF;
|
|
||||||
}
|
|
||||||
sigmaDeltaEnable();
|
|
||||||
sigmaDeltaSetPrescaler ((uint8_t) prescaler);
|
|
||||||
|
|
||||||
return 10000000/((prescaler + 1) * 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
uint32_t prescaler = ((uint32_t)10000000 / (freq * 32)) - 1;
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
uint32_t reg = GPSD;
|
|
||||||
(void) channel;
|
|
||||||
|
|
||||||
reg = (reg & ~(0xFF << GPSDT)) | ((duty & 0xFF) << GPSDT);
|
if (prescaler > 0xFF)
|
||||||
GPSD = reg;
|
{
|
||||||
|
prescaler = 0xFF;
|
||||||
}
|
}
|
||||||
/******************************************************************************
|
sigmaDeltaEnable();
|
||||||
* FunctionName : sigmaDeltaRead
|
sigmaDeltaSetPrescaler((uint8_t) prescaler);
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
(void) channel;
|
|
||||||
return (uint8_t)((GPSD >> GPSDT) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
return 10000000 / ((prescaler + 1) * 32);
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
uint32_t reg = GPSD;
|
|
||||||
|
|
||||||
reg = (reg & ~(0xFF << GPSDP)) | ((prescaler & 0xFF) << GPSDP);
|
/******************************************************************************
|
||||||
GPSD = reg;
|
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)
|
||||||
|
{
|
||||||
|
uint32_t reg = GPSD;
|
||||||
|
(void) channel;
|
||||||
|
|
||||||
/******************************************************************************
|
reg = (reg & ~(0xFF << GPSDT)) | ((duty & 0xFF) << GPSDT);
|
||||||
* FunctionName : sigmaDeltaGetPrescaler
|
GPSD = reg;
|
||||||
* Description : get the prescaler value from the GPIO_SIGMA_DELTA register
|
|
||||||
* Parameters : none
|
}
|
||||||
* Returns : uint8 prescaler, CLK_DIV , 0-255
|
/******************************************************************************
|
||||||
*******************************************************************************/
|
FunctionName : sigmaDeltaRead
|
||||||
uint8_t ICACHE_FLASH_ATTR sigmaDeltaGetPrescaler(void)
|
Description : get the duty cycle for the sigma-delta source
|
||||||
{
|
Parameters : channel = unused, for compatibility with ESP32
|
||||||
return (uint8_t)((GPSD >> GPSDP) & 0xFF);
|
Returns : uint8_t duty cycle value 0..255
|
||||||
}
|
*******************************************************************************/
|
||||||
|
uint8_t ICACHE_FLASH_ATTR sigmaDeltaRead(uint8_t channel)
|
||||||
|
{
|
||||||
|
(void) channel;
|
||||||
|
return (uint8_t)((GPSD >> GPSDT) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
uint32_t reg = GPSD;
|
||||||
|
|
||||||
|
reg = (reg & ~(0xFF << GPSDP)) | ((prescaler & 0xFF) << GPSDP);
|
||||||
|
GPSD = reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return (uint8_t)((GPSD >> GPSDP) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
timer.c - Timer1 library for esp8266
|
timer.c - Timer1 library for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include "wiring_private.h"
|
#include "wiring_private.h"
|
||||||
#include "pins_arduino.h"
|
#include "pins_arduino.h"
|
||||||
@ -26,82 +26,101 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
// ------------------------------------------------------------------ -
|
// ------------------------------------------------------------------ -
|
||||||
// timer 1
|
// timer 1
|
||||||
|
|
||||||
static volatile timercallback timer1_user_cb = NULL;
|
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
|
(void) para;
|
||||||
T1I = 0;
|
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0)
|
||||||
if (timer1_user_cb) {
|
{
|
||||||
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
TEIE &= ~TEIE1; //edge int disable
|
||||||
// we disable them before we call the client ISR
|
}
|
||||||
uint32_t savedPS = xt_rsil(15); // stop other interrupts
|
T1I = 0;
|
||||||
timer1_user_cb();
|
if (timer1_user_cb)
|
||||||
xt_wsr_ps(savedPS);
|
{
|
||||||
|
// 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
|
||||||
|
timer1_user_cb();
|
||||||
|
xt_wsr_ps(savedPS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR timer1_isr_init(){
|
void ICACHE_RAM_ATTR timer1_isr_init()
|
||||||
ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL);
|
{
|
||||||
}
|
ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL);
|
||||||
|
|
||||||
void timer1_attachInterrupt(timercallback userFunc) {
|
|
||||||
timer1_user_cb = userFunc;
|
|
||||||
ETS_FRC1_INTR_ENABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
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){
|
|
||||||
T1C = (1 << TCTE) | ((divider & 3) << TCPD) | ((int_type & 1) << TCIT) | ((reload & 1) << TCAR);
|
|
||||||
T1I = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR timer1_write(uint32_t ticks){
|
|
||||||
T1L = ((ticks)& 0x7FFFFF);
|
|
||||||
if ((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR timer1_disable(){
|
|
||||||
T1C = 0;
|
|
||||||
T1I = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
// timer 0
|
|
||||||
|
|
||||||
static volatile timercallback timer0_user_cb = NULL;
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR timer0_isr_handler(void* para){
|
|
||||||
(void) para;
|
|
||||||
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
|
|
||||||
timer0_user_cb();
|
|
||||||
xt_wsr_ps(savedPS);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void timer0_isr_init(){
|
void timer1_attachInterrupt(timercallback userFunc)
|
||||||
ETS_CCOMPARE0_INTR_ATTACH(timer0_isr_handler, NULL);
|
{
|
||||||
}
|
timer1_user_cb = userFunc;
|
||||||
|
ETS_FRC1_INTR_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
void timer0_attachInterrupt(timercallback userFunc) {
|
void ICACHE_RAM_ATTR timer1_detachInterrupt()
|
||||||
timer0_user_cb = userFunc;
|
{
|
||||||
ETS_CCOMPARE0_ENABLE();
|
timer1_user_cb = 0;
|
||||||
}
|
TEIE &= ~TEIE1;//edge int disable
|
||||||
|
ETS_FRC1_INTR_DISABLE();
|
||||||
|
}
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR timer0_detachInterrupt() {
|
void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload)
|
||||||
timer0_user_cb = NULL;
|
{
|
||||||
ETS_CCOMPARE0_DISABLE();
|
T1C = (1 << TCTE) | ((divider & 3) << TCPD) | ((int_type & 1) << TCIT) | ((reload & 1) << TCAR);
|
||||||
}
|
T1I = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR timer1_write(uint32_t ticks)
|
||||||
|
{
|
||||||
|
T1L = ((ticks) & 0x7FFFFF);
|
||||||
|
if ((T1C & (1 << TCIT)) == 0)
|
||||||
|
{
|
||||||
|
TEIE |= TEIE1; //edge int enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR timer1_disable()
|
||||||
|
{
|
||||||
|
T1C = 0;
|
||||||
|
T1I = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// timer 0
|
||||||
|
|
||||||
|
static volatile timercallback timer0_user_cb = NULL;
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR timer0_isr_handler(void* para)
|
||||||
|
{
|
||||||
|
(void) para;
|
||||||
|
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
|
||||||
|
timer0_user_cb();
|
||||||
|
xt_wsr_ps(savedPS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer0_isr_init()
|
||||||
|
{
|
||||||
|
ETS_CCOMPARE0_INTR_ATTACH(timer0_isr_handler, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer0_attachInterrupt(timercallback userFunc)
|
||||||
|
{
|
||||||
|
timer0_user_cb = userFunc;
|
||||||
|
ETS_CCOMPARE0_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR timer0_detachInterrupt()
|
||||||
|
{
|
||||||
|
timer0_user_cb = NULL;
|
||||||
|
ETS_CCOMPARE0_DISABLE();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
core_esp8266_version.h - parse "git describe" at compile time
|
core_esp8266_version.h - parse "git describe" at compile time
|
||||||
Copyright (c) 2018 david gauchard. All rights reserved.
|
Copyright (c) 2018 david gauchard. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CORE_ESP8266_VERSION_H
|
#ifndef __CORE_ESP8266_VERSION_H
|
||||||
@ -33,148 +33,152 @@
|
|||||||
extern "C++"
|
extern "C++"
|
||||||
{
|
{
|
||||||
|
|
||||||
// Following constexpr functions are compiled and executed
|
// Following constexpr functions are compiled and executed
|
||||||
// *after* pre-processing and *during* compilation
|
// *after* pre-processing and *during* compilation
|
||||||
//
|
//
|
||||||
// Their result is treated like a numeric constant in final binary code.
|
// Their result is treated like a numeric constant in final binary code.
|
||||||
// git tags must be in the form:
|
// git tags must be in the form:
|
||||||
// - <major>.<minor>.<revision> (2.4.2) (2.5.0)
|
// - <major>.<minor>.<revision> (2.4.2) (2.5.0)
|
||||||
// - <major>.<minor>.<revision>-rc<rc> (2.5.0-rc1) (2.5.0-rc2)
|
// - <major>.<minor>.<revision>-rc<rc> (2.5.0-rc1) (2.5.0-rc2)
|
||||||
//
|
//
|
||||||
// "git describe" = ARDUINO_ESP8266_GIT_DESC will thus be in the form:
|
// "git describe" = ARDUINO_ESP8266_GIT_DESC will thus be in the form:
|
||||||
// - <tag> (2.4.2) (2.5.0)
|
// - <tag> (2.4.2) (2.5.0)
|
||||||
// - <tag>-<numberOfCommits>-g<git-hash> (2.4.2-91-gcb05b86d) (2.5.0-rc3-1-gcb05b86d)
|
// - <tag>-<numberOfCommits>-g<git-hash> (2.4.2-91-gcb05b86d) (2.5.0-rc3-1-gcb05b86d)
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// case 2.4.2 (fresh version/tag)
|
// case 2.4.2 (fresh version/tag)
|
||||||
// esp8266CoreVersionSubRevision() is 0 Numeric is: 20402000
|
// esp8266CoreVersionSubRevision() is 0 Numeric is: 20402000
|
||||||
// case 2.4.2-91-gcb05b86d:
|
// case 2.4.2-91-gcb05b86d:
|
||||||
// esp8266CoreVersionSubRevision() is -91 Numeric is: 20402091
|
// esp8266CoreVersionSubRevision() is -91 Numeric is: 20402091
|
||||||
// case 2.5.0-rc3-1-gcb05b86d:
|
// case 2.5.0-rc3-1-gcb05b86d:
|
||||||
// esp8266CoreVersionSubRevision() is 3 Numeric is: 20499903
|
// esp8266CoreVersionSubRevision() is 3 Numeric is: 20499903
|
||||||
// case 2.5.0:
|
// case 2.5.0:
|
||||||
// esp8266CoreVersionSubRevision() is 0 Numeric is: 20500000
|
// esp8266CoreVersionSubRevision() is 0 Numeric is: 20500000
|
||||||
//
|
//
|
||||||
// Using esp8266::coreVersionNumeric() in a portable way:
|
// Using esp8266::coreVersionNumeric() in a portable way:
|
||||||
//
|
//
|
||||||
// #if HAS_ESP8266_VERSION_NUMERIC
|
// #if HAS_ESP8266_VERSION_NUMERIC
|
||||||
// if (esp8266::coreVersionNumeric() >= 20500042)
|
// if (esp8266::coreVersionNumeric() >= 20500042)
|
||||||
// {
|
// {
|
||||||
// // modern api can be used
|
// // modern api can be used
|
||||||
// }
|
// }
|
||||||
// else
|
// else
|
||||||
// #endif
|
// #endif
|
||||||
// {
|
// {
|
||||||
// // code using older api
|
// // code using older api
|
||||||
// // (will not be compiled in when newer api is usable)
|
// // (will not be compiled in when newer api is usable)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
namespace conststr {
|
namespace conststr {
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
bool isDecimal (const char c)
|
bool isDecimal(const char c)
|
||||||
{
|
{
|
||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned N> constexpr
|
template<unsigned N> constexpr
|
||||||
bool isMinus (const char (&arr) [N], unsigned i)
|
bool isMinus(const char (&arr) [N], unsigned i)
|
||||||
{
|
{
|
||||||
return arr[i] == '-' && isDecimal(arr[i+1]);
|
return arr[i] == '-' && isDecimal(arr[i + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned N> constexpr
|
template<unsigned N> constexpr
|
||||||
int atoi (const char (&arr) [N], unsigned i)
|
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] == '-')
|
|
||||||
{
|
{
|
||||||
sign = -1;
|
int ret = 0;
|
||||||
i++;
|
int sign = 1;
|
||||||
}
|
if (arr[i] == '-')
|
||||||
while (isDecimal(arr[i]))
|
{
|
||||||
ret = 10*ret + arr[i++] - '0';
|
sign = -1;
|
||||||
ret * sign;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned N> constexpr
|
|
||||||
int parseNthInteger (const char (&arr) [N], unsigned f)
|
|
||||||
{
|
|
||||||
return ({ // <= c++11 requires a "return statement"
|
|
||||||
unsigned i = 0;
|
|
||||||
while (f && arr[i])
|
|
||||||
{
|
|
||||||
if (isMinus(arr, i))
|
|
||||||
i++;
|
i++;
|
||||||
for (; isDecimal(arr[i]); i++);
|
}
|
||||||
f--;
|
while (isDecimal(arr[i]))
|
||||||
for (; arr[i] && !isMinus(arr, i) && !isDecimal(arr[i]); i++);
|
ret = 10 * ret + arr[i++] - '0';
|
||||||
}
|
ret * sign;
|
||||||
atoi(arr, i);
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace conststr
|
template<unsigned N> constexpr
|
||||||
|
int parseNthInteger(const char (&arr) [N], unsigned f)
|
||||||
|
{
|
||||||
|
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++);
|
||||||
|
}
|
||||||
|
atoi(arr, i);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
namespace esp8266 {
|
}; // namespace conststr
|
||||||
|
|
||||||
/*
|
namespace esp8266 {
|
||||||
* version major
|
|
||||||
*/
|
|
||||||
constexpr
|
|
||||||
int coreVersionMajor ()
|
|
||||||
{
|
|
||||||
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* version minor
|
version major
|
||||||
*/
|
*/
|
||||||
constexpr
|
constexpr
|
||||||
int coreVersionMinor ()
|
int coreVersionMajor()
|
||||||
{
|
{
|
||||||
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 1);
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* version revision
|
version minor
|
||||||
*/
|
*/
|
||||||
constexpr
|
constexpr
|
||||||
int coreVersionRevision ()
|
int coreVersionMinor()
|
||||||
{
|
{
|
||||||
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 2);
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* git commit number since last tag (negative)
|
version revision
|
||||||
* or RC-number (positive)
|
*/
|
||||||
*/
|
constexpr
|
||||||
constexpr
|
int coreVersionRevision()
|
||||||
int coreVersionSubRevision ()
|
{
|
||||||
{
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 2);
|
||||||
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 3);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* unique revision indentifier (never decreases)
|
git commit number since last tag (negative)
|
||||||
*/
|
or RC-number (positive)
|
||||||
constexpr
|
*/
|
||||||
int coreVersionNumeric ()
|
constexpr
|
||||||
{
|
int coreVersionSubRevision()
|
||||||
return coreVersionMajor() * 10000000
|
{
|
||||||
+ coreVersionMinor() * 100000
|
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 3);
|
||||||
+ coreVersionRevision() * 1000
|
}
|
||||||
+ (coreVersionSubRevision() < 0 ?
|
|
||||||
-coreVersionSubRevision() :
|
|
||||||
coreVersionSubRevision() ?
|
|
||||||
coreVersionSubRevision() - 100 :
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace esp8266
|
/*
|
||||||
|
unique revision indentifier (never decreases)
|
||||||
|
*/
|
||||||
|
constexpr
|
||||||
|
int coreVersionNumeric()
|
||||||
|
{
|
||||||
|
return coreVersionMajor() * 10000000
|
||||||
|
+ coreVersionMinor() * 100000
|
||||||
|
+ coreVersionRevision() * 1000
|
||||||
|
+ (coreVersionSubRevision() < 0 ?
|
||||||
|
-coreVersionSubRevision() :
|
||||||
|
coreVersionSubRevision() ?
|
||||||
|
coreVersionSubRevision() - 100 :
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace esp8266
|
||||||
|
|
||||||
} // extern "C++"
|
} // extern "C++"
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
/*
|
/*
|
||||||
esp8266_waveform - General purpose waveform generation and control,
|
esp8266_waveform - General purpose waveform generation and control,
|
||||||
supporting outputs on all pins in parallel.
|
supporting outputs on all pins in parallel.
|
||||||
|
|
||||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
The core idea is to have a programmable waveform generator with a unique
|
The core idea is to have a programmable waveform generator with a unique
|
||||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||||
mode and is always loaded with the time until the next edge of any live
|
mode and is always loaded with the time until the next edge of any live
|
||||||
waveforms.
|
waveforms.
|
||||||
|
|
||||||
Up to one waveform generator per pin supported.
|
Up to one waveform generator per pin supported.
|
||||||
|
|
||||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||||
timer. This allows for removing interrupt jitter and delay as the counter
|
timer. This allows for removing interrupt jitter and delay as the counter
|
||||||
always increments once per 80MHz clock. Changes to a waveform are
|
always increments once per 80MHz clock. Changes to a waveform are
|
||||||
contiguous and only take effect on the next waveform transition,
|
contiguous and only take effect on the next waveform transition,
|
||||||
allowing for smooth transitions.
|
allowing for smooth transitions.
|
||||||
|
|
||||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||||
|
|
||||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@ -43,267 +43,318 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
// Maximum delay between IRQs
|
// Maximum delay between IRQs
|
||||||
#define MAXIRQUS (10000)
|
#define MAXIRQUS (10000)
|
||||||
|
|
||||||
// Set/clear GPIO 0-15 by bitmask
|
// Set/clear GPIO 0-15 by bitmask
|
||||||
#define SetGPIO(a) do { GPOS = a; } while (0)
|
#define SetGPIO(a) do { GPOS = a; } while (0)
|
||||||
#define ClearGPIO(a) do { GPOC = a; } while (0)
|
#define ClearGPIO(a) do { GPOC = a; } while (0)
|
||||||
|
|
||||||
// Waveform generator can create tones, PWM, and servos
|
// 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 nextServiceCycle; // ESP cycle timer when a transition required
|
||||||
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
|
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
|
||||||
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
|
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
|
||||||
} Waveform;
|
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
|
||||||
|
} Waveform;
|
||||||
|
|
||||||
static Waveform waveform[17]; // State of all possible pins
|
static Waveform waveform[17]; // State of all possible pins
|
||||||
static volatile uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
static volatile uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
||||||
static volatile uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
static volatile uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
||||||
|
|
||||||
// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine
|
// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine
|
||||||
static volatile uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin
|
static volatile uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin
|
||||||
static volatile uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation
|
static volatile uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation
|
||||||
|
|
||||||
static uint32_t (*timer1CB)() = NULL;
|
static uint32_t (*timer1CB)() = NULL;
|
||||||
|
|
||||||
|
|
||||||
// Non-speed critical bits
|
// Non-speed critical bits
|
||||||
#pragma GCC optimize ("Os")
|
#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));
|
uint32_t ccount;
|
||||||
return ccount;
|
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
|
||||||
}
|
return ccount;
|
||||||
|
|
||||||
// Interrupt on/off control
|
|
||||||
static ICACHE_RAM_ATTR void timer1Interrupt();
|
|
||||||
static bool timerRunning = false;
|
|
||||||
|
|
||||||
static void initTimer() {
|
|
||||||
timer1_disable();
|
|
||||||
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
|
||||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
|
||||||
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
|
|
||||||
timerRunning = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ICACHE_RAM_ATTR deinitTimer() {
|
|
||||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
|
||||||
timer1_disable();
|
|
||||||
timer1_isr_init();
|
|
||||||
timerRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a callback. Pass in NULL to stop it
|
|
||||||
void setTimer1Callback(uint32_t (*fn)()) {
|
|
||||||
timer1CB = fn;
|
|
||||||
if (!timerRunning && fn) {
|
|
||||||
initTimer();
|
|
||||||
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
|
|
||||||
} else if (timerRunning && !fn && !waveformEnabled) {
|
|
||||||
deinitTimer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Waveform *wave = &waveform[pin];
|
|
||||||
// Adjust to shave off some of the IRQ time, approximately
|
|
||||||
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
|
|
||||||
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
|
|
||||||
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
|
|
||||||
if (runTimeUS && !wave->expiryCycle) {
|
|
||||||
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t mask = 1<<pin;
|
|
||||||
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) {
|
|
||||||
initTimer();
|
|
||||||
timer1_write(microsecondsToClockCycles(10));
|
|
||||||
} else {
|
|
||||||
// Ensure timely service....
|
|
||||||
if (T1L > microsecondsToClockCycles(10)) {
|
|
||||||
timer1_write(microsecondsToClockCycles(10));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
while (waveformToEnable) {
|
|
||||||
delay(0); // Wait for waveform to update
|
// Interrupt on/off control
|
||||||
|
static ICACHE_RAM_ATTR void timer1Interrupt();
|
||||||
|
static bool timerRunning = false;
|
||||||
|
|
||||||
|
static void initTimer()
|
||||||
|
{
|
||||||
|
timer1_disable();
|
||||||
|
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||||
|
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
||||||
|
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
|
||||||
|
timerRunning = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
static void ICACHE_RAM_ATTR deinitTimer()
|
||||||
}
|
{
|
||||||
|
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||||
|
timer1_disable();
|
||||||
|
timer1_isr_init();
|
||||||
|
timerRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Speed critical bits
|
// Set a callback. Pass in NULL to stop it
|
||||||
|
void setTimer1Callback(uint32_t (*fn)())
|
||||||
|
{
|
||||||
|
timer1CB = fn;
|
||||||
|
if (!timerRunning && fn)
|
||||||
|
{
|
||||||
|
initTimer();
|
||||||
|
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
|
||||||
|
}
|
||||||
|
else if (timerRunning && !fn && !waveformEnabled)
|
||||||
|
{
|
||||||
|
deinitTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Waveform *wave = &waveform[pin];
|
||||||
|
// Adjust to shave off some of the IRQ time, approximately
|
||||||
|
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
|
||||||
|
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
|
||||||
|
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
|
||||||
|
if (runTimeUS && !wave->expiryCycle)
|
||||||
|
{
|
||||||
|
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mask = 1 << pin;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
initTimer();
|
||||||
|
timer1_write(microsecondsToClockCycles(10));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ensure timely service....
|
||||||
|
if (T1L > microsecondsToClockCycles(10))
|
||||||
|
{
|
||||||
|
timer1_write(microsecondsToClockCycles(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (waveformToEnable)
|
||||||
|
{
|
||||||
|
delay(0); // Wait for waveform to update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speed critical bits
|
||||||
#pragma GCC optimize ("O2")
|
#pragma GCC optimize ("O2")
|
||||||
// Normally would not want two copies like this, but due to different
|
// Normally would not want two copies like this, but due to different
|
||||||
// optimization levels the inline attribute gets lost if we try the
|
// optimization levels the inline attribute gets lost if we try the
|
||||||
// other version.
|
// 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));
|
uint32_t ccount;
|
||||||
return 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) {
|
static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b)
|
||||||
if (a < b) {
|
{
|
||||||
return a;
|
if (a < b)
|
||||||
}
|
{
|
||||||
return b;
|
return a;
|
||||||
}
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
// Stops a waveform on a pin
|
// 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) {
|
// Can't possibly need to stop anything if there is no timer active
|
||||||
return false;
|
if (!timerRunning)
|
||||||
}
|
{
|
||||||
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
return false;
|
||||||
// If they send >=32, then the shift will result in 0 and it will also return false
|
}
|
||||||
uint32_t mask = 1<<pin;
|
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
||||||
if (!(waveformEnabled & mask)) {
|
// If they send >=32, then the shift will result in 0 and it will also return false
|
||||||
return false; // It's not running, nothing to do here
|
uint32_t mask = 1 << pin;
|
||||||
}
|
if (!(waveformEnabled & mask))
|
||||||
waveformToDisable |= mask;
|
{
|
||||||
// Ensure timely service....
|
return false; // It's not running, nothing to do here
|
||||||
if (T1L > microsecondsToClockCycles(10)) {
|
}
|
||||||
timer1_write(microsecondsToClockCycles(10));
|
waveformToDisable |= mask;
|
||||||
}
|
// Ensure timely service....
|
||||||
while (waveformToDisable) {
|
if (T1L > microsecondsToClockCycles(10))
|
||||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
{
|
||||||
}
|
timer1_write(microsecondsToClockCycles(10));
|
||||||
if (!waveformEnabled && !timer1CB) {
|
}
|
||||||
deinitTimer();
|
while (waveformToDisable)
|
||||||
}
|
{
|
||||||
return true;
|
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||||
}
|
}
|
||||||
|
if (!waveformEnabled && !timer1CB)
|
||||||
|
{
|
||||||
|
deinitTimer();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// The SDK and hardware take some time to actually get to our NMI code, so
|
// The SDK and hardware take some time to actually get to our NMI code, so
|
||||||
// decrement the next IRQ's timer value by a bit so we can actually catch the
|
// decrement the next IRQ's timer value by a bit so we can actually catch the
|
||||||
// real CPU cycle counter we want for the waveforms.
|
// real CPU cycle counter we want for the waveforms.
|
||||||
#if F_CPU == 80000000
|
#if F_CPU == 80000000
|
||||||
#define DELTAIRQ (microsecondsToClockCycles(3))
|
#define DELTAIRQ (microsecondsToClockCycles(3))
|
||||||
#else
|
#else
|
||||||
#define DELTAIRQ (microsecondsToClockCycles(2))
|
#define DELTAIRQ (microsecondsToClockCycles(2))
|
||||||
#endif
|
#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
|
// Optimize the NMI inner loop by keeping track of the min and max GPIO that we
|
||||||
// we can avoid looking at the other pins.
|
// are generating. In the common case (1 PWM) these may be the same pin and
|
||||||
static int startPin = 0;
|
// we can avoid looking at the other pins.
|
||||||
static int endPin = 0;
|
static int startPin = 0;
|
||||||
|
static int endPin = 0;
|
||||||
|
|
||||||
uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||||
uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14);
|
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
|
// Handle enable/disable requests from main app.
|
||||||
waveformState &= ~waveformToEnable; // And clear the state of any just started
|
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
|
||||||
waveformToEnable = 0;
|
waveformState &= ~waveformToEnable; // And clear the state of any just started
|
||||||
waveformToDisable = 0;
|
waveformToEnable = 0;
|
||||||
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
|
waveformToDisable = 0;
|
||||||
startPin = __builtin_ffs(waveformEnabled) - 1;
|
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
|
||||||
// Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one)
|
startPin = __builtin_ffs(waveformEnabled) - 1;
|
||||||
endPin = 32 - __builtin_clz(waveformEnabled);
|
// Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one)
|
||||||
}
|
endPin = 32 - __builtin_clz(waveformEnabled);
|
||||||
|
|
||||||
bool done = false;
|
|
||||||
if (waveformEnabled) {
|
|
||||||
do {
|
|
||||||
nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
|
||||||
for (int i = startPin; i <= endPin; i++) {
|
|
||||||
uint32_t mask = 1<<i;
|
|
||||||
|
|
||||||
// If it's not on, ignore!
|
|
||||||
if (!(waveformEnabled & mask)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Waveform *wave = &waveform[i];
|
bool done = false;
|
||||||
uint32_t now = GetCycleCountIRQ();
|
if (waveformEnabled)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||||
|
for (int i = startPin; i <= endPin; i++)
|
||||||
|
{
|
||||||
|
uint32_t mask = 1 << i;
|
||||||
|
|
||||||
// Disable any waveforms that are done
|
// If it's not on, ignore!
|
||||||
if (wave->expiryCycle) {
|
if (!(waveformEnabled & mask))
|
||||||
int32_t expiryToGo = wave->expiryCycle - now;
|
{
|
||||||
if (expiryToGo < 0) {
|
continue;
|
||||||
// Done, remove!
|
}
|
||||||
waveformEnabled &= ~mask;
|
|
||||||
if (i == 16) {
|
Waveform *wave = &waveform[i];
|
||||||
GP16O &= ~1;
|
uint32_t now = GetCycleCountIRQ();
|
||||||
} else {
|
|
||||||
ClearGPIO(mask);
|
// Disable any waveforms that are done
|
||||||
}
|
if (wave->expiryCycle)
|
||||||
continue;
|
{
|
||||||
}
|
int32_t expiryToGo = wave->expiryCycle - now;
|
||||||
|
if (expiryToGo < 0)
|
||||||
|
{
|
||||||
|
// Done, remove!
|
||||||
|
waveformEnabled &= ~mask;
|
||||||
|
if (i == 16)
|
||||||
|
{
|
||||||
|
GP16O &= ~1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearGPIO(mask);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for toggles
|
||||||
|
int32_t cyclesToGo = wave->nextServiceCycle - now;
|
||||||
|
if (cyclesToGo < 0)
|
||||||
|
{
|
||||||
|
waveformState ^= mask;
|
||||||
|
if (waveformState & mask)
|
||||||
|
{
|
||||||
|
if (i == 16)
|
||||||
|
{
|
||||||
|
GP16O |= 1; // GPIO16 write slow as it's RMW
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetGPIO(mask);
|
||||||
|
}
|
||||||
|
wave->nextServiceCycle = now + wave->nextTimeHighCycles;
|
||||||
|
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeHighCycles);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (i == 16)
|
||||||
|
{
|
||||||
|
GP16O &= ~1; // GPIO16 write slow as it's RMW
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearGPIO(mask);
|
||||||
|
}
|
||||||
|
wave->nextServiceCycle = now + wave->nextTimeLowCycles;
|
||||||
|
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeLowCycles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t deltaCycles = wave->nextServiceCycle - now;
|
||||||
|
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur
|
||||||
|
uint32_t now = GetCycleCountIRQ();
|
||||||
|
int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles);
|
||||||
|
int32_t cyclesLeftTimeout = timeoutCycle - now;
|
||||||
|
done = (cycleDeltaNextEvent < 0) || (cyclesLeftTimeout < 0);
|
||||||
|
} while (!done);
|
||||||
|
} // if (waveformEnabled)
|
||||||
|
|
||||||
|
if (timer1CB)
|
||||||
|
{
|
||||||
|
nextEventCycles = min_u32(nextEventCycles, timer1CB());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for toggles
|
if (nextEventCycles < microsecondsToClockCycles(10))
|
||||||
int32_t cyclesToGo = wave->nextServiceCycle - now;
|
{
|
||||||
if (cyclesToGo < 0) {
|
nextEventCycles = microsecondsToClockCycles(10);
|
||||||
waveformState ^= mask;
|
|
||||||
if (waveformState & mask) {
|
|
||||||
if (i == 16) {
|
|
||||||
GP16O |= 1; // GPIO16 write slow as it's RMW
|
|
||||||
} else {
|
|
||||||
SetGPIO(mask);
|
|
||||||
}
|
|
||||||
wave->nextServiceCycle = now + wave->nextTimeHighCycles;
|
|
||||||
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeHighCycles);
|
|
||||||
} else {
|
|
||||||
if (i == 16) {
|
|
||||||
GP16O &= ~1; // GPIO16 write slow as it's RMW
|
|
||||||
} else {
|
|
||||||
ClearGPIO(mask);
|
|
||||||
}
|
|
||||||
wave->nextServiceCycle = now + wave->nextTimeLowCycles;
|
|
||||||
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeLowCycles);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint32_t deltaCycles = wave->nextServiceCycle - now;
|
|
||||||
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
|
|
||||||
}
|
}
|
||||||
}
|
nextEventCycles -= DELTAIRQ;
|
||||||
|
|
||||||
// Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur
|
// Do it here instead of global function to save time and because we know it's edge-IRQ
|
||||||
uint32_t now = GetCycleCountIRQ();
|
|
||||||
int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles);
|
|
||||||
int32_t cyclesLeftTimeout = timeoutCycle - now;
|
|
||||||
done = (cycleDeltaNextEvent < 0) || (cyclesLeftTimeout < 0);
|
|
||||||
} while (!done);
|
|
||||||
} // if (waveformEnabled)
|
|
||||||
|
|
||||||
if (timer1CB) {
|
|
||||||
nextEventCycles = min_u32(nextEventCycles, timer1CB());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextEventCycles < microsecondsToClockCycles(10)) {
|
|
||||||
nextEventCycles = microsecondsToClockCycles(10);
|
|
||||||
}
|
|
||||||
nextEventCycles -= DELTAIRQ;
|
|
||||||
|
|
||||||
// Do it here instead of global function to save time and because we know it's edge-IRQ
|
|
||||||
#if F_CPU == 160000000
|
#if F_CPU == 160000000
|
||||||
T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS
|
T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS
|
||||||
#else
|
#else
|
||||||
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
|
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
|
||||||
#endif
|
#endif
|
||||||
TEIE |= TEIE1; // Edge int enable
|
TEIE |= TEIE1; // Edge int enable
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
/*
|
/*
|
||||||
esp8266_waveform - General purpose waveform generation and control,
|
esp8266_waveform - General purpose waveform generation and control,
|
||||||
supporting outputs on all pins in parallel.
|
supporting outputs on all pins in parallel.
|
||||||
|
|
||||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
The core idea is to have a programmable waveform generator with a unique
|
The core idea is to have a programmable waveform generator with a unique
|
||||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||||
mode and is always loaded with the time until the next edge of any live
|
mode and is always loaded with the time until the next edge of any live
|
||||||
waveforms.
|
waveforms.
|
||||||
|
|
||||||
Up to one waveform generator per pin supported.
|
Up to one waveform generator per pin supported.
|
||||||
|
|
||||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||||
timer. This allows for removing interrupt jitter and delay as the counter
|
timer. This allows for removing interrupt jitter and delay as the counter
|
||||||
always increments once per 80MHz clock. Changes to a waveform are
|
always increments once per 80MHz clock. Changes to a waveform are
|
||||||
contiguous and only take effect on the next waveform transition,
|
contiguous and only take effect on the next waveform transition,
|
||||||
allowing for smooth transitions.
|
allowing for smooth transitions.
|
||||||
|
|
||||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||||
|
|
||||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
core_esp8266_wiring.c - implementation of Wiring API for esp8266
|
core_esp8266_wiring.c - implementation of Wiring API for esp8266
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 "wiring_private.h"
|
#include "wiring_private.h"
|
||||||
#include "ets_sys.h"
|
#include "ets_sys.h"
|
||||||
@ -27,191 +27,205 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
extern void ets_delay_us(uint32_t us);
|
extern void ets_delay_us(uint32_t us);
|
||||||
extern void esp_schedule();
|
extern void esp_schedule();
|
||||||
extern void esp_yield();
|
extern void esp_yield();
|
||||||
|
|
||||||
static os_timer_t delay_timer;
|
static os_timer_t delay_timer;
|
||||||
static os_timer_t micros_overflow_timer;
|
static os_timer_t micros_overflow_timer;
|
||||||
static uint32_t micros_at_last_overflow_tick = 0;
|
static uint32_t micros_at_last_overflow_tick = 0;
|
||||||
static uint32_t micros_overflow_count = 0;
|
static uint32_t micros_overflow_count = 0;
|
||||||
#define ONCE 0
|
#define ONCE 0
|
||||||
#define REPEAT 1
|
#define REPEAT 1
|
||||||
|
|
||||||
void delay_end(void* arg) {
|
void delay_end(void* arg)
|
||||||
(void) arg;
|
{
|
||||||
esp_schedule();
|
(void) arg;
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
esp_yield();
|
|
||||||
if(ms) {
|
void delay(unsigned long ms)
|
||||||
os_timer_disarm(&delay_timer);
|
{
|
||||||
|
if (ms)
|
||||||
|
{
|
||||||
|
os_timer_setfn(&delay_timer, (os_timer_func_t*) &delay_end, 0);
|
||||||
|
os_timer_arm(&delay_timer, ms, ONCE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
esp_schedule();
|
||||||
|
}
|
||||||
|
esp_yield();
|
||||||
|
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();
|
(void) arg;
|
||||||
if(m < micros_at_last_overflow_tick)
|
uint32_t m = system_get_time();
|
||||||
++micros_overflow_count;
|
if (m < micros_at_last_overflow_tick)
|
||||||
micros_at_last_overflow_tick = m;
|
{
|
||||||
}
|
++micros_overflow_count;
|
||||||
|
}
|
||||||
|
micros_at_last_overflow_tick = m;
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// millis() 'magic multiplier' approximation
|
// millis() 'magic multiplier' approximation
|
||||||
//
|
//
|
||||||
// This function corrects the cumlative (296us / usec overflow) drift
|
// This function corrects the cumlative (296us / usec overflow) drift
|
||||||
// seen in the orignal 'millis()' function.
|
// seen in the orignal 'millis()' function.
|
||||||
//
|
//
|
||||||
// Input:
|
// Input:
|
||||||
// 'm' - 32-bit usec counter, 0 <= m <= 0xFFFFFFFF
|
// 'm' - 32-bit usec counter, 0 <= m <= 0xFFFFFFFF
|
||||||
// 'c' - 32-bit usec overflow counter 0 <= c < 0x00400000
|
// 'c' - 32-bit usec overflow counter 0 <= c < 0x00400000
|
||||||
// Output:
|
// Output:
|
||||||
// Returns milliseconds in modulo 0x1,0000,0000 (0 to 0xFFFFFFFF)
|
// Returns milliseconds in modulo 0x1,0000,0000 (0 to 0xFFFFFFFF)
|
||||||
//
|
//
|
||||||
// Notes:
|
// Notes:
|
||||||
//
|
//
|
||||||
// 1) This routine approximates the 64-bit integer division,
|
// 1) This routine approximates the 64-bit integer division,
|
||||||
//
|
//
|
||||||
// quotient = ( 2^32 c + m ) / 1000,
|
// quotient = ( 2^32 c + m ) / 1000,
|
||||||
//
|
//
|
||||||
// through the use of 'magic' multipliers. A slow division is replaced by
|
// through the use of 'magic' multipliers. A slow division is replaced by
|
||||||
// a faster multiply using a scaled multiplicative inverse of the divisor:
|
// a faster multiply using a scaled multiplicative inverse of the divisor:
|
||||||
//
|
//
|
||||||
// quotient =~ ( 2^32 c + m ) * k, where k = Ceiling[ 2^n / 1000 ]
|
// quotient =~ ( 2^32 c + m ) * k, where k = Ceiling[ 2^n / 1000 ]
|
||||||
//
|
//
|
||||||
// The precision difference between multiplier and divisor sets the
|
// The precision difference between multiplier and divisor sets the
|
||||||
// upper-bound of the dividend which can be successfully divided.
|
// upper-bound of the dividend which can be successfully divided.
|
||||||
//
|
//
|
||||||
// For this application, n = 64, and the divisor (1000) has 10-bits of
|
// For this application, n = 64, and the divisor (1000) has 10-bits of
|
||||||
// precision. This sets the dividend upper-bound to (64 - 10) = 54 bits,
|
// precision. This sets the dividend upper-bound to (64 - 10) = 54 bits,
|
||||||
// and that of 'c' to (54 - 32) = 22 bits. This corresponds to a value
|
// and that of 'c' to (54 - 32) = 22 bits. This corresponds to a value
|
||||||
// for 'c' = 0x0040,0000 , or +570 years of usec counter overflows.
|
// for 'c' = 0x0040,0000 , or +570 years of usec counter overflows.
|
||||||
//
|
//
|
||||||
// 2) A distributed multiply with offset-summing is used find k( 2^32 c + m ):
|
// 2) A distributed multiply with offset-summing is used find k( 2^32 c + m ):
|
||||||
//
|
//
|
||||||
// prd = (2^32 kh + kl) * ( 2^32 c + m )
|
// prd = (2^32 kh + kl) * ( 2^32 c + m )
|
||||||
// = 2^64 kh c + 2^32 kl c + 2^32 kh m + kl m
|
// = 2^64 kh c + 2^32 kl c + 2^32 kh m + kl m
|
||||||
// (d) (c) (b) (a)
|
// (d) (c) (b) (a)
|
||||||
//
|
//
|
||||||
// Graphically, the offset-sums align in little endian like this:
|
// Graphically, the offset-sums align in little endian like this:
|
||||||
// LS -> MS
|
// LS -> MS
|
||||||
// 32 64 96 128
|
// 32 64 96 128
|
||||||
// | a[-1] | a[0] | a[1] | a[2] |
|
// | a[-1] | a[0] | a[1] | a[2] |
|
||||||
// | m kl | 0 | 0 | a[-1] not needed
|
// | m kl | 0 | 0 | a[-1] not needed
|
||||||
// | | m kh | |
|
// | | m kh | |
|
||||||
// | | c kl | | a[1] holds the result
|
// | | c kl | | a[1] holds the result
|
||||||
// | | | c kh | a[2] can be discarded
|
// | | | c kh | a[2] can be discarded
|
||||||
//
|
//
|
||||||
// As only the high-word of 'm kl' and low-word of 'c kh' contribute to the
|
// As only the high-word of 'm kl' and low-word of 'c kh' contribute to the
|
||||||
// overall result, only (2) 32-bit words are needed for the accumulator.
|
// overall result, only (2) 32-bit words are needed for the accumulator.
|
||||||
//
|
//
|
||||||
// 3) As C++ does not intrinsically test for addition overflows, one must
|
// 3) As C++ does not intrinsically test for addition overflows, one must
|
||||||
// code specifically to detect them. This approximation skips these
|
// code specifically to detect them. This approximation skips these
|
||||||
// overflow checks for speed, hence the sum,
|
// overflow checks for speed, hence the sum,
|
||||||
//
|
//
|
||||||
// highword( m kl ) + m kh + c kl < (2^64-1), MUST NOT OVERFLOW.
|
// highword( m kl ) + m kh + c kl < (2^64-1), MUST NOT OVERFLOW.
|
||||||
//
|
//
|
||||||
// To meet this criteria, not only do we have to pick 'k' to achieve our
|
// To meet this criteria, not only do we have to pick 'k' to achieve our
|
||||||
// desired precision, we also have to split 'k' appropriately to avoid
|
// desired precision, we also have to split 'k' appropriately to avoid
|
||||||
// any addition overflows.
|
// any addition overflows.
|
||||||
//
|
//
|
||||||
// 'k' should be also chosen to align the various products on byte
|
// 'k' should be also chosen to align the various products on byte
|
||||||
// boundaries to avoid any 64-bit shifts before additions, as they incur
|
// boundaries to avoid any 64-bit shifts before additions, as they incur
|
||||||
// major time penalties. The 'k' chosen for this specific division by 1000
|
// major time penalties. The 'k' chosen for this specific division by 1000
|
||||||
// was picked primarily to avoid shifts as well as for precision.
|
// was picked primarily to avoid shifts as well as for precision.
|
||||||
//
|
//
|
||||||
// For the reasons list above, this routine is NOT a general one.
|
// For the reasons list above, this routine is NOT a general one.
|
||||||
// Changing divisors could break the overflow requirement and force
|
// Changing divisors could break the overflow requirement and force
|
||||||
// picking a 'k' split which requires shifts before additions.
|
// picking a 'k' split which requires shifts before additions.
|
||||||
//
|
//
|
||||||
// ** Test THOROUGHLY after making changes **
|
// ** Test THOROUGHLY after making changes **
|
||||||
//
|
//
|
||||||
// 4) Results of time benchmarks run on an ESP8266 Huzzah feather are:
|
// 4) Results of time benchmarks run on an ESP8266 Huzzah feather are:
|
||||||
//
|
//
|
||||||
// usec x Orig Comment
|
// usec x Orig Comment
|
||||||
// Orig: 3.18 1.00 Original code
|
// Orig: 3.18 1.00 Original code
|
||||||
// Corr: 13.21 4.15 64-bit reference code
|
// Corr: 13.21 4.15 64-bit reference code
|
||||||
// Test: 4.60 1.45 64-bit magic multiply, 4x32
|
// Test: 4.60 1.45 64-bit magic multiply, 4x32
|
||||||
//
|
//
|
||||||
// The magic multiplier routine runs ~3x faster than the reference. Execution
|
// The magic multiplier routine runs ~3x faster than the reference. Execution
|
||||||
// times can vary considerably with the numbers being multiplied, so one
|
// times can vary considerably with the numbers being multiplied, so one
|
||||||
// should derate this factor to around 2x, worst case.
|
// should derate this factor to around 2x, worst case.
|
||||||
//
|
//
|
||||||
// Reference function: corrected millis(), 64-bit arithmetic,
|
// Reference function: corrected millis(), 64-bit arithmetic,
|
||||||
// truncated to 32-bits by return
|
// truncated to 32-bits by return
|
||||||
// unsigned long ICACHE_RAM_ATTR millis_corr_DEBUG( void )
|
// unsigned long ICACHE_RAM_ATTR millis_corr_DEBUG( void )
|
||||||
// {
|
// {
|
||||||
// // Get usec system time, usec overflow conter
|
// // Get usec system time, usec overflow conter
|
||||||
// ......
|
// ......
|
||||||
// return ( (c * 4294967296 + m) / 1000 ); // 64-bit division is SLOW
|
// return ( (c * 4294967296 + m) / 1000 ); // 64-bit division is SLOW
|
||||||
// } //millis_corr
|
// } //millis_corr
|
||||||
//
|
//
|
||||||
// 5) See this link for a good discussion on magic multipliers:
|
// 5) See this link for a good discussion on magic multipliers:
|
||||||
// http://ridiculousfish.com/blog/posts/labor-of-division-episode-i.html
|
// http://ridiculousfish.com/blog/posts/labor-of-division-episode-i.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#define MAGIC_1E3_wLO 0x4bc6a7f0 // LS part
|
#define MAGIC_1E3_wLO 0x4bc6a7f0 // LS part
|
||||||
#define MAGIC_1E3_wHI 0x00418937 // MS part, magic multiplier
|
#define MAGIC_1E3_wHI 0x00418937 // MS part, magic multiplier
|
||||||
|
|
||||||
unsigned long ICACHE_RAM_ATTR millis()
|
unsigned long ICACHE_RAM_ATTR millis()
|
||||||
{
|
{
|
||||||
union {
|
union
|
||||||
uint64_t q; // Accumulator, 64-bit, little endian
|
{
|
||||||
uint32_t a[2]; // ..........., 32-bit segments
|
uint64_t q; // Accumulator, 64-bit, little endian
|
||||||
} acc;
|
uint32_t a[2]; // ..........., 32-bit segments
|
||||||
acc.a[1] = 0; // Zero high-acc
|
} acc;
|
||||||
|
acc.a[1] = 0; // Zero high-acc
|
||||||
// Get usec system time, usec overflow counter
|
|
||||||
uint32_t m = system_get_time();
|
|
||||||
uint32_t c = micros_overflow_count +
|
|
||||||
((m < micros_at_last_overflow_tick) ? 1 : 0);
|
|
||||||
|
|
||||||
// (a) Init. low-acc with high-word of 1st product. The right-shift
|
// Get usec system time, usec overflow counter
|
||||||
// falls on a byte boundary, hence is relatively quick.
|
uint32_t m = system_get_time();
|
||||||
|
uint32_t c = micros_overflow_count +
|
||||||
acc.q = ( (uint64_t)( m * (uint64_t)MAGIC_1E3_wLO ) >> 32 );
|
((m < micros_at_last_overflow_tick) ? 1 : 0);
|
||||||
|
|
||||||
// (b) Offset sum, low-acc
|
// (a) Init. low-acc with high-word of 1st product. The right-shift
|
||||||
acc.q += ( m * (uint64_t)MAGIC_1E3_wHI );
|
// falls on a byte boundary, hence is relatively quick.
|
||||||
|
|
||||||
// (c) Offset sum, low-acc
|
acc.q = ((uint64_t)(m * (uint64_t)MAGIC_1E3_wLO) >> 32);
|
||||||
acc.q += ( c * (uint64_t)MAGIC_1E3_wLO );
|
|
||||||
|
|
||||||
// (d) Truncated sum, high-acc
|
// (b) Offset sum, low-acc
|
||||||
acc.a[1] += (uint32_t)( c * (uint64_t)MAGIC_1E3_wHI );
|
acc.q += (m * (uint64_t)MAGIC_1E3_wHI);
|
||||||
|
|
||||||
return ( acc.a[1] ); // Extract result, high-acc
|
// (c) Offset sum, low-acc
|
||||||
|
acc.q += (c * (uint64_t)MAGIC_1E3_wLO);
|
||||||
|
|
||||||
} //millis
|
// (d) Truncated sum, high-acc
|
||||||
|
acc.a[1] += (uint32_t)(c * (uint64_t)MAGIC_1E3_wHI);
|
||||||
|
|
||||||
unsigned long ICACHE_RAM_ATTR micros() {
|
return (acc.a[1]); // Extract result, high-acc
|
||||||
return system_get_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t ICACHE_RAM_ATTR micros64() {
|
} //millis
|
||||||
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) {
|
unsigned long ICACHE_RAM_ATTR micros()
|
||||||
os_delay_us(us);
|
{
|
||||||
}
|
return system_get_time();
|
||||||
|
}
|
||||||
|
|
||||||
void init() {
|
uint64_t ICACHE_RAM_ATTR micros64()
|
||||||
initPins();
|
{
|
||||||
timer1_isr_init();
|
uint32_t low32_us = system_get_time();
|
||||||
os_timer_setfn(µs_overflow_timer, (os_timer_func_t*) µs_overflow_tick, 0);
|
uint32_t high32_us = micros_overflow_count + ((low32_us < micros_at_last_overflow_tick) ? 1 : 0);
|
||||||
os_timer_arm(µs_overflow_timer, 60000, REPEAT);
|
uint64_t duration64_us = (uint64_t)high32_us << 32 | low32_us;
|
||||||
}
|
return duration64_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR delayMicroseconds(unsigned int us)
|
||||||
|
{
|
||||||
|
os_delay_us(us);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
initPins();
|
||||||
|
timer1_isr_init();
|
||||||
|
os_timer_setfn(µs_overflow_timer, (os_timer_func_t*) µs_overflow_tick, 0);
|
||||||
|
os_timer_arm(µs_overflow_timer, 60000, REPEAT);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
/*
|
/*
|
||||||
analog.c - analogRead implementation for esp8266
|
analog.c - analogRead implementation for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
18/06/2015 analogRead bugfix by Testato
|
18/06/2015 analogRead bugfix by Testato
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "wiring_private.h"
|
#include "wiring_private.h"
|
||||||
@ -28,15 +28,16 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
extern int __analogRead(uint8_t pin)
|
extern int __analogRead(uint8_t pin)
|
||||||
{
|
{
|
||||||
// accept both A0 constant and ADC channel number
|
// accept both A0 constant and ADC channel number
|
||||||
if(pin == 17 || pin == 0) {
|
if (pin == 17 || pin == 0)
|
||||||
return system_adc_read();
|
{
|
||||||
|
return system_adc_read();
|
||||||
|
}
|
||||||
|
return digitalRead(pin) * 1023;
|
||||||
}
|
}
|
||||||
return digitalRead(pin) * 1023;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead")));
|
extern int analogRead(uint8_t pin) __attribute__((weak, alias("__analogRead")));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
digital.c - wiring digital implementation for esp8266
|
digital.c - wiring digital implementation for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#define ARDUINO_MAIN
|
#define ARDUINO_MAIN
|
||||||
#include "wiring_private.h"
|
#include "wiring_private.h"
|
||||||
@ -29,220 +29,291 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x04, 0x08, 0x0C, 0x10};
|
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) {
|
extern void __pinMode(uint8_t pin, uint8_t mode)
|
||||||
if(pin < 16){
|
{
|
||||||
if(mode == SPECIAL){
|
if (pin < 16)
|
||||||
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
{
|
||||||
GPEC = (1 << pin); //Disable
|
if (mode == SPECIAL)
|
||||||
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
|
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
||||||
} else if(mode & FUNCTION_0){
|
GPEC = (1 << pin); //Disable
|
||||||
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin)
|
||||||
GPEC = (1 << pin); //Disable
|
if (pin == 3)
|
||||||
GPF(pin) = GPFFS((mode >> 4) & 0x07);
|
{
|
||||||
if(pin == 13 && mode == FUNCTION_4) GPF(pin) |= (1 << GPFPU);//enable pullup on RX
|
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)
|
else if (mode & FUNCTION_0)
|
||||||
if(mode == OUTPUT_OPEN_DRAIN) GPC(pin) |= (1 << GPCD);
|
{
|
||||||
GPES = (1 << pin); //Enable
|
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
||||||
} else if(mode == INPUT || mode == INPUT_PULLUP){
|
GPEC = (1 << pin); //Disable
|
||||||
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
GPF(pin) = GPFFS((mode >> 4) & 0x07);
|
||||||
GPEC = (1 << pin); //Disable
|
if (pin == 13 && mode == FUNCTION_4)
|
||||||
GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
{
|
||||||
if(mode == INPUT_PULLUP) {
|
GPF(pin) |= (1 << GPFPU); //enable pullup on RX
|
||||||
GPF(pin) |= (1 << GPFPU); // Enable Pullup
|
}
|
||||||
}
|
}
|
||||||
} else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){
|
else if (mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN)
|
||||||
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
{
|
||||||
GPEC = (1 << pin); //Disable
|
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
||||||
if(mode == WAKEUP_PULLUP) {
|
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
|
||||||
GPF(pin) |= (1 << GPFPU); // Enable Pullup
|
if (mode == OUTPUT_OPEN_DRAIN)
|
||||||
GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED)
|
{
|
||||||
} else {
|
GPC(pin) |= (1 << GPCD);
|
||||||
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)
|
GPES = (1 << pin); //Enable
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
GPF(pin) |= (1 << GPFPU); // Enable Pullup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
||||||
|
GPC16 = 0;
|
||||||
|
if (mode == INPUT || mode == INPUT_PULLDOWN_16)
|
||||||
|
{
|
||||||
|
if (mode == INPUT_PULLDOWN_16)
|
||||||
|
{
|
||||||
|
GPF16 |= (1 << GP16FPD);//Enable Pulldown
|
||||||
|
}
|
||||||
|
GP16E &= ~1;
|
||||||
|
}
|
||||||
|
else if (mode == OUTPUT)
|
||||||
|
{
|
||||||
|
GP16E |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if(pin == 16){
|
|
||||||
GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO
|
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val)
|
||||||
GPC16 = 0;
|
{
|
||||||
if(mode == INPUT || mode == INPUT_PULLDOWN_16){
|
stopWaveform(pin);
|
||||||
if(mode == INPUT_PULLDOWN_16){
|
if (pin < 16)
|
||||||
GPF16 |= (1 << GP16FPD);//Enable Pulldown
|
{
|
||||||
}
|
if (val)
|
||||||
GP16E &= ~1;
|
{
|
||||||
} else if(mode == OUTPUT){
|
GPOS = (1 << pin);
|
||||||
GP16E |= 1;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GPOC = (1 << pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pin == 16)
|
||||||
|
{
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
GP16O |= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GP16O &= ~1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) {
|
extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin)
|
||||||
stopWaveform(pin);
|
{
|
||||||
if(pin < 16){
|
if (pin < 16)
|
||||||
if(val) GPOS = (1 << pin);
|
{
|
||||||
else GPOC = (1 << pin);
|
return GPIP(pin);
|
||||||
} else if(pin == 16){
|
}
|
||||||
if(val) GP16O |= 1;
|
else if (pin == 16)
|
||||||
else GP16O &= ~1;
|
{
|
||||||
}
|
return GP16I & 0x01;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) {
|
|
||||||
if(pin < 16){
|
|
||||||
return GPIP(pin);
|
|
||||||
} else if(pin == 16){
|
|
||||||
return GP16I & 0x01;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
GPIO INTERRUPTS
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef void (*voidFuncPtr)(void);
|
|
||||||
typedef void (*voidFuncPtrArg)(void*);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t mode;
|
|
||||||
void (*fn)(void);
|
|
||||||
void * arg;
|
|
||||||
} interrupt_handler_t;
|
|
||||||
|
|
||||||
//duplicate from functionalInterrupt.h keep in sync
|
|
||||||
typedef struct InterruptInfo {
|
|
||||||
uint8_t pin;
|
|
||||||
uint8_t value;
|
|
||||||
uint32_t micro;
|
|
||||||
} InterruptInfo;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
InterruptInfo* interruptInfo;
|
|
||||||
void* functionInfo;
|
|
||||||
} ArgStructure;
|
|
||||||
|
|
||||||
static interrupt_handler_t interrupt_handlers[16];
|
|
||||||
static uint32_t interrupt_reg = 0;
|
|
||||||
|
|
||||||
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;
|
|
||||||
ETS_GPIO_INTR_DISABLE();
|
|
||||||
int i = 0;
|
|
||||||
uint32_t changedbits = status & interrupt_reg;
|
|
||||||
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)))) {
|
|
||||||
// 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
|
|
||||||
ArgStructure* localArg = (ArgStructure*)handler->arg;
|
|
||||||
if (localArg && localArg->interruptInfo)
|
|
||||||
{
|
|
||||||
localArg->interruptInfo->pin = i;
|
|
||||||
localArg->interruptInfo->value = __digitalRead(i);
|
|
||||||
localArg->interruptInfo->micro = micros();
|
|
||||||
}
|
|
||||||
if (handler->arg)
|
|
||||||
{
|
|
||||||
((voidFuncPtrArg)handler->fn)(handler->arg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
handler->fn();
|
|
||||||
}
|
|
||||||
xt_wsr_ps(savedPS);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ETS_GPIO_INTR_ENABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void cleanupFunctional(void* arg);
|
/*
|
||||||
|
GPIO INTERRUPTS
|
||||||
|
*/
|
||||||
|
|
||||||
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) {
|
typedef void (*voidFuncPtr)(void);
|
||||||
|
typedef void (*voidFuncPtrArg)(void*);
|
||||||
|
|
||||||
// #5780
|
typedef struct
|
||||||
// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
|
{
|
||||||
if ((uint32_t)userFunc >= 0x40200000)
|
uint8_t mode;
|
||||||
{
|
void (*fn)(void);
|
||||||
// ISR not in IRAM
|
void * arg;
|
||||||
::printf((PGM_P)F("ISR not in IRAM!\r\n"));
|
} interrupt_handler_t;
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pin < 16) {
|
//duplicate from functionalInterrupt.h keep in sync
|
||||||
ETS_GPIO_INTR_DISABLE();
|
typedef struct InterruptInfo
|
||||||
interrupt_handler_t *handler = &interrupt_handlers[pin];
|
{
|
||||||
handler->mode = mode;
|
uint8_t pin;
|
||||||
handler->fn = userFunc;
|
uint8_t value;
|
||||||
if (handler->arg) // Clean when new attach without detach
|
uint32_t micro;
|
||||||
{
|
} InterruptInfo;
|
||||||
cleanupFunctional(handler->arg);
|
|
||||||
}
|
|
||||||
handler->arg = arg;
|
|
||||||
interrupt_reg |= (1 << pin);
|
|
||||||
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
|
|
||||||
GPIEC = (1 << pin); //Clear Interrupt for this pin
|
|
||||||
GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode"
|
|
||||||
ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg);
|
|
||||||
ETS_GPIO_INTR_ENABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode )
|
typedef struct
|
||||||
{
|
{
|
||||||
__attachInterruptArg (pin, userFunc, 0, mode);
|
InterruptInfo* interruptInfo;
|
||||||
}
|
void* functionInfo;
|
||||||
|
} ArgStructure;
|
||||||
|
|
||||||
extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
|
static interrupt_handler_t interrupt_handlers[16];
|
||||||
if(pin < 16) {
|
static uint32_t interrupt_reg = 0;
|
||||||
ETS_GPIO_INTR_DISABLE();
|
|
||||||
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
|
|
||||||
GPIEC = (1 << pin); //Clear Interrupt for this pin
|
|
||||||
interrupt_reg &= ~(1 << pin);
|
|
||||||
interrupt_handler_t *handler = &interrupt_handlers[pin];
|
|
||||||
handler->mode = 0;
|
|
||||||
handler->fn = 0;
|
|
||||||
if (handler->arg)
|
|
||||||
{
|
|
||||||
cleanupFunctional(handler->arg);
|
|
||||||
}
|
|
||||||
handler->arg = 0;
|
|
||||||
if (interrupt_reg)
|
|
||||||
ETS_GPIO_INTR_ENABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initPins() {
|
void ICACHE_RAM_ATTR interrupt_handler(void *arg)
|
||||||
//Disable UART interrupts
|
{
|
||||||
system_set_os_print(0);
|
(void) arg;
|
||||||
U0IE = 0;
|
uint32_t status = GPIE;
|
||||||
U1IE = 0;
|
GPIEC = status;//clear them interrupts
|
||||||
|
uint32_t levels = GPI;
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
changedbits &= ~(1 << i);
|
||||||
|
interrupt_handler_t *handler = &interrupt_handlers[i];
|
||||||
|
if (handler->fn &&
|
||||||
|
(handler->mode == CHANGE ||
|
||||||
|
(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
|
||||||
|
ArgStructure* localArg = (ArgStructure*)handler->arg;
|
||||||
|
if (localArg && localArg->interruptInfo)
|
||||||
|
{
|
||||||
|
localArg->interruptInfo->pin = i;
|
||||||
|
localArg->interruptInfo->value = __digitalRead(i);
|
||||||
|
localArg->interruptInfo->micro = micros();
|
||||||
|
}
|
||||||
|
if (handler->arg)
|
||||||
|
{
|
||||||
|
((voidFuncPtrArg)handler->fn)(handler->arg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler->fn();
|
||||||
|
}
|
||||||
|
xt_wsr_ps(savedPS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ETS_GPIO_INTR_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i <= 5; ++i) {
|
extern void cleanupFunctional(void* arg);
|
||||||
pinMode(i, INPUT);
|
|
||||||
}
|
|
||||||
// pins 6-11 are used for the SPI flash interface
|
|
||||||
for (int i = 12; i <= 16; ++i) {
|
|
||||||
pinMode(i, INPUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode")));
|
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode)
|
||||||
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
|
{
|
||||||
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")));
|
|
||||||
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
|
// #5780
|
||||||
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));
|
// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
|
||||||
|
if ((uint32_t)userFunc >= 0x40200000)
|
||||||
|
{
|
||||||
|
// ISR not in IRAM
|
||||||
|
::printf((PGM_P)F("ISR not in IRAM!\r\n"));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pin < 16)
|
||||||
|
{
|
||||||
|
ETS_GPIO_INTR_DISABLE();
|
||||||
|
interrupt_handler_t *handler = &interrupt_handlers[pin];
|
||||||
|
handler->mode = mode;
|
||||||
|
handler->fn = userFunc;
|
||||||
|
if (handler->arg) // Clean when new attach without detach
|
||||||
|
{
|
||||||
|
cleanupFunctional(handler->arg);
|
||||||
|
}
|
||||||
|
handler->arg = arg;
|
||||||
|
interrupt_reg |= (1 << pin);
|
||||||
|
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
|
||||||
|
GPIEC = (1 << pin); //Clear Interrupt for this pin
|
||||||
|
GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode"
|
||||||
|
ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg);
|
||||||
|
ETS_GPIO_INTR_ENABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode)
|
||||||
|
{
|
||||||
|
__attachInterruptArg(pin, userFunc, 0, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
interrupt_reg &= ~(1 << pin);
|
||||||
|
interrupt_handler_t *handler = &interrupt_handlers[pin];
|
||||||
|
handler->mode = 0;
|
||||||
|
handler->fn = 0;
|
||||||
|
if (handler->arg)
|
||||||
|
{
|
||||||
|
cleanupFunctional(handler->arg);
|
||||||
|
}
|
||||||
|
handler->arg = 0;
|
||||||
|
if (interrupt_reg)
|
||||||
|
{
|
||||||
|
ETS_GPIO_INTR_ENABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initPins()
|
||||||
|
{
|
||||||
|
//Disable UART interrupts
|
||||||
|
system_set_os_print(0);
|
||||||
|
U0IE = 0;
|
||||||
|
U1IE = 0;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
pinMode(i, INPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void pinMode(uint8_t pin, uint8_t mode) __attribute__((weak, alias("__pinMode")));
|
||||||
|
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__((weak, alias("__digitalWrite")));
|
||||||
|
extern int digitalRead(uint8_t pin) __attribute__((weak, alias("__digitalRead")));
|
||||||
|
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__((weak, alias("__attachInterrupt")));
|
||||||
|
extern void detachInterrupt(uint8_t pin) __attribute__((weak, alias("__detachInterrupt")));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
pulse.c - wiring pulseIn implementation for esp8266
|
pulse.c - wiring pulseIn implementation for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "wiring_private.h"
|
#include "wiring_private.h"
|
||||||
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
extern uint32_t xthal_get_ccount();
|
extern uint32_t xthal_get_ccount();
|
||||||
|
|
||||||
#define WAIT_FOR_PIN_STATE(state) \
|
#define WAIT_FOR_PIN_STATE(state) \
|
||||||
while (digitalRead(pin) != (state)) { \
|
while (digitalRead(pin) != (state)) { \
|
||||||
@ -34,25 +34,26 @@ extern uint32_t xthal_get_ccount();
|
|||||||
optimistic_yield(5000); \
|
optimistic_yield(5000); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// max timeout is 27 seconds at 160MHz clock and 54 seconds at 80MHz clock
|
// max timeout is 27 seconds at 160MHz clock and 54 seconds at 80MHz clock
|
||||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||||
{
|
{
|
||||||
const uint32_t max_timeout_us = clockCyclesToMicroseconds(UINT_MAX);
|
const uint32_t max_timeout_us = clockCyclesToMicroseconds(UINT_MAX);
|
||||||
if (timeout > max_timeout_us) {
|
if (timeout > max_timeout_us)
|
||||||
timeout = max_timeout_us;
|
{
|
||||||
|
timeout = max_timeout_us;
|
||||||
|
}
|
||||||
|
const uint32_t timeout_cycles = microsecondsToClockCycles(timeout);
|
||||||
|
const uint32_t start_cycle_count = xthal_get_ccount();
|
||||||
|
WAIT_FOR_PIN_STATE(!state);
|
||||||
|
WAIT_FOR_PIN_STATE(state);
|
||||||
|
const uint32_t pulse_start_cycle_count = xthal_get_ccount();
|
||||||
|
WAIT_FOR_PIN_STATE(!state);
|
||||||
|
return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count);
|
||||||
}
|
}
|
||||||
const uint32_t timeout_cycles = microsecondsToClockCycles(timeout);
|
|
||||||
const uint32_t start_cycle_count = xthal_get_ccount();
|
|
||||||
WAIT_FOR_PIN_STATE(!state);
|
|
||||||
WAIT_FOR_PIN_STATE(state);
|
|
||||||
const uint32_t pulse_start_cycle_count = xthal_get_ccount();
|
|
||||||
WAIT_FOR_PIN_STATE(!state);
|
|
||||||
return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
|
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||||
{
|
{
|
||||||
return pulseIn(pin, state, timeout);
|
return pulseIn(pin, state, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
pwm.c - analogWrite implementation for esp8266
|
pwm.c - analogWrite implementation for esp8266
|
||||||
|
|
||||||
Use the shared TIMER1 utilities to generate PWM signals
|
Use the shared TIMER1 utilities to generate PWM signals
|
||||||
|
|
||||||
Original Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Original Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@ -26,56 +26,75 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static uint32_t analogMap = 0;
|
static uint32_t analogMap = 0;
|
||||||
static int32_t analogScale = PWMRANGE;
|
static int32_t analogScale = PWMRANGE;
|
||||||
static uint16_t analogFreq = 1000;
|
static uint16_t analogFreq = 1000;
|
||||||
|
|
||||||
extern void __analogWriteRange(uint32_t range) {
|
extern void __analogWriteRange(uint32_t range)
|
||||||
if (range > 0) {
|
{
|
||||||
analogScale = range;
|
if (range > 0)
|
||||||
}
|
{
|
||||||
}
|
analogScale = range;
|
||||||
|
}
|
||||||
extern void __analogWriteFreq(uint32_t freq) {
|
|
||||||
if (freq < 100) {
|
|
||||||
analogFreq = 100;
|
|
||||||
} else if (freq > 40000) {
|
|
||||||
analogFreq = 40000;
|
|
||||||
} else {
|
|
||||||
analogFreq = freq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void __analogWrite(uint8_t pin, int val) {
|
|
||||||
if (pin > 16) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint32_t analogPeriod = 1000000L / analogFreq;
|
|
||||||
if (val < 0) {
|
|
||||||
val = 0;
|
|
||||||
} else if (val > analogScale) {
|
|
||||||
val = analogScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
analogMap &= ~(1 << pin);
|
|
||||||
uint32_t high = (analogPeriod * val) / analogScale;
|
|
||||||
uint32_t low = analogPeriod - high;
|
|
||||||
pinMode(pin, OUTPUT);
|
|
||||||
if (low == 0) {
|
|
||||||
stopWaveform(pin);
|
|
||||||
digitalWrite(pin, HIGH);
|
|
||||||
} else if (high == 0) {
|
|
||||||
stopWaveform(pin);
|
|
||||||
digitalWrite(pin, LOW);
|
|
||||||
} else {
|
|
||||||
if (startWaveform(pin, high, low, 0)) {
|
|
||||||
analogMap |= (1 << pin);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void analogWrite(uint8_t pin, int val) __attribute__((weak, alias("__analogWrite")));
|
extern void __analogWriteFreq(uint32_t freq)
|
||||||
extern void analogWriteFreq(uint32_t freq) __attribute__((weak, alias("__analogWriteFreq")));
|
{
|
||||||
extern void analogWriteRange(uint32_t range) __attribute__((weak, alias("__analogWriteRange")));
|
if (freq < 100)
|
||||||
|
{
|
||||||
|
analogFreq = 100;
|
||||||
|
}
|
||||||
|
else if (freq > 40000)
|
||||||
|
{
|
||||||
|
analogFreq = 40000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
analogFreq = freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void __analogWrite(uint8_t pin, int val)
|
||||||
|
{
|
||||||
|
if (pin > 16)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t analogPeriod = 1000000L / analogFreq;
|
||||||
|
if (val < 0)
|
||||||
|
{
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
else if (val > analogScale)
|
||||||
|
{
|
||||||
|
val = analogScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
analogMap &= ~(1 << pin);
|
||||||
|
uint32_t high = (analogPeriod * val) / analogScale;
|
||||||
|
uint32_t low = analogPeriod - high;
|
||||||
|
pinMode(pin, OUTPUT);
|
||||||
|
if (low == 0)
|
||||||
|
{
|
||||||
|
stopWaveform(pin);
|
||||||
|
digitalWrite(pin, HIGH);
|
||||||
|
}
|
||||||
|
else if (high == 0)
|
||||||
|
{
|
||||||
|
stopWaveform(pin);
|
||||||
|
digitalWrite(pin, LOW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (startWaveform(pin, high, low, 0))
|
||||||
|
{
|
||||||
|
analogMap |= (1 << pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void analogWrite(uint8_t pin, int val) __attribute__((weak, alias("__analogWrite")));
|
||||||
|
extern void analogWriteFreq(uint32_t freq) __attribute__((weak, alias("__analogWriteFreq")));
|
||||||
|
extern void analogWriteRange(uint32_t range) __attribute__((weak, alias("__analogWriteRange")));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,60 +1,72 @@
|
|||||||
/*
|
/*
|
||||||
wiring_shift.c - shiftOut() function
|
wiring_shift.c - shiftOut() function
|
||||||
Part of Arduino - http://www.arduino.cc/
|
Part of Arduino - http://www.arduino.cc/
|
||||||
|
|
||||||
Copyright (c) 2005-2006 David A. Mellis
|
Copyright (c) 2005-2006 David A. Mellis
|
||||||
|
|
||||||
Note: file renamed with a core_esp8266_ prefix to simplify linker
|
Note: file renamed with a core_esp8266_ prefix to simplify linker
|
||||||
script rules for moving code into irom0_text section.
|
script rules for moving code into irom0_text section.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General
|
You should have received a copy of the GNU Lesser General
|
||||||
Public License along with this library; if not, write to the
|
Public License along with this library; if not, write to the
|
||||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
Boston, MA 02111-1307 USA
|
Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "wiring_private.h"
|
#include "wiring_private.h"
|
||||||
extern "C" {
|
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;
|
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)
|
digitalWrite(clockPin, HIGH);
|
||||||
value |= digitalRead(dataPin) << i;
|
if (bitOrder == LSBFIRST)
|
||||||
else
|
{
|
||||||
value |= digitalRead(dataPin) << (7 - i);
|
value |= digitalRead(dataPin) << i;
|
||||||
digitalWrite(clockPin, LOW);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value |= digitalRead(dataPin) << (7 - i);
|
||||||
|
}
|
||||||
|
digitalWrite(clockPin, LOW);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
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;
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
for(i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++)
|
||||||
if(bitOrder == LSBFIRST)
|
{
|
||||||
digitalWrite(dataPin, !!(val & (1 << i)));
|
if (bitOrder == LSBFIRST)
|
||||||
else
|
{
|
||||||
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
|
digitalWrite(dataPin, !!(val & (1 << i)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
|
||||||
|
}
|
||||||
|
|
||||||
digitalWrite(clockPin, HIGH);
|
digitalWrite(clockPin, HIGH);
|
||||||
digitalWrite(clockPin, LOW);
|
digitalWrite(clockPin, LOW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -15,11 +15,11 @@ extern bool timeshift64_is_set;
|
|||||||
|
|
||||||
void esp_yield();
|
void esp_yield();
|
||||||
void esp_schedule();
|
void esp_schedule();
|
||||||
void tune_timeshift64 (uint64_t now_us);
|
void tune_timeshift64(uint64_t now_us);
|
||||||
void settimeofday_cb (void (*cb)(void));
|
void settimeofday_cb(void (*cb)(void));
|
||||||
void disable_extra4k_at_link_time (void) __attribute__((noinline));
|
void disable_extra4k_at_link_time(void) __attribute__((noinline));
|
||||||
|
|
||||||
uint32_t sqrt32 (uint32_t n);
|
uint32_t sqrt32(uint32_t n);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,39 @@
|
|||||||
/*
|
/*
|
||||||
debug.cpp - debug helper functions
|
debug.cpp - debug helper functions
|
||||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "debug.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);
|
const uint8_t* src = (const uint8_t*) mem;
|
||||||
for(uint32_t i = 0; i < len; i++) {
|
os_printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||||
if(i % cols == 0) {
|
for (uint32_t i = 0; i < len; i++)
|
||||||
os_printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
{
|
||||||
yield();
|
if (i % cols == 0)
|
||||||
}
|
{
|
||||||
os_printf("%02X ", *src);
|
os_printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||||
src++;
|
yield();
|
||||||
}
|
}
|
||||||
os_printf("\n");
|
os_printf("%02X ", *src);
|
||||||
}
|
src++;
|
||||||
|
}
|
||||||
|
os_printf("\n");
|
||||||
|
}
|
||||||
|
@ -9,7 +9,8 @@ extern "C" {
|
|||||||
|
|
||||||
#define RTC_MEM ((volatile uint32_t*)0x60001200)
|
#define RTC_MEM ((volatile uint32_t*)0x60001200)
|
||||||
|
|
||||||
enum action_t {
|
enum action_t
|
||||||
|
{
|
||||||
ACTION_COPY_RAW = 0x00000001,
|
ACTION_COPY_RAW = 0x00000001,
|
||||||
ACTION_LOAD_APP = 0xffffffff
|
ACTION_LOAD_APP = 0xffffffff
|
||||||
};
|
};
|
||||||
@ -17,7 +18,8 @@ enum action_t {
|
|||||||
#define EBOOT_MAGIC 0xeb001000
|
#define EBOOT_MAGIC 0xeb001000
|
||||||
#define EBOOT_MAGIC_MASK 0xfffff000
|
#define EBOOT_MAGIC_MASK 0xfffff000
|
||||||
|
|
||||||
struct eboot_command {
|
struct eboot_command
|
||||||
|
{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
enum action_t action;
|
enum action_t action;
|
||||||
uint32_t args[29];
|
uint32_t args[29];
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
esp8266_peri.h - Peripheral registers exposed in more AVR style for esp8266
|
esp8266_peri.h - Peripheral registers exposed in more AVR style for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 ESP8266_PERI_H_INCLUDED
|
#ifndef ESP8266_PERI_H_INCLUDED
|
||||||
#define ESP8266_PERI_H_INCLUDED
|
#define ESP8266_PERI_H_INCLUDED
|
||||||
@ -842,8 +842,8 @@ extern uint8_t esp8266_gpioToFn[16];
|
|||||||
#define I2STXCM (0) //I2S_TX_CHAN_MOD_S
|
#define I2STXCM (0) //I2S_TX_CHAN_MOD_S
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Random Number Generator 32bit
|
Random Number Generator 32bit
|
||||||
http://esp8266-re.foogod.com/wiki/Random_Number_Generator
|
http://esp8266-re.foogod.com/wiki/Random_Number_Generator
|
||||||
**/
|
**/
|
||||||
#define RANDOM_REG32 ESP8266_DREG(0x20E44)
|
#define RANDOM_REG32 ESP8266_DREG(0x20E44)
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
flash_utils.h - Flash access function and data structures
|
flash_utils.h - Flash access function and data structures
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All right reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -26,10 +26,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Definitions are placed in eboot. Include them here rather than duplicate them.
|
/* 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
|
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.
|
rather than have eboot depend on the core.
|
||||||
*/
|
*/
|
||||||
#include <../../bootloaders/eboot/flash.h>
|
#include <../../bootloaders/eboot/flash.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,44 +1,44 @@
|
|||||||
/*
|
/*
|
||||||
gdb_hooks.c - Default (no-op) hooks for GDB Stub library
|
gdb_hooks.c - Default (no-op) hooks for GDB Stub library
|
||||||
Copyright (c) 2018 Ivan Grokhotkov. All right reserved.
|
Copyright (c) 2018 Ivan Grokhotkov. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ets_sys.h"
|
#include "ets_sys.h"
|
||||||
#include "gdb_hooks.h"
|
#include "gdb_hooks.h"
|
||||||
|
|
||||||
|
|
||||||
/* gdb_init and gdb_do_break do not return anything, but since the return
|
/* gdb_init and gdb_do_break do not return anything, but since the return
|
||||||
value is in register, it doesn't hurt to return a bool, so that the
|
value is in register, it doesn't hurt to return a bool, so that the
|
||||||
same stub can be used for gdb_present. */
|
same stub can be used for gdb_present. */
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static bool ICACHE_RAM_ATTR __gdb_no_op()
|
static bool ICACHE_RAM_ATTR __gdb_no_op()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdb_init(void) __attribute__ ((weak, alias("__gdb_no_op")));
|
void gdb_init(void) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
void gdb_do_break(void) __attribute__ ((weak, alias("__gdb_no_op")));
|
void gdb_do_break(void) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
bool gdb_present(void) __attribute__ ((weak, alias("__gdb_no_op")));
|
bool gdb_present(void) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
bool gdbstub_has_putc1_control(void) __attribute__ ((weak, alias("__gdb_no_op")));
|
bool gdbstub_has_putc1_control(void) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
void gdbstub_set_putc1_callback(void (*func)(char)) __attribute__ ((weak, alias("__gdb_no_op")));
|
void gdbstub_set_putc1_callback(void (*func)(char)) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
bool gdbstub_has_uart_isr_control(void) __attribute__ ((weak, alias("__gdb_no_op")));
|
bool gdbstub_has_uart_isr_control(void) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
void gdbstub_set_uart_isr_callback(void (*func)(void*, uint8_t), void* arg) __attribute__ ((weak, alias("__gdb_no_op")));
|
void gdbstub_set_uart_isr_callback(void (*func)(void*, uint8_t), void* arg) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
void gdbstub_write_char(char c) __attribute__ ((weak, alias("__gdb_no_op")));
|
void gdbstub_write_char(char c) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
void gdbstub_write(const char* buf, size_t size) __attribute__ ((weak, alias("__gdb_no_op")));
|
void gdbstub_write(const char* buf, size_t size) __attribute__((weak, alias("__gdb_no_op")));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
gdb_hooks.h - Hooks for GDB Stub library
|
gdb_hooks.h - Hooks for GDB Stub library
|
||||||
Copyright (c) 2018 Ivan Grokhotkov. All right reserved.
|
Copyright (c) 2018 Ivan Grokhotkov. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -24,97 +24,97 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize GDB stub, if present
|
@brief Initialize GDB stub, if present
|
||||||
*
|
|
||||||
* By default, this function is a no-op. When GDBStub library is linked,
|
By default, this function is a no-op. When GDBStub library is linked,
|
||||||
* this function is overriden and does necessary initialization of that library.
|
this function is overriden and does necessary initialization of that library.
|
||||||
* Called early at startup.
|
Called early at startup.
|
||||||
*/
|
*/
|
||||||
void gdb_init(void);
|
void gdb_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Break into GDB, if present
|
@brief Break into GDB, if present
|
||||||
*
|
|
||||||
* By default, this function is a no-op. When GDBStub library is linked,
|
By default, this function is a no-op. When GDBStub library is linked,
|
||||||
* this function is overriden and triggers entry into the debugger, which
|
this function is overriden and triggers entry into the debugger, which
|
||||||
* looks like a breakpoint hit.
|
looks like a breakpoint hit.
|
||||||
*/
|
*/
|
||||||
void gdb_do_break(void);
|
void gdb_do_break(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if GDB stub is present.
|
@brief Check if GDB stub is present.
|
||||||
*
|
|
||||||
* By default, this function returns false. When GDBStub library is linked,
|
By default, this function returns false. When GDBStub library is linked,
|
||||||
* this function is overriden and returns true. Can be used to check whether
|
this function is overriden and returns true. Can be used to check whether
|
||||||
* GDB is used.
|
GDB is used.
|
||||||
*
|
|
||||||
* @return true if GDB stub is present
|
@return true if GDB stub is present
|
||||||
*/
|
*/
|
||||||
bool gdb_present(void);
|
bool gdb_present(void);
|
||||||
|
|
||||||
// If gdbstub has these set true, then we will disable our own
|
// If gdbstub has these set true, then we will disable our own
|
||||||
// usage of them, but use gdbstub's callbacks for them instead
|
// usage of them, but use gdbstub's callbacks for them instead
|
||||||
/**
|
/**
|
||||||
* @brief Check 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,
|
By default, this function returns false. When GDBStub library is linked,
|
||||||
* this function is overriden and returns true.
|
this function is overriden and returns true.
|
||||||
*
|
|
||||||
* @return true if GDB is installing a putc1 callback
|
@return true if GDB is installing a putc1 callback
|
||||||
*/
|
*/
|
||||||
bool gdbstub_has_putc1_control(void);
|
bool gdbstub_has_putc1_control(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a putc1 callback with GDB.
|
@brief Register a putc1 callback with GDB.
|
||||||
* @param func function GDB will proxy putc1 data to
|
@param func function GDB will proxy putc1 data to
|
||||||
*
|
|
||||||
* By default, this function is a no-op. When GDBStub library is linked,
|
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
|
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,
|
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.
|
then GDB stub will pass putc1 chars directly to this function.
|
||||||
*/
|
*/
|
||||||
void gdbstub_set_putc1_callback(void (*func)(char));
|
void gdbstub_set_putc1_callback(void (*func)(char));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check 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,
|
By default, this function returns false. When GDBStub library is linked,
|
||||||
* this function is overriden and returns true.
|
this function is overriden and returns true.
|
||||||
*
|
|
||||||
* @return true if GDB is installing a uart0 isr callback
|
@return true if GDB is installing a uart0 isr callback
|
||||||
*/
|
*/
|
||||||
bool gdbstub_has_uart_isr_control(void);
|
bool gdbstub_has_uart_isr_control(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a uart0 isr callback with GDB.
|
@brief Register a uart0 isr callback with GDB.
|
||||||
* @param func function GDB will proxy uart0 isr data to
|
@param func function GDB will proxy uart0 isr data to
|
||||||
*
|
|
||||||
* By default, this function is a no-op. When GDBStub library is linked,
|
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
|
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,
|
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.
|
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);
|
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.
|
@brief Write a character for output to a GDB session on uart0.
|
||||||
* @param c character to write
|
@param c character to write
|
||||||
*
|
|
||||||
* By default, this function is a no-op. When GDBStub library is linked,
|
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
|
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.
|
uart0 or directly to uart0 if not GDB session is attached.
|
||||||
*/
|
*/
|
||||||
void gdbstub_write_char(char c);
|
void gdbstub_write_char(char c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write a char buffer for output to a GDB session on uart0.
|
@brief Write a char buffer for output to a GDB session on uart0.
|
||||||
* @param buf buffer of data to write
|
@param buf buffer of data to write
|
||||||
* @param size length of buffer
|
@param size length of buffer
|
||||||
*
|
|
||||||
* By default, this function is a no-op. When GDBStub library is linked,
|
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
|
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.
|
uart0 or directly to uart0 if not GDB session is attached.
|
||||||
*/
|
*/
|
||||||
void gdbstub_write(const char* buf, size_t size);
|
void gdbstub_write(const char* buf, size_t size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* heap.c - overrides of SDK heap handling functions
|
/* heap.c - overrides of SDK heap handling functions
|
||||||
* Copyright (c) 2016 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2016 Ivan Grokhotkov. All rights reserved.
|
||||||
* This file is distributed under MIT license.
|
This file is distributed under MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "umm_malloc/umm_malloc.h"
|
#include "umm_malloc/umm_malloc.h"
|
||||||
@ -10,186 +10,201 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
// Debugging helper, last allocation which returned NULL
|
// Debugging helper, last allocation which returned NULL
|
||||||
void *umm_last_fail_alloc_addr = NULL;
|
void *umm_last_fail_alloc_addr = NULL;
|
||||||
int umm_last_fail_alloc_size = 0;
|
int umm_last_fail_alloc_size = 0;
|
||||||
|
|
||||||
void* _malloc_r(struct _reent* unused, size_t size)
|
void* _malloc_r(struct _reent* unused, size_t size)
|
||||||
{
|
{
|
||||||
(void) unused;
|
(void) unused;
|
||||||
void *ret = malloc(size);
|
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;
|
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
||||||
|
umm_last_fail_alloc_size = size;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _free_r(struct _reent* unused, void* ptr)
|
void _free_r(struct _reent* unused, void* ptr)
|
||||||
{
|
{
|
||||||
(void) unused;
|
(void) unused;
|
||||||
return free(ptr);
|
return free(ptr);
|
||||||
}
|
|
||||||
|
|
||||||
void* _realloc_r(struct _reent* unused, void* ptr, size_t size)
|
|
||||||
{
|
|
||||||
(void) unused;
|
|
||||||
void *ret = realloc(ptr, size);
|
|
||||||
if (0 != size && 0 == ret) {
|
|
||||||
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
|
||||||
umm_last_fail_alloc_size = size;
|
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* _calloc_r(struct _reent* unused, size_t count, size_t size)
|
void* _realloc_r(struct _reent* unused, void* ptr, size_t size)
|
||||||
{
|
{
|
||||||
(void) unused;
|
(void) unused;
|
||||||
void *ret = calloc(count, size);
|
void *ret = realloc(ptr, size);
|
||||||
if (0 != (count * size) && 0 == ret) {
|
if (0 != size && 0 == ret)
|
||||||
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
{
|
||||||
umm_last_fail_alloc_size = count * size;
|
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
||||||
|
umm_last_fail_alloc_size = size;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line)
|
void* _calloc_r(struct _reent* unused, size_t count, size_t size)
|
||||||
{
|
{
|
||||||
(void) file;
|
(void) unused;
|
||||||
(void) line;
|
void *ret = calloc(count, size);
|
||||||
free(ptr);
|
if (0 != (count * size) && 0 == ret)
|
||||||
}
|
{
|
||||||
|
umm_last_fail_alloc_addr = __builtin_return_address(0);
|
||||||
|
umm_last_fail_alloc_size = count * size;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line)
|
||||||
|
{
|
||||||
|
(void) file;
|
||||||
|
(void) line;
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ESP_OOM
|
#ifdef DEBUG_ESP_OOM
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
return malloc_loc(size, file, line);
|
return malloc_loc(size, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
return calloc_loc(count, size, file, line);
|
return calloc_loc(count, size, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
return realloc_loc(ptr, size, file, line);
|
return realloc_loc(ptr, size, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
return calloc_loc(1, size, file, line);
|
return calloc_loc(1, size, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef malloc
|
#undef malloc
|
||||||
#undef calloc
|
#undef calloc
|
||||||
#undef realloc
|
#undef realloc
|
||||||
|
|
||||||
static const char oom_fmt[] PROGMEM STORE_ATTR = ":oom(%d)@?\n";
|
static const char oom_fmt[] PROGMEM STORE_ATTR = ":oom(%d)@?\n";
|
||||||
static const char oom_fmt_1[] PROGMEM STORE_ATTR = ":oom(%d)@";
|
static const char oom_fmt_1[] PROGMEM STORE_ATTR = ":oom(%d)@";
|
||||||
static const char oom_fmt_2[] PROGMEM STORE_ATTR = ":%d\n";
|
static const char oom_fmt_2[] PROGMEM STORE_ATTR = ":%d\n";
|
||||||
|
|
||||||
void* malloc (size_t s)
|
void* malloc(size_t s)
|
||||||
{
|
{
|
||||||
void* ret = umm_malloc(s);
|
void* ret = umm_malloc(s);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
os_printf(oom_fmt, (int)s);
|
{
|
||||||
return ret;
|
os_printf(oom_fmt, (int)s);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void* calloc (size_t n, size_t s)
|
void* calloc(size_t n, size_t s)
|
||||||
{
|
{
|
||||||
void* ret = umm_calloc(n, s);
|
void* ret = umm_calloc(n, s);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
os_printf(oom_fmt, (int)s);
|
{
|
||||||
return ret;
|
os_printf(oom_fmt, (int)s);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void* realloc (void* p, size_t s)
|
void* realloc(void* p, size_t s)
|
||||||
{
|
{
|
||||||
void* ret = umm_realloc(p, s);
|
void* ret = umm_realloc(p, s);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
os_printf(oom_fmt, (int)s);
|
{
|
||||||
return ret;
|
os_printf(oom_fmt, (int)s);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void print_loc (size_t s, const char* file, int line)
|
void print_loc(size_t s, const char* file, int line)
|
||||||
{
|
{
|
||||||
os_printf(oom_fmt_1, (int)s);
|
os_printf(oom_fmt_1, (int)s);
|
||||||
os_printf(file);
|
os_printf(file);
|
||||||
os_printf(oom_fmt_2, line);
|
os_printf(oom_fmt_2, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* malloc_loc (size_t s, const char* file, int line)
|
void* malloc_loc(size_t s, const char* file, int line)
|
||||||
{
|
{
|
||||||
void* ret = umm_malloc(s);
|
void* ret = umm_malloc(s);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
print_loc(s, file, line);
|
{
|
||||||
return ret;
|
print_loc(s, file, line);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void* calloc_loc (size_t n, size_t s, const char* file, int line)
|
void* calloc_loc(size_t n, size_t s, const char* file, int line)
|
||||||
{
|
{
|
||||||
void* ret = umm_calloc(n, s);
|
void* ret = umm_calloc(n, s);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
print_loc(s, file, line);
|
{
|
||||||
return ret;
|
print_loc(s, file, line);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void* realloc_loc (void* p, size_t s, const char* file, int line)
|
void* realloc_loc(void* p, size_t s, const char* file, int line)
|
||||||
{
|
{
|
||||||
void* ret = umm_realloc(p, s);
|
void* ret = umm_realloc(p, s);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
print_loc(s, file, line);
|
{
|
||||||
return ret;
|
print_loc(s, file, line);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
(void) file;
|
(void) file;
|
||||||
(void) line;
|
(void) line;
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
(void) file;
|
(void) file;
|
||||||
(void) line;
|
(void) line;
|
||||||
return calloc(count, size);
|
return calloc(count, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
(void) file;
|
(void) file;
|
||||||
(void) line;
|
(void) line;
|
||||||
return realloc(ptr, size);
|
return realloc(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line)
|
void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line)
|
||||||
{
|
{
|
||||||
(void) file;
|
(void) file;
|
||||||
(void) line;
|
(void) line;
|
||||||
return calloc(1, size);
|
return calloc(1, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !defined(DEBUG_ESP_OOM)
|
#endif // !defined(DEBUG_ESP_OOM)
|
||||||
|
|
||||||
size_t xPortGetFreeHeapSize(void)
|
size_t xPortGetFreeHeapSize(void)
|
||||||
{
|
{
|
||||||
return umm_free_heap_size();
|
return umm_free_heap_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ICACHE_RAM_ATTR xPortWantedSizeAlign(size_t size)
|
size_t ICACHE_RAM_ATTR xPortWantedSizeAlign(size_t size)
|
||||||
{
|
{
|
||||||
return (size + 3) & ~((size_t) 3);
|
return (size + 3) & ~((size_t) 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void system_show_malloc(void)
|
void system_show_malloc(void)
|
||||||
{
|
{
|
||||||
umm_info(NULL, 1);
|
umm_info(NULL, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
/*
|
/*
|
||||||
i2s.h - Software I2S library for esp8266
|
i2s.h - Software I2S library for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 I2S_h
|
#ifndef I2S_h
|
||||||
#define I2S_h
|
#define I2S_h
|
||||||
|
|
||||||
/*
|
/*
|
||||||
How does this work? Basically, to get sound, you need to:
|
How does this work? Basically, to get sound, you need to:
|
||||||
- Connect an I2S codec to the I2S pins on the ESP.
|
- Connect an I2S codec to the I2S pins on the ESP.
|
||||||
- Start up a thread that's going to do the sound output
|
- Start up a thread that's going to do the sound output
|
||||||
- Call i2s_begin()
|
- Call i2s_begin()
|
||||||
- Call i2s_set_rate() with the sample rate you want.
|
- Call i2s_set_rate() with the sample rate you want.
|
||||||
- Generate sound and call i2s_write_sample() with 32-bit samples.
|
- Generate sound and call i2s_write_sample() with 32-bit samples.
|
||||||
The 32bit samples basically are 2 16-bit signed values (the analog values for
|
The 32bit samples basically are 2 16-bit signed values (the analog values for
|
||||||
the left and right channel) concatenated as (Rout<<16)+Lout
|
the left and right channel) concatenated as (Rout<<16)+Lout
|
||||||
|
|
||||||
i2s_write_sample will block when you're sending data too quickly, so you can just
|
i2s_write_sample will block when you're sending data too quickly, so you can just
|
||||||
generate and push data as fast as you can and i2s_write_sample will regulate the
|
generate and push data as fast as you can and i2s_write_sample will regulate the
|
||||||
speed.
|
speed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -56,15 +56,15 @@ bool i2s_rx_is_full();
|
|||||||
bool i2s_rx_is_empty();
|
bool i2s_rx_is_empty();
|
||||||
uint16_t i2s_available();// returns the number of samples than can be written before blocking
|
uint16_t i2s_available();// returns the number of samples than can be written before blocking
|
||||||
uint16_t i2s_rx_available();// returns the number of samples than can be written before blocking
|
uint16_t i2s_rx_available();// returns the number of samples than can be written before blocking
|
||||||
void i2s_set_callback(void (*callback) (void));
|
void i2s_set_callback(void (*callback)(void));
|
||||||
void i2s_rx_set_callback(void (*callback) (void));
|
void i2s_rx_set_callback(void (*callback)(void));
|
||||||
|
|
||||||
// writes a buffer of frames into the DMA memory, returns the amount of frames written
|
// 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.
|
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
|
||||||
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count);
|
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count);
|
||||||
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count);
|
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count);
|
||||||
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count);
|
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count);
|
||||||
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count);
|
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -9,29 +9,33 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// these auto classes wrap up xt_rsil so your code can be simplier, but can only be
|
// these auto classes wrap up xt_rsil so your code can be simplier, but can only be
|
||||||
// used in an ino or cpp files.
|
// used in an ino or cpp files.
|
||||||
|
|
||||||
// InterruptLock is used when you want to completely disable interrupts
|
// InterruptLock is used when you want to completely disable interrupts
|
||||||
//{
|
//{
|
||||||
// {
|
// {
|
||||||
// InterruptLock lock;
|
// InterruptLock lock;
|
||||||
// // do work within interrupt lock here
|
// // do work within interrupt lock here
|
||||||
// }
|
// }
|
||||||
// do work outside of interrupt lock here outside its scope
|
// do work outside of interrupt lock here outside its scope
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
|
|
||||||
class InterruptLock {
|
class InterruptLock
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
InterruptLock() {
|
InterruptLock()
|
||||||
|
{
|
||||||
_state = xt_rsil(15);
|
_state = xt_rsil(15);
|
||||||
}
|
}
|
||||||
|
|
||||||
~InterruptLock() {
|
~InterruptLock()
|
||||||
|
{
|
||||||
xt_wsr_ps(_state);
|
xt_wsr_ps(_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t savedInterruptLevel() const {
|
uint32_t savedInterruptLevel() const
|
||||||
|
{
|
||||||
return _state & 0x0f;
|
return _state & 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +61,6 @@ public: \
|
|||||||
private: \
|
private: \
|
||||||
uint32_t _savedPS; \
|
uint32_t _savedPS; \
|
||||||
}; \
|
}; \
|
||||||
_AutoDisableIntr _autoDisableIntr
|
_AutoDisableIntr _autoDisableIntr
|
||||||
|
|
||||||
#endif //INTERRUPTS_H
|
#endif //INTERRUPTS_H
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
cdecoder.c - c source to a base64 decoding algorithm implementation
|
cdecoder.c - c source to a base64 decoding algorithm implementation
|
||||||
|
|
||||||
This is part of the libb64 project, and has been placed in the public domain.
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
For details, see http://sourceforge.net/projects/libb64
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pgmspace.h>
|
#include <pgmspace.h>
|
||||||
@ -11,94 +11,117 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
|
|
||||||
extern "C" {
|
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);
|
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};
|
||||||
value_in -= 43;
|
static const int8_t decoding_size = sizeof(decoding);
|
||||||
if (value_in < 0 || value_in > decoding_size) return -1;
|
value_in -= 43;
|
||||||
return pgm_read_byte( &decoding[(int)value_in] );
|
if (value_in < 0 || value_in > decoding_size)
|
||||||
}
|
{
|
||||||
|
return -1;
|
||||||
void base64_init_decodestate(base64_decodestate* state_in){
|
}
|
||||||
state_in->step = step_a;
|
return pgm_read_byte(&decoding[(int)value_in]);
|
||||||
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){
|
|
||||||
const int8_t* codechar = code_in;
|
|
||||||
int8_t* plainchar = plaintext_out;
|
|
||||||
int8_t fragment;
|
|
||||||
|
|
||||||
*plainchar = state_in->plainchar;
|
|
||||||
|
|
||||||
switch (state_in->step){
|
|
||||||
while (1){
|
|
||||||
case step_a:
|
|
||||||
do {
|
|
||||||
if (codechar == code_in+length_in){
|
|
||||||
state_in->step = step_a;
|
|
||||||
state_in->plainchar = *plainchar;
|
|
||||||
return plainchar - plaintext_out;
|
|
||||||
}
|
|
||||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
|
||||||
} while (fragment < 0);
|
|
||||||
*plainchar = (fragment & 0x03f) << 2;
|
|
||||||
case step_b:
|
|
||||||
do {
|
|
||||||
if (codechar == code_in+length_in){
|
|
||||||
state_in->step = step_b;
|
|
||||||
state_in->plainchar = *plainchar;
|
|
||||||
return plainchar - plaintext_out;
|
|
||||||
}
|
|
||||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
|
||||||
} while (fragment < 0);
|
|
||||||
*plainchar++ |= (fragment & 0x030) >> 4;
|
|
||||||
*plainchar = (fragment & 0x00f) << 4;
|
|
||||||
case step_c:
|
|
||||||
do {
|
|
||||||
if (codechar == code_in+length_in){
|
|
||||||
state_in->step = step_c;
|
|
||||||
state_in->plainchar = *plainchar;
|
|
||||||
return plainchar - plaintext_out;
|
|
||||||
}
|
|
||||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
|
||||||
} while (fragment < 0);
|
|
||||||
*plainchar++ |= (fragment & 0x03c) >> 2;
|
|
||||||
*plainchar = (fragment & 0x003) << 6;
|
|
||||||
case step_d:
|
|
||||||
do {
|
|
||||||
if (codechar == code_in+length_in){
|
|
||||||
state_in->step = step_d;
|
|
||||||
state_in->plainchar = *plainchar;
|
|
||||||
return plainchar - plaintext_out;
|
|
||||||
}
|
|
||||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
|
||||||
} while (fragment < 0);
|
|
||||||
*plainchar++ |= (fragment & 0x03f);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* control should not reach here */
|
|
||||||
return plainchar - plaintext_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out){
|
void base64_init_decodestate(base64_decodestate* state_in)
|
||||||
base64_decodestate _state;
|
{
|
||||||
base64_init_decodestate(&_state);
|
state_in->step = step_a;
|
||||||
int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state);
|
state_in->plainchar = 0;
|
||||||
if(len > 0) plaintext_out[len] = 0;
|
}
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int base64_decode_value(char value_in){
|
static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in)
|
||||||
return base64_decode_value_signed(*((int8_t *) &value_in));
|
{
|
||||||
}
|
const int8_t* codechar = code_in;
|
||||||
|
int8_t* plainchar = plaintext_out;
|
||||||
|
int8_t fragment;
|
||||||
|
|
||||||
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){
|
*plainchar = state_in->plainchar;
|
||||||
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){
|
switch (state_in->step)
|
||||||
return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out);
|
{
|
||||||
}
|
while (1)
|
||||||
|
{
|
||||||
|
case step_a:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (codechar == code_in + length_in)
|
||||||
|
{
|
||||||
|
state_in->step = step_a;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar = (fragment & 0x03f) << 2;
|
||||||
|
case step_b:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (codechar == code_in + length_in)
|
||||||
|
{
|
||||||
|
state_in->step = step_b;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar++ |= (fragment & 0x030) >> 4;
|
||||||
|
*plainchar = (fragment & 0x00f) << 4;
|
||||||
|
case step_c:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (codechar == code_in + length_in)
|
||||||
|
{
|
||||||
|
state_in->step = step_c;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar++ |= (fragment & 0x03c) >> 2;
|
||||||
|
*plainchar = (fragment & 0x003) << 6;
|
||||||
|
case step_d:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (codechar == code_in + length_in)
|
||||||
|
{
|
||||||
|
state_in->step = step_d;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar++ |= (fragment & 0x03f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* control should not reach here */
|
||||||
|
return plainchar - 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;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
cdecode.h - c header for a base64 decoding algorithm
|
cdecode.h - c header for a base64 decoding algorithm
|
||||||
|
|
||||||
This is part of the libb64 project, and has been placed in the public domain.
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
For details, see http://sourceforge.net/projects/libb64
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BASE64_CDECODE_H
|
#ifndef BASE64_CDECODE_H
|
||||||
@ -14,13 +14,15 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
step_a, step_b, step_c, step_d
|
{
|
||||||
|
step_a, step_b, step_c, step_d
|
||||||
} base64_decodestep;
|
} base64_decodestep;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
base64_decodestep step;
|
{
|
||||||
char plainchar;
|
base64_decodestep step;
|
||||||
|
char plainchar;
|
||||||
} base64_decodestate;
|
} base64_decodestate;
|
||||||
|
|
||||||
void base64_init_decodestate(base64_decodestate* state_in);
|
void base64_init_decodestate(base64_decodestate* state_in);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
cencoder.c - c source to a base64 encoding algorithm implementation
|
cencoder.c - c source to a base64 encoding algorithm implementation
|
||||||
|
|
||||||
This is part of the libb64 project, and has been placed in the public domain.
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
For details, see http://sourceforge.net/projects/libb64
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pgmspace.h>
|
#include <pgmspace.h>
|
||||||
@ -10,105 +10,121 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
|
|
||||||
extern "C" {
|
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;
|
|
||||||
state_in->stepsnewline = BASE64_CHARS_PER_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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){
|
|
||||||
static const char encoding[] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
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){
|
|
||||||
const char* plainchar = plaintext_in;
|
|
||||||
const char* const plaintextend = plaintext_in + length_in;
|
|
||||||
char* codechar = code_out;
|
|
||||||
char result;
|
|
||||||
char fragment;
|
|
||||||
|
|
||||||
result = state_in->result;
|
|
||||||
|
|
||||||
switch (state_in->step){
|
|
||||||
while (1){
|
|
||||||
case step_A:
|
|
||||||
if (plainchar == plaintextend){
|
|
||||||
state_in->result = result;
|
|
||||||
state_in->step = step_A;
|
state_in->step = step_A;
|
||||||
return codechar - code_out;
|
state_in->result = 0;
|
||||||
}
|
|
||||||
fragment = *plainchar++;
|
|
||||||
result = (fragment & 0x0fc) >> 2;
|
|
||||||
*codechar++ = base64_encode_value(result);
|
|
||||||
result = (fragment & 0x003) << 4;
|
|
||||||
case step_B:
|
|
||||||
if (plainchar == plaintextend){
|
|
||||||
state_in->result = result;
|
|
||||||
state_in->step = step_B;
|
|
||||||
return codechar - code_out;
|
|
||||||
}
|
|
||||||
fragment = *plainchar++;
|
|
||||||
result |= (fragment & 0x0f0) >> 4;
|
|
||||||
*codechar++ = base64_encode_value(result);
|
|
||||||
result = (fragment & 0x00f) << 2;
|
|
||||||
case step_C:
|
|
||||||
if (plainchar == plaintextend){
|
|
||||||
state_in->result = result;
|
|
||||||
state_in->step = step_C;
|
|
||||||
return codechar - code_out;
|
|
||||||
}
|
|
||||||
fragment = *plainchar++;
|
|
||||||
result |= (fragment & 0x0c0) >> 6;
|
|
||||||
*codechar++ = base64_encode_value(result);
|
|
||||||
result = (fragment & 0x03f) >> 0;
|
|
||||||
*codechar++ = base64_encode_value(result);
|
|
||||||
|
|
||||||
++(state_in->stepcount);
|
|
||||||
if ((state_in->stepcount == BASE64_CHARS_PER_LINE/4) && (state_in->stepsnewline > 0)){
|
|
||||||
*codechar++ = '\n';
|
|
||||||
state_in->stepcount = 0;
|
state_in->stepcount = 0;
|
||||||
}
|
state_in->stepsnewline = BASE64_CHARS_PER_LINE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* control should not reach here */
|
|
||||||
return codechar - code_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in){
|
|
||||||
char* codechar = code_out;
|
|
||||||
|
|
||||||
switch (state_in->step){
|
|
||||||
case step_B:
|
|
||||||
*codechar++ = base64_encode_value(state_in->result);
|
|
||||||
*codechar++ = '=';
|
|
||||||
*codechar++ = '=';
|
|
||||||
break;
|
|
||||||
case step_C:
|
|
||||||
*codechar++ = base64_encode_value(state_in->result);
|
|
||||||
*codechar++ = '=';
|
|
||||||
break;
|
|
||||||
case step_A:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*codechar = 0x00;
|
|
||||||
|
|
||||||
return codechar - code_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out){
|
void base64_init_encodestate_nonewlines(base64_encodestate* state_in)
|
||||||
base64_encodestate _state;
|
{
|
||||||
base64_init_encodestate(&_state);
|
base64_init_encodestate(state_in);
|
||||||
int len = base64_encode_block(plaintext_in, length_in, code_out, &_state);
|
state_in->stepsnewline = -1;
|
||||||
return len + base64_encode_blockend((code_out + len), &_state);
|
}
|
||||||
}
|
|
||||||
|
char base64_encode_value(char value_in)
|
||||||
|
{
|
||||||
|
static const char encoding[] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const char* plainchar = plaintext_in;
|
||||||
|
const char* const plaintextend = plaintext_in + length_in;
|
||||||
|
char* codechar = code_out;
|
||||||
|
char result;
|
||||||
|
char fragment;
|
||||||
|
|
||||||
|
result = state_in->result;
|
||||||
|
|
||||||
|
switch (state_in->step)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
case step_A:
|
||||||
|
if (plainchar == plaintextend)
|
||||||
|
{
|
||||||
|
state_in->result = result;
|
||||||
|
state_in->step = step_A;
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
fragment = *plainchar++;
|
||||||
|
result = (fragment & 0x0fc) >> 2;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
result = (fragment & 0x003) << 4;
|
||||||
|
case step_B:
|
||||||
|
if (plainchar == plaintextend)
|
||||||
|
{
|
||||||
|
state_in->result = result;
|
||||||
|
state_in->step = step_B;
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
fragment = *plainchar++;
|
||||||
|
result |= (fragment & 0x0f0) >> 4;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
result = (fragment & 0x00f) << 2;
|
||||||
|
case step_C:
|
||||||
|
if (plainchar == plaintextend)
|
||||||
|
{
|
||||||
|
state_in->result = result;
|
||||||
|
state_in->step = step_C;
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
fragment = *plainchar++;
|
||||||
|
result |= (fragment & 0x0c0) >> 6;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
result = (fragment & 0x03f) >> 0;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
|
||||||
|
++(state_in->stepcount);
|
||||||
|
if ((state_in->stepcount == BASE64_CHARS_PER_LINE / 4) && (state_in->stepsnewline > 0))
|
||||||
|
{
|
||||||
|
*codechar++ = '\n';
|
||||||
|
state_in->stepcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* control should not reach here */
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||||
|
{
|
||||||
|
char* codechar = code_out;
|
||||||
|
|
||||||
|
switch (state_in->step)
|
||||||
|
{
|
||||||
|
case step_B:
|
||||||
|
*codechar++ = base64_encode_value(state_in->result);
|
||||||
|
*codechar++ = '=';
|
||||||
|
*codechar++ = '=';
|
||||||
|
break;
|
||||||
|
case step_C:
|
||||||
|
*codechar++ = base64_encode_value(state_in->result);
|
||||||
|
*codechar++ = '=';
|
||||||
|
break;
|
||||||
|
case step_A:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*codechar = 0x00;
|
||||||
|
|
||||||
|
return codechar - 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);
|
||||||
|
return len + base64_encode_blockend((code_out + len), &_state);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
cencode.h - c header for a base64 encoding algorithm
|
cencode.h - c header for a base64 encoding algorithm
|
||||||
|
|
||||||
This is part of the libb64 project, and has been placed in the public domain.
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
For details, see http://sourceforge.net/projects/libb64
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BASE64_CENCODE_H
|
#ifndef BASE64_CENCODE_H
|
||||||
@ -19,15 +19,17 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
step_A, step_B, step_C
|
{
|
||||||
|
step_A, step_B, step_C
|
||||||
} base64_encodestep;
|
} base64_encodestep;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
base64_encodestep step;
|
{
|
||||||
char result;
|
base64_encodestep step;
|
||||||
int stepcount;
|
char result;
|
||||||
int stepsnewline;
|
int stepcount;
|
||||||
|
int stepsnewline;
|
||||||
} base64_encodestate;
|
} base64_encodestate;
|
||||||
|
|
||||||
void base64_init_encodestate(base64_encodestate* state_in);
|
void base64_init_encodestate(base64_encodestate* state_in);
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
libc_replacements.c - replaces libc functions with functions
|
libc_replacements.c - replaces libc functions with functions
|
||||||
from Espressif SDK
|
from Espressif SDK
|
||||||
|
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
Modified 03 April 2015 by Markus Sattler
|
Modified 03 April 2015 by Markus Sattler
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -47,88 +47,103 @@
|
|||||||
|
|
||||||
extern "C" {
|
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)unused;
|
||||||
(void)mode;
|
(void)ptr;
|
||||||
return 0;
|
(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;
|
(void)unused;
|
||||||
return 0;
|
(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;
|
(void)unused;
|
||||||
st->st_mode = S_IFCHR;
|
(void)file;
|
||||||
return 0;
|
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)unused;
|
||||||
(void)ptr;
|
(void)file;
|
||||||
(void)dir;
|
(void)ptr;
|
||||||
return 0;
|
(void)dir;
|
||||||
}
|
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)unused;
|
||||||
(void)ptr;
|
(void)file;
|
||||||
(void)len;
|
(void)ptr;
|
||||||
return 0;
|
(void)len;
|
||||||
}
|
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;
|
(void) r;
|
||||||
if (file == STDOUT_FILENO) {
|
int pos = len;
|
||||||
while(pos--) {
|
if (file == STDOUT_FILENO)
|
||||||
ets_putc(*ptr);
|
{
|
||||||
++ptr;
|
while (pos--)
|
||||||
|
{
|
||||||
|
ets_putc(*ptr);
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) __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) {
|
(void) r;
|
||||||
return ets_putc(c);
|
if (file->_file == STDOUT_FILENO)
|
||||||
|
{
|
||||||
|
return ets_putc(c);
|
||||||
|
}
|
||||||
|
return EOF;
|
||||||
}
|
}
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ICACHE_RAM_ATTR puts(const char * str) {
|
int ICACHE_RAM_ATTR puts(const char * str)
|
||||||
char c;
|
{
|
||||||
while((c = *str) != 0) {
|
char c;
|
||||||
ets_putc(c);
|
while ((c = *str) != 0)
|
||||||
++str;
|
{
|
||||||
|
ets_putc(c);
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
ets_putc('\n');
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
ets_putc('\n');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef putchar
|
#undef putchar
|
||||||
int ICACHE_RAM_ATTR putchar(int c) {
|
int ICACHE_RAM_ATTR putchar(int c)
|
||||||
ets_putc(c);
|
{
|
||||||
return c;
|
ets_putc(c);
|
||||||
}
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
void _exit(int status) {
|
void _exit(int status)
|
||||||
(void) status;
|
{
|
||||||
abort();
|
(void) status;
|
||||||
}
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
int atexit(void (*func)()) {
|
int atexit(void (*func)())
|
||||||
(void) func;
|
{
|
||||||
return 0;
|
(void) func;
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
md5.h - exposed md5 ROM functions for esp8266
|
md5.h - exposed md5 ROM functions for esp8266
|
||||||
|
|
||||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
original C source from https://github.com/morrissinger/ESP8266-Websocket/raw/master/MD5.h
|
original C source from https://github.com/morrissinger/ESP8266-Websocket/raw/master/MD5.h
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#ifndef __ESP8266_MD5__
|
#ifndef __ESP8266_MD5__
|
||||||
#define __ESP8266_MD5__
|
#define __ESP8266_MD5__
|
||||||
@ -27,15 +27,16 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
uint32_t state[4];
|
{
|
||||||
uint32_t count[2];
|
uint32_t state[4];
|
||||||
uint8_t buffer[64];
|
uint32_t count[2];
|
||||||
|
uint8_t buffer[64];
|
||||||
} md5_context_t;
|
} md5_context_t;
|
||||||
|
|
||||||
extern void MD5Init (md5_context_t *);
|
extern void MD5Init(md5_context_t *);
|
||||||
extern void MD5Update (md5_context_t *, const uint8_t *, const uint16_t);
|
extern void MD5Update(md5_context_t *, const uint8_t *, const uint16_t);
|
||||||
extern void MD5Final (uint8_t [16], md5_context_t *);
|
extern void MD5Final(uint8_t [16], md5_context_t *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -1,45 +1,45 @@
|
|||||||
/*
|
/*
|
||||||
sigma_delta.h - esp8266 sigma-delta source
|
sigma_delta.h - esp8266 sigma-delta source
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
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,
|
This library is free software; you can redistribute it and/or
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
modify it under the terms of the GNU Lesser General Public
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
License as published by the Free Software Foundation; either
|
||||||
Lesser General Public License for more details.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
This library is distributed in the hope that it will be useful,
|
||||||
License along with this library; if not, write to the Free Software
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
*/
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Info Sigma delta module
|
|
||||||
|
|
||||||
This module controls the esp8266 internal sigma delta source
|
You should have received a copy of the GNU Lesser General Public
|
||||||
Each pin can be connected to the sigma delta source
|
License along with this library; if not, write to the Free Software
|
||||||
The target duty and frequency can be modified via the register GPIO_SIGMA_DELTA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
THE TARGET FREQUENCY IS DEFINED AS:
|
/*******************************************************************************
|
||||||
|
Info Sigma delta module
|
||||||
|
|
||||||
FREQ = 80,000,000/prescaler * target /256 HZ, 0<target<128
|
This module controls the esp8266 internal sigma delta source
|
||||||
FREQ = 80,000,000/prescaler * (256-target) /256 HZ, 128<target<256
|
Each pin can be connected to the sigma delta source
|
||||||
target: duty cycle,range 0-255
|
The target duty and frequency can be modified via the register GPIO_SIGMA_DELTA
|
||||||
prescaler: is a clock divider, range 0-255
|
|
||||||
so the target and prescale will both affect the freq.
|
|
||||||
CPU_FREQ has no influence on the sigma delta frequency.
|
|
||||||
|
|
||||||
Usage :
|
THE TARGET FREQUENCY IS DEFINED AS:
|
||||||
1. sigmaDeltaSetup(0,f) : activate the sigma delta source with frequency f and default duty cycle (0)
|
|
||||||
2. sigmaDeltaAttachPin(pin), any pin 0..15, TBC if gpio16 supports sigma-delta source
|
FREQ = 80,000,000/prescaler * target /256 HZ, 0<target<128
|
||||||
This will set the pin to NORMAL output mode (pinMode(pin,OUTPUT))
|
FREQ = 80,000,000/prescaler * (256-target) /256 HZ, 128<target<256
|
||||||
3. sigmaDeltaWrite(0,dc) : set the output signal duty cycle, duty cycle = dc/256
|
target: duty cycle,range 0-255
|
||||||
|
prescaler: is a clock divider, range 0-255
|
||||||
|
so the target and prescale will both affect the freq.
|
||||||
|
CPU_FREQ has no influence on the sigma delta frequency.
|
||||||
|
|
||||||
|
Usage :
|
||||||
|
1. sigmaDeltaSetup(0,f) : activate the sigma delta source with frequency f and default duty cycle (0)
|
||||||
|
2. sigmaDeltaAttachPin(pin), any pin 0..15, TBC if gpio16 supports sigma-delta source
|
||||||
|
This will set the pin to NORMAL output mode (pinMode(pin,OUTPUT))
|
||||||
|
3. sigmaDeltaWrite(0,dc) : set the output signal duty cycle, duty cycle = dc/256
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* sntp-lwip2.c - ESP8266-specific functions for SNTP and lwIP-v2
|
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)
|
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,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
* are permitted provided that the following conditions are met:
|
are permitted provided that the following conditions are met:
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
* this list of conditions and the following disclaimer.
|
this list of conditions and the following disclaimer.
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
this list of conditions and the following disclaimer in the documentation
|
||||||
* and/or other materials provided with the distribution.
|
and/or other materials provided with the distribution.
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
3. The name of the author may not be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
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
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
* OF SUCH DAMAGE.
|
OF SUCH DAMAGE.
|
||||||
*
|
|
||||||
*
|
|
||||||
* History:
|
History:
|
||||||
* This code is extracted from lwip1.4-espressif's sntp.c
|
This code is extracted from lwip1.4-espressif's sntp.c
|
||||||
* which is a patched version of the original lwip1's sntp.
|
which is a patched version of the original lwip1's sntp.
|
||||||
* (check the mix-up in tools/sdk/lwip/src/core/sntp.c)
|
(check the mix-up in tools/sdk/lwip/src/core/sntp.c)
|
||||||
* It is moved here as-is and cleaned for maintainability and
|
It is moved here as-is and cleaned for maintainability and
|
||||||
* because it does not belong to lwip.
|
because it does not belong to lwip.
|
||||||
*
|
|
||||||
* TODOs:
|
TODOs:
|
||||||
* settimeofday(): handle tv->tv_usec
|
settimeofday(): handle tv->tv_usec
|
||||||
* sntp_mktm_r(): review, fix DST handling (this one is currently untouched from lwip-1.4)
|
sntp_mktm_r(): review, fix DST handling (this one is currently untouched from lwip-1.4)
|
||||||
* implement adjtime()
|
implement adjtime()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lwip/init.h>
|
#include <lwip/init.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@ -45,46 +45,46 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static void (*_settimeofday_cb)(void) = NULL;
|
static void (*_settimeofday_cb)(void) = NULL;
|
||||||
|
|
||||||
void settimeofday_cb (void (*cb)(void))
|
void settimeofday_cb(void (*cb)(void))
|
||||||
{
|
{
|
||||||
_settimeofday_cb = cb;
|
_settimeofday_cb = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LWIP_VERSION_MAJOR == 1
|
#if LWIP_VERSION_MAJOR == 1
|
||||||
|
|
||||||
#include <pgmspace.h>
|
#include <pgmspace.h>
|
||||||
|
|
||||||
static const char stod14[] PROGMEM = "settimeofday() can't set time!\n";
|
static const char stod14[] PROGMEM = "settimeofday() can't set time!\n";
|
||||||
bool sntp_set_timezone(sint8 timezone);
|
bool sntp_set_timezone(sint8 timezone);
|
||||||
bool sntp_set_timezone_in_seconds(sint32 timezone)
|
bool sntp_set_timezone_in_seconds(sint32 timezone)
|
||||||
{
|
|
||||||
return sntp_set_timezone((sint8)(timezone/(60*60))); //TODO: move this to the same file as sntp_set_timezone() in lwip1.4, and implement correctly over there.
|
|
||||||
}
|
|
||||||
|
|
||||||
void sntp_set_daylight(int daylight);
|
|
||||||
|
|
||||||
int settimeofday(const struct timeval* tv, const struct timezone* tz)
|
|
||||||
{
|
|
||||||
if (tz) /*before*/
|
|
||||||
{
|
{
|
||||||
sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60);
|
return sntp_set_timezone((sint8)(timezone / (60 * 60))); //TODO: move this to the same file as sntp_set_timezone() in lwip1.4, and implement correctly over there.
|
||||||
// apparently tz->tz_dsttime is a bitfield and should not be further used (cf man)
|
|
||||||
sntp_set_daylight(0);
|
|
||||||
}
|
}
|
||||||
if (tv) /* after*/
|
|
||||||
{
|
|
||||||
// can't call lwip1.4's static sntp_set_system_time()
|
|
||||||
os_printf(stod14);
|
|
||||||
|
|
||||||
// reset time subsystem
|
void sntp_set_daylight(int daylight);
|
||||||
timeshift64_is_set = false;
|
|
||||||
|
int settimeofday(const struct timeval* tv, const struct timezone* tz)
|
||||||
return -1;
|
{
|
||||||
|
if (tz) /*before*/
|
||||||
|
{
|
||||||
|
sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60);
|
||||||
|
// apparently tz->tz_dsttime is a bitfield and should not be further used (cf man)
|
||||||
|
sntp_set_daylight(0);
|
||||||
|
}
|
||||||
|
if (tv) /* after*/
|
||||||
|
{
|
||||||
|
// can't call lwip1.4's static sntp_set_system_time()
|
||||||
|
os_printf(stod14);
|
||||||
|
|
||||||
|
// reset time subsystem
|
||||||
|
timeshift64_is_set = false;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // lwip 1.4 only
|
#endif // lwip 1.4 only
|
||||||
|
|
||||||
@ -92,12 +92,12 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz)
|
|||||||
|
|
||||||
#include <lwip/apps/sntp.h>
|
#include <lwip/apps/sntp.h>
|
||||||
|
|
||||||
static uint32 realtime_stamp = 0;
|
static uint32 realtime_stamp = 0;
|
||||||
static uint16 dst = 0;
|
static uint16 dst = 0;
|
||||||
static sint32 time_zone = 8 * (60 * 60); // espressif HQ's default timezone
|
static sint32 time_zone = 8 * (60 * 60); // espressif HQ's default timezone
|
||||||
LOCAL os_timer_t sntp_timer;
|
LOCAL os_timer_t sntp_timer;
|
||||||
|
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
#define SECSPERMIN 60L
|
#define SECSPERMIN 60L
|
||||||
#define MINSPERHOUR 60L
|
#define MINSPERHOUR 60L
|
||||||
#define HOURSPERDAY 24L
|
#define HOURSPERDAY 24L
|
||||||
@ -115,373 +115,404 @@ LOCAL os_timer_t sntp_timer;
|
|||||||
|
|
||||||
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
|
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
|
||||||
|
|
||||||
int __tznorth;
|
int __tznorth;
|
||||||
int __tzyear;
|
int __tzyear;
|
||||||
char reult[100];
|
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] = {
|
|
||||||
365,
|
|
||||||
366
|
|
||||||
} ;
|
|
||||||
struct tm
|
|
||||||
{
|
|
||||||
int tm_sec;
|
|
||||||
int tm_min;
|
|
||||||
int tm_hour;
|
|
||||||
int tm_mday;
|
|
||||||
int tm_mon;
|
|
||||||
int tm_year;
|
|
||||||
int tm_wday;
|
|
||||||
int tm_yday;
|
|
||||||
int tm_isdst;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tm res_buf;
|
|
||||||
typedef struct __tzrule_struct
|
|
||||||
{
|
|
||||||
char ch;
|
|
||||||
int m;
|
|
||||||
int n;
|
|
||||||
int d;
|
|
||||||
int s;
|
|
||||||
time_t change;
|
|
||||||
int offset;
|
|
||||||
} __tzrule_type;
|
|
||||||
|
|
||||||
__tzrule_type sntp__tzrule[2];
|
|
||||||
struct tm *
|
|
||||||
sntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime)
|
|
||||||
{
|
|
||||||
long days, rem;
|
|
||||||
time_t lcltime;
|
|
||||||
int y;
|
|
||||||
int yleap;
|
|
||||||
const int *ip;
|
|
||||||
|
|
||||||
/* base decision about std/dst time on current time */
|
|
||||||
lcltime = *tim_p;
|
|
||||||
|
|
||||||
days = ((long)lcltime) / SECSPERDAY;
|
|
||||||
rem = ((long)lcltime) % SECSPERDAY;
|
|
||||||
while (rem < 0)
|
|
||||||
{
|
{
|
||||||
rem += SECSPERDAY;
|
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||||
--days;
|
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||||
}
|
} ;
|
||||||
while (rem >= SECSPERDAY)
|
|
||||||
|
static const int year_lengths[2] =
|
||||||
{
|
{
|
||||||
rem -= SECSPERDAY;
|
365,
|
||||||
++days;
|
366
|
||||||
}
|
} ;
|
||||||
|
struct tm
|
||||||
/* compute hour, min, and sec */
|
|
||||||
res->tm_hour = (int) (rem / SECSPERHOUR);
|
|
||||||
rem %= SECSPERHOUR;
|
|
||||||
res->tm_min = (int) (rem / SECSPERMIN);
|
|
||||||
res->tm_sec = (int) (rem % SECSPERMIN);
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
if (days >= 0)
|
|
||||||
{
|
{
|
||||||
for (;;)
|
int tm_sec;
|
||||||
{
|
int tm_min;
|
||||||
yleap = isleap(y);
|
int tm_hour;
|
||||||
if (days < year_lengths[yleap])
|
int tm_mday;
|
||||||
break;
|
int tm_mon;
|
||||||
y++;
|
int tm_year;
|
||||||
days -= year_lengths[yleap];
|
int tm_wday;
|
||||||
}
|
int tm_yday;
|
||||||
}
|
int tm_isdst;
|
||||||
else
|
};
|
||||||
|
|
||||||
|
struct tm res_buf;
|
||||||
|
typedef struct __tzrule_struct
|
||||||
{
|
{
|
||||||
do
|
char ch;
|
||||||
{
|
int m;
|
||||||
--y;
|
int n;
|
||||||
yleap = isleap(y);
|
int d;
|
||||||
days += year_lengths[yleap];
|
int s;
|
||||||
} while (days < 0);
|
time_t change;
|
||||||
}
|
int offset;
|
||||||
|
} __tzrule_type;
|
||||||
|
|
||||||
res->tm_year = y - YEAR_BASE;
|
__tzrule_type sntp__tzrule[2];
|
||||||
res->tm_yday = days;
|
struct tm *
|
||||||
ip = mon_lengths[yleap];
|
sntp_mktm_r(const time_t * tim_p, struct tm *res, int is_gmtime)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int offset;
|
long days, rem;
|
||||||
int hours, mins, secs;
|
time_t lcltime;
|
||||||
|
int y;
|
||||||
|
int yleap;
|
||||||
|
const int *ip;
|
||||||
|
|
||||||
// TZ_LOCK;
|
/* base decision about std/dst time on current time */
|
||||||
// if (_daylight)
|
lcltime = *tim_p;
|
||||||
// {
|
|
||||||
// if (y == __tzyear || __tzcalc_limits (y))
|
|
||||||
// res->tm_isdst = (__tznorth
|
|
||||||
// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change)
|
|
||||||
// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change));
|
|
||||||
// else
|
|
||||||
// res->tm_isdst = -1;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
res->tm_isdst = -1;
|
|
||||||
|
|
||||||
offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset);
|
days = ((long)lcltime) / SECSPERDAY;
|
||||||
|
rem = ((long)lcltime) % SECSPERDAY;
|
||||||
|
while (rem < 0)
|
||||||
|
{
|
||||||
|
rem += SECSPERDAY;
|
||||||
|
--days;
|
||||||
|
}
|
||||||
|
while (rem >= SECSPERDAY)
|
||||||
|
{
|
||||||
|
rem -= SECSPERDAY;
|
||||||
|
++days;
|
||||||
|
}
|
||||||
|
|
||||||
hours = offset / SECSPERHOUR;
|
/* compute hour, min, and sec */
|
||||||
offset = offset % SECSPERHOUR;
|
res->tm_hour = (int)(rem / SECSPERHOUR);
|
||||||
|
rem %= SECSPERHOUR;
|
||||||
|
res->tm_min = (int)(rem / SECSPERMIN);
|
||||||
|
res->tm_sec = (int)(rem % SECSPERMIN);
|
||||||
|
|
||||||
mins = offset / SECSPERMIN;
|
/* compute day of week */
|
||||||
secs = offset % SECSPERMIN;
|
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
|
||||||
|
{
|
||||||
|
res->tm_wday += DAYSPERWEEK;
|
||||||
|
}
|
||||||
|
|
||||||
res->tm_sec -= secs;
|
/* compute year & day of year */
|
||||||
res->tm_min -= mins;
|
y = EPOCH_YEAR;
|
||||||
res->tm_hour -= hours;
|
if (days >= 0)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
yleap = isleap(y);
|
||||||
|
if (days < year_lengths[yleap])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
days -= year_lengths[yleap];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
--y;
|
||||||
|
yleap = isleap(y);
|
||||||
|
days += year_lengths[yleap];
|
||||||
|
} while (days < 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (res->tm_sec >= SECSPERMIN)
|
res->tm_year = y - YEAR_BASE;
|
||||||
{
|
res->tm_yday = days;
|
||||||
res->tm_min += 1;
|
ip = mon_lengths[yleap];
|
||||||
res->tm_sec -= SECSPERMIN;
|
for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
|
||||||
}
|
{
|
||||||
else if (res->tm_sec < 0)
|
days -= ip[res->tm_mon];
|
||||||
{
|
}
|
||||||
res->tm_min -= 1;
|
res->tm_mday = days + 1;
|
||||||
res->tm_sec += SECSPERMIN;
|
|
||||||
}
|
if (!is_gmtime)
|
||||||
if (res->tm_min >= MINSPERHOUR)
|
{
|
||||||
{
|
int offset;
|
||||||
res->tm_hour += 1;
|
int hours, mins, secs;
|
||||||
res->tm_min -= MINSPERHOUR;
|
|
||||||
}
|
// TZ_LOCK;
|
||||||
else if (res->tm_min < 0)
|
// if (_daylight)
|
||||||
{
|
// {
|
||||||
res->tm_hour -= 1;
|
// if (y == __tzyear || __tzcalc_limits (y))
|
||||||
res->tm_min += MINSPERHOUR;
|
// res->tm_isdst = (__tznorth
|
||||||
}
|
// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change)
|
||||||
if (res->tm_hour >= HOURSPERDAY)
|
// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change));
|
||||||
{
|
// else
|
||||||
++res->tm_yday;
|
// res->tm_isdst = -1;
|
||||||
++res->tm_wday;
|
// }
|
||||||
if (res->tm_wday > 6)
|
// else
|
||||||
res->tm_wday = 0;
|
res->tm_isdst = -1;
|
||||||
++res->tm_mday;
|
|
||||||
res->tm_hour -= HOURSPERDAY;
|
offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset);
|
||||||
if (res->tm_mday > ip[res->tm_mon])
|
|
||||||
{
|
hours = offset / SECSPERHOUR;
|
||||||
res->tm_mday -= ip[res->tm_mon];
|
offset = offset % SECSPERHOUR;
|
||||||
res->tm_mon += 1;
|
|
||||||
if (res->tm_mon == 12)
|
mins = offset / SECSPERMIN;
|
||||||
{
|
secs = offset % SECSPERMIN;
|
||||||
res->tm_mon = 0;
|
|
||||||
res->tm_year += 1;
|
res->tm_sec -= secs;
|
||||||
res->tm_yday = 0;
|
res->tm_min -= mins;
|
||||||
}
|
res->tm_hour -= hours;
|
||||||
}
|
|
||||||
}
|
if (res->tm_sec >= SECSPERMIN)
|
||||||
else if (res->tm_hour < 0)
|
{
|
||||||
{
|
res->tm_min += 1;
|
||||||
res->tm_yday -= 1;
|
res->tm_sec -= SECSPERMIN;
|
||||||
res->tm_wday -= 1;
|
}
|
||||||
if (res->tm_wday < 0)
|
else if (res->tm_sec < 0)
|
||||||
res->tm_wday = 6;
|
{
|
||||||
res->tm_mday -= 1;
|
res->tm_min -= 1;
|
||||||
res->tm_hour += 24;
|
res->tm_sec += SECSPERMIN;
|
||||||
if (res->tm_mday == 0)
|
}
|
||||||
{
|
if (res->tm_min >= MINSPERHOUR)
|
||||||
res->tm_mon -= 1;
|
{
|
||||||
if (res->tm_mon < 0)
|
res->tm_hour += 1;
|
||||||
{
|
res->tm_min -= MINSPERHOUR;
|
||||||
res->tm_mon = 11;
|
}
|
||||||
res->tm_year -= 1;
|
else if (res->tm_min < 0)
|
||||||
res->tm_yday = 365 + isleap(res->tm_year);
|
{
|
||||||
}
|
res->tm_hour -= 1;
|
||||||
res->tm_mday = ip[res->tm_mon];
|
res->tm_min += MINSPERHOUR;
|
||||||
}
|
}
|
||||||
}
|
if (res->tm_hour >= HOURSPERDAY)
|
||||||
// TZ_UNLOCK;
|
{
|
||||||
|
++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])
|
||||||
|
{
|
||||||
|
res->tm_mday -= ip[res->tm_mon];
|
||||||
|
res->tm_mon += 1;
|
||||||
|
if (res->tm_mon == 12)
|
||||||
|
{
|
||||||
|
res->tm_mon = 0;
|
||||||
|
res->tm_year += 1;
|
||||||
|
res->tm_yday = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (res->tm_hour < 0)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
res->tm_mon -= 1;
|
||||||
|
if (res->tm_mon < 0)
|
||||||
|
{
|
||||||
|
res->tm_mon = 11;
|
||||||
|
res->tm_year -= 1;
|
||||||
|
res->tm_yday = 365 + isleap(res->tm_year);
|
||||||
|
}
|
||||||
|
res->tm_mday = ip[res->tm_mon];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
else
|
struct tm *
|
||||||
res->tm_isdst = 0;
|
sntp_localtime_r(const time_t * tim_p,
|
||||||
// os_printf("res %d %d %d %d %d\n",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour);
|
struct tm *res)
|
||||||
return (res);
|
|
||||||
}
|
|
||||||
struct tm *
|
|
||||||
sntp_localtime_r(const time_t * tim_p ,
|
|
||||||
struct tm *res)
|
|
||||||
{
|
|
||||||
return sntp_mktm_r (tim_p, res, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tm *
|
|
||||||
sntp_localtime(const time_t * tim_p)
|
|
||||||
{
|
|
||||||
return sntp_localtime_r (tim_p, &res_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sntp__tzcalc_limits(int year)
|
|
||||||
{
|
|
||||||
int days, year_days, years;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
if (year < EPOCH_YEAR)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
__tzyear = year;
|
|
||||||
|
|
||||||
years = (year - EPOCH_YEAR);
|
|
||||||
|
|
||||||
year_days = years * 365 +
|
|
||||||
(years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
|
|
||||||
(years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
|
|
||||||
|
|
||||||
for (i = 0; i < 2; ++i)
|
|
||||||
{
|
{
|
||||||
if (sntp__tzrule[i].ch == 'J')
|
return sntp_mktm_r(tim_p, res, 0);
|
||||||
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);
|
|
||||||
int m_day, m_wday, wday_diff;
|
|
||||||
const int *ip = mon_lengths[yleap];
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* store the change-over time in GMT form by adding offset */
|
|
||||||
sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change);
|
struct tm *
|
||||||
|
sntp_localtime(const time_t * tim_p)
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* sntp_asctime_r(struct tm *tim_p ,char *result)
|
|
||||||
{
|
|
||||||
static const char day_name[7][4] = {
|
|
||||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
|
||||||
};
|
|
||||||
static const char mon_name[12][4] = {
|
|
||||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
||||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
||||||
};
|
|
||||||
os_sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n",
|
|
||||||
day_name[tim_p->tm_wday],
|
|
||||||
mon_name[tim_p->tm_mon],
|
|
||||||
tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min,
|
|
||||||
tim_p->tm_sec, 1900 + tim_p->tm_year);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* sntp_asctime(struct tm *tim_p)
|
|
||||||
{
|
|
||||||
return sntp_asctime_r (tim_p, reult);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 ICACHE_RAM_ATTR sntp_get_current_timestamp(void)
|
|
||||||
{
|
|
||||||
return realtime_stamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* sntp_get_real_time(time_t t)
|
|
||||||
{
|
|
||||||
return sntp_asctime(sntp_localtime (&t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the set timezone in seconds. If the timezone was set as seconds, the fractional part is floored. */
|
|
||||||
sint32 sntp_get_timezone_in_seconds(void)
|
|
||||||
{
|
|
||||||
return time_zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the set timezone in hours. If the timezone was set as seconds, the fractional part is floored. */
|
|
||||||
sint8 sntp_get_timezone(void)
|
|
||||||
{
|
|
||||||
return (sint8)(time_zone / (60 * 60));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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))) {
|
|
||||||
time_zone = timezone;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */
|
|
||||||
bool sntp_set_timezone(sint8 timezone)
|
|
||||||
{
|
|
||||||
return sntp_set_timezone_in_seconds((sint32)timezone * 60 * 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sntp_set_daylight(int daylight)
|
|
||||||
{
|
|
||||||
dst = daylight;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR sntp_time_inc (void)
|
|
||||||
{
|
|
||||||
realtime_stamp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sntp_set_system_time (uint32_t t)
|
|
||||||
{
|
|
||||||
realtime_stamp = t + time_zone + dst;
|
|
||||||
os_timer_disarm(&sntp_timer);
|
|
||||||
os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL);
|
|
||||||
os_timer_arm(&sntp_timer, 1000, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int settimeofday(const struct timeval* tv, const struct timezone* tz)
|
|
||||||
{
|
|
||||||
if (tz) /*before*/
|
|
||||||
{
|
{
|
||||||
sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60);
|
return sntp_localtime_r(tim_p, &res_buf);
|
||||||
// apparently tz->tz_dsttime is a bitfield and should not be further used (cf man)
|
|
||||||
sntp_set_daylight(0);
|
|
||||||
}
|
}
|
||||||
if (tv) /* after*/
|
|
||||||
|
int sntp__tzcalc_limits(int year)
|
||||||
{
|
{
|
||||||
// reset time subsystem
|
int days, year_days, years;
|
||||||
tune_timeshift64(tv->tv_sec * 1000000ULL + tv->tv_usec);
|
int i, j;
|
||||||
|
|
||||||
sntp_set_system_time(tv->tv_sec);
|
if (year < EPOCH_YEAR)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (_settimeofday_cb)
|
__tzyear = year;
|
||||||
_settimeofday_cb();
|
|
||||||
|
years = (year - EPOCH_YEAR);
|
||||||
|
|
||||||
|
year_days = years * 365 +
|
||||||
|
(years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
|
||||||
|
(years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
|
||||||
|
|
||||||
|
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);
|
||||||
|
int m_day, m_wday, wday_diff;
|
||||||
|
const int *ip = mon_lengths[yleap];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store the change-over time in GMT form by adding offset */
|
||||||
|
sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
__tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sntp_asctime_r(struct tm *tim_p, char *result)
|
||||||
|
{
|
||||||
|
static const char day_name[7][4] =
|
||||||
|
{
|
||||||
|
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||||
|
};
|
||||||
|
static const char mon_name[12][4] =
|
||||||
|
{
|
||||||
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||||
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||||
|
};
|
||||||
|
os_sprintf(result, "%s %s %02d %02d:%02d:%02d %02d\n",
|
||||||
|
day_name[tim_p->tm_wday],
|
||||||
|
mon_name[tim_p->tm_mon],
|
||||||
|
tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min,
|
||||||
|
tim_p->tm_sec, 1900 + tim_p->tm_year);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sntp_asctime(struct tm *tim_p)
|
||||||
|
{
|
||||||
|
return sntp_asctime_r(tim_p, reult);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ICACHE_RAM_ATTR sntp_get_current_timestamp(void)
|
||||||
|
{
|
||||||
|
return realtime_stamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sntp_get_real_time(time_t t)
|
||||||
|
{
|
||||||
|
return sntp_asctime(sntp_localtime(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the set timezone in seconds. If the timezone was set as seconds, the fractional part is floored. */
|
||||||
|
sint32 sntp_get_timezone_in_seconds(void)
|
||||||
|
{
|
||||||
|
return time_zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the set timezone in hours. If the timezone was set as seconds, the fractional part is floored. */
|
||||||
|
sint8 sntp_get_timezone(void)
|
||||||
|
{
|
||||||
|
return (sint8)(time_zone / (60 * 60));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)))
|
||||||
|
{
|
||||||
|
time_zone = timezone;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */
|
||||||
|
bool sntp_set_timezone(sint8 timezone)
|
||||||
|
{
|
||||||
|
return sntp_set_timezone_in_seconds((sint32)timezone * 60 * 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sntp_set_daylight(int daylight)
|
||||||
|
{
|
||||||
|
dst = daylight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR sntp_time_inc(void)
|
||||||
|
{
|
||||||
|
realtime_stamp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sntp_set_system_time(uint32_t t)
|
||||||
|
{
|
||||||
|
realtime_stamp = t + time_zone + dst;
|
||||||
|
os_timer_disarm(&sntp_timer);
|
||||||
|
os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL);
|
||||||
|
os_timer_arm(&sntp_timer, 1000, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int settimeofday(const struct timeval* tv, const struct timezone* tz)
|
||||||
|
{
|
||||||
|
if (tz) /*before*/
|
||||||
|
{
|
||||||
|
sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60);
|
||||||
|
// apparently tz->tz_dsttime is a bitfield and should not be further used (cf man)
|
||||||
|
sntp_set_daylight(0);
|
||||||
|
}
|
||||||
|
if (tv) /* after*/
|
||||||
|
{
|
||||||
|
// reset time subsystem
|
||||||
|
tune_timeshift64(tv->tv_sec * 1000000ULL + tv->tv_usec);
|
||||||
|
|
||||||
|
sntp_set_system_time(tv->tv_sec);
|
||||||
|
|
||||||
|
if (_settimeofday_cb)
|
||||||
|
{
|
||||||
|
_settimeofday_cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // lwip2 only
|
#endif // lwip2 only
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
bool sntp_set_timezone_in_seconds(sint32 timezone);
|
bool sntp_set_timezone_in_seconds(sint32 timezone);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* spiffs_cache.c
|
spiffs_cache.c
|
||||||
*
|
|
||||||
* Created on: Jun 23, 2013
|
Created on: Jun 23, 2013
|
||||||
* Author: petera
|
Author: petera
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "spiffs.h"
|
#include "spiffs.h"
|
||||||
#include "spiffs_nucleus.h"
|
#include "spiffs_nucleus.h"
|
||||||
@ -12,311 +12,372 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
// returns cached page for give page index, or null if no such cached page
|
// 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;
|
|
||||||
int 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 ) {
|
|
||||||
//SPIFFS_CACHE_DBG("CACHE_GET: have cache page " _SPIPRIi " for " _SPIPRIpg"\n", i, pix);
|
|
||||||
cp->last_access = cache->last_access;
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for " _SPIPRIpg"\n", pix);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// frees cached page
|
|
||||||
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 (write_back &&
|
|
||||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
|
||||||
(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) {
|
|
||||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " objid " _SPIPRIid "\n", ix, cp->obj_id);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " pix " _SPIPRIpg "\n", ix, cp->pix);
|
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||||
}
|
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0)
|
||||||
cache->cpage_use_map &= ~(1 << ix);
|
{
|
||||||
cp->flags = 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int i;
|
||||||
return res;
|
for (i = 0; i < cache->cpage_count; i++)
|
||||||
}
|
{
|
||||||
|
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||||
// removes the oldest accessed cached page
|
if ((cache->cpage_use_map & (1 << i)) &&
|
||||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||||
s32_t res = SPIFFS_OK;
|
cp->pix == pix)
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
{
|
||||||
|
//SPIFFS_CACHE_DBG("CACHE_GET: have cache page " _SPIPRIi " for " _SPIPRIpg"\n", i, pix);
|
||||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
cp->last_access = cache->last_access;
|
||||||
// at least one free cpage
|
return cp;
|
||||||
return SPIFFS_OK;
|
}
|
||||||
}
|
}
|
||||||
|
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for " _SPIPRIpg"\n", pix);
|
||||||
// all busy, scan thru all to find the cpage which has oldest access
|
return 0;
|
||||||
int i;
|
|
||||||
int cand_ix = -1;
|
|
||||||
u32_t oldest_val = 0;
|
|
||||||
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) {
|
|
||||||
oldest_val = cache->last_access - cp->last_access;
|
|
||||||
cand_ix = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cand_ix >= 0) {
|
|
||||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
|
||||||
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) {
|
|
||||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
|
||||||
cache->cpage_use_map |= (1<<i);
|
|
||||||
cp->last_access = cache->last_access;
|
|
||||||
//SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi"\n", i);
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// out of cache entries
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// drops the cache page for give page index
|
|
||||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
|
||||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
|
||||||
if (cp) {
|
|
||||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
|
|
||||||
// reads from spi flash or the cache
|
|
||||||
s32_t spiffs_phys_rd(
|
|
||||||
spiffs *fs,
|
|
||||||
u8_t op,
|
|
||||||
spiffs_file fh,
|
|
||||||
u32_t addr,
|
|
||||||
u32_t len,
|
|
||||||
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) {
|
|
||||||
// we've already got one, you see
|
|
||||||
#if SPIFFS_CACHE_STATS
|
|
||||||
fs->cache_hits++;
|
|
||||||
#endif
|
|
||||||
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) {
|
|
||||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
|
||||||
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
|
||||||
}
|
|
||||||
#if SPIFFS_CACHE_STATS
|
|
||||||
fs->cache_misses++;
|
|
||||||
#endif
|
|
||||||
// this operation will always free one cache page (unless all already free),
|
|
||||||
// the result code stems from the write operation of the possibly freed cache page
|
|
||||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
|
||||||
|
|
||||||
cp = spiffs_cache_page_allocate(fs);
|
|
||||||
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);
|
|
||||||
|
|
||||||
s32_t res2 = SPIFFS_HAL_READ(fs,
|
|
||||||
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) {
|
|
||||||
// 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 {
|
|
||||||
// this will never happen, last resort for sake of symmetry
|
|
||||||
s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
|
|
||||||
if (res2 != SPIFFS_OK) {
|
|
||||||
// honor read failure before possible write failure (bad idea?)
|
|
||||||
res = res2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// writes to spi flash and/or the cache
|
|
||||||
s32_t spiffs_phys_wr(
|
|
||||||
spiffs *fs,
|
|
||||||
u8_t op,
|
|
||||||
spiffs_file fh,
|
|
||||||
u32_t addr,
|
|
||||||
u32_t len,
|
|
||||||
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) {
|
|
||||||
// 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) {
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
// frees cached page
|
||||||
_SPIFFS_MEMCPY(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back)
|
||||||
|
{
|
||||||
cache->last_access++;
|
s32_t res = SPIFFS_OK;
|
||||||
cp->last_access = cache->last_access;
|
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||||
|
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
|
||||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
if (cache->cpage_use_map & (1 << ix))
|
||||||
// page is being updated, no write-cache, just pass thru
|
{
|
||||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
if (write_back &&
|
||||||
} else {
|
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||||
return SPIFFS_OK;
|
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY))
|
||||||
}
|
{
|
||||||
} else {
|
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
||||||
// no cache page, no write cache - just write thru
|
SPIFFS_CACHE_DBG("CACHE_FREE: write cache page " _SPIPRIi " pix " _SPIPRIpg "\n", ix, cp->pix);
|
||||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE_WR
|
#if SPIFFS_CACHE_WR
|
||||||
// returns the cache page that this fd refers, or null if no cache page
|
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR)
|
||||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
{
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " objid " _SPIPRIid "\n", ix, cp->obj_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " pix " _SPIPRIpg "\n", ix, cp->pix);
|
||||||
|
}
|
||||||
|
cache->cpage_use_map &= ~(1 << ix);
|
||||||
|
cp->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
return res;
|
||||||
// all cpages free, no cpage cannot be assigned to obj_id
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int 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) {
|
|
||||||
return cp;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
// removes the oldest accessed cached page
|
||||||
}
|
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);
|
||||||
|
|
||||||
// allocates a new cache page and refers this to given fd - flushes an old cache
|
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask)
|
||||||
// page if all cache is busy
|
{
|
||||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
// at least one free cpage
|
||||||
// before this function is called, it is ensured that there is no already existing
|
return SPIFFS_OK;
|
||||||
// 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) {
|
|
||||||
// could not get cache page
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
// all busy, scan thru all to find the cpage which has oldest access
|
||||||
cp->obj_id = fd->obj_id;
|
int i;
|
||||||
fd->cache_page = cp;
|
int cand_ix = -1;
|
||||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi " for fd " _SPIPRIfd ":" _SPIPRIid "\n", cp->ix, fd->file_nbr, fd->obj_id);
|
u32_t oldest_val = 0;
|
||||||
return cp;
|
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)
|
||||||
|
{
|
||||||
|
oldest_val = cache->last_access - cp->last_access;
|
||||||
|
cand_ix = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// unrefers all fds that this cache page refers to and releases the cache page
|
if (cand_ix >= 0)
|
||||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
|
{
|
||||||
if (cp == 0) return;
|
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
||||||
u32_t i;
|
}
|
||||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
|
||||||
for (i = 0; i < fs->fd_count; i++) {
|
return res;
|
||||||
spiffs_fd *cur_fd = &fds[i];
|
|
||||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
|
||||||
cur_fd->cache_page = 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
|
||||||
|
|
||||||
cp->obj_id = 0;
|
// 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)
|
||||||
|
{
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||||
|
cache->cpage_use_map |= (1 << i);
|
||||||
|
cp->last_access = cache->last_access;
|
||||||
|
//SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi"\n", i);
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// out of cache entries
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// drops the cache page for give page index
|
||||||
|
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix)
|
||||||
|
{
|
||||||
|
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||||
|
if (cp)
|
||||||
|
{
|
||||||
|
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// reads from spi flash or the cache
|
||||||
|
s32_t spiffs_phys_rd(
|
||||||
|
spiffs *fs,
|
||||||
|
u8_t op,
|
||||||
|
spiffs_file fh,
|
||||||
|
u32_t addr,
|
||||||
|
u32_t len,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// we've already got one, you see
|
||||||
|
#if SPIFFS_CACHE_STATS
|
||||||
|
fs->cache_hits++;
|
||||||
|
#endif
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||||
|
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||||
|
}
|
||||||
|
#if SPIFFS_CACHE_STATS
|
||||||
|
fs->cache_misses++;
|
||||||
|
#endif
|
||||||
|
// this operation will always free one cache page (unless all already free),
|
||||||
|
// the result code stems from the write operation of the possibly freed cache page
|
||||||
|
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||||
|
|
||||||
|
cp = spiffs_cache_page_allocate(fs);
|
||||||
|
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);
|
||||||
|
|
||||||
|
s32_t res2 = SPIFFS_HAL_READ(fs,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
// this will never happen, last resort for sake of symmetry
|
||||||
|
s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||||
|
if (res2 != SPIFFS_OK)
|
||||||
|
{
|
||||||
|
// honor read failure before possible write failure (bad idea?)
|
||||||
|
res = res2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes to spi flash and/or the cache
|
||||||
|
s32_t spiffs_phys_wr(
|
||||||
|
spiffs *fs,
|
||||||
|
u8_t op,
|
||||||
|
spiffs_file fh,
|
||||||
|
u32_t addr,
|
||||||
|
u32_t len,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||||
|
_SPIFFS_MEMCPY(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
||||||
|
|
||||||
|
cache->last_access++;
|
||||||
|
cp->last_access = cache->last_access;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
return SPIFFS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no cache page, no write cache - just write thru
|
||||||
|
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 *cache = spiffs_get_cache(fs);
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// could not get cache page
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
||||||
|
cp->obj_id = fd->obj_id;
|
||||||
|
fd->cache_page = cp;
|
||||||
|
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi " for fd " _SPIPRIfd ":" _SPIPRIid "\n", cp->ix, fd->file_nbr, fd->obj_id);
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
u32_t i;
|
||||||
|
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
cur_fd->cache_page = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||||
|
|
||||||
|
cp->obj_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initializes the cache
|
// initializes the cache
|
||||||
void spiffs_cache_init(spiffs *fs) {
|
void spiffs_cache_init(spiffs *fs)
|
||||||
if (fs->cache == 0) return;
|
{
|
||||||
u32_t sz = fs->cache_size;
|
if (fs->cache == 0)
|
||||||
u32_t cache_mask = 0;
|
{
|
||||||
int i;
|
return;
|
||||||
int cache_entries =
|
}
|
||||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
u32_t sz = fs->cache_size;
|
||||||
if (cache_entries <= 0) return;
|
u32_t cache_mask = 0;
|
||||||
|
int i;
|
||||||
|
int cache_entries =
|
||||||
|
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||||
|
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;
|
cache_mask <<= 1;
|
||||||
}
|
cache_mask |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
spiffs_cache cache;
|
spiffs_cache cache;
|
||||||
memset(&cache, 0, sizeof(spiffs_cache));
|
memset(&cache, 0, sizeof(spiffs_cache));
|
||||||
cache.cpage_count = cache_entries;
|
cache.cpage_count = cache_entries;
|
||||||
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
||||||
|
|
||||||
cache.cpage_use_map = 0xffffffff;
|
cache.cpage_use_map = 0xffffffff;
|
||||||
cache.cpage_use_mask = cache_mask;
|
cache.cpage_use_mask = cache_mask;
|
||||||
_SPIFFS_MEMCPY(fs->cache, &cache, sizeof(spiffs_cache));
|
_SPIFFS_MEMCPY(fs->cache, &cache, sizeof(spiffs_cache));
|
||||||
|
|
||||||
spiffs_cache *c = spiffs_get_cache(fs);
|
spiffs_cache *c = spiffs_get_cache(fs);
|
||||||
|
|
||||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||||
|
|
||||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
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;
|
{
|
||||||
}
|
spiffs_get_cache_page_hdr(fs, c, i)->ix = i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif // SPIFFS_CACHE
|
#endif // SPIFFS_CACHE
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* spiffs_config.h
|
spiffs_config.h
|
||||||
*
|
|
||||||
* Created on: Jul 3, 2013
|
Created on: Jul 3, 2013
|
||||||
* Author: petera
|
Author: petera
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SPIFFS_CONFIG_H_
|
#ifndef SPIFFS_CONFIG_H_
|
||||||
#define SPIFFS_CONFIG_H_
|
#define SPIFFS_CONFIG_H_
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,112 +1,112 @@
|
|||||||
/*
|
/*
|
||||||
* spiffs_nucleus.h
|
spiffs_nucleus.h
|
||||||
*
|
|
||||||
* Created on: Jun 15, 2013
|
|
||||||
* Author: petera
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* SPIFFS layout
|
Created on: Jun 15, 2013
|
||||||
*
|
Author: petera
|
||||||
* 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
|
/* SPIFFS layout
|
||||||
* - writing pulls ones to zeroes
|
|
||||||
* - zeroes cannot be pulled to ones, without erase
|
spiffs is designed for following spi flash characteristics:
|
||||||
* - wear leveling
|
- only big areas of data (blocks) can be erased
|
||||||
*
|
- erasing resets all bits in a block to ones
|
||||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
- writing pulls ones to zeroes
|
||||||
*
|
- zeroes cannot be pulled to ones, without erase
|
||||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
- wear leveling
|
||||||
* Each block contains same number of pages. A page cannot be erased, but a
|
|
||||||
* block can be erased.
|
spiffs is also meant to be run on embedded, memory constraint devices.
|
||||||
*
|
|
||||||
* Entire area must be block_size * x
|
Entire area is divided in blocks. Entire area is also divided in pages.
|
||||||
* page_size must be block_size / (2^y) where y > 2
|
Each block contains same number of pages. A page cannot be erased, but a
|
||||||
*
|
block can be erased.
|
||||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
|
||||||
*
|
Entire area must be block_size * x
|
||||||
* BLOCK 0 PAGE 0 object lookup 1
|
page_size must be block_size / (2^y) where y > 2
|
||||||
* PAGE 1 object lookup 2
|
|
||||||
* ...
|
ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||||
* PAGE n-1 object lookup n
|
|
||||||
* PAGE n object data 1
|
BLOCK 0 PAGE 0 object lookup 1
|
||||||
* PAGE n+1 object data 2
|
PAGE 1 object lookup 2
|
||||||
* ...
|
...
|
||||||
* PAGE n+m-1 object data m
|
PAGE n-1 object lookup n
|
||||||
*
|
PAGE n object data 1
|
||||||
* BLOCK 1 PAGE n+m object lookup 1
|
PAGE n+1 object data 2
|
||||||
* PAGE n+m+1 object lookup 2
|
...
|
||||||
* ...
|
PAGE n+m-1 object data m
|
||||||
* PAGE 2n+m-1 object lookup n
|
|
||||||
* PAGE 2n+m object data 1
|
BLOCK 1 PAGE n+m object lookup 1
|
||||||
* PAGE 2n+m object data 2
|
PAGE n+m+1 object lookup 2
|
||||||
* ...
|
...
|
||||||
* PAGE 2n+2m-1 object data m
|
PAGE 2n+m-1 object lookup n
|
||||||
* ...
|
PAGE 2n+m object data 1
|
||||||
*
|
PAGE 2n+m object data 2
|
||||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
...
|
||||||
* in a block by object id
|
PAGE 2n+2m-1 object data m
|
||||||
* : 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
|
n is number of object lookup pages, which is number of pages needed to index all pages
|
||||||
* thus, n+m is total number of pages in a block
|
in a block by object id
|
||||||
* : block_size / page_size
|
: 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
|
||||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
: block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||||
*
|
thus, n+m is total number of pages in a block
|
||||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
: block_size / page_size
|
||||||
* data page.
|
|
||||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||||
* An object id being 0x0000 represents a deleted page.
|
|
||||||
*
|
Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
data page.
|
||||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||||
* page 2 : data : data for object id 0008
|
An object id being 0x0000 represents a deleted page.
|
||||||
* page 3 : data : data for object id 0001
|
|
||||||
* page 4 : data : data for object id 0aaa
|
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
|
||||||
* Object data pages can be either object index pages or object content.
|
page 4 : data : data for object id 0aaa
|
||||||
* 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.
|
Object data pages can be either object index pages or object content.
|
||||||
* An object index page contains page entries pointing to object content page. The entry index
|
All object data pages contains a data page header, containing object id and span index.
|
||||||
* in a object index page correlates to the span index in the actual object data page.
|
The span index denotes the object page ordering amongst data pages with same object id.
|
||||||
* The first object index page (span index 0) is called object index header page, and also
|
This applies to both object index pages (when index spans more than one page of entries),
|
||||||
* contains object flags (directory/file), size, object name etc.
|
and object data pages.
|
||||||
*
|
An object index page contains page entries pointing to object content page. The entry index
|
||||||
* ex:
|
in a object index page correlates to the span index in the actual object data page.
|
||||||
* BLOCK 1
|
The first object index page (span index 0) is called object index header page, and also
|
||||||
* PAGE 256: objectl lookup page 1
|
contains object flags (directory/file), size, object name etc.
|
||||||
* [*123] [ 123] [ 123] [ 123]
|
|
||||||
* [ 123] [*123] [ 123] [ 123]
|
ex:
|
||||||
* [free] [free] [free] [free] ...
|
BLOCK 1
|
||||||
* PAGE 257: objectl lookup page 2
|
PAGE 256: objectl lookup page 1
|
||||||
* [free] [free] [free] [free] ...
|
[*123] [ 123] [ 123] [ 123]
|
||||||
* PAGE 258: object index page (header)
|
[ 123] [*123] [ 123] [ 123]
|
||||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
[free] [free] [free] [free] ...
|
||||||
* size:1600 name:ex.txt type:file
|
PAGE 257: objectl lookup page 2
|
||||||
* [259] [260] [261] [262]
|
[free] [free] [free] [free] ...
|
||||||
* PAGE 259: object data page
|
PAGE 258: object index page (header)
|
||||||
* obj.id:0123 span.ix:0000 flags:DATA
|
obj.id:0123 span.ix:0000 flags:INDEX
|
||||||
* PAGE 260: object data page
|
size:1600 name:ex.txt type:file
|
||||||
* obj.id:0123 span.ix:0001 flags:DATA
|
[259] [260] [261] [262]
|
||||||
* PAGE 261: object data page
|
PAGE 259: object data page
|
||||||
* obj.id:0123 span.ix:0002 flags:DATA
|
obj.id:0123 span.ix:0000 flags:DATA
|
||||||
* PAGE 262: object data page
|
PAGE 260: object data page
|
||||||
* obj.id:0123 span.ix:0003 flags:DATA
|
obj.id:0123 span.ix:0001 flags:DATA
|
||||||
* PAGE 263: object index page
|
PAGE 261: object data page
|
||||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
obj.id:0123 span.ix:0002 flags:DATA
|
||||||
* [264] [265] [fre] [fre]
|
PAGE 262: object data page
|
||||||
* [fre] [fre] [fre] [fre]
|
obj.id:0123 span.ix:0003 flags:DATA
|
||||||
* PAGE 264: object data page
|
PAGE 263: object index page
|
||||||
* obj.id:0123 span.ix:0004 flags:DATA
|
obj.id:0123 span.ix:0001 flags:INDEX
|
||||||
* PAGE 265: object data page
|
[264] [265] [fre] [fre]
|
||||||
* obj.id:0123 span.ix:0005 flags:DATA
|
[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_
|
#ifndef SPIFFS_NUCLEUS_H_
|
||||||
#define SPIFFS_NUCLEUS_H_
|
#define SPIFFS_NUCLEUS_H_
|
||||||
|
|
||||||
@ -148,15 +148,15 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
/* For GCC and clang */
|
/* For GCC and clang */
|
||||||
#define SPIFFS_PACKED __attribute__((packed))
|
#define SPIFFS_PACKED __attribute__((packed))
|
||||||
#elif defined(__ICCARM__) || defined(__CC_ARM)
|
#elif defined(__ICCARM__) || defined(__CC_ARM)
|
||||||
/* For IAR ARM and Keil MDK-ARM compilers */
|
/* For IAR ARM and Keil MDK-ARM compilers */
|
||||||
#define SPIFFS_PACKED
|
#define SPIFFS_PACKED
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Unknown compiler */
|
/* Unknown compiler */
|
||||||
#define SPIFFS_PACKED
|
#define SPIFFS_PACKED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -342,7 +342,7 @@ extern "C" {
|
|||||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||||
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
||||||
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
||||||
|
|
||||||
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
||||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||||
@ -402,79 +402,85 @@ extern "C" {
|
|||||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||||||
|
|
||||||
// cache page struct
|
// cache page struct
|
||||||
typedef struct {
|
typedef struct
|
||||||
// cache flags
|
{
|
||||||
u8_t flags;
|
// cache flags
|
||||||
// cache page index
|
u8_t flags;
|
||||||
u8_t ix;
|
// cache page index
|
||||||
// last access of this cache page
|
u8_t ix;
|
||||||
u32_t last_access;
|
// last access of this cache page
|
||||||
union {
|
u32_t last_access;
|
||||||
// type read cache
|
union
|
||||||
struct {
|
{
|
||||||
// read cache page index
|
// type read cache
|
||||||
spiffs_page_ix pix;
|
struct
|
||||||
};
|
{
|
||||||
|
// read cache page index
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
};
|
||||||
#if SPIFFS_CACHE_WR
|
#if SPIFFS_CACHE_WR
|
||||||
// type write cache
|
// type write cache
|
||||||
struct {
|
struct
|
||||||
// write cache
|
{
|
||||||
spiffs_obj_id obj_id;
|
// write cache
|
||||||
// offset in cache page
|
spiffs_obj_id obj_id;
|
||||||
u32_t offset;
|
// offset in cache page
|
||||||
// size of cache page
|
u32_t offset;
|
||||||
u16_t size;
|
// size of cache page
|
||||||
};
|
u16_t size;
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
} spiffs_cache_page;
|
} spiffs_cache_page;
|
||||||
|
|
||||||
// cache struct
|
// cache struct
|
||||||
typedef struct {
|
typedef struct
|
||||||
u8_t cpage_count;
|
{
|
||||||
u32_t last_access;
|
u8_t cpage_count;
|
||||||
u32_t cpage_use_map;
|
u32_t last_access;
|
||||||
u32_t cpage_use_mask;
|
u32_t cpage_use_map;
|
||||||
u8_t *cpages;
|
u32_t cpage_use_mask;
|
||||||
|
u8_t *cpages;
|
||||||
} spiffs_cache;
|
} spiffs_cache;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// spiffs nucleus file descriptor
|
// spiffs nucleus file descriptor
|
||||||
typedef struct {
|
typedef struct
|
||||||
// the filesystem of this descriptor
|
{
|
||||||
spiffs *fs;
|
// the filesystem of this descriptor
|
||||||
// number of file descriptor - if 0, the file descriptor is closed
|
spiffs *fs;
|
||||||
spiffs_file file_nbr;
|
// number of file descriptor - if 0, the file descriptor is closed
|
||||||
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
spiffs_file file_nbr;
|
||||||
spiffs_obj_id obj_id;
|
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
||||||
// size of the file
|
spiffs_obj_id obj_id;
|
||||||
u32_t size;
|
// size of the file
|
||||||
// cached object index header page index
|
u32_t size;
|
||||||
spiffs_page_ix objix_hdr_pix;
|
// cached object index header page index
|
||||||
// cached offset object index page index
|
spiffs_page_ix objix_hdr_pix;
|
||||||
spiffs_page_ix cursor_objix_pix;
|
// cached offset object index page index
|
||||||
// cached offset object index span index
|
spiffs_page_ix cursor_objix_pix;
|
||||||
spiffs_span_ix cursor_objix_spix;
|
// cached offset object index span index
|
||||||
// current absolute offset
|
spiffs_span_ix cursor_objix_spix;
|
||||||
u32_t offset;
|
// current absolute offset
|
||||||
// current file descriptor offset (cached)
|
u32_t offset;
|
||||||
u32_t fdoffset;
|
// current file descriptor offset (cached)
|
||||||
// fd flags
|
u32_t fdoffset;
|
||||||
spiffs_flags flags;
|
// fd flags
|
||||||
|
spiffs_flags flags;
|
||||||
#if SPIFFS_CACHE_WR
|
#if SPIFFS_CACHE_WR
|
||||||
spiffs_cache_page *cache_page;
|
spiffs_cache_page *cache_page;
|
||||||
#endif
|
#endif
|
||||||
#if SPIFFS_TEMPORAL_FD_CACHE
|
#if SPIFFS_TEMPORAL_FD_CACHE
|
||||||
// djb2 hash of filename
|
// djb2 hash of filename
|
||||||
u32_t name_hash;
|
u32_t name_hash;
|
||||||
// hit score (score == 0 indicates never used fd)
|
// hit score (score == 0 indicates never used fd)
|
||||||
u16_t score;
|
u16_t score;
|
||||||
#endif
|
#endif
|
||||||
#if SPIFFS_IX_MAP
|
#if SPIFFS_IX_MAP
|
||||||
// spiffs index map, if 0 it means unmapped
|
// spiffs index map, if 0 it means unmapped
|
||||||
spiffs_ix_map *ix_map;
|
spiffs_ix_map *ix_map;
|
||||||
#endif
|
#endif
|
||||||
} spiffs_fd;
|
} spiffs_fd;
|
||||||
|
|
||||||
@ -484,46 +490,48 @@ typedef struct {
|
|||||||
// page header, part of each page except object lookup pages
|
// page header, part of each page except object lookup pages
|
||||||
// NB: this is always aligned when the data page is an object index,
|
// NB: this is always aligned when the data page is an object index,
|
||||||
// as in this case struct spiffs_page_object_ix is used
|
// 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 id
|
||||||
// object span index
|
spiffs_obj_id obj_id;
|
||||||
spiffs_span_ix span_ix;
|
// object span index
|
||||||
// flags
|
spiffs_span_ix span_ix;
|
||||||
u8_t flags;
|
// flags
|
||||||
|
u8_t flags;
|
||||||
} spiffs_page_header;
|
} spiffs_page_header;
|
||||||
|
|
||||||
// object index header page header
|
// object index header page header
|
||||||
typedef struct SPIFFS_PACKED
|
typedef struct SPIFFS_PACKED
|
||||||
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||||
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
|
__attribute((aligned(sizeof(spiffs_page_ix))))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// common page header
|
// common page header
|
||||||
spiffs_page_header p_hdr;
|
spiffs_page_header p_hdr;
|
||||||
// alignment
|
// alignment
|
||||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
u8_t _align[4 - ((sizeof(spiffs_page_header) & 3) == 0 ? 4 : (sizeof(spiffs_page_header) & 3))];
|
||||||
// size of object
|
// size of object
|
||||||
u32_t size;
|
u32_t size;
|
||||||
// type of object
|
// type of object
|
||||||
spiffs_obj_type type;
|
spiffs_obj_type type;
|
||||||
// name of object
|
// name of object
|
||||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||||
#if SPIFFS_OBJ_META_LEN
|
#if SPIFFS_OBJ_META_LEN
|
||||||
// metadata. not interpreted by SPIFFS in any way.
|
// metadata. not interpreted by SPIFFS in any way.
|
||||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||||
#endif
|
#endif
|
||||||
} spiffs_page_object_ix_header;
|
} spiffs_page_object_ix_header;
|
||||||
|
|
||||||
// object index page 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_header p_hdr;
|
||||||
|
u8_t _align[4 - ((sizeof(spiffs_page_header) & 3) == 0 ? 4 : (sizeof(spiffs_page_header) & 3))];
|
||||||
} spiffs_page_object_ix;
|
} spiffs_page_object_ix;
|
||||||
|
|
||||||
// callback func for object lookup visitor
|
// callback func for object lookup visitor
|
||||||
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
||||||
const void *user_const_p, void *user_var_p);
|
const void *user_const_p, void *user_var_p);
|
||||||
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
#if SPIFFS_CACHE
|
||||||
|
@ -1,50 +1,54 @@
|
|||||||
/*
|
/*
|
||||||
spiffs_api.cpp - file system wrapper for SPIFFS
|
spiffs_api.cpp - file system wrapper for SPIFFS
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
|
|
||||||
This code was influenced by NodeMCU and Sming libraries, and first version of
|
This code was influenced by NodeMCU and Sming libraries, and first version of
|
||||||
Arduino wrapper written by Hristo Gochkov.
|
Arduino wrapper written by Hristo Gochkov.
|
||||||
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include "spiffs_api.h"
|
#include "spiffs_api.h"
|
||||||
|
|
||||||
using namespace fs;
|
using namespace fs;
|
||||||
|
|
||||||
FileImplPtr SPIFFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode)
|
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);
|
DEBUGV("SPIFFSImpl::open: invalid path=`%s` \r\n", path);
|
||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
}
|
}
|
||||||
int mode = getSpiffsMode(openMode, accessMode);
|
int mode = getSpiffsMode(openMode, accessMode);
|
||||||
int fd = SPIFFS_open(&_fs, path, mode, 0);
|
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",
|
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);
|
fd, path, openMode, accessMode, _fs.err_code);
|
||||||
auto rc = SPIFFS_remove(&_fs, path);
|
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",
|
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);
|
path, openMode, accessMode, _fs.err_code);
|
||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
}
|
}
|
||||||
fd = SPIFFS_open(&_fs, path, mode, 0);
|
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",
|
DEBUGV("SPIFFSImpl::open: fd=%d path=`%s` openMode=%d accessMode=%d err=%d\r\n",
|
||||||
fd, path, openMode, accessMode, _fs.err_code);
|
fd, path, openMode, accessMode, _fs.err_code);
|
||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
@ -54,7 +58,8 @@ FileImplPtr SPIFFSImpl::open(const char* path, OpenMode openMode, AccessMode acc
|
|||||||
|
|
||||||
bool SPIFFSImpl::exists(const char* path)
|
bool SPIFFSImpl::exists(const char* path)
|
||||||
{
|
{
|
||||||
if (!isSpiffsFilenameValid(path)) {
|
if (!isSpiffsFilenameValid(path))
|
||||||
|
{
|
||||||
DEBUGV("SPIFFSImpl::exists: invalid path=`%s` \r\n", path);
|
DEBUGV("SPIFFSImpl::exists: invalid path=`%s` \r\n", path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -63,15 +68,17 @@ bool SPIFFSImpl::exists(const char* path)
|
|||||||
return rc == SPIFFS_OK;
|
return rc == SPIFFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirImplPtr SPIFFSImpl::openDir(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);
|
DEBUGV("SPIFFSImpl::openDir: invalid path=`%s` \r\n", path);
|
||||||
return DirImplPtr();
|
return DirImplPtr();
|
||||||
}
|
}
|
||||||
spiffs_DIR dir;
|
spiffs_DIR dir;
|
||||||
spiffs_DIR* result = SPIFFS_opendir(&_fs, path, &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);
|
DEBUGV("SPIFFSImpl::openDir: path=`%s` err=%d\r\n", path, _fs.err_code);
|
||||||
return DirImplPtr();
|
return DirImplPtr();
|
||||||
}
|
}
|
||||||
@ -81,19 +88,24 @@ DirImplPtr SPIFFSImpl::openDir(const char* path)
|
|||||||
int getSpiffsMode(OpenMode openMode, AccessMode accessMode)
|
int getSpiffsMode(OpenMode openMode, AccessMode accessMode)
|
||||||
{
|
{
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
if (openMode & OM_CREATE) {
|
if (openMode & OM_CREATE)
|
||||||
|
{
|
||||||
mode |= SPIFFS_CREAT;
|
mode |= SPIFFS_CREAT;
|
||||||
}
|
}
|
||||||
if (openMode & OM_APPEND) {
|
if (openMode & OM_APPEND)
|
||||||
|
{
|
||||||
mode |= SPIFFS_APPEND;
|
mode |= SPIFFS_APPEND;
|
||||||
}
|
}
|
||||||
if (openMode & OM_TRUNCATE) {
|
if (openMode & OM_TRUNCATE)
|
||||||
|
{
|
||||||
mode |= SPIFFS_TRUNC;
|
mode |= SPIFFS_TRUNC;
|
||||||
}
|
}
|
||||||
if (accessMode & AM_READ) {
|
if (accessMode & AM_READ)
|
||||||
|
{
|
||||||
mode |= SPIFFS_RDONLY;
|
mode |= SPIFFS_RDONLY;
|
||||||
}
|
}
|
||||||
if (accessMode & AM_WRITE) {
|
if (accessMode & AM_WRITE)
|
||||||
|
{
|
||||||
mode |= SPIFFS_WRONLY;
|
mode |= SPIFFS_WRONLY;
|
||||||
}
|
}
|
||||||
return mode;
|
return mode;
|
||||||
@ -101,7 +113,8 @@ int getSpiffsMode(OpenMode openMode, AccessMode accessMode)
|
|||||||
|
|
||||||
bool isSpiffsFilenameValid(const char* name)
|
bool isSpiffsFilenameValid(const char* name)
|
||||||
{
|
{
|
||||||
if (name == nullptr) {
|
if (name == nullptr)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto len = strlen(name);
|
auto len = strlen(name);
|
||||||
|
@ -2,36 +2,36 @@
|
|||||||
#define spiffs_api_h
|
#define spiffs_api_h
|
||||||
|
|
||||||
/*
|
/*
|
||||||
spiffs_api.h - file system wrapper for SPIFFS
|
spiffs_api.h - file system wrapper for SPIFFS
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
|
|
||||||
This code was influenced by NodeMCU and Sming libraries, and first version of
|
This code was influenced by NodeMCU and Sming libraries, and first version of
|
||||||
Arduino wrapper written by Hristo Gochkov.
|
Arduino wrapper written by Hristo Gochkov.
|
||||||
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#undef max
|
#undef max
|
||||||
#undef min
|
#undef min
|
||||||
#include "FSImpl.h"
|
#include "FSImpl.h"
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "spiffs/spiffs.h"
|
#include "spiffs/spiffs.h"
|
||||||
#include "spiffs/spiffs_nucleus.h"
|
#include "spiffs/spiffs_nucleus.h"
|
||||||
};
|
};
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "flash_utils.h"
|
#include "flash_utils.h"
|
||||||
@ -65,10 +65,10 @@ class SPIFFSImpl : public FSImpl
|
|||||||
public:
|
public:
|
||||||
SPIFFSImpl(uint32_t start, uint32_t size, uint32_t pageSize, uint32_t blockSize, uint32_t maxOpenFds)
|
SPIFFSImpl(uint32_t start, uint32_t size, uint32_t pageSize, uint32_t blockSize, uint32_t maxOpenFds)
|
||||||
: _start(start)
|
: _start(start)
|
||||||
, _size(size)
|
, _size(size)
|
||||||
, _pageSize(pageSize)
|
, _pageSize(pageSize)
|
||||||
, _blockSize(blockSize)
|
, _blockSize(blockSize)
|
||||||
, _maxOpenFds(maxOpenFds)
|
, _maxOpenFds(maxOpenFds)
|
||||||
{
|
{
|
||||||
memset(&_fs, 0, sizeof(_fs));
|
memset(&_fs, 0, sizeof(_fs));
|
||||||
}
|
}
|
||||||
@ -79,16 +79,19 @@ public:
|
|||||||
|
|
||||||
bool rename(const char* pathFrom, const char* pathTo) override
|
bool rename(const char* pathFrom, const char* pathTo) override
|
||||||
{
|
{
|
||||||
if (!isSpiffsFilenameValid(pathFrom)) {
|
if (!isSpiffsFilenameValid(pathFrom))
|
||||||
|
{
|
||||||
DEBUGV("SPIFFSImpl::rename: invalid pathFrom=`%s`\r\n", pathFrom);
|
DEBUGV("SPIFFSImpl::rename: invalid pathFrom=`%s`\r\n", pathFrom);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!isSpiffsFilenameValid(pathTo)) {
|
if (!isSpiffsFilenameValid(pathTo))
|
||||||
|
{
|
||||||
DEBUGV("SPIFFSImpl::rename: invalid pathTo=`%s` \r\n", pathTo);
|
DEBUGV("SPIFFSImpl::rename: invalid pathTo=`%s` \r\n", pathTo);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto rc = SPIFFS_rename(&_fs, pathFrom, pathTo);
|
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,
|
DEBUGV("SPIFFS_rename: rc=%d, from=`%s`, to=`%s`\r\n", rc,
|
||||||
pathFrom, pathTo);
|
pathFrom, pathTo);
|
||||||
return false;
|
return false;
|
||||||
@ -104,7 +107,8 @@ public:
|
|||||||
info.maxPathLength = SPIFFS_OBJ_NAME_LEN;
|
info.maxPathLength = SPIFFS_OBJ_NAME_LEN;
|
||||||
uint32_t totalBytes, usedBytes;
|
uint32_t totalBytes, usedBytes;
|
||||||
auto rc = SPIFFS_info(&_fs, &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);
|
DEBUGV("SPIFFS_info: rc=%d, err=%d\r\n", rc, _fs.err_code);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -115,12 +119,14 @@ public:
|
|||||||
|
|
||||||
bool remove(const char* path) override
|
bool remove(const char* path) override
|
||||||
{
|
{
|
||||||
if (!isSpiffsFilenameValid(path)) {
|
if (!isSpiffsFilenameValid(path))
|
||||||
|
{
|
||||||
DEBUGV("SPIFFSImpl::remove: invalid path=`%s`\r\n", path);
|
DEBUGV("SPIFFSImpl::remove: invalid path=`%s`\r\n", path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto rc = SPIFFS_remove(&_fs, path);
|
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);
|
DEBUGV("SPIFFS_remove: rc=%d path=`%s`\r\n", rc, path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -141,40 +147,49 @@ public:
|
|||||||
|
|
||||||
bool setConfig(const FSConfig &cfg) override
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
_cfg = *static_cast<const SPIFFSConfig *>(&cfg);
|
_cfg = *static_cast<const SPIFFSConfig *>(&cfg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool begin() override
|
bool begin() override
|
||||||
{
|
{
|
||||||
if (SPIFFS_mounted(&_fs) != 0) {
|
if (SPIFFS_mounted(&_fs) != 0)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (_size == 0) {
|
if (_size == 0)
|
||||||
|
{
|
||||||
DEBUGV("SPIFFS size is zero");
|
DEBUGV("SPIFFS size is zero");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_tryMount()) {
|
if (_tryMount())
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (_cfg._autoFormat) {
|
if (_cfg._autoFormat)
|
||||||
|
{
|
||||||
auto rc = SPIFFS_format(&_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);
|
DEBUGV("SPIFFS_format: rc=%d, err=%d\r\n", rc, _fs.err_code);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _tryMount();
|
return _tryMount();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void end() override
|
void end() override
|
||||||
{
|
{
|
||||||
if (SPIFFS_mounted(&_fs) == 0) {
|
if (SPIFFS_mounted(&_fs) == 0)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SPIFFS_unmount(&_fs);
|
SPIFFS_unmount(&_fs);
|
||||||
@ -185,23 +200,27 @@ public:
|
|||||||
|
|
||||||
bool format() override
|
bool format() override
|
||||||
{
|
{
|
||||||
if (_size == 0) {
|
if (_size == 0)
|
||||||
|
{
|
||||||
DEBUGV("SPIFFS size is zero");
|
DEBUGV("SPIFFS size is zero");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wasMounted = (SPIFFS_mounted(&_fs) != 0);
|
bool wasMounted = (SPIFFS_mounted(&_fs) != 0);
|
||||||
|
|
||||||
if (_tryMount()) {
|
if (_tryMount())
|
||||||
|
{
|
||||||
SPIFFS_unmount(&_fs);
|
SPIFFS_unmount(&_fs);
|
||||||
}
|
}
|
||||||
auto rc = SPIFFS_format(&_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);
|
DEBUGV("SPIFFS_format: rc=%d, err=%d\r\n", rc, _fs.err_code);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasMounted) {
|
if (wasMounted)
|
||||||
|
{
|
||||||
return _tryMount();
|
return _tryMount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +229,7 @@ public:
|
|||||||
|
|
||||||
bool gc() override
|
bool gc() override
|
||||||
{
|
{
|
||||||
return SPIFFS_gc_quick( &_fs, 0 ) == SPIFFS_OK;
|
return SPIFFS_gc_quick(&_fs, 0) == SPIFFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -237,22 +256,26 @@ protected:
|
|||||||
config.log_page_size = _pageSize;
|
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");
|
DEBUGV("spiffs_block_ix type too small");
|
||||||
abort();
|
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");
|
DEBUGV("spiffs_page_ix type too small");
|
||||||
abort();
|
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");
|
DEBUGV("spiffs_obj_id type too small");
|
||||||
abort();
|
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");
|
DEBUGV("spiffs_span_ix type too small");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -267,7 +290,8 @@ protected:
|
|||||||
size_t fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&_fs, _maxOpenFds);
|
size_t fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&_fs, _maxOpenFds);
|
||||||
size_t cacheBufSize = SPIFFS_buffer_bytes_for_cache(&_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",
|
DEBUGV("SPIFFSImpl: allocating %zd+%zd+%zd=%zd bytes\r\n",
|
||||||
workBufSize, fdsBufSize, cacheBufSize,
|
workBufSize, fdsBufSize, cacheBufSize,
|
||||||
workBufSize + fdsBufSize + cacheBufSize);
|
workBufSize + fdsBufSize + cacheBufSize);
|
||||||
@ -324,7 +348,7 @@ public:
|
|||||||
SPIFFSFileImpl(SPIFFSImpl* fs, spiffs_file fd)
|
SPIFFSFileImpl(SPIFFSImpl* fs, spiffs_file fd)
|
||||||
: _fs(fs)
|
: _fs(fs)
|
||||||
, _fd(fd)
|
, _fd(fd)
|
||||||
, _written(false)
|
, _written(false)
|
||||||
{
|
{
|
||||||
memset(&_stat, 0, sizeof(_stat));
|
memset(&_stat, 0, sizeof(_stat));
|
||||||
_getStat();
|
_getStat();
|
||||||
@ -340,7 +364,8 @@ public:
|
|||||||
CHECKFD();
|
CHECKFD();
|
||||||
|
|
||||||
auto result = SPIFFS_write(_fs->getFs(), _fd, (void*) buf, size);
|
auto result = SPIFFS_write(_fs->getFs(), _fd, (void*) buf, size);
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
|
{
|
||||||
DEBUGV("SPIFFS_write rc=%d\r\n", result);
|
DEBUGV("SPIFFS_write rc=%d\r\n", result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -352,7 +377,8 @@ public:
|
|||||||
{
|
{
|
||||||
CHECKFD();
|
CHECKFD();
|
||||||
auto result = SPIFFS_read(_fs->getFs(), _fd, (void*) buf, size);
|
auto result = SPIFFS_read(_fs->getFs(), _fd, (void*) buf, size);
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
|
{
|
||||||
DEBUGV("SPIFFS_read rc=%d\r\n", result);
|
DEBUGV("SPIFFS_read rc=%d\r\n", result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -365,7 +391,8 @@ public:
|
|||||||
CHECKFD();
|
CHECKFD();
|
||||||
|
|
||||||
auto rc = SPIFFS_fflush(_fs->getFs(), _fd);
|
auto rc = SPIFFS_fflush(_fs->getFs(), _fd);
|
||||||
if (rc < 0) {
|
if (rc < 0)
|
||||||
|
{
|
||||||
DEBUGV("SPIFFS_fflush rc=%d\r\n", rc);
|
DEBUGV("SPIFFS_fflush rc=%d\r\n", rc);
|
||||||
}
|
}
|
||||||
_written = true;
|
_written = true;
|
||||||
@ -376,11 +403,13 @@ public:
|
|||||||
CHECKFD();
|
CHECKFD();
|
||||||
|
|
||||||
int32_t offset = static_cast<int32_t>(pos);
|
int32_t offset = static_cast<int32_t>(pos);
|
||||||
if (mode == SeekEnd) {
|
if (mode == SeekEnd)
|
||||||
|
{
|
||||||
offset = -offset;
|
offset = -offset;
|
||||||
}
|
}
|
||||||
auto rc = SPIFFS_lseek(_fs->getFs(), _fd, offset, (int) mode);
|
auto rc = SPIFFS_lseek(_fs->getFs(), _fd, offset, (int) mode);
|
||||||
if (rc < 0) {
|
if (rc < 0)
|
||||||
|
{
|
||||||
DEBUGV("SPIFFS_lseek rc=%d\r\n", rc);
|
DEBUGV("SPIFFS_lseek rc=%d\r\n", rc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -393,7 +422,8 @@ public:
|
|||||||
CHECKFD();
|
CHECKFD();
|
||||||
|
|
||||||
auto result = SPIFFS_lseek(_fs->getFs(), _fd, 0, SPIFFS_SEEK_CUR);
|
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);
|
DEBUGV("SPIFFS_tell rc=%d\r\n", result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -404,7 +434,8 @@ public:
|
|||||||
size_t size() const override
|
size_t size() const override
|
||||||
{
|
{
|
||||||
CHECKFD();
|
CHECKFD();
|
||||||
if (_written) {
|
if (_written)
|
||||||
|
{
|
||||||
_getStat();
|
_getStat();
|
||||||
}
|
}
|
||||||
return _stat.size;
|
return _stat.size;
|
||||||
@ -414,10 +445,13 @@ public:
|
|||||||
{
|
{
|
||||||
CHECKFD();
|
CHECKFD();
|
||||||
spiffs_fd *sfd;
|
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);
|
return SPIFFS_OK == spiffs_object_truncate(sfd, size, 0);
|
||||||
} else {
|
}
|
||||||
return false;
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +492,8 @@ protected:
|
|||||||
{
|
{
|
||||||
CHECKFD();
|
CHECKFD();
|
||||||
auto rc = SPIFFS_fstat(_fs->getFs(), _fd, &_stat);
|
auto rc = SPIFFS_fstat(_fs->getFs(), _fd, &_stat);
|
||||||
if (rc != SPIFFS_OK) {
|
if (rc != SPIFFS_OK)
|
||||||
|
{
|
||||||
DEBUGV("SPIFFS_fstat rc=%d\r\n", rc);
|
DEBUGV("SPIFFS_fstat rc=%d\r\n", rc);
|
||||||
memset(&_stat, 0, sizeof(_stat));
|
memset(&_stat, 0, sizeof(_stat));
|
||||||
}
|
}
|
||||||
@ -490,13 +525,15 @@ public:
|
|||||||
|
|
||||||
FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) override
|
FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) override
|
||||||
{
|
{
|
||||||
if (!_valid) {
|
if (!_valid)
|
||||||
|
{
|
||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
}
|
}
|
||||||
int mode = getSpiffsMode(openMode, accessMode);
|
int mode = getSpiffsMode(openMode, accessMode);
|
||||||
auto fs = _fs->getFs();
|
auto fs = _fs->getFs();
|
||||||
spiffs_file fd = SPIFFS_open_by_dirent(fs, &_dirent, mode, 0);
|
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",
|
DEBUGV("SPIFFSDirImpl::openFile: fd=%d path=`%s` openMode=%d accessMode=%d err=%d\r\n",
|
||||||
fd, _dirent.name, openMode, accessMode, fs->err_code);
|
fd, _dirent.name, openMode, accessMode, fs->err_code);
|
||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
@ -506,7 +543,8 @@ public:
|
|||||||
|
|
||||||
const char* fileName() override
|
const char* fileName() override
|
||||||
{
|
{
|
||||||
if (!_valid) {
|
if (!_valid)
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +553,8 @@ public:
|
|||||||
|
|
||||||
size_t fileSize() override
|
size_t fileSize() override
|
||||||
{
|
{
|
||||||
if (!_valid) {
|
if (!_valid)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,10 +576,11 @@ public:
|
|||||||
bool next() override
|
bool next() override
|
||||||
{
|
{
|
||||||
const int n = _pattern.length();
|
const int n = _pattern.length();
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
spiffs_dirent* result = SPIFFS_readdir(&_dir, &_dirent);
|
spiffs_dirent* result = SPIFFS_readdir(&_dir, &_dirent);
|
||||||
_valid = (result != nullptr);
|
_valid = (result != nullptr);
|
||||||
} while(_valid && strncmp((const char*) _dirent.name, _pattern.c_str(), n) != 0);
|
} while (_valid && strncmp((const char*) _dirent.name, _pattern.c_str(), n) != 0);
|
||||||
return _valid;
|
return _valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
spiffs_hal.cpp - SPI read/write/erase functions for SPIFFS.
|
spiffs_hal.cpp - SPI read/write/erase functions for SPIFFS.
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -29,55 +29,63 @@ extern "C" {
|
|||||||
#include "spi_flash.h"
|
#include "spi_flash.h"
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
spi_flash_read function requires flash address to be aligned on word boundary.
|
spi_flash_read function requires flash address to be aligned on word boundary.
|
||||||
We take care of this by reading first and last words separately and memcpy
|
We take care of this by reading first and last words separately and memcpy
|
||||||
relevant bytes into result buffer.
|
relevant bytes into result buffer.
|
||||||
|
|
||||||
alignment: 012301230123012301230123
|
alignment: 012301230123012301230123
|
||||||
bytes requested: -------***********------
|
bytes requested: -------***********------
|
||||||
read directly: --------xxxxxxxx--------
|
read directly: --------xxxxxxxx--------
|
||||||
read pre: ----aaaa----------------
|
read pre: ----aaaa----------------
|
||||||
read post: ----------------bbbb----
|
read post: ----------------bbbb----
|
||||||
alignedBegin: ^
|
alignedBegin: ^
|
||||||
alignedEnd: ^
|
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);
|
optimistic_yield(10000);
|
||||||
|
|
||||||
uint32_t result = SPIFFS_OK;
|
uint32_t result = SPIFFS_OK;
|
||||||
uint32_t alignedBegin = (addr + 3) & (~3);
|
uint32_t alignedBegin = (addr + 3) & (~3);
|
||||||
uint32_t alignedEnd = (addr + size) & (~3);
|
uint32_t alignedEnd = (addr + size) & (~3);
|
||||||
if (alignedEnd < alignedBegin) {
|
if (alignedEnd < alignedBegin)
|
||||||
|
{
|
||||||
alignedEnd = alignedBegin;
|
alignedEnd = alignedBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr < alignedBegin) {
|
if (addr < alignedBegin)
|
||||||
|
{
|
||||||
uint32_t nb = alignedBegin - addr;
|
uint32_t nb = alignedBegin - addr;
|
||||||
uint32_t tmp;
|
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",
|
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
memcpy(dst, ((uint8_t*) &tmp) + 4 - nb, nb);
|
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)) {
|
if (!ESP.flashRead(alignedBegin, (uint32_t*)(dst + alignedBegin - addr),
|
||||||
|
alignedEnd - alignedBegin))
|
||||||
|
{
|
||||||
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr + size > alignedEnd) {
|
if (addr + size > alignedEnd)
|
||||||
|
{
|
||||||
uint32_t nb = addr + size - alignedEnd;
|
uint32_t nb = addr + size - alignedEnd;
|
||||||
uint32_t tmp;
|
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",
|
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,58 +96,68 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Like spi_flash_read, spi_flash_write has a requirement for flash address to be
|
Like spi_flash_read, spi_flash_write has a requirement for flash address to be
|
||||||
aligned. However it also requires RAM address to be aligned as it reads data
|
aligned. However it also requires RAM address to be aligned as it reads data
|
||||||
in 32-bit words. Flash address (mis-)alignment is handled much the same way
|
in 32-bit words. Flash address (mis-)alignment is handled much the same way
|
||||||
as for reads, but for RAM alignment we have to copy data into a temporary
|
as for reads, but for RAM alignment we have to copy data into a temporary
|
||||||
buffer. The size of this buffer is a tradeoff between number of writes required
|
buffer. The size of this buffer is a tradeoff between number of writes required
|
||||||
and amount of stack required. This is chosen to be 512 bytes here, but might
|
and amount of stack required. This is chosen to be 512 bytes here, but might
|
||||||
be adjusted in the future if there are good reasons to do so.
|
be adjusted in the future if there are good reasons to do so.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const int UNALIGNED_WRITE_BUFFER_SIZE = 512;
|
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);
|
optimistic_yield(10000);
|
||||||
|
|
||||||
uint32_t alignedBegin = (addr + 3) & (~3);
|
uint32_t alignedBegin = (addr + 3) & (~3);
|
||||||
uint32_t alignedEnd = (addr + size) & (~3);
|
uint32_t alignedEnd = (addr + size) & (~3);
|
||||||
if (alignedEnd < alignedBegin) {
|
if (alignedEnd < alignedBegin)
|
||||||
|
{
|
||||||
alignedEnd = alignedBegin;
|
alignedEnd = alignedBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr < alignedBegin) {
|
if (addr < alignedBegin)
|
||||||
|
{
|
||||||
uint32_t ofs = alignedBegin - addr;
|
uint32_t ofs = alignedBegin - addr;
|
||||||
uint32_t nb = (size < ofs) ? size : ofs;
|
uint32_t nb = (size < ofs) ? size : ofs;
|
||||||
uint8_t tmp[4] __attribute__((aligned(4))) = {0xff, 0xff, 0xff, 0xff};
|
uint8_t tmp[4] __attribute__((aligned(4))) = {0xff, 0xff, 0xff, 0xff};
|
||||||
memcpy(tmp + 4 - ofs, src, nb);
|
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",
|
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alignedEnd != alignedBegin) {
|
if (alignedEnd != alignedBegin)
|
||||||
uint32_t* srcLeftover = (uint32_t*) (src + alignedBegin - addr);
|
{
|
||||||
|
uint32_t* srcLeftover = (uint32_t*)(src + alignedBegin - addr);
|
||||||
uint32_t srcAlign = ((uint32_t) srcLeftover) & 3;
|
uint32_t srcAlign = ((uint32_t) srcLeftover) & 3;
|
||||||
if (!srcAlign) {
|
if (!srcAlign)
|
||||||
|
{
|
||||||
if (!ESP.flashWrite(alignedBegin, (uint32_t*) srcLeftover,
|
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",
|
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
uint8_t buf[UNALIGNED_WRITE_BUFFER_SIZE];
|
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));
|
size_t willCopy = std::min(sizeLeft, sizeof(buf));
|
||||||
memcpy(buf, srcLeftover, willCopy);
|
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",
|
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,14 +168,16 @@ 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 nb = addr + size - alignedEnd;
|
||||||
uint32_t tmp = 0xffffffff;
|
uint32_t tmp = 0xffffffff;
|
||||||
memcpy(&tmp, src + size - nb, nb);
|
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",
|
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
|
||||||
__LINE__, addr, size, alignedBegin, alignedEnd);
|
__LINE__, addr, size, alignedBegin, alignedEnd);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,17 +185,21 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
|
|||||||
return SPIFFS_OK;
|
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 ||
|
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);
|
DEBUGV("_spif_erase called with addr=%x, size=%d\r\n", addr, size);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
const uint32_t sector = addr / SPI_FLASH_SEC_SIZE;
|
const uint32_t sector = addr / SPI_FLASH_SEC_SIZE;
|
||||||
const uint32_t sectorCount = size / 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);
|
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);
|
DEBUGV("_spif_erase addr=%x size=%d i=%d\r\n", addr, size, i);
|
||||||
return SPIFFS_ERR_INTERNAL;
|
return SPIFFS_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
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