esp8266 SPIFF 源码

FS.H

/*
 FS.h - file system wrapper
 Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
 This file is part of the esp8266 core for Arduino environment.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef FS_H
#define FS_H

#include <memory>
#include <Arduino.h>
#include <../include/time.h> // See issue #6714

class SDClass;

namespace fs {

class File;
class Dir;
class FS;

class FileImpl;
typedef std::shared_ptr<FileImpl> FileImplPtr;
class FSImpl;
typedef std::shared_ptr<FSImpl> FSImplPtr;
class DirImpl;
typedef std::shared_ptr<DirImpl> DirImplPtr;

template <typename Tfs>
bool mount(Tfs& fs, const char* mountPoint);

enum SeekMode {
    SeekSet = 0,
    SeekCur = 1,
    SeekEnd = 2
};

class File : public Stream
{
public:
    File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) { }

    // Print methods:
    size_t write(uint8_t) override;
    size_t write(const uint8_t *buf, size_t size) override;

    // Stream methods:
    int available() override;
    int read() override;
    int peek() override;
    void flush() override;
    size_t readBytes(char *buffer, size_t length) override {
        return read((uint8_t*)buffer, length);
    }
    size_t read(uint8_t* buf, size_t size);
    bool seek(uint32_t pos, SeekMode mode);
    bool seek(uint32_t pos) {
        return seek(pos, SeekSet);
    }
    size_t position() const;
    size_t size() const;
    void close();
    operator bool() const;
    const char* name() const;
    const char* fullName() const; // Includes path
    bool truncate(uint32_t size);

    bool isFile() const;
    bool isDirectory() const;

    // Arduino "class SD" methods for compatibility
    template<typename T> size_t write(T &src){
      uint8_t obuf[256];
      size_t doneLen = 0;
      size_t sentLen;
      int i;

      while (src.available() > sizeof(obuf)){
        src.read(obuf, sizeof(obuf));
        sentLen = write(obuf, sizeof(obuf));
        doneLen = doneLen + sentLen;
        if(sentLen != sizeof(obuf)){
          return doneLen;
        }
      }

      size_t leftLen = src.available();
      src.read(obuf, leftLen);
      sentLen = write(obuf, leftLen);
      doneLen = doneLen + sentLen;
      return doneLen;
    }
    using Print::write;

    void rewindDirectory();
    File openNextFile();

    String readString() override;

    time_t getLastWrite();
    time_t getCreationTime();
    void setTimeCallback(time_t (*cb)(void));

protected:
    FileImplPtr _p;

    // Arduino SD class emulation
    std::shared_ptr<Dir> _fakeDir;
    FS                  *_baseFS;
};

class Dir {
public:
    Dir(DirImplPtr impl = DirImplPtr(), FS *baseFS = nullptr): _impl(impl), _baseFS(baseFS) { }

    File openFile(const char* mode);

    String fileName();
    size_t fileSize();
    time_t fileTime();
    time_t fileCreationTime();
    bool isFile() const;
    bool isDirectory() const;

    bool next();
    bool rewind();

    void setTimeCallback(time_t (*cb)(void));

protected:
    DirImplPtr _impl;
    FS       *_baseFS;
    time_t (*timeCallback)(void) = nullptr;
};

// Backwards compatible, <4GB filesystem usage
struct FSInfo {
    size_t totalBytes;
    size_t usedBytes;
    size_t blockSize;
    size_t pageSize;
    size_t maxOpenFiles;
    size_t maxPathLength;
};

// Support > 4GB filesystems (SD, etc.)
struct FSInfo64 {
    uint64_t totalBytes;
    uint64_t usedBytes;
    size_t blockSize;
    size_t pageSize;
    size_t maxOpenFiles;
    size_t maxPathLength;
};


class FSConfig
{
public:
    static constexpr uint32_t FSId = 0x00000000;

    FSConfig(uint32_t type = FSId, bool autoFormat = true) : _type(type), _autoFormat(autoFormat) { }

    FSConfig setAutoFormat(bool val = true) {
        _autoFormat = val;
        return *this;
    }

    uint32_t _type;
    bool     _autoFormat;
};

class SPIFFSConfig : public FSConfig
{
public:
    static constexpr uint32_t FSId = 0x53504946;
    SPIFFSConfig(bool autoFormat = true) : FSConfig(FSId, autoFormat) { }

    // Inherit _type and _autoFormat
    // nothing yet, enableTime TBD when SPIFFS has metadate
};

class FS
{
public:
    FS(FSImplPtr impl) : _impl(impl) { timeCallback = _defaultTimeCB; }

    bool setConfig(const FSConfig &cfg);

    bool begin();
    void end();

    bool format();
    bool info(FSInfo& info);
    bool info64(FSInfo64& info);

    File open(const char* path, const char* mode);
    File open(const String& path, const char* mode);

    bool exists(const char* path);
    bool exists(const String& path);

    Dir openDir(const char* path);
    Dir openDir(const String& path);

    bool remove(const char* path);
    bool remove(const String& path);

    bool rename(const char* pathFrom, const char* pathTo);
    bool rename(const String& pathFrom, const String& pathTo);

    bool mkdir(const char* path);
    bool mkdir(const String& path);

    bool rmdir(const char* path);
    bool rmdir(const String& path);

    // Low-level FS routines, not needed by most applications
    bool gc();
    bool check();

    void setTimeCallback(time_t (*cb)(void));

    friend class ::SDClass; // More of a frenemy, but SD needs internal implementation to get private FAT bits
protected:
    FSImplPtr _impl;
    FSImplPtr getImpl() { return _impl; }
    time_t (*timeCallback)(void);
    static time_t _defaultTimeCB(void) { return time(NULL); }
};

} // namespace fs

extern "C"
{
void close_all_fs(void);
void littlefs_request_end(void);
void spiffs_request_end(void);
}

#ifndef FS_NO_GLOBALS
using fs::FS;
using fs::File;
using fs::Dir;
using fs::SeekMode;
using fs::SeekSet;
using fs::SeekCur;
using fs::SeekEnd;
using fs::FSInfo;
using fs::FSConfig;
using fs::SPIFFSConfig;
#endif //FS_NO_GLOBALS

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPIFFS)
extern fs::FS SPIFFS __attribute__((deprecated("SPIFFS has been deprecated. Please consider moving to LittleFS or other filesystems.")));
#endif

#endif //FS_H

FS.CPP

/*
 FS.cpp - file system wrapper
 Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
 This file is part of the esp8266 core for Arduino environment.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "FS.h"
#include "FSImpl.h"

using namespace fs;

static bool sflags(const char* mode, OpenMode& om, AccessMode& am);

size_t File::write(uint8_t c) {
    if (!_p)
        return 0;

    return _p->write(&c, 1);
}

size_t File::write(const uint8_t *buf, size_t size) {
    if (!_p)
        return 0;

    return _p->write(buf, size);
}

int File::available() {
    if (!_p)
        return false;

    return _p->size() - _p->position();
}

int File::read() {
    if (!_p)
        return -1;

    uint8_t result;
    if (_p->read(&result, 1) != 1) {
        return -1;
    }

    return result;
}

size_t File::read(uint8_t* buf, size_t size) {
    if (!_p)
        return -1;

    return _p->read(buf, size);
}

int File::peek() {
    if (!_p)
        return -1;

    size_t curPos = _p->position();
    int result = read();
    seek(curPos, SeekSet);
    return result;
}

void File::flush() {
    if (!_p)
        return;

    _p->flush();
}

bool File::seek(uint32_t pos, SeekMode mode) {
    if (!_p)
        return false;

    return _p->seek(pos, mode);
}

size_t File::position() const {
    if (!_p)
        return 0;

    return _p->position();
}

size_t File::size() const {
    if (!_p)
        return 0;

    return _p->size();
}

void File::close() {
    if (_p) {
        _p->close();
        _p = nullptr;
    }
}

File::operator bool() const {
    return !!_p;
}

bool File::truncate(uint32_t size) {
    if (!_p)
        return false;

    return _p->truncate(size);
}

const char* File::name() const {
    if (!_p)
        return nullptr;

    return _p->name();
}

const char* File::fullName() const {
    if (!_p)
        return nullptr;

    return _p->fullName();
}

bool File::isFile() const {
    if (!_p)
        return false;

    return _p->isFile();
}

bool File::isDirectory() const {
    if (!_p)
        return false;

    return _p->isDirectory();
}

void File::rewindDirectory() {
    if (!_fakeDir) {
        _fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
    } else {
        _fakeDir->rewind();
   }
}

File File::openNextFile() {
    if (!_fakeDir) {
        _fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
    }
    _fakeDir->next();
    return _fakeDir->openFile("r");
}

String File::readString()
{
    String ret;
    ret.reserve(size() - position());
    char temp[256+1];
    int countRead = readBytes(temp, sizeof(temp)-1);
    while (countRead > 0)
    {
        temp[countRead] = 0;
        ret += temp;
        countRead = readBytes(temp, sizeof(temp)-1);
    }
    return ret;
}

time_t File::getLastWrite() {
    if (!_p)
        return 0;

    return _p->getLastWrite();
}

time_t File::getCreationTime() {
    if (!_p)
        return 0;

    return _p->getCreationTime();
}

void File::setTimeCallback(time_t (*cb)(void)) {
    if (!_p)
        return;
    _p->setTimeCallback(cb);
}

File Dir::openFile(const char* mode) {
    if (!_impl) {
        return File();
    }

    OpenMode om;
    AccessMode am;
    if (!sflags(mode, om, am)) {
        DEBUGV("Dir::openFile: invalid mode `%s`\r\n", mode);
        return File();
    }

    File f(_impl->openFile(om, am), _baseFS);
    f.setTimeCallback(timeCallback);
    return f;
}

String Dir::fileName() {
    if (!_impl) {
        return String();
    }

    return _impl->fileName();
}

time_t Dir::fileTime() {
    if (!_impl)
        return 0;
    return _impl->fileTime();
}

time_t Dir::fileCreationTime() {
    if (!_impl)
        return 0;
    return _impl->fileCreationTime();
}

size_t Dir::fileSize() {
    if (!_impl) {
        return 0;
    }

    return _impl->fileSize();
}

bool Dir::isFile() const {
    if (!_impl)
        return false;

    return _impl->isFile();
}

bool Dir::isDirectory() const {
    if (!_impl)
        return false;

    return _impl->isDirectory();
}

bool Dir::next() {
    if (!_impl) {
        return false;
    }

    return _impl->next();
}

bool Dir::rewind() {
    if (!_impl) {
        return false;
    }

    return _impl->rewind();
}

void Dir::setTimeCallback(time_t (*cb)(void)) {
    if (!_impl)
        return;
    _impl->setTimeCallback(cb);
    timeCallback = cb;
}


bool FS::setConfig(const FSConfig &cfg) {
    if (!_impl) {
        return false;
    }

    return _impl->setConfig(cfg);
}

bool FS::begin() {
    if (!_impl) {
        DEBUGV("#error: FS: no implementation");
        return false;
    }
    _impl->setTimeCallback(timeCallback);
    bool ret = _impl->begin();
    DEBUGV("%s\n", ret? "": "#error: FS could not start");
    return ret;
}

void FS::end() {
    if (_impl) {
        _impl->end();
    }
}

bool FS::gc() {
    if (!_impl) {
        return false;
    }
    return _impl->gc();
}

bool FS::check() {
    if (!_impl) {
        return false;
    }
    return _impl->check();
}

bool FS::format() {
    if (!_impl) {
        return false;
    }
    return _impl->format();
}

bool FS::info(FSInfo& info){
    if (!_impl) {
        return false;
    }
    return _impl->info(info);
}

bool FS::info64(FSInfo64& info){
    if (!_impl) {
        return false;
    }
    return _impl->info64(info);
}

File FS::open(const String& path, const char* mode) {
    return open(path.c_str(), mode);
}

File FS::open(const char* path, const char* mode) {
    if (!_impl) {
        return File();
    }

    OpenMode om;
    AccessMode am;
    if (!sflags(mode, om, am)) {
        DEBUGV("FS::open: invalid mode `%s`\r\n", mode);
        return File();
    }
    File f(_impl->open(path, om, am), this);
    f.setTimeCallback(timeCallback);
    return f;
}

bool FS::exists(const char* path) {
    if (!_impl) {
        return false;
    }
    return _impl->exists(path);
}

bool FS::exists(const String& path) {
    return exists(path.c_str());
}

Dir FS::openDir(const char* path) {
    if (!_impl) {
        return Dir();
    }
    DirImplPtr p = _impl->openDir(path);
    Dir d(p, this);
    d.setTimeCallback(timeCallback);
    return d;
}

Dir FS::openDir(const String& path) {
    return openDir(path.c_str());
}

bool FS::remove(const char* path) {
    if (!_impl) {
        return false;
    }
    return _impl->remove(path);
}

bool FS::remove(const String& path) {
    return remove(path.c_str());
}

bool FS::rmdir(const char* path) {
    if (!_impl) {
        return false;
    }
    return _impl->rmdir(path);
}

bool FS::rmdir(const String& path) {
    return rmdir(path.c_str());
}

bool FS::mkdir(const char* path) {
    if (!_impl) {
        return false;
    }
    return _impl->mkdir(path);
}

bool FS::mkdir(const String& path) {
    return mkdir(path.c_str());
}

bool FS::rename(const char* pathFrom, const char* pathTo) {
    if (!_impl) {
        return false;
    }
    return _impl->rename(pathFrom, pathTo);
}

bool FS::rename(const String& pathFrom, const String& pathTo) {
    return rename(pathFrom.c_str(), pathTo.c_str());
}

void FS::setTimeCallback(time_t (*cb)(void)) {
    if (!_impl)
        return;
    _impl->setTimeCallback(cb);
}


static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
    switch (mode[0]) {
        case 'r':
            am = AM_READ;
            om = OM_DEFAULT;
            break;
        case 'w':
            am = AM_WRITE;
            om = (OpenMode) (OM_CREATE | OM_TRUNCATE);
            break;
        case 'a':
            am = AM_WRITE;
            om = (OpenMode) (OM_CREATE | OM_APPEND);
            break;
        default:
            return false;
    }
    switch(mode[1]) {
        case '+':
            am = (AccessMode) (AM_WRITE | AM_READ);
            break;
        case 0:
            break;
        default:
            return false;
    }
    return true;
}


#if defined(FS_FREESTANDING_FUNCTIONS)

/*
TODO: move these functions to public API:
*/
File open(const char* path, const char* mode);
File open(String& path, const char* mode);

