1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Revert "Allman now (#6080)" (#6090)

This reverts commit 98125f88605cd7e46e9be4e1b3ad0600dd5d2b51.
This commit is contained in:
Allman-astyler 2019-05-14 00:09:54 +02:00 committed by david gauchard
parent 98125f8860
commit eea9999dc5
255 changed files with 42650 additions and 50904 deletions

View File

@ -15,7 +15,7 @@
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
@ -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,64 +110,25 @@ struct netifWrapper
} }
// address properties // address properties
IPAddress addr() const IPAddress addr () const { return ipFromNetifNum(); }
{ bool isLegacy () const { return _num == 0; }
return ipFromNetifNum(); bool isLocal () const { return addr().isLocal(); }
} bool isV4 () const { return addr().isV4(); }
bool isLegacy() const bool isV6 () const { return !addr().isV4(); }
{ 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 IPAddress ipv4 () const { return _netif->ip_addr; }
{ IPAddress netmask () const { return _netif->netmask; }
return _netif->ip_addr; IPAddress gw () const { return _netif->gw; }
}
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 String ifname () const { return String(_netif->name[0]) + _netif->name[1]; }
{ const char* ifhostname () const { return _netif->hostname?: emptyString.c_str(); }
return String(_netif->name[0]) + _netif->name[1]; const char* ifmac () const { return (const char*)_netif->hwaddr; }
} 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;
@ -189,8 +150,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_
@ -199,29 +160,13 @@ public:
(void)operator++(); (void)operator++();
} }
const netifWrapper& operator* () const const netifWrapper& operator* () const { return netIf; }
{ const netifWrapper* operator-> () const { return &netIf; }
return netIf;
}
const netifWrapper* operator-> () const
{
return &netIf;
}
bool operator== (AddressListIterator& o) bool operator== (AddressListIterator& o) { return netIf.equal(*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) AddressListIterator& operator= (const AddressListIterator& o) { netIf = o.netIf; return *this; }
{
netIf = o.netIf;
return *this;
}
AddressListIterator operator++ (int) AddressListIterator operator++ (int)
{ {
@ -243,10 +188,8 @@ 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;
} }
@ -259,25 +202,13 @@ class AddressList
public: public:
using const_iterator = const AddressListIterator; using const_iterator = const AddressListIterator;
const_iterator begin() const const_iterator begin () const { return const_iterator(netif_list); }
{ 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) inline AddressList::const_iterator begin (const AddressList& a) { return a.begin(); }
{ 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

View File

@ -15,7 +15,7 @@
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,8 +86,7 @@ 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_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max)
TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.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) TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max)

View File

@ -15,7 +15,7 @@
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,14 +23,13 @@
#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;
@ -39,14 +38,12 @@ public:
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

View File

@ -16,7 +16,7 @@
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,17 +33,11 @@ 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()

View File

@ -16,7 +16,7 @@
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>

View File

@ -16,7 +16,7 @@
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,54 +38,45 @@ extern "C" {
/** /**
User-defined Literals * User-defined Literals
usage: * usage:
*
* uint32_t = test = 10_MHz; // --> 10000000
*/
uint32_t = test = 10_MHz; // --> 10000000 unsigned long long operator"" _kHz(unsigned long long x) {
*/
unsigned long long operator"" _kHz(unsigned long long x)
{
return x * 1000; 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;
} }
@ -137,64 +128,58 @@ void EspClass::deepSleepInstant(uint64_t time_us, WakeMode mode)
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);
} }
} }
@ -250,8 +235,7 @@ 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];
@ -283,8 +267,7 @@ 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;
@ -305,8 +288,7 @@ 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;
@ -317,8 +299,7 @@ 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;
@ -330,17 +311,14 @@ 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) {
switch (byte & 0x0F)
{
case 0x0: // 4 Mbit (512KB) case 0x0: // 4 Mbit (512KB)
return (512_kB); return (512_kB);
case 0x1: // 2 MBit (256KB) case 0x1: // 2 MBit (256KB)
@ -360,10 +338,8 @@ uint32_t EspClass::magicFlashChipSize(uint8_t byte)
} }
} }
uint32_t EspClass::magicFlashChipSpeed(uint8_t byte) uint32_t EspClass::magicFlashChipSpeed(uint8_t byte) {
{ switch(byte & 0x0F) {
switch (byte & 0x0F)
{
case 0x0: // 40 MHz case 0x0: // 40 MHz
return (40_MHz); return (40_MHz);
case 0x1: // 26 MHz case 0x1: // 26 MHz
@ -377,34 +353,30 @@ uint32_t EspClass::magicFlashChipSpeed(uint8_t byte)
} }
} }
FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) {
{
FlashMode_t mode = (FlashMode_t) byte; 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
@ -450,71 +422,47 @@ uint32_t EspClass::getFlashChipSizeByChipId(void)
} }
/** /**
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 (needsEquals) if(getFlashChipRealSize() == getFlashChipSize()) {
{
if (getFlashChipRealSize() == getFlashChipSize())
{
return true; return true;
} }
} } else {
else if(getFlashChipRealSize() >= getFlashChipSize()) {
{
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")); strcpy_P(buff, PSTR("Power on"));
} } else if (resetInfo.reason == REASON_WDT_RST) { // hardware watch dog reset
else if (resetInfo.reason == REASON_WDT_RST) // hardware watch dog reset
{
strcpy_P(buff, PSTR("Hardware Watchdog")); strcpy_P(buff, PSTR("Hardware Watchdog"));
} } else if (resetInfo.reason == REASON_EXCEPTION_RST) { // exception reset, GPIO status wont change
else if (resetInfo.reason == REASON_EXCEPTION_RST) // exception reset, GPIO status wont change
{
strcpy_P(buff, PSTR("Exception")); strcpy_P(buff, PSTR("Exception"));
} } else if (resetInfo.reason == REASON_SOFT_WDT_RST) { // software watch dog reset, GPIO status wont change
else if (resetInfo.reason == REASON_SOFT_WDT_RST) // software watch dog reset, GPIO status wont change
{
strcpy_P(buff, PSTR("Software Watchdog")); strcpy_P(buff, PSTR("Software Watchdog"));
} } else if (resetInfo.reason == REASON_SOFT_RESTART) { // software restart ,system_restart , GPIO status wont change
else if (resetInfo.reason == REASON_SOFT_RESTART) // software restart ,system_restart , GPIO status wont change
{
strcpy_P(buff, PSTR("Software/System restart")); strcpy_P(buff, PSTR("Software/System restart"));
} } else if (resetInfo.reason == REASON_DEEP_SLEEP_AWAKE) { // wake up from deep-sleep
else if (resetInfo.reason == REASON_DEEP_SLEEP_AWAKE) // wake up from deep-sleep
{
strcpy_P(buff, PSTR("Deep-Sleep Wake")); strcpy_P(buff, PSTR("Deep-Sleep Wake"));
} } else if (resetInfo.reason == REASON_EXT_SYS_RST) { // external system reset
else if (resetInfo.reason == REASON_EXT_SYS_RST) // external system reset
{
strcpy_P(buff, PSTR("External System")); strcpy_P(buff, PSTR("External System"));
} } else {
else
{
strcpy_P(buff, PSTR("Unknown")); 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);
@ -522,20 +470,16 @@ 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;
} }
} }
@ -543,18 +487,14 @@ 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);
@ -566,8 +506,7 @@ uint32_t EspClass::getSketchSize()
++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*) &section_header, sizeof(section_header))) if (spi_flash_read(pos, (uint32_t*) &section_header, sizeof(section_header))) {
{
return 0; return 0;
} }
pos += sizeof(section_header); pos += sizeof(section_header);
@ -582,8 +521,7 @@ 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
@ -596,70 +534,51 @@ 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) if(restartOnFail) ESP.restart();
{
ESP.restart();
}
return false; 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) if(restartOnFail) ESP.restart();
{
ESP.restart();
}
return false; 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) if(restartOnFail) ESP.restart();
{
ESP.restart();
}
return false; return false;
} }
#ifdef DEBUG_SERIAL #ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("Update SUCCESS"); DEBUG_SERIAL.println("Update SUCCESS");
#endif #endif
if (restartOnSuccess) if(restartOnSuccess) ESP.restart();
{
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) {
if (data == nullptr)
{
return 1; // SPI_FLASH_RESULT_ERR 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.
@ -667,37 +586,29 @@ static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size)
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;
} }
@ -708,12 +619,10 @@ 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
@ -724,8 +633,7 @@ 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;
} }
@ -733,25 +641,21 @@ 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);

View File

@ -16,7 +16,7 @@
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,18 +24,17 @@
#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 */
@ -71,10 +70,9 @@ 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
@ -96,8 +94,7 @@ 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.
@ -114,8 +111,7 @@ 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,
@ -124,8 +120,7 @@ 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_QIO = 0x00,
FM_QOUT = 0x01, FM_QOUT = 0x01,
FM_DIO = 0x02, FM_DIO = 0x02,
@ -133,9 +128,8 @@ typedef enum
FM_UNKNOWN = 0xff FM_UNKNOWN = 0xff
} FlashMode_t; } FlashMode_t;
class EspClass class EspClass {
{ public:
public:
// TODO: figure out how to set WDT timeout // TODO: figure out how to set WDT timeout
void wdtEnable(uint32_t timeout_ms = 0); void wdtEnable(uint32_t timeout_ms = 0);
// note: setting the timeout value is not implemented at the moment // note: setting the timeout value is not implemented at the moment
@ -216,7 +210,7 @@ public:
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

View File

@ -16,7 +16,7 @@
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,68 +25,49 @@ 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();
@ -94,126 +75,90 @@ 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();
@ -224,28 +169,25 @@ 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();
} }
@ -253,252 +195,201 @@ 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]) {
switch (mode[0])
{
case 'r': case 'r':
am = AM_READ; am = AM_READ;
om = OM_DEFAULT; om = OM_DEFAULT;
break; break;
case 'w': case 'w':
am = AM_WRITE; am = AM_WRITE;
om = (OpenMode)(OM_CREATE | OM_TRUNCATE); om = (OpenMode) (OM_CREATE | OM_TRUNCATE);
break; break;
case 'a': case 'a':
am = AM_WRITE; am = AM_WRITE;
om = (OpenMode)(OM_CREATE | OM_APPEND); om = (OpenMode) (OM_CREATE | OM_APPEND);
break; break;
default: default:
return false; return false;
} }
switch (mode[1]) switch(mode[1]) {
{
case '+': case '+':
am = (AccessMode)(AM_WRITE | AM_READ); am = (AccessMode) (AM_WRITE | AM_READ);
break; break;
case 0: case 0:
break; break;
@ -512,7 +403,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);
@ -526,8 +417,7 @@ bool mount<FS>(FS& fs, const char* mountPoint);
*/ */
struct MountEntry struct MountEntry {
{
FSImplPtr fs; FSImplPtr fs;
String path; String path;
MountEntry* next; MountEntry* next;
@ -536,11 +426,9 @@ 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;
} }
@ -559,39 +447,31 @@ 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

View File

@ -16,7 +16,7 @@
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,8 +24,7 @@
#include <memory> #include <memory>
#include <Arduino.h> #include <Arduino.h>
namespace fs namespace fs {
{
class File; class File;
class Dir; class Dir;
@ -41,8 +40,7 @@ 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
@ -62,14 +60,12 @@ 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;
@ -84,20 +80,17 @@ 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]; uint8_t obuf[256];
size_t doneLen = 0; size_t doneLen = 0;
size_t sentLen; size_t sentLen;
int i; int i;
while (src.available() > sizeof(obuf)) while (src.available() > sizeof(obuf)){
{
src.read(obuf, sizeof(obuf)); src.read(obuf, sizeof(obuf));
sentLen = write(obuf, sizeof(obuf)); sentLen = write(obuf, sizeof(obuf));
doneLen = doneLen + sentLen; doneLen = doneLen + sentLen;
if (sentLen != sizeof(obuf)) if(sentLen != sizeof(obuf)){
{
return doneLen; return doneLen;
} }
} }
@ -123,8 +116,7 @@ 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) { }
@ -143,8 +135,7 @@ 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;
@ -156,15 +147,13 @@ 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;
} }
@ -176,8 +165,7 @@ 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;
} }

View File

@ -16,18 +16,16 @@
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;
@ -44,23 +42,20 @@ 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;
@ -72,10 +67,9 @@ 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;
@ -88,10 +82,7 @@ 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() virtual bool gc() { return true; } // May not be implemented in all file systems.
{
return true; // May not be implemented in all file systems.
}
}; };
} // namespace fs } // namespace fs

View File

@ -8,7 +8,7 @@ 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)
@ -16,8 +16,8 @@ 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)
{ {
@ -49,7 +49,7 @@ void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode
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)
@ -67,5 +67,5 @@ void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> sc
as->interruptInfo = ii; as->interruptInfo = ii;
as->functionInfo = fi; as->functionInfo = fi;
__attachInterruptArg(pin, (voidFuncPtr)interruptFunctional, as, mode); __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
} }

View File

@ -13,21 +13,18 @@ extern "C" {
// Structures for communication // Structures for communication
struct InterruptInfo struct InterruptInfo {
{
uint8_t pin = 0; uint8_t pin = 0;
uint8_t value = 0; uint8_t value = 0;
uint32_t micro = 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; InterruptInfo* interruptInfo = nullptr;
FunctionInfo* functionInfo = nullptr; FunctionInfo* functionInfo = nullptr;
}; };

View File

@ -21,7 +21,7 @@
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>
@ -52,8 +52,7 @@ void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode m
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);
} }
@ -61,14 +60,10 @@ void HardwareSerial::end()
_uart = NULL; _uart = NULL;
} }
size_t HardwareSerial::setRxBufferSize(size_t size) size_t HardwareSerial::setRxBufferSize(size_t size){
{ if(_uart) {
if (_uart)
{
_rx_size = uart_resize_rx_buffer(_uart, size); _rx_size = uart_resize_rx_buffer(_uart, size);
} } else {
else
{
_rx_size = size; _rx_size = size;
} }
return _rx_size; return _rx_size;
@ -76,26 +71,18 @@ size_t HardwareSerial::setRxBufferSize(size_t size)
void HardwareSerial::setDebugOutput(bool en) void HardwareSerial::setDebugOutput(bool en)
{ {
if (!_uart) if(!_uart) {
{
return; return;
} }
if (en) if(en) {
{ if(uart_tx_enabled(_uart)) {
if (uart_tx_enabled(_uart))
{
uart_set_debug(_uart_nr); uart_set_debug(_uart_nr);
} } else {
else
{
uart_set_debug(UART_NO); uart_set_debug(UART_NO);
} }
} } else {
else
{
// disable debug for this interface // disable debug for this interface
if (uart_get_debug() == _uart_nr) if(uart_get_debug() == _uart_nr) {
{
uart_set_debug(UART_NO); uart_set_debug(UART_NO);
} }
} }
@ -104,8 +91,7 @@ void HardwareSerial::setDebugOutput(bool en)
int HardwareSerial::available(void) int HardwareSerial::available(void)
{ {
int result = static_cast<int>(uart_rx_available(_uart)); int result = static_cast<int>(uart_rx_available(_uart));
if (!result) if (!result) {
{
optimistic_yield(10000); optimistic_yield(10000);
} }
return result; return result;
@ -113,8 +99,7 @@ int HardwareSerial::available(void)
void HardwareSerial::flush() void HardwareSerial::flush()
{ {
if (!_uart || !uart_tx_enabled(_uart)) if(!_uart || !uart_tx_enabled(_uart)) {
{
return; return;
} }
@ -138,10 +123,8 @@ unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
{ {
time_t startMillis = millis(); time_t startMillis = millis();
unsigned long detectedBaudrate; unsigned long detectedBaudrate;
while ((time_t) millis() - startMillis < timeoutMillis) while ((time_t) millis() - startMillis < timeoutMillis) {
{ if ((detectedBaudrate = testBaudrate())) {
if ((detectedBaudrate = testBaudrate()))
{
break; break;
} }
yield(); yield();
@ -160,9 +143,7 @@ size_t HardwareSerial::readBytes(char* buffer, size_t size)
size_t avail; size_t avail;
while ((avail = available()) == 0 && !timeOut); while ((avail = available()) == 0 && !timeOut);
if (avail == 0) if (avail == 0)
{
break; break;
}
got += read(buffer + got, std::min(size - got, avail)); got += read(buffer + got, std::min(size - got, avail));
} }
return got; return got;

View File

@ -22,7 +22,7 @@
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,8 +32,7 @@
#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,
@ -60,8 +59,7 @@ 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
@ -106,8 +104,8 @@ 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)
{ {
@ -115,8 +113,8 @@ public:
} }
/* /*
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)
{ {

View File

@ -15,7 +15,7 @@
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,18 +27,15 @@ 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;
@ -46,14 +43,12 @@ 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];
@ -61,10 +56,8 @@ 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
@ -74,8 +67,7 @@ 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
@ -87,16 +79,14 @@ 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;
} }
@ -110,8 +100,7 @@ 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;
} }
@ -121,71 +110,52 @@ 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;
} }
@ -194,9 +164,7 @@ 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)'
@ -204,25 +172,22 @@ 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
@ -231,65 +196,45 @@ 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();
return true; return true;

View File

@ -15,7 +15,7 @@
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,9 +54,8 @@ 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;
@ -64,119 +63,72 @@ private:
// 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 const uint8_t* raw_address() const {
{
return reinterpret_cast<const uint8_t*>(&v4()); 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) IPAddress(uint32_t address) { ctor32(address); }
{ IPAddress(u32_t address) { ctor32(address); }
ctor32(address); IPAddress(int address) { ctor32(address); }
}
IPAddress(u32_t address)
{
ctor32(address);
}
IPAddress(int address)
{
ctor32(address);
}
IPAddress(const uint8_t *address); IPAddress(const uint8_t *address);
bool fromString(const char *address); bool fromString(const char *address);
bool fromString(const String &address) bool fromString(const String &address) { return fromString(address.c_str()); }
{
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 operator uint32_t() const { return isV4()? v4(): (uint32_t)0; }
{ operator uint32_t() { return isV4()? v4(): (uint32_t)0; }
return isV4() ? v4() : (uint32_t)0; operator u32_t() const { return isV4()? v4(): (u32_t)0; }
} operator u32_t() { return isV4()? v4(): (u32_t)0; }
operator uint32_t()
{
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 operator bool () const { return isSet(); } // <-
{ 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 const u32_t& v4() const { return ip_2_ip4(&_ip)->addr; } // for raw_address(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 bool operator!=(const IPAddress& addr) const {
{
return !ip_addr_cmp(&_ip, &addr._ip); return !ip_addr_cmp(&_ip, &addr._ip);
} }
bool operator==(uint32_t addr) const bool operator==(uint32_t addr) const {
{
return isV4() && v4() == addr; return isV4() && v4() == addr;
} }
bool operator==(u32_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!=(uint32_t addr) const {
{
return !(isV4() && v4() == addr); return !(isV4() && v4() == addr);
} }
bool operator!=(u32_t addr) const bool operator!=(u32_t addr) const {
{
return !(isV4() && v4() == addr); return !(isV4() && v4() == addr);
} }
bool operator==(const uint8_t* addr) const; 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) uint8_t& operator[](int index) {
{
setV4(); setV4();
return *(raw_address() + index); return *(raw_address() + index);
} }
@ -206,78 +158,28 @@ public:
/* /*
lwIP address compatibility lwIP address compatibility
*/ */
IPAddress(const ipv4_addr& fw_addr) IPAddress(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.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) IPAddress& operator=(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; return *this; }
{ IPAddress& operator=(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; return *this; }
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 operator ip_addr_t () const { return _ip; }
{ operator const ip_addr_t*() const { return &_ip; }
return _ip; operator ip_addr_t*() { return &_ip; }
}
operator const ip_addr_t*() const
{
return &_ip;
}
operator ip_addr_t*()
{
return &_ip;
}
bool isV4() const bool isV4() const { return IP_IS_V4_VAL(_ip); }
{ 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 bool isLocal () const { return ip_addr_islinklocal(&_ip); }
{
return ip_addr_islinklocal(&_ip);
}
#if LWIP_IPV6 #if LWIP_IPV6
IPAddress(const ip_addr_t& lwip_addr) IPAddress(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); }
{ IPAddress(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); }
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) IPAddress& operator=(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); return *this; }
{ IPAddress& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; }
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()
{ {
@ -287,49 +189,31 @@ public:
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 operator const ip4_addr_t*() const { return isV4()? ip_2_ip4(&_ip): nullptr; }
{
return isV4() ? ip_2_ip4(&_ip) : nullptr;
}
bool isV6() const bool isV6() const { return IP_IS_V6_VAL(_ip); }
{ 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() uint16_t* raw6() { return nullptr; }
{ const uint16_t* raw6() const { return nullptr; }
return nullptr; bool isV6() const { return false; }
}
const uint16_t* raw6() const
{
return nullptr;
}
bool isV6() const
{
return false;
}
void setV6() { } void setV6() { }
#endif #endif
protected: protected:
bool fromString4(const char *address); bool fromString4(const char *address);
}; };

View File

@ -1,72 +1,60 @@
#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)) : return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
(c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) :
(c >= '0' && c <= '9') ? (c - (uint8_t)'0') : 0; (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;
} }
@ -83,26 +71,21 @@ 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);

View File

@ -25,35 +25,19 @@
#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) void add(const char * data){ add((const uint8_t*)data, strlen(data)); }
{ void add(char * data){ add((const char*)data); }
add((const uint8_t*)data, strlen(data)); void add(const String& data){ add(data.c_str()); }
}
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) void addHexString(char * data){ addHexString((const 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);

View File

@ -21,7 +21,7 @@
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>
@ -44,19 +44,13 @@ struct DoNothing
struct YieldOrSkip struct YieldOrSkip
{ {
static void execute() static void execute() {delay(0);}
{
delay(0);
}
}; };
template <unsigned long delayMs> template <unsigned long delayMs>
struct YieldAndDelayMs struct YieldAndDelayMs
{ {
static void execute() static void execute() {delay(delayMs);}
{
delay(delayMs);
}
}; };
} //YieldPolicy } //YieldPolicy
@ -69,10 +63,7 @@ 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() static timeType time() {return millis();}
{
return millis();
}
static constexpr timeType ticksPerSecond = 1000; static constexpr timeType ticksPerSecond = 1000;
static constexpr timeType ticksPerSecondMax = 1000; static constexpr timeType ticksPerSecondMax = 1000;
}; };
@ -84,16 +75,13 @@ struct TimeSourceCycles
// (every loop, every yield) // (every loop, every yield)
using timeType = decltype(ESP.getCycleCount()); using timeType = decltype(ESP.getCycleCount());
static timeType time() static timeType time() {return ESP.getCycleCount();}
{
return ESP.getCycleCount();
}
static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz
static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz 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;
@ -101,30 +89,28 @@ struct TimeUnit
#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?
fractional == 0 ? 1: // no need for compensation
1 : // no need for compensation
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division (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 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 fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
fractional == 0 ? fractional == 0?
1 : // no need for compensation 1: // no need for compensation
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division (number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
}); });
} }
@ -139,18 +125,9 @@ struct TimeUnit
// 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) static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;}
{ static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;}
return (userUnit * user2UnitMultiplier) / user2UnitDivider; static timeType time () {return TimeSourceType::time();}
}
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 >;
@ -180,10 +157,8 @@ public:
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 expiredRetrigger();
}
return expiredOneShot(); return expiredOneShot();
} }
@ -193,12 +168,12 @@ public:
return expired(); return expired();
} }
bool canExpire() const bool canExpire () const
{ {
return !_neverExpires; return !_neverExpires;
} }
bool canWait() const bool canWait () const
{ {
return _timeout != alwaysExpired; return _timeout != alwaysExpired;
} }
@ -215,7 +190,7 @@ public:
_start = TimePolicyT::time(); _start = TimePolicyT::time();
} }
void resetToNeverExpires() void resetToNeverExpires ()
{ {
_timeout = alwaysExpired + 1; // because canWait() has precedence _timeout = alwaysExpired + 1; // because canWait() has precedence
_neverExpires = true; _neverExpires = true;
@ -247,12 +222,10 @@ protected:
bool expiredRetrigger() bool expiredRetrigger()
{ {
if (!canWait()) if (!canWait())
{
return true; return true;
}
timeType current = TimePolicyT::time(); timeType current = TimePolicyT::time();
if (checkExpired(current)) if(checkExpired(current))
{ {
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout) unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
_start += n * _timeout; _start += n * _timeout;
@ -304,10 +277,10 @@ using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothi
/* 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

View File

@ -19,7 +19,7 @@
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,25 +32,21 @@
// 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;
} }
@ -59,19 +55,16 @@ 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);
@ -79,26 +72,22 @@ 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);
@ -106,181 +95,143 @@ 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) if (c == 0) break;
{
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) {
else if (base == 10) if(n < 0) {
{
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;
@ -288,64 +239,48 @@ 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)
if (number > 4294967040.0)
{
return print("ovf"); // constant determined empirically 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
}
// 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;
@ -355,14 +290,12 @@ 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);

View File

@ -15,7 +15,7 @@
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,46 @@
#define OCT 8 #define OCT 8
#define BIN 2 #define BIN 2
class Print class Print {
{ private:
private:
int write_error; int write_error;
size_t printNumber(unsigned long, uint8_t); size_t printNumber(unsigned long, uint8_t);
size_t printFloat(double, uint8_t); size_t printFloat(double, uint8_t);
protected: protected:
void setWriteError(int err = 1) void setWriteError(int err = 1) {
{
write_error = err; write_error = err;
} }
public: public:
Print() : Print() :
write_error(0) write_error(0) {
{
} }
int getWriteError() int getWriteError() {
{
return write_error; return write_error;
} }
void clearWriteError() void clearWriteError() {
{
setWriteError(0); 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)
if (str == NULL)
{
return 0; return 0;
}
return write((const uint8_t *) str, strlen(str)); return write((const uint8_t *) str, strlen(str));
} }
virtual size_t write(const uint8_t *buffer, size_t size); virtual size_t write(const uint8_t *buffer, size_t size);
size_t write(const char *buffer, size_t size) size_t write(const char *buffer, size_t size) {
{
return write((const uint8_t *) buffer, size); return write((const uint8_t *) buffer, size);
} }
// These handle ambiguity for write(0) case, because (0) can be a pointer or an integer // These handle ambiguity for write(0) case, because (0) can be a pointer or an integer
size_t write(short t) size_t write(short t) { return write((uint8_t)t); }
{ size_t write(unsigned short t) { return write((uint8_t)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(unsigned 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(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 &);

View File

@ -15,7 +15,7 @@
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
@ -28,11 +28,10 @@ class Print;
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:
public:
virtual size_t printTo(Print& p) const = 0; virtual size_t printTo(Print& p) const = 0;
}; };

View File

@ -14,22 +14,18 @@ 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;
@ -39,12 +35,10 @@ 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;
@ -54,18 +48,15 @@ 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;
@ -77,8 +68,7 @@ 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();

View File

@ -1,15 +1,15 @@
/* /*
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)
{ {
} }
@ -18,8 +18,7 @@ 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)
@ -52,7 +51,7 @@ std::list<ScheduledFunctions::ScheduledElement>::iterator ScheduledFunctions::er
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)
@ -60,9 +59,9 @@ 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()

View File

@ -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,8 +18,7 @@
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();
@ -38,7 +37,7 @@ public:
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);

View File

@ -15,17 +15,16 @@
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:
public: virtual void begin() =0;
virtual void begin() = 0;
}; };
#endif #endif

View File

@ -31,111 +31,97 @@
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_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
stack_thunk_top = stack_thunk_ptr + _stackSize - 1; stack_thunk_top = stack_thunk_ptr + _stackSize - 1;
stack_thunk_save = NULL; stack_thunk_save = NULL;
stack_thunk_repaint(); 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! */ /* Error! */
return; return;
} }
stack_thunk_refcnt--; stack_thunk_refcnt--;
if (!stack_thunk_refcnt) if (!stack_thunk_refcnt) {
{
free(stack_thunk_ptr); free(stack_thunk_ptr);
stack_thunk_ptr = NULL; stack_thunk_ptr = NULL;
stack_thunk_top = NULL; stack_thunk_top = NULL;
stack_thunk_save = 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)) if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint))
{
break; break;
}
pos += 4; pos += 4;
} }
ets_printf(">>>stack>>>\n"); ets_printf(">>>stack>>>\n");
while (pos < stack_thunk_ptr) while (pos < stack_thunk_ptr) {
{
ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]); ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]);
pos += 4; pos += 4;
} }
ets_printf("<<<stack<<<\n"); ets_printf("<<<stack<<<\n");
} }
}; };

View File

@ -18,7 +18,7 @@
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,59 +26,43 @@
#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 return c; // timeout
} if(c == '-')
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
} }
} }
@ -92,125 +76,95 @@ 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 return true; // return true if target is a null string
} while((c = timedRead()) > 0) {
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)
if (++termIndex >= termLen)
{
return false; // return false if terminate string found before target string return false; // return false if terminate string found before target string
} } else
}
else
{
termIndex = 0; termIndex = 0;
} }
}
return false; return false;
} }
// 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;
@ -219,47 +173,31 @@ 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
@ -267,16 +205,12 @@ 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++;
} }
@ -287,44 +221,34 @@ size_t Stream::readBytes(char *buffer, size_t length)
// terminates if length characters have been read, timeout, or if the terminator character detected // 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();
} }

View File

@ -17,7 +17,7 @@
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
@ -33,59 +33,50 @@
#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:
protected:
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
unsigned long _startMillis; // used for timeout measurement unsigned long _startMillis; // used for timeout measurement
int timedRead(); // private method to read stream with timeout int timedRead(); // private method to read stream with timeout
int timedPeek(); // private method to peek stream with timeout int timedPeek(); // private method to peek stream with timeout
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if 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) bool find(char target) { return find (&target, 1); }
{
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);
} }
@ -96,16 +87,14 @@ public:
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) // 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) // 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 // terminates if length characters have been read, timeout, or if the terminator character detected
@ -115,7 +104,7 @@ public:
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

View File

@ -18,19 +18,16 @@
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;
@ -39,20 +36,16 @@ 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;
@ -61,17 +54,14 @@ 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() {
{
} }

View File

