compiling

This commit is contained in:
Dmitry Borisenko
2021-12-13 00:58:42 +01:00
parent 7486ba7438
commit b8a8290928
188 changed files with 14925 additions and 45 deletions

View File

@@ -0,0 +1,7 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#include "StreamUtils.hpp"
using namespace StreamUtils;

View File

@@ -0,0 +1,28 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#include "StreamUtils/Clients/HammingClient.hpp"
#include "StreamUtils/Clients/HammingDecodingClient.hpp"
#include "StreamUtils/Clients/HammingEncodingClient.hpp"
#include "StreamUtils/Clients/LoggingClient.hpp"
#include "StreamUtils/Clients/ReadBufferingClient.hpp"
#include "StreamUtils/Clients/ReadLoggingClient.hpp"
#include "StreamUtils/Clients/WriteBufferingClient.hpp"
#include "StreamUtils/Clients/WriteLoggingClient.hpp"
#include "StreamUtils/Prints/BufferingPrint.hpp"
#include "StreamUtils/Prints/HammingPrint.hpp"
#include "StreamUtils/Prints/LoggingPrint.hpp"
#include "StreamUtils/Prints/StringPrint.hpp"
#include "StreamUtils/Streams/EepromStream.hpp"
#include "StreamUtils/Streams/HammingDecodingStream.hpp"
#include "StreamUtils/Streams/HammingEncodingStream.hpp"
#include "StreamUtils/Streams/HammingStream.hpp"
#include "StreamUtils/Streams/LoggingStream.hpp"
#include "StreamUtils/Streams/ReadBufferingStream.hpp"
#include "StreamUtils/Streams/ReadLoggingStream.hpp"
#include "StreamUtils/Streams/ReadThrottlingStream.hpp"
#include "StreamUtils/Streams/StringStream.hpp"
#include "StreamUtils/Streams/WriteBufferingStream.hpp"
#include "StreamUtils/Streams/WriteLoggingStream.hpp"
#include "StreamUtils/Streams/WriteWaitingStream.hpp"

View File