Dir openDir(const char* path);
Dir openDir(String& path);

template<>
bool mount<FS>(FS& fs, const char* mountPoint);
/*
*/


struct MountEntry {
    FSImplPtr fs;
    String    path;
    MountEntry* next;
};

static MountEntry* s_mounted = nullptr;

template<>
bool mount<FS>(FS& fs, const char* mountPoint) {
    FSImplPtr p = fs._impl;
    if (!p || !p->mount()) {
        DEBUGV("FSImpl mount failed\r\n");
        return false;
    }

    !make sure mountPoint has trailing '/' here

    MountEntry* entry = new MountEntry;
    entry->fs = p;
    entry->path = mountPoint;
    entry->next = s_mounted;
    s_mounted = entry;
    return true;
}


/*
    iterate over MountEntries and look for the ones which match the path
*/
File open(const char* path, const char* mode) {
    OpenMode om;
    AccessMode am;
    if (!sflags(mode, om, am)) {
        DEBUGV("open: invalid mode `%s`\r\n", mode);
        return File();
    }

    for (MountEntry* entry = s_mounted; entry; entry = entry->next) {
        size_t offset = entry->path.length();
        if (strstr(path, entry->path.c_str())) {
            File result = entry->fs->open(path + offset);
            if (result)
                return result;
        }
    }

    return File();
}