@ -24,8 +24,7 @@
#define STREAMSTRING_H_ #define STREAMSTRING_H_
class StreamString: public Stream, public String class StreamString: public Stream, public String {
{
public: public:
size_t write(const uint8_t *buffer, size_t size) override; size_t write(const uint8_t *buffer, size_t size) override;
size_t write(uint8_t data) override; size_t write(uint8_t data) override;

View File

@ -28,10 +28,8 @@
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) {
if (_pin > 16)
{
return; return;
} }
@ -40,21 +38,16 @@ static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long
high = std::max(high, (uint32_t)100); 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) {
if (frequency == 0)
{
noTone(_pin); noTone(_pin);
} } else {
else
{
uint32_t period = 1000000L / frequency; uint32_t period = 1000000L / frequency;
uint32_t high = period / 2; uint32_t high = period / 2;
uint32_t low = period - high; uint32_t low = period - high;
@ -65,14 +58,10 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
// Separate tone(float) to hopefully not pull in floating point libs unless // 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
if (frequency < 1.0) // FP means no exact comparisons
{
noTone(_pin); noTone(_pin);
} } else {
else
{
double period = 1000000.0 / frequency; double period = 1000000.0 / frequency;
uint32_t high = (uint32_t)((period / 2.0) + 0.5); uint32_t high = (uint32_t)((period / 2.0) + 0.5);
uint32_t low = (uint32_t)(period + 0.5) - high; uint32_t low = (uint32_t)(period + 0.5) - high;
@ -82,17 +71,14 @@ void tone(uint8_t _pin, double frequency, unsigned long duration)
// Fix ambiguous tone() binding when adding in a duration // 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 // Call the unsigned int version of the function explicitly
tone(_pin, (unsigned int)frequency, duration); tone(_pin, (unsigned int)frequency, duration);
} }
void noTone(uint8_t _pin) void noTone(uint8_t _pin) {
{ if (_pin > 16) {
if (_pin > 16)
{
return; return;
} }
stopWaveform(_pin); stopWaveform(_pin);

View File

@ -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,59 +38,56 @@
#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

View File

@ -8,54 +8,50 @@
#include <Updater_Signing.h> #include <Updater_Signing.h>
#ifndef ARDUINO_SIGNING #ifndef ARDUINO_SIGNING
#define ARDUINO_SIGNING 0 #define ARDUINO_SIGNING 0
#endif #endif
#if ARDUINO_SIGNING #if ARDUINO_SIGNING
#include "../../libraries/ESP8266WiFi/src/BearSSLHelpers.h" #include "../../libraries/ESP8266WiFi/src/BearSSLHelpers.h"
static BearSSL::PublicKey signPubKey(signing_pubkey); static BearSSL::PublicKey signPubKey(signing_pubkey);
static BearSSL::HashSHA256 hash; static BearSSL::HashSHA256 hash;
static BearSSL::SigningVerifier sign(&signPubKey); static BearSSL::SigningVerifier sign(&signPubKey);
#endif #endif
extern "C" { extern "C" {
#include "c_types.h" #include "c_types.h"
#include "spi_flash.h" #include "spi_flash.h"
#include "user_interface.h" #include "user_interface.h"
} }
extern "C" uint32_t _SPIFFS_start; extern "C" uint32_t _SPIFFS_start;
UpdaterClass::UpdaterClass() UpdaterClass::UpdaterClass()
: _async(false) : _async(false)
, _error(0) , _error(0)
, _buffer(0) , _buffer(0)
, _bufferLen(0) , _bufferLen(0)
, _size(0) , _size(0)
, _startAddress(0) , _startAddress(0)
, _currentAddress(0) , _currentAddress(0)
, _command(U_FLASH) , _command(U_FLASH)
, _hash(nullptr) , _hash(nullptr)
, _verify(nullptr) , _verify(nullptr)
, _progress_callback(nullptr) , _progress_callback(nullptr)
{ {
#if ARDUINO_SIGNING #if ARDUINO_SIGNING
installSignature(&hash, &sign); installSignature(&hash, &sign);
#endif #endif
} }
UpdaterClass& UpdaterClass::onProgress(THandlerFunction_Progress fn) UpdaterClass& UpdaterClass::onProgress(THandlerFunction_Progress fn) {
{
_progress_callback = fn; _progress_callback = fn;
return *this; return *this;
} }
void UpdaterClass::_reset() void UpdaterClass::_reset() {
{
if (_buffer) if (_buffer)
{
delete[] _buffer; delete[] _buffer;
}
_buffer = 0; _buffer = 0;
_bufferLen = 0; _bufferLen = 0;
_startAddress = 0; _startAddress = 0;
@ -63,16 +59,13 @@ void UpdaterClass::_reset()
_size = 0; _size = 0;
_command = U_FLASH; _command = U_FLASH;
if (_ledPin != -1) if(_ledPin != -1) {
{
digitalWrite(_ledPin, !_ledOn); // off digitalWrite(_ledPin, !_ledOn); // off
} }
} }
bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
{ if(_size > 0){
if (_size > 0)
{
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.println(F("[begin] already running")); DEBUG_UPDATER.println(F("[begin] already running"));
#endif #endif
@ -88,27 +81,23 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
https://github.com/esp8266/Arduino/issues/1017#issuecomment-200605576 https://github.com/esp8266/Arduino/issues/1017#issuecomment-200605576
*/ */
int boot_mode = (GPI >> 16) & 0xf; int boot_mode = (GPI >> 16) & 0xf;
if (boot_mode == 1) if (boot_mode == 1) {
{
_setError(UPDATE_ERROR_BOOTSTRAP); _setError(UPDATE_ERROR_BOOTSTRAP);
return false; return false;
} }
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
if (command == U_SPIFFS) if (command == U_SPIFFS) {
{
DEBUG_UPDATER.println(F("[begin] Update SPIFFS.")); DEBUG_UPDATER.println(F("[begin] Update SPIFFS."));
} }
#endif #endif
if (size == 0) if(size == 0) {
{
_setError(UPDATE_ERROR_SIZE); _setError(UPDATE_ERROR_SIZE);
return false; return false;
} }
if (!ESP.checkFlashConfig(false)) if(!ESP.checkFlashConfig(false)) {
{
_setError(UPDATE_ERROR_FLASH_CONFIG); _setError(UPDATE_ERROR_FLASH_CONFIG);
return false; return false;
} }
@ -119,8 +108,7 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
wifi_set_sleep_type(NONE_SLEEP_T); wifi_set_sleep_type(NONE_SLEEP_T);
uintptr_t updateStartAddress = 0; uintptr_t updateStartAddress = 0;
if (command == U_FLASH) if (command == U_FLASH) {
{
//size of current sketch rounded to a sector //size of current sketch rounded to a sector
size_t currentSketchSize = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); size_t currentSketchSize = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
//address of the end of the space available for sketch and update //address of the end of the space available for sketch and update
@ -128,7 +116,7 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
//size of the update rounded to a sector //size of the update rounded to a sector
size_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); size_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
//address where we will start writing the update //address where we will start writing the update
updateStartAddress = (updateEndAddress > roundedSize) ? (updateEndAddress - roundedSize) : 0; updateStartAddress = (updateEndAddress > roundedSize)? (updateEndAddress - roundedSize) : 0;
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("[begin] roundedSize: 0x%08zX (%zd)\n"), roundedSize, roundedSize); DEBUG_UPDATER.printf_P(PSTR("[begin] roundedSize: 0x%08zX (%zd)\n"), roundedSize, roundedSize);
@ -137,18 +125,15 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
#endif #endif
//make sure that the size of both sketches is less than the total space (updateEndAddress) //make sure that the size of both sketches is less than the total space (updateEndAddress)
if (updateStartAddress < currentSketchSize) if(updateStartAddress < currentSketchSize) {
{
_setError(UPDATE_ERROR_SPACE); _setError(UPDATE_ERROR_SPACE);
return false; return false;
} }
} }
else if (command == U_SPIFFS) else if (command == U_SPIFFS) {
{
updateStartAddress = (uintptr_t)&_SPIFFS_start - 0x40200000; updateStartAddress = (uintptr_t)&_SPIFFS_start - 0x40200000;
} }
else else {
{
// unknown command // unknown command
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.println(F("[begin] Unknown update command.")); DEBUG_UPDATER.println(F("[begin] Unknown update command."));
@ -160,12 +145,9 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
_startAddress = updateStartAddress; _startAddress = updateStartAddress;
_currentAddress = _startAddress; _currentAddress = _startAddress;
_size = size; _size = size;
if (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE) if (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE) {
{
_bufferSize = FLASH_SECTOR_SIZE; _bufferSize = FLASH_SECTOR_SIZE;
} } else {
else
{
_bufferSize = 256; _bufferSize = 256;
} }
_buffer = new uint8_t[_bufferSize]; _buffer = new uint8_t[_bufferSize];
@ -177,16 +159,14 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn)
DEBUG_UPDATER.printf_P(PSTR("[begin] _size: 0x%08zX (%zd)\n"), _size, _size); DEBUG_UPDATER.printf_P(PSTR("[begin] _size: 0x%08zX (%zd)\n"), _size, _size);
#endif #endif
if (!_verify) if (!_verify) {
{
_md5.begin(); _md5.begin();
} }
return true; return true;
} }
bool UpdaterClass::setMD5(const char * expected_md5) bool UpdaterClass::setMD5(const char * expected_md5){
{ if(strlen(expected_md5) != 32)
if (strlen(expected_md5) != 32)
{ {
return false; return false;
} }
@ -194,18 +174,15 @@ bool UpdaterClass::setMD5(const char * expected_md5)
return true; return true;
} }
bool UpdaterClass::end(bool evenIfRemaining) bool UpdaterClass::end(bool evenIfRemaining){
{ if(_size == 0){
if (_size == 0)
{
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.println(F("no update")); DEBUG_UPDATER.println(F("no update"));
#endif #endif
return false; return false;
} }
if (hasError() || (!isFinished() && !evenIfRemaining)) if(hasError() || (!isFinished() && !evenIfRemaining)){
{
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("premature end: res:%u, pos:%zu/%zu\n"), getError(), progress(), _size); DEBUG_UPDATER.printf_P(PSTR("premature end: res:%u, pos:%zu/%zu\n"), getError(), progress(), _size);
#endif #endif
@ -214,24 +191,20 @@ bool UpdaterClass::end(bool evenIfRemaining)
return false; return false;
} }
if (evenIfRemaining) if(evenIfRemaining) {
{ if(_bufferLen > 0) {
if (_bufferLen > 0)
{
_writeBuffer(); _writeBuffer();
} }
_size = progress(); _size = progress();
} }
uint32_t sigLen = 0; uint32_t sigLen = 0;
if (_verify) if (_verify) {
{
ESP.flashRead(_startAddress + _size - sizeof(uint32_t), &sigLen, sizeof(uint32_t)); ESP.flashRead(_startAddress + _size - sizeof(uint32_t), &sigLen, sizeof(uint32_t));
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("[Updater] sigLen: %d\n"), sigLen); DEBUG_UPDATER.printf_P(PSTR("[Updater] sigLen: %d\n"), sigLen);
#endif #endif
if (sigLen != _verify->length()) if (sigLen != _verify->length()) {
{
_setError(UPDATE_ERROR_SIGN); _setError(UPDATE_ERROR_SIGN);
_reset(); _reset();
return false; return false;
@ -244,8 +217,7 @@ bool UpdaterClass::end(bool evenIfRemaining)
#endif #endif
// Calculate the MD5 and hash using proper size // Calculate the MD5 and hash using proper size
uint8_t buff[128]; uint8_t buff[128];
for (int i = 0; i < binSize; i += sizeof(buff)) for(int i = 0; i < binSize; i += sizeof(buff)) {
{
ESP.flashRead(_startAddress + i, (uint32_t *)buff, sizeof(buff)); ESP.flashRead(_startAddress + i, (uint32_t *)buff, sizeof(buff));
size_t read = std::min((int)sizeof(buff), binSize - i); size_t read = std::min((int)sizeof(buff), binSize - i);
_hash->add(buff, read); _hash->add(buff, read);
@ -254,15 +226,11 @@ bool UpdaterClass::end(bool evenIfRemaining)
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
unsigned char *ret = (unsigned char *)_hash->hash(); unsigned char *ret = (unsigned char *)_hash->hash();
DEBUG_UPDATER.printf_P(PSTR("[Updater] Computed Hash:")); DEBUG_UPDATER.printf_P(PSTR("[Updater] Computed Hash:"));
for (int i = 0; i < _hash->len(); i++) for (int i=0; i<_hash->len(); i++) DEBUG_UPDATER.printf(" %02x", ret[i]);
{
DEBUG_UPDATER.printf(" %02x", ret[i]);
}
DEBUG_UPDATER.printf("\n"); DEBUG_UPDATER.printf("\n");
#endif #endif
uint8_t *sig = (uint8_t*)malloc(sigLen); uint8_t *sig = (uint8_t*)malloc(sigLen);
if (!sig) if (!sig) {
{
_setError(UPDATE_ERROR_SIGN); _setError(UPDATE_ERROR_SIGN);
_reset(); _reset();
return false; return false;
@ -270,14 +238,12 @@ bool UpdaterClass::end(bool evenIfRemaining)
ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen); ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen);
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("[Updater] Received Signature:")); DEBUG_UPDATER.printf_P(PSTR("[Updater] Received Signature:"));
for (size_t i = 0; i < sigLen; i++) for (size_t i=0; i<sigLen; i++) {
{
DEBUG_UPDATER.printf(" %02x", sig[i]); DEBUG_UPDATER.printf(" %02x", sig[i]);
} }
DEBUG_UPDATER.printf("\n"); DEBUG_UPDATER.printf("\n");
#endif #endif
if (!_verify->verify(_hash, (void *)sig, sigLen)) if (!_verify->verify(_hash, (void *)sig, sigLen)) {
{
_setError(UPDATE_ERROR_SIGN); _setError(UPDATE_ERROR_SIGN);
_reset(); _reset();
return false; return false;
@ -285,32 +251,24 @@ bool UpdaterClass::end(bool evenIfRemaining)
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("[Updater] Signature matches\n")); DEBUG_UPDATER.printf_P(PSTR("[Updater] Signature matches\n"));
#endif #endif
} } else if (_target_md5.length()) {
else if (_target_md5.length())
{
_md5.calculate(); _md5.calculate();
if (strcasecmp(_target_md5.c_str(), _md5.toString().c_str())) if (strcasecmp(_target_md5.c_str(), _md5.toString().c_str())) {
{
_setError(UPDATE_ERROR_MD5); _setError(UPDATE_ERROR_MD5);
_reset(); _reset();
return false; return false;
} }
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
else else DEBUG_UPDATER.printf_P(PSTR("MD5 Success: %s\n"), _target_md5.c_str());
{
DEBUG_UPDATER.printf_P(PSTR("MD5 Success: %s\n"), _target_md5.c_str());
}
#endif #endif
} }
if (!_verifyEnd()) if(!_verifyEnd()) {
{
_reset(); _reset();
return false; return false;
} }
if (_command == U_FLASH) if (_command == U_FLASH) {
{
eboot_command ebcmd; eboot_command ebcmd;
ebcmd.action = ACTION_COPY_RAW; ebcmd.action = ACTION_COPY_RAW;
ebcmd.args[0] = _startAddress; ebcmd.args[0] = _startAddress;
@ -321,8 +279,7 @@ bool UpdaterClass::end(bool evenIfRemaining)
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("Staged: address:0x%08X, size:0x%08zX\n"), _startAddress, _size); DEBUG_UPDATER.printf_P(PSTR("Staged: address:0x%08X, size:0x%08zX\n"), _startAddress, _size);
} }
else if (_command == U_SPIFFS) else if (_command == U_SPIFFS) {
{
DEBUG_UPDATER.printf_P(PSTR("SPIFFS: address:0x%08X, size:0x%08zX\n"), _startAddress, _size); DEBUG_UPDATER.printf_P(PSTR("SPIFFS: address:0x%08X, size:0x%08zX\n"), _startAddress, _size);
#endif #endif
} }
@ -331,19 +288,14 @@ bool UpdaterClass::end(bool evenIfRemaining)
return true; return true;
} }
bool UpdaterClass::_writeBuffer() bool UpdaterClass::_writeBuffer(){
{ #define FLASH_MODE_PAGE 0
#define FLASH_MODE_PAGE 0 #define FLASH_MODE_OFFSET 2
#define FLASH_MODE_OFFSET 2
bool eraseResult = true, writeResult = true; bool eraseResult = true, writeResult = true;
if (_currentAddress % FLASH_SECTOR_SIZE == 0) if (_currentAddress % FLASH_SECTOR_SIZE == 0) {
{ if(!_async) yield();
if (!_async) eraseResult = ESP.flashEraseSector(_currentAddress/FLASH_SECTOR_SIZE);
{
yield();
}
eraseResult = ESP.flashEraseSector(_currentAddress / FLASH_SECTOR_SIZE);
} }
// If the flash settings don't match what we already have, modify them. // If the flash settings don't match what we already have, modify them.
@ -352,34 +304,26 @@ bool UpdaterClass::_writeBuffer()
bool modifyFlashMode = false; bool modifyFlashMode = false;
FlashMode_t flashMode = FM_QIO; FlashMode_t flashMode = FM_QIO;
FlashMode_t bufferFlashMode = FM_QIO; FlashMode_t bufferFlashMode = FM_QIO;
if (_currentAddress == _startAddress + FLASH_MODE_PAGE) if (_currentAddress == _startAddress + FLASH_MODE_PAGE) {
{
flashMode = ESP.getFlashChipMode(); flashMode = ESP.getFlashChipMode();
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("Header: 0x%1X %1X %1X %1X\n"), _buffer[0], _buffer[1], _buffer[2], _buffer[3]); DEBUG_UPDATER.printf_P(PSTR("Header: 0x%1X %1X %1X %1X\n"), _buffer[0], _buffer[1], _buffer[2], _buffer[3]);
#endif #endif
bufferFlashMode = ESP.magicFlashChipMode(_buffer[FLASH_MODE_OFFSET]); bufferFlashMode = ESP.magicFlashChipMode(_buffer[FLASH_MODE_OFFSET]);
if (bufferFlashMode != flashMode) if (bufferFlashMode != flashMode) {
{ #ifdef DEBUG_UPDATER
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("Set flash mode from 0x%1X to 0x%1X\n"), bufferFlashMode, flashMode); DEBUG_UPDATER.printf_P(PSTR("Set flash mode from 0x%1X to 0x%1X\n"), bufferFlashMode, flashMode);
#endif #endif
_buffer[FLASH_MODE_OFFSET] = flashMode; _buffer[FLASH_MODE_OFFSET] = flashMode;
modifyFlashMode = true; modifyFlashMode = true;
} }
} }
if (eraseResult) if (eraseResult) {
{ if(!_async) yield();
if (!_async)
{
yield();
}
writeResult = ESP.flashWrite(_currentAddress, (uint32_t*) _buffer, _bufferLen); writeResult = ESP.flashWrite(_currentAddress, (uint32_t*) _buffer, _bufferLen);
} } else { // if erase was unsuccessful
else // if erase was unsuccessful
{
_currentAddress = (_startAddress + _size); _currentAddress = (_startAddress + _size);
_setError(UPDATE_ERROR_ERASE); _setError(UPDATE_ERROR_ERASE);
return false; return false;
@ -387,19 +331,16 @@ bool UpdaterClass::_writeBuffer()
// Restore the old flash mode, if we modified it. // Restore the old flash mode, if we modified it.
// Ensures that the MD5 hash will still match what was sent. // Ensures that the MD5 hash will still match what was sent.
if (modifyFlashMode) if (modifyFlashMode) {
{
_buffer[FLASH_MODE_OFFSET] = bufferFlashMode; _buffer[FLASH_MODE_OFFSET] = bufferFlashMode;
} }
if (!writeResult) if (!writeResult) {
{
_currentAddress = (_startAddress + _size); _currentAddress = (_startAddress + _size);
_setError(UPDATE_ERROR_WRITE); _setError(UPDATE_ERROR_WRITE);
return false; return false;
} }
if (!_verify) if (!_verify) {
{
_md5.add(_buffer, _bufferLen); _md5.add(_buffer, _bufferLen);
} }
_currentAddress += _bufferLen; _currentAddress += _bufferLen;
@ -407,15 +348,11 @@ bool UpdaterClass::_writeBuffer()
return true; return true;
} }
size_t UpdaterClass::write(uint8_t *data, size_t len) size_t UpdaterClass::write(uint8_t *data, size_t len) {
{ if(hasError() || !isRunning())
if (hasError() || !isRunning())
{
return 0; return 0;
}
if (len > remaining()) if(len > remaining()){
{
//len = remaining(); //len = remaining();
//fail instead //fail instead
_setError(UPDATE_ERROR_SPACE); _setError(UPDATE_ERROR_SPACE);
@ -424,72 +361,56 @@ size_t UpdaterClass::write(uint8_t *data, size_t len)
size_t left = len; size_t left = len;
while ((_bufferLen + left) > _bufferSize) while((_bufferLen + left) > _bufferSize) {
{
size_t toBuff = _bufferSize - _bufferLen; size_t toBuff = _bufferSize - _bufferLen;
memcpy(_buffer + _bufferLen, data + (len - left), toBuff); memcpy(_buffer + _bufferLen, data + (len - left), toBuff);
_bufferLen += toBuff; _bufferLen += toBuff;
if (!_writeBuffer()) if(!_writeBuffer()){
{
return len - left; return len - left;
} }
left -= toBuff; left -= toBuff;
if (!_async) if(!_async) yield();
{
yield();
}
} }
//lets see whats left //lets see whats left
memcpy(_buffer + _bufferLen, data + (len - left), left); memcpy(_buffer + _bufferLen, data + (len - left), left);
_bufferLen += left; _bufferLen += left;
if (_bufferLen == remaining()) if(_bufferLen == remaining()){
{
//we are at the end of the update, so should write what's left to flash //we are at the end of the update, so should write what's left to flash
if (!_writeBuffer()) if(!_writeBuffer()){
{
return len - left; return len - left;
} }
} }
return len; return len;
} }
bool UpdaterClass::_verifyHeader(uint8_t data) bool UpdaterClass::_verifyHeader(uint8_t data) {
{ if(_command == U_FLASH) {
if (_command == U_FLASH)
{
// check for valid first magic byte (is always 0xE9) // check for valid first magic byte (is always 0xE9)
if (data != 0xE9) if(data != 0xE9) {
{
_currentAddress = (_startAddress + _size); _currentAddress = (_startAddress + _size);
_setError(UPDATE_ERROR_MAGIC_BYTE); _setError(UPDATE_ERROR_MAGIC_BYTE);
return false; return false;
} }
return true; return true;
} } else if(_command == U_SPIFFS) {
else if (_command == U_SPIFFS)
{
// no check of SPIFFS possible with first byte. // no check of SPIFFS possible with first byte.
return true; return true;
} }
return false; return false;
} }
bool UpdaterClass::_verifyEnd() bool UpdaterClass::_verifyEnd() {
{ if(_command == U_FLASH) {
if (_command == U_FLASH)
{
uint8_t buf[4]; uint8_t buf[4];
if (!ESP.flashRead(_startAddress, (uint32_t *) &buf[0], 4)) if(!ESP.flashRead(_startAddress, (uint32_t *) &buf[0], 4)) {
{
_currentAddress = (_startAddress); _currentAddress = (_startAddress);
_setError(UPDATE_ERROR_READ); _setError(UPDATE_ERROR_READ);
return false; return false;
} }
// check for valid first magic byte // check for valid first magic byte
if (buf[0] != 0xE9) if(buf[0] != 0xE9) {
{
_currentAddress = (_startAddress); _currentAddress = (_startAddress);
_setError(UPDATE_ERROR_MAGIC_BYTE); _setError(UPDATE_ERROR_MAGIC_BYTE);
return false; return false;
@ -498,161 +419,113 @@ bool UpdaterClass::_verifyEnd()
uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4); uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
// check if new bin fits to SPI flash // check if new bin fits to SPI flash
if (bin_flash_size > ESP.getFlashChipRealSize()) if(bin_flash_size > ESP.getFlashChipRealSize()) {
{
_currentAddress = (_startAddress); _currentAddress = (_startAddress);
_setError(UPDATE_ERROR_NEW_FLASH_CONFIG); _setError(UPDATE_ERROR_NEW_FLASH_CONFIG);
return false; return false;
} }
return true; return true;
} } else if(_command == U_SPIFFS) {
else if (_command == U_SPIFFS)
{
// SPIFFS is already over written checks make no sense any more. // SPIFFS is already over written checks make no sense any more.
return true; return true;
} }
return false; return false;
} }
size_t UpdaterClass::writeStream(Stream &data) size_t UpdaterClass::writeStream(Stream &data) {
{
size_t written = 0; size_t written = 0;
size_t toRead = 0; size_t toRead = 0;
if (hasError() || !isRunning()) if(hasError() || !isRunning())
{
return 0; return 0;
}
if (!_verifyHeader(data.peek())) if(!_verifyHeader(data.peek())) {
{
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
printError(DEBUG_UPDATER); printError(DEBUG_UPDATER);
#endif #endif
_reset(); _reset();
return 0; return 0;
} }
if (_progress_callback) if (_progress_callback) {
{
_progress_callback(0, _size); _progress_callback(0, _size);
} }
if (_ledPin != -1) if(_ledPin != -1) {
{
pinMode(_ledPin, OUTPUT); pinMode(_ledPin, OUTPUT);
} }
while (remaining()) while(remaining()) {
{ if(_ledPin != -1) {
if (_ledPin != -1)
{
digitalWrite(_ledPin, _ledOn); // Switch LED on digitalWrite(_ledPin, _ledOn); // Switch LED on
} }
size_t bytesToRead = _bufferSize - _bufferLen; size_t bytesToRead = _bufferSize - _bufferLen;
if (bytesToRead > remaining()) if(bytesToRead > remaining()) {
{
bytesToRead = remaining(); bytesToRead = remaining();
} }
toRead = data.readBytes(_buffer + _bufferLen, bytesToRead); toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
if (toRead == 0) //Timeout if(toRead == 0) { //Timeout
{
delay(100); delay(100);
toRead = data.readBytes(_buffer + _bufferLen, bytesToRead); toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
if (toRead == 0) //Timeout if(toRead == 0) { //Timeout
{
_currentAddress = (_startAddress + _size); _currentAddress = (_startAddress + _size);
_setError(UPDATE_ERROR_STREAM); _setError(UPDATE_ERROR_STREAM);
_reset(); _reset();
return written; return written;
} }
} }
if (_ledPin != -1) if(_ledPin != -1) {
{
digitalWrite(_ledPin, !_ledOn); // Switch LED off digitalWrite(_ledPin, !_ledOn); // Switch LED off
} }
_bufferLen += toRead; _bufferLen += toRead;
if ((_bufferLen == remaining() || _bufferLen == _bufferSize) && !_writeBuffer()) if((_bufferLen == remaining() || _bufferLen == _bufferSize) && !_writeBuffer())
{
return written; return written;
}
written += toRead; written += toRead;
if (_progress_callback) if(_progress_callback) {
{
_progress_callback(progress(), _size); _progress_callback(progress(), _size);
} }
yield(); yield();
} }
if (_progress_callback) if(_progress_callback) {
{
_progress_callback(progress(), _size); _progress_callback(progress(), _size);
} }
return written; return written;
} }
void UpdaterClass::_setError(int error) void UpdaterClass::_setError(int error){
{
_error = error; _error = error;
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
printError(DEBUG_UPDATER); printError(DEBUG_UPDATER);
#endif #endif
} }
void UpdaterClass::printError(Print &out) void UpdaterClass::printError(Print &out){
{
out.printf_P(PSTR("ERROR[%u]: "), _error); out.printf_P(PSTR("ERROR[%u]: "), _error);
if (_error == UPDATE_ERROR_OK) if(_error == UPDATE_ERROR_OK){
{
out.println(F("No Error")); out.println(F("No Error"));
} } else if(_error == UPDATE_ERROR_WRITE){
else if (_error == UPDATE_ERROR_WRITE)
{
out.println(F("Flash Write Failed")); out.println(F("Flash Write Failed"));
} } else if(_error == UPDATE_ERROR_ERASE){
else if (_error == UPDATE_ERROR_ERASE)
{
out.println(F("Flash Erase Failed")); out.println(F("Flash Erase Failed"));
} } else if(_error == UPDATE_ERROR_READ){
else if (_error == UPDATE_ERROR_READ)
{
out.println(F("Flash Read Failed")); out.println(F("Flash Read Failed"));
} } else if(_error == UPDATE_ERROR_SPACE){
else if (_error == UPDATE_ERROR_SPACE)
{
out.println(F("Not Enough Space")); out.println(F("Not Enough Space"));
} } else if(_error == UPDATE_ERROR_SIZE){
else if (_error == UPDATE_ERROR_SIZE)
{
out.println(F("Bad Size Given")); out.println(F("Bad Size Given"));
} } else if(_error == UPDATE_ERROR_STREAM){
else if (_error == UPDATE_ERROR_STREAM)
{
out.println(F("Stream Read Timeout")); out.println(F("Stream Read Timeout"));
} } else if(_error == UPDATE_ERROR_MD5){
else if (_error == UPDATE_ERROR_MD5)
{
out.printf_P(PSTR("MD5 Failed: expected:%s, calculated:%s\n"), _target_md5.c_str(), _md5.toString().c_str()); out.printf_P(PSTR("MD5 Failed: expected:%s, calculated:%s\n"), _target_md5.c_str(), _md5.toString().c_str());
} } else if(_error == UPDATE_ERROR_SIGN){
else if (_error == UPDATE_ERROR_SIGN)
{
out.println(F("Signature verification failed")); out.println(F("Signature verification failed"));
} } else if(_error == UPDATE_ERROR_FLASH_CONFIG){
else if (_error == UPDATE_ERROR_FLASH_CONFIG)
{
out.printf_P(PSTR("Flash config wrong real: %d IDE: %d\n"), ESP.getFlashChipRealSize(), ESP.getFlashChipSize()); out.printf_P(PSTR("Flash config wrong real: %d IDE: %d\n"), ESP.getFlashChipRealSize(), ESP.getFlashChipSize());
} } else if(_error == UPDATE_ERROR_NEW_FLASH_CONFIG){
else if (_error == UPDATE_ERROR_NEW_FLASH_CONFIG)
{
out.printf_P(PSTR("new Flash config wrong real: %d\n"), ESP.getFlashChipRealSize()); out.printf_P(PSTR("new Flash config wrong real: %d\n"), ESP.getFlashChipRealSize());
} } else if(_error == UPDATE_ERROR_MAGIC_BYTE){
else if (_error == UPDATE_ERROR_MAGIC_BYTE)
{
out.println(F("Magic byte is wrong, not 0xE9")); out.println(F("Magic byte is wrong, not 0xE9"));
} } else if (_error == UPDATE_ERROR_BOOTSTRAP){
else if (_error == UPDATE_ERROR_BOOTSTRAP)
{
out.println(F("Invalid bootstrapping state, reset ESP8266 before updating")); out.println(F("Invalid bootstrapping state, reset ESP8266 before updating"));
} } else {
else
{
out.println(F("UNKNOWN")); out.println(F("UNKNOWN"));
} }
} }

View File

@ -31,9 +31,8 @@
#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;
@ -42,26 +41,20 @@ public:
}; };
// 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) void installSignature(UpdaterHashClass *hash, UpdaterVerifyClass *verify) { _hash = hash; _verify = 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
@ -72,10 +65,7 @@ public:
/* /*
Run Updater from asynchronous callbacs Run Updater from asynchronous callbacs
*/ */
void runAsync(bool async) void runAsync(bool async){ _async = async; }
{
_async = async;
}
/* /*
Writes a buffer to the flash and increments the address Writes a buffer to the flash and increments the address
@ -117,18 +107,12 @@ public:
/* /*
returns the MD5 String of the sucessfully ended firmware returns the MD5 String of the sucessfully ended firmware
*/ */
String md5String(void) String md5String(void){ return _md5.toString(); }
{
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) void md5(uint8_t * result){ return _md5.getBytes(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
@ -136,38 +120,14 @@ public:
UpdaterClass& onProgress(THandlerFunction_Progress fn); UpdaterClass& onProgress(THandlerFunction_Progress fn);
//Helpers //Helpers
uint8_t getError() uint8_t getError(){ return _error; }
{ void clearError(){ _error = UPDATE_ERROR_OK; }
return _error; bool hasError(){ return _error != UPDATE_ERROR_OK; }
} bool isRunning(){ return _size > 0; }
void clearError() bool isFinished(){ return _currentAddress == (_startAddress + _size); }
{ size_t size(){ return _size; }
_error = UPDATE_ERROR_OK; size_t progress(){ return _currentAddress - _startAddress; }
} size_t remaining(){ return _size - (_currentAddress - _startAddress); }
bool hasError()
{
return _error != UPDATE_ERROR_OK;
}
bool isRunning()
{
return _size > 0;
}
bool isFinished()
{
return _currentAddress == (_startAddress + _size);
}
size_t size()
{
return _size;
}
size_t progress()
{
return _currentAddress - _startAddress;
}
size_t remaining()
{
return _size - (_currentAddress - _startAddress);
}
/* /*
Template to write from objects that expose Template to write from objects that expose
@ -176,56 +136,42 @@ public:
writes only what is available writes only what is available
*/ */
template<typename T> template<typename T>
size_t write(T &data) size_t write(T &data){
{
size_t written = 0; size_t written = 0;
if (hasError() || !isRunning()) if (hasError() || !isRunning())
{
return 0; return 0;
}
size_t available = data.available(); size_t available = data.available();
while (available) while(available) {
{ if(_bufferLen + available > remaining()){
if (_bufferLen + available > remaining())
{
available = remaining() - _bufferLen; available = remaining() - _bufferLen;
} }
if (_bufferLen + available > _bufferSize) if(_bufferLen + available > _bufferSize) {
{
size_t toBuff = _bufferSize - _bufferLen; size_t toBuff = _bufferSize - _bufferLen;
data.read(_buffer + _bufferLen, toBuff); data.read(_buffer + _bufferLen, toBuff);
_bufferLen += toBuff; _bufferLen += toBuff;
if (!_writeBuffer()) if(!_writeBuffer())
{
return written; return written;
}
written += toBuff; written += toBuff;
} } else {
else
{
data.read(_buffer + _bufferLen, available); data.read(_buffer + _bufferLen, available);
_bufferLen += available; _bufferLen += available;
written += available; written += available;
if (_bufferLen == remaining()) if(_bufferLen == remaining()) {
{ if(!_writeBuffer()) {
if (!_writeBuffer())
{
return written; return written;
} }
} }
} }
if (remaining() == 0) if(remaining() == 0)
{
return written; return written;
}
delay(1); delay(1);
available = data.available(); available = data.available();
} }
return written; return written;
} }
private: private:
void _reset(); void _reset();
bool _writeBuffer(); bool _writeBuffer();

View File

@ -15,7 +15,7 @@
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
@ -46,93 +46,79 @@ 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);
} }
@ -142,14 +128,12 @@ inline int toAscii(int c)
// 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);
} }

View File

@ -21,7 +21,7 @@
Boston, MA 02111-1307 USA Boston, MA 02111-1307 USA
$Id$ $Id$
*/ */
extern "C" { extern "C" {
#include <stdlib.h> #include <stdlib.h>
@ -30,19 +30,15 @@ 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
@ -50,51 +46,41 @@ 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

View File

@ -17,7 +17,7 @@
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,17 +39,15 @@ 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 // use a function pointer to allow for "if (s)" without the
// complications of an operator bool(). for more information, see: // complications of an operator bool(). for more information, see:
// http://www.artima.com/cppsource/safebool.html // http://www.artima.com/cppsource/safebool.html
typedef void (String::*StringIfHelperType)() const; typedef void (String::*StringIfHelperType)() const;
void StringIfHelper() 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
@ -77,14 +75,10 @@ public:
// 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()) {
if (buffer())
{
return len(); return len();
} } else {
else
{
return 0; return 0;
} }
} }
@ -119,58 +113,47 @@ public:
// 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); concat(rhs);
return (*this); return (*this);
} }
String & operator +=(const char *cstr) String & operator +=(const char *cstr) {
{
concat(cstr); concat(cstr);
return (*this); return (*this);
} }
String & operator +=(char c) String & operator +=(char c) {
{
concat(c); concat(c);
return (*this); return (*this);
} }
String & operator +=(unsigned char num) String & operator +=(unsigned char num) {
{
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator +=(int num) String & operator +=(int num) {
{
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator +=(unsigned int num) String & operator +=(unsigned int num) {
{
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator +=(long num) String & operator +=(long num) {
{
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator +=(unsigned long num) String & operator +=(unsigned long num) {
{
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator +=(float num) String & operator +=(float num) {
{
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator +=(double num) String & operator +=(double num) {
{
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator += (const __FlashStringHelper *str) String & operator += (const __FlashStringHelper *str){
{
concat(str); concat(str);
return (*this); return (*this);
} }
@ -188,27 +171,22 @@ public:
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; int compareTo(const String &s) const;
unsigned char equals(const String &s) const; unsigned char equals(const String &s) const;
unsigned char equals(const char *cstr) const; unsigned char equals(const char *cstr) const;
unsigned char operator ==(const String &rhs) const unsigned char operator ==(const String &rhs) const {
{
return equals(rhs); return equals(rhs);
} }
unsigned char operator ==(const char *cstr) const unsigned char operator ==(const char *cstr) const {
{
return equals(cstr); return equals(cstr);
} }
unsigned char operator !=(const String &rhs) const unsigned char operator !=(const String &rhs) const {
{
return !equals(rhs); return !equals(rhs);
} }
unsigned char operator !=(const char *cstr) const unsigned char operator !=(const char *cstr) const {
{
return !equals(cstr); return !equals(cstr);
} }
unsigned char operator <(const String &rhs) const; unsigned char operator <(const String &rhs) const;
@ -227,30 +205,14 @@ public:
char operator [](unsigned int index) const; char operator [](unsigned int index) const;
char& operator [](unsigned int index); char& operator [](unsigned int index);
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const; void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const;
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const {
{
getBytes((unsigned char *) buf, bufsize, index); getBytes((unsigned char *) buf, bufsize, index);
} }
const char* c_str() const const char* c_str() const { return buffer(); }
{ char* begin() { return wbuffer(); }
return buffer(); char* end() { return wbuffer() + length(); }
} const char* begin() const { return c_str(); }
char* begin() const char* end() const { return c_str() + length(); }
{
return wbuffer();
}
char* end()
{
return wbuffer() + length();
}
const char* begin() const
{
return c_str();
}
const char* end() const
{
return c_str() + length();
}
// search // search
int indexOf(char ch) const; int indexOf(char ch) const;
@ -261,8 +223,7 @@ public:
int lastIndexOf(char ch, unsigned int fromIndex) const; int lastIndexOf(char ch, unsigned int fromIndex) const;
int lastIndexOf(const String &str) const; int lastIndexOf(const String &str) const;
int lastIndexOf(const String &str, unsigned int fromIndex) const; int lastIndexOf(const String &str, unsigned int fromIndex) const;
String substring(unsigned int beginIndex) const String substring(unsigned int beginIndex) const {
{
return substring(beginIndex, len()); return substring(beginIndex, len());
} }
; ;
@ -282,10 +243,9 @@ public:
float toFloat(void) const; float toFloat(void) const;
double toDouble(void) const; double toDouble(void) const;
protected: protected:
// Contains the string info when we're not in SSO mode // Contains the string info when we're not in SSO mode
struct _ptr struct _ptr {
{
char * buff; char * buff;
uint16_t cap; uint16_t cap;
uint16_t len; uint16_t len;
@ -296,60 +256,23 @@ protected:
// This allows strings up up to 12 (11 + \0 termination) without any extra space. // 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 { 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 enum { CAPACITY_MAX = 65535 }; // If size of capacity changed, be sure to update this enum
union union {
{
struct _ptr ptr; struct _ptr ptr;
char sso_buf[SSOSIZE]; char sso_buf[SSOSIZE];
}; };
// Accessor functions // Accessor functions
inline bool sso() const inline bool sso() const { return sso_buf[SSOSIZE - 1] == 0; }
{ inline unsigned int len() const { return sso() ? strlen(sso_buf) : ptr.len; }
return sso_buf[SSOSIZE - 1] == 0; inline unsigned int capacity() const { return sso() ? SSOSIZE - 1 : ptr.cap; }
} inline void setSSO(bool sso) { sso_buf[SSOSIZE - 1] = sso ? 0x00 : 0xff; }
inline unsigned int len() const inline void setLen(int len) { if (!sso()) ptr.len = len; }
{ inline void setCapacity(int cap) { if (!sso()) ptr.cap = cap; }
return sso() ? strlen(sso_buf) : ptr.len; inline void setBuffer(char *buff) { if (!sso()) ptr.buff = buff; }
}
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 // Buffer accessor functions
inline const char *buffer() const 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
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: protected:
void init(void); void init(void);
void invalidate(void); void invalidate(void);
unsigned char changeBuffer(unsigned int maxStrLen); unsigned char changeBuffer(unsigned int maxStrLen);
@ -363,48 +286,37 @@ protected:
#endif #endif
}; };
class StringSumHelper: public String class StringSumHelper: public String {
{ public:
public:
StringSumHelper(const String &s) : StringSumHelper(const String &s) :
String(s) String(s) {
{
} }
StringSumHelper(const char *p) : StringSumHelper(const char *p) :
String(p) String(p) {
{
} }
StringSumHelper(char c) : StringSumHelper(char c) :
String(c) String(c) {
{
} }
StringSumHelper(unsigned char num) : StringSumHelper(unsigned char num) :
String(num) String(num) {
{
} }
StringSumHelper(int num) : StringSumHelper(int num) :
String(num) String(num) {
{
} }
StringSumHelper(unsigned int num) : StringSumHelper(unsigned int num) :
String(num) String(num) {
{
} }
StringSumHelper(long num) : StringSumHelper(long num) :
String(num) String(num) {
{
} }
StringSumHelper(unsigned long num) : StringSumHelper(unsigned long num) :
String(num) String(num) {
{
} }
StringSumHelper(float num) : StringSumHelper(float num) :
String(num) String(num) {
{
} }
StringSumHelper(double num) : StringSumHelper(double num) :
String(num) String(num) {
{
} }
}; };

View File

@ -14,7 +14,7 @@
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,8 +41,7 @@ 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;
@ -50,8 +49,7 @@ 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;
} }

View File

@ -1,26 +1,26 @@
/** /**
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" {
@ -30,21 +30,19 @@ extern "C" {
#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 // base64 needs more size then the source data, use cencode.h macros
size_t size = ((doNewLines ? base64_encode_expected_len(length) size_t size = ((doNewLines ? base64_encode_expected_len(length)
: base64_encode_expected_len_nonewlines(length)) + 1); : base64_encode_expected_len_nonewlines(length)) + 1);
char * buffer = (char *) malloc(size); char * buffer = (char *) malloc(size);
if (buffer) if(buffer) {
{
base64_encodestate _state; base64_encodestate _state;
if (doNewLines) if(doNewLines)
{ {
base64_init_encodestate(&_state); base64_init_encodestate(&_state);
} }
@ -63,12 +61,11 @@ String base64::encode(uint8_t * data, size_t length, bool doNewLines)
} }
/** /**
convert input data to base64 * convert input data to base64
@param text String * @param text String
@return String * @return String
*/ */
String base64::encode(String text, bool doNewLines) String base64::encode(String text, bool doNewLines) {
{
return base64::encode((uint8_t *) text.c_str(), text.length(), doNewLines); return base64::encode((uint8_t *) text.c_str(), text.length(), doNewLines);
} }

View File

@ -1,39 +1,38 @@
/** /**
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:
public:
// NOTE: The default behaviour of backend (lib64) // NOTE: The default behaviour of backend (lib64)
// is to add a newline every 72 (encoded) characters output. // is to add a newline every 72 (encoded) characters output.
// This may 'break' longer uris and json variables // This may 'break' longer uris and json variables
static String encode(uint8_t * data, size_t length, bool doNewLines = true); static String encode(uint8_t * data, size_t length, bool doNewLines = true);
static String encode(String text, bool doNewLines = true); static String encode(String text, bool doNewLines = true);
private: private:
}; };

View File

@ -15,7 +15,7 @@
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

View File

@ -16,48 +16,41 @@
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 "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));
} }
@ -73,47 +66,37 @@ 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;
@ -124,25 +107,20 @@ 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;
@ -154,25 +132,20 @@ 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;
@ -184,23 +157,19 @@ 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;

View File

@ -16,7 +16,7 @@
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 __cbuf_h #ifndef __cbuf_h
#define __cbuf_h #define __cbuf_h
@ -25,9 +25,8 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
class cbuf class cbuf {
{ public:
public:
cbuf(size_t size); cbuf(size_t size);
~cbuf(); ~cbuf();
@ -38,13 +37,11 @@ public:
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;
} }
@ -62,9 +59,8 @@ public:
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;
} }

View File

@ -16,7 +16,7 @@
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,8 +31,7 @@
extern "C" { extern "C" {
#endif #endif
typedef struct cont_ typedef struct cont_ {
{
void (*pc_ret)(void); void (*pc_ret)(void);
unsigned* sp_ret; unsigned* sp_ret;

View File

@ -16,7 +16,7 @@
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,8 +27,7 @@ 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)); memset(cont, 0, sizeof(cont_t));
cont->stack_guard1 = CONT_STACKGUARD; cont->stack_guard1 = CONT_STACKGUARD;
@ -37,54 +36,48 @@ extern "C" {
cont->struct_start = (unsigned*) cont; cont->struct_start = (unsigned*) cont;
// fill stack with magic values to check high water mark // fill stack with magic values to check high water mark
for (int pos = 0; pos < (int)(sizeof(cont->stack) / 4); pos++) for(int pos = 0; pos < (int)(sizeof(cont->stack) / 4); pos++)
{ {
cont->stack[pos] = CONT_STACKGUARD; 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;
if (cont->stack_guard1 != CONT_STACKGUARD || cont->stack_guard2 != CONT_STACKGUARD)
{
return 1;
}
return 0; return 0;
} }
// No need for this to be in IRAM, not expected to be IRQ called // No need for this to be in IRAM, not expected to be IRQ called
int cont_get_free_stack(cont_t* cont) int cont_get_free_stack(cont_t* cont) {
{
uint32_t *head = cont->stack; uint32_t *head = cont->stack;
int freeWords = 0; int freeWords = 0;
while (*head == CONT_STACKGUARD) while(*head == CONT_STACKGUARD)
{ {
head++; head++;
freeWords++; freeWords++;
} }
return freeWords * 4; return freeWords * 4;
} }
bool ICACHE_RAM_ATTR cont_can_yield(cont_t* cont) bool ICACHE_RAM_ATTR cont_can_yield(cont_t* cont) {
{
return !ETS_INTR_WITHINISR() && return !ETS_INTR_WITHINISR() &&
cont->pc_ret != 0 && cont->pc_yield == 0; cont->pc_ret != 0 && cont->pc_yield == 0;
} }
// No need for this to be in IRAM, not expected to be IRQ called // No need for this to be in IRAM, not expected to be IRQ called
void cont_repaint_stack(cont_t *cont) void cont_repaint_stack(cont_t *cont)
{ {
register uint32_t *sp asm("a1"); register uint32_t *sp asm("a1");
// Ensure 64 bytes adjacent to the current SP don't get touched to endure // Ensure 64 bytes adjacent to the current SP don't get touched to endure
// we don't accidentally trounce over locals or IRQ temps. // we don't accidentally trounce over locals or IRQ temps.
// Fill stack with magic values // Fill stack with magic values
for (uint32_t *pos = sp - 16; pos >= &cont->stack[0]; pos--) for ( uint32_t *pos = sp - 16; pos >= &cont->stack[0]; pos-- )
{ {
*pos = CONT_STACKGUARD; *pos = CONT_STACKGUARD;
} }
} }
}; };

View File

@ -1,22 +1,22 @@
/* /*
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
*
*/ */
} }
@ -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)
{ {

View File

@ -17,7 +17,7 @@
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 <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
@ -25,74 +25,67 @@
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++; c = *data++;
for (i = 0x80; i > 0; i >>= 1) for (i = 0x80; i > 0; i >>= 1) {
{
bit = crc & 0x80000000; bit = crc & 0x80000000;
if (c & i) if (c & i) {
{
bit = !bit; bit = !bit;
} }
crc <<= 1; crc <<= 1;
if (bit) if (bit) {
{
crc ^= 0x04c11db7; crc ^= 0x04c11db7;
} }
} }
} }
return crc; return crc;
} }
static uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd) static uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd)
{ {
return crc_update(0xffffffff, (const uint8_t*) cmd, return crc_update(0xffffffff, (const uint8_t*) cmd,
offsetof(struct eboot_command, crc32)); offsetof(struct eboot_command, crc32));
} }
int eboot_command_read(struct eboot_command* cmd) int eboot_command_read(struct eboot_command* cmd)
{ {
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t); const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
uint32_t* dst = (uint32_t *) cmd; uint32_t* dst = (uint32_t *) cmd;
for (uint32_t i = 0; i < dw_count; ++i) for (uint32_t i = 0; i < dw_count; ++i) {
{
dst[i] = RTC_MEM[i]; dst[i] = RTC_MEM[i];
} }
uint32_t crc32 = eboot_command_calculate_crc32(cmd); uint32_t crc32 = eboot_command_calculate_crc32(cmd);
if ((cmd->magic & EBOOT_MAGIC_MASK) != EBOOT_MAGIC || if ((cmd->magic & EBOOT_MAGIC_MASK) != EBOOT_MAGIC ||
cmd->crc32 != crc32) cmd->crc32 != crc32) {
{
return 1; return 1;
} }
return 0; return 0;
} }
void eboot_command_write(struct eboot_command* cmd) void eboot_command_write(struct eboot_command* cmd)
{ {
cmd->magic = EBOOT_MAGIC; cmd->magic = EBOOT_MAGIC;
cmd->crc32 = eboot_command_calculate_crc32(cmd); cmd->crc32 = eboot_command_calculate_crc32(cmd);
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t); const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
const uint32_t* src = (const uint32_t *) cmd; const uint32_t* src = (const uint32_t *) cmd;
for (uint32_t i = 0; i < dw_count; ++i) for (uint32_t i = 0; i < dw_count; ++i) {
{
RTC_MEM[i] = src[i]; RTC_MEM[i] = src[i];
} }
} }
void eboot_command_clear() void eboot_command_clear()
{ {
RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0; RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0;
RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0; RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0;
} }
}; };

View File

@ -18,7 +18,7 @@
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

View File

@ -17,7 +17,7 @@
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 <stddef.h> #include <stddef.h>
@ -27,10 +27,9 @@
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;
} }
@ -39,35 +38,29 @@ extern "C" {
uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE; uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
const uint32_t end = current_sector + sector_count; const uint32_t end = current_sector + sector_count;
for (; current_sector < end && (current_sector & (sectors_per_block - 1)); for (; current_sector < end && (current_sector & (sectors_per_block-1));
++current_sector, --sector_count) ++current_sector, --sector_count) {
{ if (SPIEraseSector(current_sector)) {
if (SPIEraseSector(current_sector))
{
return 2; return 2;
} }
} }
for (; current_sector + sectors_per_block <= end; for (;current_sector + sectors_per_block <= end;
current_sector += sectors_per_block, current_sector += sectors_per_block,
sector_count -= sectors_per_block) sector_count -= sectors_per_block) {
{ if (SPIEraseBlock(current_sector / sectors_per_block)) {
if (SPIEraseBlock(current_sector / sectors_per_block))
{
return 3; return 3;
} }
} }
for (; current_sector < end; for (; current_sector < end;
++current_sector, --sector_count) ++current_sector, --sector_count) {
{ if (SPIEraseSector(current_sector)) {
if (SPIEraseSector(current_sector))
{
return 4; return 4;
} }
} }
return 0; return 0;
} }
}; };