@@ -0,0 +1,57 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <assert.h>
#include <stdlib.h> // size_t
#include <string.h> // memcpy
namespace StreamUtils {
template <typename TAllocator>
class CharArray {
public:
CharArray(size_t size, TAllocator allocator = TAllocator())
: _allocator(allocator) {
_data = reinterpret_cast<char *>(_allocator.allocate(size));
_size = _data ? size : 0;
}
CharArray(const CharArray &src) : CharArray(src._size, src._allocator) {
if (_data != nullptr)
memcpy(_data, src._data, _size);
}
~CharArray() {
_allocator.deallocate(_data);
}
size_t size() const {
return _size;
}
operator bool() const {
return _size > 0;
}
char *operator&() {
return _data;
}
char &operator[](size_t i) {
return _data[i];
}
char operator[](size_t i) const {
return _data[i];
}
protected:
TAllocator _allocator;
char *_data;
size_t _size;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,101 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <stdint.h>
#include "CharArray.hpp"
namespace StreamUtils {
template <typename TAllocator>
class CircularBuffer {
public:
CircularBuffer(size_t capacity, TAllocator allocator = TAllocator())
: _data(capacity, allocator) {
_begin = _end = _size = 0;
}
CircularBuffer(const CircularBuffer &src)
: CircularBuffer(src._data.size(), src._allocator) {
if (_data) {
_begin = src._begin;
_end = src._end;
_size = src._size;
}
}
size_t available() const {
return _size;
}
size_t capacity() const {
return _data.size();
}
void clear() {
_begin = _end = _size = 0;
}
bool isEmpty() const {
return _size == 0;
}
bool isFull() const {
return _size == _data.size();
}
char peek() const {
assert(_size > 0);
return _data[_begin];
}
char read() {
assert(_size > 0);
char result = _data[_begin];
_begin = (_begin + 1) % _data.size();
_size--;
return result;
}
size_t readBytes(char *data, size_t size) {
// don't read more that available
if (size > _size)
size = _size;
for (size_t i = 0; i < size; i++)
data[i] = read();
return size;
}
size_t write(uint8_t data) {
assert(_size < _data.size());
_data[_end] = data;
_end = (_end + 1) % _data.size();
_size++;
return 1;
}
size_t write(const uint8_t *data, size_t size) {
// don't read more that available
size_t roomLeft = _data.size() - _size;
if (size > roomLeft)
size = roomLeft;
for (size_t i = 0; i < size; i++)
write(data[i]);
return size;
}
private:
CharArray<TAllocator> _data;
size_t _size;
size_t _begin;
size_t _end;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,111 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
#include <Stream.h>
#include "../Helpers.hpp"
#include "CharArray.hpp"
namespace StreamUtils {
template <typename TAllocator>
class LinearBuffer {
public:
LinearBuffer(size_t capacity, TAllocator allocator = TAllocator())
: _data(capacity, allocator) {
_begin = _data ? &_data : nullptr;
_end = _begin;
}
LinearBuffer(const LinearBuffer &src) : _data(src._data) {
if (_data) {
memcpy(&_data, src._begin, src.available());
_begin = &_data;
_end = &_data + src.available();
} else {
_begin = nullptr;
_end = nullptr;
}
}
size_t available() const {
return _end - _begin;
}
size_t capacity() const {
return _data.size();
}
void clear() {
_begin = _end = _data;
}
bool isEmpty() const {
return available() == 0;
}
bool isFull() const {
return available() == capacity();
}
operator bool() const {
return _data;
}
char peek() const {
return *_begin;
}
char read() {
return *_begin++;
}
size_t readBytes(char *dstPtr, size_t dstSize) {
size_t srcSize = available();
size_t n = srcSize < dstSize ? srcSize : dstSize;
memcpy(dstPtr, _begin, n);
_begin += n;
return n;
}
size_t write(uint8_t data) {
assert(!isFull());
*_end++ = data;
return 1;
}
size_t write(const uint8_t *data, size_t size) {
size_t roomLeft = capacity() - available();
if (size > roomLeft)
size = roomLeft;
memcpy(_end, data, size);
_end += size;
return size;
}
template <typename TTarget> // Stream or Client
void reloadFrom(TTarget &source, size_t size) {
if (size > _data.size())
size = _data.size();
size_t n = readOrReadBytes(source, &_data, size);
_begin = &_data;
_end = &_data + n;
}
void flushInto(Print &destination) {
if (_begin != _end)
destination.write(_begin, _end - _begin);
_begin = _end = &_data;
}
private:
CharArray<TAllocator> _data;
char *_begin;
char *_end;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,105 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
#include "../Configuration.hpp"
#include "../Streams/StreamProxy.hpp"
namespace StreamUtils {
template <typename ReadPolicy, typename WritePolicy, typename ConnectPolicy>
class ClientProxy : public Client {
public:
explicit ClientProxy(Client &upstream, ReadPolicy reader = ReadPolicy(),
WritePolicy writer = WritePolicy(),
ConnectPolicy connection = ConnectPolicy())
: _target(upstream),
_reader(reader),
_writer(Polyfills::move(writer)),
_connection(connection) {}
ClientProxy(const ClientProxy &other)
: _target(other._target),
_reader(other._reader),
_writer(other._writer),
_connection(other._connection) {}
~ClientProxy() {
_writer.implicitFlush(_target);
}
// --- Print ---
size_t write(const uint8_t *buffer, size_t size) override {
return _writer.write(_target, buffer, size);
}
size_t write(uint8_t data) override {
return _writer.write(_target, data);
}
using Print::write;
// --- Stream ---
int available() override {
return _reader.available(_target);
}
int read() override {
return _reader.read(_target);
}
int peek() override {
return _reader.peek(_target);
}
#if STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL
size_t readBytes(char *buffer, size_t size) override {
return _reader.readBytes(_target, buffer, size);
}
#endif
// --- Client ---
int connect(IPAddress ip, uint16_t port) override {
return _connection.connect(_target, ip, port);
}
int connect(const char *ip, uint16_t port) override {
return _connection.connect(_target, ip, port);
}
uint8_t connected() override {
return _connection.connected(_target);
}
void stop() override {
_writer.implicitFlush(_target);
_connection.stop(_target);
}
operator bool() override {
return _connection.operator_bool(_target);
}
int read(uint8_t *buf, size_t size) override {
return _reader.read(_target, buf, size);
}
void flush() override {
_writer.flush(_target);
}
protected:
Client &_target;
ReadPolicy _reader;
WritePolicy _writer;
ConnectPolicy _connection;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,23 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/HammingDecodingPolicy.hpp"
#include "../Policies/HammingEncodingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
using BasicHammingClient = ClientProxy<HammingDecodingPolicy<N, K, TAllocator>,
HammingEncodingPolicy<N, K, TAllocator>,
ConnectForwardingPolicy>;
template <int N, int K>
using HammingClient = BasicHammingClient<N, K, DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,24 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/HammingDecodingPolicy.hpp"
#include "../Policies/WriteForwardingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
using BasicHammingDecodingClient =
ClientProxy<HammingDecodingPolicy<N, K, TAllocator>, WriteForwardingPolicy,
ConnectForwardingPolicy>;
template <int N, int K>
using HammingDecodingClient =
BasicHammingDecodingClient<N, K, DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,24 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/HammingEncodingPolicy.hpp"
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
using BasicHammingEncodingClient =
ClientProxy<ReadForwardingPolicy, HammingEncodingPolicy<N, K, TAllocator>,
ConnectForwardingPolicy>;
template <int N, int K>
using HammingEncodingClient =
BasicHammingEncodingClient<N, K, DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,23 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/ReadLoggingPolicy.hpp"
#include "../Policies/WriteLoggingPolicy.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
struct LoggingClient : ClientProxy<ReadLoggingPolicy, WriteLoggingPolicy,
ConnectForwardingPolicy> {
LoggingClient(Client &target, Print &log)
: ClientProxy<ReadLoggingPolicy, WriteLoggingPolicy,
ConnectForwardingPolicy>(target, ReadLoggingPolicy{log},
WriteLoggingPolicy{log},
ConnectForwardingPolicy{}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,92 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
#include "../Buffers/CircularBuffer.hpp"
#include "../Configuration.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "../Streams/MemoryStream.hpp"
namespace StreamUtils {
template <typename TAllocator>
class BasicMemoryClient : public Client {
public:
BasicMemoryClient(size_t capacity, TAllocator allocator = TAllocator())
: _stream(capacity, allocator), _connected(false) {}
BasicMemoryClient(const BasicMemoryClient &src) : _stream(src._stream) {}
// --- Print ---
size_t write(uint8_t data) override {
return _stream.write(data);
}
size_t write(const uint8_t *data, size_t size) override {
return _stream.write(data, size);
}
// --- Stream ---
int available() override {
return _stream.available();
}
int peek() override {
return _stream.peek();
}
int read() override {
return _stream.read();
}
#if STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL
size_t readBytes(char *data, size_t size) override {
return _stream.readBytes(data, size);
}
#endif
void flush() override {
_stream.flush();
}
// --- Client ---
int connect(IPAddress, uint16_t) override {
_connected = true;
return 1;
}
int connect(const char *, uint16_t) override {
_connected = true;
return 1;
}
uint8_t connected() override {
return _connected;
}
void stop() override {
_connected = false;
}
operator bool() override {
return true;
}
int read(uint8_t *buf, size_t size) override {
return _stream.readBytes(reinterpret_cast<char *>(buf), size);
}
private:
BasicMemoryStream<TAllocator> _stream;
bool _connected;
};
using MemoryClient = BasicMemoryClient<DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,30 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/ReadBufferingPolicy.hpp"
#include "../Policies/WriteForwardingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
template <typename TAllocator>
class BasicReadBufferingClient
: public ClientProxy<ReadBufferingPolicy<TAllocator>, WriteForwardingPolicy,
ConnectForwardingPolicy> {
using base_type = ClientProxy<ReadBufferingPolicy<TAllocator>,
WriteForwardingPolicy, ConnectForwardingPolicy>;
public:
explicit BasicReadBufferingClient(Client &target, size_t capacity,
TAllocator allocator = TAllocator())
: base_type(target, ReadBufferingPolicy<TAllocator>{capacity, allocator},
WriteForwardingPolicy{}, ConnectForwardingPolicy{}) {}
};
using ReadBufferingClient = BasicReadBufferingClient<DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,23 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/ReadLoggingPolicy.hpp"
#include "../Policies/WriteForwardingPolicy.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
struct ReadLoggingClient : ClientProxy<ReadLoggingPolicy, WriteForwardingPolicy,
ConnectForwardingPolicy> {
ReadLoggingClient(Client &target, Print &log)
: ClientProxy<ReadLoggingPolicy, WriteForwardingPolicy,
ConnectForwardingPolicy>(target, ReadLoggingPolicy{log},
WriteForwardingPolicy{},
ConnectForwardingPolicy{}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,21 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectSpyingPolicy.hpp"
#include "../Policies/ReadSpyingPolicy.hpp"
#include "../Policies/WriteSpyingPolicy.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
struct SpyingClient
: ClientProxy<ReadSpyingPolicy, WriteSpyingPolicy, ConnectSpyingPolicy> {
SpyingClient(Client &target, Print &log)
: ClientProxy<ReadSpyingPolicy, WriteSpyingPolicy, ConnectSpyingPolicy>(
target, {log}, {log}, {log}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,29 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Policies/WriteBufferingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
template <typename TAllocator>
struct BasicWriteBufferingClient
: ClientProxy<ReadForwardingPolicy, WriteBufferingPolicy<TAllocator>,
ConnectForwardingPolicy> {
explicit BasicWriteBufferingClient(Client &target, size_t capacity,
TAllocator allocator = TAllocator())
: ClientProxy<ReadForwardingPolicy, WriteBufferingPolicy<TAllocator>,
ConnectForwardingPolicy>(
target, ReadForwardingPolicy{},
WriteBufferingPolicy<TAllocator>{capacity, allocator},
ConnectForwardingPolicy{}) {}
};
using WriteBufferingClient = BasicWriteBufferingClient<DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,24 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Policies/WriteLoggingPolicy.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
struct WriteLoggingClient
: ClientProxy<ReadForwardingPolicy, WriteLoggingPolicy,
ConnectForwardingPolicy> {
WriteLoggingClient(Client &target, Print &log)
: ClientProxy<ReadForwardingPolicy, WriteLoggingPolicy,
ConnectForwardingPolicy>(target, ReadForwardingPolicy{},
WriteLoggingPolicy{log},
ConnectForwardingPolicy{}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,30 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ConnectForwardingPolicy.hpp"
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Policies/WriteWaitingPolicy.hpp"
#include "ClientProxy.hpp"
namespace StreamUtils {
struct WriteWaitingClient
: ClientProxy<ReadForwardingPolicy, WriteWaitingPolicy,
ConnectForwardingPolicy> {
WriteWaitingClient(Client &target, Polyfills::function wait = yield)
: ClientProxy<ReadForwardingPolicy, WriteWaitingPolicy,
ConnectForwardingPolicy>(
target, ReadForwardingPolicy{},
WriteWaitingPolicy{Polyfills::move(wait)},
ConnectForwardingPolicy{}) {}
void setTimeout(unsigned long timeout) {
Client::setTimeout(timeout);
_writer.setTimeout(timeout);
}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,53 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#ifndef STREAMUTILS_PRINT_FLUSH_EXISTS
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_SAMD) || \
defined(ARDUINO_ARCH_AVR)
#define STREAMUTILS_PRINT_FLUSH_EXISTS 1
#else
#define STREAMUTILS_PRINT_FLUSH_EXISTS 0
#endif
#endif
#ifndef STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || \
defined(ARDUINO_ARCH_STM32)
#define STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL 1
#else
#define STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL 0
#endif
#endif
#ifndef STREAMUTILS_ENABLE_EEPROM
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP8266) || \
defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32) || \
defined(CORE_TEENSY)
#define STREAMUTILS_ENABLE_EEPROM 1
#else
#define STREAMUTILS_ENABLE_EEPROM 0
#endif
#endif
#ifndef STREAMUTILS_USE_EEPROM_COMMIT
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#define STREAMUTILS_USE_EEPROM_COMMIT 1
#else
#define STREAMUTILS_USE_EEPROM_COMMIT 0
#endif
#endif
#ifndef STREAMUTILS_USE_EEPROM_UPDATE
#if defined(ARDUINO_ARCH_AVR) || defined(CORE_TEENSY)
#define STREAMUTILS_USE_EEPROM_UPDATE 1
#else
#define STREAMUTILS_USE_EEPROM_UPDATE 0
#endif
#endif
#ifndef STREAMUTILS_STACK_BUFFER_MAX_SIZE
#define STREAMUTILS_STACK_BUFFER_MAX_SIZE 32
#endif

View File

@@ -0,0 +1,17 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
namespace StreamUtils {
inline size_t readOrReadBytes(Stream &stream, char *buffer, size_t size) {
return stream.readBytes(buffer, size);
}
inline size_t readOrReadBytes(Client &client, char *buffer, size_t size) {
return client.read(reinterpret_cast<uint8_t *>(buffer), size);
}
} // namespace StreamUtils

View File

@@ -0,0 +1,35 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
#include "../Configuration.hpp"
namespace StreamUtils {
struct ConnectForwardingPolicy {
int connect(Client& target, const IPAddress& ip, uint16_t port) {
return target.connect(ip, port);
}
int connect(Client& target, const char* ip, uint16_t port) {
return target.connect(ip, port);
}
uint8_t connected(Client& target) {
return target.connected();
}
void stop(Client& target) {
target.stop();
}
bool operator_bool(Client& target) {
return target.operator bool();
}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,68 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
namespace StreamUtils {
class ConnectSpyingPolicy {
public:
ConnectSpyingPolicy(Print& log) : _log(log) {}
int connect(Client& target, const IPAddress& ip, uint16_t port) {
_log.print("connect('");
_log.print(ip);
_log.print("', ");
_log.print(port);
_log.print(") -> ");
int result = target.connect(ip, port);
_log.println(result);
return result;
}
int connect(Client& target, const char* ip, uint16_t port) {
_log.print("connect('");
_log.print(ip);
_log.print("', ");
_log.print(port);
_log.print(") -> ");
int result = target.connect(ip, port);
_log.println(result);
return result;
}
uint8_t connected(Client& target) {
_log.print("connected() -> ");
uint8_t result = target.connected();
_log.println(result);
return result;
}
void stop(Client& target) {
_log.print("stop()");
target.stop();
}
bool operator_bool(Client& target) {
_log.print("operator bool() -> ");
bool result = target.operator bool();
_log.println(result ? "true" : "false");
return result;
}
private:
Print& _log;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,137 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
#include <malloc.h>
#else
#include <alloca.h>
#endif
#include <Client.h>
#include <Stream.h>
#include "../Configuration.hpp"
#include "../Helpers.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
class HammingDecodingPolicy;
template <typename TAllocator>
class HammingDecodingPolicy<7, 4, TAllocator> {
const static size_t sizeAllowedOnStack = STREAMUTILS_STACK_BUFFER_MAX_SIZE;
public:
HammingDecodingPolicy(TAllocator allocator = TAllocator())
: _allocator(allocator) {}
int available(Stream &stream) {
int n = stream.available();
if (_remainder >= 0)
n++;
return n / 2;
}
template <typename TTarget> // Stream or Client
int read(TTarget &target) {
if (_remainder < 0) {
_remainder = target.read();
if (_remainder < 0)
return -1;
}
int c = target.read();
if (c < 0)
return -1;
int result = decode(_remainder, c);
_remainder = -1;
return result;
}
int peek(Stream &stream) {
if (_remainder < 0) {
_remainder = stream.read();
if (_remainder < 0)
return -1;
}
int c = stream.peek();
if (c < 0)
return -1;
return decode(_remainder, c);
}
size_t readBytes(Stream &stream, char *buffer, size_t size) {
return doReadBytes(stream, buffer, size);
}
int read(Client &client, uint8_t *buffer, size_t size) {
return doReadBytes(client, reinterpret_cast<char *>(buffer), size);
}
private:
// Decode 7-bits to 4-bits using Hamming(7,4)
uint8_t decode(uint8_t input) {
// table is packed: each element contains two 4-bits values
static uint8_t table[] = {
0x00, 0x03, 0x05, 0xE7, 0x09, 0xEB, 0xED, 0xEE, 0x03, 0x33, 0x4D,
0x63, 0x8D, 0xA3, 0xDD, 0xED, 0x05, 0x2B, 0x55, 0x65, 0x8B, 0xBB,
0xC5, 0xEB, 0x81, 0x63, 0x65, 0x66, 0x88, 0x8B, 0x8D, 0x6F, 0x09,
0x27, 0x47, 0x77, 0x99, 0xA9, 0xC9, 0xE7, 0x41, 0xA3, 0x44, 0x47,
0xA9, 0xAA, 0x4D, 0xAF, 0x21, 0x22, 0xC5, 0x27, 0xC9, 0x2B, 0xCC,
0xCF, 0x11, 0x21, 0x41, 0x6F, 0x81, 0xAF, 0xCF, 0xFF};
uint8_t elem = table[input / 2];
if (input % 2)
return elem & 0x0f;
else
return elem >> 4;
}
uint8_t decode(uint8_t first, uint8_t second) {
return decode(first) << 4 | decode(second);
}
template <typename TTarget> // Stream or Client
size_t doReadBytes(TTarget &target, char *output, size_t outputSize) {
char *buffer;
size_t bufferSize = outputSize * 2;
if (bufferSize > sizeAllowedOnStack) {
buffer = static_cast<char *>(_allocator.allocate(bufferSize));
if (!buffer) {
// allocation failed => use the input buffer
bufferSize = outputSize;
buffer = output;
}
} else {
buffer = static_cast<char *>(alloca(bufferSize));
}
size_t loadedSize = 0;
if (_remainder >= 0)
buffer[loadedSize++] = _remainder;
loadedSize +=
readOrReadBytes(target, buffer + loadedSize, bufferSize - loadedSize);
for (size_t i = 0; i < loadedSize / 2; i++)
output[i] = decode(buffer[2 * i], buffer[2 * i + 1]);
if (loadedSize % 2)
_remainder = buffer[loadedSize - 1];
else
_remainder = -1;
if (bufferSize > sizeAllowedOnStack)
_allocator.deallocate(buffer);
return loadedSize / 2;
}
TAllocator _allocator;
char _remainder = -1;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,116 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
#include <malloc.h>
#else
#include <alloca.h>
#endif
#include "../Configuration.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
class HammingEncodingPolicy;
template <typename TAllocator>
class HammingEncodingPolicy<7, 4, TAllocator> {
const static size_t sizeAllowedOnStack = STREAMUTILS_STACK_BUFFER_MAX_SIZE;
public:
HammingEncodingPolicy(TAllocator allocator = TAllocator())
: _allocator(allocator) {}
size_t write(Print &target, const uint8_t *data, size_t size) {
if (!flushRemainder(target))
return 0;
size_t bufferSize = size * 2;
uint8_t *buffer;
if (bufferSize > sizeAllowedOnStack) {
buffer = static_cast<uint8_t *>(_allocator.allocate(bufferSize));
if (!buffer) {
bufferSize = sizeAllowedOnStack;
buffer = static_cast<uint8_t *>(alloca(bufferSize));
}
} else {
buffer = static_cast<uint8_t *>(alloca(bufferSize));
}
for (size_t i = 0, j = 0; j < bufferSize; i++) {
buffer[j++] = encode(data[i] >> 4);
buffer[j++] = encode(data[i] & 0x0f);
}
size_t n = target.write(buffer, bufferSize);
if (n & 1) {
_remainder = buffer[n];
++n;
}
if (bufferSize > sizeAllowedOnStack)
_allocator.deallocate(buffer);
return n / 2;
}
size_t write(Print &target, uint8_t data) {
uint8_t first = encode(data >> 4);
uint8_t second = encode(data & 0x0f);
if (!flushRemainder(target))
return 0;
if (!target.write(first))
return 0;
if (!target.write(second))
_remainder = second;
return 1;
}
void flush(Stream &target) {
flushRemainder(target);
target.flush();
}
void flush(Print &target) {
flushRemainder(target);
#if STREAMUTILS_PRINT_FLUSH_EXISTS
target.flush();
#endif
}
void implicitFlush(Print &target) {
flushRemainder(target);
}
private:
// Encode 4-bits to 7-bits using Hamming(7,4)
uint8_t encode(uint8_t input) {
static uint8_t table[] = {0x00, 0x71, 0x62, 0x13, 0x54, 0x25, 0x36, 0x47,
0x38, 0x49, 0x5A, 0x2B, 0x6C, 0x1D, 0x0E, 0x7F};
return table[input];
}
template <typename TTarget>
bool flushRemainder(TTarget &target) {
if (_remainder < 0)
return true;
if (!target.write(_remainder))
return false;
_remainder = -1;
return true;
}
TAllocator _allocator;
int16_t _remainder = -1;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,97 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Stream.h>
#include "../Buffers/LinearBuffer.hpp"
#include "../Helpers.hpp"
namespace StreamUtils {
template <typename TAllocator>
struct ReadBufferingPolicy {
ReadBufferingPolicy(size_t capacity, TAllocator allocator = TAllocator())
: _buffer(capacity, allocator) {}
ReadBufferingPolicy(const ReadBufferingPolicy &other)
: _buffer(other._buffer) {}
int available(Stream &stream) {
return stream.available() + _buffer.available();
}
template <typename TTarget> // Stream or Client
int read(TTarget &target) {
if (!_buffer)
return target.read();
if (_buffer.available() > 0)
return _buffer.read();
size_t avail = static_cast<size_t>(target.available());
if (avail <= 1)
return target.read();
_buffer.reloadFrom(target, avail);
return _buffer.read();
}
int peek(Stream &stream) {
return isEmpty() ? stream.peek() : _buffer.peek();
}
size_t readBytes(Stream &stream, char *buffer, size_t size) {
return doReadBytes(stream, buffer, size);
}
int read(Client &client, uint8_t *buffer, size_t size) {
return doReadBytes(client, reinterpret_cast<char *>(buffer), size);
}
private:
bool isEmpty() const {
return _buffer.available() == 0;
}
LinearBuffer<TAllocator> _buffer;
template <typename TTarget> // Stream or Client
size_t doReadBytes(TTarget &target, char *buffer, size_t size) {
if (!_buffer)
return readOrReadBytes(target, buffer, size);
size_t result = 0;
// can we read from buffer?
if (_buffer.available() > 0) {
size_t bytesRead = _buffer.readBytes(buffer, size);
result += bytesRead;
buffer += bytesRead;
size -= bytesRead;
}
// still something to read?
if (size > 0) {
// (at this point, the buffer is empty)
size_t avail = static_cast<size_t>(target.available());
// should we use the buffer?
if (avail > size && size < _buffer.capacity()) {
_buffer.reloadFrom(target, avail);
size_t bytesRead = _buffer.readBytes(buffer, size);
result += bytesRead;
} else {
// we can bypass the buffer
result += readOrReadBytes(target, buffer, size);
}
}
return result;
}
}; // namespace StreamUtils
} // namespace StreamUtils

View File

@@ -0,0 +1,33 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
namespace StreamUtils {
struct ReadForwardingPolicy {
int available(Stream &target) {
return target.available();
}
int read(Stream &target) {
return target.read();
}
int peek(Stream &target) {
return target.peek();
}
size_t readBytes(Stream &target, char *buffer, size_t size) {
return target.readBytes(buffer, size);
}
int read(Client &target, uint8_t *buffer, size_t size) {
return target.read(buffer, size);
}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,46 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
namespace StreamUtils {
class ReadLoggingPolicy {
public:
ReadLoggingPolicy(Print &log) : _log(log) {}
int available(Stream &stream) {
return stream.available();
}
int read(Stream &stream) {
int result = stream.read();
if (result >= 0)
_log.write(result);
return result;
}
int peek(Stream &stream) {
return stream.peek();
}
size_t readBytes(Stream &stream, char *buffer, size_t size) {
size_t result = stream.readBytes(buffer, size);
_log.write(buffer, result);
return result;
}
int read(Client &client, uint8_t *buffer, size_t size) {
int result = client.read(buffer, size);
_log.write(buffer, result);
return result;
}
private:
Print &_log;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,64 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
namespace StreamUtils {
class ReadSpyingPolicy {
public:
ReadSpyingPolicy(Print &log) : _log(log) {}
int available(Stream &target) {
int result = target.available();
_log.print("available() -> ");
_log.println(result);
return result;
}
int read(Stream &target) {
int result = target.read();
_log.print("read() -> ");
_log.println(result);
return result;
}
int peek(Stream &target) {
int result = target.peek();
_log.print("peek() -> ");
_log.println(result);
return result;
}
size_t readBytes(Stream &target, char *buffer, size_t size) {
size_t result = target.readBytes(buffer, size);
_log.print("readBytes(");
_log.print(size);
_log.print(") -> ");
_log.print(result);
if (size > result)
_log.print(" [timeout]");
_log.println();
return result;
}
int read(Client &target, uint8_t *buffer, size_t size) {
int result = target.read(buffer, size);
_log.print("read(");
_log.print(size);
_log.print(") -> ");
_log.print(result);
if (static_cast<int>(size) > result)
_log.print(" [timeout]");
_log.println();
return result;
}
private:
Print &_log;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,47 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Stream.h>
namespace StreamUtils {
template <typename TThrottler>
struct ReadThrottlingPolicy {
ReadThrottlingPolicy(TThrottler throttler) : _throttler(throttler) {}
int available(Stream &stream) {
return stream.available();
}
int read(Stream &stream) {
_throttler.throttle();
return stream.read();
}
int peek(Stream &stream) {
_throttler.throttle();
return stream.peek();
}
size_t readBytes(Stream &stream, char *buffer, size_t size) {
for (size_t i = 0; i < size; i++) {
int c = read(stream);
if (c < 0)
return i;
buffer[i] = c;
}
return size;
}
const TThrottler &throttler() const {
return _throttler;
}
private:
TThrottler _throttler;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,78 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Stream.h>
#include "../Buffers/LinearBuffer.hpp"
#include "../Configuration.hpp"
namespace StreamUtils {
template <typename TAllocator>
struct WriteBufferingPolicy {
public:
WriteBufferingPolicy(size_t capacity, TAllocator allocator)
: _buffer(capacity, allocator) {}
size_t write(Print &target, const uint8_t *data, size_t size) {
size_t result = 0;
// continue to fill the buffer?
if (!_buffer.isEmpty()) {
size_t n = _buffer.write(data, size);
data += n;
size -= n;
result += n;
// time to flush?
if (_buffer.isFull()) {
_buffer.flushInto(target);
}
}
// something left to write?
if (size > 0) {
// can we bypass the buffer?
if (size >= _buffer.capacity()) {
result += target.write(data, size);
} else {
result += _buffer.write(data, size);
}
}
return result;
}
size_t write(Print &target, uint8_t data) {
if (!_buffer)
return target.write(data);
_buffer.write(data);
if (_buffer.isFull())
_buffer.flushInto(target);
return 1;
}
void flush(Stream &target) {
_buffer.flushInto(target);
target.flush();
}
void flush(Print &target) {
_buffer.flushInto(target);
#if STREAMUTILS_PRINT_FLUSH_EXISTS
target.flush();
#endif
}
void implicitFlush(Print &target) {
_buffer.flushInto(target);
}
private:
LinearBuffer<TAllocator> _buffer;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,27 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
#include <Stream.h>
#include "../Configuration.hpp"
namespace StreamUtils {
struct WriteForwardingPolicy {
template <typename... Args>
size_t write(Stream &stream, Args... args) {
return stream.write(args...);
}
void flush(Stream &stream) {
stream.flush();
}
void implicitFlush(Stream &) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,39 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Client.h>
#include "../Configuration.hpp"
namespace StreamUtils {
class WriteLoggingPolicy {
public:
WriteLoggingPolicy(Print &log) : _log(log) {}
size_t write(Print &target, const uint8_t *buffer, size_t size) {
size_t result = target.write(buffer, size);
_log.write(buffer, result);
return result;
}
size_t write(Print &target, uint8_t c) {
size_t result = target.write(c);
_log.write(c);
return result;
}
template <typename TTarget>
void flush(TTarget &target) {
target.flush();
}
void implicitFlush(Print &) {}
private:
Print &_log;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,55 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Stream.h>
#include "../Configuration.hpp"
namespace StreamUtils {
class WriteSpyingPolicy {
public:
WriteSpyingPolicy(Print &log) : _log(log) {}
size_t write(Print &stream, const uint8_t *buffer, size_t size) {
_log.print("write('");
for (size_t i = 0; i < size; i++) {
_log.write(buffer[i]);
}
_log.print("', ");
_log.print(size);
_log.print(") -> ");
size_t result = stream.write(buffer, size);
_log.println(result);
return result;
}
size_t write(Print &stream, uint8_t data) {
_log.print("write('");
_log.write(data);
_log.print("') -> ");
size_t result = stream.write(data);
_log.println(result);
return result;
}
template <typename TTarget>
void flush(TTarget &target) {
_log.println("flush()");
target.flush();
}
void implicitFlush(Print &) {}
private:
Print &_log;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,63 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Arduino.h>
#include "../Buffers/LinearBuffer.hpp"
#include "../Configuration.hpp"
#include "../Polyfills.hpp"
namespace StreamUtils {
struct WriteWaitingPolicy {
public:
WriteWaitingPolicy(Polyfills::function wait)
: _wait(Polyfills::move(wait)), _timeout(1000) {}
size_t write(Print &target, const uint8_t *data, size_t size) {
unsigned long startTime = millis();
size_t totalWritten = 0;
for (;;) {
size_t n = target.write(data, size);
size -= n;
data += n;
totalWritten += n;
if (size == 0 || millis() - startTime >= _timeout)
return totalWritten;
_wait();
}
}
size_t write(Print &target, uint8_t data) {
unsigned long startTime = millis();
for (;;) {
if (target.write(data))
return 1;
if (millis() - startTime >= _timeout)
return 0;
_wait();
}
}
template <typename TTarget>
void flush(TTarget &target) {
target.flush();
}
void implicitFlush(Print &) {}
void setTimeout(unsigned long timeout) {
_timeout = timeout;
}
private:
Polyfills::function _wait;
unsigned long _timeout;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,60 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
namespace StreamUtils {
namespace Polyfills {
template <typename T>
struct remove_reference {
using type = T;
};
template <typename T>
struct remove_reference<T &> {
using type = T;
};
template <typename T>
typename remove_reference<T>::type &&move(T &&t) {
return static_cast<typename remove_reference<T>::type &&>(t);
}
// poor man's std::function<void()>
class function {
struct callable_base {
virtual void operator()() = 0;
virtual ~callable_base() {}
};
template <typename Functor>
struct callable : callable_base {
Functor functor;
callable(Functor functor) : functor(functor) {}
virtual void operator()() {
functor();
}
};
callable_base *_callable;
public:
template <typename Functor>
function(Functor f) {
_callable = new callable<Functor>(f);
}
function(function &&src) {
_callable = src._callable, src._callable = 0;
}
~function() {
delete _callable;
}
void operator()() const {
(*_callable)();
}
};
} // namespace Polyfills
} // namespace StreamUtils

View File

@@ -0,0 +1,29 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
namespace StreamUtils {
class ArduinoThrottler {
public:
ArduinoThrottler(uint32_t rate) : _interval(1000000 / rate), _last(0) {}
void throttle() {
auto now = micros();
auto elapsed = now - _last;
if (elapsed < _interval) {
delayMicroseconds(_interval - elapsed);
}
_last = now;
}
private:
unsigned long _interval;
unsigned long _last;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,21 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
namespace StreamUtils {
#include <stdlib.h> // malloc, free, size_t
struct DefaultAllocator {
void* allocate(size_t n) {
return malloc(n);
}
void deallocate(void* p) {
free(p);
}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,22 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/WriteBufferingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "PrintProxy.hpp"
namespace StreamUtils {
template <typename TAllocator>
struct BasicBufferingPrint : PrintProxy<WriteBufferingPolicy<TAllocator>> {
explicit BasicBufferingPrint(Print &upstream, size_t capacity,
TAllocator allocator = TAllocator())
: PrintProxy<WriteBufferingPolicy<TAllocator>>(upstream,
{capacity, allocator}) {}
};
using BufferingPrint = BasicBufferingPrint<DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,19 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/HammingEncodingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "PrintProxy.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
using BasicHammingPrint = PrintProxy<HammingEncodingPolicy<N, K, TAllocator>>;
template <int N, int K>
using HammingPrint = BasicHammingPrint<N, K, DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,17 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/WriteLoggingPolicy.hpp"
#include "PrintProxy.hpp"
namespace StreamUtils {
struct LoggingPrint : PrintProxy<WriteLoggingPolicy> {
LoggingPrint(Print &upstream, Print &log)
: PrintProxy<WriteLoggingPolicy>(upstream, {log}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,50 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Print.h>
#include "../Configuration.hpp"
#include "../Polyfills.hpp"
namespace StreamUtils {
template <typename WritePolicy>
class PrintProxy : public Print {
public:
explicit PrintProxy(Print &upstream, WritePolicy writer = WritePolicy{})
: _target(upstream), _writer(Polyfills::move(writer)) {}
PrintProxy(const PrintProxy &other)
: _target(other._target), _writer(other._writer) {}
~PrintProxy() {
_writer.implicitFlush(_target);
}
size_t write(const uint8_t *buffer, size_t size) override {
return _writer.write(_target, buffer, size);
}
size_t write(uint8_t data) override {
return _writer.write(_target, data);
}
#if STREAMUTILS_PRINT_FLUSH_EXISTS
void flush() override {
#else
void flush() {
#endif
_writer.flush(_target);
}
using Print::write;
protected:
Print &_target;
WritePolicy _writer;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,17 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/WriteSpyingPolicy.hpp"
#include "PrintProxy.hpp"
namespace StreamUtils {
struct SpyingPrint : PrintProxy<WriteSpyingPolicy> {
SpyingPrint(Print &target, Print &log)
: PrintProxy<WriteSpyingPolicy>(target, WriteSpyingPolicy{log}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,52 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Print.h>
#include <WString.h>
#include "../Polyfills.hpp"
namespace StreamUtils {
class StringPrint : public Print {
public:
StringPrint() {}
explicit StringPrint(String str) : _str(Polyfills::move(str)) {}
size_t write(const uint8_t* p, size_t n) override {
for (size_t i = 0; i < n; i++) {
uint8_t c = p[i];
if (c == 0)
return i;
write(c);
}
return n;
}
size_t write(uint8_t c) override {
if (c == 0)
return 0;
_str += static_cast<char>(c);
return 1;
}
const String& str() const {
return _str;
}
void str(String str) {
_str = Polyfills::move(str);
}
void clear() {
_str = "";
}
private:
String _str;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,22 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/WriteWaitingPolicy.hpp"
#include "PrintProxy.hpp"
namespace StreamUtils {
struct WaitingPrint : PrintProxy<WriteWaitingPolicy> {
WaitingPrint(Print &target, Polyfills::function wait = yield)
: PrintProxy<WriteWaitingPolicy>(
target, WriteWaitingPolicy{Polyfills::move(wait)}) {}
void setTimeout(unsigned long timeout) {
_writer.setTimeout(timeout);
}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,76 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Configuration.hpp"
#if STREAMUTILS_ENABLE_EEPROM
#include <EEPROM.h>
#include <Stream.h>
namespace StreamUtils {
class EepromStream : public Stream {
public:
EepromStream(size_t address, size_t size)
: _readAddress(address), _writeAddress(address), _end(address + size) {}
int available() override {
return _end - _readAddress;
}
int read() override {
if (_readAddress >= _end)
return -1;
return EEPROM.read(_readAddress++);
}
int peek() override {
if (_readAddress >= _end)
return -1;
return EEPROM.read(_readAddress);
}
void flush() override {
#if STREAMUTILS_USE_EEPROM_COMMIT
EEPROM.commit();
#endif
}
using Print::write;
size_t write(const uint8_t *buffer, size_t size) override {
size_t remaining = _end - _writeAddress;
if (size > remaining)
size = remaining;
for (size_t i = 0; i < size; i++) {
#if STREAMUTILS_USE_EEPROM_UPDATE
EEPROM.update(_writeAddress++, buffer[i]);
#else
EEPROM.write(_writeAddress++, buffer[i]);
#endif
}
return size;
}
size_t write(uint8_t data) override {
if (_writeAddress >= _end)
return 0;
#if STREAMUTILS_USE_EEPROM_UPDATE
EEPROM.update(_writeAddress++, data);
#else
EEPROM.write(_writeAddress++, data);
#endif
return 1;
}
private:
size_t _readAddress, _writeAddress, _end;
};
} // namespace StreamUtils
#endif

View File

@@ -0,0 +1,22 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/HammingDecodingPolicy.hpp"
#include "../Policies/WriteForwardingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
using BasicHammingDecodingStream =
StreamProxy<HammingDecodingPolicy<N, K, TAllocator>, WriteForwardingPolicy>;
template <int N, int K>
using HammingDecodingStream =
BasicHammingDecodingStream<N, K, DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,22 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/HammingEncodingPolicy.hpp"
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
using BasicHammingEncodingStream =
StreamProxy<ReadForwardingPolicy, HammingEncodingPolicy<N, K, TAllocator>>;
template <int N, int K>
using HammingEncodingStream =
BasicHammingEncodingStream<N, K, DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,21 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/HammingDecodingPolicy.hpp"
#include "../Policies/HammingEncodingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
template <int N, int K, typename TAllocator>
using BasicHammingStream = StreamProxy<HammingDecodingPolicy<N, K, TAllocator>,
HammingEncodingPolicy<N, K, TAllocator>>;
template <int N, int K>
using HammingStream = BasicHammingStream<N, K, DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,19 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadLoggingPolicy.hpp"
#include "../Policies/WriteLoggingPolicy.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
struct LoggingStream : StreamProxy<ReadLoggingPolicy, WriteLoggingPolicy> {
LoggingStream(Stream& target, Print& log)
: StreamProxy<ReadLoggingPolicy, WriteLoggingPolicy>(
target, ReadLoggingPolicy{log}, WriteLoggingPolicy{log}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,61 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Stream.h>
#include "../Buffers/CircularBuffer.hpp"
#include "../Configuration.hpp"
#include "../Ports/DefaultAllocator.hpp"
namespace StreamUtils {
template <typename TAllocator>
class BasicMemoryStream : public Stream {
public:
BasicMemoryStream(size_t capacity, TAllocator allocator = TAllocator())
: _buffer(capacity, allocator) {}
BasicMemoryStream(const BasicMemoryStream &src) : _buffer(src._buffer) {}
int available() override {
return static_cast<int>(_buffer.available());
}
int peek() override {
return _buffer.isEmpty() ? -1 : _buffer.peek();
}
int read() override {
return _buffer.isEmpty() ? -1 : _buffer.read();
}
#if STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL
size_t readBytes(char *data, size_t size) override {
return _buffer.readBytes(data, size);
}
#endif
size_t write(uint8_t data) override {
return _buffer.isFull() ? 0 : _buffer.write(data);
}
size_t write(const uint8_t *data, size_t size) override {
return _buffer.write(data, size);
}
using Stream::write;
void flush() override {
_buffer.clear();
}
private:
CircularBuffer<TAllocator> _buffer;
};
using MemoryStream = BasicMemoryStream<DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,28 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadBufferingPolicy.hpp"
#include "../Policies/WriteForwardingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
template <typename TAllocator>
class BasicReadBufferingStream
: public StreamProxy<ReadBufferingPolicy<TAllocator>,
WriteForwardingPolicy> {
using base_type =
StreamProxy<ReadBufferingPolicy<TAllocator>, WriteForwardingPolicy>;
public:
explicit BasicReadBufferingStream(Stream &upstream, size_t capacity,
TAllocator allocator = TAllocator())
: base_type(upstream, {capacity, allocator}, {}) {}
};
using ReadBufferingStream = BasicReadBufferingStream<DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,19 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadLoggingPolicy.hpp"
#include "../Policies/WriteForwardingPolicy.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
struct ReadLoggingStream
: StreamProxy<ReadLoggingPolicy, WriteForwardingPolicy> {
ReadLoggingStream(Stream &target, Print &log)
: StreamProxy<ReadLoggingPolicy, WriteForwardingPolicy>(
target, ReadLoggingPolicy{log}, WriteForwardingPolicy{}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,35 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadThrottlingPolicy.hpp"
#include "../Policies/WriteForwardingPolicy.hpp"
#include "StreamProxy.hpp"
#ifdef ARDUINO
#include "../Ports/ArduinoThrottler.hpp"
#endif
namespace StreamUtils {
template <typename TThrottler>
class BasicReadThrottlingStream
: public StreamProxy<ReadThrottlingPolicy<TThrottler>,
WriteForwardingPolicy> {
public:
BasicReadThrottlingStream(Stream& upstream,
TThrottler throttler = TThrottler())
: StreamProxy<ReadThrottlingPolicy<TThrottler>, WriteForwardingPolicy>(
upstream, ReadThrottlingPolicy<TThrottler>(throttler), {}) {}
const TThrottler& throttler() const {
return this->_reader.throttler();
}
};
#ifdef ARDUINO
using ReadThrottlingStream = BasicReadThrottlingStream<ArduinoThrottler>;
#endif
} // namespace StreamUtils

View File

@@ -0,0 +1,19 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadSpyingPolicy.hpp"
#include "../Policies/WriteSpyingPolicy.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
struct SpyingStream : StreamProxy<ReadSpyingPolicy, WriteSpyingPolicy> {
SpyingStream(Stream &target, Print &log)
: StreamProxy<ReadSpyingPolicy, WriteSpyingPolicy>(
target, ReadSpyingPolicy{log}, WriteSpyingPolicy{log}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,68 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Stream.h>
#include "../Polyfills.hpp"
namespace StreamUtils {
template <typename ReadPolicy, typename WritePolicy>
class StreamProxy : public Stream {
public:
explicit StreamProxy(Stream &upstream, ReadPolicy reader = ReadPolicy{},
WritePolicy writer = WritePolicy{})
: _upstream(upstream),
_reader(reader),
_writer(Polyfills::move(writer)) {}
StreamProxy(const StreamProxy &other)
: _upstream(other._upstream),
_reader(other._reader),
_writer(other._writer) {}
~StreamProxy() {
_writer.implicitFlush(_upstream);
}
size_t write(const uint8_t *buffer, size_t size) override {
return _writer.write(_upstream, buffer, size);
}
size_t write(uint8_t data) override {
return _writer.write(_upstream, data);
}
using Stream::write;
int available() override {
return _reader.available(_upstream);
}
int read() override {
return _reader.read(_upstream);
}
int peek() override {
return _reader.peek(_upstream);
}
void flush() override {
_writer.flush(_upstream);
}
#if STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL
size_t readBytes(char *buffer, size_t size) override {
return _reader.readBytes(_upstream, buffer, size);
}
#endif
protected:
Stream &_upstream;
ReadPolicy _reader;
WritePolicy _writer;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,77 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include <Stream.h>
#include <WString.h>
#include "../Configuration.hpp"
#include "../Polyfills.hpp"
namespace StreamUtils {
class StringStream : public Stream {
public:
StringStream() {}
explicit StringStream(String str) : _str(Polyfills::move(str)) {}
size_t write(const uint8_t* p, size_t n) override {
for (size_t i = 0; i < n; i++) {
uint8_t c = p[i];
if (c == 0)
return i;
write(c);
}
return n;
}
size_t write(uint8_t c) override {
if (c == 0)
return 0;
_str += static_cast<char>(c);
return 1;
}
const String& str() const {
return _str;
}
void str(String str) {
_str = Polyfills::move(str);
}
int available() override {
return _str.length();
}
int read() override {
if (_str.length() == 0)
return -1;
char c = _str[0];
_str.remove(0, 1);
return c;
}
#if STREAMUTILS_STREAM_READBYTES_IS_VIRTUAL
size_t readBytes(char* buffer, size_t length) override {
if (length > _str.length())
length = _str.length();
_str.toCharArray(buffer, length);
_str.remove(0, length);
return length;
}
#endif
int peek() override {
return _str.length() > 0 ? _str[0] : -1;
}
void flush() override {}
private:
String _str;
};
} // namespace StreamUtils

View File

@@ -0,0 +1,24 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Policies/WriteBufferingPolicy.hpp"
#include "../Ports/DefaultAllocator.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
template <typename TAllocator>
struct BasicWriteBufferingStream
: StreamProxy<ReadForwardingPolicy, WriteBufferingPolicy<TAllocator>> {
explicit BasicWriteBufferingStream(Stream &upstream, size_t capacity,
TAllocator allocator = TAllocator())
: StreamProxy<ReadForwardingPolicy, WriteBufferingPolicy<TAllocator>>(
upstream, {}, {capacity, allocator}) {}
};
using WriteBufferingStream = BasicWriteBufferingStream<DefaultAllocator>;
} // namespace StreamUtils

View File

@@ -0,0 +1,20 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Policies/WriteLoggingPolicy.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
struct WriteLoggingStream
: StreamProxy<ReadForwardingPolicy, WriteLoggingPolicy> {
WriteLoggingStream(Stream &target, Print &log)
: StreamProxy<ReadForwardingPolicy, WriteLoggingPolicy>(
target, ReadForwardingPolicy{}, WriteLoggingPolicy{log}) {}
};
} // namespace StreamUtils

View File

@@ -0,0 +1,26 @@
// StreamUtils - github.com/bblanchon/ArduinoStreamUtils
// Copyright Benoit Blanchon 2019-2021
// MIT License
#pragma once
#include "../Policies/ReadForwardingPolicy.hpp"
#include "../Policies/WriteWaitingPolicy.hpp"
#include "StreamProxy.hpp"
namespace StreamUtils {
struct WriteWaitingStream
: StreamProxy<ReadForwardingPolicy, WriteWaitingPolicy> {
WriteWaitingStream(Stream &target, Polyfills::function wait = yield)
: StreamProxy<ReadForwardingPolicy, WriteWaitingPolicy>(
target, ReadForwardingPolicy{},
WriteWaitingPolicy{Polyfills::move(wait)}) {}
void setTimeout(unsigned long timeout) {
Stream::setTimeout(timeout);
_writer.setTimeout(timeout);
}
};
} // namespace StreamUtils