File open(const String& path, const char* mode) {
    return FS::open(path.c_str(), mode);
}

Dir openDir(const String& path) {
    return openDir(path.c_str());
}
#endif

Stream.h

/*
 Stream.h - base class for character-based streams.
 Copyright (c) 2010 David A. Mellis.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

 parsing functions based on TextFinder library by Michael Margolis
 */

#ifndef Stream_h
#define Stream_h

#include <inttypes.h>
#include "Print.h"

// compatability macros for testing
/*
 #define   getInt()            parseInt()
 #define   getInt(skipChar)    parseInt(skipchar)
 #define   getFloat()          parseFloat()
 #define   getFloat(skipChar)  parseFloat(skipChar)
 #define   getString( pre_string, post_string, buffer, length)
 readBytesBetween( pre_string, terminator, buffer, length)
 */

class Stream: public Print {
    protected:
        unsigned long _timeout;      // number of milliseconds to wait for the next char before aborting timed read
        unsigned long _startMillis;  // used for timeout measurement
        int timedRead();    // private method to read 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

    public:
        virtual int available() = 0;
        virtual int read() = 0;
        virtual int peek() = 0;

        Stream() {
            _timeout = 1000;
        }

// parsing methods

        void setTimeout(unsigned long timeout);  // sets maximum milliseconds to wait for stream data, default is 1 second