View File

@ -31,19 +31,18 @@ extern "C" {
#define SLC_BUF_CNT (8) // Number of buffers in the I2S circular buffer #define SLC_BUF_CNT (8) // Number of buffers in the I2S circular buffer
#define SLC_BUF_LEN (64) // Length of one buffer, in 32-bit words. #define SLC_BUF_LEN (64) // Length of one buffer, in 32-bit words.
// We use a queue to keep track of the DMA buffers that are empty. The ISR // We use a queue to keep track of the DMA buffers that are empty. The ISR
// will push buffers to the back of the queue, the I2S transmitter will pull // will push buffers to the back of the queue, the I2S transmitter will pull
// them from the front and fill them. For ease, the queue will contain // them from the front and fill them. For ease, the queue will contain
// *pointers* to the DMA buffers, not the data itself. The queue depth is // *pointers* to the DMA buffers, not the data itself. The queue depth is
// one smaller than the amount of buffers we have, because there's always a // one smaller than the amount of buffers we have, because there's always a
// buffer that is being used by the DMA subsystem *right now* and we don't // buffer that is being used by the DMA subsystem *right now* and we don't
// want to be able to write to that simultaneously. // want to be able to write to that simultaneously.
// For RX, it's a little different. The buffers in i2s_slc_queue are // For RX, it's a little different. The buffers in i2s_slc_queue are
// placed onto the list when they're filled by DMA // placed onto the list when they're filled by DMA
typedef struct slc_queue_item typedef struct slc_queue_item {
{
uint32_t blocksize : 12; uint32_t blocksize : 12;
uint32_t datalen : 12; uint32_t datalen : 12;
uint32_t unused : 5; uint32_t unused : 5;
@ -52,32 +51,31 @@ extern "C" {
volatile uint32_t owner : 1; // DMA can change this value volatile uint32_t owner : 1; // DMA can change this value
uint32_t * buf_ptr; uint32_t * buf_ptr;
struct slc_queue_item * next_link_ptr; struct slc_queue_item * next_link_ptr;
} slc_queue_item_t; } slc_queue_item_t;
typedef struct i2s_state typedef struct i2s_state {
{
uint32_t * slc_queue[SLC_BUF_CNT]; uint32_t * slc_queue[SLC_BUF_CNT];
volatile uint8_t slc_queue_len; volatile uint8_t slc_queue_len;
uint32_t * slc_buf_pntr[SLC_BUF_CNT]; // Pointer to the I2S DMA buffer data uint32_t * slc_buf_pntr[SLC_BUF_CNT]; // Pointer to the I2S DMA buffer data
slc_queue_item_t slc_items[SLC_BUF_CNT]; // I2S DMA buffer descriptors slc_queue_item_t slc_items[SLC_BUF_CNT]; // I2S DMA buffer descriptors
uint32_t * curr_slc_buf; // Current buffer for writing uint32_t * curr_slc_buf; // Current buffer for writing
uint32_t curr_slc_buf_pos; // Position in the current buffer uint32_t curr_slc_buf_pos; // Position in the current buffer
void (*callback)(void); void (*callback) (void);
// Callback function should be defined as 'void ICACHE_RAM_ATTR function_name()', // Callback function should be defined as 'void ICACHE_RAM_ATTR function_name()',
// and be placed in IRAM for faster execution. Avoid long computational tasks in this // and be placed in IRAM for faster execution. Avoid long computational tasks in this
// function, use it to set flags and process later. // function, use it to set flags and process later.
} i2s_state_t; } i2s_state_t;
// RX = I2S receive (i.e. microphone), TX = I2S transmit (i.e. DAC) // RX = I2S receive (i.e. microphone), TX = I2S transmit (i.e. DAC)
static i2s_state_t *rx = NULL; static i2s_state_t *rx = NULL;
static i2s_state_t *tx = NULL; static i2s_state_t *tx = NULL;
// Last I2S sample rate requested // Last I2S sample rate requested
static uint32_t _i2s_sample_rate; static uint32_t _i2s_sample_rate;
// IOs used for I2S. Not defined in i2s.h, unfortunately. // IOs used for I2S. Not defined in i2s.h, unfortunately.
// Note these are internal GPIO numbers and not pins on an // Note these are internal GPIO numbers and not pins on an
// Arduino board. Users need to verify their particular wiring. // Arduino board. Users need to verify their particular wiring.
#define I2SO_DATA 3 #define I2SO_DATA 3
#define I2SO_BCK 15 #define I2SO_BCK 15
#define I2SO_WS 2 #define I2SO_WS 2
@ -85,150 +83,119 @@ extern "C" {
#define I2SI_BCK 13 #define I2SI_BCK 13
#define I2SI_WS 14 #define I2SI_WS 14
static bool _i2s_is_full(const i2s_state_t *ch) static bool _i2s_is_full(const i2s_state_t *ch) {
{ if (!ch) {
if (!ch)
{
return false; return false;
} }
return (ch->curr_slc_buf_pos == SLC_BUF_LEN || ch->curr_slc_buf == NULL) && (ch->slc_queue_len == 0); return (ch->curr_slc_buf_pos==SLC_BUF_LEN || ch->curr_slc_buf==NULL) && (ch->slc_queue_len == 0);
} }
bool i2s_is_full() bool i2s_is_full() {
{ return _i2s_is_full( tx );
return _i2s_is_full(tx); }
}
bool i2s_rx_is_full() bool i2s_rx_is_full() {
{ return _i2s_is_full( rx );
return _i2s_is_full(rx); }
}
static bool _i2s_is_empty(const i2s_state_t *ch) static bool _i2s_is_empty(const i2s_state_t *ch) {
{ if (!ch) {
if (!ch)
{
return false; return false;
} }
return (ch->slc_queue_len >= SLC_BUF_CNT - 1); return (ch->slc_queue_len >= SLC_BUF_CNT-1);
} }
bool i2s_is_empty() bool i2s_is_empty() {
{ return _i2s_is_empty( tx );
return _i2s_is_empty(tx); }
}
bool i2s_rx_is_empty() bool i2s_rx_is_empty() {
{ return _i2s_is_empty( rx );
return _i2s_is_empty(rx); }
}
static uint16_t _i2s_available(const i2s_state_t *ch) static uint16_t _i2s_available(const i2s_state_t *ch) {
{ if (!ch) {
if (!ch)
{
return 0; return 0;
} }
return (SLC_BUF_CNT - ch->slc_queue_len) * SLC_BUF_LEN; return (SLC_BUF_CNT - ch->slc_queue_len) * SLC_BUF_LEN;
} }
uint16_t i2s_available() uint16_t i2s_available(){
{ return _i2s_available( tx );
return _i2s_available(tx); }
}
uint16_t i2s_rx_available() uint16_t i2s_rx_available(){
{ return _i2s_available( rx );
return _i2s_available(rx); }
}
// Pop the top off of the queue and return it // Pop the top off of the queue and return it
static uint32_t * ICACHE_RAM_ATTR i2s_slc_queue_next_item(i2s_state_t *ch) static uint32_t * ICACHE_RAM_ATTR i2s_slc_queue_next_item(i2s_state_t *ch) {
{
uint8_t i; uint8_t i;
uint32_t *item = ch->slc_queue[0]; uint32_t *item = ch->slc_queue[0];
ch->slc_queue_len--; ch->slc_queue_len--;
for (i = 0; i < ch->slc_queue_len; i++) for ( i = 0; i < ch->slc_queue_len; i++) {
{ ch->slc_queue[i] = ch->slc_queue[i+1];
ch->slc_queue[i] = ch->slc_queue[i + 1];
} }
return item; return item;
} }
// Append an item to the end of the queue from receive // Append an item to the end of the queue from receive
static void ICACHE_RAM_ATTR i2s_slc_queue_append_item(i2s_state_t *ch, uint32_t *item) static void ICACHE_RAM_ATTR i2s_slc_queue_append_item(i2s_state_t *ch, uint32_t *item) {
{
// Shift everything up, except for the one corresponding to this item // Shift everything up, except for the one corresponding to this item
for (int i = 0, dest = 0; i < ch->slc_queue_len; i++) for (int i=0, dest=0; i < ch->slc_queue_len; i++) {
{ if (ch->slc_queue[i] != item) {
if (ch->slc_queue[i] != item)
{
ch->slc_queue[dest++] = ch->slc_queue[i]; ch->slc_queue[dest++] = ch->slc_queue[i];
} }
} }
if (ch->slc_queue_len < SLC_BUF_CNT - 1) if (ch->slc_queue_len < SLC_BUF_CNT - 1) {
{
ch->slc_queue[ch->slc_queue_len++] = item; ch->slc_queue[ch->slc_queue_len++] = item;
} } else {
else
{
ch->slc_queue[ch->slc_queue_len] = item; ch->slc_queue[ch->slc_queue_len] = item;
} }
} }
static void ICACHE_RAM_ATTR i2s_slc_isr(void) static void ICACHE_RAM_ATTR i2s_slc_isr(void) {
{
ETS_SLC_INTR_DISABLE(); ETS_SLC_INTR_DISABLE();
uint32_t slc_intr_status = SLCIS; uint32_t slc_intr_status = SLCIS;
SLCIC = 0xFFFFFFFF; SLCIC = 0xFFFFFFFF;
if (slc_intr_status & SLCIRXEOF) if (slc_intr_status & SLCIRXEOF) {
{
slc_queue_item_t *finished_item = (slc_queue_item_t *)SLCRXEDA; slc_queue_item_t *finished_item = (slc_queue_item_t *)SLCRXEDA;
// Zero the buffer so it is mute in case of underflow // Zero the buffer so it is mute in case of underflow
ets_memset((void *)finished_item->buf_ptr, 0x00, SLC_BUF_LEN * 4); ets_memset((void *)finished_item->buf_ptr, 0x00, SLC_BUF_LEN * 4);
if (tx->slc_queue_len >= SLC_BUF_CNT - 1) if (tx->slc_queue_len >= SLC_BUF_CNT-1) {
{
// All buffers are empty. This means we have an underflow // All buffers are empty. This means we have an underflow
i2s_slc_queue_next_item(tx); // Free space for finished_item i2s_slc_queue_next_item(tx); // Free space for finished_item
} }
tx->slc_queue[tx->slc_queue_len++] = finished_item->buf_ptr; tx->slc_queue[tx->slc_queue_len++] = finished_item->buf_ptr;
if (tx->callback) if (tx->callback) {
{
tx->callback(); tx->callback();
} }
} }
if (slc_intr_status & SLCITXEOF) if (slc_intr_status & SLCITXEOF) {
{
slc_queue_item_t *finished_item = (slc_queue_item_t *)SLCTXEDA; slc_queue_item_t *finished_item = (slc_queue_item_t *)SLCTXEDA;
// Set owner back to 1 (SW) or else RX stops. TX has no such restriction. // Set owner back to 1 (SW) or else RX stops. TX has no such restriction.
finished_item->owner = 1; finished_item->owner = 1;
i2s_slc_queue_append_item(rx, finished_item->buf_ptr); i2s_slc_queue_append_item(rx, finished_item->buf_ptr);
if (rx->callback) if (rx->callback) {
{
rx->callback(); rx->callback();
} }
} }
ETS_SLC_INTR_ENABLE(); ETS_SLC_INTR_ENABLE();
} }
void i2s_set_callback(void (*callback)(void)) void i2s_set_callback(void (*callback) (void)) {
{
tx->callback = callback; tx->callback = callback;
} }
void i2s_rx_set_callback(void (*callback)(void)) void i2s_rx_set_callback(void (*callback) (void)) {
{
rx->callback = callback; rx->callback = callback;
} }
static bool _alloc_channel(i2s_state_t *ch) static bool _alloc_channel(i2s_state_t *ch) {
{
ch->slc_queue_len = 0; ch->slc_queue_len = 0;
for (int x = 0; x < SLC_BUF_CNT; x++) for (int x=0; x<SLC_BUF_CNT; x++) {
{
ch->slc_buf_pntr[x] = (uint32_t *)malloc(SLC_BUF_LEN * sizeof(ch->slc_buf_pntr[0][0])); ch->slc_buf_pntr[x] = (uint32_t *)malloc(SLC_BUF_LEN * sizeof(ch->slc_buf_pntr[0][0]));
if (!ch->slc_buf_pntr[x]) if (!ch->slc_buf_pntr[x]) {
{
// OOM, the upper layer will free up any partially allocated channels. // OOM, the upper layer will free up any partially allocated channels.
return false; return false;
} }
@ -241,24 +208,19 @@ extern "C" {
ch->slc_items[x].datalen = SLC_BUF_LEN * 4; ch->slc_items[x].datalen = SLC_BUF_LEN * 4;
ch->slc_items[x].blocksize = SLC_BUF_LEN * 4; ch->slc_items[x].blocksize = SLC_BUF_LEN * 4;
ch->slc_items[x].buf_ptr = (uint32_t*)&ch->slc_buf_pntr[x][0]; ch->slc_items[x].buf_ptr = (uint32_t*)&ch->slc_buf_pntr[x][0];
ch->slc_items[x].next_link_ptr = (x < (SLC_BUF_CNT - 1)) ? (&ch->slc_items[x + 1]) : (&ch->slc_items[0]); ch->slc_items[x].next_link_ptr = (x<(SLC_BUF_CNT-1))?(&ch->slc_items[x+1]):(&ch->slc_items[0]);
} }
return true; return true;
} }
static bool i2s_slc_begin() static bool i2s_slc_begin() {
{ if (tx) {
if (tx) if (!_alloc_channel(tx)) {
{
if (!_alloc_channel(tx))
{
return false; return false;
} }
} }
if (rx) if (rx) {
{ if (!_alloc_channel(rx)) {
if (!_alloc_channel(rx))
{
return false; return false;
} }
} }
@ -280,87 +242,67 @@ extern "C" {
//an error at us otherwise. Just feed it any random descriptor. //an error at us otherwise. Just feed it any random descriptor.
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
if (!rx) if (!rx) {
{
SLCTXL |= (uint32)&tx->slc_items[1] << SLCTXLA; // Set fake (unused) RX descriptor address SLCTXL |= (uint32)&tx->slc_items[1] << SLCTXLA; // Set fake (unused) RX descriptor address
} } else {
else
{
SLCTXL |= (uint32)&rx->slc_items[0] << SLCTXLA; // Set real RX address SLCTXL |= (uint32)&rx->slc_items[0] << SLCTXLA; // Set real RX address
} }
if (!tx) if (!tx) {
{
SLCRXL |= (uint32)&rx->slc_items[1] << SLCRXLA; // Set fake (unused) TX descriptor address SLCRXL |= (uint32)&rx->slc_items[1] << SLCRXLA; // Set fake (unused) TX descriptor address
} } else {
else
{
SLCRXL |= (uint32)&tx->slc_items[0] << SLCRXLA; // Set real TX address SLCRXL |= (uint32)&tx->slc_items[0] << SLCRXLA; // Set real TX address
} }
ETS_SLC_INTR_ATTACH(i2s_slc_isr, NULL); ETS_SLC_INTR_ATTACH(i2s_slc_isr, NULL);
SLCIE = (tx ? SLCIRXEOF : 0) | (rx ? SLCITXEOF : 0); // Enable appropriate EOF IRQ SLCIE = (tx?SLCIRXEOF:0) | (rx?SLCITXEOF:0); // Enable appropriate EOF IRQ
ETS_SLC_INTR_ENABLE(); ETS_SLC_INTR_ENABLE();
// Start transmission ("TX" DMA always needed to be enabled) // Start transmission ("TX" DMA always needed to be enabled)
SLCTXL |= SLCTXLS; SLCTXL |= SLCTXLS;
if (tx) if (tx) {
{
SLCRXL |= SLCRXLS; SLCRXL |= SLCRXLS;
} }
return true; return true;
} }
static void i2s_slc_end() static void i2s_slc_end(){
{
ETS_SLC_INTR_DISABLE(); ETS_SLC_INTR_DISABLE();
SLCIC = 0xFFFFFFFF; SLCIC = 0xFFFFFFFF;
SLCIE = 0; SLCIE = 0;
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
for (int x = 0; x < SLC_BUF_CNT; x++) for (int x = 0; x<SLC_BUF_CNT; x++) {
{ if (tx) {
if (tx)
{
free(tx->slc_buf_pntr[x]); free(tx->slc_buf_pntr[x]);
tx->slc_buf_pntr[x] = NULL; tx->slc_buf_pntr[x] = NULL;
} }
if (rx) if (rx) {
{
free(rx->slc_buf_pntr[x]); free(rx->slc_buf_pntr[x]);
rx->slc_buf_pntr[x] = NULL; rx->slc_buf_pntr[x] = NULL;
} }
} }
} }
// These routines push a single, 32-bit sample to the I2S buffers. Call at (on average) // These routines push a single, 32-bit sample to the I2S buffers. Call at (on average)
// at least the current sample rate. // at least the current sample rate.
static bool _i2s_write_sample(uint32_t sample, bool nb) static bool _i2s_write_sample(uint32_t sample, bool nb) {
{ if (!tx) {
if (!tx)
{
return false; return false;
} }
if (tx->curr_slc_buf_pos == SLC_BUF_LEN || tx->curr_slc_buf == NULL) if (tx->curr_slc_buf_pos==SLC_BUF_LEN || tx->curr_slc_buf==NULL) {
{ if (tx->slc_queue_len == 0) {
if (tx->slc_queue_len == 0) if (nb) {
{
if (nb)
{
// Don't wait if nonblocking, just notify upper levels // Don't wait if nonblocking, just notify upper levels
return false; return false;
} }
while (1) while (1) {
{ if (tx->slc_queue_len > 0) {
if (tx->slc_queue_len > 0)
{
break; break;
} } else {
else
{
optimistic_yield(10000); optimistic_yield(10000);
} }
} }
@ -368,60 +310,48 @@ extern "C" {
ETS_SLC_INTR_DISABLE(); ETS_SLC_INTR_DISABLE();
tx->curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(tx); tx->curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(tx);
ETS_SLC_INTR_ENABLE(); ETS_SLC_INTR_ENABLE();
tx->curr_slc_buf_pos = 0; tx->curr_slc_buf_pos=0;
} }
tx->curr_slc_buf[tx->curr_slc_buf_pos++] = sample; tx->curr_slc_buf[tx->curr_slc_buf_pos++]=sample;
return true; return true;
} }
bool i2s_write_sample(uint32_t sample) bool i2s_write_sample(uint32_t sample) {
{
return _i2s_write_sample(sample, false); return _i2s_write_sample(sample, false);
} }
bool i2s_write_sample_nb(uint32_t sample) bool i2s_write_sample_nb(uint32_t sample) {
{
return _i2s_write_sample(sample, true); return _i2s_write_sample(sample, true);
} }
bool i2s_write_lr(int16_t left, int16_t right) bool i2s_write_lr(int16_t left, int16_t right){
{
int sample = right & 0xFFFF; int sample = right & 0xFFFF;
sample = sample << 16; sample = sample << 16;
sample |= left & 0xFFFF; sample |= left & 0xFFFF;
return i2s_write_sample(sample); return i2s_write_sample(sample);
} }
// 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.
static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mono, bool nb) static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mono, bool nb) {
{ uint16_t frames_written=0;
uint16_t frames_written = 0;
while (frame_count > 0) while(frame_count>0) {
{
// make sure we have room in the current buffer // make sure we have room in the current buffer
if (tx->curr_slc_buf_pos == SLC_BUF_LEN || tx->curr_slc_buf == NULL) if (tx->curr_slc_buf_pos==SLC_BUF_LEN || tx->curr_slc_buf==NULL) {
{
// no room in the current buffer? if there are no buffers available then exit // no room in the current buffer? if there are no buffers available then exit
if (tx->slc_queue_len == 0) if (tx->slc_queue_len == 0)
{ {
if (nb) if (nb) {
{
// if nonblocking just return the number of frames written so far // if nonblocking just return the number of frames written so far
break; break;
} }
else else {
{ while (1) {
while (1) if (tx->slc_queue_len > 0) {
{
if (tx->slc_queue_len > 0)
{
break; break;
} } else {
else
{
optimistic_yield(10000); optimistic_yield(10000);
} }
} }
@ -432,7 +362,7 @@ extern "C" {
ETS_SLC_INTR_DISABLE(); ETS_SLC_INTR_DISABLE();
tx->curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(tx); tx->curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(tx);
ETS_SLC_INTR_ENABLE(); ETS_SLC_INTR_ENABLE();
tx->curr_slc_buf_pos = 0; tx->curr_slc_buf_pos=0;
} }
//space available in the current buffer //space available in the current buffer
@ -440,18 +370,15 @@ extern "C" {
uint16_t fc = (available < frame_count) ? available : frame_count; uint16_t fc = (available < frame_count) ? available : frame_count;
if (mono) if (mono) {
{ for(uint16_t i=0;i<fc;i++){
for (uint16_t i = 0; i < fc; i++)
{
uint16_t v = (uint16_t)(*frames++); uint16_t v = (uint16_t)(*frames++);
tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v << 16) | v; tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v << 16) | v;
} }
} }
else else
{ {
for (uint16_t i = 0; i < fc; i++) for(uint16_t i=0;i<fc;i++){
{
uint16_t v1 = (uint16_t)(*frames++); uint16_t v1 = (uint16_t)(*frames++);
uint16_t v2 = (uint16_t)(*frames++); uint16_t v2 = (uint16_t)(*frames++);
tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v1 << 16) | v2; tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v1 << 16) | v2;
@ -462,50 +389,29 @@ extern "C" {
frames_written += fc; frames_written += fc;
} }
return frames_written; return frames_written;
} }
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) { return _i2s_write_buffer(frames, frame_count, true, true); }
{
return _i2s_write_buffer(frames, frame_count, true, true);
}
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) { return _i2s_write_buffer(frames, frame_count, true, false); }
{
return _i2s_write_buffer(frames, frame_count, true, false);
}
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) { return _i2s_write_buffer(frames, frame_count, false, true); }
{
return _i2s_write_buffer(frames, frame_count, false, true);
}
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count) uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, false); }
{
return _i2s_write_buffer(frames, frame_count, false, false);
}
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking) bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking) {
{ if (!rx) {
if (!rx)
{
return false; return false;
} }
if (rx->curr_slc_buf_pos == SLC_BUF_LEN || rx->curr_slc_buf == NULL) if (rx->curr_slc_buf_pos==SLC_BUF_LEN || rx->curr_slc_buf==NULL) {
{ if (rx->slc_queue_len == 0) {
if (rx->slc_queue_len == 0) if (!blocking) {
{
if (!blocking)
{
return false; return false;
} }
while (1) while (1) {
{ if (rx->slc_queue_len > 0){
if (rx->slc_queue_len > 0)
{
break; break;
} } else {
else
{
optimistic_yield(10000); optimistic_yield(10000);
} }
} }
@ -513,43 +419,36 @@ extern "C" {
ETS_SLC_INTR_DISABLE(); ETS_SLC_INTR_DISABLE();
rx->curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(rx); rx->curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(rx);
ETS_SLC_INTR_ENABLE(); ETS_SLC_INTR_ENABLE();
rx->curr_slc_buf_pos = 0; rx->curr_slc_buf_pos=0;
} }
uint32_t sample = rx->curr_slc_buf[rx->curr_slc_buf_pos++]; uint32_t sample = rx->curr_slc_buf[rx->curr_slc_buf_pos++];
if (left) if (left) {
{
*left = sample & 0xffff; *left = sample & 0xffff;
} }
if (right) if (right) {
{
*right = sample >> 16; *right = sample >> 16;
} }
return true; return true;
} }
void i2s_set_rate(uint32_t rate) //Rate in HZ void i2s_set_rate(uint32_t rate) { //Rate in HZ
{ if (rate == _i2s_sample_rate) {
if (rate == _i2s_sample_rate)
{
return; return;
} }
_i2s_sample_rate = rate; _i2s_sample_rate = rate;
uint32_t scaled_base_freq = I2SBASEFREQ / 32; uint32_t scaled_base_freq = I2SBASEFREQ/32;
float delta_best = scaled_base_freq; float delta_best = scaled_base_freq;
uint8_t sbd_div_best = 1; uint8_t sbd_div_best=1;
uint8_t scd_div_best = 1; uint8_t scd_div_best=1;
for (uint8_t i = 1; i < 64; i++) for (uint8_t i=1; i<64; i++) {
{ for (uint8_t j=i; j<64; j++) {
for (uint8_t j = i; j < 64; j++) float new_delta = fabs(((float)scaled_base_freq/i/j) - rate);
{ if (new_delta < delta_best){
float new_delta = fabs(((float)scaled_base_freq / i / j) - rate);
if (new_delta < delta_best)
{
delta_best = new_delta; delta_best = new_delta;
sbd_div_best = i; sbd_div_best = i;
scd_div_best = j; scd_div_best = j;
@ -557,11 +456,10 @@ extern "C" {
} }
} }
i2s_set_dividers(sbd_div_best, scd_div_best); i2s_set_dividers( sbd_div_best, scd_div_best );
} }
void i2s_set_dividers(uint8_t div1, uint8_t div2) void i2s_set_dividers(uint8_t div1, uint8_t div2) {
{
// Ensure dividers fit in bit fields // Ensure dividers fit in bit fields
div1 &= I2SBDM; div1 &= I2SBDM;
div2 &= I2SCDM; div2 &= I2SCDM;
@ -574,25 +472,20 @@ extern "C" {
// I2SRMS, I2STMS = 1-bit delay from WS to MSB (I2S format) // I2SRMS, I2STMS = 1-bit delay from WS to MSB (I2S format)
// div1, div2 = Set I2S WS clock frequency. BCLK seems to be generated from 32x this // div1, div2 = Set I2S WS clock frequency. BCLK seems to be generated from 32x this
I2SC |= I2SRF | I2SMR | I2SRMS | I2STMS | (div1 << I2SBD) | (div2 << I2SCD); I2SC |= I2SRF | I2SMR | I2SRMS | I2STMS | (div1 << I2SBD) | (div2 << I2SCD);
} }
float i2s_get_real_rate() float i2s_get_real_rate(){
{ return (float)I2SBASEFREQ/32/((I2SC>>I2SBD) & I2SBDM)/((I2SC >> I2SCD) & I2SCDM);
return (float)I2SBASEFREQ / 32 / ((I2SC >> I2SBD) & I2SBDM) / ((I2SC >> I2SCD) & I2SCDM); }
}
bool i2s_rxtx_begin(bool enableRx, bool enableTx) bool i2s_rxtx_begin(bool enableRx, bool enableTx) {
{ if (tx || rx) {
if (tx || rx)
{
i2s_end(); // Stop and free any ongoing stuff i2s_end(); // Stop and free any ongoing stuff
} }
if (enableTx) if (enableTx) {
{
tx = (i2s_state_t*)calloc(1, sizeof(*tx)); tx = (i2s_state_t*)calloc(1, sizeof(*tx));
if (!tx) if (!tx) {
{
// Nothing to clean up yet // Nothing to clean up yet
return false; // OOM Error! return false; // OOM Error!
} }
@ -600,11 +493,9 @@ extern "C" {
pinMode(I2SO_DATA, FUNCTION_1); pinMode(I2SO_DATA, FUNCTION_1);
pinMode(I2SO_BCK, FUNCTION_1); pinMode(I2SO_BCK, FUNCTION_1);
} }
if (enableRx) if (enableRx) {
{
rx = (i2s_state_t*)calloc(1, sizeof(*rx)); rx = (i2s_state_t*)calloc(1, sizeof(*rx));
if (!rx) if (!rx) {
{
i2s_end(); // Clean up any TX or pin changes i2s_end(); // Clean up any TX or pin changes
return false; // OOM error! return false; // OOM error!
} }
@ -617,8 +508,7 @@ extern "C" {
} }
_i2s_sample_rate = 0; _i2s_sample_rate = 0;
if (!i2s_slc_begin()) if (!i2s_slc_begin()) {
{
// OOM in SLC memory allocations, tear it all down and abort! // OOM in SLC memory allocations, tear it all down and abort!
i2s_end(); i2s_end();
return false; return false;
@ -642,24 +532,21 @@ extern "C" {
i2s_set_rate(44100); i2s_set_rate(44100);
if (rx) if (rx) {
{
// Need to prime the # of samples to receive in the engine // Need to prime the # of samples to receive in the engine
I2SRXEN = SLC_BUF_LEN; I2SRXEN = SLC_BUF_LEN;
} }
I2SC |= (rx ? I2SRXS : 0) | (tx ? I2STXS : 0); // Start transmission/reception I2SC |= (rx?I2SRXS:0) | (tx?I2STXS:0); // Start transmission/reception
return true; return true;
} }
void i2s_begin() void i2s_begin() {
{
i2s_rxtx_begin(false, true); i2s_rxtx_begin(false, true);
} }
void i2s_end() void i2s_end() {
{
// Disable any I2S send or receive // Disable any I2S send or receive
// ? Maybe not needed since we're resetting on the next line... // ? Maybe not needed since we're resetting on the next line...
I2SC &= ~(I2STXS | I2SRXS); I2SC &= ~(I2STXS | I2SRXS);
@ -671,22 +558,20 @@ extern "C" {
i2s_slc_end(); i2s_slc_end();
if (tx) if (tx) {
{
pinMode(I2SO_DATA, INPUT); pinMode(I2SO_DATA, INPUT);
pinMode(I2SO_BCK, INPUT); pinMode(I2SO_BCK, INPUT);
pinMode(I2SO_WS, INPUT); pinMode(I2SO_WS, INPUT);
free(tx); free(tx);
tx = NULL; tx = NULL;
} }
if (rx) if (rx) {
{
pinMode(I2SI_DATA, INPUT); pinMode(I2SI_DATA, INPUT);
pinMode(I2SI_BCK, INPUT); pinMode(I2SI_BCK, INPUT);
pinMode(I2SI_WS, INPUT); pinMode(I2SI_WS, INPUT);
free(rx); free(rx);
rx = NULL; rx = NULL;
} }
} }
}; };

View File

@ -18,7 +18,7 @@
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
@ -49,9 +49,9 @@ extern void (*__init_array_end)(void);
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,8 +62,8 @@ 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
@ -72,13 +72,11 @@ extern "C" {
} // 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);
@ -86,36 +84,29 @@ 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)
{ {
@ -123,12 +114,10 @@ extern "C" void optimistic_yield(uint32_t interval_us)
} }
} }
static void loop_wrapper() static void loop_wrapper() {
{
static bool setup_done = false; 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;
} }
@ -137,72 +126,56 @@ 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 struct object { long placeholder[ 10 ]; };
{ void __register_frame_info (const void *begin, struct object *ob);
long placeholder[ 10 ]; extern char __eh_frame[];
};
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(); abort();
#else #else
static bool terminating; static bool terminating;
if (terminating) if (terminating)
{
abort(); abort();
}
terminating = true; terminating = true;
/* Use a trick from vterminate.cc to get any std::exception what() */ /* Use a trick from vterminate.cc to get any std::exception what() */
try try {
{
__throw_exception_again; __throw_exception_again;
} } catch (const std::exception& e) {
catch (const std::exception& e) __unhandled_exception( e.what() );
{ } catch (...) {
__unhandled_exception(e.what()); __unhandled_exception( "" );
}
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);
@ -211,13 +184,13 @@ void init_done()
} }
/* 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:
@ -267,21 +240,20 @@ 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));

View File

@ -20,7 +20,7 @@
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,27 +31,22 @@
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) char* ultoa(unsigned long value, char* result, int base) {
{
return utoa((unsigned int)value, result, base); return utoa((unsigned int)value, result, base);
} }
char * dtostrf(double number, signed char width, unsigned char prec, char *s) char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
{
bool negative = false; bool negative = false;
if (isnan(number)) if (isnan(number)) {
{
strcpy(s, "nan"); strcpy(s, "nan");
return s; return s;
} }
if (isinf(number)) if (isinf(number)) {
{
strcpy(s, "inf"); strcpy(s, "inf");
return s; return s;
} }
@ -59,14 +54,12 @@ extern "C" {
char* out = s; char* out = s;
int fillme = width; // how many cells to fill for the integer part int fillme = width; // how many cells to fill for the integer part
if (prec > 0) if (prec > 0) {
{ fillme -= (prec+1);
fillme -= (prec + 1);
} }
// Handle negative numbers // Handle negative numbers
if (number < 0.0) if (number < 0.0) {
{
negative = true; negative = true;
fillme--; fillme--;
number = -number; number = -number;
@ -76,9 +69,7 @@ extern "C" {
// I optimized out most of the divisions // I optimized out most of the divisions
double rounding = 2.0; double rounding = 2.0;
for (uint8_t i = 0; i < prec; ++i) for (uint8_t i = 0; i < prec; ++i)
{
rounding *= 10.0; rounding *= 10.0;
}
rounding = 1.0 / rounding; rounding = 1.0 / rounding;
number += rounding; number += rounding;
@ -86,8 +77,7 @@ extern "C" {
// Figure out how big our number really is // Figure out how big our number really is
double tenpow = 1.0; double tenpow = 1.0;
int digitcount = 1; int digitcount = 1;
while (number >= 10.0 * tenpow) while (number >= 10.0 * tenpow) {
{
tenpow *= 10.0; tenpow *= 10.0;
digitcount++; digitcount++;
} }
@ -96,30 +86,21 @@ extern "C" {
fillme -= digitcount; fillme -= digitcount;
// Pad unused cells with spaces // Pad unused cells with spaces
while (fillme-- > 0) while (fillme-- > 0) {
{
*out++ = ' '; *out++ = ' ';
} }
// Handle negative sign // Handle negative sign
if (negative) if (negative) *out++ = '-';
{
*out++ = '-';
}
// Print the digits, and if necessary, the decimal point // Print the digits, and if necessary, the decimal point
digitcount += prec; digitcount += prec;
int8_t digit = 0; int8_t digit = 0;
while (digitcount-- > 0) while (digitcount-- > 0) {
{
digit = (int8_t)number; digit = (int8_t)number;
if (digit > 9) if (digit > 9) digit = 9; // insurance
{
digit = 9; // insurance
}
*out++ = (char)('0' | digit); *out++ = (char)('0' | digit);
if ((digitcount == prec) && (prec > 0)) if ((digitcount == prec) && (prec > 0)) {
{
*out++ = '.'; *out++ = '.';
} }
number -= digit; number -= digit;
@ -129,6 +110,6 @@ extern "C" {
// make sure the string is terminated // make sure the string is terminated
*out = 0; *out = 0;
return s; return s;
} }
}; };

View File

@ -17,7 +17,7 @@
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,8 +30,8 @@
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
@ -49,15 +49,15 @@ extern "C" {
/*[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
@ -90,11 +90,11 @@ extern "C" {
// 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,
@ -286,61 +286,60 @@ extern "C" {
// 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)); memcpy(dst, phy_init_data, sizeof(phy_init_data));
((uint8_t*)dst)[107] = __get_adc_mode(); ((uint8_t*)dst)[107] = __get_adc_mode();
return 0; return 0;
} }
extern int __get_rf_mode(void) __attribute__((weak)); extern int __get_rf_mode(void) __attribute__((weak));
extern int __get_rf_mode(void) extern int __get_rf_mode(void)
{ {
return -1; // mode not set return -1; // mode not set
} }
extern int __get_adc_mode(void) __attribute__((weak)); extern int __get_adc_mode(void) __attribute__((weak));
extern int __get_adc_mode(void) extern int __get_adc_mode(void)
{ {
return 33; // default ADC mode return 33; // default ADC mode
} }
extern void __run_user_rf_pre_init(void) __attribute__((weak)); extern void __run_user_rf_pre_init(void) __attribute__((weak));
extern void __run_user_rf_pre_init(void) extern void __run_user_rf_pre_init(void)
{ {
return; // default do noting return; // default do noting
} }
uint32_t user_rf_cal_sector_set(void) uint32_t user_rf_cal_sector_set(void)
{ {
spoof_init_data = true; spoof_init_data = true;
return flashchip->chip_size / SPI_FLASH_SEC_SIZE - 4; return flashchip->chip_size/SPI_FLASH_SEC_SIZE - 4;
} }
void user_rf_pre_init() void user_rf_pre_init()
{ {
// *((volatile uint32_t*) 0x60000710) = 0; // *((volatile uint32_t*) 0x60000710) = 0;
spoof_init_data = false; spoof_init_data = false;
volatile uint32_t* rtc_reg = (volatile uint32_t*) 0x60001000; volatile uint32_t* rtc_reg = (volatile uint32_t*) 0x60001000;
@ -348,14 +347,13 @@ extern "C" {
system_set_os_print(0); system_set_os_print(0);
int rf_mode = __get_rf_mode(); int rf_mode = __get_rf_mode();
if (rf_mode >= 0) if (rf_mode >= 0) {
{
system_phy_set_rfoption(rf_mode); system_phy_set_rfoption(rf_mode);
} }
__run_user_rf_pre_init(); __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() {}
}; };

View File

@ -16,7 +16,7 @@
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,63 +35,58 @@
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) rst_info;
(void) stack; (void) stack;
(void) stack_end; (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"))); 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 // Prints need to use our library function to allow for file and function
// to be safely accessed from flash. This function encapsulates snprintf() // to be safely accessed from flash. This function encapsulates snprintf()
// [which by definition will 0-terminate] and dumping to the UART // [which by definition will 0-terminate] and dumping to the UART
static void ets_printf_P(const char *str, ...) static void ets_printf_P(const char *str, ...) {
{
char destStr[160]; char destStr[160];
char *c = destStr; char *c = destStr;
va_list argPtr; va_list argPtr;
va_start(argPtr, str); va_start(argPtr, str);
vsnprintf(destStr, sizeof(destStr), str, argPtr); vsnprintf(destStr, sizeof(destStr), str, argPtr);
va_end(argPtr); va_end(argPtr);
while (*c) while (*c) {
{
ets_putc(*(c++)); ets_putc(*(c++));
} }
} }
void __wrap_system_restart_local() void __wrap_system_restart_local() {
{
register uint32_t sp asm("a1"); register uint32_t sp asm("a1");
uint32_t sp_dump = sp; uint32_t sp_dump = sp;
if (gdb_present()) if (gdb_present()) {
{
/* When GDBStub is present, exceptions are handled by GDBStub, /* When GDBStub is present, exceptions are handled by GDBStub,
but Soft WDT will still call this function. but Soft WDT will still call this function.
Trigger an exception to break into GDB. Trigger an exception to break into GDB.
@ -113,34 +108,28 @@ extern "C" {
// TODO: ets_install_putc1 definition is wrong in ets_sys.h, need cast // TODO: ets_install_putc1 definition is wrong in ets_sys.h, need cast
ets_install_putc1((void *)&uart_write_char_d); ets_install_putc1((void *)&uart_write_char_d);
if (s_panic_line) if (s_panic_line) {
{
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func); ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
if (s_panic_what) if (s_panic_what) {
{
ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what); ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
} }
ets_putc('\n'); ets_putc('\n');
} }
else if (s_unhandled_exception) else if (s_unhandled_exception) {
{
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception); ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
} }
else if (s_abort_called) else if (s_abort_called) {
{
ets_printf_P(PSTR("\nAbort called\n")); ets_printf_P(PSTR("\nAbort called\n"));
} }
else if (rst_info.reason == REASON_EXCEPTION_RST) else if (rst_info.reason == REASON_EXCEPTION_RST) {
{
ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"), 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); rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
} }
else if (rst_info.reason == REASON_SOFT_WDT_RST) else if (rst_info.reason == REASON_SOFT_WDT_RST) {
{
ets_printf_P(PSTR("\nSoft WDT reset\n")); ets_printf_P(PSTR("\nSoft WDT reset\n"));
} }
uint32_t cont_stack_start = (uint32_t) & (g_pcont->stack); uint32_t cont_stack_start = (uint32_t) &(g_pcont->stack);
uint32_t cont_stack_end = (uint32_t) g_pcont->stack_end; uint32_t cont_stack_end = (uint32_t) g_pcont->stack_end;
uint32_t stack_end; uint32_t stack_end;
@ -148,23 +137,19 @@ extern "C" {
// and everything up to __wrap_system_restart_local // and everything up to __wrap_system_restart_local
// (determined empirically, might break) // (determined empirically, might break)
uint32_t offset = 0; uint32_t offset = 0;
if (rst_info.reason == REASON_SOFT_WDT_RST) if (rst_info.reason == REASON_SOFT_WDT_RST) {
{
offset = 0x1b0; offset = 0x1b0;
} }
else if (rst_info.reason == REASON_EXCEPTION_RST) else if (rst_info.reason == REASON_EXCEPTION_RST) {
{
offset = 0x1a0; offset = 0x1a0;
} }
else if (rst_info.reason == REASON_WDT_RST) else if (rst_info.reason == REASON_WDT_RST) {
{
offset = 0x10; offset = 0x10;
} }
ets_printf_P(PSTR("\n>>>stack>>>\n")); ets_printf_P(PSTR("\n>>>stack>>>\n"));
if (sp_dump > stack_thunk_get_stack_bot() && sp_dump <= stack_thunk_get_stack_top()) if (sp_dump > stack_thunk_get_stack_bot() && sp_dump <= stack_thunk_get_stack_top()) {
{
// BearSSL we dump the BSSL second stack and then reset SP back to the main cont stack // 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); 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()); print_stack(sp_dump + offset, stack_thunk_get_stack_top());
@ -172,13 +157,11 @@ extern "C" {
sp_dump = stack_thunk_get_cont_sp(); sp_dump = stack_thunk_get_cont_sp();
} }
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end) if (sp_dump > cont_stack_start && sp_dump < cont_stack_end) {
{
ets_printf_P(PSTR("\nctx: cont\n")); ets_printf_P(PSTR("\nctx: cont\n"));
stack_end = cont_stack_end; stack_end = cont_stack_end;
} }
else else {
{
ets_printf_P(PSTR("\nctx: sys\n")); ets_printf_P(PSTR("\nctx: sys\n"));
stack_end = 0x3fffffb0; stack_end = 0x3fffffb0;
// it's actually 0x3ffffff0, but the stuff below ets_run // it's actually 0x3ffffff0, but the stuff below ets_run
@ -192,96 +175,83 @@ extern "C" {
ets_printf_P(PSTR("<<<stack<<<\n")); ets_printf_P(PSTR("<<<stack<<<\n"));
// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address // Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
if (umm_last_fail_alloc_addr) if (umm_last_fail_alloc_addr) {
{
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size); 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); custom_crash_callback( &rst_info, sp_dump + offset, stack_end );
ets_delay_us(10000); ets_delay_us(10000);
__real_system_restart_local(); __real_system_restart_local();
} }
static void print_stack(uint32_t start, uint32_t end) static void print_stack(uint32_t start, uint32_t end) {
{ for (uint32_t pos = start; pos < end; pos += 0x10) {
for (uint32_t pos = start; pos < end; pos += 0x10)
{
uint32_t* values = (uint32_t*)(pos); uint32_t* values = (uint32_t*)(pos);
// rough indicator: stack frames usually have SP saved as the second word // rough indicator: stack frames usually have SP saved as the second word
bool looksLikeStackFrame = (values[2] == pos + 0x10); bool looksLikeStackFrame = (values[2] == pos + 0x10);
ets_printf_P(PSTR("%08x: %08x %08x %08x %08x %c\n"), ets_printf_P(PSTR("%08x: %08x %08x %08x %08x %c\n"),
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame) ? '<' : ' '); pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
}
} }
}
static void uart_write_char_d(char c) static void uart_write_char_d(char c) {
{
uart0_write_char_d(c); uart0_write_char_d(c);
uart1_write_char_d(c); uart1_write_char_d(c);
} }
static void uart0_write_char_d(char c) static void uart0_write_char_d(char c) {
{
while (((USS(0) >> USTXC) & 0xff)) { } while (((USS(0) >> USTXC) & 0xff)) { }
if (c == '\n') if (c == '\n') {
{
USF(0) = '\r'; USF(0) = '\r';
} }
USF(0) = c; USF(0) = c;
} }
static void uart1_write_char_d(char c) static void uart1_write_char_d(char c) {
{
while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { } while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
if (c == '\n') if (c == '\n') {
{
USF(1) = '\r'; USF(1) = '\r';
} }
USF(1) = c; USF(1) = c;
} }
static void raise_exception() static void raise_exception() {
{ __asm__ __volatile__ ("syscall");
__asm__ __volatile__("syscall");
while (1); // never reached, needed to satisfy "noreturn" attribute while (1); // never reached, needed to satisfy "noreturn" attribute
} }
void abort() void abort() {
{
s_abort_called = true; s_abort_called = true;
raise_exception(); raise_exception();
} }
void __unhandled_exception(const char *str) void __unhandled_exception(const char *str) {
{
s_unhandled_exception = str; s_unhandled_exception = str;
raise_exception(); raise_exception();
} }
void __assert_func(const char *file, int line, const char *func, const char *what) void __assert_func(const char *file, int line, const char *func, const char *what) {
{
s_panic_file = file; s_panic_file = file;
s_panic_line = line; s_panic_line = line;
s_panic_func = func; s_panic_func = func;
s_panic_what = what; s_panic_what = what;
gdb_do_break(); /* if GDB is not present, this is a no-op */ gdb_do_break(); /* if GDB is not present, this is a no-op */
raise_exception(); raise_exception();
} }
void __panic_func(const char* file, int line, const char* func) void __panic_func(const char* file, int line, const char* func) {
{
s_panic_file = file; s_panic_file = file;
s_panic_line = line; s_panic_line = line;
s_panic_func = func; s_panic_func = func;
s_panic_what = 0; s_panic_what = 0;
gdb_do_break(); /* if GDB is not present, this is a no-op */ gdb_do_break(); /* if GDB is not present, this is a no-op */
raise_exception(); raise_exception();
} }
}; };

View File

@ -25,23 +25,23 @@
extern "C" { extern "C" {
unsigned int preferred_si2c_clock = 100000; unsigned int preferred_si2c_clock = 100000;
#include "twi_util.h" #include "twi_util.h"
#include "ets_sys.h" #include "ets_sys.h"
unsigned char twi_dcount = 18; unsigned char twi_dcount = 18;
static unsigned char twi_sda, twi_scl; static unsigned char twi_sda, twi_scl;
static uint32_t twi_clockStretchLimit; static uint32_t twi_clockStretchLimit;
static unsigned char twi_addr = 0; static unsigned char twi_addr = 0;
// modes (private) // modes (private)
#define TWIPM_UNKNOWN 0 #define TWIPM_UNKNOWN 0
#define TWIPM_IDLE 1 #define TWIPM_IDLE 1
#define TWIPM_ADDRESSED 2 #define TWIPM_ADDRESSED 2
#define TWIPM_WAIT 3 #define TWIPM_WAIT 3
// states (private) // states (private)
#define TWIP_UNKNOWN 0 #define TWIP_UNKNOWN 0
#define TWIP_IDLE 1 #define TWIP_IDLE 1
#define TWIP_START 2 #define TWIP_START 2
@ -59,37 +59,37 @@ extern "C" {
#define TWIP_WRITE 14 #define TWIP_WRITE 14
#define TWIP_BUS_ERR 15 #define TWIP_BUS_ERR 15
static volatile uint8_t twip_mode = TWIPM_IDLE; static volatile uint8_t twip_mode = TWIPM_IDLE;
static volatile uint8_t twip_state = TWIP_IDLE; static volatile uint8_t twip_state = TWIP_IDLE;
static volatile uint8_t twip_status = TW_NO_INFO; static volatile uint8_t twip_status = TW_NO_INFO;
static volatile uint8_t bitCount = 0; static volatile uint8_t bitCount = 0;
#define TWDR twi_data #define TWDR twi_data
static volatile uint8_t twi_data = 0x00; static volatile uint8_t twi_data = 0x00;
static volatile uint8_t twi_ack = 0; static volatile uint8_t twi_ack = 0;
static volatile uint8_t twi_ack_rec = 0; static volatile uint8_t twi_ack_rec = 0;
static volatile int twi_timeout_ms = 10; static volatile int twi_timeout_ms = 10;
#define TWI_READY 0 #define TWI_READY 0
#define TWI_MRX 1 #define TWI_MRX 1
#define TWI_MTX 2 #define TWI_MTX 2
#define TWI_SRX 3 #define TWI_SRX 3
#define TWI_STX 4 #define TWI_STX 4
static volatile uint8_t twi_state = TWI_READY; static volatile uint8_t twi_state = TWI_READY;
static volatile uint8_t twi_error = 0xFF; static volatile uint8_t twi_error = 0xFF;
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_txBufferIndex; static volatile uint8_t twi_txBufferIndex;
static volatile uint8_t twi_txBufferLength; static volatile uint8_t twi_txBufferLength;
static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_rxBufferIndex; static volatile uint8_t twi_rxBufferIndex;
static void (*twi_onSlaveTransmit)(void); static void (*twi_onSlaveTransmit)(void);
static void (*twi_onSlaveReceive)(uint8_t*, size_t); static void (*twi_onSlaveReceive)(uint8_t*, size_t);
static void onSclChange(void); static void onSclChange(void);
static void onSdaChange(void); static void onSdaChange(void);
#define EVENTTASK_QUEUE_SIZE 1 #define EVENTTASK_QUEUE_SIZE 1
#define EVENTTASK_QUEUE_PRIO 2 #define EVENTTASK_QUEUE_PRIO 2
@ -98,10 +98,10 @@ extern "C" {
#define TWI_SIG_RX (TWI_SIG_RANGE + 0x01) #define TWI_SIG_RX (TWI_SIG_RANGE + 0x01)
#define TWI_SIG_TX (TWI_SIG_RANGE + 0x02) #define TWI_SIG_TX (TWI_SIG_RANGE + 0x02)
static ETSEvent eventTaskQueue[EVENTTASK_QUEUE_SIZE]; static ETSEvent eventTaskQueue[EVENTTASK_QUEUE_SIZE];
static void eventTask(ETSEvent *e); static void eventTask(ETSEvent *e);
static ETSTimer timer; static ETSTimer timer;
static void onTimer(void *unused); static void onTimer(void *unused);
#define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low) #define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low)
#define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high) #define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high)
@ -120,77 +120,33 @@ extern "C" {
#define TWI_CLOCK_STRETCH_MULTIPLIER 6 #define TWI_CLOCK_STRETCH_MULTIPLIER 6
#endif #endif
void twi_setClock(unsigned int freq) void twi_setClock(unsigned int freq){
{
preferred_si2c_clock = freq; preferred_si2c_clock = freq;
#if F_CPU == FCPU80 #if F_CPU == FCPU80
if (freq <= 50000) if(freq <= 50000) twi_dcount = 38;//about 50KHz
{ else if(freq <= 100000) twi_dcount = 19;//about 100KHz
twi_dcount = 38; //about 50KHz else if(freq <= 200000) twi_dcount = 8;//about 200KHz
} else if(freq <= 300000) twi_dcount = 3;//about 300KHz
else if (freq <= 100000) else if(freq <= 400000) twi_dcount = 1;//about 400KHz
{ else twi_dcount = 1;//about 400KHz
twi_dcount = 19; //about 100KHz
}
else if (freq <= 200000)
{
twi_dcount = 8; //about 200KHz
}
else if (freq <= 300000)
{
twi_dcount = 3; //about 300KHz
}
else if (freq <= 400000)
{
twi_dcount = 1; //about 400KHz
}
else
{
twi_dcount = 1; //about 400KHz
}
#else #else
if (freq <= 50000) if(freq <= 50000) twi_dcount = 64;//about 50KHz
{ else if(freq <= 100000) twi_dcount = 32;//about 100KHz
twi_dcount = 64; //about 50KHz else if(freq <= 200000) twi_dcount = 14;//about 200KHz
} else if(freq <= 300000) twi_dcount = 8;//about 300KHz
else if (freq <= 100000) else if(freq <= 400000) twi_dcount = 5;//about 400KHz
{ else if(freq <= 500000) twi_dcount = 3;//about 500KHz
twi_dcount = 32; //about 100KHz else if(freq <= 600000) twi_dcount = 2;//about 600KHz
} else twi_dcount = 1;//about 700KHz
else if (freq <= 200000)
{
twi_dcount = 14; //about 200KHz
}
else if (freq <= 300000)
{
twi_dcount = 8; //about 300KHz
}
else if (freq <= 400000)
{
twi_dcount = 5; //about 400KHz
}
else if (freq <= 500000)
{
twi_dcount = 3; //about 500KHz
}
else if (freq <= 600000)
{
twi_dcount = 2; //about 600KHz
}
else
{
twi_dcount = 1; //about 700KHz
}
#endif #endif
} }
void twi_setClockStretchLimit(uint32_t limit) void twi_setClockStretchLimit(uint32_t limit){
{
twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER; twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER;
} }
void twi_init(unsigned char sda, unsigned char scl) void twi_init(unsigned char sda, unsigned char scl)
{ {
// set timer function // set timer function
ets_timer_setfn(&timer, onTimer, NULL); ets_timer_setfn(&timer, onTimer, NULL);
@ -209,44 +165,39 @@ extern "C" {
attachInterrupt(scl, onSclChange, CHANGE); attachInterrupt(scl, onSclChange, CHANGE);
attachInterrupt(sda, onSdaChange, CHANGE); attachInterrupt(sda, onSdaChange, CHANGE);
} }
} }
void twi_setAddress(uint8_t address) void twi_setAddress(uint8_t address)
{ {
// set twi slave address (skip over R/W bit) // set twi slave address (skip over R/W bit)
twi_addr = address << 1; twi_addr = address << 1;
} }
static void ICACHE_RAM_ATTR twi_delay(unsigned char v) static void ICACHE_RAM_ATTR twi_delay(unsigned char v){
{
unsigned int i; unsigned int i;
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
unsigned int reg; unsigned int reg;
for (i = 0; i < v; i++) for (i = 0; i < v; i++) {
{
reg = GPI; reg = GPI;
} }
(void)reg; (void)reg;
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
} }
static bool twi_write_start(void) static bool twi_write_start(void) {
{
SCL_HIGH(); SCL_HIGH();
SDA_HIGH(); SDA_HIGH();
if (SDA_READ() == 0) if (SDA_READ() == 0) {
{
return false; return false;
} }
twi_delay(twi_dcount); twi_delay(twi_dcount);
SDA_LOW(); SDA_LOW();
twi_delay(twi_dcount); twi_delay(twi_dcount);
return true; return true;
} }
static bool twi_write_stop(void) static bool twi_write_stop(void){
{
uint32_t i = 0; uint32_t i = 0;
SCL_LOW(); SCL_LOW();
SDA_LOW(); SDA_LOW();
@ -257,225 +208,164 @@ extern "C" {
SDA_HIGH(); SDA_HIGH();
twi_delay(twi_dcount); twi_delay(twi_dcount);
return true; return true;
} }
static bool twi_write_bit(bool bit) static bool twi_write_bit(bool bit) {
{
uint32_t i = 0; uint32_t i = 0;
SCL_LOW(); SCL_LOW();
if (bit) if (bit) SDA_HIGH();
{ else SDA_LOW();
SDA_HIGH(); twi_delay(twi_dcount+1);
}
else
{
SDA_LOW();
}
twi_delay(twi_dcount + 1);
SCL_HIGH(); SCL_HIGH();
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching
twi_delay(twi_dcount); twi_delay(twi_dcount);
return true; return true;
} }
static bool twi_read_bit(void) static bool twi_read_bit(void) {
{
uint32_t i = 0; uint32_t i = 0;
SCL_LOW(); SCL_LOW();
SDA_HIGH(); SDA_HIGH();
twi_delay(twi_dcount + 2); twi_delay(twi_dcount+2);
SCL_HIGH(); SCL_HIGH();
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching
bool bit = SDA_READ(); bool bit = SDA_READ();
twi_delay(twi_dcount); twi_delay(twi_dcount);
return bit; return bit;
} }
static bool twi_write_byte(unsigned char byte) static bool twi_write_byte(unsigned char byte) {
{
unsigned char bit; unsigned char bit;
for (bit = 0; bit < 8; bit++) for (bit = 0; bit < 8; bit++) {
{
twi_write_bit(byte & 0x80); twi_write_bit(byte & 0x80);
byte <<= 1; byte <<= 1;
} }
return !twi_read_bit();//NACK/ACK return !twi_read_bit();//NACK/ACK
} }
static unsigned char twi_read_byte(bool nack) static unsigned char twi_read_byte(bool nack) {
{
unsigned char byte = 0; unsigned char byte = 0;
unsigned char bit; unsigned char bit;
for (bit = 0; bit < 8; bit++) for (bit = 0; bit < 8; bit++) byte = (byte << 1) | twi_read_bit();
{
byte = (byte << 1) | twi_read_bit();
}
twi_write_bit(nack); twi_write_bit(nack);
return byte; return byte;
} }
unsigned char twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop) unsigned char twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop){
{
unsigned int i; unsigned int i;
if (!twi_write_start()) if(!twi_write_start()) return 4;//line busy
{ if(!twi_write_byte(((address << 1) | 0) & 0xFF)) {
return 4; //line busy if (sendStop) twi_write_stop();
}
if (!twi_write_byte(((address << 1) | 0) & 0xFF))
{
if (sendStop)
{
twi_write_stop();
}
return 2; //received NACK on transmit of address return 2; //received NACK on transmit of address
} }
for (i = 0; i < len; i++) for(i=0; i<len; i++) {
{ if(!twi_write_byte(buf[i])) {
if (!twi_write_byte(buf[i])) if (sendStop) twi_write_stop();
{
if (sendStop)
{
twi_write_stop();
}
return 3;//received NACK on transmit of data return 3;//received NACK on transmit of data
} }
} }
if (sendStop) if(sendStop) twi_write_stop();
{
twi_write_stop();
}
i = 0; i = 0;
while (SDA_READ() == 0 && (i++) < 10) while(SDA_READ() == 0 && (i++) < 10){
{
SCL_LOW(); SCL_LOW();
twi_delay(twi_dcount); twi_delay(twi_dcount);
SCL_HIGH(); SCL_HIGH();
unsigned int t = 0; while (SCL_READ() == 0 && (t++) < twi_clockStretchLimit); // twi_clockStretchLimit unsigned int t=0; while(SCL_READ()==0 && (t++)<twi_clockStretchLimit); // twi_clockStretchLimit
twi_delay(twi_dcount); twi_delay(twi_dcount);
} }
return 0; return 0;
} }
unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop) unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop){
{
unsigned int i; unsigned int i;
if (!twi_write_start()) if(!twi_write_start()) return 4;//line busy
{ if(!twi_write_byte(((address << 1) | 1) & 0xFF)) {
return 4; //line busy if (sendStop) twi_write_stop();
}
if (!twi_write_byte(((address << 1) | 1) & 0xFF))
{
if (sendStop)
{
twi_write_stop();
}
return 2;//received NACK on transmit of address return 2;//received NACK on transmit of address
} }
for (i = 0; i < (len - 1); i++) for(i=0; i<(len-1); i++) buf[i] = twi_read_byte(false);
{ buf[len-1] = twi_read_byte(true);
buf[i] = twi_read_byte(false); if(sendStop) twi_write_stop();
}
buf[len - 1] = twi_read_byte(true);
if (sendStop)
{
twi_write_stop();
}
i = 0; i = 0;
while (SDA_READ() == 0 && (i++) < 10) while(SDA_READ() == 0 && (i++) < 10){
{
SCL_LOW(); SCL_LOW();
twi_delay(twi_dcount); twi_delay(twi_dcount);
SCL_HIGH(); SCL_HIGH();
unsigned int t = 0; while (SCL_READ() == 0 && (t++) < twi_clockStretchLimit); // twi_clockStretchLimit unsigned int t=0; while(SCL_READ()==0 && (t++)<twi_clockStretchLimit); // twi_clockStretchLimit
twi_delay(twi_dcount); twi_delay(twi_dcount);
} }
return 0; return 0;
} }
uint8_t twi_status() uint8_t twi_status() {
{
if (SCL_READ() == 0) if (SCL_READ() == 0)
{
return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to recover return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to recover
}
int clockCount = 20; int clockCount = 20;
while (SDA_READ() == 0 && clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max while (SDA_READ() == 0 && clockCount-- > 0) { // if SDA low, read the bits slaves have to sent to a max
{
twi_read_bit(); twi_read_bit();
if (SCL_READ() == 0) if (SCL_READ() == 0) {
{
return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time
} }
} }
if (SDA_READ() == 0) if (SDA_READ() == 0)
{
return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits. return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits.
}
if (!twi_write_start()) if (!twi_write_start())
{
return I2C_SDA_HELD_LOW_AFTER_INIT; // line busy. SDA again held low by another device. 2nd master? return I2C_SDA_HELD_LOW_AFTER_INIT; // line busy. SDA again held low by another device. 2nd master?
}
return I2C_OK; return I2C_OK;
} }
uint8_t twi_transmit(const uint8_t* data, uint8_t length) uint8_t twi_transmit(const uint8_t* data, uint8_t length)
{ {
uint8_t i; uint8_t i;
// ensure data will fit into buffer // ensure data will fit into buffer
if (length > TWI_BUFFER_LENGTH) if (length > TWI_BUFFER_LENGTH) {
{
return 1; return 1;
} }
// ensure we are currently a slave transmitter // ensure we are currently a slave transmitter
if (twi_state != TWI_STX) if (twi_state != TWI_STX) {
{
return 2; return 2;
} }
// set length and copy data into tx buffer // set length and copy data into tx buffer
twi_txBufferLength = length; twi_txBufferLength = length;
for (i = 0; i < length; ++i) for (i = 0; i < length; ++i) {
{
twi_txBuffer[i] = data[i]; twi_txBuffer[i] = data[i];
} }
return 0; return 0;
} }
void twi_attachSlaveRxEvent(void (*function)(uint8_t*, size_t)) void twi_attachSlaveRxEvent( void (*function)(uint8_t*, size_t) )
{ {
twi_onSlaveReceive = function; twi_onSlaveReceive = function;
} }
void twi_attachSlaveTxEvent(void (*function)(void)) void twi_attachSlaveTxEvent( void (*function)(void) )
{ {
twi_onSlaveTransmit = function; twi_onSlaveTransmit = function;
} }
void ICACHE_RAM_ATTR twi_reply(uint8_t ack) void ICACHE_RAM_ATTR twi_reply(uint8_t ack)
{ {
// transmit master read ready signal, with or without ack // transmit master read ready signal, with or without ack
if (ack) if (ack) {
{
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(); // _BV(TWINT)
twi_ack = 1; // _BV(TWEA) twi_ack = 1; // _BV(TWEA)
} } else {
else
{
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(); // _BV(TWINT)
twi_ack = 0; // ~_BV(TWEA) twi_ack = 0; // ~_BV(TWEA)
} }
} }
void ICACHE_RAM_ATTR twi_stop(void) void ICACHE_RAM_ATTR twi_stop(void)
{ {
// send stop condition // send stop condition
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(); // _BV(TWINT)
@ -484,10 +374,10 @@ extern "C" {
SDA_HIGH(); // _BV(TWSTO) SDA_HIGH(); // _BV(TWSTO)
// update twi state // update twi state
twi_state = TWI_READY; twi_state = TWI_READY;
} }
void ICACHE_RAM_ATTR twi_releaseBus(void) void ICACHE_RAM_ATTR twi_releaseBus(void)
{ {
// release bus // release bus
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(); // _BV(TWINT)
@ -496,13 +386,12 @@ extern "C" {
// update twi state // update twi state
twi_state = TWI_READY; twi_state = TWI_READY;
} }
void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status)
{ {
switch (status) switch(status) {
{
// Slave Receiver // Slave Receiver
case TW_SR_SLA_ACK: // addressed, returned ack case TW_SR_SLA_ACK: // addressed, returned ack
case TW_SR_GCALL_ACK: // addressed generally, returned ack case TW_SR_GCALL_ACK: // addressed generally, returned ack
@ -517,22 +406,18 @@ extern "C" {
case TW_SR_DATA_ACK: // data received, returned ack case TW_SR_DATA_ACK: // data received, returned ack
case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
// if there is still room in the rx buffer // if there is still room in the rx buffer
if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
{
// put byte in buffer and ack // put byte in buffer and ack
twi_rxBuffer[twi_rxBufferIndex++] = TWDR; twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
twi_reply(1); twi_reply(1);
} }else{
else
{
// otherwise nack // otherwise nack
twi_reply(0); twi_reply(0);
} }
break; break;
case TW_SR_STOP: // stop or repeated start condition received case TW_SR_STOP: // stop or repeated start condition received
// put a null char after data if there's room // put a null char after data if there's room
if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
{
twi_rxBuffer[twi_rxBufferIndex] = '\0'; twi_rxBuffer[twi_rxBufferIndex] = '\0';
} }
// callback to user-defined callback over event task to allow for non-RAM-residing code // callback to user-defined callback over event task to allow for non-RAM-residing code
@ -574,12 +459,9 @@ extern "C" {
twi_data <<= 1; twi_data <<= 1;
// if there is more to send, ack, otherwise nack // if there is more to send, ack, otherwise nack
if (twi_txBufferIndex < twi_txBufferLength) if(twi_txBufferIndex < twi_txBufferLength){
{
twi_reply(1); twi_reply(1);
} }else{
else
{
twi_reply(0); twi_reply(0);
} }
break; break;
@ -597,23 +479,22 @@ extern "C" {
twi_stop(); twi_stop();
break; break;
} }
} }
void ICACHE_RAM_ATTR onTimer(void *unused) void ICACHE_RAM_ATTR onTimer(void *unused)
{ {
(void)unused; (void)unused;
twi_releaseBus(); twi_releaseBus();
twip_status = TW_BUS_ERROR; twip_status = TW_BUS_ERROR;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
twip_mode = TWIPM_WAIT; twip_mode = TWIPM_WAIT;
twip_state = TWIP_BUS_ERR; twip_state = TWIP_BUS_ERR;
} }
static void eventTask(ETSEvent *e) static void eventTask(ETSEvent *e)
{ {
if (e == NULL) if (e == NULL) {
{
return; return;
} }
@ -623,8 +504,7 @@ extern "C" {
twi_onSlaveTransmit(); twi_onSlaveTransmit();
// if they didn't change buffer & length, initialize it // if they didn't change buffer & length, initialize it
if (twi_txBufferLength == 0) if (twi_txBufferLength == 0) {
{
twi_txBufferLength = 1; twi_txBufferLength = 1;
twi_txBuffer[0] = 0x00; twi_txBuffer[0] = 0x00;
} }
@ -640,10 +520,10 @@ extern "C" {
twi_onSlaveReceive(twi_rxBuffer, e->par); twi_onSlaveReceive(twi_rxBuffer, e->par);
break; break;
} }
} }
void ICACHE_RAM_ATTR onSclChange(void) void ICACHE_RAM_ATTR onSclChange(void)
{ {
static uint8_t sda; static uint8_t sda;
static uint8_t scl; static uint8_t scl;
@ -664,53 +544,35 @@ extern "C" {
case TWIP_REP_START: case TWIP_REP_START:
case TWIP_SLA_W: case TWIP_SLA_W:
case TWIP_READ: case TWIP_READ:
if (!scl) if (!scl) {
{
// ignore // ignore
} } else {
else
{
bitCount--; bitCount--;
twi_data <<= 1; twi_data <<= 1;
twi_data |= sda; twi_data |= sda;
if (bitCount != 0) if (bitCount != 0) {
{
// continue // continue
} } else {
else
{
twip_state = TWIP_SEND_ACK; twip_state = TWIP_SEND_ACK;
} }
} }
break; break;
case TWIP_SEND_ACK: case TWIP_SEND_ACK:
if (scl) if (scl) {
{
// ignore // ignore
} } else {
else if (twip_mode == TWIPM_IDLE) {
{ if ((twi_data & 0xFE) != twi_addr) {
if (twip_mode == TWIPM_IDLE)
{
if ((twi_data & 0xFE) != twi_addr)
{
// ignore // ignore
} } else {
else
{
SDA_LOW(); SDA_LOW();
} }
} } else {
else if (!twi_ack) {
{
if (!twi_ack)
{
// ignore // ignore
} } else {
else
{
SDA_LOW(); SDA_LOW();
} }
} }
@ -719,52 +581,37 @@ extern "C" {
break; break;
case TWIP_WAIT_ACK: case TWIP_WAIT_ACK:
if (scl) if (scl) {
{
// ignore // ignore
} } else {
else if (twip_mode == TWIPM_IDLE) {
{ if ((twi_data & 0xFE) != twi_addr) {
if (twip_mode == TWIPM_IDLE)
{
if ((twi_data & 0xFE) != twi_addr)
{
SDA_HIGH(); SDA_HIGH();
twip_state = TWIP_WAIT_STOP; twip_state = TWIP_WAIT_STOP;
} } else {
else
{
SCL_LOW(); // clock stretching SCL_LOW(); // clock stretching
SDA_HIGH(); SDA_HIGH();
twip_mode = TWIPM_ADDRESSED; twip_mode = TWIPM_ADDRESSED;
if (!(twi_data & 0x01)) if (!(twi_data & 0x01)) {
{
twip_status = TW_SR_SLA_ACK; twip_status = TW_SR_SLA_ACK;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
bitCount = 8; bitCount = 8;
twip_state = TWIP_SLA_W; twip_state = TWIP_SLA_W;
} } else {
else
{
twip_status = TW_ST_SLA_ACK; twip_status = TW_ST_SLA_ACK;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
twip_state = TWIP_SLA_R; twip_state = TWIP_SLA_R;
} }
} }
} } else {
else
{
SCL_LOW(); // clock stretching SCL_LOW(); // clock stretching
SDA_HIGH(); SDA_HIGH();
if (!twi_ack) if (!twi_ack) {
{
twip_status = TW_SR_DATA_NACK; twip_status = TW_SR_DATA_NACK;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
twip_mode = TWIPM_WAIT; twip_mode = TWIPM_WAIT;
twip_state = TWIP_WAIT_STOP; twip_state = TWIP_WAIT_STOP;
} } else {
else
{
twip_status = TW_SR_DATA_ACK; twip_status = TW_SR_DATA_ACK;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
bitCount = 8; bitCount = 8;
@ -776,67 +623,49 @@ extern "C" {
case TWIP_SLA_R: case TWIP_SLA_R:
case TWIP_WRITE: case TWIP_WRITE:
if (scl) if (scl) {
{
// ignore // ignore
} } else {
else
{
bitCount--; bitCount--;
(twi_data & 0x80) ? SDA_HIGH() : SDA_LOW(); (twi_data & 0x80) ? SDA_HIGH() : SDA_LOW();
twi_data <<= 1; twi_data <<= 1;
if (bitCount != 0) if (bitCount != 0) {
{
// continue // continue
} } else {
else
{
twip_state = TWIP_REC_ACK; twip_state = TWIP_REC_ACK;
} }
} }
break; break;
case TWIP_REC_ACK: case TWIP_REC_ACK:
if (scl) if (scl) {
{
// ignore // ignore
} } else {
else
{
SDA_HIGH(); SDA_HIGH();
twip_state = TWIP_READ_ACK; twip_state = TWIP_READ_ACK;
} }
break; break;
case TWIP_READ_ACK: case TWIP_READ_ACK:
if (!scl) if (!scl) {
{
// ignore // ignore
} } else {
else
{
twi_ack_rec = !sda; twi_ack_rec = !sda;
twip_state = TWIP_RWAIT_ACK; twip_state = TWIP_RWAIT_ACK;
} }
break; break;
case TWIP_RWAIT_ACK: case TWIP_RWAIT_ACK:
if (scl) if (scl) {
{
// ignore // ignore
} } else {
else
{
SCL_LOW(); // clock stretching SCL_LOW(); // clock stretching
if (twi_ack && twi_ack_rec) if (twi_ack && twi_ack_rec) {
{
twip_status = TW_ST_DATA_ACK; twip_status = TW_ST_DATA_ACK;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
twip_state = TWIP_WRITE; twip_state = TWIP_WRITE;
} } else {
else
{
// we have no more data to send and/or the master doesn't want anymore // we have no more data to send and/or the master doesn't want anymore
twip_status = twi_ack_rec ? TW_ST_LAST_DATA : TW_ST_DATA_NACK; twip_status = twi_ack_rec ? TW_ST_LAST_DATA : TW_ST_DATA_NACK;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
@ -849,10 +678,10 @@ extern "C" {
default: default:
break; break;
} }
} }
void ICACHE_RAM_ATTR onSdaChange(void) void ICACHE_RAM_ATTR onSdaChange(void)
{ {
static uint8_t sda; static uint8_t sda;
static uint8_t scl; static uint8_t scl;
sda = SDA_READ(); sda = SDA_READ();
@ -861,16 +690,11 @@ extern "C" {
switch (twip_state) switch (twip_state)
{ {
case TWIP_IDLE: case TWIP_IDLE:
if (!scl) if (!scl) {
{
// DATA - ignore // DATA - ignore
} } else if (sda) {
else if (sda)
{
// STOP - ignore // STOP - ignore
} } else {
else
{
// START // START
bitCount = 8; bitCount = 8;
twip_state = TWIP_START; twip_state = TWIP_START;
@ -887,12 +711,9 @@ extern "C" {
case TWIP_READ_ACK: case TWIP_READ_ACK:
case TWIP_RWAIT_ACK: case TWIP_RWAIT_ACK:
case TWIP_WRITE: case TWIP_WRITE:
if (!scl) if (!scl) {
{
// DATA - ignore // DATA - ignore
} } else {
else
{
// START or STOP // START or STOP
SDA_HIGH(); // Should not be necessary SDA_HIGH(); // Should not be necessary
twip_status = TW_BUS_ERROR; twip_status = TW_BUS_ERROR;
@ -904,30 +725,21 @@ extern "C" {
case TWIP_WAIT_STOP: case TWIP_WAIT_STOP:
case TWIP_BUS_ERR: case TWIP_BUS_ERR:
if (!scl) if (!scl) {
{
// DATA - ignore // DATA - ignore
} } else {
else if (sda) {
{
if (sda)
{
// STOP // STOP
SCL_LOW(); // clock stretching SCL_LOW(); // clock stretching
ets_timer_disarm(&timer); ets_timer_disarm(&timer);
twip_state = TWIP_IDLE; twip_state = TWIP_IDLE;
twip_mode = TWIPM_IDLE; twip_mode = TWIPM_IDLE;
SCL_HIGH(); SCL_HIGH();
} } else {
else
{
// START // START
if (twip_state == TWIP_BUS_ERR) if (twip_state == TWIP_BUS_ERR) {
{
// ignore // ignore
} } else {
else
{
bitCount = 8; bitCount = 8;
twip_state = TWIP_REP_START; twip_state = TWIP_REP_START;
ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms
@ -938,36 +750,27 @@ extern "C" {
case TWIP_SLA_W: case TWIP_SLA_W:
case TWIP_READ: case TWIP_READ:
if (!scl) if (!scl) {
{
// DATA - ignore // DATA - ignore
} } else {
else
{
// START or STOP // START or STOP
if (bitCount != 7) if (bitCount != 7) {
{
// inside byte transfer - error // inside byte transfer - error
twip_status = TW_BUS_ERROR; twip_status = TW_BUS_ERROR;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
twip_mode = TWIPM_WAIT; twip_mode = TWIPM_WAIT;
twip_state = TWIP_BUS_ERR; twip_state = TWIP_BUS_ERR;
} } else {
else
{
// during first bit in byte transfer - ok // during first bit in byte transfer - ok
SCL_LOW(); // clock stretching SCL_LOW(); // clock stretching
twip_status = TW_SR_STOP; twip_status = TW_SR_STOP;
twi_onTwipEvent(twip_status); twi_onTwipEvent(twip_status);
if (sda) if (sda) {
{
// STOP // STOP
ets_timer_disarm(&timer); ets_timer_disarm(&timer);
twip_state = TWIP_IDLE; twip_state = TWIP_IDLE;
twip_mode = TWIPM_IDLE; twip_mode = TWIPM_IDLE;
} } else {
else
{
// START // START
bitCount = 8; bitCount = 8;
ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms
@ -981,6 +784,6 @@ extern "C" {
default: default:
break; break;
} }
} }
}; };

View File

@ -23,162 +23,156 @@
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 // set its source to the sigma delta source
GPC(pin) |= (1 << GPCS); //SOURCE 0:GPIO_DATA,1:SigmaDelta 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 // set its source to the sigma delta source
GPC(pin) &= ~(1 << GPCS); //SOURCE 0:GPIO_DATA,1:SigmaDelta 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 // set its source to the sigma delta source
return (GPC(pin) & (1 << GPCS)); //SOURCE 0:GPIO_DATA,1:SigmaDelta return (GPC(pin) & (1 << GPCS)); //SOURCE 0:GPIO_DATA,1:SigmaDelta
} }
else else
{
return false; 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; uint32_t prescaler = ((uint32_t)10000000/(freq*32)) - 1;
if (prescaler > 0xFF) if(prescaler > 0xFF) {
{
prescaler = 0xFF; prescaler = 0xFF;
} }
sigmaDeltaEnable(); sigmaDeltaEnable();
sigmaDeltaSetPrescaler((uint8_t) prescaler); sigmaDeltaSetPrescaler ((uint8_t) prescaler);
return 10000000 / ((prescaler + 1) * 32); return 10000000/((prescaler + 1) * 32);
} }
/****************************************************************************** /******************************************************************************
FunctionName : sigmaDeltaWrite * FunctionName : sigmaDeltaWrite
Description : set the duty cycle for the sigma-delta source * Description : set the duty cycle for the sigma-delta source
Parameters : uint8 duty, 0-255, duty cycle = target/256, * Parameters : uint8 duty, 0-255, duty cycle = target/256,
channel = unused, for compatibility with ESP32 * channel = unused, for compatibility with ESP32
Returns : none * Returns : none
*******************************************************************************/ *******************************************************************************/
void ICACHE_FLASH_ATTR sigmaDeltaWrite(uint8_t channel, uint8_t duty) void ICACHE_FLASH_ATTR sigmaDeltaWrite(uint8_t channel, uint8_t duty)
{ {
uint32_t reg = GPSD; uint32_t reg = GPSD;
(void) channel; (void) channel;
reg = (reg & ~(0xFF << GPSDT)) | ((duty & 0xFF) << GPSDT); reg = (reg & ~(0xFF << GPSDT)) | ((duty & 0xFF) << GPSDT);
GPSD = reg; GPSD = reg;
} }
/****************************************************************************** /******************************************************************************
FunctionName : sigmaDeltaRead * FunctionName : sigmaDeltaRead
Description : get the duty cycle for the sigma-delta source * Description : get the duty cycle for the sigma-delta source
Parameters : channel = unused, for compatibility with ESP32 * Parameters : channel = unused, for compatibility with ESP32
Returns : uint8_t duty cycle value 0..255 * Returns : uint8_t duty cycle value 0..255
*******************************************************************************/ *******************************************************************************/
uint8_t ICACHE_FLASH_ATTR sigmaDeltaRead(uint8_t channel) uint8_t ICACHE_FLASH_ATTR sigmaDeltaRead(uint8_t channel)
{ {
(void) channel; (void) channel;
return (uint8_t)((GPSD >> GPSDT) & 0xFF); return (uint8_t)((GPSD >> GPSDT) & 0xFF);
} }
/****************************************************************************** /******************************************************************************
FunctionName : sigmaDeltaSetPrescaler * FunctionName : sigmaDeltaSetPrescaler
Description : set the clock divider for the sigma-delta source * Description : set the clock divider for the sigma-delta source
Parameters : uint8 prescaler, 0-255, divides the 80MHz base clock by this amount * Parameters : uint8 prescaler, 0-255, divides the 80MHz base clock by this amount
Returns : none * Returns : none
*******************************************************************************/ *******************************************************************************/
void ICACHE_FLASH_ATTR sigmaDeltaSetPrescaler(uint8_t prescaler) void ICACHE_FLASH_ATTR sigmaDeltaSetPrescaler(uint8_t prescaler)
{ {
uint32_t reg = GPSD; uint32_t reg = GPSD;
reg = (reg & ~(0xFF << GPSDP)) | ((prescaler & 0xFF) << GPSDP); reg = (reg & ~(0xFF << GPSDP)) | ((prescaler & 0xFF) << GPSDP);
GPSD = reg; GPSD = reg;
} }
/****************************************************************************** /******************************************************************************
FunctionName : sigmaDeltaGetPrescaler * FunctionName : sigmaDeltaGetPrescaler
Description : get the prescaler value from the GPIO_SIGMA_DELTA register * Description : get the prescaler value from the GPIO_SIGMA_DELTA register
Parameters : none * Parameters : none
Returns : uint8 prescaler, CLK_DIV , 0-255 * Returns : uint8 prescaler, CLK_DIV , 0-255
*******************************************************************************/ *******************************************************************************/
uint8_t ICACHE_FLASH_ATTR sigmaDeltaGetPrescaler(void) uint8_t ICACHE_FLASH_ATTR sigmaDeltaGetPrescaler(void)
{ {
return (uint8_t)((GPSD >> GPSDP) & 0xFF); return (uint8_t)((GPSD >> GPSDP) & 0xFF);
} }
}; };

View File

@ -26,101 +26,82 @@
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; (void) para;
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
{
TEIE &= ~TEIE1; //edge int disable
}
T1I = 0; T1I = 0;
if (timer1_user_cb) if (timer1_user_cb) {
{
// to make ISR compatible to Arduino AVR model where interrupts are disabled // to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR // we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts uint32_t savedPS = xt_rsil(15); // stop other interrupts
timer1_user_cb(); timer1_user_cb();
xt_wsr_ps(savedPS); 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) void timer1_attachInterrupt(timercallback userFunc) {
{
timer1_user_cb = userFunc; timer1_user_cb = userFunc;
ETS_FRC1_INTR_ENABLE(); ETS_FRC1_INTR_ENABLE();
} }
void ICACHE_RAM_ATTR timer1_detachInterrupt() void ICACHE_RAM_ATTR timer1_detachInterrupt() {
{
timer1_user_cb = 0; timer1_user_cb = 0;
TEIE &= ~TEIE1;//edge int disable TEIE &= ~TEIE1;//edge int disable
ETS_FRC1_INTR_DISABLE(); ETS_FRC1_INTR_DISABLE();
} }
void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload) void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload){
{
T1C = (1 << TCTE) | ((divider & 3) << TCPD) | ((int_type & 1) << TCIT) | ((reload & 1) << TCAR); T1C = (1 << TCTE) | ((divider & 3) << TCPD) | ((int_type & 1) << TCIT) | ((reload & 1) << TCAR);
T1I = 0; T1I = 0;
} }
void ICACHE_RAM_ATTR timer1_write(uint32_t ticks) void ICACHE_RAM_ATTR timer1_write(uint32_t ticks){
{ T1L = ((ticks)& 0x7FFFFF);
T1L = ((ticks) & 0x7FFFFF); if ((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable
if ((T1C & (1 << TCIT)) == 0) }
{
TEIE |= TEIE1; //edge int enable
}
}
void ICACHE_RAM_ATTR timer1_disable() void ICACHE_RAM_ATTR timer1_disable(){
{
T1C = 0; T1C = 0;
T1I = 0; T1I = 0;
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
// timer 0 // timer 0
static volatile timercallback timer0_user_cb = NULL; static volatile timercallback timer0_user_cb = NULL;
void ICACHE_RAM_ATTR timer0_isr_handler(void* para) void ICACHE_RAM_ATTR timer0_isr_handler(void* para){
{
(void) para; (void) para;
if (timer0_user_cb) if (timer0_user_cb) {
{
// to make ISR compatible to Arduino AVR model where interrupts are disabled // to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR // we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts uint32_t savedPS = xt_rsil(15); // stop other interrupts
timer0_user_cb(); timer0_user_cb();
xt_wsr_ps(savedPS); xt_wsr_ps(savedPS);
} }
} }
void timer0_isr_init() void timer0_isr_init(){
{
ETS_CCOMPARE0_INTR_ATTACH(timer0_isr_handler, NULL); ETS_CCOMPARE0_INTR_ATTACH(timer0_isr_handler, NULL);
} }
void timer0_attachInterrupt(timercallback userFunc) void timer0_attachInterrupt(timercallback userFunc) {
{
timer0_user_cb = userFunc; timer0_user_cb = userFunc;
ETS_CCOMPARE0_ENABLE(); ETS_CCOMPARE0_ENABLE();
} }
void ICACHE_RAM_ATTR timer0_detachInterrupt() void ICACHE_RAM_ATTR timer0_detachInterrupt() {
{
timer0_user_cb = NULL; timer0_user_cb = NULL;
ETS_CCOMPARE0_DISABLE(); ETS_CCOMPARE0_DISABLE();
} }
}; };

View File

@ -33,61 +33,60 @@
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 ret = 0;
int sign = 1; int sign = 1;
if (arr[i] == '-') if (arr[i] == '-')
@ -96,78 +95,75 @@ extern "C++"
i++; i++;
} }
while (isDecimal(arr[i])) while (isDecimal(arr[i]))
ret = 10 * ret + arr[i++] - '0'; ret = 10*ret + arr[i++] - '0';
ret * sign; ret * sign;
}); });
} }
template<unsigned N> constexpr template<unsigned N> constexpr
int parseNthInteger(const char (&arr) [N], unsigned f) int parseNthInteger (const char (&arr) [N], unsigned f)
{ {
return ( // <= c++11 requires a "return statement" return ({ // <= c++11 requires a "return statement"
{
unsigned i = 0; unsigned i = 0;
while (f && arr[i]) while (f && arr[i])
{ {
if (isMinus(arr, i)) if (isMinus(arr, i))
{
i++; i++;
}
for (; isDecimal(arr[i]); i++); for (; isDecimal(arr[i]); i++);
f--; f--;
for (; arr[i] && !isMinus(arr, i) && !isDecimal(arr[i]); i++); for (; arr[i] && !isMinus(arr, i) && !isDecimal(arr[i]); i++);
} }
atoi(arr, i); atoi(arr, i);
}); });
} }
}; // namespace conststr }; // namespace conststr
namespace esp8266 { namespace esp8266 {
/* /*
version major * version major
*/ */
constexpr constexpr
int coreVersionMajor() int coreVersionMajor ()
{ {
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 0); return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 0);
} }
/* /*
version minor * version minor
*/ */
constexpr constexpr
int coreVersionMinor() int coreVersionMinor ()
{ {
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 1); return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 1);
} }
/* /*
version revision * version revision
*/ */
constexpr constexpr
int coreVersionRevision() int coreVersionRevision ()
{ {
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 2); return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 2);
} }
/* /*
git commit number since last tag (negative) * git commit number since last tag (negative)
or RC-number (positive) * or RC-number (positive)
*/ */
constexpr constexpr
int coreVersionSubRevision() int coreVersionSubRevision ()
{ {
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 3); return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 3);
} }
/* /*
unique revision indentifier (never decreases) * unique revision indentifier (never decreases)
*/ */
constexpr constexpr
int coreVersionNumeric() int coreVersionNumeric ()
{ {
return coreVersionMajor() * 10000000 return coreVersionMajor() * 10000000
+ coreVersionMinor() * 100000 + coreVersionMinor() * 100000
+ coreVersionRevision() * 1000 + coreVersionRevision() * 1000
@ -176,9 +172,9 @@ extern "C++"
coreVersionSubRevision() ? coreVersionSubRevision() ?
coreVersionSubRevision() - 100 : coreVersionSubRevision() - 100 :
0); 0);
} }
}; // namespace esp8266 }; // namespace esp8266
} // extern "C++" } // extern "C++"
#endif // __cplusplus #endif // __cplusplus

View File

@ -43,86 +43,76 @@
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 nextServiceCycle; // ESP cycle timer when a transition required
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
} 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; uint32_t ccount;
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount)); __asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
return ccount; return ccount;
} }
// Interrupt on/off control // Interrupt on/off control
static ICACHE_RAM_ATTR void timer1Interrupt(); static ICACHE_RAM_ATTR void timer1Interrupt();
static bool timerRunning = false; static bool timerRunning = false;
static void initTimer() static void initTimer() {
{
timer1_disable(); timer1_disable();
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL); ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt); ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE); timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
timerRunning = true; timerRunning = true;
} }
static void ICACHE_RAM_ATTR deinitTimer() static void ICACHE_RAM_ATTR deinitTimer() {
{
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL); ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
timer1_disable(); timer1_disable();
timer1_isr_init(); timer1_isr_init();
timerRunning = false; timerRunning = false;
} }
// Set a callback. Pass in NULL to stop it // Set a callback. Pass in NULL to stop it
void setTimer1Callback(uint32_t (*fn)()) void setTimer1Callback(uint32_t (*fn)()) {
{
timer1CB = fn; timer1CB = fn;
if (!timerRunning && fn) if (!timerRunning && fn) {
{
initTimer(); initTimer();
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
} } else if (timerRunning && !fn && !waveformEnabled) {
else if (timerRunning && !fn && !waveformEnabled)
{
deinitTimer(); deinitTimer();
} }
} }
// Start up a waveform on a pin, or change the current one. Will change to the new // 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() // waveform smoothly on next low->high transition. For immediate change, stopWaveform()
// first, then it will immediately begin. // first, then it will immediately begin.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
{ if ((pin > 16) || isFlashInterfacePin(pin)) {
if ((pin > 16) || isFlashInterfacePin(pin))
{
return false; return false;
} }
Waveform *wave = &waveform[pin]; Waveform *wave = &waveform[pin];
@ -130,105 +120,88 @@ extern "C" {
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS); wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS); wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0; wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
if (runTimeUS && !wave->expiryCycle) if (runTimeUS && !wave->expiryCycle) {
{
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
} }
uint32_t mask = 1 << pin; uint32_t mask = 1<<pin;
if (!(waveformEnabled & mask)) if (!(waveformEnabled & mask)) {
{
// Actually set the pin high or low in the IRQ service to guarantee times // Actually set the pin high or low in the IRQ service to guarantee times
wave->nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1); wave->nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1);
waveformToEnable |= mask; waveformToEnable |= mask;
if (!timerRunning) if (!timerRunning) {
{
initTimer(); initTimer();
timer1_write(microsecondsToClockCycles(10)); timer1_write(microsecondsToClockCycles(10));
} } else {
else
{
// Ensure timely service.... // Ensure timely service....
if (T1L > microsecondsToClockCycles(10)) if (T1L > microsecondsToClockCycles(10)) {
{
timer1_write(microsecondsToClockCycles(10)); timer1_write(microsecondsToClockCycles(10));
} }
} }
while (waveformToEnable) while (waveformToEnable) {
{
delay(0); // Wait for waveform to update delay(0); // Wait for waveform to update
} }
} }
return true; return true;
} }
// Speed critical bits // 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; uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount)); __asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
return 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) {
if (a < b)
{
return a; return a;
} }
return b; 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 // Can't possibly need to stop anything if there is no timer active
if (!timerRunning) if (!timerRunning) {
{
return false; return false;
} }
// If user sends in a pin >16 but <32, this will always point to a 0 bit // If user sends in a pin >16 but <32, this will always point to a 0 bit
// If they send >=32, then the shift will result in 0 and it will also return false // If they send >=32, then the shift will result in 0 and it will also return false
uint32_t mask = 1 << pin; uint32_t mask = 1<<pin;
if (!(waveformEnabled & mask)) if (!(waveformEnabled & mask)) {
{
return false; // It's not running, nothing to do here return false; // It's not running, nothing to do here
} }
waveformToDisable |= mask; waveformToDisable |= mask;
// Ensure timely service.... // Ensure timely service....
if (T1L > microsecondsToClockCycles(10)) if (T1L > microsecondsToClockCycles(10)) {
{
timer1_write(microsecondsToClockCycles(10)); timer1_write(microsecondsToClockCycles(10));
} }
while (waveformToDisable) while (waveformToDisable) {
{
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ /* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
} }
if (!waveformEnabled && !timer1CB) if (!waveformEnabled && !timer1CB) {
{
deinitTimer(); deinitTimer();
} }
return true; 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 // 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 // are generating. In the common case (1 PWM) these may be the same pin and
// we can avoid looking at the other pins. // we can avoid looking at the other pins.
@ -238,8 +211,7 @@ extern "C" {
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. // Handle enable/disable requests from main app.
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
waveformState &= ~waveformToEnable; // And clear the state of any just started waveformState &= ~waveformToEnable; // And clear the state of any just started
@ -252,18 +224,14 @@ extern "C" {
} }
bool done = false; bool done = false;
if (waveformEnabled) if (waveformEnabled) {
{ do {
do
{
nextEventCycles = microsecondsToClockCycles(MAXIRQUS); nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
for (int i = startPin; i <= endPin; i++) for (int i = startPin; i <= endPin; i++) {
{ uint32_t mask = 1<<i;
uint32_t mask = 1 << i;
// If it's not on, ignore! // If it's not on, ignore!
if (!(waveformEnabled & mask)) if (!(waveformEnabled & mask)) {
{
continue; continue;
} }
@ -271,19 +239,14 @@ extern "C" {
uint32_t now = GetCycleCountIRQ(); uint32_t now = GetCycleCountIRQ();
// Disable any waveforms that are done // Disable any waveforms that are done
if (wave->expiryCycle) if (wave->expiryCycle) {
{
int32_t expiryToGo = wave->expiryCycle - now; int32_t expiryToGo = wave->expiryCycle - now;
if (expiryToGo < 0) if (expiryToGo < 0) {
{
// Done, remove! // Done, remove!
waveformEnabled &= ~mask; waveformEnabled &= ~mask;
if (i == 16) if (i == 16) {
{
GP16O &= ~1; GP16O &= ~1;
} } else {
else
{
ClearGPIO(mask); ClearGPIO(mask);
} }
continue; continue;
@ -292,38 +255,26 @@ extern "C" {
// Check for toggles // Check for toggles
int32_t cyclesToGo = wave->nextServiceCycle - now; int32_t cyclesToGo = wave->nextServiceCycle - now;
if (cyclesToGo < 0) if (cyclesToGo < 0) {
{
waveformState ^= mask; waveformState ^= mask;
if (waveformState & mask) if (waveformState & mask) {
{ if (i == 16) {
if (i == 16)
{
GP16O |= 1; // GPIO16 write slow as it's RMW GP16O |= 1; // GPIO16 write slow as it's RMW
} } else {
else
{
SetGPIO(mask); SetGPIO(mask);
} }
wave->nextServiceCycle = now + wave->nextTimeHighCycles; wave->nextServiceCycle = now + wave->nextTimeHighCycles;
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeHighCycles); nextEventCycles = min_u32(nextEventCycles, wave->nextTimeHighCycles);
} } else {
else if (i == 16) {
{
if (i == 16)
{
GP16O &= ~1; // GPIO16 write slow as it's RMW GP16O &= ~1; // GPIO16 write slow as it's RMW
} } else {
else
{
ClearGPIO(mask); ClearGPIO(mask);
} }
wave->nextServiceCycle = now + wave->nextTimeLowCycles; wave->nextServiceCycle = now + wave->nextTimeLowCycles;
nextEventCycles = min_u32(nextEventCycles, wave->nextTimeLowCycles); nextEventCycles = min_u32(nextEventCycles, wave->nextTimeLowCycles);
} }
} } else {
else
{
uint32_t deltaCycles = wave->nextServiceCycle - now; uint32_t deltaCycles = wave->nextServiceCycle - now;
nextEventCycles = min_u32(nextEventCycles, deltaCycles); nextEventCycles = min_u32(nextEventCycles, deltaCycles);
} }
@ -337,13 +288,11 @@ extern "C" {
} while (!done); } while (!done);
} // if (waveformEnabled) } // if (waveformEnabled)
if (timer1CB) if (timer1CB) {
{
nextEventCycles = min_u32(nextEventCycles, timer1CB()); nextEventCycles = min_u32(nextEventCycles, timer1CB());
} }
if (nextEventCycles < microsecondsToClockCycles(10)) if (nextEventCycles < microsecondsToClockCycles(10)) {
{
nextEventCycles = microsecondsToClockCycles(10); nextEventCycles = microsecondsToClockCycles(10);
} }
nextEventCycles -= DELTAIRQ; nextEventCycles -= DELTAIRQ;
@ -355,6 +304,6 @@ extern "C" {
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
} }
}; };

View File

@ -17,7 +17,7 @@
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 "ets_sys.h" #include "ets_sys.h"
@ -27,153 +27,143 @@
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; (void) arg;
esp_schedule(); esp_schedule();
} }
void delay(unsigned long ms) void delay(unsigned long ms) {
{ if(ms) {
if (ms)
{
os_timer_setfn(&delay_timer, (os_timer_func_t*) &delay_end, 0); os_timer_setfn(&delay_timer, (os_timer_func_t*) &delay_end, 0);
os_timer_arm(&delay_timer, ms, ONCE); os_timer_arm(&delay_timer, ms, ONCE);
} } else {
else
{
esp_schedule(); esp_schedule();
} }
esp_yield(); esp_yield();
if (ms) if(ms) {
{
os_timer_disarm(&delay_timer); os_timer_disarm(&delay_timer);
} }
} }
void micros_overflow_tick(void* arg) void micros_overflow_tick(void* arg) {
{
(void) arg; (void) arg;
uint32_t m = system_get_time(); uint32_t m = system_get_time();
if (m < micros_at_last_overflow_tick) if(m < micros_at_last_overflow_tick)
{
++micros_overflow_count; ++micros_overflow_count;
}
micros_at_last_overflow_tick = m; 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 uint64_t q; // Accumulator, 64-bit, little endian
uint32_t a[2]; // ..........., 32-bit segments uint32_t a[2]; // ..........., 32-bit segments
} acc; } acc;
@ -187,45 +177,41 @@ extern "C" {
// (a) Init. low-acc with high-word of 1st product. The right-shift // (a) Init. low-acc with high-word of 1st product. The right-shift
// falls on a byte boundary, hence is relatively quick. // falls on a byte boundary, hence is relatively quick.
acc.q = ((uint64_t)(m * (uint64_t)MAGIC_1E3_wLO) >> 32); acc.q = ( (uint64_t)( m * (uint64_t)MAGIC_1E3_wLO ) >> 32 );
// (b) Offset sum, low-acc // (b) Offset sum, low-acc
acc.q += (m * (uint64_t)MAGIC_1E3_wHI); acc.q += ( m * (uint64_t)MAGIC_1E3_wHI );
// (c) Offset sum, low-acc // (c) Offset sum, low-acc
acc.q += (c * (uint64_t)MAGIC_1E3_wLO); acc.q += ( c * (uint64_t)MAGIC_1E3_wLO );
// (d) Truncated sum, high-acc // (d) Truncated sum, high-acc
acc.a[1] += (uint32_t)(c * (uint64_t)MAGIC_1E3_wHI); acc.a[1] += (uint32_t)( c * (uint64_t)MAGIC_1E3_wHI );
return (acc.a[1]); // Extract result, high-acc return ( acc.a[1] ); // Extract result, high-acc
} //millis } //millis
unsigned long ICACHE_RAM_ATTR micros() unsigned long ICACHE_RAM_ATTR micros() {
{
return system_get_time(); return system_get_time();
} }
uint64_t ICACHE_RAM_ATTR micros64() uint64_t ICACHE_RAM_ATTR micros64() {
{
uint32_t low32_us = system_get_time(); uint32_t low32_us = system_get_time();
uint32_t high32_us = micros_overflow_count + ((low32_us < micros_at_last_overflow_tick) ? 1 : 0); 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; uint64_t duration64_us = (uint64_t)high32_us << 32 | low32_us;
return duration64_us; return duration64_us;
} }
void ICACHE_RAM_ATTR delayMicroseconds(unsigned int us) void ICACHE_RAM_ATTR delayMicroseconds(unsigned int us) {
{
os_delay_us(us); os_delay_us(us);
} }
void init() void init() {
{
initPins(); initPins();
timer1_isr_init(); timer1_isr_init();
os_timer_setfn(&micros_overflow_timer, (os_timer_func_t*) &micros_overflow_tick, 0); os_timer_setfn(&micros_overflow_timer, (os_timer_func_t*) &micros_overflow_tick, 0);
os_timer_arm(&micros_overflow_timer, 60000, REPEAT); os_timer_arm(&micros_overflow_timer, 60000, REPEAT);
} }
}; };

View File

@ -28,16 +28,15 @@
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")));
}; };

View File

@ -29,183 +29,121 @@
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 (pin < 16) if(mode == SPECIAL){
{
if (mode == SPECIAL)
{
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
GPEC = (1 << pin); //Disable GPEC = (1 << pin); //Disable
GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin) GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin)
if (pin == 3) if(pin == 3) GPF(pin) |= (1 << GPFPU);//enable pullup on RX
{ } else if(mode & FUNCTION_0){
GPF(pin) |= (1 << GPFPU); //enable pullup on RX
}
}
else if (mode & FUNCTION_0)
{
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
GPEC = (1 << pin); //Disable GPEC = (1 << pin); //Disable
GPF(pin) = GPFFS((mode >> 4) & 0x07); GPF(pin) = GPFFS((mode >> 4) & 0x07);
if (pin == 13 && mode == FUNCTION_4) if(pin == 13 && mode == FUNCTION_4) GPF(pin) |= (1 << GPFPU);//enable pullup on RX
{ } else if(mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN){
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 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) GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
if (mode == OUTPUT_OPEN_DRAIN) if(mode == OUTPUT_OPEN_DRAIN) GPC(pin) |= (1 << GPCD);
{
GPC(pin) |= (1 << GPCD);
}
GPES = (1 << pin); //Enable GPES = (1 << pin); //Enable
} } else if(mode == INPUT || mode == INPUT_PULLUP){
else if (mode == INPUT || mode == INPUT_PULLUP)
{
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
GPEC = (1 << pin); //Disable GPEC = (1 << pin); //Disable
GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
if (mode == INPUT_PULLUP) if(mode == INPUT_PULLUP) {
{
GPF(pin) |= (1 << GPFPU); // Enable Pullup GPF(pin) |= (1 << GPFPU); // Enable Pullup
} }
} } else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){
else if (mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN)
{
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
GPEC = (1 << pin); //Disable GPEC = (1 << pin); //Disable
if (mode == WAKEUP_PULLUP) if(mode == WAKEUP_PULLUP) {
{
GPF(pin) |= (1 << GPFPU); // Enable 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) GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED)
} } else {
else
{
GPF(pin) |= (1 << GPFPD); // Enable Pulldown 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) GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED)
} }
} }
} } else if(pin == 16){
else if (pin == 16)
{
GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO
GPC16 = 0; GPC16 = 0;
if (mode == INPUT || mode == INPUT_PULLDOWN_16) if(mode == INPUT || mode == INPUT_PULLDOWN_16){
{ if(mode == INPUT_PULLDOWN_16){
if (mode == INPUT_PULLDOWN_16)
{
GPF16 |= (1 << GP16FPD);//Enable Pulldown GPF16 |= (1 << GP16FPD);//Enable Pulldown
} }
GP16E &= ~1; GP16E &= ~1;
} } else if(mode == OUTPUT){
else if (mode == OUTPUT)
{
GP16E |= 1; GP16E |= 1;
} }
} }
} }
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) {
{
stopWaveform(pin); stopWaveform(pin);
if (pin < 16) if(pin < 16){
{ if(val) GPOS = (1 << pin);
if (val) else GPOC = (1 << pin);
{ } else if(pin == 16){
GPOS = (1 << pin); if(val) GP16O |= 1;
} else GP16O &= ~1;
else
{
GPOC = (1 << pin);
}
}
else if (pin == 16)
{
if (val)
{
GP16O |= 1;
}
else
{
GP16O &= ~1;
}
}
} }
}
extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) {
{ if(pin < 16){
if (pin < 16)
{
return GPIP(pin); return GPIP(pin);
} } else if(pin == 16){
else if (pin == 16)
{
return GP16I & 0x01; return GP16I & 0x01;
} }
return 0; return 0;
} }
/* /*
GPIO INTERRUPTS GPIO INTERRUPTS
*/ */
typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtr)(void);
typedef void (*voidFuncPtrArg)(void*); typedef void (*voidFuncPtrArg)(void*);
typedef struct typedef struct {
{
uint8_t mode; uint8_t mode;
void (*fn)(void); void (*fn)(void);
void * arg; void * arg;
} interrupt_handler_t; } interrupt_handler_t;
//duplicate from functionalInterrupt.h keep in sync //duplicate from functionalInterrupt.h keep in sync
typedef struct InterruptInfo typedef struct InterruptInfo {
{
uint8_t pin; uint8_t pin;
uint8_t value; uint8_t value;
uint32_t micro; uint32_t micro;
} InterruptInfo; } InterruptInfo;
typedef struct typedef struct {
{
InterruptInfo* interruptInfo; InterruptInfo* interruptInfo;
void* functionInfo; void* functionInfo;
} ArgStructure; } ArgStructure;
static interrupt_handler_t interrupt_handlers[16]; static interrupt_handler_t interrupt_handlers[16];
static uint32_t interrupt_reg = 0; static uint32_t interrupt_reg = 0;
void ICACHE_RAM_ATTR interrupt_handler(void *arg) void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
{
(void) arg; (void) arg;
uint32_t status = GPIE; uint32_t status = GPIE;
GPIEC = status;//clear them interrupts GPIEC = status;//clear them interrupts
uint32_t levels = GPI; uint32_t levels = GPI;
if (status == 0 || interrupt_reg == 0) if(status == 0 || interrupt_reg == 0) return;
{
return;
}
ETS_GPIO_INTR_DISABLE(); ETS_GPIO_INTR_DISABLE();
int i = 0; int i = 0;
uint32_t changedbits = status & interrupt_reg; uint32_t changedbits = status & interrupt_reg;
while (changedbits) while(changedbits){
{ while(!(changedbits & (1 << i))) i++;
while (!(changedbits & (1 << i)))
{
i++;
}
changedbits &= ~(1 << i); changedbits &= ~(1 << i);
interrupt_handler_t *handler = &interrupt_handlers[i]; interrupt_handler_t *handler = &interrupt_handlers[i];
if (handler->fn && if (handler->fn &&
(handler->mode == CHANGE || (handler->mode == CHANGE ||
(handler->mode & 1) == !!(levels & (1 << i)))) (handler->mode & 1) == !!(levels & (1 << i)))) {
{
// to make ISR compatible to Arduino AVR model where interrupts are disabled // to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR // we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts uint32_t savedPS = xt_rsil(15); // stop other interrupts
@ -228,12 +166,11 @@ extern "C" {
} }
} }
ETS_GPIO_INTR_ENABLE(); ETS_GPIO_INTR_ENABLE();
} }
extern void cleanupFunctional(void* arg); extern void cleanupFunctional(void* arg);
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) {
{
// #5780 // #5780
// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
@ -244,8 +181,7 @@ extern "C" {
abort(); abort();
} }
if (pin < 16) if(pin < 16) {
{
ETS_GPIO_INTR_DISABLE(); ETS_GPIO_INTR_DISABLE();
interrupt_handler_t *handler = &interrupt_handlers[pin]; interrupt_handler_t *handler = &interrupt_handlers[pin];
handler->mode = mode; handler->mode = mode;
@ -262,17 +198,15 @@ extern "C" {
ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg); ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg);
ETS_GPIO_INTR_ENABLE(); ETS_GPIO_INTR_ENABLE();
} }
} }
extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode) extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode )
{ {
__attachInterruptArg(pin, userFunc, 0, mode); __attachInterruptArg (pin, userFunc, 0, mode);
} }
extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
{ if(pin < 16) {
if (pin < 16)
{
ETS_GPIO_INTR_DISABLE(); ETS_GPIO_INTR_DISABLE();
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
GPIEC = (1 << pin); //Clear Interrupt for this pin GPIEC = (1 << pin); //Clear Interrupt for this pin
@ -286,34 +220,29 @@ extern "C" {
} }
handler->arg = 0; handler->arg = 0;
if (interrupt_reg) if (interrupt_reg)
{
ETS_GPIO_INTR_ENABLE(); ETS_GPIO_INTR_ENABLE();
} }
} }
}
void initPins() void initPins() {
{
//Disable UART interrupts //Disable UART interrupts
system_set_os_print(0); system_set_os_print(0);
U0IE = 0; U0IE = 0;
U1IE = 0; U1IE = 0;
for (int i = 0; i <= 5; ++i) for (int i = 0; i <= 5; ++i) {
{
pinMode(i, INPUT); pinMode(i, INPUT);
} }
// pins 6-11 are used for the SPI flash interface // pins 6-11 are used for the SPI flash interface
for (int i = 12; i <= 16; ++i) for (int i = 12; i <= 16; ++i) {
{
pinMode(i, INPUT); pinMode(i, INPUT);
} }
} }
extern void pinMode(uint8_t pin, uint8_t mode) __attribute__((weak, alias("__pinMode"))); 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 void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
extern int digitalRead(uint8_t pin) __attribute__((weak, alias("__digitalRead"))); 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 attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
extern void detachInterrupt(uint8_t pin) __attribute__((weak, alias("__detachInterrupt"))); extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));
}; };

