Stream::send() by d-a-v · Pull Request #6979 · esp8266/Arduino (original) (raw)

Expand Up

@@ -22,10 +22,13 @@

#ifndef Stream_h

#define Stream_h

#include <debug.h>

#include <inttypes.h>

#include "Print.h"

#include <Print.h>

#include <PolledTimeout.h>

#include <sys/types.h> // ssize_t

// compatability macros for testing

// compatibility macros for testing

/*

#define getInt() parseInt()

#define getInt(skipChar) parseInt(skipchar)

Expand All

@@ -35,6 +38,15 @@

readBytesBetween( pre_string, terminator, buffer, length)

*/

// Arduino `Client: public Stream` class defines `virtual int read(uint8_t *buf, size_t size) = 0;`

// This function is now imported into `Stream::` for `Stream::send*()`.

// Other classes inheriting from `Stream::` and implementing `read(uint8_t *buf, size_t size)`

// must consequently use `int` as return type, namely Hardware/SoftwareSerial, FileSystems...

#define STREAM_READ_RETURNS_INT 1

// Stream::send API is present

#define STREAMSEND_API 1

class Stream: public Print {

protected:

unsigned long _timeout = 1000; // number of milliseconds to wait for the next char before aborting timed read

Expand All

@@ -53,6 +65,7 @@ class Stream: public Print {

// parsing methods

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

unsigned long getTimeout () const { return _timeout; }

bool find(const char *target); // reads data from the stream until the target string is found

bool find(uint8_t *target) {

Expand Down Expand Up

@@ -102,12 +115,114 @@ class Stream: public Print {

virtual String readString();

String readStringUntil(char terminator);

virtual int read (uint8_t* buffer, size_t len);

int read (char* buffer, size_t len) { return read((uint8_t*)buffer, len); }

//////////////////// extension: direct access to input buffer

// to provide when possible a pointer to available data for read

// informs user and ::to*() on effective buffered peek API implementation

// by default: not available

virtual bool hasPeekBufferAPI () const { return false; }

// returns number of byte accessible by peekBuffer()

virtual size_t peekAvailable () { return 0; }

// returns a pointer to available data buffer (size = peekAvailable())

// semantic forbids any kind of ::read()

// - after calling peekBuffer()

// - and before calling peekConsume()

virtual const char* peekBuffer () { return nullptr; }

// consumes bytes after peekBuffer() use

// (then ::read() is allowed)

virtual void peekConsume (size_t consume) { (void)consume; }

// by default read timeout is possible (incoming data from network,serial..)

// children can override to false (like String::)

virtual bool inputCanTimeout () { return true; }

// (outputCanTimeout() is defined in Print::)

////////////////////////

//////////////////// extensions: Streaming streams to streams

// Stream::send*()

//

// Stream::send*() uses 1-copy transfers when peekBuffer API is

// available, or makes a regular transfer through a temporary buffer.

//

// - for efficiency, Stream classes should implement peekAPI when

// possible

// - for an efficient timeout management, Print/Stream classes

// should implement {output,input}CanTimeout()

using oneShotMs = esp8266::polledTimeout::oneShotFastMs;

static constexpr int temporaryStackBufferSize = 64;

// ::send*() methods:

// - always stop before timeout when "no-more-input-possible-data"

// or "no-more-output-possible-data" condition is met

// - always return number of transfered bytes

// When result is 0 or less than requested maxLen, Print::getLastSend()

// contains an error reason.

// transfers already buffered / immediately available data (no timeout)

// returns number of transfered bytes

size_t sendAvailable (Print* to) { return sendGeneric(to, -1, -1, oneShotMs::alwaysExpired); }

size_t sendAvailable (Print& to) { return sendAvailable(&to); }

// transfers data until timeout

// returns number of transfered bytes

size_t sendAll (Print* to, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendGeneric(to, -1, -1, timeoutMs); }

size_t sendAll (Print& to, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendAll(&to, timeoutMs); }

// transfers data until a char is encountered (the char is swallowed but not transfered) with timeout

// returns number of transfered bytes

size_t sendUntil (Print* to, const int readUntilChar, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendGeneric(to, -1, readUntilChar, timeoutMs); }

size_t sendUntil (Print& to, const int readUntilChar, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendUntil(&to, readUntilChar, timeoutMs); }

// transfers data until requested size or timeout

// returns number of transfered bytes

size_t sendSize (Print* to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendGeneric(to, maxLen, -1, timeoutMs); }

size_t sendSize (Print& to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendSize(&to, maxLen, timeoutMs); }

// remaining size (-1 by default = unknown)

virtual ssize_t streamRemaining () { return -1; }

enum class Report

{

Success = 0,

TimedOut,

ReadError,

WriteError,

ShortOperation,

};

Report getLastSendReport () const { return _sendReport; }

protected:

size_t sendGeneric (Print* to,

const ssize_t len = -1,

const int readUntilChar = -1,

oneShotMs::timeType timeoutMs = oneShotMs::neverExpires /* neverExpires=>getTimeout() */);

size_t SendGenericPeekBuffer(Print* to, const ssize_t len, const int readUntilChar, const oneShotMs::timeType timeoutMs);

size_t SendGenericRegularUntil(Print* to, const ssize_t len, const int readUntilChar, const oneShotMs::timeType timeoutMs);

size_t SendGenericRegular(Print* to, const ssize_t len, const oneShotMs::timeType timeoutMs);

void setReport (Report report) { _sendReport = report; }

private:

Report _sendReport = Report::Success;

//////////////////// end of extensions

protected:

long parseInt(char skipChar); // as above but the given skipChar is ignored

// as above but the given skipChar is ignored

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

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

};

#endif