        bool find(const char *target);   // reads data from the stream until the target string is found
        bool find(uint8_t *target) {
            return find((char *) target);
        }
        // returns true if target string is found, false if timed out (see setTimeout)

        bool find(const char *target, size_t length);   // reads data from the stream until the target string of given length is found
        bool find(const uint8_t *target, size_t length) {
            return find((char *) target, length);
        }
        // returns true if target string is found, false if timed out

        bool find(char target) { return find (&target, 1); }

        bool 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) {
            return findUntil((char *) target, terminator);
        }

        bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen);   // as above but search ends if the terminate string is found
        bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) {
            return findUntil((char *) target, targetLen, terminate, termLen);
        }

        long parseInt(); // returns the first valid (long) integer value from the current position.
        // initial characters that are not digits (or the minus sign) are skipped
        // integer is terminated by the first character that is not a digit.

        float parseFloat();               // float version of parseInt

        virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
        virtual size_t readBytes(uint8_t *buffer, size_t length) {
            return readBytes((char *) buffer, length);
        }
        // terminates if length characters have been read or timeout (see setTimeout)
        // returns the number of characters placed in the buffer (0 means no valid data found)

        size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character
        size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) {
            return readBytesUntil(terminator, (char *) buffer, length);
        }
        // terminates if length characters have been read, timeout, or if the terminator character  detected
        // returns the number of characters placed in the buffer (0 means no valid data found)

        // Arduino String functions to be added here
        virtual String readString();
        String readStringUntil(char terminator);

    protected:
        long parseInt(char skipChar); // 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

        float parseFloat(char skipChar);  // as above but the given skipChar is ignored
};