View File

@ -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,12 +34,11 @@ extern "C" {
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 timeout_cycles = microsecondsToClockCycles(timeout);
@ -49,11 +48,11 @@ extern "C" {
const uint32_t pulse_start_cycle_count = xthal_get_ccount(); const uint32_t pulse_start_cycle_count = xthal_get_ccount();
WAIT_FOR_PIN_STATE(!state); WAIT_FOR_PIN_STATE(!state);
return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count); 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);
} }
}; };

View File

@ -26,47 +26,34 @@
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) {
if (range > 0)
{
analogScale = range; analogScale = range;
} }
} }
extern void __analogWriteFreq(uint32_t freq) extern void __analogWriteFreq(uint32_t freq) {
{ if (freq < 100) {
if (freq < 100)
{
analogFreq = 100; analogFreq = 100;
} } else if (freq > 40000) {
else if (freq > 40000)
{
analogFreq = 40000; analogFreq = 40000;
} } else {
else
{
analogFreq = freq; analogFreq = freq;
} }
} }
extern void __analogWrite(uint8_t pin, int val) extern void __analogWrite(uint8_t pin, int val) {
{ if (pin > 16) {
if (pin > 16)
{
return; return;
} }
uint32_t analogPeriod = 1000000L / analogFreq; uint32_t analogPeriod = 1000000L / analogFreq;
if (val < 0) if (val < 0) {
{
val = 0; val = 0;
} } else if (val > analogScale) {
else if (val > analogScale)
{
val = analogScale; val = analogScale;
} }
@ -74,27 +61,21 @@ extern "C" {
uint32_t high = (analogPeriod * val) / analogScale; uint32_t high = (analogPeriod * val) / analogScale;
uint32_t low = analogPeriod - high; uint32_t low = analogPeriod - high;
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
if (low == 0) if (low == 0) {
{
stopWaveform(pin); stopWaveform(pin);
digitalWrite(pin, HIGH); digitalWrite(pin, HIGH);
} } else if (high == 0) {
else if (high == 0)
{
stopWaveform(pin); stopWaveform(pin);
digitalWrite(pin, LOW); digitalWrite(pin, LOW);
} } else {
else if (startWaveform(pin, high, low, 0)) {
{
if (startWaveform(pin, high, low, 0))
{
analogMap |= (1 << pin); analogMap |= (1 << pin);
} }
} }
} }
extern void analogWrite(uint8_t pin, int val) __attribute__((weak, alias("__analogWrite"))); extern void analogWrite(uint8_t pin, int val) __attribute__((weak, alias("__analogWrite")));
extern void analogWriteFreq(uint32_t freq) __attribute__((weak, alias("__analogWriteFreq"))); extern void analogWriteFreq(uint32_t freq) __attribute__((weak, alias("__analogWriteFreq")));
extern void analogWriteRange(uint32_t range) __attribute__((weak, alias("__analogWriteRange"))); extern void analogWriteRange(uint32_t range) __attribute__((weak, alias("__analogWriteRange")));
}; };