#endif

Stream.cpp

/*
 Stream.cpp - adds parsing methods to Stream class
 Copyright (c) 2008 David A. Mellis.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

 Created July 2011
 parsing functions based on TextFinder library by Michael Margolis
 */

#include <Arduino.h>
#include <Stream.h>
#define PARSE_TIMEOUT 1000  // default number of milli-seconds to wait
#define NO_SKIP_CHAR  1  // a magic char not found in a valid ASCII numeric field

// private method to read stream with timeout
int Stream::timedRead() {
    int c;
    _startMillis = millis();
    do {
        c = read();
        if(c >= 0)
            return c;
        if(_timeout == 0)
            return -1;
        yield();
    } while(millis() - _startMillis < _timeout);
    return -1;     // -1 indicates timeout
}

// private method to peek stream with timeout
int Stream::timedPeek() {
    int c;
    _startMillis = millis();
    do {
        c = peek();
        if(c >= 0)
            return c;
        if(_timeout == 0)
            return -1;
        yield();
    } while(millis() - _startMillis < _timeout);
    return -1;     // -1 indicates timeout
}

// returns peek of the next digit in the stream or -1 if timeout
// discards non-numeric characters
int Stream::peekNextDigit() {
    int c;
    while(1) {
        c = timedPeek();
        if(c < 0)
            return c;  // timeout
        if(c == '-')
            return c;
        if(c >= '0' && c <= '9')
            return c;
        read();  // discard non-numeric
    }
}

// Public Methods
//

void Stream::setTimeout(unsigned long timeout)  // sets the maximum number of milliseconds to wait
{
    _timeout = timeout;
}

// find returns true if the target string is found
bool Stream::find(const char *target) {
    return findUntil(target, (char*) "");
}

// reads data from the stream until the target string of given length is found
// returns true if target string is found, false if timed out
bool Stream::find(const char *target, size_t length) {
    return findUntil(target, length, NULL, 0);
}

// as find but search ends if the terminator string is found
bool Stream::findUntil(const char *target, const char *terminator) {
    return findUntil(target, strlen(target), terminator, strlen(terminator));
}

// reads data from the stream until the target string of the given length is found
// search terminated if the terminator string is found
// returns true if target string is found, false if terminated or timed out
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) {
    size_t index = 0;  // maximum target string length is 64k bytes!
    size_t termIndex = 0;
    int c;

    if(*target == 0)
        return true;   // return true if target is a null string
    while((c = timedRead()) > 0) {

        if(c != target[index])
            index = 0; // reset index if any char does not match

        if(c == target[index]) {
            //Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
            if(++index >= targetLen) { // return true if all chars in the target match
                return true;
            }
        }

        if(termLen > 0 && c == terminator[termIndex]) {
            if(++termIndex >= termLen)
                return false;       // return false if terminate string found before target string
        } else
            termIndex = 0;
    }
    return false;
}

// returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped
// function is terminated by the first character that is not a digit.
long Stream::parseInt() {
    return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
}

// as above but a given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
long Stream::parseInt(char skipChar) {
    boolean isNegative = false;
    long value = 0;
    int c;

    c = peekNextDigit();
    // ignore non numeric leading characters
    if(c < 0)
        return 0; // zero returned if timeout

    do {
        if(c == skipChar)
            ; // ignore this charactor
        else if(c == '-')
            isNegative = true;
        else if(c >= '0' && c <= '9')        // is c a digit?
            value = value * 10 + c - '0';
        read();  // consume the character we got with peek
        c = timedPeek();
    } while((c >= '0' && c <= '9') || c == skipChar);

    if(isNegative)
        value = -value;
    return value;
}

// as parseInt but returns a floating point value
float Stream::parseFloat() {
    return parseFloat(NO_SKIP_CHAR);
}

// as above but the given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
float Stream::parseFloat(char skipChar) {
    boolean isNegative = false;
    boolean isFraction = false;
    long value = 0;
    int c;
    float fraction = 1.0;

    c = peekNextDigit();
    // ignore non numeric leading characters
    if(c < 0)
        return 0; // zero returned if timeout

    do {
        if(c == skipChar)
            ; // ignore
        else if(c == '-')
            isNegative = true;
        else if(c == '.')
            isFraction = true;
        else if(c >= '0' && c <= '9') {      // is c a digit?
            value = value * 10 + c - '0';
            if(isFraction)
                fraction *= 0.1;
        }
        read();  // consume the character we got with peek
        c = timedPeek();
    } while((c >= '0' && c <= '9') || c == '.' || c == skipChar);

    if(isNegative)
        value = -value;
    if(isFraction)
        return value * fraction;
    else
        return value;
}

// read characters from stream into buffer
// terminates if length characters have been read, or timeout (see setTimeout)
// returns the number of characters placed in the buffer
// the buffer is NOT null terminated.
//
size_t Stream::readBytes(char *buffer, size_t length) {
    size_t count = 0;
    while(count < length) {
        int c = timedRead();
        if(c < 0)
            break;
        *buffer++ = (char) c;
        count++;
    }
    return count;
}

// as readBytes with terminator character
// terminates if length characters have been read, timeout, or if the terminator character  detected
// returns the number of characters placed in the buffer (0 means no valid data found)

size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) {
    if(length < 1)
        return 0;
    size_t index = 0;
    while(index < length) {
        int c = timedRead();
        if(c < 0 || c == terminator)
            break;
        *buffer++ = (char) c;
        index++;
    }
    return index; // return number of characters, not including null terminator
}

String Stream::readString() {
    String ret;
    int c = timedRead();
    while(c >= 0) {
        ret += (char) c;
        c = timedRead();
    }
    return ret;
}