View File

@ -23,50 +23,38 @@
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 value = 0;
uint8_t i; uint8_t i;
for (i = 0; i < 8; ++i) for(i = 0; i < 8; ++i) {
{
digitalWrite(clockPin, HIGH); digitalWrite(clockPin, HIGH);
if (bitOrder == LSBFIRST) if(bitOrder == LSBFIRST)
{
value |= digitalRead(dataPin) << i; value |= digitalRead(dataPin) << i;
}
else else
{
value |= digitalRead(dataPin) << (7 - i); value |= digitalRead(dataPin) << (7 - i);
}
digitalWrite(clockPin, LOW); 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)
if (bitOrder == LSBFIRST)
{
digitalWrite(dataPin, !!(val & (1 << i))); digitalWrite(dataPin, !!(val & (1 << i)));
}
else else
{
digitalWrite(dataPin, !!(val & (1 << (7 - i)))); digitalWrite(dataPin, !!(val & (1 << (7 - i))));
}
digitalWrite(clockPin, HIGH); digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW); digitalWrite(clockPin, LOW);
} }
} }
}; };

View File

@ -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
} }

View File

@ -16,19 +16,16 @@
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; const uint8_t* src = (const uint8_t*) mem;
os_printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); os_printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
for (uint32_t i = 0; i < len; i++) for(uint32_t i = 0; i < len; i++) {
{ if(i % cols == 0) {
if (i % cols == 0)
{
os_printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); os_printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
yield(); yield();
} }

View File

@ -9,8 +9,7 @@ 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
}; };
@ -18,8 +17,7 @@ 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];