String Stream::readStringUntil(char terminator) {
    String ret;
    int c = timedRead();
    while(c >= 0 && c != terminator) {
        ret += (char) c;
        c = timedRead();
    }
    return ret;
}

Print.h

/*
 Print.h - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef Print_h
#define Print_h

#include <stdint.h>
#include <stddef.h>

#include "WString.h"
#include "Printable.h"

#include "stdlib_noniso.h"

#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2

class Print {
    private:
        int write_error;
        size_t printNumber(unsigned long, uint8_t);
        size_t printFloat(double, uint8_t);
    protected:
        void setWriteError(int err = 1) {
            write_error = err;
        }
    public:
        Print() :
                write_error(0) {
        }

        int getWriteError() {
            return write_error;
        }
        void clearWriteError() {
            setWriteError(0);
        }

        virtual size_t write(uint8_t) = 0;
        size_t write(const char *str) {
            if(str == NULL)
                return 0;
            return write((const uint8_t *) str, strlen_P(str));
        }
        virtual size_t write(const uint8_t *buffer, size_t size);
        size_t write(const char *buffer, size_t size) {
            return write((const uint8_t *) buffer, size);
        }
        // These handle ambiguity for write(0) case, because (0) can be a pointer or an integer
        inline size_t write(short t) { return write((uint8_t)t); }
        inline size_t write(unsigned short t) { return write((uint8_t)t); }
        inline size_t write(int t) { return write((uint8_t)t); }
        inline size_t write(unsigned int t) { return write((uint8_t)t); }
        inline size_t write(long t) { return write((uint8_t)t); }
        inline size_t write(unsigned long t) { return write((uint8_t)t); }
        // Enable write(char) to fall through to write(uint8_t)
        inline size_t write(char c) { return write((uint8_t) c); }
        inline size_t write(int8_t c) { return write((uint8_t) c); }

        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 print(const __FlashStringHelper *);
        size_t print(const String &);
        size_t print(const char[]);
        size_t print(char);
        size_t print(unsigned char, int = DEC);
        size_t print(int, int = DEC);
        size_t print(unsigned int, int = DEC);
        size_t print(long, int = DEC);
        size_t print(unsigned long, int = DEC);
        size_t print(double, int = 2);
        size_t print(const Printable&);

        size_t println(const __FlashStringHelper *);
        size_t println(const String &s);
        size_t println(const char[]);
        size_t println(char);
        size_t println(unsigned char, int = DEC);
        size_t println(int, int = DEC);
        size_t println(unsigned int, int = DEC);
        size_t println(long, int = DEC);
        size_t println(unsigned long, int = DEC);
        size_t println(double, int = 2);
        size_t println(const Printable&);
        size_t println(void);

        virtual void flush() { /* Empty implementation for backward compatibility */ }
};

#endif

Print.cpp