View File

@ -27,9 +27,9 @@ 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>

View File

@ -26,19 +26,19 @@
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")));
}; };

View File

@ -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

View File

@ -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,201 +10,186 @@
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_addr = __builtin_return_address(0);
umm_last_fail_alloc_size = size; 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* _realloc_r(struct _reent* unused, void* ptr, size_t size)
{ {
(void) unused; (void) unused;
void *ret = realloc(ptr, size); void *ret = realloc(ptr, size);
if (0 != size && 0 == ret) if (0 != size && 0 == ret) {
{
umm_last_fail_alloc_addr = __builtin_return_address(0); umm_last_fail_alloc_addr = __builtin_return_address(0);
umm_last_fail_alloc_size = size; umm_last_fail_alloc_size = size;
} }
return ret; return ret;
} }
void* _calloc_r(struct _reent* unused, size_t count, size_t size) void* _calloc_r(struct _reent* unused, size_t count, size_t size)
{ {
(void) unused; (void) unused;
void *ret = calloc(count, size); void *ret = calloc(count, size);
if (0 != (count * size) && 0 == ret) if (0 != (count * size) && 0 == ret) {
{
umm_last_fail_alloc_addr = __builtin_return_address(0); umm_last_fail_alloc_addr = __builtin_return_address(0);
umm_last_fail_alloc_size = count * size; umm_last_fail_alloc_size = count * size;
} }
return ret; return ret;
} }
void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line) void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line)
{ {
(void) file; (void) file;
(void) line; (void) line;
free(ptr); 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); os_printf(oom_fmt, (int)s);
}
return ret; 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); os_printf(oom_fmt, (int)s);
}
return ret; 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); os_printf(oom_fmt, (int)s);
}
return ret; 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); print_loc(s, file, line);
}
return ret; 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); print_loc(s, file, line);
}
return ret; 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); print_loc(s, file, line);
}
return ret; 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);
} }
}; };

View File

@ -22,18 +22,18 @@
#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,8 +56,8 @@ 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.

View File

@ -21,21 +21,17 @@ extern "C" {
//} //}
// //
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;
} }

View File

@ -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,41 +11,31 @@
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[] 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_size = sizeof(decoding);
value_in -= 43; value_in -= 43;
if (value_in < 0 || value_in > decoding_size) if (value_in < 0 || value_in > decoding_size) return -1;
{ return pgm_read_byte( &decoding[(int)value_in] );
return -1; }
}
return pgm_read_byte(&decoding[(int)value_in]);
}
void base64_init_decodestate(base64_decodestate* state_in) void base64_init_decodestate(base64_decodestate* state_in){
{
state_in->step = step_a; state_in->step = step_a;
state_in->plainchar = 0; state_in->plainchar = 0;
} }
static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in) static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in){
{
const int8_t* codechar = code_in; const int8_t* codechar = code_in;
int8_t* plainchar = plaintext_out; int8_t* plainchar = plaintext_out;
int8_t fragment; int8_t fragment;
*plainchar = state_in->plainchar; *plainchar = state_in->plainchar;
switch (state_in->step) switch (state_in->step){
{ while (1){
while (1)
{
case step_a: case step_a:
do do {
{ if (codechar == code_in+length_in){
if (codechar == code_in + length_in)
{
state_in->step = step_a; state_in->step = step_a;
state_in->plainchar = *plainchar; state_in->plainchar = *plainchar;
return plainchar - plaintext_out; return plainchar - plaintext_out;
@ -54,10 +44,8 @@ extern "C" {
} while (fragment < 0); } while (fragment < 0);
*plainchar = (fragment & 0x03f) << 2; *plainchar = (fragment & 0x03f) << 2;
case step_b: case step_b:
do do {
{ if (codechar == code_in+length_in){
if (codechar == code_in + length_in)
{
state_in->step = step_b; state_in->step = step_b;
state_in->plainchar = *plainchar; state_in->plainchar = *plainchar;
return plainchar - plaintext_out; return plainchar - plaintext_out;
@ -67,10 +55,8 @@ extern "C" {
*plainchar++ |= (fragment & 0x030) >> 4; *plainchar++ |= (fragment & 0x030) >> 4;
*plainchar = (fragment & 0x00f) << 4; *plainchar = (fragment & 0x00f) << 4;
case step_c: case step_c:
do do {
{ if (codechar == code_in+length_in){
if (codechar == code_in + length_in)
{
state_in->step = step_c; state_in->step = step_c;
state_in->plainchar = *plainchar; state_in->plainchar = *plainchar;
return plainchar - plaintext_out; return plainchar - plaintext_out;
@ -80,10 +66,8 @@ extern "C" {
*plainchar++ |= (fragment & 0x03c) >> 2; *plainchar++ |= (fragment & 0x03c) >> 2;
*plainchar = (fragment & 0x003) << 6; *plainchar = (fragment & 0x003) << 6;
case step_d: case step_d:
do do {
{ if (codechar == code_in+length_in){
if (codechar == code_in + length_in)
{
state_in->step = step_d; state_in->step = step_d;
state_in->plainchar = *plainchar; state_in->plainchar = *plainchar;
return plainchar - plaintext_out; return plainchar - plaintext_out;
@ -95,33 +79,26 @@ extern "C" {
} }
/* control should not reach here */ /* control should not reach here */
return plainchar - plaintext_out; return plainchar - plaintext_out;
} }
static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out) static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out){
{
base64_decodestate _state; base64_decodestate _state;
base64_init_decodestate(&_state); base64_init_decodestate(&_state);
int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state); int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state);
if (len > 0) if(len > 0) plaintext_out[len] = 0;
{
plaintext_out[len] = 0;
}
return len; return len;
} }
int base64_decode_value(char value_in) int base64_decode_value(char value_in){
{
return base64_decode_value_signed(*((int8_t *) &value_in)); return base64_decode_value_signed(*((int8_t *) &value_in));
} }
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){
{
return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in); return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in);
} }
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out) int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){
{
return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out); return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out);
} }
}; };

View File

@ -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,11 @@
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; base64_decodestep step;
char plainchar; char plainchar;
} base64_decodestate; } base64_decodestate;

View File

@ -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,33 +10,26 @@
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->step = step_A;
state_in->result = 0; state_in->result = 0;
state_in->stepcount = 0; state_in->stepcount = 0;
state_in->stepsnewline = BASE64_CHARS_PER_LINE; state_in->stepsnewline = BASE64_CHARS_PER_LINE;
} }
void base64_init_encodestate_nonewlines(base64_encodestate* state_in) void base64_init_encodestate_nonewlines(base64_encodestate* state_in){
{
base64_init_encodestate(state_in); base64_init_encodestate(state_in);
state_in->stepsnewline = -1; state_in->stepsnewline = -1;
} }
char base64_encode_value(char value_in) char base64_encode_value(char value_in){
{
static const char encoding[] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char encoding[] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (value_in > 63) if (value_in > 63) return '=';
{ return pgm_read_byte( &encoding[(int)value_in] );
return '='; }
}
return pgm_read_byte(&encoding[(int)value_in]);
}
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in){
{
const char* plainchar = plaintext_in; const char* plainchar = plaintext_in;
const char* const plaintextend = plaintext_in + length_in; const char* const plaintextend = plaintext_in + length_in;
char* codechar = code_out; char* codechar = code_out;
@ -45,13 +38,10 @@ extern "C" {
result = state_in->result; result = state_in->result;
switch (state_in->step) switch (state_in->step){
{ while (1){
while (1)
{
case step_A: case step_A:
if (plainchar == plaintextend) if (plainchar == plaintextend){
{
state_in->result = result; state_in->result = result;
state_in->step = step_A; state_in->step = step_A;
return codechar - code_out; return codechar - code_out;
@ -61,8 +51,7 @@ extern "C" {
*codechar++ = base64_encode_value(result); *codechar++ = base64_encode_value(result);
result = (fragment & 0x003) << 4; result = (fragment & 0x003) << 4;
case step_B: case step_B:
if (plainchar == plaintextend) if (plainchar == plaintextend){
{
state_in->result = result; state_in->result = result;
state_in->step = step_B; state_in->step = step_B;
return codechar - code_out; return codechar - code_out;
@ -72,8 +61,7 @@ extern "C" {
*codechar++ = base64_encode_value(result); *codechar++ = base64_encode_value(result);
result = (fragment & 0x00f) << 2; result = (fragment & 0x00f) << 2;
case step_C: case step_C:
if (plainchar == plaintextend) if (plainchar == plaintextend){
{
state_in->result = result; state_in->result = result;
state_in->step = step_C; state_in->step = step_C;
return codechar - code_out; return codechar - code_out;
@ -85,8 +73,7 @@ extern "C" {
*codechar++ = base64_encode_value(result); *codechar++ = base64_encode_value(result);
++(state_in->stepcount); ++(state_in->stepcount);
if ((state_in->stepcount == BASE64_CHARS_PER_LINE / 4) && (state_in->stepsnewline > 0)) if ((state_in->stepcount == BASE64_CHARS_PER_LINE/4) && (state_in->stepsnewline > 0)){
{
*codechar++ = '\n'; *codechar++ = '\n';
state_in->stepcount = 0; state_in->stepcount = 0;
} }
@ -94,14 +81,12 @@ extern "C" {
} }
/* control should not reach here */ /* control should not reach here */
return codechar - code_out; return codechar - code_out;
} }
int base64_encode_blockend(char* code_out, base64_encodestate* state_in) int base64_encode_blockend(char* code_out, base64_encodestate* state_in){
{
char* codechar = code_out; char* codechar = code_out;
switch (state_in->step) switch (state_in->step){
{
case step_B: case step_B:
*codechar++ = base64_encode_value(state_in->result); *codechar++ = base64_encode_value(state_in->result);
*codechar++ = '='; *codechar++ = '=';
@ -117,14 +102,13 @@ extern "C" {
*codechar = 0x00; *codechar = 0x00;
return codechar - code_out; return codechar - code_out;
} }
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out) int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out){
{
base64_encodestate _state; base64_encodestate _state;
base64_init_encodestate(&_state); base64_init_encodestate(&_state);
int len = base64_encode_block(plaintext_in, length_in, code_out, &_state); int len = base64_encode_block(plaintext_in, length_in, code_out, &_state);
return len + base64_encode_blockend((code_out + len), &_state); return len + base64_encode_blockend((code_out + len), &_state);
} }
}; };

View File

@ -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,13 +19,11 @@
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; base64_encodestep step;
char result; char result;
int stepcount; int stepcount;

View File

@ -21,7 +21,7 @@
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,103 +47,88 @@
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)unused;
(void)ptr; (void)ptr;
(void)mode; (void)mode;
return 0; 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)unused;
(void)file; (void)file;
return 0; 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)unused;
(void)file; (void)file;
st->st_mode = S_IFCHR; st->st_mode = S_IFCHR;
return 0; 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)unused;
(void)file; (void)file;
(void)ptr; (void)ptr;
(void)dir; (void)dir;
return 0; 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)unused;
(void)file; (void)file;
(void)ptr; (void)ptr;
(void)len; (void)len;
return 0; 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; (void) r;
int pos = len; int pos = len;
if (file == STDOUT_FILENO) if (file == STDOUT_FILENO) {
{ while(pos--) {
while (pos--)
{
ets_putc(*ptr); ets_putc(*ptr);
++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; (void) r;
if (file->_file == STDOUT_FILENO) if (file->_file == STDOUT_FILENO) {
{
return ets_putc(c); 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; char c;
while ((c = *str) != 0) while((c = *str) != 0) {
{
ets_putc(c); ets_putc(c);
++str; ++str;
} }
ets_putc('\n'); ets_putc('\n');
return true; return true;
} }
#undef putchar #undef putchar
int ICACHE_RAM_ATTR putchar(int c) int ICACHE_RAM_ATTR putchar(int c) {
{
ets_putc(c); ets_putc(c);
return c; return c;
} }
void _exit(int status) void _exit(int status) {
{
(void) status; (void) status;
abort(); abort();
} }
int atexit(void (*func)()) int atexit(void (*func)()) {
{
(void) func; (void) func;
return 0; return 0;
} }
}; };

View File

@ -27,16 +27,15 @@
extern "C" { extern "C" {
#endif #endif
typedef struct typedef struct {
{
uint32_t state[4]; uint32_t state[4];
uint32_t count[2]; uint32_t count[2];
uint8_t buffer[64]; 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"

View File

@ -17,29 +17,29 @@
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
*/ */
/******************************************************************************* /*******************************************************************************
Info Sigma delta module * Info Sigma delta module
This module controls the esp8266 internal sigma delta source This module controls the esp8266 internal sigma delta source
Each pin can be connected to the sigma delta source Each pin can be connected to the sigma delta source
The target duty and frequency can be modified via the register GPIO_SIGMA_DELTA The target duty and frequency can be modified via the register GPIO_SIGMA_DELTA
THE TARGET FREQUENCY IS DEFINED AS: THE TARGET FREQUENCY IS DEFINED AS:
FREQ = 80,000,000/prescaler * target /256 HZ, 0<target<128 FREQ = 80,000,000/prescaler * target /256 HZ, 0<target<128
FREQ = 80,000,000/prescaler * (256-target) /256 HZ, 128<target<256 FREQ = 80,000,000/prescaler * (256-target) /256 HZ, 128<target<256
target: duty cycle,range 0-255 target: duty cycle,range 0-255
prescaler: is a clock divider, range 0-255 prescaler: is a clock divider, range 0-255
so the target and prescale will both affect the freq. so the target and prescale will both affect the freq.
CPU_FREQ has no influence on the sigma delta frequency. CPU_FREQ has no influence on the sigma delta frequency.
Usage : Usage :
1. sigmaDeltaSetup(0,f) : activate the sigma delta source with frequency f and default duty cycle (0) 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 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)) 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 3. sigmaDeltaWrite(0,dc) : set the output signal duty cycle, duty cycle = dc/256
*******************************************************************************/ *******************************************************************************/

View File

@ -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,28 +45,28 @@
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. 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); void sntp_set_daylight(int daylight);
int settimeofday(const struct timeval* tv, const struct timezone* tz) int settimeofday(const struct timeval* tv, const struct timezone* tz)
{ {
if (tz) /*before*/ if (tz) /*before*/
{ {
sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60); sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60);
@ -84,7 +84,7 @@ extern "C" {
return -1; return -1;
} }
return 0; return 0;
} }
#endif // lwip 1.4 only #endif // lwip 1.4 only
@ -92,12 +92,12 @@ extern "C" {
#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,22 +115,20 @@ extern "C" {
#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, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
} ; } ;
static const int year_lengths[2] = static const int year_lengths[2] = {
{
365, 365,
366 366
} ; } ;
struct tm struct tm
{ {
int tm_sec; int tm_sec;
int tm_min; int tm_min;
int tm_hour; int tm_hour;
@ -140,11 +138,11 @@ extern "C" {
int tm_wday; int tm_wday;
int tm_yday; int tm_yday;
int tm_isdst; int tm_isdst;
}; };
struct tm res_buf; struct tm res_buf;
typedef struct __tzrule_struct typedef struct __tzrule_struct
{ {
char ch; char ch;
int m; int m;
int n; int n;
@ -152,12 +150,12 @@ extern "C" {
int s; int s;
time_t change; time_t change;
int offset; int offset;
} __tzrule_type; } __tzrule_type;
__tzrule_type sntp__tzrule[2]; __tzrule_type sntp__tzrule[2];
struct tm * struct tm *
sntp_mktm_r(const time_t * tim_p, struct tm *res, int is_gmtime) sntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime)
{ {
long days, rem; long days, rem;
time_t lcltime; time_t lcltime;
int y; int y;
@ -181,16 +179,14 @@ extern "C" {
} }
/* compute hour, min, and sec */ /* compute hour, min, and sec */
res->tm_hour = (int)(rem / SECSPERHOUR); res->tm_hour = (int) (rem / SECSPERHOUR);
rem %= SECSPERHOUR; rem %= SECSPERHOUR;
res->tm_min = (int)(rem / SECSPERMIN); res->tm_min = (int) (rem / SECSPERMIN);
res->tm_sec = (int)(rem % SECSPERMIN); res->tm_sec = (int) (rem % SECSPERMIN);
/* compute day of week */ /* compute day of week */
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
{
res->tm_wday += DAYSPERWEEK; res->tm_wday += DAYSPERWEEK;
}
/* compute year & day of year */ /* compute year & day of year */
y = EPOCH_YEAR; y = EPOCH_YEAR;
@ -200,9 +196,7 @@ extern "C" {
{ {
yleap = isleap(y); yleap = isleap(y);
if (days < year_lengths[yleap]) if (days < year_lengths[yleap])
{
break; break;
}
y++; y++;
days -= year_lengths[yleap]; days -= year_lengths[yleap];
} }
@ -221,9 +215,7 @@ extern "C" {
res->tm_yday = days; res->tm_yday = days;
ip = mon_lengths[yleap]; ip = mon_lengths[yleap];
for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
{
days -= ip[res->tm_mon]; days -= ip[res->tm_mon];
}
res->tm_mday = days + 1; res->tm_mday = days + 1;
if (!is_gmtime) if (!is_gmtime)
@ -231,17 +223,17 @@ extern "C" {
int offset; int offset;
int hours, mins, secs; int hours, mins, secs;
// TZ_LOCK; // TZ_LOCK;
// if (_daylight) // if (_daylight)
// { // {
// if (y == __tzyear || __tzcalc_limits (y)) // if (y == __tzyear || __tzcalc_limits (y))
// res->tm_isdst = (__tznorth // res->tm_isdst = (__tznorth
// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change) // ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change)
// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change)); // : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change));
// else // else
// res->tm_isdst = -1; // res->tm_isdst = -1;
// } // }
// else // else
res->tm_isdst = -1; res->tm_isdst = -1;
offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset); offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset);
@ -281,9 +273,7 @@ extern "C" {
++res->tm_yday; ++res->tm_yday;
++res->tm_wday; ++res->tm_wday;
if (res->tm_wday > 6) if (res->tm_wday > 6)
{
res->tm_wday = 0; res->tm_wday = 0;
}
++res->tm_mday; ++res->tm_mday;
res->tm_hour -= HOURSPERDAY; res->tm_hour -= HOURSPERDAY;
if (res->tm_mday > ip[res->tm_mon]) if (res->tm_mday > ip[res->tm_mon])
@ -303,9 +293,7 @@ extern "C" {
res->tm_yday -= 1; res->tm_yday -= 1;
res->tm_wday -= 1; res->tm_wday -= 1;
if (res->tm_wday < 0) if (res->tm_wday < 0)
{
res->tm_wday = 6; res->tm_wday = 6;
}
res->tm_mday -= 1; res->tm_mday -= 1;
res->tm_hour += 24; res->tm_hour += 24;
if (res->tm_mday == 0) if (res->tm_mday == 0)
@ -320,37 +308,33 @@ extern "C" {
res->tm_mday = ip[res->tm_mon]; res->tm_mday = ip[res->tm_mon];
} }
} }
// TZ_UNLOCK; // TZ_UNLOCK;
} }
else else
{
res->tm_isdst = 0; 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);
// 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); return (res);
} }
struct tm * struct tm *
sntp_localtime_r(const time_t * tim_p, sntp_localtime_r(const time_t * tim_p ,
struct tm *res) struct tm *res)
{ {
return sntp_mktm_r(tim_p, res, 0); return sntp_mktm_r (tim_p, res, 0);
} }
struct tm * struct tm *
sntp_localtime(const time_t * tim_p) sntp_localtime(const time_t * tim_p)
{ {
return sntp_localtime_r(tim_p, &res_buf); return sntp_localtime_r (tim_p, &res_buf);
} }
int sntp__tzcalc_limits(int year) int sntp__tzcalc_limits(int year)
{ {
int days, year_days, years; int days, year_days, years;
int i, j; int i, j;
if (year < EPOCH_YEAR) if (year < EPOCH_YEAR)
{
return 0; return 0;
}
__tzyear = year; __tzyear = year;
@ -363,13 +347,9 @@ extern "C" {
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
{ {
if (sntp__tzrule[i].ch == 'J') if (sntp__tzrule[i].ch == 'J')
{
days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60); days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60);
}
else if (sntp__tzrule[i].ch == 'D') else if (sntp__tzrule[i].ch == 'D')
{
days = year_days + sntp__tzrule[i].d; days = year_days + sntp__tzrule[i].d;
}
else else
{ {
int yleap = isleap(year); int yleap = isleap(year);
@ -379,23 +359,17 @@ extern "C" {
days = year_days; days = year_days;
for (j = 1; j < sntp__tzrule[i].m; ++j) for (j = 1; j < sntp__tzrule[i].m; ++j)
{ days += ip[j-1];
days += ip[j - 1];
}
m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
wday_diff = sntp__tzrule[i].d - m_wday; wday_diff = sntp__tzrule[i].d - m_wday;
if (wday_diff < 0) if (wday_diff < 0)
{
wday_diff += DAYSPERWEEK; wday_diff += DAYSPERWEEK;
}
m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
while (m_day >= ip[j - 1]) while (m_day >= ip[j-1])
{
m_day -= DAYSPERWEEK; m_day -= DAYSPERWEEK;
}
days += m_day; days += m_day;
} }
@ -407,92 +381,89 @@ extern "C" {
__tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change); __tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change);
return 1; return 1;
} }
char* sntp_asctime_r(struct tm *tim_p, char *result) char* sntp_asctime_r(struct tm *tim_p ,char *result)
{ {
static const char day_name[7][4] = static const char day_name[7][4] = {
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
}; };
static const char mon_name[12][4] = static const char mon_name[12][4] = {
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
}; };
os_sprintf(result, "%s %s %02d %02d:%02d:%02d %02d\n", os_sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n",
day_name[tim_p->tm_wday], day_name[tim_p->tm_wday],
mon_name[tim_p->tm_mon], mon_name[tim_p->tm_mon],
tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min,
tim_p->tm_sec, 1900 + tim_p->tm_year); tim_p->tm_sec, 1900 + tim_p->tm_year);
return result; return result;
} }
char* sntp_asctime(struct tm *tim_p) char* sntp_asctime(struct tm *tim_p)
{ {
return sntp_asctime_r(tim_p, reult); return sntp_asctime_r (tim_p, reult);
} }
uint32 ICACHE_RAM_ATTR sntp_get_current_timestamp(void) uint32 ICACHE_RAM_ATTR sntp_get_current_timestamp(void)
{ {
return realtime_stamp; return realtime_stamp;
} }
char* sntp_get_real_time(time_t t) char* sntp_get_real_time(time_t t)
{ {
return sntp_asctime(sntp_localtime(&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. */ /* 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) sint32 sntp_get_timezone_in_seconds(void)
{ {
return time_zone; return time_zone;
} }
/* Returns the set timezone in hours. If the timezone was set as seconds, the fractional part is floored. */ /* Returns the set timezone in hours. If the timezone was set as seconds, the fractional part is floored. */
sint8 sntp_get_timezone(void) sint8 sntp_get_timezone(void)
{ {
return (sint8)(time_zone / (60 * 60)); return (sint8)(time_zone / (60 * 60));
} }
/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */ /* Sets the timezone in hours. Internally, the timezone is converted to seconds. */
bool sntp_set_timezone_in_seconds(sint32 timezone) bool sntp_set_timezone_in_seconds(sint32 timezone)
{ {
if (timezone >= (-11 * (60 * 60)) || timezone <= (13 * (60 * 60))) if(timezone >= (-11 * (60 * 60)) || timezone <= (13 * (60 * 60))) {
{
time_zone = timezone; time_zone = timezone;
return true; return true;
} }
return false; return false;
} }
/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */ /* Sets the timezone in hours. Internally, the timezone is converted to seconds. */
bool sntp_set_timezone(sint8 timezone) bool sntp_set_timezone(sint8 timezone)
{ {
return sntp_set_timezone_in_seconds((sint32)timezone * 60 * 60); return sntp_set_timezone_in_seconds((sint32)timezone * 60 * 60);
} }
void sntp_set_daylight(int daylight) void sntp_set_daylight(int daylight)
{ {
dst = daylight; dst = daylight;
} }
void ICACHE_RAM_ATTR sntp_time_inc(void) void ICACHE_RAM_ATTR sntp_time_inc (void)
{ {
realtime_stamp++; realtime_stamp++;
} }
static void sntp_set_system_time(uint32_t t) static void sntp_set_system_time (uint32_t t)
{ {
realtime_stamp = t + time_zone + dst; realtime_stamp = t + time_zone + dst;
os_timer_disarm(&sntp_timer); os_timer_disarm(&sntp_timer);
os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL);
os_timer_arm(&sntp_timer, 1000, 1); os_timer_arm(&sntp_timer, 1000, 1);
} }
int settimeofday(const struct timeval* tv, const struct timezone* tz) int settimeofday(const struct timeval* tv, const struct timezone* tz)
{ {
if (tz) /*before*/ if (tz) /*before*/
{ {
sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60); sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60);
@ -507,12 +478,10 @@ extern "C" {
sntp_set_system_time(tv->tv_sec); sntp_set_system_time(tv->tv_sec);
if (_settimeofday_cb) if (_settimeofday_cb)
{
_settimeofday_cb(); _settimeofday_cb();
} }
}
return 0; return 0;
} }
#endif // lwip2 only #endif // lwip2 only

View File

@ -3,7 +3,7 @@
extern "C" { extern "C" {
bool sntp_set_timezone_in_seconds(sint32 timezone); bool sntp_set_timezone_in_seconds(sint32 timezone);
} }

View File

@ -1,9 +1,9 @@
/* /*
spiffs.h * spiffs.h
*
Created on: May 26, 2013 * Created on: May 26, 2013
Author: petera * Author: petera
*/ */
#ifndef SPIFFS_H_ #ifndef SPIFFS_H_
#define SPIFFS_H_ #define SPIFFS_H_
@ -99,16 +99,14 @@ typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
#endif // SPIFFS_HAL_CALLBACK_EXTRA #endif // SPIFFS_HAL_CALLBACK_EXTRA
/* file system check callback report operation */ /* file system check callback report operation */
typedef enum typedef enum {
{
SPIFFS_CHECK_LOOKUP = 0, SPIFFS_CHECK_LOOKUP = 0,
SPIFFS_CHECK_INDEX, SPIFFS_CHECK_INDEX,
SPIFFS_CHECK_PAGE SPIFFS_CHECK_PAGE
} spiffs_check_type; } spiffs_check_type;
/* file system check callback report type */ /* file system check callback report type */
typedef enum typedef enum {
{
SPIFFS_CHECK_PROGRESS = 0, SPIFFS_CHECK_PROGRESS = 0,
SPIFFS_CHECK_ERROR, SPIFFS_CHECK_ERROR,
SPIFFS_CHECK_FIX_INDEX, SPIFFS_CHECK_FIX_INDEX,
@ -128,8 +126,7 @@ typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_repor
#endif // SPIFFS_HAL_CALLBACK_EXTRA #endif // SPIFFS_HAL_CALLBACK_EXTRA
/* file system listener callback operation */ /* file system listener callback operation */
typedef enum typedef enum {
{
/* the file has been created */ /* the file has been created */
SPIFFS_CB_CREATED = 0, SPIFFS_CB_CREATED = 0,
/* the file has been updated or moved to another page */ /* the file has been updated or moved to another page */
@ -200,8 +197,7 @@ typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op,
// phys structs // phys structs
// spiffs spi configuration struct // spiffs spi configuration struct
typedef struct typedef struct {
{
// physical read function // physical read function
spiffs_read hal_read_f; spiffs_read hal_read_f;
// physical write function // physical write function
@ -232,8 +228,7 @@ typedef struct
#endif #endif
} spiffs_config; } spiffs_config;
typedef struct spiffs_t typedef struct spiffs_t {
{
// file system configuration // file system configuration
spiffs_config cfg; spiffs_config cfg;
// number of logical blocks // number of logical blocks
@ -299,8 +294,7 @@ typedef struct spiffs_t
} spiffs; } spiffs;
/* spiffs file status struct */ /* spiffs file status struct */
typedef struct typedef struct {
{
spiffs_obj_id obj_id; spiffs_obj_id obj_id;
u32_t size; u32_t size;
spiffs_obj_type type; spiffs_obj_type type;
@ -311,8 +305,7 @@ typedef struct
#endif #endif
} spiffs_stat; } spiffs_stat;
struct spiffs_dirent struct spiffs_dirent {
{
spiffs_obj_id obj_id; spiffs_obj_id obj_id;
u8_t name[SPIFFS_OBJ_NAME_LEN]; u8_t name[SPIFFS_OBJ_NAME_LEN];
spiffs_obj_type type; spiffs_obj_type type;
@ -323,8 +316,7 @@ struct spiffs_dirent
#endif #endif
}; };
typedef struct typedef struct {
{
spiffs *fs; spiffs *fs;
spiffs_block_ix block; spiffs_block_ix block;
int entry; int entry;
@ -332,8 +324,7 @@ typedef struct
#if SPIFFS_IX_MAP #if SPIFFS_IX_MAP
typedef struct typedef struct {
{
// buffer with looked up data pixes // buffer with looked up data pixes
spiffs_page_ix *map_buf; spiffs_page_ix *map_buf;
// precise file byte offset // precise file byte offset
@ -350,443 +341,443 @@ typedef struct
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
/** /**
Special function. This takes a spiffs config struct and returns the number * Special function. This takes a spiffs config struct and returns the number
of blocks this file system was formatted with. This function relies on * of blocks this file system was formatted with. This function relies on
that following info is set correctly in given config struct: * that following info is set correctly in given config struct:
*
phys_addr, log_page_size, and log_block_size. * phys_addr, log_page_size, and log_block_size.
*
Also, hal_read_f must be set in the config struct. * Also, hal_read_f must be set in the config struct.
*
One must be sure of the correct page size and that the physical address is * One must be sure of the correct page size and that the physical address is
correct in the probed file system when calling this function. It is not * correct in the probed file system when calling this function. It is not
checked if the phys_addr actually points to the start of the file system, * checked if the phys_addr actually points to the start of the file system,
so one might get a false positive if entering a phys_addr somewhere in the * so one might get a false positive if entering a phys_addr somewhere in the
middle of the file system at block boundary. In addition, it is not checked * middle of the file system at block boundary. In addition, it is not checked
if the page size is actually correct. If it is not, weird file system sizes * if the page size is actually correct. If it is not, weird file system sizes
will be returned. * will be returned.
*
If this function detects a file system it returns the assumed file system * If this function detects a file system it returns the assumed file system
size, which can be used to set the phys_size. * size, which can be used to set the phys_size.
*
Otherwise, it returns an error indicating why it is not regarded as a file * Otherwise, it returns an error indicating why it is not regarded as a file
system. * system.
*
Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK * Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
macros. It returns the error code directly, instead of as read by * macros. It returns the error code directly, instead of as read by
SPIFFS_errno. * SPIFFS_errno.
*
@param config essential parts of the physical and logical * @param config essential parts of the physical and logical
configuration of the file system. * configuration of the file system.
*/ */
s32_t SPIFFS_probe_fs(spiffs_config *config); s32_t SPIFFS_probe_fs(spiffs_config *config);
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 #endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
/** /**
Initializes the file system dynamic parameters and mounts the filesystem. * Initializes the file system dynamic parameters and mounts the filesystem.
If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS * If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
if the flash does not contain a recognizable file system. * if the flash does not contain a recognizable file system.
In this case, SPIFFS_format must be called prior to remounting. * In this case, SPIFFS_format must be called prior to remounting.
@param fs the file system struct * @param fs the file system struct
@param config the physical and logical configuration of the file system * @param config the physical and logical configuration of the file system
@param work a memory work buffer comprising 2*config->log_page_size * @param work a memory work buffer comprising 2*config->log_page_size
bytes used throughout all file system operations * bytes used throughout all file system operations
@param fd_space memory for file descriptors * @param fd_space memory for file descriptors
@param fd_space_size memory size of file descriptors * @param fd_space_size memory size of file descriptors
@param cache memory for cache, may be null * @param cache memory for cache, may be null
@param cache_size memory size of cache * @param cache_size memory size of cache
@param check_cb_f callback function for reporting during consistency checks * @param check_cb_f callback function for reporting during consistency checks
*/ */
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
u8_t *fd_space, u32_t fd_space_size, u8_t *fd_space, u32_t fd_space_size,
void *cache, u32_t cache_size, void *cache, u32_t cache_size,
spiffs_check_callback check_cb_f); spiffs_check_callback check_cb_f);
/** /**
Unmounts the file system. All file handles will be flushed of any * Unmounts the file system. All file handles will be flushed of any
cached writes and closed. * cached writes and closed.
@param fs the file system struct * @param fs the file system struct
*/ */
void SPIFFS_unmount(spiffs *fs); void SPIFFS_unmount(spiffs *fs);
/** /**
Creates a new file. * Creates a new file.
@param fs the file system struct * @param fs the file system struct
@param path the path of the new file * @param path the path of the new file
@param mode ignored, for posix compliance * @param mode ignored, for posix compliance
*/ */
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode); s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
/** /**
Opens/creates a file. * Opens/creates a file.
@param fs the file system struct * @param fs the file system struct
@param path the path of the new file * @param path the path of the new file
@param flags the flags for the open command, can be combinations of * @param flags the flags for the open command, can be combinations of
SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY, * SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,
SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL * SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL
@param mode ignored, for posix compliance * @param mode ignored, for posix compliance
*/ */
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode); spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
/** /**
Opens a file by given dir entry. * Opens a file by given dir entry.
Optimization purposes, when traversing a file system with SPIFFS_readdir * Optimization purposes, when traversing a file system with SPIFFS_readdir
a normal SPIFFS_open would need to traverse the filesystem again to find * a normal SPIFFS_open would need to traverse the filesystem again to find
the file, whilst SPIFFS_open_by_dirent already knows where the file resides. * the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
@param fs the file system struct * @param fs the file system struct
@param e the dir entry to the file * @param e the dir entry to the file
@param flags the flags for the open command, can be combinations of * @param flags the flags for the open command, can be combinations of
SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY, * SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT. * SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
SPIFFS_CREAT will have no effect in this case. * SPIFFS_CREAT will have no effect in this case.
@param mode ignored, for posix compliance * @param mode ignored, for posix compliance
*/ */
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode); spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
/** /**
Opens a file by given page index. * Opens a file by given page index.
Optimization purposes, opens a file by directly pointing to the page * Optimization purposes, opens a file by directly pointing to the page
index in the spi flash. * index in the spi flash.
If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE * If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
is returned. * is returned.
@param fs the file system struct * @param fs the file system struct
@param page_ix the page index * @param page_ix the page index
@param flags the flags for the open command, can be combinations of * @param flags the flags for the open command, can be combinations of
SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY, * SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT. * SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
SPIFFS_CREAT will have no effect in this case. * SPIFFS_CREAT will have no effect in this case.
@param mode ignored, for posix compliance * @param mode ignored, for posix compliance
*/ */
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode); spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
/** /**
Reads from given filehandle. * Reads from given filehandle.
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle * @param fh the filehandle
@param buf where to put read data * @param buf where to put read data
@param len how much to read * @param len how much to read
@returns number of bytes read, or -1 if error * @returns number of bytes read, or -1 if error
*/ */
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len); s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
/** /**
Writes to given filehandle. * Writes to given filehandle.
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle * @param fh the filehandle
@param buf the data to write * @param buf the data to write
@param len how much to write * @param len how much to write
@returns number of bytes written, or -1 if error * @returns number of bytes written, or -1 if error
*/ */
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len); s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
/** /**
Moves the read/write file offset. Resulting offset is returned or negative if error. * Moves the read/write file offset. Resulting offset is returned or negative if error.
lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset. * lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle * @param fh the filehandle
@param offs how much/where to move the offset * @param offs how much/where to move the offset
@param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes * @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset * if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative * if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
*/ */
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence); s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
/** /**
Removes a file by path * Removes a file by path
@param fs the file system struct * @param fs the file system struct
@param path the path of the file to remove * @param path the path of the file to remove
*/ */
s32_t SPIFFS_remove(spiffs *fs, const char *path); s32_t SPIFFS_remove(spiffs *fs, const char *path);
/** /**
Removes a file by filehandle * Removes a file by filehandle
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle of the file to remove * @param fh the filehandle of the file to remove
*/ */
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh); s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
/** /**
Gets file status by path * Gets file status by path
@param fs the file system struct * @param fs the file system struct
@param path the path of the file to stat * @param path the path of the file to stat
@param s the stat struct to populate * @param s the stat struct to populate
*/ */
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s); s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
/** /**
Gets file status by filehandle * Gets file status by filehandle
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle of the file to stat * @param fh the filehandle of the file to stat
@param s the stat struct to populate * @param s the stat struct to populate
*/ */
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s); s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
/** /**
Flushes all pending write operations from cache for given file * Flushes all pending write operations from cache for given file
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle of the file to flush * @param fh the filehandle of the file to flush
*/ */
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh); s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
/** /**
Closes a filehandle. If there are pending write operations, these are finalized before closing. * Closes a filehandle. If there are pending write operations, these are finalized before closing.
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle of the file to close * @param fh the filehandle of the file to close
*/ */
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh); s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
/** /**
Renames a file * Renames a file
@param fs the file system struct * @param fs the file system struct
@param old path of file to rename * @param old path of file to rename
@param newPath new path of file * @param newPath new path of file
*/ */
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath); s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
#if SPIFFS_OBJ_META_LEN #if SPIFFS_OBJ_META_LEN
/** /**
Updates file's metadata * Updates file's metadata
@param fs the file system struct * @param fs the file system struct
@param path path to the file * @param path path to the file
@param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long. * @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
*/ */
s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta); s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);
/** /**
Updates file's metadata * Updates file's metadata
@param fs the file system struct * @param fs the file system struct
@param fh file handle of the file * @param fh file handle of the file
@param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long. * @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
*/ */
s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta); s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);
#endif #endif
/** /**
Returns last error of last file operation. * Returns last error of last file operation.
@param fs the file system struct * @param fs the file system struct
*/ */
s32_t SPIFFS_errno(spiffs *fs); s32_t SPIFFS_errno(spiffs *fs);
/** /**
Clears last error. * Clears last error.
@param fs the file system struct * @param fs the file system struct
*/ */
void SPIFFS_clearerr(spiffs *fs); void SPIFFS_clearerr(spiffs *fs);
/** /**
Opens a directory stream corresponding to the given name. * Opens a directory stream corresponding to the given name.
The stream is positioned at the first entry in the directory. * The stream is positioned at the first entry in the directory.
On hydrogen builds the name argument is ignored as hydrogen builds always correspond * On hydrogen builds the name argument is ignored as hydrogen builds always correspond
to a flat file structure - no directories. * to a flat file structure - no directories.
@param fs the file system struct * @param fs the file system struct
@param name the name of the directory * @param name the name of the directory
@param d pointer the directory stream to be populated * @param d pointer the directory stream to be populated
*/ */
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d); spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
/** /**
Closes a directory stream * Closes a directory stream
@param d the directory stream to close * @param d the directory stream to close
*/ */
s32_t SPIFFS_closedir(spiffs_DIR *d); s32_t SPIFFS_closedir(spiffs_DIR *d);
/** /**
Reads a directory into given spifs_dirent struct. * Reads a directory into given spifs_dirent struct.
@param d pointer to the directory stream * @param d pointer to the directory stream
@param e the dirent struct to be populated * @param e the dirent struct to be populated
@returns null if error or end of stream, else given dirent is returned * @returns null if error or end of stream, else given dirent is returned
*/ */
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e); struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
/** /**
Runs a consistency check on given filesystem. * Runs a consistency check on given filesystem.
@param fs the file system struct * @param fs the file system struct
*/ */
s32_t SPIFFS_check(spiffs *fs); s32_t SPIFFS_check(spiffs *fs);
/** /**
Returns number of total bytes available and number of used bytes. * Returns number of total bytes available and number of used bytes.
This is an estimation, and depends on if there a many files with little * This is an estimation, and depends on if there a many files with little
data or few files with much data. * data or few files with much data.
NB: If used number of bytes exceeds total bytes, a SPIFFS_check should * NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
run. This indicates a power loss in midst of things. In worst case * run. This indicates a power loss in midst of things. In worst case
(repeated powerlosses in mending or gc) you might have to delete some files. * (repeated powerlosses in mending or gc) you might have to delete some files.
*
@param fs the file system struct * @param fs the file system struct
@param total total number of bytes in filesystem * @param total total number of bytes in filesystem
@param used used number of bytes in filesystem * @param used used number of bytes in filesystem
*/ */
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used); s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
/** /**
Formats the entire file system. All data will be lost. * Formats the entire file system. All data will be lost.
The filesystem must not be mounted when calling this. * The filesystem must not be mounted when calling this.
*
NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount * NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
MUST be called prior to formatting in order to configure the filesystem. * MUST be called prior to formatting in order to configure the filesystem.
If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling * If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
SPIFFS_format. * SPIFFS_format.
If SPIFFS_mount fails, SPIFFS_format can be called directly without calling * If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
SPIFFS_unmount first. * SPIFFS_unmount first.
*
@param fs the file system struct * @param fs the file system struct
*/ */
s32_t SPIFFS_format(spiffs *fs); s32_t SPIFFS_format(spiffs *fs);
/** /**
Returns nonzero if spiffs is mounted, or zero if unmounted. * Returns nonzero if spiffs is mounted, or zero if unmounted.
@param fs the file system struct * @param fs the file system struct
*/ */
u8_t SPIFFS_mounted(spiffs *fs); u8_t SPIFFS_mounted(spiffs *fs);
/** /**
Tries to find a block where most or all pages are deleted, and erase that * Tries to find a block where most or all pages are deleted, and erase that
block if found. Does not care for wear levelling. Will not move pages * block if found. Does not care for wear levelling. Will not move pages
around. * around.
If parameter max_free_pages are set to 0, only blocks with only deleted * If parameter max_free_pages are set to 0, only blocks with only deleted
pages will be selected. * pages will be selected.
*
NB: the garbage collector is automatically called when spiffs needs free * NB: the garbage collector is automatically called when spiffs needs free
pages. The reason for this function is to give possibility to do background * pages. The reason for this function is to give possibility to do background
tidying when user knows the system is idle. * tidying when user knows the system is idle.
*
Use with care. * Use with care.
*
Setting max_free_pages to anything larger than zero will eventually wear * Setting max_free_pages to anything larger than zero will eventually wear
flash more as a block containing free pages can be erased. * flash more as a block containing free pages can be erased.
*
Will set err_no to SPIFFS_OK if a block was found and erased, * Will set err_no to SPIFFS_OK if a block was found and erased,
SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found, * SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
or other error. * or other error.
*
@param fs the file system struct * @param fs the file system struct
@param max_free_pages maximum number allowed free pages in block * @param max_free_pages maximum number allowed free pages in block
*/ */
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages); s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
/** /**
Will try to make room for given amount of bytes in the filesystem by moving * Will try to make room for given amount of bytes in the filesystem by moving
pages and erasing blocks. * pages and erasing blocks.
If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If * If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
there already is this amount (or more) of free space, SPIFFS_gc will * there already is this amount (or more) of free space, SPIFFS_gc will
silently return. It is recommended to call SPIFFS_info before invoking * silently return. It is recommended to call SPIFFS_info before invoking
this method in order to determine what amount of bytes to give. * this method in order to determine what amount of bytes to give.
*
NB: the garbage collector is automatically called when spiffs needs free * NB: the garbage collector is automatically called when spiffs needs free
pages. The reason for this function is to give possibility to do background * pages. The reason for this function is to give possibility to do background
tidying when user knows the system is idle. * tidying when user knows the system is idle.
*
Use with care. * Use with care.
*
@param fs the file system struct * @param fs the file system struct
@param size amount of bytes that should be freed * @param size amount of bytes that should be freed
*/ */
s32_t SPIFFS_gc(spiffs *fs, u32_t size); s32_t SPIFFS_gc(spiffs *fs, u32_t size);
/** /**
Check if EOF reached. * Check if EOF reached.
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle of the file to check * @param fh the filehandle of the file to check
*/ */
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh); s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
/** /**
Get position in file. * Get position in file.
@param fs the file system struct * @param fs the file system struct
@param fh the filehandle of the file to check * @param fh the filehandle of the file to check
*/ */
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh); s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
/** /**
Registers a callback function that keeps track on operations on file * Registers a callback function that keeps track on operations on file
headers. Do note, that this callback is called from within internal spiffs * headers. Do note, that this callback is called from within internal spiffs
mechanisms. Any operations on the actual file system being callbacked from * mechanisms. Any operations on the actual file system being callbacked from
in this callback will mess things up for sure - do not do this. * in this callback will mess things up for sure - do not do this.
This can be used to track where files are and move around during garbage * This can be used to track where files are and move around during garbage
collection, which in turn can be used to build location tables in ram. * collection, which in turn can be used to build location tables in ram.
Used in conjuction with SPIFFS_open_by_page this may improve performance * Used in conjuction with SPIFFS_open_by_page this may improve performance
when opening a lot of files. * when opening a lot of files.
Must be invoked after mount. * Must be invoked after mount.
*
@param fs the file system struct * @param fs the file system struct
@param cb_func the callback on file operations * @param cb_func the callback on file operations
*/ */
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func); s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
#if SPIFFS_IX_MAP #if SPIFFS_IX_MAP
/** /**
Maps the first level index lookup to a given memory map. * Maps the first level index lookup to a given memory map.
This will make reading big files faster, as the memory map will be used for * This will make reading big files faster, as the memory map will be used for
looking up data pages instead of searching for the indices on the physical * looking up data pages instead of searching for the indices on the physical
medium. When mapping, all affected indicies are found and the information is * medium. When mapping, all affected indicies are found and the information is
copied to the array. * copied to the array.
Whole file or only parts of it may be mapped. The index map will cover file * Whole file or only parts of it may be mapped. The index map will cover file
contents from argument offset until and including arguments (offset+len). * contents from argument offset until and including arguments (offset+len).
It is valid to map a longer range than the current file size. The map will * It is valid to map a longer range than the current file size. The map will
then be populated when the file grows. * then be populated when the file grows.
On garbage collections and file data page movements, the map array will be * On garbage collections and file data page movements, the map array will be
automatically updated. Do not tamper with the map array, as this contains * automatically updated. Do not tamper with the map array, as this contains
the references to the data pages. Modifying it from outside will corrupt any * the references to the data pages. Modifying it from outside will corrupt any
future readings using this file descriptor. * future readings using this file descriptor.
The map will no longer be used when the file descriptor closed or the file * The map will no longer be used when the file descriptor closed or the file
is unmapped. * is unmapped.
This can be useful to get faster and more deterministic timing when reading * This can be useful to get faster and more deterministic timing when reading
large files, or when seeking and reading a lot within a file. * large files, or when seeking and reading a lot within a file.
@param fs the file system struct * @param fs the file system struct
@param fh the file handle of the file to map * @param fh the file handle of the file to map
@param map a spiffs_ix_map struct, describing the index map * @param map a spiffs_ix_map struct, describing the index map
@param offset absolute file offset where to start the index map * @param offset absolute file offset where to start the index map
@param len length of the mapping in actual file bytes * @param len length of the mapping in actual file bytes
@param map_buf the array buffer for the look up data - number of required * @param map_buf the array buffer for the look up data - number of required
elements in the array can be derived from function * elements in the array can be derived from function
SPIFFS_bytes_to_ix_map_entries given the length * SPIFFS_bytes_to_ix_map_entries given the length
*/ */
s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map, s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
u32_t offset, u32_t len, spiffs_page_ix *map_buf); u32_t offset, u32_t len, spiffs_page_ix *map_buf);
/** /**
Unmaps the index lookup from this filehandle. All future readings will * Unmaps the index lookup from this filehandle. All future readings will
proceed as normal, requiring reading of the first level indices from * proceed as normal, requiring reading of the first level indices from
physical media. * physical media.
The map and map buffer given in function SPIFFS_ix_map will no longer be * The map and map buffer given in function SPIFFS_ix_map will no longer be
referenced by spiffs. * referenced by spiffs.
It is not strictly necessary to unmap a file before closing it, as closing * It is not strictly necessary to unmap a file before closing it, as closing
a file will automatically unmap it. * a file will automatically unmap it.
@param fs the file system struct * @param fs the file system struct
@param fh the file handle of the file to unmap * @param fh the file handle of the file to unmap
*/ */
s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh); s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);
/** /**
Moves the offset for the index map given in function SPIFFS_ix_map. Parts or * Moves the offset for the index map given in function SPIFFS_ix_map. Parts or
all of the map buffer will repopulated. * all of the map buffer will repopulated.
@param fs the file system struct * @param fs the file system struct
@param fh the mapped file handle of the file to remap * @param fh the mapped file handle of the file to remap
@param offset new absolute file offset where to start the index map * @param offset new absolute file offset where to start the index map
*/ */
s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs); s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);
/** /**
Utility function to get number of spiffs_page_ix entries a map buffer must * Utility function to get number of spiffs_page_ix entries a map buffer must
contain on order to map given amount of file data in bytes. * contain on order to map given amount of file data in bytes.
See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes. * See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.
@param fs the file system struct * @param fs the file system struct
@param bytes number of file data bytes to map * @param bytes number of file data bytes to map
@return needed number of elements in a spiffs_page_ix array needed to * @return needed number of elements in a spiffs_page_ix array needed to
map given amount of bytes in a file * map given amount of bytes in a file
*/ */
s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes); s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);
/** /**
Utility function to amount of file data bytes that can be mapped when * Utility function to amount of file data bytes that can be mapped when
mapping a file with buffer having given number of spiffs_page_ix entries. * mapping a file with buffer having given number of spiffs_page_ix entries.
See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries. * See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.
@param fs the file system struct * @param fs the file system struct
@param map_page_ix_entries number of entries in a spiffs_page_ix array * @param map_page_ix_entries number of entries in a spiffs_page_ix array
@return amount of file data in bytes that can be mapped given a map * @return amount of file data in bytes that can be mapped given a map
buffer having given amount of spiffs_page_ix entries * buffer having given amount of spiffs_page_ix entries
*/ */
s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries); s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
#endif // SPIFFS_IX_MAP #endif // SPIFFS_IX_MAP
@ -794,24 +785,24 @@ s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
#if SPIFFS_TEST_VISUALISATION #if SPIFFS_TEST_VISUALISATION
/** /**
Prints out a visualization of the filesystem. * Prints out a visualization of the filesystem.
@param fs the file system struct * @param fs the file system struct
*/ */
s32_t SPIFFS_vis(spiffs *fs); s32_t SPIFFS_vis(spiffs *fs);
#endif #endif
#if SPIFFS_BUFFER_HELP #if SPIFFS_BUFFER_HELP
/** /**
Returns number of bytes needed for the filedescriptor buffer given * Returns number of bytes needed for the filedescriptor buffer given
amount of file descriptors. * amount of file descriptors.
*/ */
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs); u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);
#if SPIFFS_CACHE #if SPIFFS_CACHE
/** /**
Returns number of bytes needed for the cache buffer given * Returns number of bytes needed for the cache buffer given
amount of cache pages. * amount of cache pages.
*/ */
u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages); u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
#endif #endif
#endif #endif