/*
 Print.cpp - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

 Modified 23 November 2006 by David A. Mellis
 Modified December 2014 by Ivan Grokhotkov
 Modified May 2015 by Michael C. Miller - esp8266 progmem support
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <Arduino.h>

#include "Print.h"

// Public Methods //

/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size) {

#ifdef DEBUG_ESP_CORE
    static char not_the_best_way [] PROGMEM STORE_ATTR = "Print::write(data,len) should be overridden for better efficiency\r\n";
    static bool once = false;
    if (!once) {
        once = true;
        os_printf_plus(not_the_best_way);
    }
#endif

    size_t n = 0;
    while (size--) {
        size_t ret = write(pgm_read_byte(buffer++));
        if (ret == 0) {
            // Write of last byte didn't complete, abort additional processing
            break;
        }
        n += ret;
    }
    return n;
}

size_t Print::printf(const char *format, ...) {
    va_list arg;
    va_start(arg, format);
    char temp[64];
    char* buffer = temp;
    size_t len = vsnprintf(temp, sizeof(temp), format, arg);
    va_end(arg);
    if (len > sizeof(temp) - 1) {
        buffer = new char[len + 1];
        if (!buffer) {
            return 0;
        }
        va_start(arg, format);
        vsnprintf(buffer, len + 1, format, arg);
        va_end(arg);
    }
    len = write((const uint8_t*) buffer, len);
    if (buffer != temp) {
        delete[] buffer;
    }
    return len;
}

size_t Print::printf_P(PGM_P format, ...) {
    va_list arg;
    va_start(arg, format);
    char temp[64];
    char* buffer = temp;
    size_t len = vsnprintf_P(temp, sizeof(temp), format, arg);
    va_end(arg);
    if (len > sizeof(temp) - 1) {
        buffer = new char[len + 1];
        if (!buffer) {
            return 0;
        }
        va_start(arg, format);
        vsnprintf_P(buffer, len + 1, format, arg);
        va_end(arg);
    }
    len = write((const uint8_t*) buffer, len);
    if (buffer != temp) {
        delete[] buffer;
    }
    return len;
}

size_t Print::print(const __FlashStringHelper *ifsh) {
    PGM_P p = reinterpret_cast<PGM_P>(ifsh);

    char buff[128] __attribute__ ((aligned(4)));
    auto len = strlen_P(p);
    size_t n = 0;
    while (n < len) {
        int to_write = std::min(sizeof(buff), len - n);
        memcpy_P(buff, p, to_write);
        auto written = write(buff, to_write);
        n += written;
        p += written;
        if (!written) {
            // Some error, write() should write at least 1 byte before returning
            break;
        }
    }
    return n;
}

size_t Print::print(const String &s) {
    return write(s.c_str(), s.length());
}

size_t Print::print(const char str[]) {
    return write(str);
}

size_t Print::print(char c) {
    return write(c);
}

size_t Print::print(unsigned char b, int base) {
    return print((unsigned long) b, base);
}

size_t Print::print(int n, int base) {
    return print((long) n, base);
}

size_t Print::print(unsigned int n, int base) {
    return print((unsigned long) n, base);
}

size_t Print::print(long n, int base) {
    if(base == 0) {
        return write(n);
    } else if(base == 10) {
        if(n < 0) {
            int t = print('-');
            n = -n;
            return printNumber(n, 10) + t;
        }
        return printNumber(n, 10);
    } else {
        return printNumber(n, base);
    }
}

size_t Print::print(unsigned long n, int base) {
    if(base == 0)
        return write(n);
    else
        return printNumber(n, base);
}

size_t Print::print(double n, int digits) {
    return printFloat(n, digits);
}

size_t Print::println(const __FlashStringHelper *ifsh) {
    size_t n = print(ifsh);
    n += println();
    return n;
}

size_t Print::print(const Printable& x) {
    return x.printTo(*this);
}

size_t Print::println(void) {
    return print("\r\n");
}

size_t Print::println(const String &s) {
    size_t n = print(s);
    n += println();
    return n;
}

size_t Print::println(const char c[]) {
    size_t n = print(c);
    n += println();
    return n;
}

size_t Print::println(char c) {
    size_t n = print(c);
    n += println();
    return n;
}

size_t Print::println(unsigned char b, int base) {
    size_t n = print(b, base);
    n += println();
    return n;
}

size_t Print::println(int num, int base) {
    size_t n = print(num, base);
    n += println();
    return n;
}

size_t Print::println(unsigned int num, int base) {
    size_t n = print(num, base);
    n += println();
    return n;
}

size_t Print::println(long num, int base) {
    size_t n = print(num, base);
    n += println();
    return n;
}

size_t Print::println(unsigned long num, int base) {
    size_t n = print(num, base);
    n += println();
    return n;
}

size_t Print::println(double num, int digits) {
    size_t n = print(num, digits);
    n += println();
    return n;
}

size_t Print::println(const Printable& x) {
    size_t n = print(x);
    n += println();
    return n;
}

// Private Methods /

size_t Print::printNumber(unsigned long n, uint8_t base) {
    char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
    char *str = &buf[sizeof(buf) - 1];

    *str = '\0';

    // prevent crash if called with base == 1
    if(base < 2)
        base = 10;

    do {
        unsigned long m = n;
        n /= base;
        char c = m - base * n;
        *--str = c < 10 ? c + '0' : c + 'A' - 10;
    } while(n);

    return write(str);
}

size_t Print::printFloat(double number, uint8_t digits) {
    char buf[40];
    return write(dtostrf(number, 0, digits, buf));
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

armcsdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值