View File

@ -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,22 +12,16 @@
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); spiffs_cache *cache = spiffs_get_cache(fs);
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
{
return 0;
}
int i; int i;
for (i = 0; i < cache->cpage_count; i++) for (i = 0; i < cache->cpage_count; i++) {
{
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
if ((cache->cpage_use_map & (1 << i)) && if ((cache->cpage_use_map & (1<<i)) &&
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
cp->pix == pix) cp->pix == pix ) {
{
//SPIFFS_CACHE_DBG("CACHE_GET: have cache page " _SPIPRIi " for " _SPIPRIpg"\n", i, pix); //SPIFFS_CACHE_DBG("CACHE_GET: have cache page " _SPIPRIi " for " _SPIPRIpg"\n", i, pix);
cp->last_access = cache->last_access; cp->last_access = cache->last_access;
return cp; return cp;
@ -35,31 +29,26 @@ extern "C" {
} }
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for " _SPIPRIpg"\n", pix); //SPIFFS_CACHE_DBG("CACHE_GET: no cache for " _SPIPRIpg"\n", pix);
return 0; return 0;
} }
// frees cached page // frees cached page
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
{
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
spiffs_cache *cache = spiffs_get_cache(fs); spiffs_cache *cache = spiffs_get_cache(fs);
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix); spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
if (cache->cpage_use_map & (1 << ix)) if (cache->cpage_use_map & (1<<ix)) {
{
if (write_back && if (write_back &&
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) (cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
{
u8_t *mem = spiffs_get_cache_page(fs, cache, ix); 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); 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); 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
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
{
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " objid " _SPIPRIid "\n", ix, cp->obj_id); SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " objid " _SPIPRIid "\n", ix, cp->obj_id);
} } else
else
#endif #endif
{ {
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " pix " _SPIPRIpg "\n", ix, cp->pix); SPIFFS_CACHE_DBG("CACHE_FREE: free cache page " _SPIPRIi " pix " _SPIPRIpg "\n", ix, cp->pix);
@ -69,16 +58,14 @@ extern "C" {
} }
return res; return res;
} }
// removes the oldest accessed cached page // removes the oldest accessed cached page
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
{
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
spiffs_cache *cache = spiffs_get_cache(fs); spiffs_cache *cache = spiffs_get_cache(fs);
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
{
// at least one free cpage // at least one free cpage
return SPIFFS_OK; return SPIFFS_OK;
} }
@ -87,41 +74,34 @@ extern "C" {
int i; int i;
int cand_ix = -1; int cand_ix = -1;
u32_t oldest_val = 0; u32_t oldest_val = 0;
for (i = 0; i < cache->cpage_count; i++) for (i = 0; i < cache->cpage_count; i++) {
{
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
if ((cache->last_access - cp->last_access) > oldest_val && if ((cache->last_access - cp->last_access) > oldest_val &&
(cp->flags & flag_mask) == flags) (cp->flags & flag_mask) == flags) {
{
oldest_val = cache->last_access - cp->last_access; oldest_val = cache->last_access - cp->last_access;
cand_ix = i; cand_ix = i;
} }
} }
if (cand_ix >= 0) if (cand_ix >= 0) {
{
res = spiffs_cache_page_free(fs, cand_ix, 1); res = spiffs_cache_page_free(fs, cand_ix, 1);
} }
return res; return res;
} }
// allocates a new cached page and returns it, or null if all cache pages are busy // allocates a new cached page and returns it, or null if all cache pages are busy
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
{
spiffs_cache *cache = spiffs_get_cache(fs); spiffs_cache *cache = spiffs_get_cache(fs);
if (cache->cpage_use_map == 0xffffffff) if (cache->cpage_use_map == 0xffffffff) {
{
// out of cache memory // out of cache memory
return 0; return 0;
} }
int i; int i;
for (i = 0; i < cache->cpage_count; i++) for (i = 0; i < cache->cpage_count; i++) {
{ if ((cache->cpage_use_map & (1<<i)) == 0) {
if ((cache->cpage_use_map & (1 << i)) == 0)
{
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
cache->cpage_use_map |= (1 << i); cache->cpage_use_map |= (1<<i);
cp->last_access = cache->last_access; cp->last_access = cache->last_access;
//SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi"\n", i); //SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi"\n", i);
return cp; return cp;
@ -129,36 +109,32 @@ extern "C" {
} }
// out of cache entries // out of cache entries
return 0; return 0;
} }
// drops the cache page for give page index // drops the cache page for give page index
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
{
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix); spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
if (cp) if (cp) {
{
spiffs_cache_page_free(fs, cp->ix, 0); spiffs_cache_page_free(fs, cp->ix, 0);
} }
} }
// ------------------------------ // ------------------------------
// reads from spi flash or the cache // reads from spi flash or the cache
s32_t spiffs_phys_rd( s32_t spiffs_phys_rd(
spiffs *fs, spiffs *fs,
u8_t op, u8_t op,
spiffs_file fh, spiffs_file fh,
u32_t addr, u32_t addr,
u32_t len, u32_t len,
u8_t *dst) u8_t *dst) {
{
(void)fh; (void)fh;
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
spiffs_cache *cache = spiffs_get_cache(fs); spiffs_cache *cache = spiffs_get_cache(fs);
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr)); spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
cache->last_access++; cache->last_access++;
if (cp) if (cp) {
{
// we've already got one, you see // we've already got one, you see
#if SPIFFS_CACHE_STATS #if SPIFFS_CACHE_STATS
fs->cache_hits++; fs->cache_hits++;
@ -166,11 +142,8 @@ extern "C" {
cp->last_access = cache->last_access; cp->last_access = cache->last_access;
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
_SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
} } else {
else if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
{
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 // for second layer lookup functions, we do not cache in order to prevent shredding
return SPIFFS_HAL_READ(fs, addr, len, dst); return SPIFFS_HAL_READ(fs, addr, len, dst);
} }
@ -182,8 +155,7 @@ extern "C" {
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0); res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
cp = spiffs_cache_page_allocate(fs); cp = spiffs_cache_page_allocate(fs);
if (cp) if (cp) {
{
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU; cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr); 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); SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi " for pix " _SPIPRIpg "\n", cp->ix, cp->pix);
@ -192,50 +164,43 @@ extern "C" {
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr), addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
SPIFFS_CFG_LOG_PAGE_SZ(fs), SPIFFS_CFG_LOG_PAGE_SZ(fs),
spiffs_get_cache_page(fs, cache, cp->ix)); spiffs_get_cache_page(fs, cache, cp->ix));
if (res2 != SPIFFS_OK) if (res2 != SPIFFS_OK) {
{
// honor read failure before possible write failure (bad idea?) // honor read failure before possible write failure (bad idea?)
res = res2; res = res2;
} }
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
_SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
} } else {
else
{
// this will never happen, last resort for sake of symmetry // this will never happen, last resort for sake of symmetry
s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst); s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
if (res2 != SPIFFS_OK) if (res2 != SPIFFS_OK) {
{
// honor read failure before possible write failure (bad idea?) // honor read failure before possible write failure (bad idea?)
res = res2; res = res2;
} }
} }
} }
return res; return res;
} }
// writes to spi flash and/or the cache // writes to spi flash and/or the cache
s32_t spiffs_phys_wr( s32_t spiffs_phys_wr(
spiffs *fs, spiffs *fs,
u8_t op, u8_t op,
spiffs_file fh, spiffs_file fh,
u32_t addr, u32_t addr,
u32_t len, u32_t len,
u8_t *src) u8_t *src) {
{
(void)fh; (void)fh;
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr); spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
spiffs_cache *cache = spiffs_get_cache(fs); spiffs_cache *cache = spiffs_get_cache(fs);
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix); spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {
{
// have a cache page // have a cache page
// copy in data to cache page // copy in data to cache page
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE && if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) (op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
{
// page is being deleted, wipe from cache - unless it is a lookup page // page is being deleted, wipe from cache - unless it is a lookup page
spiffs_cache_page_free(fs, cp->ix, 0); spiffs_cache_page_free(fs, cp->ix, 0);
return SPIFFS_HAL_WRITE(fs, addr, len, src); return SPIFFS_HAL_WRITE(fs, addr, len, src);
@ -247,60 +212,49 @@ extern "C" {
cache->last_access++; cache->last_access++;
cp->last_access = cache->last_access; cp->last_access = cache->last_access;
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
{
// page is being updated, no write-cache, just pass thru // page is being updated, no write-cache, just pass thru
return SPIFFS_HAL_WRITE(fs, addr, len, src); return SPIFFS_HAL_WRITE(fs, addr, len, src);
} } else {
else
{
return SPIFFS_OK; return SPIFFS_OK;
} }
} } else {
else
{
// no cache page, no write cache - just write thru // no cache page, no write cache - just write thru
return SPIFFS_HAL_WRITE(fs, addr, len, src); return SPIFFS_HAL_WRITE(fs, addr, len, src);
} }
} }
#if SPIFFS_CACHE_WR #if SPIFFS_CACHE_WR
// returns the cache page that this fd refers, or null if no cache page // returns the cache page that this fd refers, or null if no cache page
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
{
spiffs_cache *cache = spiffs_get_cache(fs); spiffs_cache *cache = spiffs_get_cache(fs);
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
{
// all cpages free, no cpage cannot be assigned to obj_id // all cpages free, no cpage cannot be assigned to obj_id
return 0; return 0;
} }
int i; int i;
for (i = 0; i < cache->cpage_count; i++) for (i = 0; i < cache->cpage_count; i++) {
{
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
if ((cache->cpage_use_map & (1 << i)) && if ((cache->cpage_use_map & (1<<i)) &&
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) && (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
cp->obj_id == fd->obj_id) cp->obj_id == fd->obj_id) {
{
return cp; return cp;
} }
} }
return 0; return 0;
} }
// allocates a new cache page and refers this to given fd - flushes an old cache // allocates a new cache page and refers this to given fd - flushes an old cache
// page if all cache is busy // page if all cache is busy
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
{
// before this function is called, it is ensured that there is no already existing // before this function is called, it is ensured that there is no already existing
// cache page with same object id // cache page with same object id
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0); spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs); spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
if (cp == 0) if (cp == 0) {
{
// could not get cache page // could not get cache page
return 0; return 0;
} }
@ -310,51 +264,37 @@ extern "C" {
fd->cache_page = cp; 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); SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page " _SPIPRIi " for fd " _SPIPRIfd ":" _SPIPRIid "\n", cp->ix, fd->file_nbr, fd->obj_id);
return cp; return cp;
} }
// unrefers all fds that this cache page refers to and releases the cache page // 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) void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
{ if (cp == 0) return;
if (cp == 0)
{
return;
}
u32_t i; u32_t i;
spiffs_fd *fds = (spiffs_fd *)fs->fd_space; spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
for (i = 0; i < fs->fd_count; i++) for (i = 0; i < fs->fd_count; i++) {
{
spiffs_fd *cur_fd = &fds[i]; spiffs_fd *cur_fd = &fds[i];
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
{
cur_fd->cache_page = 0; cur_fd->cache_page = 0;
} }
} }
spiffs_cache_page_free(fs, cp->ix, 0); spiffs_cache_page_free(fs, cp->ix, 0);
cp->obj_id = 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;
if (fs->cache == 0)
{
return;
}
u32_t sz = fs->cache_size; u32_t sz = fs->cache_size;
u32_t cache_mask = 0; u32_t cache_mask = 0;
int i; int i;
int cache_entries = int cache_entries =
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs)); (sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
if (cache_entries <= 0) if (cache_entries <= 0) return;
{
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;
} }
@ -373,11 +313,10 @@ extern "C" {
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

View File

@ -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_

View File

@ -5,13 +5,12 @@
extern "C" { extern "C" {
// Erases a logical block and updates the erase counter. // Erases a logical block and updates the erase counter.
// If cache is enabled, all pages that might be cached in this block // If cache is enabled, all pages that might be cached in this block
// is dropped. // is dropped.
static s32_t spiffs_gc_erase_block( static s32_t spiffs_gc_erase_block(
spiffs *fs, spiffs *fs,
spiffs_block_ix bix) spiffs_block_ix bix) {
{
s32_t res; s32_t res;
SPIFFS_GC_DBG("gc: erase block " _SPIPRIbl "\n", bix); SPIFFS_GC_DBG("gc: erase block " _SPIPRIbl "\n", bix);
@ -21,21 +20,19 @@ extern "C" {
#if SPIFFS_CACHE #if SPIFFS_CACHE
{ {
u32_t i; u32_t i;
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
{
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i); spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);
} }
} }
#endif #endif
return res; return res;
} }
// Searches for blocks where all entries are deleted - if one is found, // Searches for blocks where all entries are deleted - if one is found,
// the block is erased. Compared to the non-quick gc, the quick one ensures // the block is erased. Compared to the non-quick gc, the quick one ensures
// that no updates are needed on existing objects on pages that are erased. // that no updates are needed on existing objects on pages that are erased.
s32_t spiffs_gc_quick( s32_t spiffs_gc_quick(
spiffs *fs, u16_t max_free_pages) spiffs *fs, u16_t max_free_pages) {
{
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
u32_t blocks = fs->block_count; u32_t blocks = fs->block_count;
spiffs_block_ix cur_block = 0; spiffs_block_ix cur_block = 0;
@ -52,41 +49,32 @@ extern "C" {
// find fully deleted blocks // find fully deleted blocks
// check each block // check each block
while (res == SPIFFS_OK && blocks--) while (res == SPIFFS_OK && blocks--) {
{
u16_t deleted_pages_in_block = 0; u16_t deleted_pages_in_block = 0;
u16_t free_pages_in_block = 0; u16_t free_pages_in_block = 0;
int obj_lookup_page = 0; int obj_lookup_page = 0;
// check each object lookup page // check each object lookup page
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
{
int entry_offset = obj_lookup_page * entries_per_page; int entry_offset = obj_lookup_page * entries_per_page;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
// check each entry // check each entry
while (res == SPIFFS_OK && while (res == SPIFFS_OK &&
cur_entry - entry_offset < entries_per_page && cur_entry - entry_offset < entries_per_page &&
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs))) cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
{ spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
spiffs_obj_id obj_id = obj_lu_buf[cur_entry - entry_offset]; if (obj_id == SPIFFS_OBJ_ID_DELETED) {
if (obj_id == SPIFFS_OBJ_ID_DELETED)
{
deleted_pages_in_block++; deleted_pages_in_block++;
} } else if (obj_id == SPIFFS_OBJ_ID_FREE) {
else if (obj_id == SPIFFS_OBJ_ID_FREE)
{
// kill scan, go for next block // kill scan, go for next block
free_pages_in_block++; free_pages_in_block++;
if (free_pages_in_block > max_free_pages) if (free_pages_in_block > max_free_pages) {
{
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
res = 1; // kill object lu loop res = 1; // kill object lu loop
break; break;
} }
} } else {
else
{
// kill scan, go for next block // kill scan, go for next block
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
res = 1; // kill object lu loop res = 1; // kill object lu loop
@ -96,15 +84,11 @@ extern "C" {
} // per entry } // per entry
obj_lookup_page++; obj_lookup_page++;
} // per object lookup page } // per object lookup page
if (res == 1) if (res == 1) res = SPIFFS_OK;
{
res = SPIFFS_OK;
}
if (res == SPIFFS_OK && if (res == SPIFFS_OK &&
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) && deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
free_pages_in_block <= max_free_pages) free_pages_in_block <= max_free_pages) {
{
// found a fully deleted block // found a fully deleted block
fs->stats_p_deleted -= deleted_pages_in_block; fs->stats_p_deleted -= deleted_pages_in_block;
res = spiffs_gc_erase_block(fs, cur_block); res = spiffs_gc_erase_block(fs, cur_block);
@ -116,48 +100,43 @@ extern "C" {
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
} // per block } // per block
if (res == SPIFFS_OK) if (res == SPIFFS_OK) {
{
res = SPIFFS_ERR_NO_DELETED_BLOCKS; res = SPIFFS_ERR_NO_DELETED_BLOCKS;
} }
return res; return res;
} }
// Checks if garbage collecting is necessary. If so a candidate block is found, // Checks if garbage collecting is necessary. If so a candidate block is found,
// cleansed and erased // cleansed and erased
s32_t spiffs_gc_check( s32_t spiffs_gc_check(
spiffs *fs, spiffs *fs,
u32_t len) u32_t len) {
{
s32_t res; s32_t res;
s32_t free_pages = s32_t free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
- fs->stats_p_allocated - fs->stats_p_deleted; - fs->stats_p_allocated - fs->stats_p_deleted;
int tries = 0; int tries = 0;
if (fs->free_blocks > 3 && if (fs->free_blocks > 3 &&
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
{
return SPIFFS_OK; return SPIFFS_OK;
} }
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs); u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) { // if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
// SPIFFS_GC_DBG("gc: full freeblk:" _SPIPRIi " needed:" _SPIPRIi " free:" _SPIPRIi " dele:" _SPIPRIi "\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); // SPIFFS_GC_DBG("gc: full freeblk:" _SPIPRIi " needed:" _SPIPRIi " free:" _SPIPRIi " dele:" _SPIPRIi "\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
// return SPIFFS_ERR_FULL; // return SPIFFS_ERR_FULL;
// } // }
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
{
SPIFFS_GC_DBG("gc_check: full freeblk:" _SPIPRIi " needed:" _SPIPRIi " free:" _SPIPRIi " dele:" _SPIPRIi "\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); SPIFFS_GC_DBG("gc_check: full freeblk:" _SPIPRIi " needed:" _SPIPRIi " free:" _SPIPRIi " dele:" _SPIPRIi "\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
return SPIFFS_ERR_FULL; return SPIFFS_ERR_FULL;
} }
do do {
{
SPIFFS_GC_DBG("\ngc_check #" _SPIPRIi": run gc free_blocks:" _SPIPRIi " pfree:" _SPIPRIi " pallo:" _SPIPRIi " pdele:" _SPIPRIi " [" _SPIPRIi"] len:" _SPIPRIi " of " _SPIPRIi "\n", SPIFFS_GC_DBG("\ngc_check #" _SPIPRIi": run gc free_blocks:" _SPIPRIi " pfree:" _SPIPRIi " pallo:" _SPIPRIi " pdele:" _SPIPRIi " [" _SPIPRIi"] len:" _SPIPRIi " of " _SPIPRIi "\n",
tries, tries,
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages + fs->stats_p_allocated + fs->stats_p_deleted), fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
len, (u32_t)(free_pages * SPIFFS_DATA_PAGE_SIZE(fs))); len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));
spiffs_block_ix *cands; spiffs_block_ix *cands;
int count; int count;
@ -166,8 +145,7 @@ extern "C" {
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state // if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0); res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
if (count == 0) if (count == 0) {
{
SPIFFS_GC_DBG("gc_check: no candidates, return\n"); SPIFFS_GC_DBG("gc_check: no candidates, return\n");
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL; return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
} }
@ -179,12 +157,9 @@ extern "C" {
//SPIFFS_GC_DBG("gcing: cleaning block " _SPIPRIi "\n", cand); //SPIFFS_GC_DBG("gcing: cleaning block " _SPIPRIi "\n", cand);
res = spiffs_gc_clean(fs, cand); res = spiffs_gc_clean(fs, cand);
fs->cleaning = 0; fs->cleaning = 0;
if (res < 0) if (res < 0) {
{
SPIFFS_GC_DBG("gc_check: cleaning block " _SPIPRIi ", result " _SPIPRIi "\n", cand, res); SPIFFS_GC_DBG("gc_check: cleaning block " _SPIPRIi ", result " _SPIPRIi "\n", cand, res);
} } else {
else
{
SPIFFS_GC_DBG("gc_check: cleaning block " _SPIPRIi ", result " _SPIPRIi "\n", cand, res); SPIFFS_GC_DBG("gc_check: cleaning block " _SPIPRIi ", result " _SPIPRIi "\n", cand, res);
} }
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
@ -199,21 +174,19 @@ extern "C" {
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
- fs->stats_p_allocated - fs->stats_p_deleted; - fs->stats_p_allocated - fs->stats_p_deleted;
if (prev_free_pages <= 0 && prev_free_pages == free_pages) if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
{
// abort early to reduce wear, at least tried once // abort early to reduce wear, at least tried once
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n"); SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
break; break;
} }
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
(s32_t)len > free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs))); (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
free_pages = free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
- fs->stats_p_allocated - fs->stats_p_deleted; - fs->stats_p_allocated - fs->stats_p_deleted;
if ((s32_t)len > free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
{
res = SPIFFS_ERR_FULL; res = SPIFFS_ERR_FULL;
} }
@ -222,13 +195,12 @@ extern "C" {
fs->free_blocks, free_pages, tries, res); fs->free_blocks, free_pages, tries, res);
return res; return res;
} }
// Updates page statistics for a block that is about to be erased // Updates page statistics for a block that is about to be erased
s32_t spiffs_gc_erase_page_stats( s32_t spiffs_gc_erase_page_stats(
spiffs *fs, spiffs *fs,
spiffs_block_ix bix) spiffs_block_ix bix) {
{
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
int obj_lookup_page = 0; int obj_lookup_page = 0;
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
@ -238,25 +210,18 @@ extern "C" {
u32_t allo = 0; u32_t allo = 0;
// check each object lookup page // check each object lookup page
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
{
int entry_offset = obj_lookup_page * entries_per_page; int entry_offset = obj_lookup_page * entries_per_page;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
// check each entry // check each entry
while (res == SPIFFS_OK && while (res == SPIFFS_OK &&
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs))) cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
{ spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
spiffs_obj_id obj_id = obj_lu_buf[cur_entry - entry_offset]; if (obj_id == SPIFFS_OBJ_ID_FREE) {
if (obj_id == SPIFFS_OBJ_ID_FREE) } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
{
}
else if (obj_id == SPIFFS_OBJ_ID_DELETED)
{
dele++; dele++;
} } else {
else
{
allo++; allo++;
} }
cur_entry++; cur_entry++;
@ -267,15 +232,14 @@ extern "C" {
fs->stats_p_allocated -= allo; fs->stats_p_allocated -= allo;
fs->stats_p_deleted -= dele; fs->stats_p_deleted -= dele;
return res; return res;
} }
// Finds block candidates to erase // Finds block candidates to erase
s32_t spiffs_gc_find_candidate( s32_t spiffs_gc_find_candidate(
spiffs *fs, spiffs *fs,
spiffs_block_ix **block_candidates, spiffs_block_ix **block_candidates,
int *candidate_count, int *candidate_count,
char fs_crammed) char fs_crammed) {
{
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
u32_t blocks = fs->block_count; u32_t blocks = fs->block_count;
spiffs_block_ix cur_block = 0; spiffs_block_ix cur_block = 0;
@ -284,7 +248,7 @@ extern "C" {
int cur_entry = 0; int cur_entry = 0;
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs) - 8) / (sizeof(spiffs_block_ix) + sizeof(s32_t))); int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
*candidate_count = 0; *candidate_count = 0;
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
@ -300,51 +264,39 @@ extern "C" {
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
// check each block // check each block
while (res == SPIFFS_OK && blocks--) while (res == SPIFFS_OK && blocks--) {
{
u16_t deleted_pages_in_block = 0; u16_t deleted_pages_in_block = 0;
u16_t used_pages_in_block = 0; u16_t used_pages_in_block = 0;
int obj_lookup_page = 0; int obj_lookup_page = 0;
// check each object lookup page // check each object lookup page
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
{
int entry_offset = obj_lookup_page * entries_per_page; int entry_offset = obj_lookup_page * entries_per_page;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
// check each entry // check each entry
while (res == SPIFFS_OK && while (res == SPIFFS_OK &&
cur_entry - entry_offset < entries_per_page && cur_entry - entry_offset < entries_per_page &&
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs))) cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
{ spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
spiffs_obj_id obj_id = obj_lu_buf[cur_entry - entry_offset]; if (obj_id == SPIFFS_OBJ_ID_FREE) {
if (obj_id == SPIFFS_OBJ_ID_FREE)
{
// when a free entry is encountered, scan logic ensures that all following entries are free also // when a free entry is encountered, scan logic ensures that all following entries are free also
res = 1; // kill object lu loop res = 1; // kill object lu loop
break; break;
} } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
else if (obj_id == SPIFFS_OBJ_ID_DELETED)
{
deleted_pages_in_block++; deleted_pages_in_block++;
} } else {
else
{
used_pages_in_block++; used_pages_in_block++;
} }
cur_entry++; cur_entry++;
} // per entry } // per entry
obj_lookup_page++; obj_lookup_page++;
} // per object lookup page } // per object lookup page
if (res == 1) if (res == 1) res = SPIFFS_OK;
{
res = SPIFFS_OK;
}
// calculate score and insert into candidate table // calculate score and insert into candidate table
// stoneage sort, but probably not so many blocks // stoneage sort, but probably not so many blocks
if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {
{
// read erase count // read erase count
spiffs_obj_id erase_count; spiffs_obj_id erase_count;
res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
@ -353,12 +305,9 @@ extern "C" {
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
spiffs_obj_id erase_age; spiffs_obj_id erase_age;
if (fs->max_erase_count > erase_count) if (fs->max_erase_count > erase_count) {
{
erase_age = fs->max_erase_count - erase_count; erase_age = fs->max_erase_count - erase_count;
} } else {
else
{
erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count); erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
} }
@ -368,19 +317,14 @@ extern "C" {
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE); erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
int cand_ix = 0; int cand_ix = 0;
SPIFFS_GC_DBG("gc_check: bix:" _SPIPRIbl" del:" _SPIPRIi " use:" _SPIPRIi " score:" _SPIPRIi "\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); SPIFFS_GC_DBG("gc_check: bix:" _SPIPRIbl" del:" _SPIPRIi " use:" _SPIPRIi " score:" _SPIPRIi "\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
while (cand_ix < max_candidates) while (cand_ix < max_candidates) {
{ if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
if (cand_blocks[cand_ix] == (spiffs_block_ix) - 1)
{
cand_blocks[cand_ix] = cur_block; cand_blocks[cand_ix] = cur_block;
cand_scores[cand_ix] = score; cand_scores[cand_ix] = score;
break; break;
} } else if (cand_scores[cand_ix] < score) {
else if (cand_scores[cand_ix] < score)
{
int reorder_cand_ix = max_candidates - 2; int reorder_cand_ix = max_candidates - 2;
while (reorder_cand_ix >= cand_ix) while (reorder_cand_ix >= cand_ix) {
{
cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix]; cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix]; cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
reorder_cand_ix--; reorder_cand_ix--;
@ -400,18 +344,16 @@ extern "C" {
} // per block } // per block
return res; return res;
} }
typedef enum typedef enum {
{
FIND_OBJ_DATA, FIND_OBJ_DATA,
MOVE_OBJ_DATA, MOVE_OBJ_DATA,
MOVE_OBJ_IX, MOVE_OBJ_IX,
FINISHED FINISHED
} spiffs_gc_clean_state; } spiffs_gc_clean_state;
typedef struct typedef struct {
{
spiffs_gc_clean_state state; spiffs_gc_clean_state state;
spiffs_obj_id cur_obj_id; spiffs_obj_id cur_obj_id;
spiffs_span_ix cur_objix_spix; spiffs_span_ix cur_objix_spix;
@ -419,23 +361,22 @@ extern "C" {
spiffs_page_ix cur_data_pix; spiffs_page_ix cur_data_pix;
int stored_scan_entry_index; int stored_scan_entry_index;
u8_t obj_id_found; u8_t obj_id_found;
} spiffs_gc; } spiffs_gc;
// Empties given block by moving all data into free pages of another block // Empties given block by moving all data into free pages of another block
// Strategy: // Strategy:
// loop: // loop:
// scan object lookup for object data pages // scan object lookup for object data pages
// for first found id, check spix and load corresponding object index page to memory // for first found id, check spix and load corresponding object index page to memory
// push object scan lookup entry index // push object scan lookup entry index
// rescan object lookup, find data pages with same id and referenced by same object index // rescan object lookup, find data pages with same id and referenced by same object index
// move data page, update object index in memory // move data page, update object index in memory
// when reached end of lookup, store updated object index // when reached end of lookup, store updated object index
// pop object scan lookup entry index // pop object scan lookup entry index
// repeat loop until end of object lookup // repeat loop until end of object lookup
// scan object lookup again for remaining object index pages, move to new page in other block // scan object lookup again for remaining object index pages, move to new page in other block
// //
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
{
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
// this is the global localizer being pushed and popped // this is the global localizer being pushed and popped
@ -451,16 +392,14 @@ extern "C" {
memset(&gc, 0, sizeof(spiffs_gc)); memset(&gc, 0, sizeof(spiffs_gc));
gc.state = FIND_OBJ_DATA; gc.state = FIND_OBJ_DATA;
if (fs->free_cursor_block_ix == bix) if (fs->free_cursor_block_ix == bix) {
{
// move free cursor to next block, cannot use free pages from the block we want to clean // move free cursor to next block, cannot use free pages from the block we want to clean
fs->free_cursor_block_ix = (bix + 1) % fs->block_count; fs->free_cursor_block_ix = (bix+1)%fs->block_count;
fs->free_cursor_obj_lu_entry = 0; fs->free_cursor_obj_lu_entry = 0;
SPIFFS_GC_DBG("gc_clean: move free cursor to block " _SPIPRIbl "\n", fs->free_cursor_block_ix); SPIFFS_GC_DBG("gc_clean: move free cursor to block " _SPIPRIbl "\n", fs->free_cursor_block_ix);
} }
while (res == SPIFFS_OK && gc.state != FINISHED) while (res == SPIFFS_OK && gc.state != FINISHED) {
{
SPIFFS_GC_DBG("gc_clean: state = " _SPIPRIi " entry:" _SPIPRIi "\n", gc.state, cur_entry); SPIFFS_GC_DBG("gc_clean: state = " _SPIPRIi " entry:" _SPIPRIi "\n", gc.state, cur_entry);
gc.obj_id_found = 0; // reset (to no found data page) gc.obj_id_found = 0; // reset (to no found data page)
@ -468,27 +407,23 @@ extern "C" {
int obj_lookup_page = cur_entry / entries_per_page; int obj_lookup_page = cur_entry / entries_per_page;
u8_t scan = 1; u8_t scan = 1;
// check each object lookup page // check each object lookup page
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
{
int entry_offset = obj_lookup_page * entries_per_page; int entry_offset = obj_lookup_page * entries_per_page;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
// check each object lookup entry // check each object lookup entry
while (scan && res == SPIFFS_OK && while (scan && res == SPIFFS_OK &&
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs))) cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
{ spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
spiffs_obj_id obj_id = obj_lu_buf[cur_entry - entry_offset];
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry); cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
// act upon object id depending on gc state // act upon object id depending on gc state
switch (gc.state) switch (gc.state) {
{
case FIND_OBJ_DATA: case FIND_OBJ_DATA:
// find a data page // find a data page
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
{
// found a data page, stop scanning and handle in switch case below // found a data page, stop scanning and handle in switch case below
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:" _SPIPRIi " - found obj id " _SPIPRIid"\n", gc.state, obj_id); SPIFFS_GC_DBG("gc_clean: FIND_DATA state:" _SPIPRIi " - found obj id " _SPIPRIid"\n", gc.state, obj_id);
gc.obj_id_found = 1; gc.obj_id_found = 1;
@ -500,22 +435,17 @@ extern "C" {
case MOVE_OBJ_DATA: case MOVE_OBJ_DATA:
// evacuate found data pages for corresponding object index we have in memory, // evacuate found data pages for corresponding object index we have in memory,
// update memory representation // update memory representation
if (obj_id == gc.cur_obj_id) if (obj_id == gc.cur_obj_id) {
{
spiffs_page_header p_hdr; spiffs_page_header p_hdr;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page " _SPIPRIid":" _SPIPRIsp" @ " _SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix); SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page " _SPIPRIid":" _SPIPRIsp" @ " _SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
{
SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n"); SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n");
} } else {
else
{
spiffs_page_ix new_data_pix; spiffs_page_ix new_data_pix;
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
{
// move page // move page
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix); res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);
SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg" to " _SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix); SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg" to " _SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);
@ -525,9 +455,7 @@ extern "C" {
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
} } else {
else
{
// page is deleted but not deleted in lookup, scrap it - // page is deleted but not deleted in lookup, scrap it -
// might seem unnecessary as we will erase this block, but // might seem unnecessary as we will erase this block, but
// we might get aborted // we might get aborted
@ -537,14 +465,11 @@ extern "C" {
new_data_pix = SPIFFS_OBJ_ID_FREE; new_data_pix = SPIFFS_OBJ_ID_FREE;
} }
// update memory representation of object index page with new data page // update memory representation of object index page with new data page
if (gc.cur_objix_spix == 0) if (gc.cur_objix_spix == 0) {
{
// update object index header page // update object index header page
((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix; ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page " _SPIPRIpg" to objix_hdr entry " _SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page " _SPIPRIpg" to objix_hdr entry " _SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
} } else {
else
{
// update object index page // update object index page
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix; ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page " _SPIPRIpg" to objix entry " _SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page " _SPIPRIpg" to objix entry " _SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
@ -555,8 +480,7 @@ extern "C" {
case MOVE_OBJ_IX: case MOVE_OBJ_IX:
// find and evacuate object index pages // find and evacuate object index pages
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
(obj_id & SPIFFS_OBJ_ID_IX_FLAG)) (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
{
// found an index object id // found an index object id
spiffs_page_header p_hdr; spiffs_page_header p_hdr;
spiffs_page_ix new_pix; spiffs_page_ix new_pix;
@ -564,8 +488,7 @@ extern "C" {
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
{
// move page // move page
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix); res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg" to " _SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix); SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg" to " _SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
@ -577,16 +500,13 @@ extern "C" {
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
} } else {
else
{
// page is deleted but not deleted in lookup, scrap it - // page is deleted but not deleted in lookup, scrap it -
// might seem unnecessary as we will erase this block, but // might seem unnecessary as we will erase this block, but
// we might get aborted // we might get aborted
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix); SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix " _SPIPRIid":" _SPIPRIsp" page " _SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
res = spiffs_page_delete(fs, cur_pix); res = spiffs_page_delete(fs, cur_pix);
if (res == SPIFFS_OK) if (res == SPIFFS_OK) {
{
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0, spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0); SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
} }
@ -602,17 +522,12 @@ extern "C" {
} // per entry } // per entry
obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop
} // per object lookup page } // per object lookup page
if (res != SPIFFS_OK) if (res != SPIFFS_OK) break;
{
break;
}
// state finalization and switch // state finalization and switch
switch (gc.state) switch (gc.state) {
{
case FIND_OBJ_DATA: case FIND_OBJ_DATA:
if (gc.obj_id_found) if (gc.obj_id_found) {
{
// handle found data page - // handle found data page -
// find out corresponding obj ix page and load it to memory // find out corresponding obj ix page and load it to memory
spiffs_page_header p_hdr; spiffs_page_header p_hdr;
@ -626,8 +541,7 @@ extern "C" {
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix); gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:" _SPIPRIsp"\n", gc.cur_objix_spix); SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:" _SPIPRIsp"\n", gc.cur_objix_spix);
res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix); res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);
if (res == SPIFFS_ERR_NOT_FOUND) if (res == SPIFFS_ERR_NOT_FOUND) {
{
// on borked systems we might get an ERR_NOT_FOUND here - // on borked systems we might get an ERR_NOT_FOUND here -
// this is handled by simply deleting the page as it is not referenced // this is handled by simply deleting the page as it is not referenced
// from anywhere // from anywhere
@ -648,31 +562,25 @@ extern "C" {
// check must run or lot of data may be lost // check must run or lot of data may be lost
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix); SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);
gc.cur_objix_pix = objix_pix; gc.cur_objix_pix = objix_pix;
} } else {
else
{
// no more data pages found, passed thru all block, start evacuating object indices // no more data pages found, passed thru all block, start evacuating object indices
gc.state = MOVE_OBJ_IX; gc.state = MOVE_OBJ_IX;
cur_entry = 0; // restart entry scan index cur_entry = 0; // restart entry scan index
} }
break; break;
case MOVE_OBJ_DATA: case MOVE_OBJ_DATA: {
{
// store modified objix (hdr) page residing in memory now that all // store modified objix (hdr) page residing in memory now that all
// data pages belonging to this object index and residing in the block // data pages belonging to this object index and residing in the block
// we want to evacuate // we want to evacuate
spiffs_page_ix new_objix_pix; spiffs_page_ix new_objix_pix;
gc.state = FIND_OBJ_DATA; gc.state = FIND_OBJ_DATA;
cur_entry = gc.stored_scan_entry_index; // pop cursor cur_entry = gc.stored_scan_entry_index; // pop cursor
if (gc.cur_objix_spix == 0) if (gc.cur_objix_spix == 0) {
{
// store object index header page // store object index header page
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix); res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix);
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, " _SPIPRIpg":" _SPIPRIsp"\n", new_objix_pix, 0); SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, " _SPIPRIpg":" _SPIPRIsp"\n", new_objix_pix, 0);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
} } else {
else
{
// store object index page // store object index page
res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix); res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, " _SPIPRIpg":" _SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix); SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, " _SPIPRIpg":" _SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix);
@ -695,7 +603,7 @@ extern "C" {
return res; return res;
} }
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,112 +1,112 @@
/* /*
spiffs_nucleus.h * spiffs_nucleus.h
*
Created on: Jun 15, 2013 * Created on: Jun 15, 2013
Author: petera * Author: petera
*/ */
/* SPIFFS layout /* SPIFFS layout
*
spiffs is designed for following spi flash characteristics: * spiffs is designed for following spi flash characteristics:
- only big areas of data (blocks) can be erased * - only big areas of data (blocks) can be erased
- erasing resets all bits in a block to ones * - erasing resets all bits in a block to ones
- writing pulls ones to zeroes * - writing pulls ones to zeroes
- zeroes cannot be pulled to ones, without erase * - zeroes cannot be pulled to ones, without erase
- wear leveling * - wear leveling
*
spiffs is also meant to be run on embedded, memory constraint devices. * spiffs is also meant to be run on embedded, memory constraint devices.
*
Entire area is divided in blocks. Entire area is also divided in pages. * Entire area is divided in blocks. Entire area is also divided in pages.
Each block contains same number of pages. A page cannot be erased, but a * Each block contains same number of pages. A page cannot be erased, but a
block can be erased. * block can be erased.
*
Entire area must be block_size * x * Entire area must be block_size * x
page_size must be block_size / (2^y) where y > 2 * page_size must be block_size / (2^y) where y > 2
*
ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes * ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
*
BLOCK 0 PAGE 0 object lookup 1 * BLOCK 0 PAGE 0 object lookup 1
PAGE 1 object lookup 2 * PAGE 1 object lookup 2
... * ...
PAGE n-1 object lookup n * PAGE n-1 object lookup n
PAGE n object data 1 * PAGE n object data 1
PAGE n+1 object data 2 * PAGE n+1 object data 2
... * ...
PAGE n+m-1 object data m * PAGE n+m-1 object data m
*
BLOCK 1 PAGE n+m object lookup 1 * BLOCK 1 PAGE n+m object lookup 1
PAGE n+m+1 object lookup 2 * PAGE n+m+1 object lookup 2
... * ...
PAGE 2n+m-1 object lookup n * PAGE 2n+m-1 object lookup n
PAGE 2n+m object data 1 * PAGE 2n+m object data 1
PAGE 2n+m object data 2 * PAGE 2n+m object data 2
... * ...
PAGE 2n+2m-1 object data m * PAGE 2n+2m-1 object data m
... * ...
*
n is number of object lookup pages, which is number of pages needed to index all pages * n is number of object lookup pages, which is number of pages needed to index all pages
in a block by object id * in a block by object id
: block_size / page_size * sizeof(obj_id) / 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 * 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 * : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
thus, n+m is total number of pages in a block * thus, n+m is total number of pages in a block
: block_size / page_size * : block_size / page_size
*
ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256 * ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
*
Object lookup pages contain object id entries. Each entry represent the corresponding * Object lookup pages contain object id entries. Each entry represent the corresponding
data page. * data page.
Assuming a 16 bit object id, an object id being 0xffff represents a free page. * Assuming a 16 bit object id, an object id being 0xffff represents a free page.
An object id being 0x0000 represents a deleted page. * An object id being 0x0000 represents a deleted page.
*
ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff .. * ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
page 1 : lookup : ffff ffff ffff 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 2 : data : data for object id 0008
page 3 : data : data for object id 0001 * page 3 : data : data for object id 0001
page 4 : data : data for object id 0aaa * page 4 : data : data for object id 0aaa
... * ...
*
*
Object data pages can be either object index pages or object content. * Object data pages can be either object index pages or object content.
All object data pages contains a data page header, containing object id and span index. * 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. * 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), * This applies to both object index pages (when index spans more than one page of entries),
and object data pages. * and object data pages.
An object index page contains page entries pointing to object content page. The entry index * An object index page contains page entries pointing to object content page. The entry index
in a object index page correlates to the span index in the actual object data page. * in a object index page correlates to the span index in the actual object data page.
The first object index page (span index 0) is called object index header page, and also * The first object index page (span index 0) is called object index header page, and also
contains object flags (directory/file), size, object name etc. * contains object flags (directory/file), size, object name etc.
*
ex: * ex:
BLOCK 1 * BLOCK 1
PAGE 256: objectl lookup page 1 * PAGE 256: objectl lookup page 1
[*123] [ 123] [ 123] [ 123] * [*123] [ 123] [ 123] [ 123]
[ 123] [*123] [ 123] [ 123] * [ 123] [*123] [ 123] [ 123]
[free] [free] [free] [free] ... * [free] [free] [free] [free] ...
PAGE 257: objectl lookup page 2 * PAGE 257: objectl lookup page 2
[free] [free] [free] [free] ... * [free] [free] [free] [free] ...
PAGE 258: object index page (header) * PAGE 258: object index page (header)
obj.id:0123 span.ix:0000 flags:INDEX * obj.id:0123 span.ix:0000 flags:INDEX
size:1600 name:ex.txt type:file * size:1600 name:ex.txt type:file
[259] [260] [261] [262] * [259] [260] [261] [262]
PAGE 259: object data page * PAGE 259: object data page
obj.id:0123 span.ix:0000 flags:DATA * obj.id:0123 span.ix:0000 flags:DATA
PAGE 260: object data page * PAGE 260: object data page
obj.id:0123 span.ix:0001 flags:DATA * obj.id:0123 span.ix:0001 flags:DATA
PAGE 261: object data page * PAGE 261: object data page
obj.id:0123 span.ix:0002 flags:DATA * obj.id:0123 span.ix:0002 flags:DATA
PAGE 262: object data page * PAGE 262: object data page
obj.id:0123 span.ix:0003 flags:DATA * obj.id:0123 span.ix:0003 flags:DATA
PAGE 263: object index page * PAGE 263: object index page
obj.id:0123 span.ix:0001 flags:INDEX * obj.id:0123 span.ix:0001 flags:INDEX
[264] [265] [fre] [fre] * [264] [265] [fre] [fre]
[fre] [fre] [fre] [fre] * [fre] [fre] [fre] [fre]
PAGE 264: object data page * PAGE 264: object data page
obj.id:0123 span.ix:0004 flags:DATA * obj.id:0123 span.ix:0004 flags:DATA
PAGE 265: object data page * PAGE 265: object data page
obj.id:0123 span.ix:0005 flags:DATA * 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,14 +148,14 @@ 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,26 +402,22 @@ 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 // cache flags
u8_t flags; u8_t flags;
// cache page index // cache page index
u8_t ix; u8_t ix;
// last access of this cache page // last access of this cache page
u32_t last_access; u32_t last_access;
union union {
{
// type read cache // type read cache
struct struct {
{
// read cache page index // read cache page index
spiffs_page_ix pix; spiffs_page_ix pix;
}; };
#if SPIFFS_CACHE_WR #if SPIFFS_CACHE_WR
// type write cache // type write cache
struct struct {
{
// write cache // write cache
spiffs_obj_id obj_id; spiffs_obj_id obj_id;
// offset in cache page // offset in cache page
@ -434,8 +430,7 @@ typedef struct
} spiffs_cache_page; } spiffs_cache_page;
// cache struct // cache struct
typedef struct typedef struct {
{
u8_t cpage_count; u8_t cpage_count;
u32_t last_access; u32_t last_access;
u32_t cpage_use_map; u32_t cpage_use_map;
@ -447,8 +442,7 @@ typedef struct
// spiffs nucleus file descriptor // spiffs nucleus file descriptor
typedef struct typedef struct {
{
// the filesystem of this descriptor // the filesystem of this descriptor
spiffs *fs; spiffs *fs;
// number of file descriptor - if 0, the file descriptor is closed // number of file descriptor - if 0, the file descriptor is closed
@ -490,8 +484,7 @@ typedef struct
// page header, part of each page except object lookup pages // 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 // object id
spiffs_obj_id obj_id; spiffs_obj_id obj_id;
// object span index // object span index
@ -503,13 +496,13 @@ typedef struct SPIFFS_PACKED
// 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
@ -523,10 +516,9 @@ __attribute((aligned(sizeof(spiffs_page_ix))))
} 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; spiffs_page_header p_hdr;
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))];
} spiffs_page_object_ix; } spiffs_page_object_ix;
// callback func for object lookup visitor // callback func for object lookup visitor

View File

@ -20,35 +20,31 @@
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();
@ -58,8 +54,7 @@ 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;
} }
@ -70,15 +65,13 @@ bool SPIFFSImpl::exists(const char* path)
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();
} }
@ -88,24 +81,19 @@ 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;
@ -113,8 +101,7 @@ 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);

View File

@ -23,15 +23,15 @@
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"
@ -79,19 +79,16 @@ 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;
@ -107,8 +104,7 @@ 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;
} }
@ -119,14 +115,12 @@ 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;
} }
@ -147,8 +141,7 @@ 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);
@ -157,39 +150,31 @@ public:
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);
@ -200,27 +185,23 @@ 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();
} }
@ -229,7 +210,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:
@ -256,26 +237,22 @@ 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();
} }
@ -290,8 +267,7 @@ 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);
@ -364,8 +340,7 @@ 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;
} }
@ -377,8 +352,7 @@ 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;
} }
@ -391,8 +365,7 @@ 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;
@ -403,13 +376,11 @@ 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;
} }
@ -422,8 +393,7 @@ 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;
} }
@ -434,8 +404,7 @@ 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;
@ -445,12 +414,9 @@ 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 {
else
{
return false; return false;
} }
} }
@ -492,8 +458,7 @@ 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));
} }
@ -525,15 +490,13 @@ 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();
@ -543,8 +506,7 @@ public:
const char* fileName() override const char* fileName() override
{ {
if (!_valid) if (!_valid) {
{
return nullptr; return nullptr;
} }
@ -553,8 +515,7 @@ public:
size_t fileSize() override size_t fileSize() override
{ {
if (!_valid) if (!_valid) {
{
return 0; return 0;
} }
@ -576,11 +537,10 @@ 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;
} }

View File

@ -16,7 +16,7 @@
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>
@ -33,33 +33,29 @@ extern "C" {
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;
@ -67,23 +63,19 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst)
memcpy(dst, ((uint8_t*) &tmp) + 4 - nb, nb); memcpy(dst, ((uint8_t*) &tmp) + 4 - nb, nb);
} }
if (alignedEnd != alignedBegin) if (alignedEnd != alignedBegin) {
{ if (!ESP.flashRead(alignedBegin, (uint32_t*) (dst + alignedBegin - addr),
if (!ESP.flashRead(alignedBegin, (uint32_t*)(dst + alignedBegin - addr), alignedEnd - alignedBegin)) {
alignedEnd - alignedBegin))
{
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n", 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;
@ -107,55 +99,45 @@ int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst)
static const int UNALIGNED_WRITE_BUFFER_SIZE = 512; 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;
@ -168,14 +150,12 @@ int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src)
} }
} }
if (addr + size > alignedEnd) if (addr + size > alignedEnd) {
{
uint32_t nb = addr + size - alignedEnd; uint32_t 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;
@ -185,21 +165,17 @@ 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;
} }

View File

@ -4,8 +4,8 @@
extern "C" { extern "C" {
uint32_t sqrt32(uint32_t n) uint32_t sqrt32 (uint32_t n)
{ {
// http://www.codecodex.com/wiki/Calculate_an_integer_square_root#C // http://www.codecodex.com/wiki/Calculate_an_integer_square_root#C
// Another very fast algorithm donated by Tristan.Muntsinger@gmail.com // Another very fast algorithm donated by Tristan.Muntsinger@gmail.com
// (note: tested across the full 32 bits range, see comment below) // (note: tested across the full 32 bits range, see comment below)
@ -15,31 +15,27 @@ extern "C" {
unsigned int c = 0x8000; unsigned int c = 0x8000;
unsigned int g = 0x8000; unsigned int g = 0x8000;
for (;;) for(;;)
{
if (g * g > n)
{ {
if (g*g > n)
g ^= c; g ^= c;
}
c >>= 1; c >>= 1;
if (!c) if (!c)
{
return g; return g;
}
g |= c; g |= c;
} }
} }
/* /*
tested with: * tested with:
*
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <stdio.h> int main (void)
#include <stdint.h> {
#include <math.h>
int main (void)
{
for (uint32_t i = 0; ++i; ) for (uint32_t i = 0; ++i; )
{ {
uint32_t sr = sqrt32(i); uint32_t sr = sqrt32(i);
@ -56,9 +52,9 @@ extern "C" {
} }
printf("\n"); printf("\n");
} }
*
*/ */
}; };

View File

@ -23,7 +23,7 @@
#define STDLIB_NONISO_H #define STDLIB_NONISO_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"{
#endif #endif
int atoi(const char *s); int atoi(const char *s);
@ -32,15 +32,15 @@ long atol(const char* s);
double atof(const char* s); double atof(const char* s);
char* itoa(int val, char *s, int radix); char* itoa (int val, char *s, int radix);
char* ltoa(long val, char *s, int radix); char* ltoa (long val, char *s, int radix);
char* utoa(unsigned int val, char *s, int radix); char* utoa (unsigned int val, char *s, int radix);
char* ultoa(unsigned long val, char *s, int radix); char* ultoa (unsigned long val, char *s, int radix);
char* dtostrf(double val, signed char width, unsigned char prec, char *s); char* dtostrf (double val, signed char width, unsigned char prec, char *s);
void reverse(char* begin, char* end); void reverse(char* begin, char* end);

View File

@ -1,20 +1,20 @@
/* /*
time.c - ESP8266-specific functions for SNTP * time.c - ESP8266-specific functions for SNTP
Copyright (c) 2015 Peter Dobler. All rights reserved. * Copyright (c) 2015 Peter Dobler. 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. * 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 <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
@ -28,42 +28,41 @@ extern "C" {
#ifndef _TIMEVAL_DEFINED #ifndef _TIMEVAL_DEFINED
#define _TIMEVAL_DEFINED #define _TIMEVAL_DEFINED
struct timeval struct timeval {
{
time_t tv_sec; time_t tv_sec;
suseconds_t tv_usec; suseconds_t tv_usec;
}; };
#endif #endif
extern char* sntp_asctime(const struct tm *t); extern char* sntp_asctime(const struct tm *t);
extern struct tm* sntp_localtime(const time_t *clock); extern struct tm* sntp_localtime(const time_t *clock);
extern uint64_t micros64(); extern uint64_t micros64();
extern void sntp_set_daylight(int daylight); extern void sntp_set_daylight(int daylight);
// time gap in seconds from 01.01.1900 (NTP time) to 01.01.1970 (UNIX time) // time gap in seconds from 01.01.1900 (NTP time) to 01.01.1970 (UNIX time)
#define DIFF1900TO1970 2208988800UL #define DIFF1900TO1970 2208988800UL
bool timeshift64_is_set = false; bool timeshift64_is_set = false;
static uint64_t timeshift64 = 0; static uint64_t timeshift64 = 0;
void tune_timeshift64(uint64_t now_us) void tune_timeshift64 (uint64_t now_us)
{ {
timeshift64 = now_us - micros64(); timeshift64 = now_us - micros64();
timeshift64_is_set = true; timeshift64_is_set = true;
} }
static void setServer(int id, const char* name_or_ip) static void setServer(int id, const char* name_or_ip)
{ {
if (name_or_ip) if (name_or_ip)
{ {
//TODO: check whether server is given by name or IP //TODO: check whether server is given by name or IP
sntp_setservername(id, (char*) name_or_ip); sntp_setservername(id, (char*) name_or_ip);
} }
} }
void configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3) void configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)
{ {
sntp_stop(); sntp_stop();
setServer(0, server1); setServer(0, server1);
@ -73,42 +72,40 @@ extern "C" {
sntp_set_timezone_in_seconds(timezone_sec); sntp_set_timezone_in_seconds(timezone_sec);
sntp_set_daylight(daylightOffset_sec); sntp_set_daylight(daylightOffset_sec);
sntp_init(); sntp_init();
} }
int clock_gettime(clockid_t unused, struct timespec *tp) int clock_gettime(clockid_t unused, struct timespec *tp)
{ {
(void) unused; (void) unused;
uint64_t m = micros64(); uint64_t m = micros64();
tp->tv_sec = m / 1000000; tp->tv_sec = m / 1000000;
tp->tv_nsec = (m % 1000000) * 1000; tp->tv_nsec = (m % 1000000) * 1000;
return 0; return 0;
} }
time_t time(time_t * t) time_t time(time_t * t)
{ {
time_t seconds = sntp_get_current_timestamp(); time_t seconds = sntp_get_current_timestamp();
if (t) if (t)
{ {
*t = seconds; *t = seconds;
} }
return seconds; return seconds;
} }
int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp)
{ {
(void) unused; (void) unused;
(void) tzp; (void) tzp;
if (tp) if (tp)
{ {
if (!timeshift64_is_set) if (!timeshift64_is_set)
{
tune_timeshift64(sntp_get_current_timestamp() * 1000000ULL); tune_timeshift64(sntp_get_current_timestamp() * 1000000ULL);
}
uint64_t currentTime_us = timeshift64 + micros64(); uint64_t currentTime_us = timeshift64 + micros64();
tp->tv_sec = currentTime_us / 1000000ULL; tp->tv_sec = currentTime_us / 1000000ULL;
tp->tv_usec = currentTime_us % 1000000ULL; tp->tv_usec = currentTime_us % 1000000ULL;
} }
return 0; return 0;
} }
}; };

View File

@ -48,8 +48,8 @@ uint8_t twi_status();
uint8_t twi_transmit(const uint8_t*, uint8_t); uint8_t twi_transmit(const uint8_t*, uint8_t);
void twi_attachSlaveRxEvent(void (*)(uint8_t*, size_t)); void twi_attachSlaveRxEvent( void (*)(uint8_t*, size_t) );
void twi_attachSlaveTxEvent(void (*)(void)); void twi_attachSlaveTxEvent( void (*)(void) );
void twi_reply(uint8_t); void twi_reply(uint8_t);
//void twi_stop(void); //void twi_stop(void);
void twi_releaseBus(void); void twi_releaseBus(void);

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