From 6b4cd90d8116fac2f1ba5eeb72bf07c776584d46 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 30 Jun 2021 09:42:39 +0200 Subject: [PATCH 001/108] Backup-Point #1: This SPI access works. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 83 ++++++++++++ ThreadsafeIO/library.properties | 10 ++ ThreadsafeIO/src/ThreadsafeIO.h | 161 ++++++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 ThreadsafeIO/examples/ts_spi/ts_spi.ino create mode 100644 ThreadsafeIO/library.properties create mode 100644 ThreadsafeIO/src/ThreadsafeIO.h diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino new file mode 100644 index 0000000..aedbed9 --- /dev/null +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -0,0 +1,83 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static int const BMP388_CS_PIN = 2; +static int const BMP388_INT_PIN = 6; +static uint8_t const BMP388_CHIP_ID_REG_ADDR = 0x00; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +void bmp388_select(); +void bmp388_deselect(); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + + +SpiBusDevice bmp388{"SPI", + SpiBusDeviceConfig{ + SPISettings{1000000, MSBFIRST, SPI_MODE0}, + bmp388_select, + bmp388_deselect, + 0x00}}; + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + Serial.begin(9600); + while (!Serial) { } + + SPI.begin(); + + pinMode(BMP388_CS_PIN, OUTPUT); + digitalWrite(BMP388_CS_PIN, HIGH); + + auto bmp388_read_reg = [](uint8_t const reg_addr) -> uint8_t + { + uint8_t const tx_buf[3] = {static_cast(0x80 | reg_addr), 0, 0}; + uint8_t rx_buf[3] = {0}; + size_t rx_buf_len = sizeof(rx_buf); + + SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, &rx_buf_len); + + bmp388.transfer(req); + + return rx_buf[2]; + }; + + uint8_t const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); + Serial.print("BMP388 CHIP ID = 0x"); + Serial.println(chip_id, HEX); +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +void bmp388_select() +{ + digitalWrite(BMP388_CS_PIN, LOW); +} + +void bmp388_deselect() +{ + digitalWrite(BMP388_CS_PIN, HIGH); +} diff --git a/ThreadsafeIO/library.properties b/ThreadsafeIO/library.properties new file mode 100644 index 0000000..5dc7f5f --- /dev/null +++ b/ThreadsafeIO/library.properties @@ -0,0 +1,10 @@ +name=ThreadsafeIO +version=0.0.1 +author=Alexander Entinger +maintainer=Arduino +sentence=Enable threadsafe peripheral access via pipes. +paragraph= +category=Communication +url= +architectures=mbed +include=ThreadsafeIO.h diff --git a/ThreadsafeIO/src/ThreadsafeIO.h b/ThreadsafeIO/src/ThreadsafeIO.h new file mode 100644 index 0000000..e03cb5d --- /dev/null +++ b/ThreadsafeIO/src/ThreadsafeIO.h @@ -0,0 +1,161 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef THREADSAFE_IO_H_ +#define THREADSAFE_IO_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include +#include + +#include +#include + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +/************************************************************************************** + * IoRequest + **************************************************************************************/ + +class IoRequest +{ +public: + enum class Type { None, SPI }; + + IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) + : _type{type} + , _tx_buf{tx_buf} + , _tx_buf_len{tx_buf_len} + , _rx_buf{rx_buf} + , _rx_buf_len{rx_buf_len} + { } + + Type _type{Type::None}; + uint8_t const * const _tx_buf{nullptr}; + size_t const _tx_buf_len{0}; + uint8_t * _rx_buf{nullptr}; + size_t * _rx_buf_len{0}; +}; + +class SpiIoRequest : public IoRequest +{ +public: + SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) + : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len) + { } +}; + +/************************************************************************************** + * BusDevice + **************************************************************************************/ + +class BusDevice +{ +public: + virtual ~BusDevice() { } + enum class Status : int + { + Ok = 0, + ConfigError = -1, + }; + virtual Status transfer(IoRequest const & req) = 0; +}; + +/************************************************************************************** + * SpiBusDevice + **************************************************************************************/ + +class SpiBusDeviceConfig +{ +public: + typedef std::function SpiSelectFunc; + typedef std::function SpiDeselectFunc; + SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, uint8_t const fill_symbol = 0xFF) + : _spi_settings{spi_settings} + , _spi_select{spi_select} + , _spi_deselect{spi_deselect} + , _fill_symbol{fill_symbol} + { } + bool good () const { return (_spi_select && _spi_deselect); } + SPISettings settings () const { return _spi_settings; } + void select () const { if (_spi_select) _spi_select(); } + void deselect () const { if (_spi_deselect) _spi_deselect(); } + uint8_t fill_symbol() const { return _fill_symbol; } +private: + SPISettings _spi_settings; + SpiSelectFunc _spi_select{nullptr}; + SpiDeselectFunc _spi_deselect{nullptr}; + uint8_t _fill_symbol{0xFF}; +}; + +class SpiBusDevice : public BusDevice +{ +public: + SpiBusDevice(std::string const & spi_bus, SpiBusDeviceConfig const & config) : _config{config} + { + /* TODO: Select SPI bus based in string. */ + } + virtual Status transfer(IoRequest const & req) override + { + /* TODO: Instead of directly processing in here push + * the whole request into a queue and hand over processing + * to the IO thread. + */ + if (!_config.good()) + return Status::ConfigError; + + _config.select(); + + SPI.beginTransaction(_config.settings()); + + size_t bytes_received = 0, + bytes_sent = 0; + for(; bytes_received < (*req._rx_buf_len); bytes_received++, bytes_sent++) + { + uint8_t tx_byte = 0; + + if (bytes_sent < req._tx_buf_len) + tx_byte = req._tx_buf[bytes_sent]; + else + tx_byte = _config.fill_symbol(); + + req._rx_buf[bytes_received] = SPI.transfer(tx_byte); + } + *req._rx_buf_len = bytes_received; + + SPI.endTransaction(); + + _config.deselect(); + + return Status::Ok; + } +private: + SpiBusDeviceConfig _config; +}; + +/************************************************************************************** + * Stuff + **************************************************************************************/ + +typedef int io_error_t; + +class SpiIoManager +{ +public: + + io_error_t request(/* IoTransactionRequest const & req */); + + +private: + + void threadFunc(); + +}; + +#endif /* THREADSAFE_IO_H_ */ From c0c6644d5189d46b35039ee3e41aeeb5c3525421 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 30 Jun 2021 15:22:04 +0200 Subject: [PATCH 002/108] Backup-Point #2: This async access works but god knows its hacky as fuck. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 22 ++-- ThreadsafeIO/src/BusDevice.h | 32 +++++ ThreadsafeIO/src/IoRequest.h | 52 ++++++++ ThreadsafeIO/src/SpiBusDevice.h | 119 +++++++++++++++++++ ThreadsafeIO/src/SpiDispatcher.cpp | 3 + ThreadsafeIO/src/SpiDispatcher.h | 105 +++++++++++++++++ ThreadsafeIO/src/ThreadsafeIO.h | 150 +----------------------- 7 files changed, 327 insertions(+), 156 deletions(-) create mode 100644 ThreadsafeIO/src/BusDevice.h create mode 100644 ThreadsafeIO/src/IoRequest.h create mode 100644 ThreadsafeIO/src/SpiBusDevice.h create mode 100644 ThreadsafeIO/src/SpiDispatcher.cpp create mode 100644 ThreadsafeIO/src/SpiDispatcher.h diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index aedbed9..6e0af66 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -23,13 +23,15 @@ void bmp388_deselect(); * GLOBAL VARIABLES **************************************************************************************/ +SpiDispatcher spi_dispatcher; SpiBusDevice bmp388{"SPI", - SpiBusDeviceConfig{ - SPISettings{1000000, MSBFIRST, SPI_MODE0}, - bmp388_select, - bmp388_deselect, - 0x00}}; + SpiBusDeviceConfig { + SPISettings{1000000, MSBFIRST, SPI_MODE0}, + /* bmp388_select or ... */ [](){ digitalWrite(BMP388_CS_PIN, LOW ); }, + /* bmp388_deselect or ... */ [](){ digitalWrite(BMP388_CS_PIN, HIGH); } + } + }; /************************************************************************************** * SETUP/LOOP @@ -39,8 +41,10 @@ void setup() { Serial.begin(9600); while (!Serial) { } - - SPI.begin(); + + //SPI.begin(); + spi_dispatcher.begin(); + delay(2000); /* Ensure that the SPI dispatcher has been started. */ pinMode(BMP388_CS_PIN, OUTPUT); digitalWrite(BMP388_CS_PIN, HIGH); @@ -53,7 +57,9 @@ void setup() SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, &rx_buf_len); - bmp388.transfer(req); + bmp388.transfer(req); + + rtos::ThisThread::sleep_for(5000); /* TODO: Wait for results, otherwise the rx/tx buffers go out of range. */ return rx_buf[2]; }; diff --git a/ThreadsafeIO/src/BusDevice.h b/ThreadsafeIO/src/BusDevice.h new file mode 100644 index 0000000..a20f0a0 --- /dev/null +++ b/ThreadsafeIO/src/BusDevice.h @@ -0,0 +1,32 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef BUS_DEVICE_H_ +#define BUS_DEVICE_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "IoRequest.h" + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class BusDevice +{ +public: + virtual ~BusDevice() { } + + enum class Status : int + { + Ok = 0, + ConfigError = -1, + }; + + virtual Status transfer(IoRequest & req) = 0; +}; + +#endif /* BUS_DEVICE_H_ */ diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h new file mode 100644 index 0000000..6d3a7fa --- /dev/null +++ b/ThreadsafeIO/src/IoRequest.h @@ -0,0 +1,52 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef IO_REQUEST_H_ +#define IO_REQUEST_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class IoRequest +{ +public: + + enum class Type + { + None, + SPI + }; + + IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) + : _type{type} + , _tx_buf{tx_buf} + , _tx_buf_len{tx_buf_len} + , _rx_buf{rx_buf} + , _rx_buf_len{rx_buf_len} + { } + +/* + inline Type type () const { return _type; } + inline uint8_t const * tx_buf () const { return _tx_buf; } + inline size_t tx_buf_len() const { return _tx_buf_len; } + inline uint8_t * rx_buf () { return _rx_buf; } + inline size_t * rx_buf_len() { return _rx_buf_len; } + +private: +*/ + Type _type{Type::None}; + uint8_t const * const _tx_buf{nullptr}; + size_t const _tx_buf_len{0}; + uint8_t * _rx_buf{nullptr}; + size_t * _rx_buf_len{0}; +}; + +#endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/SpiBusDevice.h b/ThreadsafeIO/src/SpiBusDevice.h new file mode 100644 index 0000000..26e04e1 --- /dev/null +++ b/ThreadsafeIO/src/SpiBusDevice.h @@ -0,0 +1,119 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef SPI_BUS_DEVICE_H_ +#define SPI_BUS_DEVICE_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +#include +#include +#include + +#include "IoRequest.h" +#include "BusDevice.h" + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class SpiBusDeviceConfig +{ +public: + typedef std::function SpiSelectFunc; + typedef std::function SpiDeselectFunc; + SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, uint8_t const fill_symbol = 0xFF) + : _spi_settings{spi_settings} + , _spi_select{spi_select} + , _spi_deselect{spi_deselect} + , _fill_symbol{fill_symbol} + { } + bool good () const { return (_spi_select && _spi_deselect); } + SPISettings settings () const { return _spi_settings; } + void select () const { if (_spi_select) _spi_select(); } + void deselect () const { if (_spi_deselect) _spi_deselect(); } + uint8_t fill_symbol() const { return _fill_symbol; } +private: + SPISettings _spi_settings; + SpiSelectFunc _spi_select{nullptr}; + SpiDeselectFunc _spi_deselect{nullptr}; + uint8_t _fill_symbol{0xFF}; +}; + +class SpiIoRequest : public IoRequest +{ +public: + SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) + : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len) + { } + + void set_config(SpiBusDeviceConfig * config) { _config = config; } + SpiBusDeviceConfig & config() { return *_config; } + +private: + SpiBusDeviceConfig * _config{nullptr}; +}; + +extern rtos::Queue _request_queue; + +class SpiBusDevice : public BusDevice +{ +public: + SpiBusDevice(std::string const & spi_bus, SpiBusDeviceConfig const & config) : _config{config} + { + /* TODO: Select SPI bus based in string. */ + } + virtual Status transfer(IoRequest & req) override + { + if (!_config.good()) + return Status::ConfigError; + + reinterpret_cast(&req)->set_config(&_config); + + /* Insert into queue. */ + _request_queue.try_put(&req); + + /* TODO: Instead of directly processing in here push + * the whole request into a queue and hand over processing + * to the IO thread. + */ + /* + _config.select(); + + SPI.beginTransaction(_config.settings()); + + size_t bytes_received = 0, + bytes_sent = 0; + for(; bytes_received < (*req.rx_buf_len()); bytes_received++, bytes_sent++) + { + uint8_t tx_byte = 0; + + if (bytes_sent < req.tx_buf_len()) + tx_byte = req.tx_buf()[bytes_sent]; + else + tx_byte = _config.fill_symbol(); + + req.rx_buf()[bytes_received] = SPI.transfer(tx_byte); + } + *req.rx_buf_len() = bytes_received; + + SPI.endTransaction(); + + _config.deselect(); + */ + + return Status::Ok; + } + +private: + + SpiBusDeviceConfig _config; + +}; + +#endif /* SPI_BUS_DEVICE_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp new file mode 100644 index 0000000..e8e4d40 --- /dev/null +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -0,0 +1,3 @@ +#include "SpiDispatcher.h" + +rtos::Queue _request_queue; diff --git a/ThreadsafeIO/src/SpiDispatcher.h b/ThreadsafeIO/src/SpiDispatcher.h new file mode 100644 index 0000000..77f98a2 --- /dev/null +++ b/ThreadsafeIO/src/SpiDispatcher.h @@ -0,0 +1,105 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef SPI_DISPATCHER_H_ +#define SPI_DISPATCHER_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include +#include +#include + +#include "IoRequest.h" +#include "SpiBusDevice.h" + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +extern rtos::Queue _request_queue; + +class SpiDispatcher +{ +public: + + SpiDispatcher() : _thread(osPriorityNormal, 4096, nullptr, "SpiDispatcher") { } + ~SpiDispatcher() { end(); } + + enum class Status : int + { + Ok = 0 + }; + + Status begin() + { + SPI.begin(); + _thread.start(mbed::callback(this, &SpiDispatcher::threadFunc)); /* TODO: Check return code */ + return Status::Ok; + } + + Status end() + { + _terminate_thread = true; + _thread.join(); /* TODO: Check return code */ + SPI.end(); + return Status::Ok; + } + +private: + + rtos::Thread _thread; + bool _terminate_thread{false}; + + void threadFunc() + { + while(!_terminate_thread) + { + //rtos::ThisThread::yield(); + IoRequest * io_reqest = nullptr; + if (_request_queue.try_get(&io_reqest)) + { + if (io_reqest->_type == IoRequest::Type::SPI) + { + SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); + + spi_io_request->config().select(); + + SPI.beginTransaction(spi_io_request->config().settings()); + + size_t bytes_received = 0, + bytes_sent = 0; + for(; bytes_received < *(spi_io_request->_rx_buf_len); bytes_received++, bytes_sent++) + { + uint8_t tx_byte = 0; + + if (bytes_sent < spi_io_request->_tx_buf_len) + tx_byte = spi_io_request->_tx_buf[bytes_sent]; + else + tx_byte = spi_io_request->config().fill_symbol(); + + uint8_t const rx_byte = SPI.transfer(tx_byte); + + Serial.print("TX "); + Serial.print(tx_byte, HEX); + Serial.print("| RX "); + Serial.print(rx_byte, HEX); + Serial.println(); + + spi_io_request->_rx_buf[bytes_received] = rx_byte; + } + *spi_io_request->_rx_buf_len = bytes_received; + + SPI.endTransaction(); + + spi_io_request->config().deselect(); + } + } + } + } +}; + +#endif /* SPI_DISPATCHER_H_ */ diff --git a/ThreadsafeIO/src/ThreadsafeIO.h b/ThreadsafeIO/src/ThreadsafeIO.h index e03cb5d..5ee9e9a 100644 --- a/ThreadsafeIO/src/ThreadsafeIO.h +++ b/ThreadsafeIO/src/ThreadsafeIO.h @@ -9,153 +9,7 @@ * INCLUDE **************************************************************************************/ -#include -#include - -#include -#include - -/************************************************************************************** - * CLASS DECLARATION - **************************************************************************************/ - -/************************************************************************************** - * IoRequest - **************************************************************************************/ - -class IoRequest -{ -public: - enum class Type { None, SPI }; - - IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) - : _type{type} - , _tx_buf{tx_buf} - , _tx_buf_len{tx_buf_len} - , _rx_buf{rx_buf} - , _rx_buf_len{rx_buf_len} - { } - - Type _type{Type::None}; - uint8_t const * const _tx_buf{nullptr}; - size_t const _tx_buf_len{0}; - uint8_t * _rx_buf{nullptr}; - size_t * _rx_buf_len{0}; -}; - -class SpiIoRequest : public IoRequest -{ -public: - SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) - : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len) - { } -}; - -/************************************************************************************** - * BusDevice - **************************************************************************************/ - -class BusDevice -{ -public: - virtual ~BusDevice() { } - enum class Status : int - { - Ok = 0, - ConfigError = -1, - }; - virtual Status transfer(IoRequest const & req) = 0; -}; - -/************************************************************************************** - * SpiBusDevice - **************************************************************************************/ - -class SpiBusDeviceConfig -{ -public: - typedef std::function SpiSelectFunc; - typedef std::function SpiDeselectFunc; - SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, uint8_t const fill_symbol = 0xFF) - : _spi_settings{spi_settings} - , _spi_select{spi_select} - , _spi_deselect{spi_deselect} - , _fill_symbol{fill_symbol} - { } - bool good () const { return (_spi_select && _spi_deselect); } - SPISettings settings () const { return _spi_settings; } - void select () const { if (_spi_select) _spi_select(); } - void deselect () const { if (_spi_deselect) _spi_deselect(); } - uint8_t fill_symbol() const { return _fill_symbol; } -private: - SPISettings _spi_settings; - SpiSelectFunc _spi_select{nullptr}; - SpiDeselectFunc _spi_deselect{nullptr}; - uint8_t _fill_symbol{0xFF}; -}; - -class SpiBusDevice : public BusDevice -{ -public: - SpiBusDevice(std::string const & spi_bus, SpiBusDeviceConfig const & config) : _config{config} - { - /* TODO: Select SPI bus based in string. */ - } - virtual Status transfer(IoRequest const & req) override - { - /* TODO: Instead of directly processing in here push - * the whole request into a queue and hand over processing - * to the IO thread. - */ - if (!_config.good()) - return Status::ConfigError; - - _config.select(); - - SPI.beginTransaction(_config.settings()); - - size_t bytes_received = 0, - bytes_sent = 0; - for(; bytes_received < (*req._rx_buf_len); bytes_received++, bytes_sent++) - { - uint8_t tx_byte = 0; - - if (bytes_sent < req._tx_buf_len) - tx_byte = req._tx_buf[bytes_sent]; - else - tx_byte = _config.fill_symbol(); - - req._rx_buf[bytes_received] = SPI.transfer(tx_byte); - } - *req._rx_buf_len = bytes_received; - - SPI.endTransaction(); - - _config.deselect(); - - return Status::Ok; - } -private: - SpiBusDeviceConfig _config; -}; - -/************************************************************************************** - * Stuff - **************************************************************************************/ - -typedef int io_error_t; - -class SpiIoManager -{ -public: - - io_error_t request(/* IoTransactionRequest const & req */); - - -private: - - void threadFunc(); - -}; +#include "SpiBusDevice.h" +#include "SpiDispatcher.h" #endif /* THREADSAFE_IO_H_ */ From c67b92400c7e61034b2047cb751f02dfc17ce65a Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 07:00:55 +0200 Subject: [PATCH 003/108] Turn SpiDispatcher into a threadsafe singleon, eliminating the need to keep it on the stack. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 5 ++-- ThreadsafeIO/src/SpiDispatcher.cpp | 32 +++++++++++++++++++++++++ ThreadsafeIO/src/SpiDispatcher.h | 13 ++++++++-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 6e0af66..29f36a1 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -23,8 +23,6 @@ void bmp388_deselect(); * GLOBAL VARIABLES **************************************************************************************/ -SpiDispatcher spi_dispatcher; - SpiBusDevice bmp388{"SPI", SpiBusDeviceConfig { SPISettings{1000000, MSBFIRST, SPI_MODE0}, @@ -43,7 +41,8 @@ void setup() while (!Serial) { } //SPI.begin(); - spi_dispatcher.begin(); + SpiDispatcher::instance().begin(); + //spi_dispatcher.begin(); delay(2000); /* Ensure that the SPI dispatcher has been started. */ pinMode(BMP388_CS_PIN, OUTPUT); diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index e8e4d40..4a37f9b 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -1,3 +1,35 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + #include "SpiDispatcher.h" +/************************************************************************************** + * STATIC MEMBER DEFINITION + **************************************************************************************/ + +SpiDispatcher * SpiDispatcher::_p_instance{nullptr}; +rtos::Mutex SpiDispatcher::_mutex; + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +SpiDispatcher & SpiDispatcher::instance() +{ + mbed::ScopedLock lock(_mutex); + if (!_p_instance) { + _p_instance = new SpiDispatcher(); + } + return *_p_instance; +} + rtos::Queue _request_queue; diff --git a/ThreadsafeIO/src/SpiDispatcher.h b/ThreadsafeIO/src/SpiDispatcher.h index 77f98a2..fc0e5c9 100644 --- a/ThreadsafeIO/src/SpiDispatcher.h +++ b/ThreadsafeIO/src/SpiDispatcher.h @@ -26,8 +26,10 @@ class SpiDispatcher { public: - SpiDispatcher() : _thread(osPriorityNormal, 4096, nullptr, "SpiDispatcher") { } - ~SpiDispatcher() { end(); } + SpiDispatcher(SpiDispatcher &) = delete; + void operator = (SpiDispatcher &) = delete; + + static SpiDispatcher & instance(); enum class Status : int { @@ -51,9 +53,16 @@ class SpiDispatcher private: + static SpiDispatcher * _p_instance; + static rtos::Mutex _mutex; + rtos::Thread _thread; bool _terminate_thread{false}; + SpiDispatcher() : _thread(osPriorityNormal, 4096, nullptr, "SpiDispatcher") { } + ~SpiDispatcher() { end(); } + + void threadFunc() { while(!_terminate_thread) From 06f0961abec921836773fe7e8c322490e7e7a301 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 07:08:25 +0200 Subject: [PATCH 004/108] Limit public API of SpiDispatcher. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 4 +-- ThreadsafeIO/src/SpiDispatcher.cpp | 44 +++++++++++++++++++++++++ ThreadsafeIO/src/SpiDispatcher.h | 32 +++++------------- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 29f36a1..f7bd79b 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -41,9 +41,7 @@ void setup() while (!Serial) { } //SPI.begin(); - SpiDispatcher::instance().begin(); - //spi_dispatcher.begin(); - delay(2000); /* Ensure that the SPI dispatcher has been started. */ + SpiDispatcher::instance(); pinMode(BMP388_CS_PIN, OUTPUT); digitalWrite(BMP388_CS_PIN, HIGH); diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index 4a37f9b..a3fdb48 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -19,6 +19,19 @@ rtos::Mutex SpiDispatcher::_mutex; * CTOR/DTOR **************************************************************************************/ +SpiDispatcher::SpiDispatcher() +: _thread(osPriorityNormal, 4096, nullptr, "SpiDispatcher") +, _has_tread_started{false} +, _terminate_thread{false} +{ + begin(); +} + +SpiDispatcher::~SpiDispatcher() +{ + end(); +} + /************************************************************************************** * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ @@ -32,4 +45,35 @@ SpiDispatcher & SpiDispatcher::instance() return *_p_instance; } +void SpiDispatcher::destroy() +{ + mbed::ScopedLock lock(_mutex); + delete _p_instance; + _p_instance = nullptr; +} + +/************************************************************************************** + * PRIVATE MEMBER FUNCTIONS + **************************************************************************************/ + +void SpiDispatcher::begin() +{ + SPI.begin(); + _thread.start(mbed::callback(this, &SpiDispatcher::threadFunc)); /* TODO: Check return code */ + /* Is is necessary to wait until the SpiDispatcher::threadFunc() + * has started, otherwise other threads might trigger IO requests + * before this thread is actually running. + */ + while (!_has_tread_started) { } +} + + +void SpiDispatcher::end() +{ + _terminate_thread = true; + _thread.join(); /* TODO: Check return code */ + SPI.end(); +} + + rtos::Queue _request_queue; diff --git a/ThreadsafeIO/src/SpiDispatcher.h b/ThreadsafeIO/src/SpiDispatcher.h index fc0e5c9..aa9eb6a 100644 --- a/ThreadsafeIO/src/SpiDispatcher.h +++ b/ThreadsafeIO/src/SpiDispatcher.h @@ -30,26 +30,7 @@ class SpiDispatcher void operator = (SpiDispatcher &) = delete; static SpiDispatcher & instance(); - - enum class Status : int - { - Ok = 0 - }; - - Status begin() - { - SPI.begin(); - _thread.start(mbed::callback(this, &SpiDispatcher::threadFunc)); /* TODO: Check return code */ - return Status::Ok; - } - - Status end() - { - _terminate_thread = true; - _thread.join(); /* TODO: Check return code */ - SPI.end(); - return Status::Ok; - } + static void destroy(); private: @@ -57,14 +38,19 @@ class SpiDispatcher static rtos::Mutex _mutex; rtos::Thread _thread; - bool _terminate_thread{false}; + bool _has_tread_started; + bool _terminate_thread; - SpiDispatcher() : _thread(osPriorityNormal, 4096, nullptr, "SpiDispatcher") { } - ~SpiDispatcher() { end(); } + SpiDispatcher(); + ~SpiDispatcher(); + void begin(); + void end(); void threadFunc() { + _has_tread_started = true; + while(!_terminate_thread) { //rtos::ThisThread::yield(); From 46deed61048f417880a5e79f768678ac45790b4c Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 07:16:11 +0200 Subject: [PATCH 005/108] Eliminate global variable rtos::Queues. --- ThreadsafeIO/src/SpiBusDevice.h | 35 ++--------------- ThreadsafeIO/src/SpiDispatcher.cpp | 57 +++++++++++++++++++++++++++- ThreadsafeIO/src/SpiDispatcher.h | 60 +++--------------------------- 3 files changed, 64 insertions(+), 88 deletions(-) diff --git a/ThreadsafeIO/src/SpiBusDevice.h b/ThreadsafeIO/src/SpiBusDevice.h index 26e04e1..261bf0e 100644 --- a/ThreadsafeIO/src/SpiBusDevice.h +++ b/ThreadsafeIO/src/SpiBusDevice.h @@ -18,6 +18,8 @@ #include "IoRequest.h" #include "BusDevice.h" +#include "SpiDispatcher.h" + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -59,8 +61,6 @@ class SpiIoRequest : public IoRequest SpiBusDeviceConfig * _config{nullptr}; }; -extern rtos::Queue _request_queue; - class SpiBusDevice : public BusDevice { public: @@ -76,36 +76,7 @@ class SpiBusDevice : public BusDevice reinterpret_cast(&req)->set_config(&_config); /* Insert into queue. */ - _request_queue.try_put(&req); - - /* TODO: Instead of directly processing in here push - * the whole request into a queue and hand over processing - * to the IO thread. - */ - /* - _config.select(); - - SPI.beginTransaction(_config.settings()); - - size_t bytes_received = 0, - bytes_sent = 0; - for(; bytes_received < (*req.rx_buf_len()); bytes_received++, bytes_sent++) - { - uint8_t tx_byte = 0; - - if (bytes_sent < req.tx_buf_len()) - tx_byte = req.tx_buf()[bytes_sent]; - else - tx_byte = _config.fill_symbol(); - - req.rx_buf()[bytes_received] = SPI.transfer(tx_byte); - } - *req.rx_buf_len() = bytes_received; - - SPI.endTransaction(); - - _config.deselect(); - */ + SpiDispatcher::instance().request(&req); return Status::Ok; } diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index a3fdb48..a82935d 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -8,6 +8,10 @@ #include "SpiDispatcher.h" +#include + +#include "SpiBusDevice.h" + /************************************************************************************** * STATIC MEMBER DEFINITION **************************************************************************************/ @@ -52,6 +56,11 @@ void SpiDispatcher::destroy() _p_instance = nullptr; } +bool SpiDispatcher::request(IoRequest * req) +{ + return _request_queue.try_put(req); +} + /************************************************************************************** * PRIVATE MEMBER FUNCTIONS **************************************************************************************/ @@ -67,7 +76,6 @@ void SpiDispatcher::begin() while (!_has_tread_started) { } } - void SpiDispatcher::end() { _terminate_thread = true; @@ -75,5 +83,50 @@ void SpiDispatcher::end() SPI.end(); } +void SpiDispatcher::threadFunc() +{ + _has_tread_started = true; + + while(!_terminate_thread) + { + IoRequest * io_reqest = nullptr; + if (_request_queue.try_get(&io_reqest)) + { + if (io_reqest->_type == IoRequest::Type::SPI) + { + SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); + + spi_io_request->config().select(); -rtos::Queue _request_queue; + SPI.beginTransaction(spi_io_request->config().settings()); + + size_t bytes_received = 0, + bytes_sent = 0; + for(; bytes_received < *(spi_io_request->_rx_buf_len); bytes_received++, bytes_sent++) + { + uint8_t tx_byte = 0; + + if (bytes_sent < spi_io_request->_tx_buf_len) + tx_byte = spi_io_request->_tx_buf[bytes_sent]; + else + tx_byte = spi_io_request->config().fill_symbol(); + + uint8_t const rx_byte = SPI.transfer(tx_byte); + + Serial.print("TX "); + Serial.print(tx_byte, HEX); + Serial.print("| RX "); + Serial.print(rx_byte, HEX); + Serial.println(); + + spi_io_request->_rx_buf[bytes_received] = rx_byte; + } + *spi_io_request->_rx_buf_len = bytes_received; + + SPI.endTransaction(); + + spi_io_request->config().deselect(); + } + } + } +} diff --git a/ThreadsafeIO/src/SpiDispatcher.h b/ThreadsafeIO/src/SpiDispatcher.h index aa9eb6a..99f53d1 100644 --- a/ThreadsafeIO/src/SpiDispatcher.h +++ b/ThreadsafeIO/src/SpiDispatcher.h @@ -9,19 +9,14 @@ * INCLUDE **************************************************************************************/ -#include #include -#include #include "IoRequest.h" -#include "SpiBusDevice.h" /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ -extern rtos::Queue _request_queue; - class SpiDispatcher { public: @@ -32,6 +27,8 @@ class SpiDispatcher static SpiDispatcher & instance(); static void destroy(); + bool request(IoRequest * req); + private: static SpiDispatcher * _p_instance; @@ -41,60 +38,15 @@ class SpiDispatcher bool _has_tread_started; bool _terminate_thread; + static size_t constexpr REQUEST_QUEUE_SIZE = 32; + rtos::Queue _request_queue; + SpiDispatcher(); ~SpiDispatcher(); void begin(); void end(); - - void threadFunc() - { - _has_tread_started = true; - - while(!_terminate_thread) - { - //rtos::ThisThread::yield(); - IoRequest * io_reqest = nullptr; - if (_request_queue.try_get(&io_reqest)) - { - if (io_reqest->_type == IoRequest::Type::SPI) - { - SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); - - spi_io_request->config().select(); - - SPI.beginTransaction(spi_io_request->config().settings()); - - size_t bytes_received = 0, - bytes_sent = 0; - for(; bytes_received < *(spi_io_request->_rx_buf_len); bytes_received++, bytes_sent++) - { - uint8_t tx_byte = 0; - - if (bytes_sent < spi_io_request->_tx_buf_len) - tx_byte = spi_io_request->_tx_buf[bytes_sent]; - else - tx_byte = spi_io_request->config().fill_symbol(); - - uint8_t const rx_byte = SPI.transfer(tx_byte); - - Serial.print("TX "); - Serial.print(tx_byte, HEX); - Serial.print("| RX "); - Serial.print(rx_byte, HEX); - Serial.println(); - - spi_io_request->_rx_buf[bytes_received] = rx_byte; - } - *spi_io_request->_rx_buf_len = bytes_received; - - SPI.endTransaction(); - - spi_io_request->config().deselect(); - } - } - } - } + void threadFunc(); }; #endif /* SPI_DISPATCHER_H_ */ From 84d16648d56471001a2d1ffd6d7ee445edc476be Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 07:21:08 +0200 Subject: [PATCH 006/108] Extract SPI processing code for better readability. --- ThreadsafeIO/src/SpiDispatcher.cpp | 67 ++++++++++++++++-------------- ThreadsafeIO/src/SpiDispatcher.h | 1 + 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index a82935d..34864c5 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -87,46 +87,49 @@ void SpiDispatcher::threadFunc() { _has_tread_started = true; - while(!_terminate_thread) - { + while(!_terminate_thread) { IoRequest * io_reqest = nullptr; - if (_request_queue.try_get(&io_reqest)) - { - if (io_reqest->_type == IoRequest::Type::SPI) - { - SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); + if (_request_queue.try_get(&io_reqest)) { + processIoRequest(io_reqest); + } + } +} - spi_io_request->config().select(); +void SpiDispatcher::processIoRequest(IoRequest * io_reqest) +{ + if (io_reqest->_type != IoRequest::Type::SPI) + return; - SPI.beginTransaction(spi_io_request->config().settings()); + SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); - size_t bytes_received = 0, - bytes_sent = 0; - for(; bytes_received < *(spi_io_request->_rx_buf_len); bytes_received++, bytes_sent++) - { - uint8_t tx_byte = 0; + spi_io_request->config().select(); - if (bytes_sent < spi_io_request->_tx_buf_len) - tx_byte = spi_io_request->_tx_buf[bytes_sent]; - else - tx_byte = spi_io_request->config().fill_symbol(); + SPI.beginTransaction(spi_io_request->config().settings()); - uint8_t const rx_byte = SPI.transfer(tx_byte); + size_t bytes_received = 0, + bytes_sent = 0; + for(; bytes_received < *(spi_io_request->_rx_buf_len); bytes_received++, bytes_sent++) + { + uint8_t tx_byte = 0; - Serial.print("TX "); - Serial.print(tx_byte, HEX); - Serial.print("| RX "); - Serial.print(rx_byte, HEX); - Serial.println(); + if (bytes_sent < spi_io_request->_tx_buf_len) + tx_byte = spi_io_request->_tx_buf[bytes_sent]; + else + tx_byte = spi_io_request->config().fill_symbol(); - spi_io_request->_rx_buf[bytes_received] = rx_byte; - } - *spi_io_request->_rx_buf_len = bytes_received; + uint8_t const rx_byte = SPI.transfer(tx_byte); - SPI.endTransaction(); + Serial.print("TX "); + Serial.print(tx_byte, HEX); + Serial.print("| RX "); + Serial.print(rx_byte, HEX); + Serial.println(); - spi_io_request->config().deselect(); - } - } + spi_io_request->_rx_buf[bytes_received] = rx_byte; } -} + *spi_io_request->_rx_buf_len = bytes_received; + + SPI.endTransaction(); + + spi_io_request->config().deselect(); +} \ No newline at end of file diff --git a/ThreadsafeIO/src/SpiDispatcher.h b/ThreadsafeIO/src/SpiDispatcher.h index 99f53d1..7260c30 100644 --- a/ThreadsafeIO/src/SpiDispatcher.h +++ b/ThreadsafeIO/src/SpiDispatcher.h @@ -47,6 +47,7 @@ class SpiDispatcher void begin(); void end(); void threadFunc(); + void processIoRequest(IoRequest * io_reqest); }; #endif /* SPI_DISPATCHER_H_ */ From de5819cb631150d3a449e7ae451955938cdae3ca Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 08:24:01 +0200 Subject: [PATCH 007/108] Lock all public APIs of SpiDispatcher to avoid race conditions. --- ThreadsafeIO/src/SpiDispatcher.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index 34864c5..33ace52 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -58,6 +58,7 @@ void SpiDispatcher::destroy() bool SpiDispatcher::request(IoRequest * req) { + mbed::ScopedLock lock(_mutex); return _request_queue.try_put(req); } From 813b06208f4cd672d549a6c06dcff37b968e8eb0 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 10:43:12 +0200 Subject: [PATCH 008/108] Slightly expanding IoRequest API and cleaning up a bit. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 4 ++-- ThreadsafeIO/src/IoRequest.h | 32 ++++++++++++++++++------- ThreadsafeIO/src/SpiBusDevice.h | 4 ++-- ThreadsafeIO/src/SpiDispatcher.cpp | 12 ++++++---- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index f7bd79b..4d2ae17 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -50,9 +50,9 @@ void setup() { uint8_t const tx_buf[3] = {static_cast(0x80 | reg_addr), 0, 0}; uint8_t rx_buf[3] = {0}; - size_t rx_buf_len = sizeof(rx_buf); + size_t bytes_read = 0; - SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, &rx_buf_len); + SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf), &bytes_read); bmp388.transfer(req); diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index 6d3a7fa..ccbb7a3 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -25,12 +25,10 @@ class IoRequest SPI }; - IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) + IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) : _type{type} - , _tx_buf{tx_buf} - , _tx_buf_len{tx_buf_len} - , _rx_buf{rx_buf} - , _rx_buf_len{rx_buf_len} + , _tx_buf{tx_buf, tx_buf_len} + , _rx_buf{rx_buf, rx_buf_len, bytes_read} { } /* @@ -43,10 +41,26 @@ class IoRequest private: */ Type _type{Type::None}; - uint8_t const * const _tx_buf{nullptr}; - size_t const _tx_buf_len{0}; - uint8_t * _rx_buf{nullptr}; - size_t * _rx_buf_len{0}; + + class TxBuf + { + public: + TxBuf(uint8_t const * const b, size_t const l) : buf{b}, len{l} { } + uint8_t const * const buf{nullptr}; + size_t const len{0}; + }; + + class RxBuf + { + public: + RxBuf(uint8_t * b, size_t const l, size_t * br) : buf{b}, len{l}, bytes_read{br} { } + uint8_t * buf{nullptr}; + size_t const len{0}; + size_t * bytes_read{0}; + }; + + TxBuf _tx_buf; + RxBuf _rx_buf; }; #endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/SpiBusDevice.h b/ThreadsafeIO/src/SpiBusDevice.h index 261bf0e..fe6154d 100644 --- a/ThreadsafeIO/src/SpiBusDevice.h +++ b/ThreadsafeIO/src/SpiBusDevice.h @@ -50,8 +50,8 @@ class SpiBusDeviceConfig class SpiIoRequest : public IoRequest { public: - SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t * rx_buf_len) - : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len) + SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) + : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len, bytes_read) { } void set_config(SpiBusDeviceConfig * config) { _config = config; } diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index 33ace52..2f23af3 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -109,12 +109,14 @@ void SpiDispatcher::processIoRequest(IoRequest * io_reqest) size_t bytes_received = 0, bytes_sent = 0; - for(; bytes_received < *(spi_io_request->_rx_buf_len); bytes_received++, bytes_sent++) + for(; + bytes_received < spi_io_request->_rx_buf.len; + bytes_received++, bytes_sent++) { uint8_t tx_byte = 0; - if (bytes_sent < spi_io_request->_tx_buf_len) - tx_byte = spi_io_request->_tx_buf[bytes_sent]; + if (bytes_sent < spi_io_request->_tx_buf.len) + tx_byte = spi_io_request->_tx_buf.buf[bytes_sent]; else tx_byte = spi_io_request->config().fill_symbol(); @@ -126,9 +128,9 @@ void SpiDispatcher::processIoRequest(IoRequest * io_reqest) Serial.print(rx_byte, HEX); Serial.println(); - spi_io_request->_rx_buf[bytes_received] = rx_byte; + spi_io_request->_rx_buf.buf[bytes_received] = rx_byte; } - *spi_io_request->_rx_buf_len = bytes_received; + *spi_io_request->_rx_buf.bytes_read = bytes_received; SPI.endTransaction(); From d73db4855ca1dd406f0cefccd643e2027b1285b6 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 14:29:10 +0200 Subject: [PATCH 009/108] Rename TxBuf to WriteBuf, RxBuf to ReadBuf --- ThreadsafeIO/src/IoRequest.h | 24 ++++++++++++------------ ThreadsafeIO/src/SpiDispatcher.cpp | 10 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index ccbb7a3..78e0cad 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -27,40 +27,40 @@ class IoRequest IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) : _type{type} - , _tx_buf{tx_buf, tx_buf_len} - , _rx_buf{rx_buf, rx_buf_len, bytes_read} + , _write_buf{tx_buf, tx_buf_len} + , _read_buf{rx_buf, rx_buf_len, bytes_read} { } /* inline Type type () const { return _type; } - inline uint8_t const * tx_buf () const { return _tx_buf; } - inline size_t tx_buf_len() const { return _tx_buf_len; } - inline uint8_t * rx_buf () { return _rx_buf; } - inline size_t * rx_buf_len() { return _rx_buf_len; } + inline uint8_t const * tx_buf () const { return _write_buf; } + inline size_t tx_buf_len() const { return _write_buf_len; } + inline uint8_t * rx_buf () { return _read_buf; } + inline size_t * rx_buf_len() { return _read_buf_len; } private: */ Type _type{Type::None}; - class TxBuf + class WriteBuf { public: - TxBuf(uint8_t const * const b, size_t const l) : buf{b}, len{l} { } + WriteBuf(uint8_t const * const b, size_t const l) : buf{b}, len{l} { } uint8_t const * const buf{nullptr}; size_t const len{0}; }; - class RxBuf + class ReadBuf { public: - RxBuf(uint8_t * b, size_t const l, size_t * br) : buf{b}, len{l}, bytes_read{br} { } + ReadBuf(uint8_t * b, size_t const l, size_t * br) : buf{b}, len{l}, bytes_read{br} { } uint8_t * buf{nullptr}; size_t const len{0}; size_t * bytes_read{0}; }; - TxBuf _tx_buf; - RxBuf _rx_buf; + WriteBuf _write_buf; + ReadBuf _read_buf; }; #endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index 2f23af3..596ca3a 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -110,13 +110,13 @@ void SpiDispatcher::processIoRequest(IoRequest * io_reqest) size_t bytes_received = 0, bytes_sent = 0; for(; - bytes_received < spi_io_request->_rx_buf.len; + bytes_received < spi_io_request->_read_buf.len; bytes_received++, bytes_sent++) { uint8_t tx_byte = 0; - if (bytes_sent < spi_io_request->_tx_buf.len) - tx_byte = spi_io_request->_tx_buf.buf[bytes_sent]; + if (bytes_sent < spi_io_request->_write_buf.len) + tx_byte = spi_io_request->_write_buf.buf[bytes_sent]; else tx_byte = spi_io_request->config().fill_symbol(); @@ -128,9 +128,9 @@ void SpiDispatcher::processIoRequest(IoRequest * io_reqest) Serial.print(rx_byte, HEX); Serial.println(); - spi_io_request->_rx_buf.buf[bytes_received] = rx_byte; + spi_io_request->_read_buf.buf[bytes_received] = rx_byte; } - *spi_io_request->_rx_buf.bytes_read = bytes_received; + *spi_io_request->_read_buf.bytes_read = bytes_received; SPI.endTransaction(); From e588f48374fb785d910778579505c5e1c5263f59 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 14:37:28 +0200 Subject: [PATCH 010/108] IoRequest is now again properly hiding data behind accessor(). --- ThreadsafeIO/src/IoRequest.h | 44 ++++++++++++++---------------- ThreadsafeIO/src/SpiDispatcher.cpp | 12 ++++---- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index 78e0cad..49e25b4 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -25,40 +25,38 @@ class IoRequest SPI }; - IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) - : _type{type} - , _write_buf{tx_buf, tx_buf_len} - , _read_buf{rx_buf, rx_buf_len, bytes_read} - { } - -/* - inline Type type () const { return _type; } - inline uint8_t const * tx_buf () const { return _write_buf; } - inline size_t tx_buf_len() const { return _write_buf_len; } - inline uint8_t * rx_buf () { return _read_buf; } - inline size_t * rx_buf_len() { return _read_buf_len; } - -private: -*/ - Type _type{Type::None}; - class WriteBuf { public: - WriteBuf(uint8_t const * const b, size_t const l) : buf{b}, len{l} { } - uint8_t const * const buf{nullptr}; - size_t const len{0}; + WriteBuf(uint8_t const * const d, size_t const b2w) : data{d}, bytes_to_write{b2w} { } + uint8_t const * const data{nullptr}; + size_t const bytes_to_write{0}; }; class ReadBuf { public: - ReadBuf(uint8_t * b, size_t const l, size_t * br) : buf{b}, len{l}, bytes_read{br} { } - uint8_t * buf{nullptr}; - size_t const len{0}; + ReadBuf(uint8_t * d, size_t const b2r, size_t * br) : data{d}, bytes_to_read{b2r}, bytes_read{br} { } + uint8_t * data{nullptr}; + size_t const bytes_to_read{0}; size_t * bytes_read{0}; }; + + IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) + : _type{type} + , _write_buf{tx_buf, tx_buf_len} + , _read_buf{rx_buf, rx_buf_len, bytes_read} + { } + + + inline Type type () const { return _type; } + inline WriteBuf & write_buf() { return _write_buf; } + inline ReadBuf & read_buf () { return _read_buf; } + +private: + + Type _type{Type::None}; WriteBuf _write_buf; ReadBuf _read_buf; }; diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index 596ca3a..e896038 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -98,7 +98,7 @@ void SpiDispatcher::threadFunc() void SpiDispatcher::processIoRequest(IoRequest * io_reqest) { - if (io_reqest->_type != IoRequest::Type::SPI) + if (io_reqest->type() != IoRequest::Type::SPI) return; SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); @@ -110,13 +110,13 @@ void SpiDispatcher::processIoRequest(IoRequest * io_reqest) size_t bytes_received = 0, bytes_sent = 0; for(; - bytes_received < spi_io_request->_read_buf.len; + bytes_received < spi_io_request->read_buf().bytes_to_read; bytes_received++, bytes_sent++) { uint8_t tx_byte = 0; - if (bytes_sent < spi_io_request->_write_buf.len) - tx_byte = spi_io_request->_write_buf.buf[bytes_sent]; + if (bytes_sent < spi_io_request->write_buf().bytes_to_write) + tx_byte = spi_io_request->write_buf().data[bytes_sent]; else tx_byte = spi_io_request->config().fill_symbol(); @@ -128,9 +128,9 @@ void SpiDispatcher::processIoRequest(IoRequest * io_reqest) Serial.print(rx_byte, HEX); Serial.println(); - spi_io_request->_read_buf.buf[bytes_received] = rx_byte; + spi_io_request->read_buf().data[bytes_received] = rx_byte; } - *spi_io_request->_read_buf.bytes_read = bytes_received; + *spi_io_request->read_buf().bytes_read = bytes_received; SPI.endTransaction(); From 2517bed5ea4fd94e22a21e89a3e9d27be09de746 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 14:38:51 +0200 Subject: [PATCH 011/108] First call to SpiDispatcher::instance(). ... starts everything, no dedicated instantiation required. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 3 --- 1 file changed, 3 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 4d2ae17..e19dbd5 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -40,9 +40,6 @@ void setup() Serial.begin(9600); while (!Serial) { } - //SPI.begin(); - SpiDispatcher::instance(); - pinMode(BMP388_CS_PIN, OUTPUT); digitalWrite(BMP388_CS_PIN, HIGH); From 3ff0d4456fa3921aa88b69168ae3df4effe00445 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 14:41:12 +0200 Subject: [PATCH 012/108] Extract SpiBusDeviceConfig. --- ThreadsafeIO/src/BusDevice.h | 1 - ThreadsafeIO/src/SpiBusDevice.h | 27 +----------------- ThreadsafeIO/src/SpiBusDeviceConfig.h | 41 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 ThreadsafeIO/src/SpiBusDeviceConfig.h diff --git a/ThreadsafeIO/src/BusDevice.h b/ThreadsafeIO/src/BusDevice.h index a20f0a0..1f3f0d4 100644 --- a/ThreadsafeIO/src/BusDevice.h +++ b/ThreadsafeIO/src/BusDevice.h @@ -23,7 +23,6 @@ class BusDevice enum class Status : int { Ok = 0, - ConfigError = -1, }; virtual Status transfer(IoRequest & req) = 0; diff --git a/ThreadsafeIO/src/SpiBusDevice.h b/ThreadsafeIO/src/SpiBusDevice.h index fe6154d..cf6ae67 100644 --- a/ThreadsafeIO/src/SpiBusDevice.h +++ b/ThreadsafeIO/src/SpiBusDevice.h @@ -19,34 +19,12 @@ #include "BusDevice.h" #include "SpiDispatcher.h" +#include "SpiBusDeviceConfig.h" /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ -class SpiBusDeviceConfig -{ -public: - typedef std::function SpiSelectFunc; - typedef std::function SpiDeselectFunc; - SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, uint8_t const fill_symbol = 0xFF) - : _spi_settings{spi_settings} - , _spi_select{spi_select} - , _spi_deselect{spi_deselect} - , _fill_symbol{fill_symbol} - { } - bool good () const { return (_spi_select && _spi_deselect); } - SPISettings settings () const { return _spi_settings; } - void select () const { if (_spi_select) _spi_select(); } - void deselect () const { if (_spi_deselect) _spi_deselect(); } - uint8_t fill_symbol() const { return _fill_symbol; } -private: - SPISettings _spi_settings; - SpiSelectFunc _spi_select{nullptr}; - SpiDeselectFunc _spi_deselect{nullptr}; - uint8_t _fill_symbol{0xFF}; -}; - class SpiIoRequest : public IoRequest { public: @@ -70,9 +48,6 @@ class SpiBusDevice : public BusDevice } virtual Status transfer(IoRequest & req) override { - if (!_config.good()) - return Status::ConfigError; - reinterpret_cast(&req)->set_config(&_config); /* Insert into queue. */ diff --git a/ThreadsafeIO/src/SpiBusDeviceConfig.h b/ThreadsafeIO/src/SpiBusDeviceConfig.h new file mode 100644 index 0000000..3c6f41d --- /dev/null +++ b/ThreadsafeIO/src/SpiBusDeviceConfig.h @@ -0,0 +1,41 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef SPI_BUS_DEVICE_CONFIG_H_ +#define SPI_BUS_DEVICE_CONFIG_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include +#include + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class SpiBusDeviceConfig +{ +public: + typedef std::function SpiSelectFunc; + typedef std::function SpiDeselectFunc; + SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, uint8_t const fill_symbol = 0xFF) + : _spi_settings{spi_settings} + , _spi_select{spi_select} + , _spi_deselect{spi_deselect} + , _fill_symbol{fill_symbol} + { } + SPISettings settings () const { return _spi_settings; } + void select () const { if (_spi_select) _spi_select(); } + void deselect () const { if (_spi_deselect) _spi_deselect(); } + uint8_t fill_symbol() const { return _fill_symbol; } +private: + SPISettings _spi_settings; + SpiSelectFunc _spi_select{nullptr}; + SpiDeselectFunc _spi_deselect{nullptr}; + uint8_t _fill_symbol{0xFF}; +}; + +#endif /* SPI_BUS_DEVICE_CONFIG_H_ */ \ No newline at end of file From 90514b225e021e3af82237c8eedce32ccd5c0c71 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 14:59:43 +0200 Subject: [PATCH 013/108] Extracting SpiIoRequest. --- ThreadsafeIO/src/IoRequest.h | 16 ++++++++++++++++ ThreadsafeIO/src/SpiBusDevice.h | 21 +++------------------ ThreadsafeIO/src/SpiBusDeviceConfig.h | 3 ++- ThreadsafeIO/src/SpiDispatcher.cpp | 2 +- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index 49e25b4..22bca7c 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -61,4 +61,20 @@ class IoRequest ReadBuf _read_buf; }; +#include "SpiBusDeviceConfig.h" + +class SpiIoRequest : public IoRequest +{ +public: + SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) + : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len, bytes_read) + { } + + void set_config(SpiBusDeviceConfig * config) { _config = config; } + SpiBusDeviceConfig & config() { return *_config; } + +private: + SpiBusDeviceConfig * _config{nullptr}; +}; + #endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/SpiBusDevice.h b/ThreadsafeIO/src/SpiBusDevice.h index cf6ae67..823c2fe 100644 --- a/ThreadsafeIO/src/SpiBusDevice.h +++ b/ThreadsafeIO/src/SpiBusDevice.h @@ -25,20 +25,6 @@ * CLASS DECLARATION **************************************************************************************/ -class SpiIoRequest : public IoRequest -{ -public: - SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) - : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len, bytes_read) - { } - - void set_config(SpiBusDeviceConfig * config) { _config = config; } - SpiBusDeviceConfig & config() { return *_config; } - -private: - SpiBusDeviceConfig * _config{nullptr}; -}; - class SpiBusDevice : public BusDevice { public: @@ -48,11 +34,10 @@ class SpiBusDevice : public BusDevice } virtual Status transfer(IoRequest & req) override { + /* Append SPI bus device specific configuration. */ reinterpret_cast(&req)->set_config(&_config); - - /* Insert into queue. */ + /* Dispatch the request into the queue. */ SpiDispatcher::instance().request(&req); - return Status::Ok; } @@ -62,4 +47,4 @@ class SpiBusDevice : public BusDevice }; -#endif /* SPI_BUS_DEVICE_H_ */ \ No newline at end of file +#endif /* SPI_BUS_DEVICE_H_ */ diff --git a/ThreadsafeIO/src/SpiBusDeviceConfig.h b/ThreadsafeIO/src/SpiBusDeviceConfig.h index 3c6f41d..e27268a 100644 --- a/ThreadsafeIO/src/SpiBusDeviceConfig.h +++ b/ThreadsafeIO/src/SpiBusDeviceConfig.h @@ -11,6 +11,7 @@ #include #include +#include /************************************************************************************** * CLASS DECLARATION @@ -38,4 +39,4 @@ class SpiBusDeviceConfig uint8_t _fill_symbol{0xFF}; }; -#endif /* SPI_BUS_DEVICE_CONFIG_H_ */ \ No newline at end of file +#endif /* SPI_BUS_DEVICE_CONFIG_H_ */ diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index e896038..09710ca 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -135,4 +135,4 @@ void SpiDispatcher::processIoRequest(IoRequest * io_reqest) SPI.endTransaction(); spi_io_request->config().deselect(); -} \ No newline at end of file +} From eb3fb606c93c6c497aa5b976698a34f44ef4d88f Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 15:03:05 +0200 Subject: [PATCH 014/108] Minor refactorings. --- ThreadsafeIO/src/BusDevice.h | 7 +------ ThreadsafeIO/src/SpiBusDevice.h | 5 ++--- ThreadsafeIO/src/SpiDispatcher.cpp | 19 ++++++++++--------- ThreadsafeIO/src/SpiDispatcher.h | 2 +- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/ThreadsafeIO/src/BusDevice.h b/ThreadsafeIO/src/BusDevice.h index 1f3f0d4..227fc7a 100644 --- a/ThreadsafeIO/src/BusDevice.h +++ b/ThreadsafeIO/src/BusDevice.h @@ -20,12 +20,7 @@ class BusDevice public: virtual ~BusDevice() { } - enum class Status : int - { - Ok = 0, - }; - - virtual Status transfer(IoRequest & req) = 0; + virtual bool transfer(IoRequest & req) = 0; }; #endif /* BUS_DEVICE_H_ */ diff --git a/ThreadsafeIO/src/SpiBusDevice.h b/ThreadsafeIO/src/SpiBusDevice.h index 823c2fe..8e60204 100644 --- a/ThreadsafeIO/src/SpiBusDevice.h +++ b/ThreadsafeIO/src/SpiBusDevice.h @@ -32,13 +32,12 @@ class SpiBusDevice : public BusDevice { /* TODO: Select SPI bus based in string. */ } - virtual Status transfer(IoRequest & req) override + virtual bool transfer(IoRequest & req) override { /* Append SPI bus device specific configuration. */ reinterpret_cast(&req)->set_config(&_config); /* Dispatch the request into the queue. */ - SpiDispatcher::instance().request(&req); - return Status::Ok; + return SpiDispatcher::instance().request(&req); } private: diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/SpiDispatcher.cpp index 09710ca..4303c78 100644 --- a/ThreadsafeIO/src/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/SpiDispatcher.cpp @@ -88,21 +88,22 @@ void SpiDispatcher::threadFunc() { _has_tread_started = true; - while(!_terminate_thread) { + while(!_terminate_thread) + { IoRequest * io_reqest = nullptr; - if (_request_queue.try_get(&io_reqest)) { - processIoRequest(io_reqest); + if (_request_queue.try_get(&io_reqest)) + { + if (io_reqest->type() == IoRequest::Type::SPI) + { + SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); + processSpiIoRequest(spi_io_request); + } } } } -void SpiDispatcher::processIoRequest(IoRequest * io_reqest) +void SpiDispatcher::processSpiIoRequest(SpiIoRequest * spi_io_request) { - if (io_reqest->type() != IoRequest::Type::SPI) - return; - - SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); - spi_io_request->config().select(); SPI.beginTransaction(spi_io_request->config().settings()); diff --git a/ThreadsafeIO/src/SpiDispatcher.h b/ThreadsafeIO/src/SpiDispatcher.h index 7260c30..d339d64 100644 --- a/ThreadsafeIO/src/SpiDispatcher.h +++ b/ThreadsafeIO/src/SpiDispatcher.h @@ -47,7 +47,7 @@ class SpiDispatcher void begin(); void end(); void threadFunc(); - void processIoRequest(IoRequest * io_reqest); + void processSpiIoRequest(SpiIoRequest * spi_io_request); }; #endif /* SPI_DISPATCHER_H_ */ From 3d674097a74889b9e3a27712de0af14c48db68b2 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 1 Jul 2021 15:05:38 +0200 Subject: [PATCH 015/108] Move everything into subfolder spi --- ThreadsafeIO/src/IoRequest.h | 2 +- ThreadsafeIO/src/ThreadsafeIO.h | 3 +-- ThreadsafeIO/src/{ => spi}/SpiBusDevice.h | 0 ThreadsafeIO/src/{ => spi}/SpiBusDeviceConfig.h | 0 ThreadsafeIO/src/{ => spi}/SpiDispatcher.cpp | 0 ThreadsafeIO/src/{ => spi}/SpiDispatcher.h | 2 +- 6 files changed, 3 insertions(+), 4 deletions(-) rename ThreadsafeIO/src/{ => spi}/SpiBusDevice.h (100%) rename ThreadsafeIO/src/{ => spi}/SpiBusDeviceConfig.h (100%) rename ThreadsafeIO/src/{ => spi}/SpiDispatcher.cpp (100%) rename ThreadsafeIO/src/{ => spi}/SpiDispatcher.h (97%) diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index 22bca7c..b222b4b 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -61,7 +61,7 @@ class IoRequest ReadBuf _read_buf; }; -#include "SpiBusDeviceConfig.h" +#include "spi/SpiBusDeviceConfig.h" class SpiIoRequest : public IoRequest { diff --git a/ThreadsafeIO/src/ThreadsafeIO.h b/ThreadsafeIO/src/ThreadsafeIO.h index 5ee9e9a..14fa551 100644 --- a/ThreadsafeIO/src/ThreadsafeIO.h +++ b/ThreadsafeIO/src/ThreadsafeIO.h @@ -9,7 +9,6 @@ * INCLUDE **************************************************************************************/ -#include "SpiBusDevice.h" -#include "SpiDispatcher.h" +#include "spi/SpiBusDevice.h" #endif /* THREADSAFE_IO_H_ */ diff --git a/ThreadsafeIO/src/SpiBusDevice.h b/ThreadsafeIO/src/spi/SpiBusDevice.h similarity index 100% rename from ThreadsafeIO/src/SpiBusDevice.h rename to ThreadsafeIO/src/spi/SpiBusDevice.h diff --git a/ThreadsafeIO/src/SpiBusDeviceConfig.h b/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h similarity index 100% rename from ThreadsafeIO/src/SpiBusDeviceConfig.h rename to ThreadsafeIO/src/spi/SpiBusDeviceConfig.h diff --git a/ThreadsafeIO/src/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp similarity index 100% rename from ThreadsafeIO/src/SpiDispatcher.cpp rename to ThreadsafeIO/src/spi/SpiDispatcher.cpp diff --git a/ThreadsafeIO/src/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h similarity index 97% rename from ThreadsafeIO/src/SpiDispatcher.h rename to ThreadsafeIO/src/spi/SpiDispatcher.h index d339d64..cd54ce5 100644 --- a/ThreadsafeIO/src/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -11,7 +11,7 @@ #include -#include "IoRequest.h" +#include "../IoRequest.h" /************************************************************************************** * CLASS DECLARATION From 2eaab0a98ebe6a7a4f79448001af393f9eaa9bb6 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 2 Jul 2021 06:26:02 +0200 Subject: [PATCH 016/108] Extracting SpiIoRequest --- ThreadsafeIO/src/IoRequest.h | 16 ------------- ThreadsafeIO/src/spi/SpiDispatcher.h | 2 +- ThreadsafeIO/src/spi/SpiIoRequest.h | 36 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 ThreadsafeIO/src/spi/SpiIoRequest.h diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index b222b4b..49e25b4 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -61,20 +61,4 @@ class IoRequest ReadBuf _read_buf; }; -#include "spi/SpiBusDeviceConfig.h" - -class SpiIoRequest : public IoRequest -{ -public: - SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) - : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len, bytes_read) - { } - - void set_config(SpiBusDeviceConfig * config) { _config = config; } - SpiBusDeviceConfig & config() { return *_config; } - -private: - SpiBusDeviceConfig * _config{nullptr}; -}; - #endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index cd54ce5..dd1b5ab 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -11,7 +11,7 @@ #include -#include "../IoRequest.h" +#include "SpiIoRequest.h" /************************************************************************************** * CLASS DECLARATION diff --git a/ThreadsafeIO/src/spi/SpiIoRequest.h b/ThreadsafeIO/src/spi/SpiIoRequest.h new file mode 100644 index 0000000..0d16639 --- /dev/null +++ b/ThreadsafeIO/src/spi/SpiIoRequest.h @@ -0,0 +1,36 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef SPI_IO_REQUEST_H_ +#define SPI_IO_REQUEST_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "../IoRequest.h" + +#include "SpiBusDeviceConfig.h" + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class SpiIoRequest : public IoRequest +{ +public: + + SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) + : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len, bytes_read) + { } + + void set_config(SpiBusDeviceConfig * config) { _config = config; } + SpiBusDeviceConfig & config() { return *_config; } + +private: + + SpiBusDeviceConfig * _config{nullptr}; +}; + +#endif /* SPI_IO_REQUEST_H_ */ \ No newline at end of file From 920ba3f85c925ffc77b1ff6d159be0e8affeb1a4 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 2 Jul 2021 07:14:00 +0200 Subject: [PATCH 017/108] Async waiting step 1 ... --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 12 ++++-- ThreadsafeIO/src/BusDevice.h | 3 +- ThreadsafeIO/src/IoResponse.h | 49 +++++++++++++++++++++++++ ThreadsafeIO/src/spi/SpiBusDevice.h | 2 +- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 21 +++++++++-- ThreadsafeIO/src/spi/SpiDispatcher.h | 14 ++++++- 6 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 ThreadsafeIO/src/IoResponse.h diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index e19dbd5..f3df5e0 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -51,11 +51,17 @@ void setup() SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf), &bytes_read); - bmp388.transfer(req); + IoResponse * rsp = bmp388.transfer(req); - rtos::ThisThread::sleep_for(5000); /* TODO: Wait for results, otherwise the rx/tx buffers go out of range. */ + /* TODO: Compact this in some way. */ + rsp->_mutex.lock(); + rsp->_cond.wait(); + uint8_t const reg_val = rx_buf[2]; + rsp->_mutex.unlock(); - return rx_buf[2]; + //rtos::ThisThread::sleep_for(5000); /* TODO: Wait for results, otherwise the rx/tx buffers go out of range. */ + + return reg_val;//rx_buf[2]; }; uint8_t const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); diff --git a/ThreadsafeIO/src/BusDevice.h b/ThreadsafeIO/src/BusDevice.h index 227fc7a..041eea5 100644 --- a/ThreadsafeIO/src/BusDevice.h +++ b/ThreadsafeIO/src/BusDevice.h @@ -10,6 +10,7 @@ **************************************************************************************/ #include "IoRequest.h" +#include "IoResponse.h" /************************************************************************************** * CLASS DECLARATION @@ -20,7 +21,7 @@ class BusDevice public: virtual ~BusDevice() { } - virtual bool transfer(IoRequest & req) = 0; + virtual IoResponse * transfer(IoRequest & req) = 0; }; #endif /* BUS_DEVICE_H_ */ diff --git a/ThreadsafeIO/src/IoResponse.h b/ThreadsafeIO/src/IoResponse.h new file mode 100644 index 0000000..d25442d --- /dev/null +++ b/ThreadsafeIO/src/IoResponse.h @@ -0,0 +1,49 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef IO_RESPONSE_H_ +#define IO_RESPONSE_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +#include + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class IoResponse +{ +public: + + class ReadBuf + { + public: + ReadBuf(uint8_t * d, size_t * br) : data{d}, bytes_read{br} { } + uint8_t * data{nullptr}; + size_t * bytes_read{0}; + }; + + + IoResponse(uint8_t * rx_buf, size_t * bytes_read) + : _read_buf{rx_buf, bytes_read} + , _cond{_mutex} + { } + + inline ReadBuf & read_buf () { return _read_buf; } + + rtos::Mutex _mutex; + rtos::ConditionVariable _cond; + +private: + + ReadBuf _read_buf; + +}; + +#endif /* IO_RESPONSE_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/spi/SpiBusDevice.h b/ThreadsafeIO/src/spi/SpiBusDevice.h index 8e60204..c8d3caf 100644 --- a/ThreadsafeIO/src/spi/SpiBusDevice.h +++ b/ThreadsafeIO/src/spi/SpiBusDevice.h @@ -32,7 +32,7 @@ class SpiBusDevice : public BusDevice { /* TODO: Select SPI bus based in string. */ } - virtual bool transfer(IoRequest & req) override + virtual IoResponse * transfer(IoRequest & req) override { /* Append SPI bus device specific configuration. */ reinterpret_cast(&req)->set_config(&_config); diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 4303c78..0a61add 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -56,10 +56,17 @@ void SpiDispatcher::destroy() _p_instance = nullptr; } -bool SpiDispatcher::request(IoRequest * req) +IoResponse * SpiDispatcher::request(IoRequest * req) { mbed::ScopedLock lock(_mutex); - return _request_queue.try_put(req); + /* ATTENTION!!! MEM LEAK HERE!!! */ + IoResponse * rsp = new IoResponse{req->read_buf().data, req->read_buf().bytes_read}; + IoTransaction * io_transaction = new IoTransaction(req, rsp); + if (_request_queue.try_put(io_transaction)) { + return rsp; + } else { + return nullptr; + } } /************************************************************************************** @@ -90,13 +97,19 @@ void SpiDispatcher::threadFunc() while(!_terminate_thread) { - IoRequest * io_reqest = nullptr; - if (_request_queue.try_get(&io_reqest)) + IoTransaction * io_transaction = nullptr; + if (_request_queue.try_get(&io_transaction)) { + IoRequest * io_reqest = io_transaction->req; + IoResponse * io_response = io_transaction->rsp; if (io_reqest->type() == IoRequest::Type::SPI) { SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); + + io_response->_mutex.lock(); processSpiIoRequest(spi_io_request); + io_response->_cond.notify_all(); + io_response->_mutex.unlock(); } } } diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index dd1b5ab..f09921f 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -11,6 +11,8 @@ #include +#include "../IoResponse.h" + #include "SpiIoRequest.h" /************************************************************************************** @@ -27,7 +29,7 @@ class SpiDispatcher static SpiDispatcher & instance(); static void destroy(); - bool request(IoRequest * req); + IoResponse * request(IoRequest * req); private: @@ -38,8 +40,16 @@ class SpiDispatcher bool _has_tread_started; bool _terminate_thread; + class IoTransaction + { + public: + IoTransaction(IoRequest * q, IoResponse * p) : req{q}, rsp{p} { } + IoRequest * req{nullptr}; + IoResponse * rsp{nullptr}; + }; + static size_t constexpr REQUEST_QUEUE_SIZE = 32; - rtos::Queue _request_queue; + rtos::Queue _request_queue; SpiDispatcher(); ~SpiDispatcher(); From ddcb1837245f54025e89b7946ca30899bc614ed3 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 11:02:10 +0200 Subject: [PATCH 018/108] Using SharedPtr eliminates the issue of memory leaks. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 6 ++++-- ThreadsafeIO/src/BusDevice.h | 4 +++- ThreadsafeIO/src/IoResponse.h | 3 +++ ThreadsafeIO/src/spi/SpiBusDevice.h | 3 +-- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 7 ++++--- ThreadsafeIO/src/spi/SpiDispatcher.h | 2 +- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index f3df5e0..a7e09ea 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -50,13 +50,15 @@ void setup() size_t bytes_read = 0; SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf), &bytes_read); + + /* NOTE!!! TURN THIS INTO AN IoTransaction and return in IoResponse bytes_written as well as bytes_read */ - IoResponse * rsp = bmp388.transfer(req); + TSharedIoResponse rsp = bmp388.transfer(req); /* TODO: Compact this in some way. */ rsp->_mutex.lock(); rsp->_cond.wait(); - uint8_t const reg_val = rx_buf[2]; + uint8_t const reg_val = rsp->read_buf().data[2]; rsp->_mutex.unlock(); //rtos::ThisThread::sleep_for(5000); /* TODO: Wait for results, otherwise the rx/tx buffers go out of range. */ diff --git a/ThreadsafeIO/src/BusDevice.h b/ThreadsafeIO/src/BusDevice.h index 041eea5..14a8cec 100644 --- a/ThreadsafeIO/src/BusDevice.h +++ b/ThreadsafeIO/src/BusDevice.h @@ -12,6 +12,8 @@ #include "IoRequest.h" #include "IoResponse.h" +#include + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -21,7 +23,7 @@ class BusDevice public: virtual ~BusDevice() { } - virtual IoResponse * transfer(IoRequest & req) = 0; + virtual TSharedIoResponse transfer(IoRequest & req) = 0; }; #endif /* BUS_DEVICE_H_ */ diff --git a/ThreadsafeIO/src/IoResponse.h b/ThreadsafeIO/src/IoResponse.h index d25442d..771d1e0 100644 --- a/ThreadsafeIO/src/IoResponse.h +++ b/ThreadsafeIO/src/IoResponse.h @@ -12,6 +12,7 @@ #include #include +#include /************************************************************************************** * CLASS DECLARATION @@ -46,4 +47,6 @@ class IoResponse }; +typedef mbed::SharedPtr TSharedIoResponse; + #endif /* IO_RESPONSE_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/spi/SpiBusDevice.h b/ThreadsafeIO/src/spi/SpiBusDevice.h index c8d3caf..83830c8 100644 --- a/ThreadsafeIO/src/spi/SpiBusDevice.h +++ b/ThreadsafeIO/src/spi/SpiBusDevice.h @@ -15,7 +15,6 @@ #include #include -#include "IoRequest.h" #include "BusDevice.h" #include "SpiDispatcher.h" @@ -32,7 +31,7 @@ class SpiBusDevice : public BusDevice { /* TODO: Select SPI bus based in string. */ } - virtual IoResponse * transfer(IoRequest & req) override + virtual TSharedIoResponse transfer(IoRequest & req) override { /* Append SPI bus device specific configuration. */ reinterpret_cast(&req)->set_config(&_config); diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 0a61add..75893a5 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -56,12 +56,13 @@ void SpiDispatcher::destroy() _p_instance = nullptr; } -IoResponse * SpiDispatcher::request(IoRequest * req) +TSharedIoResponse SpiDispatcher::request(IoRequest * req) { mbed::ScopedLock lock(_mutex); + TSharedIoResponse rsp(new IoResponse{req->read_buf().data, req->read_buf().bytes_read}); /* ATTENTION!!! MEM LEAK HERE!!! */ - IoResponse * rsp = new IoResponse{req->read_buf().data, req->read_buf().bytes_read}; - IoTransaction * io_transaction = new IoTransaction(req, rsp); + /* Turn Queue into Mailbox for IO transactions. */ + IoTransaction * io_transaction = new IoTransaction(req, rsp.get()); if (_request_queue.try_put(io_transaction)) { return rsp; } else { diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index f09921f..2aa25e2 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -29,7 +29,7 @@ class SpiDispatcher static SpiDispatcher & instance(); static void destroy(); - IoResponse * request(IoRequest * req); + TSharedIoResponse request(IoRequest * req); private: From ab763eaab847ec043ba45dc289f515e2894db640 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 11:03:49 +0200 Subject: [PATCH 019/108] Renaming 'request' to 'dispatch' --- ThreadsafeIO/src/spi/SpiBusDevice.h | 2 +- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 2 +- ThreadsafeIO/src/spi/SpiDispatcher.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ThreadsafeIO/src/spi/SpiBusDevice.h b/ThreadsafeIO/src/spi/SpiBusDevice.h index 83830c8..c36b961 100644 --- a/ThreadsafeIO/src/spi/SpiBusDevice.h +++ b/ThreadsafeIO/src/spi/SpiBusDevice.h @@ -36,7 +36,7 @@ class SpiBusDevice : public BusDevice /* Append SPI bus device specific configuration. */ reinterpret_cast(&req)->set_config(&_config); /* Dispatch the request into the queue. */ - return SpiDispatcher::instance().request(&req); + return SpiDispatcher::instance().dispatch(&req); } private: diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 75893a5..7516dee 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -56,7 +56,7 @@ void SpiDispatcher::destroy() _p_instance = nullptr; } -TSharedIoResponse SpiDispatcher::request(IoRequest * req) +TSharedIoResponse SpiDispatcher::dispatch(IoRequest * req) { mbed::ScopedLock lock(_mutex); TSharedIoResponse rsp(new IoResponse{req->read_buf().data, req->read_buf().bytes_read}); diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index 2aa25e2..e622251 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -29,7 +29,7 @@ class SpiDispatcher static SpiDispatcher & instance(); static void destroy(); - TSharedIoResponse request(IoRequest * req); + TSharedIoResponse dispatch(IoRequest * req); private: From 3c963d3d3d8fbe7ce4688fa46d45c0191744a2e5 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 11:15:41 +0200 Subject: [PATCH 020/108] Simplifying Input and Output buffer (IoRequest/IoResponse) --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 5 ++- ThreadsafeIO/src/IoRequest.h | 47 ++++++++----------------- ThreadsafeIO/src/IoResponse.h | 26 +++++--------- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 12 +++---- ThreadsafeIO/src/spi/SpiIoRequest.h | 4 +-- 5 files changed, 33 insertions(+), 61 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index a7e09ea..1be4c38 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -47,9 +47,8 @@ void setup() { uint8_t const tx_buf[3] = {static_cast(0x80 | reg_addr), 0, 0}; uint8_t rx_buf[3] = {0}; - size_t bytes_read = 0; - SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf), &bytes_read); + SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf)); /* NOTE!!! TURN THIS INTO AN IoTransaction and return in IoResponse bytes_written as well as bytes_read */ @@ -58,7 +57,7 @@ void setup() /* TODO: Compact this in some way. */ rsp->_mutex.lock(); rsp->_cond.wait(); - uint8_t const reg_val = rsp->read_buf().data[2]; + uint8_t const reg_val = rsp->read_buf[2]; rsp->_mutex.unlock(); //rtos::ThisThread::sleep_for(5000); /* TODO: Wait for results, otherwise the rx/tx buffers go out of range. */ diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index 49e25b4..8b6c757 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -19,46 +19,29 @@ class IoRequest { public: - enum class Type - { - None, - SPI - }; - - class WriteBuf - { - public: - WriteBuf(uint8_t const * const d, size_t const b2w) : data{d}, bytes_to_write{b2w} { } - uint8_t const * const data{nullptr}; - size_t const bytes_to_write{0}; - }; + enum class Type { None, SPI }; + + IoRequest(Type const type, uint8_t const * const write_buf_, size_t const bytes_to_write_, uint8_t * read_buf_, size_t const bytes_to_read_) + : write_buf{write_buf_} + , bytes_to_write{bytes_to_write_} + , read_buf{read_buf_} + , bytes_to_read{bytes_to_read_} + , _type{type} + { } - class ReadBuf - { - public: - ReadBuf(uint8_t * d, size_t const b2r, size_t * br) : data{d}, bytes_to_read{b2r}, bytes_read{br} { } - uint8_t * data{nullptr}; - size_t const bytes_to_read{0}; - size_t * bytes_read{0}; - }; + inline Type type() const { return _type; } - IoRequest(Type const type, uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) - : _type{type} - , _write_buf{tx_buf, tx_buf_len} - , _read_buf{rx_buf, rx_buf_len, bytes_read} - { } + uint8_t const * const write_buf{nullptr}; + size_t const bytes_to_write{0}; + uint8_t * read_buf{nullptr}; + size_t const bytes_to_read{0}; - inline Type type () const { return _type; } - inline WriteBuf & write_buf() { return _write_buf; } - inline ReadBuf & read_buf () { return _read_buf; } - private: Type _type{Type::None}; - WriteBuf _write_buf; - ReadBuf _read_buf; + }; #endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/IoResponse.h b/ThreadsafeIO/src/IoResponse.h index 771d1e0..d523872 100644 --- a/ThreadsafeIO/src/IoResponse.h +++ b/ThreadsafeIO/src/IoResponse.h @@ -22,28 +22,18 @@ class IoResponse { public: - class ReadBuf - { - public: - ReadBuf(uint8_t * d, size_t * br) : data{d}, bytes_read{br} { } - uint8_t * data{nullptr}; - size_t * bytes_read{0}; - }; - - - IoResponse(uint8_t * rx_buf, size_t * bytes_read) - : _read_buf{rx_buf, bytes_read} - , _cond{_mutex} + IoResponse(uint8_t * read_buf_) + : _cond{_mutex} + , read_buf{read_buf_} + , bytes_written{0} + , bytes_read{0} { } - inline ReadBuf & read_buf () { return _read_buf; } - rtos::Mutex _mutex; rtos::ConditionVariable _cond; - -private: - - ReadBuf _read_buf; + uint8_t * read_buf{nullptr}; + size_t bytes_written{0}; + size_t bytes_read{0}; }; diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 7516dee..f7c0ce8 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -59,7 +59,7 @@ void SpiDispatcher::destroy() TSharedIoResponse SpiDispatcher::dispatch(IoRequest * req) { mbed::ScopedLock lock(_mutex); - TSharedIoResponse rsp(new IoResponse{req->read_buf().data, req->read_buf().bytes_read}); + TSharedIoResponse rsp(new IoResponse{req->read_buf}); /* ATTENTION!!! MEM LEAK HERE!!! */ /* Turn Queue into Mailbox for IO transactions. */ IoTransaction * io_transaction = new IoTransaction(req, rsp.get()); @@ -125,13 +125,13 @@ void SpiDispatcher::processSpiIoRequest(SpiIoRequest * spi_io_request) size_t bytes_received = 0, bytes_sent = 0; for(; - bytes_received < spi_io_request->read_buf().bytes_to_read; + bytes_received < spi_io_request->bytes_to_read; bytes_received++, bytes_sent++) { uint8_t tx_byte = 0; - if (bytes_sent < spi_io_request->write_buf().bytes_to_write) - tx_byte = spi_io_request->write_buf().data[bytes_sent]; + if (bytes_sent < spi_io_request->bytes_to_write) + tx_byte = spi_io_request->write_buf[bytes_sent]; else tx_byte = spi_io_request->config().fill_symbol(); @@ -143,9 +143,9 @@ void SpiDispatcher::processSpiIoRequest(SpiIoRequest * spi_io_request) Serial.print(rx_byte, HEX); Serial.println(); - spi_io_request->read_buf().data[bytes_received] = rx_byte; + spi_io_request->read_buf[bytes_received] = rx_byte; } - *spi_io_request->read_buf().bytes_read = bytes_received; + //*spi_io_request->read_buf().bytes_read = bytes_received; SPI.endTransaction(); diff --git a/ThreadsafeIO/src/spi/SpiIoRequest.h b/ThreadsafeIO/src/spi/SpiIoRequest.h index 0d16639..2f51717 100644 --- a/ThreadsafeIO/src/spi/SpiIoRequest.h +++ b/ThreadsafeIO/src/spi/SpiIoRequest.h @@ -21,8 +21,8 @@ class SpiIoRequest : public IoRequest { public: - SpiIoRequest(uint8_t const * const tx_buf, size_t const tx_buf_len, uint8_t * rx_buf, size_t const rx_buf_len, size_t * bytes_read) - : IoRequest(IoRequest::Type::SPI, tx_buf, tx_buf_len, rx_buf, rx_buf_len, bytes_read) + SpiIoRequest(uint8_t const * const write_buf, size_t const bytes_to_write, uint8_t * read_buf, size_t const bytes_to_read) + : IoRequest(IoRequest::Type::SPI, write_buf, bytes_to_write, read_buf, bytes_to_read) { } void set_config(SpiBusDeviceConfig * config) { _config = config; } From 14ff754396f71b9b094c6d9dad17a07afd426f5d Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 11:38:41 +0200 Subject: [PATCH 021/108] Pass IoTransactions instead of IoRequest/IoResponses. --- ThreadsafeIO/src/IoRequest.h | 12 +------- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 42 ++++++++++++-------------- ThreadsafeIO/src/spi/SpiDispatcher.h | 2 +- ThreadsafeIO/src/spi/SpiIoRequest.h | 2 +- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h index 8b6c757..83a1f60 100644 --- a/ThreadsafeIO/src/IoRequest.h +++ b/ThreadsafeIO/src/IoRequest.h @@ -19,29 +19,19 @@ class IoRequest { public: - enum class Type { None, SPI }; - - IoRequest(Type const type, uint8_t const * const write_buf_, size_t const bytes_to_write_, uint8_t * read_buf_, size_t const bytes_to_read_) + IoRequest(uint8_t const * const write_buf_, size_t const bytes_to_write_, uint8_t * read_buf_, size_t const bytes_to_read_) : write_buf{write_buf_} , bytes_to_write{bytes_to_write_} , read_buf{read_buf_} , bytes_to_read{bytes_to_read_} - , _type{type} { } - inline Type type() const { return _type; } - uint8_t const * const write_buf{nullptr}; size_t const bytes_to_write{0}; uint8_t * read_buf{nullptr}; size_t const bytes_to_read{0}; - -private: - - Type _type{Type::None}; - }; #endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index f7c0ce8..d1d198c 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -100,40 +100,33 @@ void SpiDispatcher::threadFunc() { IoTransaction * io_transaction = nullptr; if (_request_queue.try_get(&io_transaction)) - { - IoRequest * io_reqest = io_transaction->req; - IoResponse * io_response = io_transaction->rsp; - if (io_reqest->type() == IoRequest::Type::SPI) - { - SpiIoRequest * spi_io_request = reinterpret_cast(io_reqest); - - io_response->_mutex.lock(); - processSpiIoRequest(spi_io_request); - io_response->_cond.notify_all(); - io_response->_mutex.unlock(); - } - } + processSpiIoRequest(io_transaction); } } -void SpiDispatcher::processSpiIoRequest(SpiIoRequest * spi_io_request) +void SpiDispatcher::processSpiIoRequest(IoTransaction * io_transaction) { - spi_io_request->config().select(); + IoResponse * io_response = io_transaction->rsp; + SpiIoRequest * io_request = reinterpret_cast(io_transaction->req); - SPI.beginTransaction(spi_io_request->config().settings()); + io_response->_mutex.lock(); + + io_request->config().select(); + + SPI.beginTransaction(io_request->config().settings()); size_t bytes_received = 0, bytes_sent = 0; for(; - bytes_received < spi_io_request->bytes_to_read; + bytes_received < io_request->bytes_to_read; bytes_received++, bytes_sent++) { uint8_t tx_byte = 0; - if (bytes_sent < spi_io_request->bytes_to_write) - tx_byte = spi_io_request->write_buf[bytes_sent]; + if (bytes_sent < io_request->bytes_to_write) + tx_byte = io_request->write_buf[bytes_sent]; else - tx_byte = spi_io_request->config().fill_symbol(); + tx_byte = io_request->config().fill_symbol(); uint8_t const rx_byte = SPI.transfer(tx_byte); @@ -143,11 +136,14 @@ void SpiDispatcher::processSpiIoRequest(SpiIoRequest * spi_io_request) Serial.print(rx_byte, HEX); Serial.println(); - spi_io_request->read_buf[bytes_received] = rx_byte; + io_request->read_buf[bytes_received] = rx_byte; } - //*spi_io_request->read_buf().bytes_read = bytes_received; + //*io_request->read_buf().bytes_read = bytes_received; SPI.endTransaction(); - spi_io_request->config().deselect(); + io_request->config().deselect(); + + io_response->_cond.notify_all(); + io_response->_mutex.unlock(); } diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index e622251..b9e0fd4 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -57,7 +57,7 @@ class SpiDispatcher void begin(); void end(); void threadFunc(); - void processSpiIoRequest(SpiIoRequest * spi_io_request); + void processSpiIoRequest(IoTransaction * io_transaction); }; #endif /* SPI_DISPATCHER_H_ */ diff --git a/ThreadsafeIO/src/spi/SpiIoRequest.h b/ThreadsafeIO/src/spi/SpiIoRequest.h index 2f51717..89a02cb 100644 --- a/ThreadsafeIO/src/spi/SpiIoRequest.h +++ b/ThreadsafeIO/src/spi/SpiIoRequest.h @@ -22,7 +22,7 @@ class SpiIoRequest : public IoRequest public: SpiIoRequest(uint8_t const * const write_buf, size_t const bytes_to_write, uint8_t * read_buf, size_t const bytes_to_read) - : IoRequest(IoRequest::Type::SPI, write_buf, bytes_to_write, read_buf, bytes_to_read) + : IoRequest(write_buf, bytes_to_write, read_buf, bytes_to_read) { } void set_config(SpiBusDeviceConfig * config) { _config = config; } From c0b9db6dee1d0c7a26e4f57fd637fcc53a4a1e23 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 11:42:05 +0200 Subject: [PATCH 022/108] Also transport information on how many bytes have been read/how many bytes have been written. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 9 +++++---- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 1be4c38..237a7e4 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -50,8 +50,6 @@ void setup() SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf)); - /* NOTE!!! TURN THIS INTO AN IoTransaction and return in IoResponse bytes_written as well as bytes_read */ - TSharedIoResponse rsp = bmp388.transfer(req); /* TODO: Compact this in some way. */ @@ -60,9 +58,12 @@ void setup() uint8_t const reg_val = rsp->read_buf[2]; rsp->_mutex.unlock(); - //rtos::ThisThread::sleep_for(5000); /* TODO: Wait for results, otherwise the rx/tx buffers go out of range. */ + Serial.print(rsp->bytes_written); + Serial.print(" bytes written, "); + Serial.print(rsp->bytes_read); + Serial.println(" bytes read"); - return reg_val;//rx_buf[2]; + return reg_val; }; uint8_t const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index d1d198c..4ad6fbf 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -138,12 +138,13 @@ void SpiDispatcher::processSpiIoRequest(IoTransaction * io_transaction) io_request->read_buf[bytes_received] = rx_byte; } - //*io_request->read_buf().bytes_read = bytes_received; - SPI.endTransaction(); io_request->config().deselect(); + io_response->bytes_written = bytes_sent; + io_response->bytes_read = bytes_received; + io_response->_cond.notify_all(); io_response->_mutex.unlock(); } From b0d61eaa0d3dcdcad2d2eda5f8e858b1eeddb839 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 11:45:21 +0200 Subject: [PATCH 023/108] Encapsulate the waiting in a function. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 7 +++---- ThreadsafeIO/src/IoResponse.h | 7 +++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 237a7e4..89c0915 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -52,11 +52,10 @@ void setup() TSharedIoResponse rsp = bmp388.transfer(req); - /* TODO: Compact this in some way. */ - rsp->_mutex.lock(); - rsp->_cond.wait(); + /* Do other stuff */ + + rsp->wait(); uint8_t const reg_val = rsp->read_buf[2]; - rsp->_mutex.unlock(); Serial.print(rsp->bytes_written); Serial.print(" bytes written, "); diff --git a/ThreadsafeIO/src/IoResponse.h b/ThreadsafeIO/src/IoResponse.h index d523872..5d20d66 100644 --- a/ThreadsafeIO/src/IoResponse.h +++ b/ThreadsafeIO/src/IoResponse.h @@ -35,6 +35,13 @@ class IoResponse size_t bytes_written{0}; size_t bytes_read{0}; + void wait() + { + _mutex.lock(); /* Do we really need to lock/unlock the mutex? */ + _cond.wait(); + _mutex.unlock(); + } + }; typedef mbed::SharedPtr TSharedIoResponse; From 30b05422f6d6d695128a4a11abcb087ab8f93c72 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 13:59:38 +0200 Subject: [PATCH 024/108] Consolating IoRequest and IoResponse within IoTransaction. --- ThreadsafeIO/src/BusDevice.h | 5 +- ThreadsafeIO/src/IoRequest.h | 37 ------------ ThreadsafeIO/src/IoResponse.h | 49 --------------- ThreadsafeIO/src/IoTransaction.h | 89 ++++++++++++++++++++++++++++ ThreadsafeIO/src/spi/SpiDispatcher.h | 10 +--- ThreadsafeIO/src/spi/SpiIoRequest.h | 2 +- 6 files changed, 92 insertions(+), 100 deletions(-) delete mode 100644 ThreadsafeIO/src/IoRequest.h delete mode 100644 ThreadsafeIO/src/IoResponse.h create mode 100644 ThreadsafeIO/src/IoTransaction.h diff --git a/ThreadsafeIO/src/BusDevice.h b/ThreadsafeIO/src/BusDevice.h index 14a8cec..e2da44d 100644 --- a/ThreadsafeIO/src/BusDevice.h +++ b/ThreadsafeIO/src/BusDevice.h @@ -9,10 +9,7 @@ * INCLUDE **************************************************************************************/ -#include "IoRequest.h" -#include "IoResponse.h" - -#include +#include "IoTransaction.h" /************************************************************************************** * CLASS DECLARATION diff --git a/ThreadsafeIO/src/IoRequest.h b/ThreadsafeIO/src/IoRequest.h deleted file mode 100644 index 83a1f60..0000000 --- a/ThreadsafeIO/src/IoRequest.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * A deeply magical library providing threadsafe IO via pipes. - */ - -#ifndef IO_REQUEST_H_ -#define IO_REQUEST_H_ - -/************************************************************************************** - * INCLUDE - **************************************************************************************/ - -#include - -/************************************************************************************** - * CLASS DECLARATION - **************************************************************************************/ - -class IoRequest -{ -public: - - IoRequest(uint8_t const * const write_buf_, size_t const bytes_to_write_, uint8_t * read_buf_, size_t const bytes_to_read_) - : write_buf{write_buf_} - , bytes_to_write{bytes_to_write_} - , read_buf{read_buf_} - , bytes_to_read{bytes_to_read_} - { } - - - uint8_t const * const write_buf{nullptr}; - size_t const bytes_to_write{0}; - uint8_t * read_buf{nullptr}; - size_t const bytes_to_read{0}; - -}; - -#endif /* IO_REQUEST_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/IoResponse.h b/ThreadsafeIO/src/IoResponse.h deleted file mode 100644 index 5d20d66..0000000 --- a/ThreadsafeIO/src/IoResponse.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * A deeply magical library providing threadsafe IO via pipes. - */ - -#ifndef IO_RESPONSE_H_ -#define IO_RESPONSE_H_ - -/************************************************************************************** - * INCLUDE - **************************************************************************************/ - -#include - -#include -#include - -/************************************************************************************** - * CLASS DECLARATION - **************************************************************************************/ - -class IoResponse -{ -public: - - IoResponse(uint8_t * read_buf_) - : _cond{_mutex} - , read_buf{read_buf_} - , bytes_written{0} - , bytes_read{0} - { } - - rtos::Mutex _mutex; - rtos::ConditionVariable _cond; - uint8_t * read_buf{nullptr}; - size_t bytes_written{0}; - size_t bytes_read{0}; - - void wait() - { - _mutex.lock(); /* Do we really need to lock/unlock the mutex? */ - _cond.wait(); - _mutex.unlock(); - } - -}; - -typedef mbed::SharedPtr TSharedIoResponse; - -#endif /* IO_RESPONSE_H_ */ \ No newline at end of file diff --git a/ThreadsafeIO/src/IoTransaction.h b/ThreadsafeIO/src/IoTransaction.h new file mode 100644 index 0000000..27e6f83 --- /dev/null +++ b/ThreadsafeIO/src/IoTransaction.h @@ -0,0 +1,89 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef IO_TRANSACTION_H_ +#define IO_TRANSACTION_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +#include +#include + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +/************************************************************************************** + * IoRequest + **************************************************************************************/ + +class IoRequest +{ +public: + + IoRequest(uint8_t const * const write_buf_, size_t const bytes_to_write_, uint8_t * read_buf_, size_t const bytes_to_read_) + : write_buf{write_buf_} + , bytes_to_write{bytes_to_write_} + , read_buf{read_buf_} + , bytes_to_read{bytes_to_read_} + { } + + + uint8_t const * const write_buf{nullptr}; + size_t const bytes_to_write{0}; + uint8_t * read_buf{nullptr}; + size_t const bytes_to_read{0}; + +}; + +/************************************************************************************** + * IoResponse + **************************************************************************************/ + +class IoResponse +{ +public: + + IoResponse(uint8_t * read_buf_) + : _cond{_mutex} + , read_buf{read_buf_} + , bytes_written{0} + , bytes_read{0} + { } + + rtos::Mutex _mutex; + rtos::ConditionVariable _cond; + uint8_t * read_buf{nullptr}; + size_t bytes_written{0}; + size_t bytes_read{0}; + + void wait() + { + _mutex.lock(); /* Do we really need to lock/unlock the mutex? */ + _cond.wait(); + _mutex.unlock(); + } + +}; + +typedef mbed::SharedPtr TSharedIoResponse; + +/************************************************************************************** + * IoTransaction + **************************************************************************************/ + +class IoTransaction +{ +public: + + IoTransaction(IoRequest * q, IoResponse * p) : req{q}, rsp{p} { } + IoRequest * req{nullptr}; + IoResponse * rsp{nullptr}; +}; + +#endif /* IO_TRANSACTION_H_ */ diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index b9e0fd4..26ef8bd 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -11,7 +11,7 @@ #include -#include "../IoResponse.h" +#include "../IoTransaction.h" #include "SpiIoRequest.h" @@ -40,14 +40,6 @@ class SpiDispatcher bool _has_tread_started; bool _terminate_thread; - class IoTransaction - { - public: - IoTransaction(IoRequest * q, IoResponse * p) : req{q}, rsp{p} { } - IoRequest * req{nullptr}; - IoResponse * rsp{nullptr}; - }; - static size_t constexpr REQUEST_QUEUE_SIZE = 32; rtos::Queue _request_queue; diff --git a/ThreadsafeIO/src/spi/SpiIoRequest.h b/ThreadsafeIO/src/spi/SpiIoRequest.h index 89a02cb..94ae62e 100644 --- a/ThreadsafeIO/src/spi/SpiIoRequest.h +++ b/ThreadsafeIO/src/spi/SpiIoRequest.h @@ -9,7 +9,7 @@ * INCLUDE **************************************************************************************/ -#include "../IoRequest.h" +#include "../IoTransaction.h" #include "SpiBusDeviceConfig.h" From 22f55a956e83e090a7065099469bc67377f47686 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 14:13:08 +0200 Subject: [PATCH 025/108] Replacing the Queue with a Mailbox, therefore eliminating the last memory leak. --- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 33 +++++++++++++++++++------- ThreadsafeIO/src/spi/SpiDispatcher.h | 2 +- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 4ad6fbf..44330d8 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -62,12 +62,16 @@ TSharedIoResponse SpiDispatcher::dispatch(IoRequest * req) TSharedIoResponse rsp(new IoResponse{req->read_buf}); /* ATTENTION!!! MEM LEAK HERE!!! */ /* Turn Queue into Mailbox for IO transactions. */ - IoTransaction * io_transaction = new IoTransaction(req, rsp.get()); - if (_request_queue.try_put(io_transaction)) { - return rsp; - } else { + IoTransaction * io_transaction = _spi_io_transaction_mailbox.try_alloc(); + if (!io_transaction) return nullptr; - } + + io_transaction->req = req; + io_transaction->rsp = rsp.get(); + + _spi_io_transaction_mailbox.put(io_transaction); + + return rsp; } /************************************************************************************** @@ -98,9 +102,22 @@ void SpiDispatcher::threadFunc() while(!_terminate_thread) { - IoTransaction * io_transaction = nullptr; - if (_request_queue.try_get(&io_transaction)) - processSpiIoRequest(io_transaction); + /* Wait blocking for the next IO transaction + * request to be posted to the mailbox. + */ + osEvent evt = _spi_io_transaction_mailbox.get(); + if (evt.status == osEventMail) + { + /* Fetch the IO transaction request and + * process it. + */ + IoTransaction * io_transaction = reinterpret_cast(evt.value.p); + processSpiIoRequest(io_transaction); + /* Free the allocated memory (memory allocated + * during dispatch(...) + */ + _spi_io_transaction_mailbox.free(io_transaction); + } } } diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index 26ef8bd..9d8e75e 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -41,7 +41,7 @@ class SpiDispatcher bool _terminate_thread; static size_t constexpr REQUEST_QUEUE_SIZE = 32; - rtos::Queue _request_queue; + rtos::Mail _spi_io_transaction_mailbox; SpiDispatcher(); ~SpiDispatcher(); From 5b82cc785cd5cfa299a6eb049d0b2b6d683f54e4 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 14:29:34 +0200 Subject: [PATCH 026/108] Extending example code to whip up 20 threads and do parallel SPI access. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 69 +++++++++++++++++-------- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 4 +- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 89c0915..94930e6 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -18,6 +18,8 @@ static uint8_t const BMP388_CHIP_ID_REG_ADDR = 0x00; void bmp388_select(); void bmp388_deselect(); +byte bmp388_read_reg(byte const reg_addr); +void bmp388_thread_func(); /************************************************************************************** * GLOBAL VARIABLES @@ -43,31 +45,17 @@ void setup() pinMode(BMP388_CS_PIN, OUTPUT); digitalWrite(BMP388_CS_PIN, HIGH); - auto bmp388_read_reg = [](uint8_t const reg_addr) -> uint8_t - { - uint8_t const tx_buf[3] = {static_cast(0x80 | reg_addr), 0, 0}; - uint8_t rx_buf[3] = {0}; - - SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf)); - - TSharedIoResponse rsp = bmp388.transfer(req); - - /* Do other stuff */ - - rsp->wait(); - uint8_t const reg_val = rsp->read_buf[2]; - - Serial.print(rsp->bytes_written); - Serial.print(" bytes written, "); - Serial.print(rsp->bytes_read); - Serial.println(" bytes read"); - - return reg_val; - }; - +/* uint8_t const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); Serial.print("BMP388 CHIP ID = 0x"); Serial.println(chip_id, HEX); + */ + + for(size_t i = 0; i < 20; i++) + { + rtos::Thread * t = new rtos::Thread(); + t->start(bmp388_thread_func); + } } void loop() @@ -88,3 +76,40 @@ void bmp388_deselect() { digitalWrite(BMP388_CS_PIN, HIGH); } + +byte bmp388_read_reg(byte const reg_addr) +{ + uint8_t const tx_buf[3] = {static_cast(0x80 | reg_addr), 0, 0}; + uint8_t rx_buf[3] = {0}; + + SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf)); + + TSharedIoResponse rsp = bmp388.transfer(req); + + /* Do other stuff */ + + rsp->wait(); + uint8_t const reg_val = rsp->read_buf[2]; +/* + Serial.print(rsp->bytes_written); + Serial.print(" bytes written, "); + Serial.print(rsp->bytes_read); + Serial.println(" bytes read"); +*/ + return reg_val; +} + +void bmp388_thread_func() +{ + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(random(5,500)); + /* Try to read some data from the BMP3888. */ + byte const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); + /* Print thread id and chip id value to serial. */ + char msg[64] = {0}; + snprintf(msg, sizeof(msg), "Thread %d: Chip ID = 0x%X", rtos::ThisThread::get_id(), chip_id); + Serial.println(msg); + } +} diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 44330d8..8595828 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -146,13 +146,13 @@ void SpiDispatcher::processSpiIoRequest(IoTransaction * io_transaction) tx_byte = io_request->config().fill_symbol(); uint8_t const rx_byte = SPI.transfer(tx_byte); - +/* Serial.print("TX "); Serial.print(tx_byte, HEX); Serial.print("| RX "); Serial.print(rx_byte, HEX); Serial.println(); - +*/ io_request->read_buf[bytes_received] = rx_byte; } SPI.endTransaction(); From b54f584ec8ed98f3177fdd802744f30e47379223 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 14:32:51 +0200 Subject: [PATCH 027/108] A bit of refactoring for better readability. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 94930e6..49b26d7 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -79,17 +79,22 @@ void bmp388_deselect() byte bmp388_read_reg(byte const reg_addr) { - uint8_t const tx_buf[3] = {static_cast(0x80 | reg_addr), 0, 0}; - uint8_t rx_buf[3] = {0}; + byte const write_buf[3] = + { + static_cast(0x80 | reg_addr), /* REG_ADDR, if MSBit is set -> READ access */ + 0, /* Dummy byte. */ + 0 /* REG_VAL is output on SDO */ + }; + byte read_buf[3] = {0}; - SpiIoRequest req(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf)); + SpiIoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); TSharedIoResponse rsp = bmp388.transfer(req); /* Do other stuff */ rsp->wait(); - uint8_t const reg_val = rsp->read_buf[2]; + byte const reg_val = rsp->read_buf[2]; /* Serial.print(rsp->bytes_written); Serial.print(" bytes written, "); From 042cfc3bec33a52cdc8ce8507788ea511ed04141 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 14:59:21 +0200 Subject: [PATCH 028/108] Cleverly restructuring the way we are using IoTransactions we can remove the need for a separate class SpiIoRequest --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 2 +- ThreadsafeIO/src/spi/SpiBusDevice.h | 5 +--- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 40 +++++++++++++------------ ThreadsafeIO/src/spi/SpiDispatcher.h | 13 ++++++-- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 49b26d7..a1619f7 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -87,7 +87,7 @@ byte bmp388_read_reg(byte const reg_addr) }; byte read_buf[3] = {0}; - SpiIoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); + IoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); TSharedIoResponse rsp = bmp388.transfer(req); diff --git a/ThreadsafeIO/src/spi/SpiBusDevice.h b/ThreadsafeIO/src/spi/SpiBusDevice.h index c36b961..7557af1 100644 --- a/ThreadsafeIO/src/spi/SpiBusDevice.h +++ b/ThreadsafeIO/src/spi/SpiBusDevice.h @@ -33,10 +33,7 @@ class SpiBusDevice : public BusDevice } virtual TSharedIoResponse transfer(IoRequest & req) override { - /* Append SPI bus device specific configuration. */ - reinterpret_cast(&req)->set_config(&_config); - /* Dispatch the request into the queue. */ - return SpiDispatcher::instance().dispatch(&req); + return SpiDispatcher::instance().dispatch(&req, &_config); } private: diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 8595828..43594f4 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -56,20 +56,21 @@ void SpiDispatcher::destroy() _p_instance = nullptr; } -TSharedIoResponse SpiDispatcher::dispatch(IoRequest * req) +TSharedIoResponse SpiDispatcher::dispatch(IoRequest * req, SpiBusDeviceConfig * config) { mbed::ScopedLock lock(_mutex); - TSharedIoResponse rsp(new IoResponse{req->read_buf}); - /* ATTENTION!!! MEM LEAK HERE!!! */ - /* Turn Queue into Mailbox for IO transactions. */ - IoTransaction * io_transaction = _spi_io_transaction_mailbox.try_alloc(); - if (!io_transaction) + + SpiIoTransaction * spi_io_transaction = _spi_io_transaction_mailbox.try_alloc(); + if (!spi_io_transaction) return nullptr; - io_transaction->req = req; - io_transaction->rsp = rsp.get(); + TSharedIoResponse rsp(new IoResponse{req->read_buf}); + + spi_io_transaction->req = req; + spi_io_transaction->rsp = rsp.get(); + spi_io_transaction->config = config; - _spi_io_transaction_mailbox.put(io_transaction); + _spi_io_transaction_mailbox.put(spi_io_transaction); return rsp; } @@ -111,26 +112,27 @@ void SpiDispatcher::threadFunc() /* Fetch the IO transaction request and * process it. */ - IoTransaction * io_transaction = reinterpret_cast(evt.value.p); - processSpiIoRequest(io_transaction); + SpiIoTransaction * spi_io_transaction = reinterpret_cast(evt.value.p); + processSpiIoRequest(spi_io_transaction); /* Free the allocated memory (memory allocated * during dispatch(...) */ - _spi_io_transaction_mailbox.free(io_transaction); + _spi_io_transaction_mailbox.free(spi_io_transaction); } } } -void SpiDispatcher::processSpiIoRequest(IoTransaction * io_transaction) +void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) { - IoResponse * io_response = io_transaction->rsp; - SpiIoRequest * io_request = reinterpret_cast(io_transaction->req); + IoRequest * io_request = spi_io_transaction->req; + IoResponse * io_response = spi_io_transaction->rsp; + SpiBusDeviceConfig * config = spi_io_transaction->config; io_response->_mutex.lock(); - io_request->config().select(); + config->select(); - SPI.beginTransaction(io_request->config().settings()); + SPI.beginTransaction(config->settings()); size_t bytes_received = 0, bytes_sent = 0; @@ -143,7 +145,7 @@ void SpiDispatcher::processSpiIoRequest(IoTransaction * io_transaction) if (bytes_sent < io_request->bytes_to_write) tx_byte = io_request->write_buf[bytes_sent]; else - tx_byte = io_request->config().fill_symbol(); + tx_byte = config->fill_symbol(); uint8_t const rx_byte = SPI.transfer(tx_byte); /* @@ -157,7 +159,7 @@ void SpiDispatcher::processSpiIoRequest(IoTransaction * io_transaction) } SPI.endTransaction(); - io_request->config().deselect(); + config->deselect(); io_response->bytes_written = bytes_sent; io_response->bytes_read = bytes_received; diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index 9d8e75e..cf8e2ef 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -29,7 +29,7 @@ class SpiDispatcher static SpiDispatcher & instance(); static void destroy(); - TSharedIoResponse dispatch(IoRequest * req); + TSharedIoResponse dispatch(IoRequest * req, SpiBusDeviceConfig * config); private: @@ -40,8 +40,15 @@ class SpiDispatcher bool _has_tread_started; bool _terminate_thread; + typedef struct + { + IoRequest * req; + IoResponse * rsp; + SpiBusDeviceConfig * config; + } SpiIoTransaction; + static size_t constexpr REQUEST_QUEUE_SIZE = 32; - rtos::Mail _spi_io_transaction_mailbox; + rtos::Mail _spi_io_transaction_mailbox; SpiDispatcher(); ~SpiDispatcher(); @@ -49,7 +56,7 @@ class SpiDispatcher void begin(); void end(); void threadFunc(); - void processSpiIoRequest(IoTransaction * io_transaction); + void processSpiIoRequest(SpiIoTransaction * spi_io_transaction); }; #endif /* SPI_DISPATCHER_H_ */ From ffadee7ff6ee0bb966813fb2cc40eefcf1126084 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 15:01:59 +0200 Subject: [PATCH 029/108] Deleting SpiIoRequest --- ThreadsafeIO/src/spi/SpiDispatcher.h | 2 +- ThreadsafeIO/src/spi/SpiIoRequest.h | 36 ---------------------------- 2 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 ThreadsafeIO/src/spi/SpiIoRequest.h diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index cf8e2ef..45562c1 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -13,7 +13,7 @@ #include "../IoTransaction.h" -#include "SpiIoRequest.h" +#include "SpiBusDeviceConfig.h" /************************************************************************************** * CLASS DECLARATION diff --git a/ThreadsafeIO/src/spi/SpiIoRequest.h b/ThreadsafeIO/src/spi/SpiIoRequest.h deleted file mode 100644 index 94ae62e..0000000 --- a/ThreadsafeIO/src/spi/SpiIoRequest.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * A deeply magical library providing threadsafe IO via pipes. - */ - -#ifndef SPI_IO_REQUEST_H_ -#define SPI_IO_REQUEST_H_ - -/************************************************************************************** - * INCLUDE - **************************************************************************************/ - -#include "../IoTransaction.h" - -#include "SpiBusDeviceConfig.h" - -/************************************************************************************** - * CLASS DECLARATION - **************************************************************************************/ - -class SpiIoRequest : public IoRequest -{ -public: - - SpiIoRequest(uint8_t const * const write_buf, size_t const bytes_to_write, uint8_t * read_buf, size_t const bytes_to_read) - : IoRequest(write_buf, bytes_to_write, read_buf, bytes_to_read) - { } - - void set_config(SpiBusDeviceConfig * config) { _config = config; } - SpiBusDeviceConfig & config() { return *_config; } - -private: - - SpiBusDeviceConfig * _config{nullptr}; -}; - -#endif /* SPI_IO_REQUEST_H_ */ \ No newline at end of file From a1d0feb8ef9730453f151444554cc3c07c3adf8d Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 15:06:12 +0200 Subject: [PATCH 030/108] Minimal keywords.txt for syntax highlighting. --- ThreadsafeIO/keywords.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 ThreadsafeIO/keywords.txt diff --git a/ThreadsafeIO/keywords.txt b/ThreadsafeIO/keywords.txt new file mode 100644 index 0000000..8449b4a --- /dev/null +++ b/ThreadsafeIO/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map for ThreadsafeIO +####################################### + +####################################### +# Class (KEYWORD1) +####################################### + +SpiBusDevice KEYWORD1 +SpiBusDeviceConfig KEYWORD1 +IoRequest KEYWORD1 +IoResponse KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +transfer KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +MKRCAN_MCP2515_CS_PIN LITERAL1 From 17488b82cfa0204b5cdd292b4a46bcd932d6b408 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 5 Jul 2021 15:10:57 +0200 Subject: [PATCH 031/108] Replacing TSharedIoResponse type with name IoResponse (still a SharedPtr but now the naming is symmetrical with IoRequest. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 2 +- ThreadsafeIO/src/BusDevice.h | 2 +- ThreadsafeIO/src/IoTransaction.h | 7 ++++++- ThreadsafeIO/src/spi/SpiBusDevice.h | 2 +- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 8 ++++---- ThreadsafeIO/src/spi/SpiDispatcher.h | 4 ++-- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index a1619f7..581761c 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -89,7 +89,7 @@ byte bmp388_read_reg(byte const reg_addr) IoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); - TSharedIoResponse rsp = bmp388.transfer(req); + IoResponse rsp = bmp388.transfer(req); /* Do other stuff */ diff --git a/ThreadsafeIO/src/BusDevice.h b/ThreadsafeIO/src/BusDevice.h index e2da44d..12313ed 100644 --- a/ThreadsafeIO/src/BusDevice.h +++ b/ThreadsafeIO/src/BusDevice.h @@ -20,7 +20,7 @@ class BusDevice public: virtual ~BusDevice() { } - virtual TSharedIoResponse transfer(IoRequest & req) = 0; + virtual IoResponse transfer(IoRequest & req) = 0; }; #endif /* BUS_DEVICE_H_ */ diff --git a/ThreadsafeIO/src/IoTransaction.h b/ThreadsafeIO/src/IoTransaction.h index 27e6f83..5d9cf29 100644 --- a/ThreadsafeIO/src/IoTransaction.h +++ b/ThreadsafeIO/src/IoTransaction.h @@ -45,6 +45,9 @@ class IoRequest * IoResponse **************************************************************************************/ +namespace impl +{ + class IoResponse { public: @@ -71,7 +74,9 @@ class IoResponse }; -typedef mbed::SharedPtr TSharedIoResponse; +} /* namespace impl */ + +typedef mbed::SharedPtr IoResponse; /************************************************************************************** * IoTransaction diff --git a/ThreadsafeIO/src/spi/SpiBusDevice.h b/ThreadsafeIO/src/spi/SpiBusDevice.h index 7557af1..1c5391e 100644 --- a/ThreadsafeIO/src/spi/SpiBusDevice.h +++ b/ThreadsafeIO/src/spi/SpiBusDevice.h @@ -31,7 +31,7 @@ class SpiBusDevice : public BusDevice { /* TODO: Select SPI bus based in string. */ } - virtual TSharedIoResponse transfer(IoRequest & req) override + virtual IoResponse transfer(IoRequest & req) override { return SpiDispatcher::instance().dispatch(&req, &_config); } diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 43594f4..35a9d52 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -56,7 +56,7 @@ void SpiDispatcher::destroy() _p_instance = nullptr; } -TSharedIoResponse SpiDispatcher::dispatch(IoRequest * req, SpiBusDeviceConfig * config) +IoResponse SpiDispatcher::dispatch(IoRequest * req, SpiBusDeviceConfig * config) { mbed::ScopedLock lock(_mutex); @@ -64,10 +64,10 @@ TSharedIoResponse SpiDispatcher::dispatch(IoRequest * req, SpiBusDeviceConfig * if (!spi_io_transaction) return nullptr; - TSharedIoResponse rsp(new IoResponse{req->read_buf}); + IoResponse rsp(new impl::IoResponse{req->read_buf}); spi_io_transaction->req = req; - spi_io_transaction->rsp = rsp.get(); + spi_io_transaction->rsp = rsp; spi_io_transaction->config = config; _spi_io_transaction_mailbox.put(spi_io_transaction); @@ -125,7 +125,7 @@ void SpiDispatcher::threadFunc() void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) { IoRequest * io_request = spi_io_transaction->req; - IoResponse * io_response = spi_io_transaction->rsp; + IoResponse io_response = spi_io_transaction->rsp; SpiBusDeviceConfig * config = spi_io_transaction->config; io_response->_mutex.lock(); diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/ThreadsafeIO/src/spi/SpiDispatcher.h index 45562c1..a03e319 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.h +++ b/ThreadsafeIO/src/spi/SpiDispatcher.h @@ -29,7 +29,7 @@ class SpiDispatcher static SpiDispatcher & instance(); static void destroy(); - TSharedIoResponse dispatch(IoRequest * req, SpiBusDeviceConfig * config); + IoResponse dispatch(IoRequest * req, SpiBusDeviceConfig * config); private: @@ -43,7 +43,7 @@ class SpiDispatcher typedef struct { IoRequest * req; - IoResponse * rsp; + IoResponse rsp; SpiBusDeviceConfig * config; } SpiIoTransaction; From 3beb38e7e5835c35a9826b10d97220e42ca712e3 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 6 Jul 2021 07:31:29 +0200 Subject: [PATCH 032/108] Single-threaded example for querying WHO_AM_I register of LMS6 sensor of RP2040 Connect. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 1 - ThreadsafeIO/examples/ts_wire/ts_wire.ino | 59 +++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 ThreadsafeIO/examples/ts_wire/ts_wire.ino diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 581761c..0aad4d5 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -88,7 +88,6 @@ byte bmp388_read_reg(byte const reg_addr) byte read_buf[3] = {0}; IoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); - IoResponse rsp = bmp388.transfer(req); /* Do other stuff */ diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/ThreadsafeIO/examples/ts_wire/ts_wire.ino new file mode 100644 index 0000000..396ae91 --- /dev/null +++ b/ThreadsafeIO/examples/ts_wire/ts_wire.ino @@ -0,0 +1,59 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static byte constexpr LSM6DSOX_ADDRESS = 0x6A; +static byte constexpr LSM6DSOX_WHO_AM_I_REG = 0x0F; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +byte lsm6dsox_read_reg(byte const reg_addr); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + Serial.begin(9600); + while (!Serial) { } + + Wire.begin(); + + Serial.print("LSM6DSOX[WHO_AM_I] = 0x"); + Serial.println(lsm6dsox_read_reg(LSM6DSOX_WHO_AM_I_REG), HEX); +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +byte lsm6dsox_read_reg(byte const reg_addr) +{ + Wire.beginTransmission(LSM6DSOX_ADDRESS); + Wire.write(reg_addr); + Wire.endTransmission(false); + + Wire.requestFrom(LSM6DSOX_ADDRESS, 1); + while(!Wire.available()) { } + return Wire.read(); +} From d25b307d7d2e488bfe95f1e7f4f660f943dadd8c Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 6 Jul 2021 09:53:36 +0200 Subject: [PATCH 033/108] Providing threadsafe Wire implementation. --- ThreadsafeIO/examples/ts_wire/ts_wire.ino | 18 +++ ThreadsafeIO/keywords.txt | 8 +- ThreadsafeIO/src/ThreadsafeIO.h | 1 + ThreadsafeIO/src/spi/SpiBusDevice.h | 16 +- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 2 - ThreadsafeIO/src/wire/WireBusDevice.h | 45 ++++++ ThreadsafeIO/src/wire/WireBusDeviceConfig.h | 41 +++++ ThreadsafeIO/src/wire/WireDispatcher.cpp | 164 ++++++++++++++++++++ ThreadsafeIO/src/wire/WireDispatcher.h | 62 ++++++++ 9 files changed, 343 insertions(+), 14 deletions(-) create mode 100644 ThreadsafeIO/src/wire/WireBusDevice.h create mode 100644 ThreadsafeIO/src/wire/WireBusDeviceConfig.h create mode 100644 ThreadsafeIO/src/wire/WireDispatcher.cpp create mode 100644 ThreadsafeIO/src/wire/WireDispatcher.h diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/ThreadsafeIO/examples/ts_wire/ts_wire.ino index 396ae91..88f01f3 100644 --- a/ThreadsafeIO/examples/ts_wire/ts_wire.ino +++ b/ThreadsafeIO/examples/ts_wire/ts_wire.ino @@ -23,6 +23,8 @@ byte lsm6dsox_read_reg(byte const reg_addr); * GLOBAL VARIABLES **************************************************************************************/ +WireBusDevice lsm6dsox{"Wire", WireBusDeviceConfig{LSM6DSOX_ADDRESS}}; + /************************************************************************************** * SETUP/LOOP **************************************************************************************/ @@ -49,6 +51,21 @@ void loop() byte lsm6dsox_read_reg(byte const reg_addr) { + /* As we need only 1 byte large write/read buffers for this IO transaction + * the buffers are not arrays but rather simple variables. + */ + byte write_buf = reg_addr; + byte read_buf = 0; + + IoRequest req(&write_buf, sizeof(write_buf), &read_buf, sizeof(read_buf)); + IoResponse rsp = lsm6dsox.transfer(req); + + /* Optionally dp other stuff */ + + rsp->wait(); + return rsp->read_buf[0]; + + /* Wire.beginTransmission(LSM6DSOX_ADDRESS); Wire.write(reg_addr); Wire.endTransmission(false); @@ -56,4 +73,5 @@ byte lsm6dsox_read_reg(byte const reg_addr) Wire.requestFrom(LSM6DSOX_ADDRESS, 1); while(!Wire.available()) { } return Wire.read(); + */ } diff --git a/ThreadsafeIO/keywords.txt b/ThreadsafeIO/keywords.txt index 8449b4a..88b098e 100644 --- a/ThreadsafeIO/keywords.txt +++ b/ThreadsafeIO/keywords.txt @@ -6,10 +6,12 @@ # Class (KEYWORD1) ####################################### -SpiBusDevice KEYWORD1 -SpiBusDeviceConfig KEYWORD1 IoRequest KEYWORD1 IoResponse KEYWORD1 +SpiBusDevice KEYWORD1 +SpiBusDeviceConfig KEYWORD1 +WireBusDevice KEYWORD1 +WireBusDeviceConfig KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -20,5 +22,3 @@ transfer KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### - -MKRCAN_MCP2515_CS_PIN LITERAL1 diff --git a/ThreadsafeIO/src/ThreadsafeIO.h b/ThreadsafeIO/src/ThreadsafeIO.h index 14fa551..cdac20c 100644 --- a/ThreadsafeIO/src/ThreadsafeIO.h +++ b/ThreadsafeIO/src/ThreadsafeIO.h @@ -10,5 +10,6 @@ **************************************************************************************/ #include "spi/SpiBusDevice.h" +#include "wire/WireBusDevice.h" #endif /* THREADSAFE_IO_H_ */ diff --git a/ThreadsafeIO/src/spi/SpiBusDevice.h b/ThreadsafeIO/src/spi/SpiBusDevice.h index 1c5391e..cd8cd09 100644 --- a/ThreadsafeIO/src/spi/SpiBusDevice.h +++ b/ThreadsafeIO/src/spi/SpiBusDevice.h @@ -9,13 +9,10 @@ * INCLUDE **************************************************************************************/ -#include - #include #include -#include -#include "BusDevice.h" +#include "../BusDevice.h" #include "SpiDispatcher.h" #include "SpiBusDeviceConfig.h" @@ -27,15 +24,18 @@ class SpiBusDevice : public BusDevice { public: - SpiBusDevice(std::string const & spi_bus, SpiBusDeviceConfig const & config) : _config{config} - { - /* TODO: Select SPI bus based in string. */ - } + + SpiBusDevice(std::string const & spi_bus, SpiBusDeviceConfig const & config) + : _config{config} + { /* TODO: Select SPI bus based in string. */ } + + virtual IoResponse transfer(IoRequest & req) override { return SpiDispatcher::instance().dispatch(&req, &_config); } + private: SpiBusDeviceConfig _config; diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 35a9d52..eb75f84 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -10,8 +10,6 @@ #include -#include "SpiBusDevice.h" - /************************************************************************************** * STATIC MEMBER DEFINITION **************************************************************************************/ diff --git a/ThreadsafeIO/src/wire/WireBusDevice.h b/ThreadsafeIO/src/wire/WireBusDevice.h new file mode 100644 index 0000000..7519db5 --- /dev/null +++ b/ThreadsafeIO/src/wire/WireBusDevice.h @@ -0,0 +1,45 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef WIRE_BUS_DEVICE_H_ +#define WIRE_BUS_DEVICE_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include +#include + +#include "../BusDevice.h" + +#include "WireDispatcher.h" +#include "WireBusDeviceConfig.h" + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class WireBusDevice : public BusDevice +{ +public: + + WireBusDevice(std::string const & spi_bus, WireBusDeviceConfig const & config) + : _config{config} + { /* TODO: Select Wire bus based in string. */ } + + + virtual IoResponse transfer(IoRequest & req) override + { + return WireDispatcher::instance().dispatch(&req, &_config); + } + + +private: + + WireBusDeviceConfig _config; + +}; + +#endif /* WIRE_BUS_DEVICE_H_ */ diff --git a/ThreadsafeIO/src/wire/WireBusDeviceConfig.h b/ThreadsafeIO/src/wire/WireBusDeviceConfig.h new file mode 100644 index 0000000..68bb596 --- /dev/null +++ b/ThreadsafeIO/src/wire/WireBusDeviceConfig.h @@ -0,0 +1,41 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef WIRE_BUS_DEVICE_CONFIG_H_ +#define WIRE_BUS_DEVICE_CONFIG_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class WireBusDeviceConfig +{ +public: + + WireBusDeviceConfig(byte const slave_addr, bool const restart = true, bool const stop = true) + : _slave_addr{slave_addr} + , _restart{restart} + , _stop{stop} + { } + + + inline byte slave_addr() const { return _slave_addr; } + inline bool restart() const { return _restart; } + inline bool stop() const { return _stop; } + + +private: + + byte _slave_addr{0x00}; + bool _restart{true}, _stop{true}; + +}; + +#endif /* WIRE_BUS_DEVICE_CONFIG_H_ */ diff --git a/ThreadsafeIO/src/wire/WireDispatcher.cpp b/ThreadsafeIO/src/wire/WireDispatcher.cpp new file mode 100644 index 0000000..3b6565d --- /dev/null +++ b/ThreadsafeIO/src/wire/WireDispatcher.cpp @@ -0,0 +1,164 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "WireDispatcher.h" + +#include + +/************************************************************************************** + * STATIC MEMBER DEFINITION + **************************************************************************************/ + +WireDispatcher * WireDispatcher::_p_instance{nullptr}; +rtos::Mutex WireDispatcher::_mutex; + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +WireDispatcher::WireDispatcher() +: _thread(osPriorityNormal, 4096, nullptr, "WireDispatcher") +, _has_tread_started{false} +, _terminate_thread{false} +{ + begin(); +} + +WireDispatcher::~WireDispatcher() +{ + end(); +} + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +WireDispatcher & WireDispatcher::instance() +{ + mbed::ScopedLock lock(_mutex); + if (!_p_instance) { + _p_instance = new WireDispatcher(); + } + return *_p_instance; +} + +void WireDispatcher::destroy() +{ + mbed::ScopedLock lock(_mutex); + delete _p_instance; + _p_instance = nullptr; +} + +IoResponse WireDispatcher::dispatch(IoRequest * req, WireBusDeviceConfig * config) +{ + mbed::ScopedLock lock(_mutex); + + WireIoTransaction * wire_io_transaction = _wire_io_transaction_mailbox.try_alloc(); + if (!wire_io_transaction) + return nullptr; + + IoResponse rsp(new impl::IoResponse{req->read_buf}); + + wire_io_transaction->req = req; + wire_io_transaction->rsp = rsp; + wire_io_transaction->config = config; + + _wire_io_transaction_mailbox.put(wire_io_transaction); + + return rsp; +} + +/************************************************************************************** + * PRIVATE MEMBER FUNCTIONS + **************************************************************************************/ + +void WireDispatcher::begin() +{ + Wire.begin(); + _thread.start(mbed::callback(this, &WireDispatcher::threadFunc)); /* TODO: Check return code */ + /* Is is necessary to wait until the WireDispatcher::threadFunc() + * has started, otherwise other threads might trigger IO requests + * before this thread is actually running. + */ + while (!_has_tread_started) { } +} + +void WireDispatcher::end() +{ + _terminate_thread = true; + _thread.join(); /* TODO: Check return code */ + Wire.end(); +} + +void WireDispatcher::threadFunc() +{ + _has_tread_started = true; + + while(!_terminate_thread) + { + /* Wait blocking for the next IO transaction + * request to be posted to the mailbox. + */ + osEvent evt = _wire_io_transaction_mailbox.get(); + if (evt.status == osEventMail) + { + /* Fetch the IO transaction request and + * process it. + */ + WireIoTransaction * wire_io_transaction = reinterpret_cast(evt.value.p); + processWireIoRequest(wire_io_transaction); + /* Free the allocated memory (memory allocated + * during dispatch(...) + */ + _wire_io_transaction_mailbox.free(wire_io_transaction); + } + } +} + +void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transaction) +{ + IoRequest * io_request = wire_io_transaction->req; + IoResponse io_response = wire_io_transaction->rsp; + WireBusDeviceConfig * config = wire_io_transaction->config; + + io_response->_mutex.lock(); + + Wire.beginTransmission(config->slave_addr()); + + size_t bytes_written = 0; + for (; bytes_written < io_request->bytes_to_write; bytes_written++) + { + Wire.write(io_request->write_buf[bytes_written]); + } + io_response->bytes_written = bytes_written; + + if (config->restart() && (io_request->bytes_to_read > 0)) + Wire.endTransmission(false /* stop */); + else + Wire.endTransmission(true /* stop */); + + if (io_request->bytes_to_read > 0) + { + Wire.requestFrom(config->slave_addr(), io_request->bytes_to_read, config->stop()); + + while(Wire.available() != io_request->bytes_to_read) + { + /* TODO: Insert a timeout. */ + } + + size_t bytes_read = 0; + for (; bytes_read < io_request->bytes_to_read; bytes_read++) + { + io_response->read_buf[bytes_read] = Wire.read(); + } + io_response->bytes_read = bytes_read; + } + + io_response->_cond.notify_all(); + io_response->_mutex.unlock(); +} diff --git a/ThreadsafeIO/src/wire/WireDispatcher.h b/ThreadsafeIO/src/wire/WireDispatcher.h new file mode 100644 index 0000000..ecc25a2 --- /dev/null +++ b/ThreadsafeIO/src/wire/WireDispatcher.h @@ -0,0 +1,62 @@ +/* + * A deeply magical library providing threadsafe IO via pipes. + */ + +#ifndef WIRE_DISPATCHER_H_ +#define WIRE_DISPATCHER_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +#include "../IoTransaction.h" + +#include "WireBusDeviceConfig.h" + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class WireDispatcher +{ +public: + + WireDispatcher(WireDispatcher &) = delete; + void operator = (WireDispatcher &) = delete; + + static WireDispatcher & instance(); + static void destroy(); + + IoResponse dispatch(IoRequest * req, WireBusDeviceConfig * config); + +private: + + static WireDispatcher * _p_instance; + static rtos::Mutex _mutex; + + rtos::Thread _thread; + bool _has_tread_started; + bool _terminate_thread; + + typedef struct + { + IoRequest * req; + IoResponse rsp; + WireBusDeviceConfig * config; + } WireIoTransaction; + + static size_t constexpr REQUEST_QUEUE_SIZE = 32; + rtos::Mail _wire_io_transaction_mailbox; + + WireDispatcher(); + ~WireDispatcher(); + + void begin(); + void end(); + void threadFunc(); + void processWireIoRequest(WireIoTransaction * wire_io_transaction); +}; + +#endif /* WIRE_DISPATCHER_H_ */ From f3e5b790b353ae52c3af11f4f239938141ae165f Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 6 Jul 2021 09:54:25 +0200 Subject: [PATCH 034/108] Adding some linebreaks for better readability. --- ThreadsafeIO/src/spi/SpiBusDeviceConfig.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h b/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h index e27268a..6cb6425 100644 --- a/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h +++ b/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h @@ -20,23 +20,32 @@ class SpiBusDeviceConfig { public: + typedef std::function SpiSelectFunc; typedef std::function SpiDeselectFunc; + + SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, uint8_t const fill_symbol = 0xFF) : _spi_settings{spi_settings} , _spi_select{spi_select} , _spi_deselect{spi_deselect} , _fill_symbol{fill_symbol} { } + + SPISettings settings () const { return _spi_settings; } void select () const { if (_spi_select) _spi_select(); } void deselect () const { if (_spi_deselect) _spi_deselect(); } uint8_t fill_symbol() const { return _fill_symbol; } + + private: + SPISettings _spi_settings; SpiSelectFunc _spi_select{nullptr}; SpiDeselectFunc _spi_deselect{nullptr}; uint8_t _fill_symbol{0xFF}; + }; #endif /* SPI_BUS_DEVICE_CONFIG_H_ */ From 733ae32f197c0d0f90e20adf20938a6c37bcc87b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 6 Jul 2021 10:34:17 +0200 Subject: [PATCH 035/108] Fixing WireDispatcher and SpiDispatcher. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 26 +++++-------- ThreadsafeIO/examples/ts_wire/ts_wire.ino | 45 +++++++++++++++-------- ThreadsafeIO/src/IoTransaction.h | 8 +++- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 11 ++---- ThreadsafeIO/src/wire/WireDispatcher.cpp | 3 +- 5 files changed, 51 insertions(+), 42 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 0aad4d5..561c625 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -12,6 +12,8 @@ static int const BMP388_CS_PIN = 2; static int const BMP388_INT_PIN = 6; static uint8_t const BMP388_CHIP_ID_REG_ADDR = 0x00; +static size_t constexpr NUM_THREADS = 20; + /************************************************************************************** * FUNCTION DECLARATION **************************************************************************************/ @@ -33,6 +35,9 @@ SpiBusDevice bmp388{"SPI", } }; + +static char thread_name[NUM_THREADS][32]; + /************************************************************************************** * SETUP/LOOP **************************************************************************************/ @@ -45,15 +50,10 @@ void setup() pinMode(BMP388_CS_PIN, OUTPUT); digitalWrite(BMP388_CS_PIN, HIGH); -/* - uint8_t const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); - Serial.print("BMP388 CHIP ID = 0x"); - Serial.println(chip_id, HEX); - */ - for(size_t i = 0; i < 20; i++) { - rtos::Thread * t = new rtos::Thread(); + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); t->start(bmp388_thread_func); } } @@ -93,14 +93,8 @@ byte bmp388_read_reg(byte const reg_addr) /* Do other stuff */ rsp->wait(); - byte const reg_val = rsp->read_buf[2]; -/* - Serial.print(rsp->bytes_written); - Serial.print(" bytes written, "); - Serial.print(rsp->bytes_read); - Serial.println(" bytes read"); -*/ - return reg_val; + + return rsp->read_buf[2]; } void bmp388_thread_func() @@ -113,7 +107,7 @@ void bmp388_thread_func() byte const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); /* Print thread id and chip id value to serial. */ char msg[64] = {0}; - snprintf(msg, sizeof(msg), "Thread %d: Chip ID = 0x%X", rtos::ThisThread::get_id(), chip_id); + snprintf(msg, sizeof(msg), "%s: Chip ID = 0x%X", rtos::ThisThread::get_name(), chip_id); Serial.println(msg); } } diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/ThreadsafeIO/examples/ts_wire/ts_wire.ino index 88f01f3..5641100 100644 --- a/ThreadsafeIO/examples/ts_wire/ts_wire.ino +++ b/ThreadsafeIO/examples/ts_wire/ts_wire.ino @@ -13,11 +13,14 @@ static byte constexpr LSM6DSOX_ADDRESS = 0x6A; static byte constexpr LSM6DSOX_WHO_AM_I_REG = 0x0F; +static size_t constexpr NUM_THREADS = 20; + /************************************************************************************** * FUNCTION DECLARATION **************************************************************************************/ byte lsm6dsox_read_reg(byte const reg_addr); +void lsm6dsox_thread_func(); /************************************************************************************** * GLOBAL VARIABLES @@ -25,6 +28,8 @@ byte lsm6dsox_read_reg(byte const reg_addr); WireBusDevice lsm6dsox{"Wire", WireBusDeviceConfig{LSM6DSOX_ADDRESS}}; +static char thread_name[NUM_THREADS][32]; + /************************************************************************************** * SETUP/LOOP **************************************************************************************/ @@ -34,15 +39,18 @@ void setup() Serial.begin(9600); while (!Serial) { } - Wire.begin(); - - Serial.print("LSM6DSOX[WHO_AM_I] = 0x"); - Serial.println(lsm6dsox_read_reg(LSM6DSOX_WHO_AM_I_REG), HEX); + /* Fire up some threads all accessing the LSM6DSOX */ + for(size_t i = 0; i < NUM_THREADS; i++) + { + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); + t->start(lsm6dsox_thread_func); + } } void loop() { - + rtos::ThisThread::sleep_for(10); } /************************************************************************************** @@ -59,19 +67,26 @@ byte lsm6dsox_read_reg(byte const reg_addr) IoRequest req(&write_buf, sizeof(write_buf), &read_buf, sizeof(read_buf)); IoResponse rsp = lsm6dsox.transfer(req); - - /* Optionally dp other stuff */ + + /* Optionally do other stuff */ rsp->wait(); + return rsp->read_buf[0]; +} - /* - Wire.beginTransmission(LSM6DSOX_ADDRESS); - Wire.write(reg_addr); - Wire.endTransmission(false); - Wire.requestFrom(LSM6DSOX_ADDRESS, 1); - while(!Wire.available()) { } - return Wire.read(); - */ +void lsm6dsox_thread_func() +{ + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(random(5,500)); + /* Try to read some data from the BMP3888. */ + byte const who_am_i = lsm6dsox_read_reg(LSM6DSOX_WHO_AM_I_REG); + /* Print thread id and chip id value to serial. */ + char msg[64] = {0}; + snprintf(msg, sizeof(msg), "%s: LSM6DSOX[WHO_AM_I] = 0x%X", rtos::ThisThread::get_name(), who_am_i); + Serial.println(msg); + } } diff --git a/ThreadsafeIO/src/IoTransaction.h b/ThreadsafeIO/src/IoTransaction.h index 5d9cf29..2c4e7a4 100644 --- a/ThreadsafeIO/src/IoTransaction.h +++ b/ThreadsafeIO/src/IoTransaction.h @@ -57,6 +57,7 @@ class IoResponse , read_buf{read_buf_} , bytes_written{0} , bytes_read{0} + , is_done{false} { } rtos::Mutex _mutex; @@ -64,11 +65,14 @@ class IoResponse uint8_t * read_buf{nullptr}; size_t bytes_written{0}; size_t bytes_read{0}; + bool is_done{false}; void wait() { - _mutex.lock(); /* Do we really need to lock/unlock the mutex? */ - _cond.wait(); + _mutex.lock(); + while (!is_done) { + _cond.wait(); + } _mutex.unlock(); } diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index eb75f84..3241deb 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -22,7 +22,7 @@ rtos::Mutex SpiDispatcher::_mutex; **************************************************************************************/ SpiDispatcher::SpiDispatcher() -: _thread(osPriorityNormal, 4096, nullptr, "SpiDispatcher") +: _thread(osPriorityRealtime, 4096, nullptr, "SpiDispatcher") , _has_tread_started{false} , _terminate_thread{false} { @@ -146,13 +146,7 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) tx_byte = config->fill_symbol(); uint8_t const rx_byte = SPI.transfer(tx_byte); -/* - Serial.print("TX "); - Serial.print(tx_byte, HEX); - Serial.print("| RX "); - Serial.print(rx_byte, HEX); - Serial.println(); -*/ + io_request->read_buf[bytes_received] = rx_byte; } SPI.endTransaction(); @@ -162,6 +156,7 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) io_response->bytes_written = bytes_sent; io_response->bytes_read = bytes_received; + io_response->is_done = true; io_response->_cond.notify_all(); io_response->_mutex.unlock(); } diff --git a/ThreadsafeIO/src/wire/WireDispatcher.cpp b/ThreadsafeIO/src/wire/WireDispatcher.cpp index 3b6565d..88e6cba 100644 --- a/ThreadsafeIO/src/wire/WireDispatcher.cpp +++ b/ThreadsafeIO/src/wire/WireDispatcher.cpp @@ -22,7 +22,7 @@ rtos::Mutex WireDispatcher::_mutex; **************************************************************************************/ WireDispatcher::WireDispatcher() -: _thread(osPriorityNormal, 4096, nullptr, "WireDispatcher") +: _thread(osPriorityRealtime, 4096, nullptr, "WireDispatcher") , _has_tread_started{false} , _terminate_thread{false} { @@ -159,6 +159,7 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio io_response->bytes_read = bytes_read; } + io_response->is_done = true; io_response->_cond.notify_all(); io_response->_mutex.unlock(); } From 8ef1d71922ce8a3ac686facbef7cd3af081641da Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 6 Jul 2021 10:42:42 +0200 Subject: [PATCH 036/108] Reducing public API to prevent mis-usage. --- ThreadsafeIO/src/IoTransaction.h | 25 +++++++++++++++++------- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 6 +----- ThreadsafeIO/src/wire/WireDispatcher.cpp | 6 +----- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ThreadsafeIO/src/IoTransaction.h b/ThreadsafeIO/src/IoTransaction.h index 2c4e7a4..020287a 100644 --- a/ThreadsafeIO/src/IoTransaction.h +++ b/ThreadsafeIO/src/IoTransaction.h @@ -53,29 +53,40 @@ class IoResponse public: IoResponse(uint8_t * read_buf_) - : _cond{_mutex} - , read_buf{read_buf_} + : read_buf{read_buf_} , bytes_written{0} , bytes_read{0} - , is_done{false} + , _cond{_mutex} + , _is_done{false} { } - rtos::Mutex _mutex; - rtos::ConditionVariable _cond; uint8_t * read_buf{nullptr}; size_t bytes_written{0}; size_t bytes_read{0}; - bool is_done{false}; + + void done() + { + _mutex.lock(); + _is_done = true; + _cond.notify_all(); + _mutex.unlock(); + } void wait() { _mutex.lock(); - while (!is_done) { + while (!_is_done) { _cond.wait(); } _mutex.unlock(); } +private: + + rtos::Mutex _mutex; + rtos::ConditionVariable _cond; + bool _is_done{false}; + }; } /* namespace impl */ diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 3241deb..0aef107 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -126,8 +126,6 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) IoResponse io_response = spi_io_transaction->rsp; SpiBusDeviceConfig * config = spi_io_transaction->config; - io_response->_mutex.lock(); - config->select(); SPI.beginTransaction(config->settings()); @@ -156,7 +154,5 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) io_response->bytes_written = bytes_sent; io_response->bytes_read = bytes_received; - io_response->is_done = true; - io_response->_cond.notify_all(); - io_response->_mutex.unlock(); + io_response->done(); } diff --git a/ThreadsafeIO/src/wire/WireDispatcher.cpp b/ThreadsafeIO/src/wire/WireDispatcher.cpp index 88e6cba..6d3ca3a 100644 --- a/ThreadsafeIO/src/wire/WireDispatcher.cpp +++ b/ThreadsafeIO/src/wire/WireDispatcher.cpp @@ -126,8 +126,6 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio IoResponse io_response = wire_io_transaction->rsp; WireBusDeviceConfig * config = wire_io_transaction->config; - io_response->_mutex.lock(); - Wire.beginTransmission(config->slave_addr()); size_t bytes_written = 0; @@ -159,7 +157,5 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio io_response->bytes_read = bytes_read; } - io_response->is_done = true; - io_response->_cond.notify_all(); - io_response->_mutex.unlock(); + io_response->done(); } From b11b1bea390a2904ff89cc1da3b4b1dbec636a9b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 6 Jul 2021 10:50:57 +0200 Subject: [PATCH 037/108] Eliminate pointer to read buffer from IO response, therefore making the necessity of keeping the read buffer on the stack in scope more visible. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 2 +- ThreadsafeIO/examples/ts_wire/ts_wire.ino | 4 ++-- ThreadsafeIO/src/IoTransaction.h | 6 ++---- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 2 +- ThreadsafeIO/src/wire/WireDispatcher.cpp | 4 ++-- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 561c625..56ff791 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -94,7 +94,7 @@ byte bmp388_read_reg(byte const reg_addr) rsp->wait(); - return rsp->read_buf[2]; + return read_buf[2]; } void bmp388_thread_func() diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/ThreadsafeIO/examples/ts_wire/ts_wire.ino index 5641100..4bfe30e 100644 --- a/ThreadsafeIO/examples/ts_wire/ts_wire.ino +++ b/ThreadsafeIO/examples/ts_wire/ts_wire.ino @@ -50,7 +50,7 @@ void setup() void loop() { - rtos::ThisThread::sleep_for(10); + } /************************************************************************************** @@ -72,7 +72,7 @@ byte lsm6dsox_read_reg(byte const reg_addr) rsp->wait(); - return rsp->read_buf[0]; + return read_buf; } diff --git a/ThreadsafeIO/src/IoTransaction.h b/ThreadsafeIO/src/IoTransaction.h index 020287a..bd5c88f 100644 --- a/ThreadsafeIO/src/IoTransaction.h +++ b/ThreadsafeIO/src/IoTransaction.h @@ -52,15 +52,13 @@ class IoResponse { public: - IoResponse(uint8_t * read_buf_) - : read_buf{read_buf_} - , bytes_written{0} + IoResponse() + : bytes_written{0} , bytes_read{0} , _cond{_mutex} , _is_done{false} { } - uint8_t * read_buf{nullptr}; size_t bytes_written{0}; size_t bytes_read{0}; diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 0aef107..210c017 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -62,7 +62,7 @@ IoResponse SpiDispatcher::dispatch(IoRequest * req, SpiBusDeviceConfig * config) if (!spi_io_transaction) return nullptr; - IoResponse rsp(new impl::IoResponse{req->read_buf}); + IoResponse rsp(new impl::IoResponse()); spi_io_transaction->req = req; spi_io_transaction->rsp = rsp; diff --git a/ThreadsafeIO/src/wire/WireDispatcher.cpp b/ThreadsafeIO/src/wire/WireDispatcher.cpp index 6d3ca3a..a134593 100644 --- a/ThreadsafeIO/src/wire/WireDispatcher.cpp +++ b/ThreadsafeIO/src/wire/WireDispatcher.cpp @@ -62,7 +62,7 @@ IoResponse WireDispatcher::dispatch(IoRequest * req, WireBusDeviceConfig * confi if (!wire_io_transaction) return nullptr; - IoResponse rsp(new impl::IoResponse{req->read_buf}); + IoResponse rsp(new impl::IoResponse()); wire_io_transaction->req = req; wire_io_transaction->rsp = rsp; @@ -152,7 +152,7 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio size_t bytes_read = 0; for (; bytes_read < io_request->bytes_to_read; bytes_read++) { - io_response->read_buf[bytes_read] = Wire.read(); + io_request->read_buf[bytes_read] = Wire.read(); } io_response->bytes_read = bytes_read; } From 24623b010bf652a886d2c10717775a75fa16a754 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 7 Jul 2021 13:21:08 +0200 Subject: [PATCH 038/108] Provide overload of IoRequest constructor to deal with single-byte 'buffers' --- ThreadsafeIO/examples/ts_wire/ts_wire.ino | 2 +- ThreadsafeIO/src/IoTransaction.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/ThreadsafeIO/examples/ts_wire/ts_wire.ino index 4bfe30e..8d2c17a 100644 --- a/ThreadsafeIO/examples/ts_wire/ts_wire.ino +++ b/ThreadsafeIO/examples/ts_wire/ts_wire.ino @@ -65,7 +65,7 @@ byte lsm6dsox_read_reg(byte const reg_addr) byte write_buf = reg_addr; byte read_buf = 0; - IoRequest req(&write_buf, sizeof(write_buf), &read_buf, sizeof(read_buf)); + IoRequest req(write_buf, read_buf); IoResponse rsp = lsm6dsox.transfer(req); /* Optionally do other stuff */ diff --git a/ThreadsafeIO/src/IoTransaction.h b/ThreadsafeIO/src/IoTransaction.h index bd5c88f..9743fda 100644 --- a/ThreadsafeIO/src/IoTransaction.h +++ b/ThreadsafeIO/src/IoTransaction.h @@ -33,6 +33,9 @@ class IoRequest , bytes_to_read{bytes_to_read_} { } + IoRequest(uint8_t const & write_buf_, uint8_t & read_buf_) + : IoRequest{&write_buf_, 1, &read_buf_, 1} + { } uint8_t const * const write_buf{nullptr}; size_t const bytes_to_write{0}; From 5fde0889774394af3a1fc7898a09cbffd850da29 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 7 Jul 2021 13:27:10 +0200 Subject: [PATCH 039/108] Replacing uint8_t with byte for better consistency with the Arduino way. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 4 ++-- ThreadsafeIO/src/IoTransaction.h | 11 ++++++----- ThreadsafeIO/src/spi/SpiBusDeviceConfig.h | 10 ++++++---- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 4 ++-- ThreadsafeIO/src/wire/WireDispatcher.cpp | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index 56ff791..dffb52c 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -10,7 +10,7 @@ static int const BMP388_CS_PIN = 2; static int const BMP388_INT_PIN = 6; -static uint8_t const BMP388_CHIP_ID_REG_ADDR = 0x00; +static byte const BMP388_CHIP_ID_REG_ADDR = 0x00; static size_t constexpr NUM_THREADS = 20; @@ -81,7 +81,7 @@ byte bmp388_read_reg(byte const reg_addr) { byte const write_buf[3] = { - static_cast(0x80 | reg_addr), /* REG_ADDR, if MSBit is set -> READ access */ + static_cast(0x80 | reg_addr), /* REG_ADDR, if MSBit is set -> READ access */ 0, /* Dummy byte. */ 0 /* REG_VAL is output on SDO */ }; diff --git a/ThreadsafeIO/src/IoTransaction.h b/ThreadsafeIO/src/IoTransaction.h index 9743fda..8a4f6b0 100644 --- a/ThreadsafeIO/src/IoTransaction.h +++ b/ThreadsafeIO/src/IoTransaction.h @@ -9,9 +9,10 @@ * INCLUDE **************************************************************************************/ -#include +#include #include + #include /************************************************************************************** @@ -26,20 +27,20 @@ class IoRequest { public: - IoRequest(uint8_t const * const write_buf_, size_t const bytes_to_write_, uint8_t * read_buf_, size_t const bytes_to_read_) + IoRequest(byte const * const write_buf_, size_t const bytes_to_write_, byte * read_buf_, size_t const bytes_to_read_) : write_buf{write_buf_} , bytes_to_write{bytes_to_write_} , read_buf{read_buf_} , bytes_to_read{bytes_to_read_} { } - IoRequest(uint8_t const & write_buf_, uint8_t & read_buf_) + IoRequest(byte const & write_buf_, byte & read_buf_) : IoRequest{&write_buf_, 1, &read_buf_, 1} { } - uint8_t const * const write_buf{nullptr}; + byte const * const write_buf{nullptr}; size_t const bytes_to_write{0}; - uint8_t * read_buf{nullptr}; + byte * read_buf{nullptr}; size_t const bytes_to_read{0}; }; diff --git a/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h b/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h index 6cb6425..d7f1ddc 100644 --- a/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h +++ b/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h @@ -9,10 +9,12 @@ * INCLUDE **************************************************************************************/ -#include #include + #include +#include + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -25,7 +27,7 @@ class SpiBusDeviceConfig typedef std::function SpiDeselectFunc; - SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, uint8_t const fill_symbol = 0xFF) + SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF) : _spi_settings{spi_settings} , _spi_select{spi_select} , _spi_deselect{spi_deselect} @@ -36,7 +38,7 @@ class SpiBusDeviceConfig SPISettings settings () const { return _spi_settings; } void select () const { if (_spi_select) _spi_select(); } void deselect () const { if (_spi_deselect) _spi_deselect(); } - uint8_t fill_symbol() const { return _fill_symbol; } + byte fill_symbol() const { return _fill_symbol; } private: @@ -44,7 +46,7 @@ class SpiBusDeviceConfig SPISettings _spi_settings; SpiSelectFunc _spi_select{nullptr}; SpiDeselectFunc _spi_deselect{nullptr}; - uint8_t _fill_symbol{0xFF}; + byte _fill_symbol{0xFF}; }; diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 210c017..1e1a445 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -136,14 +136,14 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) bytes_received < io_request->bytes_to_read; bytes_received++, bytes_sent++) { - uint8_t tx_byte = 0; + byte tx_byte = 0; if (bytes_sent < io_request->bytes_to_write) tx_byte = io_request->write_buf[bytes_sent]; else tx_byte = config->fill_symbol(); - uint8_t const rx_byte = SPI.transfer(tx_byte); + byte const rx_byte = SPI.transfer(tx_byte); io_request->read_buf[bytes_received] = rx_byte; } diff --git a/ThreadsafeIO/src/wire/WireDispatcher.cpp b/ThreadsafeIO/src/wire/WireDispatcher.cpp index a134593..0c921c1 100644 --- a/ThreadsafeIO/src/wire/WireDispatcher.cpp +++ b/ThreadsafeIO/src/wire/WireDispatcher.cpp @@ -144,7 +144,7 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio { Wire.requestFrom(config->slave_addr(), io_request->bytes_to_read, config->stop()); - while(Wire.available() != io_request->bytes_to_read) + while(Wire.available() != static_cast(io_request->bytes_to_read)) { /* TODO: Insert a timeout. */ } From 552c940807cc7912d3063195c034b2226209711d Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 7 Jul 2021 14:33:39 +0200 Subject: [PATCH 040/108] Replace deprecated mailbox.get() with mailbox.try_get_for(forever) --- ThreadsafeIO/src/spi/SpiDispatcher.cpp | 8 ++------ ThreadsafeIO/src/wire/WireDispatcher.cpp | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/ThreadsafeIO/src/spi/SpiDispatcher.cpp index 1e1a445..3954e27 100644 --- a/ThreadsafeIO/src/spi/SpiDispatcher.cpp +++ b/ThreadsafeIO/src/spi/SpiDispatcher.cpp @@ -104,13 +104,9 @@ void SpiDispatcher::threadFunc() /* Wait blocking for the next IO transaction * request to be posted to the mailbox. */ - osEvent evt = _spi_io_transaction_mailbox.get(); - if (evt.status == osEventMail) + SpiIoTransaction * spi_io_transaction = _spi_io_transaction_mailbox.try_get_for(rtos::Kernel::wait_for_u32_forever); + if (spi_io_transaction) { - /* Fetch the IO transaction request and - * process it. - */ - SpiIoTransaction * spi_io_transaction = reinterpret_cast(evt.value.p); processSpiIoRequest(spi_io_transaction); /* Free the allocated memory (memory allocated * during dispatch(...) diff --git a/ThreadsafeIO/src/wire/WireDispatcher.cpp b/ThreadsafeIO/src/wire/WireDispatcher.cpp index 0c921c1..de8fe75 100644 --- a/ThreadsafeIO/src/wire/WireDispatcher.cpp +++ b/ThreadsafeIO/src/wire/WireDispatcher.cpp @@ -104,13 +104,9 @@ void WireDispatcher::threadFunc() /* Wait blocking for the next IO transaction * request to be posted to the mailbox. */ - osEvent evt = _wire_io_transaction_mailbox.get(); - if (evt.status == osEventMail) + WireIoTransaction * wire_io_transaction = _wire_io_transaction_mailbox.try_get_for(rtos::Kernel::wait_for_u32_forever); + if (wire_io_transaction) { - /* Fetch the IO transaction request and - * process it. - */ - WireIoTransaction * wire_io_transaction = reinterpret_cast(evt.value.p); processWireIoRequest(wire_io_transaction); /* Free the allocated memory (memory allocated * during dispatch(...) From 5fe1520bd34fd67f5323b084e0af53306173ca36 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 7 Jul 2021 14:41:41 +0200 Subject: [PATCH 041/108] Replacing deprecated rtos::ThisThread::sleep_for with the version using durations instead of an uint. --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 10 +++++----- ThreadsafeIO/examples/ts_wire/ts_wire.ino | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index dffb52c..bc05a85 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -8,8 +8,8 @@ * CONSTANTS **************************************************************************************/ -static int const BMP388_CS_PIN = 2; -static int const BMP388_INT_PIN = 6; +static int const BMP388_CS_PIN = 2; +static int const BMP388_INT_PIN = 6; static byte const BMP388_CHIP_ID_REG_ADDR = 0x00; static size_t constexpr NUM_THREADS = 20; @@ -82,8 +82,8 @@ byte bmp388_read_reg(byte const reg_addr) byte const write_buf[3] = { static_cast(0x80 | reg_addr), /* REG_ADDR, if MSBit is set -> READ access */ - 0, /* Dummy byte. */ - 0 /* REG_VAL is output on SDO */ + 0, /* Dummy byte. */ + 0 /* REG_VAL is output on SDO */ }; byte read_buf[3] = {0}; @@ -102,7 +102,7 @@ void bmp388_thread_func() for(;;) { /* Sleep between 5 and 500 ms */ - rtos::ThisThread::sleep_for(random(5,500)); + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); /* Try to read some data from the BMP3888. */ byte const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); /* Print thread id and chip id value to serial. */ diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/ThreadsafeIO/examples/ts_wire/ts_wire.ino index 8d2c17a..7254cdb 100644 --- a/ThreadsafeIO/examples/ts_wire/ts_wire.ino +++ b/ThreadsafeIO/examples/ts_wire/ts_wire.ino @@ -81,7 +81,7 @@ void lsm6dsox_thread_func() for(;;) { /* Sleep between 5 and 500 ms */ - rtos::ThisThread::sleep_for(random(5,500)); + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); /* Try to read some data from the BMP3888. */ byte const who_am_i = lsm6dsox_read_reg(LSM6DSOX_WHO_AM_I_REG); /* Print thread id and chip id value to serial. */ From 218383e93c57b587eb007e315f37950fe960ea54 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 07:14:24 +0200 Subject: [PATCH 042/108] Minor cosmetic operations --- ThreadsafeIO/examples/ts_spi/ts_spi.ino | 2 +- ThreadsafeIO/examples/ts_wire/ts_wire.ino | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/ThreadsafeIO/examples/ts_spi/ts_spi.ino index bc05a85..d8e40db 100644 --- a/ThreadsafeIO/examples/ts_spi/ts_spi.ino +++ b/ThreadsafeIO/examples/ts_spi/ts_spi.ino @@ -50,7 +50,7 @@ void setup() pinMode(BMP388_CS_PIN, OUTPUT); digitalWrite(BMP388_CS_PIN, HIGH); - for(size_t i = 0; i < 20; i++) + for(size_t i = 0; i < NUM_THREADS; i++) { snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/ThreadsafeIO/examples/ts_wire/ts_wire.ino index 7254cdb..9317c21 100644 --- a/ThreadsafeIO/examples/ts_wire/ts_wire.ino +++ b/ThreadsafeIO/examples/ts_wire/ts_wire.ino @@ -4,8 +4,6 @@ #include -#include - /************************************************************************************** * CONSTANTS **************************************************************************************/ From c210f2832e3dff47e0b0fcf522c51d81660343be Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 07:38:30 +0200 Subject: [PATCH 043/108] Moving all library files in the repositories root folder. --- {ThreadsafeIO/examples => examples}/ts_spi/ts_spi.ino | 0 {ThreadsafeIO/examples => examples}/ts_wire/ts_wire.ino | 0 ThreadsafeIO/keywords.txt => keywords.txt | 0 ThreadsafeIO/library.properties => library.properties | 0 {ThreadsafeIO/src => src}/BusDevice.h | 0 {ThreadsafeIO/src => src}/IoTransaction.h | 0 {ThreadsafeIO/src => src}/ThreadsafeIO.h | 0 {ThreadsafeIO/src => src}/spi/SpiBusDevice.h | 0 {ThreadsafeIO/src => src}/spi/SpiBusDeviceConfig.h | 0 {ThreadsafeIO/src => src}/spi/SpiDispatcher.cpp | 0 {ThreadsafeIO/src => src}/spi/SpiDispatcher.h | 0 {ThreadsafeIO/src => src}/wire/WireBusDevice.h | 0 {ThreadsafeIO/src => src}/wire/WireBusDeviceConfig.h | 0 {ThreadsafeIO/src => src}/wire/WireDispatcher.cpp | 0 {ThreadsafeIO/src => src}/wire/WireDispatcher.h | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename {ThreadsafeIO/examples => examples}/ts_spi/ts_spi.ino (100%) rename {ThreadsafeIO/examples => examples}/ts_wire/ts_wire.ino (100%) rename ThreadsafeIO/keywords.txt => keywords.txt (100%) rename ThreadsafeIO/library.properties => library.properties (100%) rename {ThreadsafeIO/src => src}/BusDevice.h (100%) rename {ThreadsafeIO/src => src}/IoTransaction.h (100%) rename {ThreadsafeIO/src => src}/ThreadsafeIO.h (100%) rename {ThreadsafeIO/src => src}/spi/SpiBusDevice.h (100%) rename {ThreadsafeIO/src => src}/spi/SpiBusDeviceConfig.h (100%) rename {ThreadsafeIO/src => src}/spi/SpiDispatcher.cpp (100%) rename {ThreadsafeIO/src => src}/spi/SpiDispatcher.h (100%) rename {ThreadsafeIO/src => src}/wire/WireBusDevice.h (100%) rename {ThreadsafeIO/src => src}/wire/WireBusDeviceConfig.h (100%) rename {ThreadsafeIO/src => src}/wire/WireDispatcher.cpp (100%) rename {ThreadsafeIO/src => src}/wire/WireDispatcher.h (100%) diff --git a/ThreadsafeIO/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino similarity index 100% rename from ThreadsafeIO/examples/ts_spi/ts_spi.ino rename to examples/ts_spi/ts_spi.ino diff --git a/ThreadsafeIO/examples/ts_wire/ts_wire.ino b/examples/ts_wire/ts_wire.ino similarity index 100% rename from ThreadsafeIO/examples/ts_wire/ts_wire.ino rename to examples/ts_wire/ts_wire.ino diff --git a/ThreadsafeIO/keywords.txt b/keywords.txt similarity index 100% rename from ThreadsafeIO/keywords.txt rename to keywords.txt diff --git a/ThreadsafeIO/library.properties b/library.properties similarity index 100% rename from ThreadsafeIO/library.properties rename to library.properties diff --git a/ThreadsafeIO/src/BusDevice.h b/src/BusDevice.h similarity index 100% rename from ThreadsafeIO/src/BusDevice.h rename to src/BusDevice.h diff --git a/ThreadsafeIO/src/IoTransaction.h b/src/IoTransaction.h similarity index 100% rename from ThreadsafeIO/src/IoTransaction.h rename to src/IoTransaction.h diff --git a/ThreadsafeIO/src/ThreadsafeIO.h b/src/ThreadsafeIO.h similarity index 100% rename from ThreadsafeIO/src/ThreadsafeIO.h rename to src/ThreadsafeIO.h diff --git a/ThreadsafeIO/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h similarity index 100% rename from ThreadsafeIO/src/spi/SpiBusDevice.h rename to src/spi/SpiBusDevice.h diff --git a/ThreadsafeIO/src/spi/SpiBusDeviceConfig.h b/src/spi/SpiBusDeviceConfig.h similarity index 100% rename from ThreadsafeIO/src/spi/SpiBusDeviceConfig.h rename to src/spi/SpiBusDeviceConfig.h diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.cpp b/src/spi/SpiDispatcher.cpp similarity index 100% rename from ThreadsafeIO/src/spi/SpiDispatcher.cpp rename to src/spi/SpiDispatcher.cpp diff --git a/ThreadsafeIO/src/spi/SpiDispatcher.h b/src/spi/SpiDispatcher.h similarity index 100% rename from ThreadsafeIO/src/spi/SpiDispatcher.h rename to src/spi/SpiDispatcher.h diff --git a/ThreadsafeIO/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h similarity index 100% rename from ThreadsafeIO/src/wire/WireBusDevice.h rename to src/wire/WireBusDevice.h diff --git a/ThreadsafeIO/src/wire/WireBusDeviceConfig.h b/src/wire/WireBusDeviceConfig.h similarity index 100% rename from ThreadsafeIO/src/wire/WireBusDeviceConfig.h rename to src/wire/WireBusDeviceConfig.h diff --git a/ThreadsafeIO/src/wire/WireDispatcher.cpp b/src/wire/WireDispatcher.cpp similarity index 100% rename from ThreadsafeIO/src/wire/WireDispatcher.cpp rename to src/wire/WireDispatcher.cpp diff --git a/ThreadsafeIO/src/wire/WireDispatcher.h b/src/wire/WireDispatcher.h similarity index 100% rename from ThreadsafeIO/src/wire/WireDispatcher.h rename to src/wire/WireDispatcher.h From 4eca7fb7ce7782a927f5c9e8ea4083404d0f4ab7 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 07:54:51 +0200 Subject: [PATCH 044/108] Renaming library to Arduino_ThreadsafeIO and ensure compileability for all examples. --- examples/ts_spi/ts_spi.ino | 2 +- examples/ts_wire/ts_wire.ino | 2 +- keywords.txt | 2 +- library.properties | 6 +++--- src/{ThreadsafeIO.h => Arduino_ThreadsafeIO.h} | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) rename src/{ThreadsafeIO.h => Arduino_ThreadsafeIO.h} (75%) diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index d8e40db..06bd9da 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -2,7 +2,7 @@ * INCLUDE **************************************************************************************/ -#include +#include /************************************************************************************** * CONSTANTS diff --git a/examples/ts_wire/ts_wire.ino b/examples/ts_wire/ts_wire.ino index 9317c21..67456eb 100644 --- a/examples/ts_wire/ts_wire.ino +++ b/examples/ts_wire/ts_wire.ino @@ -2,7 +2,7 @@ * INCLUDE **************************************************************************************/ -#include +#include /************************************************************************************** * CONSTANTS diff --git a/keywords.txt b/keywords.txt index 88b098e..8dbef7d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,5 +1,5 @@ ####################################### -# Syntax Coloring Map for ThreadsafeIO +# Syntax Coloring Map for Arduino_ThreadsafeIO ####################################### ####################################### diff --git a/library.properties b/library.properties index 5dc7f5f..08e7ac9 100644 --- a/library.properties +++ b/library.properties @@ -1,4 +1,4 @@ -name=ThreadsafeIO +name=Arduino_ThreadsafeIO version=0.0.1 author=Alexander Entinger maintainer=Arduino @@ -6,5 +6,5 @@ sentence=Enable threadsafe peripheral access via pipes. paragraph= category=Communication url= -architectures=mbed -include=ThreadsafeIO.h +architectures=mbed,mbed_portenta,mbed_nano +include=Arduino_ThreadsafeIO.h diff --git a/src/ThreadsafeIO.h b/src/Arduino_ThreadsafeIO.h similarity index 75% rename from src/ThreadsafeIO.h rename to src/Arduino_ThreadsafeIO.h index cdac20c..e11fa86 100644 --- a/src/ThreadsafeIO.h +++ b/src/Arduino_ThreadsafeIO.h @@ -2,8 +2,8 @@ * A deeply magical library providing threadsafe IO via pipes. */ -#ifndef THREADSAFE_IO_H_ -#define THREADSAFE_IO_H_ +#ifndef ARDUINO_THREADSAFE_IO_H_ +#define ARDUINO_THREADSAFE_IO_H_ /************************************************************************************** * INCLUDE @@ -12,4 +12,4 @@ #include "spi/SpiBusDevice.h" #include "wire/WireBusDevice.h" -#endif /* THREADSAFE_IO_H_ */ +#endif /* ARDUINO_THREADSAFE_IO_H_ */ From af14e4991359e9ded0d7983be645c554d9a9b40a Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 07:56:19 +0200 Subject: [PATCH 045/108] Providing a minimal README --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..1557883 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +`Arduino_ThreadsafeIO` +====================== \ No newline at end of file From f4db4a84baadb45eb2261fe95dc47f58bf4f1979 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 11 Jul 2021 23:28:17 -0700 Subject: [PATCH 046/108] Configure Dependabot to check for outdated actions used in workflows Dependabot will periodically check the versions of all actions used in the repository's workflows. If any are found to be outdated, it will submit a pull request to update them. NOTE: Dependabot's PRs will sometimes try to pin to the patch version of the action (e.g., updating `uses: foo/bar@v1` to `uses: foo/bar@v2.3.4`). When the action author has provided a major version ref, use that instead (e.g., `uses: foo/bar@v2`). Dependabot will automatically close its PR once the workflow has been updated. More information: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b93afff --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# See: https://docs.github.com/en/code-security/supply-chain-security/configuration-options-for-dependency-updates#about-the-dependabotyml-file +version: 2 + +updates: + # Configure check for outdated GitHub Actions actions in workflows. + # See: https://docs.github.com/en/code-security/supply-chain-security/keeping-your-actions-up-to-date-with-dependabot + - package-ecosystem: github-actions + directory: / # Check the repository's workflows under /.github/workflows/ + schedule: + interval: daily + labels: + - "topic: infrastructure" From df126d7f9ea556c4e7f74430874b06fe44b96966 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 09:54:07 +0200 Subject: [PATCH 047/108] Adding license text in header. --- src/Arduino_ThreadsafeIO.h | 16 +++++++++++++++- src/BusDevice.h | 16 +++++++++++++++- src/IoTransaction.h | 16 +++++++++++++++- src/spi/SpiBusDevice.h | 16 +++++++++++++++- src/spi/SpiBusDeviceConfig.h | 16 +++++++++++++++- src/spi/SpiDispatcher.cpp | 16 +++++++++++++++- src/spi/SpiDispatcher.h | 16 +++++++++++++++- src/wire/WireBusDevice.h | 16 +++++++++++++++- src/wire/WireBusDeviceConfig.h | 16 +++++++++++++++- src/wire/WireDispatcher.cpp | 16 +++++++++++++++- src/wire/WireDispatcher.h | 16 +++++++++++++++- 11 files changed, 165 insertions(+), 11 deletions(-) diff --git a/src/Arduino_ThreadsafeIO.h b/src/Arduino_ThreadsafeIO.h index e11fa86..20e805f 100644 --- a/src/Arduino_ThreadsafeIO.h +++ b/src/Arduino_ThreadsafeIO.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ARDUINO_THREADSAFE_IO_H_ diff --git a/src/BusDevice.h b/src/BusDevice.h index 12313ed..df1665d 100644 --- a/src/BusDevice.h +++ b/src/BusDevice.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef BUS_DEVICE_H_ diff --git a/src/IoTransaction.h b/src/IoTransaction.h index 8a4f6b0..87dad0b 100644 --- a/src/IoTransaction.h +++ b/src/IoTransaction.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IO_TRANSACTION_H_ diff --git a/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h index cd8cd09..6a3a76e 100644 --- a/src/spi/SpiBusDevice.h +++ b/src/spi/SpiBusDevice.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SPI_BUS_DEVICE_H_ diff --git a/src/spi/SpiBusDeviceConfig.h b/src/spi/SpiBusDeviceConfig.h index d7f1ddc..a1f58df 100644 --- a/src/spi/SpiBusDeviceConfig.h +++ b/src/spi/SpiBusDeviceConfig.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SPI_BUS_DEVICE_CONFIG_H_ diff --git a/src/spi/SpiDispatcher.cpp b/src/spi/SpiDispatcher.cpp index 3954e27..17a2f48 100644 --- a/src/spi/SpiDispatcher.cpp +++ b/src/spi/SpiDispatcher.cpp @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ /************************************************************************************** diff --git a/src/spi/SpiDispatcher.h b/src/spi/SpiDispatcher.h index a03e319..c42adf2 100644 --- a/src/spi/SpiDispatcher.h +++ b/src/spi/SpiDispatcher.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SPI_DISPATCHER_H_ diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index 7519db5..ef11b2e 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WIRE_BUS_DEVICE_H_ diff --git a/src/wire/WireBusDeviceConfig.h b/src/wire/WireBusDeviceConfig.h index 68bb596..a1aba0f 100644 --- a/src/wire/WireBusDeviceConfig.h +++ b/src/wire/WireBusDeviceConfig.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WIRE_BUS_DEVICE_CONFIG_H_ diff --git a/src/wire/WireDispatcher.cpp b/src/wire/WireDispatcher.cpp index de8fe75..6b00ed0 100644 --- a/src/wire/WireDispatcher.cpp +++ b/src/wire/WireDispatcher.cpp @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ /************************************************************************************** diff --git a/src/wire/WireDispatcher.h b/src/wire/WireDispatcher.h index ecc25a2..d75a75d 100644 --- a/src/wire/WireDispatcher.h +++ b/src/wire/WireDispatcher.h @@ -1,5 +1,19 @@ /* - * A deeply magical library providing threadsafe IO via pipes. + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WIRE_DISPATCHER_H_ From 679b94f8d48cebaeb866663ec497e5b4d48cf741 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 09:55:19 +0200 Subject: [PATCH 048/108] Adding LGPL license deed. --- LICENSE | 504 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 504 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8000a6f --- /dev/null +++ b/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 + USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random + Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! From 631e1495389b11d741c9b6a6aea4100b3a835fc9 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 09:56:24 +0200 Subject: [PATCH 049/108] Filling license deed. --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 8000a6f..b4e6b5f 100644 --- a/LICENSE +++ b/LICENSE @@ -470,8 +470,8 @@ safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + This library enables threadsafe peripheral IO access via pipes. + Copyright (C) 2021 Alexander Entinger / Arduino This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public From 20ba41b7b6af2ced7dbdfb6e429324cf6d6f75d5 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 12 Jul 2021 10:54:50 +0200 Subject: [PATCH 050/108] Release v0.1.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 08e7ac9..5e22e09 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_ThreadsafeIO -version=0.0.1 +version=0.1.0 author=Alexander Entinger maintainer=Arduino sentence=Enable threadsafe peripheral access via pipes. From 9d0961a894d35ed8885c1ab72d0dc6dd5c1a20f2 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 11 Jul 2021 23:29:05 -0700 Subject: [PATCH 051/108] Add CI workflow to check for commonly misspelled words On every push, pull request, and periodically, use the codespell-project/actions-codespell action to check for commonly misspelled words. In the event of a false positive, the problematic word should be added, in all lowercase, to the ignore-words-list field of ./.codespellrc. Regardless of the case of the word in the false positive, it must be in all lowercase in the ignore list. The ignore list is comma-separated with no spaces. --- .codespellrc | 8 ++++++++ .github/workflows/spell-check.yml | 22 ++++++++++++++++++++++ README.md | 4 +++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .codespellrc create mode 100644 .github/workflows/spell-check.yml diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 0000000..96747fb --- /dev/null +++ b/.codespellrc @@ -0,0 +1,8 @@ +# See: https://github.com/codespell-project/codespell#using-a-config-file +[codespell] +# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: +ignore-words-list = , +builtin = clear,informal,en-GB_to_en-US +check-filenames = +check-hidden = +skip = ./.git diff --git a/.github/workflows/spell-check.yml b/.github/workflows/spell-check.yml new file mode 100644 index 0000000..4601442 --- /dev/null +++ b/.github/workflows/spell-check.yml @@ -0,0 +1,22 @@ +name: Spell Check + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + pull_request: + schedule: + # Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates. + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +jobs: + spellcheck: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Spell check + uses: codespell-project/actions-codespell@master diff --git a/README.md b/README.md index 1557883..52b6023 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ `Arduino_ThreadsafeIO` -====================== \ No newline at end of file +====================== + +[![Spell Check status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml) From 7ec7ad69232b3c561f1d933cbc0117a9d6c17ea7 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 11 Jul 2021 23:35:32 -0700 Subject: [PATCH 052/108] Correct typos in comments --- examples/ts_wire/ts_wire.ino | 2 +- src/spi/SpiDispatcher.cpp | 2 +- src/wire/WireDispatcher.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/ts_wire/ts_wire.ino b/examples/ts_wire/ts_wire.ino index 67456eb..3752fb8 100644 --- a/examples/ts_wire/ts_wire.ino +++ b/examples/ts_wire/ts_wire.ino @@ -80,7 +80,7 @@ void lsm6dsox_thread_func() { /* Sleep between 5 and 500 ms */ rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); - /* Try to read some data from the BMP3888. */ + /* Try to read some data from the LSM6DSOX. */ byte const who_am_i = lsm6dsox_read_reg(LSM6DSOX_WHO_AM_I_REG); /* Print thread id and chip id value to serial. */ char msg[64] = {0}; diff --git a/src/spi/SpiDispatcher.cpp b/src/spi/SpiDispatcher.cpp index 3954e27..6472912 100644 --- a/src/spi/SpiDispatcher.cpp +++ b/src/spi/SpiDispatcher.cpp @@ -81,7 +81,7 @@ void SpiDispatcher::begin() { SPI.begin(); _thread.start(mbed::callback(this, &SpiDispatcher::threadFunc)); /* TODO: Check return code */ - /* Is is necessary to wait until the SpiDispatcher::threadFunc() + /* It is necessary to wait until the SpiDispatcher::threadFunc() * has started, otherwise other threads might trigger IO requests * before this thread is actually running. */ diff --git a/src/wire/WireDispatcher.cpp b/src/wire/WireDispatcher.cpp index de8fe75..b4e3316 100644 --- a/src/wire/WireDispatcher.cpp +++ b/src/wire/WireDispatcher.cpp @@ -81,7 +81,7 @@ void WireDispatcher::begin() { Wire.begin(); _thread.start(mbed::callback(this, &WireDispatcher::threadFunc)); /* TODO: Check return code */ - /* Is is necessary to wait until the WireDispatcher::threadFunc() + /* It is necessary to wait until the WireDispatcher::threadFunc() * has started, otherwise other threads might trigger IO requests * before this thread is actually running. */ From eb791f49a8834587eacdec2fd52a3f8647ddceae Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 11 Jul 2021 23:37:03 -0700 Subject: [PATCH 053/108] Add CI workflow to do Arduino project-specific linting On every push, pull request, and periodically, run Arduino Lint to check for common problems not related to the project code. --- .github/workflows/check-arduino.yml | 28 ++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 29 insertions(+) create mode 100644 .github/workflows/check-arduino.yml diff --git a/.github/workflows/check-arduino.yml b/.github/workflows/check-arduino.yml new file mode 100644 index 0000000..0d03f48 --- /dev/null +++ b/.github/workflows/check-arduino.yml @@ -0,0 +1,28 @@ +name: Check Arduino + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + pull_request: + schedule: + # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint. + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Arduino Lint + uses: arduino/arduino-lint-action@v1 + with: + compliance: specification + # Change this to "update" once the library is added to the index. + library-manager: submit + # Always use this setting for official repositories. Remove for 3rd party projects. + official: true diff --git a/README.md b/README.md index 52b6023..1ac9db8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ `Arduino_ThreadsafeIO` ====================== +[![Check Arduino status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/check-arduino.yml) [![Spell Check status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml) From c9ecc4447ad40df3bd19c6ab2e8e13ead365ccf8 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 11 Jul 2021 23:52:53 -0700 Subject: [PATCH 054/108] Correct field name in library.properties The library.properties metadata file's `includes` field name was misspelled `include`, which is not supported. --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 08e7ac9..fa4b905 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,4 @@ paragraph= category=Communication url= architectures=mbed,mbed_portenta,mbed_nano -include=Arduino_ThreadsafeIO.h +includes=Arduino_ThreadsafeIO.h From 0dd94af6b86f82ffa0df549388261603b2c33438 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 11 Jul 2021 23:38:34 -0700 Subject: [PATCH 055/108] Add "smoke test" examples compilation CI workflow On every push or pull request that affects library source or example files, and periodically, compile all example sketches for the specified boards. A report of the resulting change in memory usage of the examples will be commented to PR threads. --- .../workflows/compile-examples-private.yml | 97 +++++++++++++++++++ README.md | 1 + 2 files changed, 98 insertions(+) create mode 100644 .github/workflows/compile-examples-private.yml diff --git a/.github/workflows/compile-examples-private.yml b/.github/workflows/compile-examples-private.yml new file mode 100644 index 0000000..9645d66 --- /dev/null +++ b/.github/workflows/compile-examples-private.yml @@ -0,0 +1,97 @@ +name: Compile Examples + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/compile-examples-private.ya?ml" + - "library.properties" + - "examples/**" + - "src/**" + pull_request: + paths: + - ".github/workflows/compile-examples-private.ya?ml" + - "library.properties" + - "examples/**" + - "src/**" + schedule: + # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +env: + SKETCHES_REPORTS_PATH: sketches-reports + SKETCHES_REPORTS_ARTIFACT_NAME: sketches-reports + +jobs: + build: + name: ${{ matrix.board.fqbn }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + board: + - fqbn: arduino:mbed_nano:nano33ble + platforms: | + - name: arduino:mbed_nano + - fqbn: arduino:mbed_nano:nanorp2040connect + platforms: | + - name: arduino:mbed_nano + - fqbn: arduino:mbed_portenta:envie_m4 + platforms: | + - name: arduino:mbed_portenta + - fqbn: arduino:mbed_portenta:envie_m7 + platforms: | + - name: arduino:mbed_portenta + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Compile examples + uses: arduino/compile-sketches@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fqbn: ${{ matrix.board.fqbn }} + platforms: ${{ matrix.board.platforms }} + libraries: | + # Install the library from the local path. + - source-path: ./ + # Additional library dependencies can be listed here. + # See: https://github.com/arduino/compile-sketches#libraries + sketch-paths: | + - examples + enable-deltas-report: true + sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} + + - name: Save sketches report as workflow artifact + uses: actions/upload-artifact@v2 + with: + if-no-files-found: error + path: ${{ env.SKETCHES_REPORTS_PATH }} + name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} + + report-size-deltas: + needs: build + # Run even if some compilations failed. + if: always() && github.event_name == 'pull_request' + runs-on: ubuntu-latest + + steps: + - name: Download sketches reports artifact + id: download-artifact + continue-on-error: true # If compilation failed for all boards then there are no artifacts + uses: actions/download-artifact@v2 + with: + name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} + path: ${{ env.SKETCHES_REPORTS_PATH }} + + - name: Comment size deltas report to PR + uses: arduino/report-size-deltas@v1 + # If actions/download-artifact failed, there are no artifacts to report from. + if: steps.download-artifact.outcome == 'success' + with: + sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} diff --git a/README.md b/README.md index 1ac9db8..fe3e009 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,5 @@ ====================== [![Check Arduino status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/check-arduino.yml) +[![Compile Examples status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/compile-examples-private.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/compile-examples-private.yml) [![Spell Check status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml) From 6d9459c739e588bd62fb703ffa3f72d0df19ea9d Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 08:33:45 +0200 Subject: [PATCH 056/108] Overload SpiBusDeviceConfig in order to support the simple use case of just using a cs pin. (#2) --- examples/ts_spi/ts_spi.ino | 9 +-------- src/spi/SpiBusDeviceConfig.h | 9 +++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index 06bd9da..37e032b 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -27,14 +27,7 @@ void bmp388_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -SpiBusDevice bmp388{"SPI", - SpiBusDeviceConfig { - SPISettings{1000000, MSBFIRST, SPI_MODE0}, - /* bmp388_select or ... */ [](){ digitalWrite(BMP388_CS_PIN, LOW ); }, - /* bmp388_deselect or ... */ [](){ digitalWrite(BMP388_CS_PIN, HIGH); } - } - }; - +SpiBusDevice bmp388{"SPI", SpiBusDeviceConfig {SPISettings{1000000, MSBFIRST, SPI_MODE0}, BMP388_CS_PIN}}; static char thread_name[NUM_THREADS][32]; diff --git a/src/spi/SpiBusDeviceConfig.h b/src/spi/SpiBusDeviceConfig.h index a1f58df..56e467d 100644 --- a/src/spi/SpiBusDeviceConfig.h +++ b/src/spi/SpiBusDeviceConfig.h @@ -48,6 +48,15 @@ class SpiBusDeviceConfig , _fill_symbol{fill_symbol} { } + SpiBusDeviceConfig(SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF) + : SpiBusDeviceConfig + {spi_settings, + [cs_pin](){ digitalWrite(cs_pin, LOW); }, + [cs_pin](){ digitalWrite(cs_pin, HIGH); }, + fill_symbol + } + { } + SPISettings settings () const { return _spi_settings; } void select () const { if (_spi_select) _spi_select(); } From 30ef095c428de353f6e4035e13d53f6cff68f75e Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 08:42:49 +0200 Subject: [PATCH 057/108] Fix: Filling empty url field within library.properties. (#3) --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 9fbbcde..c879364 100644 --- a/library.properties +++ b/library.properties @@ -5,6 +5,6 @@ maintainer=Arduino sentence=Enable threadsafe peripheral access via pipes. paragraph= category=Communication -url= +url=https://github.com/bcmi-labs/Arduino_ThreadsafeIO architectures=mbed,mbed_portenta,mbed_nano includes=Arduino_ThreadsafeIO.h From b2c2b361dfe045f6fe9d64cf7ced9b879f8eefcd Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 09:15:11 +0200 Subject: [PATCH 058/108] Creating SpiBusDevice objects via new class BusDeviceCreator. --- examples/ts_spi/ts_spi.ino | 2 +- keywords.txt | 2 ++ src/Arduino_ThreadsafeIO.h | 1 + src/BusDeviceCreator.cpp | 56 ++++++++++++++++++++++++++++++++++++++ src/BusDeviceCreator.h | 53 ++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/BusDeviceCreator.cpp create mode 100644 src/BusDeviceCreator.h diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index 37e032b..982f786 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -27,7 +27,7 @@ void bmp388_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -SpiBusDevice bmp388{"SPI", SpiBusDeviceConfig {SPISettings{1000000, MSBFIRST, SPI_MODE0}, BMP388_CS_PIN}}; +SpiBusDevice bmp388 = BusDeviceCreator.create("SPI", SPISettings{1000000, MSBFIRST, SPI_MODE0}, BMP388_CS_PIN); static char thread_name[NUM_THREADS][32]; diff --git a/keywords.txt b/keywords.txt index 8dbef7d..46a38cc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -12,12 +12,14 @@ SpiBusDevice KEYWORD1 SpiBusDeviceConfig KEYWORD1 WireBusDevice KEYWORD1 WireBusDeviceConfig KEYWORD1 +BusDeviceCreator KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### transfer KEYWORD2 +create KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/Arduino_ThreadsafeIO.h b/src/Arduino_ThreadsafeIO.h index 20e805f..d2cba63 100644 --- a/src/Arduino_ThreadsafeIO.h +++ b/src/Arduino_ThreadsafeIO.h @@ -23,6 +23,7 @@ * INCLUDE **************************************************************************************/ +#include "BusDeviceCreator.h" #include "spi/SpiBusDevice.h" #include "wire/WireBusDevice.h" diff --git a/src/BusDeviceCreator.cpp b/src/BusDeviceCreator.cpp new file mode 100644 index 0000000..a945883 --- /dev/null +++ b/src/BusDeviceCreator.cpp @@ -0,0 +1,56 @@ +/* + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "BusDeviceCreator.h" + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace impl +{ + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +SpiBusDevice BusDeviceCreator::create(std::string const & spi_bus, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol) +{ + return SpiBusDevice(spi_bus, SpiBusDeviceConfig{spi_settings, spi_select, spi_deselect, fill_symbol}); +} + +SpiBusDevice BusDeviceCreator::create(std::string const & spi_bus, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol) +{ + return SpiBusDevice(spi_bus, SpiBusDeviceConfig{spi_settings, cs_pin, fill_symbol}); +} + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* namespace impl */ + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +impl::BusDeviceCreator BusDeviceCreator; diff --git a/src/BusDeviceCreator.h b/src/BusDeviceCreator.h new file mode 100644 index 0000000..6dc3097 --- /dev/null +++ b/src/BusDeviceCreator.h @@ -0,0 +1,53 @@ +/* + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BUS_DEVICE_CREATOR_H_ +#define BUS_DEVICE_CREATOR_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "spi/SpiBusDevice.h" +#include "wire/WireBusDevice.h" + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +namespace impl +{ + +class BusDeviceCreator +{ +public: + + SpiBusDevice create(std::string const & spi_bus, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF); + SpiBusDevice create(std::string const & spi_bus, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF); + +}; + +} /* namespace impl */ + +/************************************************************************************** + * EXTERN DECLARATION + **************************************************************************************/ + +extern impl::BusDeviceCreator BusDeviceCreator; + +#endif /* BUS_DEVICE_CREATOR_H_ */ From 2727e41efcf78a738e12fe1d821f3edf5ab75015 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 09:15:33 +0200 Subject: [PATCH 059/108] Creating WireBusDevice objects via new class BusDeviceCreator. --- examples/ts_wire/ts_wire.ino | 2 +- src/BusDeviceCreator.cpp | 15 +++++++++++++++ src/BusDeviceCreator.h | 4 ++++ src/wire/WireBusDeviceConfig.h | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/examples/ts_wire/ts_wire.ino b/examples/ts_wire/ts_wire.ino index 3752fb8..8f14a7c 100644 --- a/examples/ts_wire/ts_wire.ino +++ b/examples/ts_wire/ts_wire.ino @@ -24,7 +24,7 @@ void lsm6dsox_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -WireBusDevice lsm6dsox{"Wire", WireBusDeviceConfig{LSM6DSOX_ADDRESS}}; +WireBusDevice lsm6dsox = BusDeviceCreator.create("Wire", LSM6DSOX_ADDRESS); static char thread_name[NUM_THREADS][32]; diff --git a/src/BusDeviceCreator.cpp b/src/BusDeviceCreator.cpp index a945883..1b6b8e1 100644 --- a/src/BusDeviceCreator.cpp +++ b/src/BusDeviceCreator.cpp @@ -43,6 +43,21 @@ SpiBusDevice BusDeviceCreator::create(std::string const & spi_bus, SPISettings c return SpiBusDevice(spi_bus, SpiBusDeviceConfig{spi_settings, cs_pin, fill_symbol}); } +WireBusDevice BusDeviceCreator::create(std::string const & wire_bus, byte const slave_addr, bool const restart, bool const stop) +{ + return WireBusDevice(wire_bus, WireBusDeviceConfig{slave_addr, restart, stop}); +} + +WireBusDevice BusDeviceCreator::create(std::string const & wire_bus, byte const slave_addr, bool const restart) +{ + return create(wire_bus, slave_addr, restart, true); +} + +WireBusDevice BusDeviceCreator::create(std::string const & wire_bus, byte const slave_addr) +{ + return create(wire_bus, slave_addr, true, true); +} + /************************************************************************************** * NAMESPACE **************************************************************************************/ diff --git a/src/BusDeviceCreator.h b/src/BusDeviceCreator.h index 6dc3097..c23f3ca 100644 --- a/src/BusDeviceCreator.h +++ b/src/BusDeviceCreator.h @@ -40,6 +40,10 @@ class BusDeviceCreator SpiBusDevice create(std::string const & spi_bus, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF); SpiBusDevice create(std::string const & spi_bus, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF); + WireBusDevice create(std::string const & wire_bus, byte const slave_addr, bool const restart, bool const stop); + WireBusDevice create(std::string const & wire_bus, byte const slave_addr, bool const restart); + WireBusDevice create(std::string const & wire_bus, byte const slave_addr); + }; } /* namespace impl */ diff --git a/src/wire/WireBusDeviceConfig.h b/src/wire/WireBusDeviceConfig.h index a1aba0f..2f6424a 100644 --- a/src/wire/WireBusDeviceConfig.h +++ b/src/wire/WireBusDeviceConfig.h @@ -33,7 +33,7 @@ class WireBusDeviceConfig { public: - WireBusDeviceConfig(byte const slave_addr, bool const restart = true, bool const stop = true) + WireBusDeviceConfig(byte const slave_addr, bool const restart, bool const stop) : _slave_addr{slave_addr} , _restart{restart} , _stop{stop} From 010c71f46de736e2d1adf8b145ab77fe3683a1e4 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 09:28:01 +0200 Subject: [PATCH 060/108] SpiBusDevice: Replace string for object name with actual SPI object. --- examples/ts_spi/ts_spi.ino | 2 +- src/BusDeviceCreator.cpp | 8 ++++---- src/BusDeviceCreator.h | 4 ++-- src/spi/SpiBusDevice.h | 4 ++-- src/spi/SpiBusDeviceConfig.h | 12 ++++++++---- src/spi/SpiDispatcher.cpp | 6 +++--- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index 982f786..7630b44 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -27,7 +27,7 @@ void bmp388_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -SpiBusDevice bmp388 = BusDeviceCreator.create("SPI", SPISettings{1000000, MSBFIRST, SPI_MODE0}, BMP388_CS_PIN); +SpiBusDevice bmp388 = BusDeviceCreator.create(SPI, SPISettings{1000000, MSBFIRST, SPI_MODE0}, BMP388_CS_PIN); static char thread_name[NUM_THREADS][32]; diff --git a/src/BusDeviceCreator.cpp b/src/BusDeviceCreator.cpp index 1b6b8e1..581335d 100644 --- a/src/BusDeviceCreator.cpp +++ b/src/BusDeviceCreator.cpp @@ -33,14 +33,14 @@ namespace impl * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ -SpiBusDevice BusDeviceCreator::create(std::string const & spi_bus, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol) +SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol) { - return SpiBusDevice(spi_bus, SpiBusDeviceConfig{spi_settings, spi_select, spi_deselect, fill_symbol}); + return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, spi_select, spi_deselect, fill_symbol}); } -SpiBusDevice BusDeviceCreator::create(std::string const & spi_bus, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol) +SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol) { - return SpiBusDevice(spi_bus, SpiBusDeviceConfig{spi_settings, cs_pin, fill_symbol}); + return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, cs_pin, fill_symbol}); } WireBusDevice BusDeviceCreator::create(std::string const & wire_bus, byte const slave_addr, bool const restart, bool const stop) diff --git a/src/BusDeviceCreator.h b/src/BusDeviceCreator.h index c23f3ca..ce3438b 100644 --- a/src/BusDeviceCreator.h +++ b/src/BusDeviceCreator.h @@ -37,8 +37,8 @@ class BusDeviceCreator { public: - SpiBusDevice create(std::string const & spi_bus, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF); - SpiBusDevice create(std::string const & spi_bus, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF); + SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF); + SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF); WireBusDevice create(std::string const & wire_bus, byte const slave_addr, bool const restart, bool const stop); WireBusDevice create(std::string const & wire_bus, byte const slave_addr, bool const restart); diff --git a/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h index 6a3a76e..f033f30 100644 --- a/src/spi/SpiBusDevice.h +++ b/src/spi/SpiBusDevice.h @@ -39,9 +39,9 @@ class SpiBusDevice : public BusDevice { public: - SpiBusDevice(std::string const & spi_bus, SpiBusDeviceConfig const & config) + SpiBusDevice(SpiBusDeviceConfig const & config) : _config{config} - { /* TODO: Select SPI bus based in string. */ } + { } virtual IoResponse transfer(IoRequest & req) override diff --git a/src/spi/SpiBusDeviceConfig.h b/src/spi/SpiBusDeviceConfig.h index 56e467d..e46e499 100644 --- a/src/spi/SpiBusDeviceConfig.h +++ b/src/spi/SpiBusDeviceConfig.h @@ -41,16 +41,18 @@ class SpiBusDeviceConfig typedef std::function SpiDeselectFunc; - SpiBusDeviceConfig(SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF) - : _spi_settings{spi_settings} + SpiBusDeviceConfig(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF) + : _spi{spi} + , _spi_settings{spi_settings} , _spi_select{spi_select} , _spi_deselect{spi_deselect} , _fill_symbol{fill_symbol} { } - SpiBusDeviceConfig(SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF) + SpiBusDeviceConfig(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF) : SpiBusDeviceConfig - {spi_settings, + {spi, + spi_settings, [cs_pin](){ digitalWrite(cs_pin, LOW); }, [cs_pin](){ digitalWrite(cs_pin, HIGH); }, fill_symbol @@ -58,6 +60,7 @@ class SpiBusDeviceConfig { } + arduino::SPIClass & spi() { return _spi; } SPISettings settings () const { return _spi_settings; } void select () const { if (_spi_select) _spi_select(); } void deselect () const { if (_spi_deselect) _spi_deselect(); } @@ -66,6 +69,7 @@ class SpiBusDeviceConfig private: + arduino::SPIClass & _spi; SPISettings _spi_settings; SpiSelectFunc _spi_select{nullptr}; SpiDeselectFunc _spi_deselect{nullptr}; diff --git a/src/spi/SpiDispatcher.cpp b/src/spi/SpiDispatcher.cpp index 57ad833..456423c 100644 --- a/src/spi/SpiDispatcher.cpp +++ b/src/spi/SpiDispatcher.cpp @@ -138,7 +138,7 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) config->select(); - SPI.beginTransaction(config->settings()); + config->spi().beginTransaction(config->settings()); size_t bytes_received = 0, bytes_sent = 0; @@ -153,11 +153,11 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) else tx_byte = config->fill_symbol(); - byte const rx_byte = SPI.transfer(tx_byte); + byte const rx_byte = config->spi().transfer(tx_byte); io_request->read_buf[bytes_received] = rx_byte; } - SPI.endTransaction(); + config->spi().endTransaction(); config->deselect(); From a0ac8707c6acd7a9286116f7ad7ccbb1b721929b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 09:29:00 +0200 Subject: [PATCH 061/108] Removing no longer used functions bmp388_select/bmp388_deselect. --- examples/ts_spi/ts_spi.ino | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index 7630b44..ba88391 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -18,8 +18,6 @@ static size_t constexpr NUM_THREADS = 20; * FUNCTION DECLARATION **************************************************************************************/ -void bmp388_select(); -void bmp388_deselect(); byte bmp388_read_reg(byte const reg_addr); void bmp388_thread_func(); @@ -60,16 +58,6 @@ void loop() * FUNCTION DEFINITION **************************************************************************************/ -void bmp388_select() -{ - digitalWrite(BMP388_CS_PIN, LOW); -} - -void bmp388_deselect() -{ - digitalWrite(BMP388_CS_PIN, HIGH); -} - byte bmp388_read_reg(byte const reg_addr) { byte const write_buf[3] = From 062bb0a504563e6f9463005954db3127f83ab573 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 09:39:07 +0200 Subject: [PATCH 062/108] WireBusDevice: Replace string for object name with actual Wire object. --- examples/ts_wire/ts_wire.ino | 2 +- src/BusDeviceCreator.cpp | 12 ++++++------ src/BusDeviceCreator.h | 6 +++--- src/wire/WireBusDevice.h | 4 ++-- src/wire/WireBusDeviceConfig.h | 9 +++++++-- src/wire/WireDispatcher.cpp | 14 +++++++------- 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/examples/ts_wire/ts_wire.ino b/examples/ts_wire/ts_wire.ino index 8f14a7c..e8c5ee6 100644 --- a/examples/ts_wire/ts_wire.ino +++ b/examples/ts_wire/ts_wire.ino @@ -24,7 +24,7 @@ void lsm6dsox_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -WireBusDevice lsm6dsox = BusDeviceCreator.create("Wire", LSM6DSOX_ADDRESS); +WireBusDevice lsm6dsox = BusDeviceCreator.create(Wire, LSM6DSOX_ADDRESS); static char thread_name[NUM_THREADS][32]; diff --git a/src/BusDeviceCreator.cpp b/src/BusDeviceCreator.cpp index 581335d..ac334a4 100644 --- a/src/BusDeviceCreator.cpp +++ b/src/BusDeviceCreator.cpp @@ -43,19 +43,19 @@ SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SPISettings const return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, cs_pin, fill_symbol}); } -WireBusDevice BusDeviceCreator::create(std::string const & wire_bus, byte const slave_addr, bool const restart, bool const stop) +WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop) { - return WireBusDevice(wire_bus, WireBusDeviceConfig{slave_addr, restart, stop}); + return WireBusDevice(WireBusDeviceConfig{wire, slave_addr, restart, stop}); } -WireBusDevice BusDeviceCreator::create(std::string const & wire_bus, byte const slave_addr, bool const restart) +WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart) { - return create(wire_bus, slave_addr, restart, true); + return create(wire, slave_addr, restart, true); } -WireBusDevice BusDeviceCreator::create(std::string const & wire_bus, byte const slave_addr) +WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr) { - return create(wire_bus, slave_addr, true, true); + return create(wire, slave_addr, true, true); } /************************************************************************************** diff --git a/src/BusDeviceCreator.h b/src/BusDeviceCreator.h index ce3438b..8559a99 100644 --- a/src/BusDeviceCreator.h +++ b/src/BusDeviceCreator.h @@ -40,9 +40,9 @@ class BusDeviceCreator SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF); SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF); - WireBusDevice create(std::string const & wire_bus, byte const slave_addr, bool const restart, bool const stop); - WireBusDevice create(std::string const & wire_bus, byte const slave_addr, bool const restart); - WireBusDevice create(std::string const & wire_bus, byte const slave_addr); + WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop); + WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); + WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr); }; diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index ef11b2e..7a778a4 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -39,9 +39,9 @@ class WireBusDevice : public BusDevice { public: - WireBusDevice(std::string const & spi_bus, WireBusDeviceConfig const & config) + WireBusDevice(WireBusDeviceConfig const & config) : _config{config} - { /* TODO: Select Wire bus based in string. */ } + { } virtual IoResponse transfer(IoRequest & req) override diff --git a/src/wire/WireBusDeviceConfig.h b/src/wire/WireBusDeviceConfig.h index 2f6424a..c58e5b9 100644 --- a/src/wire/WireBusDeviceConfig.h +++ b/src/wire/WireBusDeviceConfig.h @@ -25,6 +25,8 @@ #include +#include + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -33,13 +35,15 @@ class WireBusDeviceConfig { public: - WireBusDeviceConfig(byte const slave_addr, bool const restart, bool const stop) - : _slave_addr{slave_addr} + WireBusDeviceConfig(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop) + : _wire{wire} + , _slave_addr{slave_addr} , _restart{restart} , _stop{stop} { } + inline arduino::HardwareI2C & wire() { return _wire; } inline byte slave_addr() const { return _slave_addr; } inline bool restart() const { return _restart; } inline bool stop() const { return _stop; } @@ -47,6 +51,7 @@ class WireBusDeviceConfig private: + arduino::HardwareI2C & _wire; byte _slave_addr{0x00}; bool _restart{true}, _stop{true}; diff --git a/src/wire/WireDispatcher.cpp b/src/wire/WireDispatcher.cpp index 3b0a394..07822a5 100644 --- a/src/wire/WireDispatcher.cpp +++ b/src/wire/WireDispatcher.cpp @@ -136,25 +136,25 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio IoResponse io_response = wire_io_transaction->rsp; WireBusDeviceConfig * config = wire_io_transaction->config; - Wire.beginTransmission(config->slave_addr()); + config->wire().beginTransmission(config->slave_addr()); size_t bytes_written = 0; for (; bytes_written < io_request->bytes_to_write; bytes_written++) { - Wire.write(io_request->write_buf[bytes_written]); + config->wire().write(io_request->write_buf[bytes_written]); } io_response->bytes_written = bytes_written; if (config->restart() && (io_request->bytes_to_read > 0)) - Wire.endTransmission(false /* stop */); + config->wire().endTransmission(false /* stop */); else - Wire.endTransmission(true /* stop */); + config->wire().endTransmission(true /* stop */); if (io_request->bytes_to_read > 0) { - Wire.requestFrom(config->slave_addr(), io_request->bytes_to_read, config->stop()); + config->wire().requestFrom(config->slave_addr(), io_request->bytes_to_read, config->stop()); - while(Wire.available() != static_cast(io_request->bytes_to_read)) + while(config->wire().available() != static_cast(io_request->bytes_to_read)) { /* TODO: Insert a timeout. */ } @@ -162,7 +162,7 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio size_t bytes_read = 0; for (; bytes_read < io_request->bytes_to_read; bytes_read++) { - io_request->read_buf[bytes_read] = Wire.read(); + io_request->read_buf[bytes_read] = config->wire().read(); } io_response->bytes_read = bytes_read; } From a9330ecd0562906338c21f8021aa4415f7364277 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 09:43:02 +0200 Subject: [PATCH 063/108] Reorder WireBusDevice create functions to form a natural progression from few parameters to many. --- src/BusDeviceCreator.cpp | 8 ++++---- src/BusDeviceCreator.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/BusDeviceCreator.cpp b/src/BusDeviceCreator.cpp index ac334a4..4f40dc9 100644 --- a/src/BusDeviceCreator.cpp +++ b/src/BusDeviceCreator.cpp @@ -43,9 +43,9 @@ SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SPISettings const return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, cs_pin, fill_symbol}); } -WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop) +WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr) { - return WireBusDevice(WireBusDeviceConfig{wire, slave_addr, restart, stop}); + return create(wire, slave_addr, true, true); } WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart) @@ -53,9 +53,9 @@ WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const s return create(wire, slave_addr, restart, true); } -WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr) +WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop) { - return create(wire, slave_addr, true, true); + return WireBusDevice(WireBusDeviceConfig{wire, slave_addr, restart, stop}); } /************************************************************************************** diff --git a/src/BusDeviceCreator.h b/src/BusDeviceCreator.h index 8559a99..3fe879f 100644 --- a/src/BusDeviceCreator.h +++ b/src/BusDeviceCreator.h @@ -40,9 +40,9 @@ class BusDeviceCreator SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF); SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF); - WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop); - WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr); + WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); + WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop); }; From d041968444800b6b8ed17177bd61cc52b56ec82a Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 19 Jul 2021 14:21:09 +0200 Subject: [PATCH 064/108] Streamline SPI API. --- examples/ts_spi/ts_spi.ino | 2 +- src/BusDeviceCreator.cpp | 21 +++++++++++++++++---- src/BusDeviceCreator.h | 5 +++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index ba88391..66e7720 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -25,7 +25,7 @@ void bmp388_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -SpiBusDevice bmp388 = BusDeviceCreator.create(SPI, SPISettings{1000000, MSBFIRST, SPI_MODE0}, BMP388_CS_PIN); +SpiBusDevice bmp388 = BusDeviceCreator.create(SPI, BMP388_CS_PIN, 1000000, MSBFIRST, SPI_MODE0); static char thread_name[NUM_THREADS][32]; diff --git a/src/BusDeviceCreator.cpp b/src/BusDeviceCreator.cpp index 4f40dc9..7e6a9e6 100644 --- a/src/BusDeviceCreator.cpp +++ b/src/BusDeviceCreator.cpp @@ -33,14 +33,27 @@ namespace impl * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ -SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol) +SpiBusDevice create(arduino::SPIClass & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol) { - return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, spi_select, spi_deselect, fill_symbol}); + return SpiBusDevice(SpiBusDeviceConfig{spi, + spi_settings, + cs_pin, + fill_symbol + }); } -SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol) +SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol) { - return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, cs_pin, fill_symbol}); + return SpiBusDevice(SpiBusDeviceConfig{spi, + SPISettings(spi_clock, spi_bit_order, spi_bit_mode), + cs_pin, + fill_symbol + }); +} + +SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol) +{ + return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, spi_select, spi_deselect, fill_symbol}); } WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr) diff --git a/src/BusDeviceCreator.h b/src/BusDeviceCreator.h index 3fe879f..e2eba88 100644 --- a/src/BusDeviceCreator.h +++ b/src/BusDeviceCreator.h @@ -37,8 +37,9 @@ class BusDeviceCreator { public: - SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF); - SpiBusDevice create(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF); + SpiBusDevice create(arduino::SPIClass & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); + SpiBusDevice create(arduino::SPIClass & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol = 0xFF); + SpiBusDevice create(arduino::SPIClass & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr); WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); From 93a70bfdc129c127cf355634f8b6762539168a81 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 22 Jul 2021 16:01:50 +0200 Subject: [PATCH 065/108] Release v0.2.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index c879364..6eb2948 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_ThreadsafeIO -version=0.1.0 +version=0.2.0 author=Alexander Entinger maintainer=Arduino sentence=Enable threadsafe peripheral access via pipes. From 77bc88b19aa3098da00d716b594add162d9656f5 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 27 Jul 2021 08:15:45 +0200 Subject: [PATCH 066/108] Replace class BusDeviceCreator with static member function BusDeviceBase::create(...) --- examples/ts_spi/ts_spi.ino | 4 +- examples/ts_wire/ts_wire.ino | 4 +- keywords.txt | 2 +- src/Arduino_ThreadsafeIO.h | 2 +- src/BusDevice.cpp | 68 +++++++++++++++++++++++++++++ src/BusDevice.h | 35 ++++++++++++++- src/BusDeviceCreator.cpp | 84 ------------------------------------ src/BusDeviceCreator.h | 58 ------------------------- src/spi/SpiBusDevice.h | 2 +- src/spi/SpiBusDeviceConfig.h | 8 ++-- src/wire/WireBusDevice.h | 2 +- 11 files changed, 113 insertions(+), 156 deletions(-) create mode 100644 src/BusDevice.cpp delete mode 100644 src/BusDeviceCreator.cpp delete mode 100644 src/BusDeviceCreator.h diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index 66e7720..a8f738f 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -25,7 +25,7 @@ void bmp388_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -SpiBusDevice bmp388 = BusDeviceCreator.create(SPI, BMP388_CS_PIN, 1000000, MSBFIRST, SPI_MODE0); +BusDevice bmp388 = BusDeviceBase::create(SPI, BMP388_CS_PIN, 1000000, MSBFIRST, SPI_MODE0); static char thread_name[NUM_THREADS][32]; @@ -69,7 +69,7 @@ byte bmp388_read_reg(byte const reg_addr) byte read_buf[3] = {0}; IoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); - IoResponse rsp = bmp388.transfer(req); + IoResponse rsp = bmp388->transfer(req); /* Do other stuff */ diff --git a/examples/ts_wire/ts_wire.ino b/examples/ts_wire/ts_wire.ino index e8c5ee6..d04a1ee 100644 --- a/examples/ts_wire/ts_wire.ino +++ b/examples/ts_wire/ts_wire.ino @@ -24,7 +24,7 @@ void lsm6dsox_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -WireBusDevice lsm6dsox = BusDeviceCreator.create(Wire, LSM6DSOX_ADDRESS); +BusDevice lsm6dsox = BusDeviceBase::create(Wire, LSM6DSOX_ADDRESS); static char thread_name[NUM_THREADS][32]; @@ -64,7 +64,7 @@ byte lsm6dsox_read_reg(byte const reg_addr) byte read_buf = 0; IoRequest req(write_buf, read_buf); - IoResponse rsp = lsm6dsox.transfer(req); + IoResponse rsp = lsm6dsox->transfer(req); /* Optionally do other stuff */ diff --git a/keywords.txt b/keywords.txt index 46a38cc..30ffbc2 100644 --- a/keywords.txt +++ b/keywords.txt @@ -12,7 +12,7 @@ SpiBusDevice KEYWORD1 SpiBusDeviceConfig KEYWORD1 WireBusDevice KEYWORD1 WireBusDeviceConfig KEYWORD1 -BusDeviceCreator KEYWORD1 +BusDevice KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) diff --git a/src/Arduino_ThreadsafeIO.h b/src/Arduino_ThreadsafeIO.h index d2cba63..616ec64 100644 --- a/src/Arduino_ThreadsafeIO.h +++ b/src/Arduino_ThreadsafeIO.h @@ -23,7 +23,7 @@ * INCLUDE **************************************************************************************/ -#include "BusDeviceCreator.h" +#include "BusDevice.h" #include "spi/SpiBusDevice.h" #include "wire/WireBusDevice.h" diff --git a/src/BusDevice.cpp b/src/BusDevice.cpp new file mode 100644 index 0000000..41ba5fe --- /dev/null +++ b/src/BusDevice.cpp @@ -0,0 +1,68 @@ +/* + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "BusDevice.h" + +#include "spi/SpiBusDevice.h" +#include "wire/WireBusDevice.h" + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +BusDevice BusDeviceBase(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol) +{ + return BusDevice(new SpiBusDevice(SpiBusDeviceConfig{spi, + spi_settings, + cs_pin, + fill_symbol + })); +} + +BusDevice BusDeviceBase::create(arduino::HardwareSPI & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol) +{ + return BusDevice(new SpiBusDevice(SpiBusDeviceConfig{spi, + SPISettings(spi_clock, spi_bit_order, spi_bit_mode), + cs_pin, + fill_symbol + })); +} + +BusDevice BusDeviceBase::create(arduino::HardwareSPI & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol) +{ + return BusDevice(new SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, spi_select, spi_deselect, fill_symbol})); +} + +BusDevice BusDeviceBase::create(arduino::HardwareI2C & wire, byte const slave_addr) +{ + return create(wire, slave_addr, true, true); +} + +BusDevice BusDeviceBase::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart) +{ + return create(wire, slave_addr, restart, true); +} + +BusDevice BusDeviceBase::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop) +{ + return BusDevice(new WireBusDevice(WireBusDeviceConfig{wire, slave_addr, restart, stop})); +} diff --git a/src/BusDevice.h b/src/BusDevice.h index df1665d..412afd8 100644 --- a/src/BusDevice.h +++ b/src/BusDevice.h @@ -25,16 +25,47 @@ #include "IoTransaction.h" +#include "spi/SpiBusDeviceConfig.h" + +/************************************************************************************** + * FORWARD DECLARATION + **************************************************************************************/ + +namespace arduino +{ + class HardwareSPI; + class HardwareI2C; +} + +class BusDeviceBase; + +/************************************************************************************** + * TYPEDEF + **************************************************************************************/ + +typedef mbed::SharedPtr BusDevice; + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ -class BusDevice +class BusDeviceBase { public: - virtual ~BusDevice() { } + + virtual ~BusDeviceBase() { } virtual IoResponse transfer(IoRequest & req) = 0; + + + static BusDevice create(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); + static BusDevice create(arduino::HardwareSPI & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol = 0xFF); + static BusDevice create(arduino::HardwareSPI & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); + + static BusDevice create(arduino::HardwareI2C & wire, byte const slave_addr); + static BusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); + static BusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop); + }; #endif /* BUS_DEVICE_H_ */ diff --git a/src/BusDeviceCreator.cpp b/src/BusDeviceCreator.cpp deleted file mode 100644 index 7e6a9e6..0000000 --- a/src/BusDeviceCreator.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of the Arduino_ThreadsafeIO library. - * Copyright (c) 2021 Arduino SA. - * - * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/************************************************************************************** - * INCLUDE - **************************************************************************************/ - -#include "BusDeviceCreator.h" - -/************************************************************************************** - * NAMESPACE - **************************************************************************************/ - -namespace impl -{ - -/************************************************************************************** - * PUBLIC MEMBER FUNCTIONS - **************************************************************************************/ - -SpiBusDevice create(arduino::SPIClass & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol) -{ - return SpiBusDevice(SpiBusDeviceConfig{spi, - spi_settings, - cs_pin, - fill_symbol - }); -} - -SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol) -{ - return SpiBusDevice(SpiBusDeviceConfig{spi, - SPISettings(spi_clock, spi_bit_order, spi_bit_mode), - cs_pin, - fill_symbol - }); -} - -SpiBusDevice BusDeviceCreator::create(arduino::SPIClass & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol) -{ - return SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, spi_select, spi_deselect, fill_symbol}); -} - -WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr) -{ - return create(wire, slave_addr, true, true); -} - -WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart) -{ - return create(wire, slave_addr, restart, true); -} - -WireBusDevice BusDeviceCreator::create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop) -{ - return WireBusDevice(WireBusDeviceConfig{wire, slave_addr, restart, stop}); -} - -/************************************************************************************** - * NAMESPACE - **************************************************************************************/ - -} /* namespace impl */ - -/************************************************************************************** - * GLOBAL VARIABLES - **************************************************************************************/ - -impl::BusDeviceCreator BusDeviceCreator; diff --git a/src/BusDeviceCreator.h b/src/BusDeviceCreator.h deleted file mode 100644 index e2eba88..0000000 --- a/src/BusDeviceCreator.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the Arduino_ThreadsafeIO library. - * Copyright (c) 2021 Arduino SA. - * - * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef BUS_DEVICE_CREATOR_H_ -#define BUS_DEVICE_CREATOR_H_ - -/************************************************************************************** - * INCLUDE - **************************************************************************************/ - -#include "spi/SpiBusDevice.h" -#include "wire/WireBusDevice.h" - -/************************************************************************************** - * CLASS DECLARATION - **************************************************************************************/ - -namespace impl -{ - -class BusDeviceCreator -{ -public: - - SpiBusDevice create(arduino::SPIClass & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); - SpiBusDevice create(arduino::SPIClass & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol = 0xFF); - SpiBusDevice create(arduino::SPIClass & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); - - WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr); - WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); - WireBusDevice create(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop); - -}; - -} /* namespace impl */ - -/************************************************************************************** - * EXTERN DECLARATION - **************************************************************************************/ - -extern impl::BusDeviceCreator BusDeviceCreator; - -#endif /* BUS_DEVICE_CREATOR_H_ */ diff --git a/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h index f033f30..f2ea7d2 100644 --- a/src/spi/SpiBusDevice.h +++ b/src/spi/SpiBusDevice.h @@ -35,7 +35,7 @@ * CLASS DECLARATION **************************************************************************************/ -class SpiBusDevice : public BusDevice +class SpiBusDevice : public BusDeviceBase { public: diff --git a/src/spi/SpiBusDeviceConfig.h b/src/spi/SpiBusDeviceConfig.h index e46e499..90a1f5d 100644 --- a/src/spi/SpiBusDeviceConfig.h +++ b/src/spi/SpiBusDeviceConfig.h @@ -41,7 +41,7 @@ class SpiBusDeviceConfig typedef std::function SpiDeselectFunc; - SpiBusDeviceConfig(arduino::SPIClass & spi, SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF) + SpiBusDeviceConfig(arduino::HardwareSPI & spi, SPISettings const & spi_settings, SpiSelectFunc spi_select, SpiDeselectFunc spi_deselect, byte const fill_symbol = 0xFF) : _spi{spi} , _spi_settings{spi_settings} , _spi_select{spi_select} @@ -49,7 +49,7 @@ class SpiBusDeviceConfig , _fill_symbol{fill_symbol} { } - SpiBusDeviceConfig(arduino::SPIClass & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF) + SpiBusDeviceConfig(arduino::HardwareSPI & spi, SPISettings const & spi_settings, int const cs_pin, byte const fill_symbol = 0xFF) : SpiBusDeviceConfig {spi, spi_settings, @@ -60,7 +60,7 @@ class SpiBusDeviceConfig { } - arduino::SPIClass & spi() { return _spi; } + arduino::HardwareSPI & spi() { return _spi; } SPISettings settings () const { return _spi_settings; } void select () const { if (_spi_select) _spi_select(); } void deselect () const { if (_spi_deselect) _spi_deselect(); } @@ -69,7 +69,7 @@ class SpiBusDeviceConfig private: - arduino::SPIClass & _spi; + arduino::HardwareSPI & _spi; SPISettings _spi_settings; SpiSelectFunc _spi_select{nullptr}; SpiDeselectFunc _spi_deselect{nullptr}; diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index 7a778a4..d3ca3e0 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -35,7 +35,7 @@ * CLASS DECLARATION **************************************************************************************/ -class WireBusDevice : public BusDevice +class WireBusDevice : public BusDeviceBase { public: From 36edb441f48022ea3d817a06ca984560f1601756 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 28 Jul 2021 13:19:45 +0200 Subject: [PATCH 067/108] Applying patch by @facchinm allowing for Ctor style object creation. --- examples/ts_wire/ts_wire.ino | 4 ++-- src/BusDevice.cpp | 2 +- src/BusDevice.h | 31 ++++++++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/examples/ts_wire/ts_wire.ino b/examples/ts_wire/ts_wire.ino index d04a1ee..0ebba48 100644 --- a/examples/ts_wire/ts_wire.ino +++ b/examples/ts_wire/ts_wire.ino @@ -24,7 +24,7 @@ void lsm6dsox_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -BusDevice lsm6dsox = BusDeviceBase::create(Wire, LSM6DSOX_ADDRESS); +BusDevice lsm6dsox(Wire, LSM6DSOX_ADDRESS); static char thread_name[NUM_THREADS][32]; @@ -64,7 +64,7 @@ byte lsm6dsox_read_reg(byte const reg_addr) byte read_buf = 0; IoRequest req(write_buf, read_buf); - IoResponse rsp = lsm6dsox->transfer(req); + IoResponse rsp = lsm6dsox.transfer(req); /* Optionally do other stuff */ diff --git a/src/BusDevice.cpp b/src/BusDevice.cpp index 41ba5fe..15131a8 100644 --- a/src/BusDevice.cpp +++ b/src/BusDevice.cpp @@ -29,7 +29,7 @@ * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ -BusDevice BusDeviceBase(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol) +BusDevice BusDeviceBase::create(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol) { return BusDevice(new SpiBusDevice(SpiBusDeviceConfig{spi, spi_settings, diff --git a/src/BusDevice.h b/src/BusDevice.h index 412afd8..bdd4e14 100644 --- a/src/BusDevice.h +++ b/src/BusDevice.h @@ -37,14 +37,12 @@ namespace arduino class HardwareI2C; } -class BusDeviceBase; +class BusDevice; /************************************************************************************** * TYPEDEF **************************************************************************************/ -typedef mbed::SharedPtr BusDevice; - /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -68,4 +66,31 @@ class BusDeviceBase }; +class BusDevice +{ +public: + BusDevice(BusDeviceBase* dev) : instance(dev) {}; + /* + BusDevice(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol = 0xFF) { + this = BusDeviceBase::create(spi, cs_pin, spi_settings, fill_symbol); + } + BusDevice(arduino::HardwareSPI & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol = 0xFF); + BusDevice(arduino::HardwareSPI & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); + */ + //BusDevice(BusDevice&&) = default; + BusDevice(arduino::HardwareI2C & wire, byte const slave_addr) { + *this = BusDeviceBase::create(wire, slave_addr); + } + /* + BusDevice(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); + BusDevice(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop); + */ + IoResponse transfer(IoRequest & req) { + return instance->transfer(req); + }; + +private: + mbed::SharedPtr instance; +}; + #endif /* BUS_DEVICE_H_ */ From 368e6a136b79f93f73c9fee1bc30b3ea918cd865 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 28 Jul 2021 13:34:20 +0200 Subject: [PATCH 068/108] Beautify up and also test for SPI. --- examples/ts_spi/ts_spi.ino | 4 ++-- src/BusDevice.cpp | 45 +++++++++++++++++++++++++++++++++++++- src/BusDevice.h | 32 ++++++++++----------------- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/examples/ts_spi/ts_spi.ino b/examples/ts_spi/ts_spi.ino index a8f738f..a6e4604 100644 --- a/examples/ts_spi/ts_spi.ino +++ b/examples/ts_spi/ts_spi.ino @@ -25,7 +25,7 @@ void bmp388_thread_func(); * GLOBAL VARIABLES **************************************************************************************/ -BusDevice bmp388 = BusDeviceBase::create(SPI, BMP388_CS_PIN, 1000000, MSBFIRST, SPI_MODE0); +BusDevice bmp388(SPI, BMP388_CS_PIN, 1000000, MSBFIRST, SPI_MODE0); static char thread_name[NUM_THREADS][32]; @@ -69,7 +69,7 @@ byte bmp388_read_reg(byte const reg_addr) byte read_buf[3] = {0}; IoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); - IoResponse rsp = bmp388->transfer(req); + IoResponse rsp = bmp388.transfer(req); /* Do other stuff */ diff --git a/src/BusDevice.cpp b/src/BusDevice.cpp index 15131a8..8bd8276 100644 --- a/src/BusDevice.cpp +++ b/src/BusDevice.cpp @@ -26,7 +26,7 @@ #include "wire/WireBusDevice.h" /************************************************************************************** - * PUBLIC MEMBER FUNCTIONS + * BusDeviceBase PUBLIC MEMBER FUNCTIONS **************************************************************************************/ BusDevice BusDeviceBase::create(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol) @@ -66,3 +66,46 @@ BusDevice BusDeviceBase::create(arduino::HardwareI2C & wire, byte const slave_ad { return BusDevice(new WireBusDevice(WireBusDeviceConfig{wire, slave_addr, restart, stop})); } + +/************************************************************************************** + * BusDevice CTOR/DTOR + **************************************************************************************/ + +BusDevice::BusDevice(BusDeviceBase * dev) +: _dev{dev} +{ } + +BusDevice::BusDevice(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol) +{ + *this = BusDeviceBase::create(spi, cs_pin, spi_settings, fill_symbol); +} + +BusDevice::BusDevice(arduino::HardwareSPI & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol) +{ + *this = BusDeviceBase::create(spi, cs_pin, spi_clock, spi_bit_order, spi_bit_mode, fill_symbol); +} + +BusDevice::BusDevice(arduino::HardwareSPI & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol) +{ + *this = BusDeviceBase::create(spi, spi_select, spi_deselect, spi_settings, fill_symbol); +} + +BusDevice::BusDevice(arduino::HardwareI2C & wire, byte const slave_addr) +{ + *this = BusDeviceBase::create(wire, slave_addr); +} + +BusDevice::BusDevice(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart) +{ + *this = BusDeviceBase::create(wire, slave_addr, restart); +} + +BusDevice::BusDevice(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop) +{ + *this = BusDeviceBase::create(wire, slave_addr, restart, stop); +} + +IoResponse BusDevice::transfer(IoRequest & req) +{ + return _dev->transfer(req); +} diff --git a/src/BusDevice.h b/src/BusDevice.h index bdd4e14..31f4b0d 100644 --- a/src/BusDevice.h +++ b/src/BusDevice.h @@ -39,10 +39,6 @@ namespace arduino class BusDevice; -/************************************************************************************** - * TYPEDEF - **************************************************************************************/ - /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -69,28 +65,24 @@ class BusDeviceBase class BusDevice { public: - BusDevice(BusDeviceBase* dev) : instance(dev) {}; - /* - BusDevice(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol = 0xFF) { - this = BusDeviceBase::create(spi, cs_pin, spi_settings, fill_symbol); - } + + BusDevice(BusDeviceBase * dev); + + BusDevice(arduino::HardwareSPI & spi, int const cs_pin, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); BusDevice(arduino::HardwareSPI & spi, int const cs_pin, uint32_t const spi_clock, BitOrder const spi_bit_order, SPIMode const spi_bit_mode, byte const fill_symbol = 0xFF); BusDevice(arduino::HardwareSPI & spi, SpiBusDeviceConfig::SpiSelectFunc spi_select, SpiBusDeviceConfig::SpiDeselectFunc spi_deselect, SPISettings const & spi_settings, byte const fill_symbol = 0xFF); - */ - //BusDevice(BusDevice&&) = default; - BusDevice(arduino::HardwareI2C & wire, byte const slave_addr) { - *this = BusDeviceBase::create(wire, slave_addr); - } - /* + + BusDevice(arduino::HardwareI2C & wire, byte const slave_addr); BusDevice(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart); BusDevice(arduino::HardwareI2C & wire, byte const slave_addr, bool const restart, bool const stop); - */ - IoResponse transfer(IoRequest & req) { - return instance->transfer(req); - }; + + IoResponse transfer(IoRequest & req); + private: - mbed::SharedPtr instance; + + mbed::SharedPtr _dev; + }; #endif /* BUS_DEVICE_H_ */ From e20752a2ad4c9e9c8059ed6b0bd0ff973069e7da Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 19 Aug 2021 15:18:57 +0200 Subject: [PATCH 069/108] Release v0.3.0. --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 6eb2948..bf9def6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_ThreadsafeIO -version=0.2.0 +version=0.3.0 author=Alexander Entinger maintainer=Arduino sentence=Enable threadsafe peripheral access via pipes. From a2f4e6daa25de712f105aeafb14fd1b0a538dbc1 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 31 Aug 2021 11:42:00 +0200 Subject: [PATCH 070/108] Initial draft of SerialDispatched based on @facchinm's implementation within ArduinoThreads. --- examples/ts_serial/ts_serial.ino | 64 ++++++++++ src/Arduino_ThreadsafeIO.h | 1 + src/serial/SerialDispatcher.cpp | 203 +++++++++++++++++++++++++++++++ src/serial/SerialDispatcher.h | 81 ++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 examples/ts_serial/ts_serial.ino create mode 100644 src/serial/SerialDispatcher.cpp create mode 100644 src/serial/SerialDispatcher.h diff --git a/examples/ts_serial/ts_serial.ino b/examples/ts_serial/ts_serial.ino new file mode 100644 index 0000000..0404716 --- /dev/null +++ b/examples/ts_serial/ts_serial.ino @@ -0,0 +1,64 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static size_t constexpr NUM_THREADS = 5; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +void serial_thread_func(); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +static char thread_name[NUM_THREADS][32]; +#undef Serial +SerialDispatcher Serial(SerialUSB); + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + /* Fire up some threads all accessing the LSM6DSOX */ + for(size_t i = 0; i < NUM_THREADS; i++) + { + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); + t->start(serial_thread_func); + } +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +void serial_thread_func() +{ + Serial.begin(9600); + + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); + /* Print thread id and chip id value to serial. */ + char msg[64] = {0}; + snprintf(msg, sizeof(msg), "[%05lu] %s: Lorem ipsum ...", millis(), rtos::ThisThread::get_name()); + Serial.println(msg); + } +} diff --git a/src/Arduino_ThreadsafeIO.h b/src/Arduino_ThreadsafeIO.h index 616ec64..46bbb72 100644 --- a/src/Arduino_ThreadsafeIO.h +++ b/src/Arduino_ThreadsafeIO.h @@ -26,5 +26,6 @@ #include "BusDevice.h" #include "spi/SpiBusDevice.h" #include "wire/WireBusDevice.h" +#include "serial/SerialDispatcher.h" #endif /* ARDUINO_THREADSAFE_IO_H_ */ diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp new file mode 100644 index 0000000..092fa2d --- /dev/null +++ b/src/serial/SerialDispatcher.cpp @@ -0,0 +1,203 @@ +/* + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "SerialDispatcher.h" + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +SerialDispatcher::SerialDispatcher(arduino::HardwareSerial & serial) +: _is_initialized{false} +, _mutex{} +, _cond{_mutex} +, _serial{serial} +, _thread(osPriorityRealtime, 4096, nullptr, "SerialDispatcher") +, _has_tread_started{false} +, _terminate_thread{false} +{ + +} + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +void SerialDispatcher::begin(unsigned long baudrate) +{ + begin(baudrate, SERIAL_8N1); +} + +void SerialDispatcher::begin(unsigned long baudrate, uint16_t config) +{ + if (!_is_initialized) + { + _serial.begin(baudrate, config); + _is_initialized = true; + _thread.start(mbed::callback(this, &SerialDispatcher::threadFunc)); /* TODO: Check return code */ + while (!_has_tread_started) { } + } + + mbed::ScopedLock lock(_mutex); + + /* Check if the thread calling begin is already in the list. */ + osThreadId_t const current_thread_id = rtos::ThisThread::get_id(); + if (findThreadCustomerDataById(rtos::ThisThread::get_id()) == std::end(_thread_customer_list)) + { + /* Since the thread is not in the list yet we are + * going to create a new entry to the list. + */ + ThreadCustomerData data; + data.thread_id = current_thread_id; + _thread_customer_list.push_back(data); + } +} + +void SerialDispatcher::end() +{ + mbed::ScopedLock lock(_mutex); + + /* Retrieve the current thread id and remove + * the thread data from the thread data list. + */ + osThreadId_t const current_thread_id = rtos::ThisThread::get_id(); + std::remove_if(std::begin(_thread_customer_list), + std::end (_thread_customer_list), + [current_thread_id](ThreadCustomerData const d) -> bool { return (d.thread_id == current_thread_id); }); + + /* If no thread consumers are left also end + * the serial device alltogether. + */ + if (_thread_customer_list.size() == 0) + { + _terminate_thread = true; + _thread.join(); + _serial.end(); + } +} + +int SerialDispatcher::available() +{ + mbed::ScopedLock lock(_mutex); + return _serial.available(); +} + +int SerialDispatcher::peek() +{ + mbed::ScopedLock lock(_mutex); + return _serial.peek(); +} + +int SerialDispatcher::read() +{ + mbed::ScopedLock lock(_mutex); + return _serial.read(); +} + +void SerialDispatcher::flush() +{ + mbed::ScopedLock lock(_mutex); + _serial.flush(); +} + +size_t SerialDispatcher::write(uint8_t const b) +{ + mbed::ScopedLock lock(_mutex); + + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + + /* If this thread hasn't registered yet + * with the SerialDispatcher via 'begin'. + */ + if (iter == std::end(_thread_customer_list)) + return 0; + + if (iter->tx_buffer.availableForStore()) + iter->tx_buffer.store_char(b); + + /* Inform the worker thread that new data has + * been written to a Serial transmit buffer. + */ + _cond.notify_one(); + + return 1; +} + +size_t SerialDispatcher::write(const uint8_t * data, size_t len) +{ + mbed::ScopedLock lock(_mutex); + + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + + /* If this thread hasn't registered yet + * with the SerialDispatcher via 'begin'. + */ + if (iter == std::end(_thread_customer_list)) + return 0; + + size_t bytes_written = 0; + for (; (bytes_written < len) && iter->tx_buffer.availableForStore(); bytes_written++) + iter->tx_buffer.store_char(data[bytes_written]); + + /* Inform the worker thread that new data has + * been written to a Serial transmit buffer. + */ + _cond.notify_one(); + + return bytes_written; +} + +/************************************************************************************** + * PRIVATE MEMBER FUNCTIONS + **************************************************************************************/ + +void SerialDispatcher::threadFunc() +{ + _has_tread_started = true; + + while(!_terminate_thread) + { + /* Prevent race conditions by multi-threaded + * access to shared data. + */ + mbed::ScopedLock lock(_mutex); + /* Wait for new data to be available */ + _cond.wait(); + /* Iterate over all list entries. */ + std::for_each(std::begin(_thread_customer_list), + std::end (_thread_customer_list), + [this](ThreadCustomerData & d) + { + while(d.tx_buffer.available()) + { + _serial.write(d.tx_buffer.read_char()); + } + }); + } +} + +std::list::iterator SerialDispatcher::findThreadCustomerDataById(osThreadId_t const thread_id) +{ + return std::find_if(std::begin(_thread_customer_list), + std::end (_thread_customer_list), + [thread_id](ThreadCustomerData const d) -> bool { return (d.thread_id == thread_id); }); +} \ No newline at end of file diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h new file mode 100644 index 0000000..806d731 --- /dev/null +++ b/src/serial/SerialDispatcher.h @@ -0,0 +1,81 @@ +/* + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SERIAL_DISPATCHER_H_ +#define SERIAL_DISPATCHER_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "api/HardwareSerial.h" + +#include + +#include + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class SerialDispatcher : public arduino::HardwareSerial +{ + +public: + + SerialDispatcher(arduino::HardwareSerial & serial); + + + virtual void begin(unsigned long baudrate) override; + virtual void begin(unsigned long baudrate, uint16_t config) override; + virtual void end() override; + virtual int available() override; + virtual int peek() override; + virtual int read() override; + virtual void flush() override; + virtual size_t write(uint8_t const b) override; + virtual size_t write(const uint8_t * data, size_t len) override; + using Print::write; + virtual operator bool() override { return _serial; } + + +private: + + bool _is_initialized; + rtos::Mutex _mutex; + rtos::ConditionVariable _cond; + arduino::HardwareSerial & _serial; + + rtos::Thread _thread; + bool _has_tread_started; + bool _terminate_thread; + + typedef struct + { + osThreadId_t thread_id; + arduino::RingBuffer tx_buffer; + } ThreadCustomerData; + + std::list _thread_customer_list; + + void threadFunc(); + std::list::iterator findThreadCustomerDataById(osThreadId_t const thread_id); + +}; + +#endif /* SERIAL_DISPATCHER_H_ */ From 8a86745f6a84a59e904aa8d3242cf9141d28e082 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 31 Aug 2021 12:41:44 +0200 Subject: [PATCH 071/108] Fixing spelling mistake. --- src/serial/SerialDispatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 092fa2d..1a655a6 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -85,7 +85,7 @@ void SerialDispatcher::end() [current_thread_id](ThreadCustomerData const d) -> bool { return (d.thread_id == current_thread_id); }); /* If no thread consumers are left also end - * the serial device alltogether. + * the serial device altogether. */ if (_thread_customer_list.size() == 0) { From 850046ba103351f2805d6446accad670fd35ec3b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 1 Sep 2021 08:39:43 +0200 Subject: [PATCH 072/108] Fix CI compilation for Portenta H7/M4 - no SerialUSB available. --- examples/ts_serial/ts_serial.ino | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/ts_serial/ts_serial.ino b/examples/ts_serial/ts_serial.ino index 0404716..90ee808 100644 --- a/examples/ts_serial/ts_serial.ino +++ b/examples/ts_serial/ts_serial.ino @@ -22,7 +22,11 @@ void serial_thread_func(); static char thread_name[NUM_THREADS][32]; #undef Serial -SerialDispatcher Serial(SerialUSB); +#ifdef ARDUINO_PORTENTA_H7_M4 + SerialDispatcher Serial(Serial1); /* No SerialUSB for Portenta H7 / M4 Core */ +#else + SerialDispatcher Serial(SerialUSB); +#endif /************************************************************************************** * SETUP/LOOP From 94c6c0f32e15d9e92739a5aa875d02e44f3f0385 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 3 Sep 2021 07:18:12 +0200 Subject: [PATCH 073/108] block/unblock allows for safe aggregration of serial messages in a threaded environment. (#10) --- examples/ts_serial/ts_serial.ino | 6 ++++++ keywords.txt | 2 ++ src/serial/SerialDispatcher.cpp | 23 +++++++++++++++++++++-- src/serial/SerialDispatcher.h | 3 +++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/examples/ts_serial/ts_serial.ino b/examples/ts_serial/ts_serial.ino index 90ee808..42ae35d 100644 --- a/examples/ts_serial/ts_serial.ino +++ b/examples/ts_serial/ts_serial.ino @@ -63,6 +63,12 @@ void serial_thread_func() /* Print thread id and chip id value to serial. */ char msg[64] = {0}; snprintf(msg, sizeof(msg), "[%05lu] %s: Lorem ipsum ...", millis(), rtos::ThisThread::get_name()); + /* Every Serial.print/println() encapsulated between + * block/unblock statements will only be printed after + * a block statement has occurred. + */ + Serial.block(); Serial.println(msg); + Serial.unblock(); } } diff --git a/keywords.txt b/keywords.txt index 30ffbc2..05231ff 100644 --- a/keywords.txt +++ b/keywords.txt @@ -20,6 +20,8 @@ BusDevice KEYWORD1 transfer KEYWORD2 create KEYWORD2 +block KEYWORD2 +unblock KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 1a655a6..e38e83b 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -68,6 +68,7 @@ void SerialDispatcher::begin(unsigned long baudrate, uint16_t config) */ ThreadCustomerData data; data.thread_id = current_thread_id; + data.block_tx_buffer = false; _thread_customer_list.push_back(data); } } @@ -166,6 +167,21 @@ size_t SerialDispatcher::write(const uint8_t * data, size_t len) return bytes_written; } +void SerialDispatcher::block() +{ + mbed::ScopedLock lock(_mutex); + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + iter->block_tx_buffer = true; +} + +void SerialDispatcher::unblock() +{ + mbed::ScopedLock lock(_mutex); + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + iter->block_tx_buffer = false; + _cond.notify_one(); +} + /************************************************************************************** * PRIVATE MEMBER FUNCTIONS **************************************************************************************/ @@ -187,9 +203,12 @@ void SerialDispatcher::threadFunc() std::end (_thread_customer_list), [this](ThreadCustomerData & d) { - while(d.tx_buffer.available()) + if (!d.block_tx_buffer) { - _serial.write(d.tx_buffer.read_char()); + while(d.tx_buffer.available()) + { + _serial.write(d.tx_buffer.read_char()); + } } }); } diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h index 806d731..1ea1492 100644 --- a/src/serial/SerialDispatcher.h +++ b/src/serial/SerialDispatcher.h @@ -53,6 +53,8 @@ class SerialDispatcher : public arduino::HardwareSerial using Print::write; virtual operator bool() override { return _serial; } + void block(); + void unblock(); private: @@ -69,6 +71,7 @@ class SerialDispatcher : public arduino::HardwareSerial { osThreadId_t thread_id; arduino::RingBuffer tx_buffer; + bool block_tx_buffer; } ThreadCustomerData; std::list _thread_customer_list; From 8edd5b950f4e0a8054a9553a9b40950211d4114b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 3 Sep 2021 07:19:02 +0200 Subject: [PATCH 074/108] Release v0.4.0. --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index bf9def6..1ee2332 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_ThreadsafeIO -version=0.3.0 +version=0.4.0 author=Alexander Entinger maintainer=Arduino sentence=Enable threadsafe peripheral access via pipes. From 8861451b4b7fc75cd9bbc2c20f087d1476484a26 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 3 Sep 2021 09:58:32 +0200 Subject: [PATCH 075/108] Removing code duplication in SerialDispatcher. (#13) --- src/serial/SerialDispatcher.cpp | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index e38e83b..8631981 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -122,25 +122,7 @@ void SerialDispatcher::flush() size_t SerialDispatcher::write(uint8_t const b) { - mbed::ScopedLock lock(_mutex); - - auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); - - /* If this thread hasn't registered yet - * with the SerialDispatcher via 'begin'. - */ - if (iter == std::end(_thread_customer_list)) - return 0; - - if (iter->tx_buffer.availableForStore()) - iter->tx_buffer.store_char(b); - - /* Inform the worker thread that new data has - * been written to a Serial transmit buffer. - */ - _cond.notify_one(); - - return 1; + return write(&b, 1); } size_t SerialDispatcher::write(const uint8_t * data, size_t len) From a04ae1fffe2c6c09831adb5d61eaefc45a6c4a99 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 3 Sep 2021 10:10:01 +0200 Subject: [PATCH 076/108] begin(baudrate,config) needs to be locked against multi-threaded access from the very start.! (#14) --- src/serial/SerialDispatcher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 8631981..82be5be 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -49,6 +49,8 @@ void SerialDispatcher::begin(unsigned long baudrate) void SerialDispatcher::begin(unsigned long baudrate, uint16_t config) { + mbed::ScopedLock lock(_mutex); + if (!_is_initialized) { _serial.begin(baudrate, config); @@ -57,8 +59,6 @@ void SerialDispatcher::begin(unsigned long baudrate, uint16_t config) while (!_has_tread_started) { } } - mbed::ScopedLock lock(_mutex); - /* Check if the thread calling begin is already in the list. */ osThreadId_t const current_thread_id = rtos::ThisThread::get_id(); if (findThreadCustomerDataById(rtos::ThisThread::get_id()) == std::end(_thread_customer_list)) From 0faf9abb0958ee4ce839a80fcbd60a44d30c0cbc Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 6 Sep 2021 08:48:25 +0200 Subject: [PATCH 077/108] Bugfix: Prevent access to iterator when block/unblock is called by an unregistered thread. (#15) --- src/serial/SerialDispatcher.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 82be5be..9b7e8a5 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -153,6 +153,7 @@ void SerialDispatcher::block() { mbed::ScopedLock lock(_mutex); auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + if (iter == std::end(_thread_customer_list)) return; iter->block_tx_buffer = true; } @@ -160,6 +161,7 @@ void SerialDispatcher::unblock() { mbed::ScopedLock lock(_mutex); auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + if (iter == std::end(_thread_customer_list)) return; iter->block_tx_buffer = false; _cond.notify_one(); } From 5000a5858fb771dd31eea5b9435b8675039f2c52 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 6 Sep 2021 09:24:31 +0200 Subject: [PATCH 078/108] Refactor lambda function to make the control flow more visible. (#16) --- src/serial/SerialDispatcher.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 9b7e8a5..973a292 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -187,12 +187,12 @@ void SerialDispatcher::threadFunc() std::end (_thread_customer_list), [this](ThreadCustomerData & d) { - if (!d.block_tx_buffer) + if (d.block_tx_buffer) + return; + + while(d.tx_buffer.available()) { - while(d.tx_buffer.available()) - { - _serial.write(d.tx_buffer.read_char()); - } + _serial.write(d.tx_buffer.read_char()); } }); } From 1d9bdc3dbe924a9bd1819d75372625b157fa19ed Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 9 Sep 2021 10:31:36 +0200 Subject: [PATCH 079/108] Implementation of threadsafe reading from the serial. By duplicating received data in a separate read buffer per thread. --- .../ts_serial_reader/ts_serial_reader.ino | 79 +++++++++++++++++++ src/serial/SerialDispatcher.cpp | 54 ++++++++++++- src/serial/SerialDispatcher.h | 7 +- 3 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 examples/ts_serial_reader/ts_serial_reader.ino diff --git a/examples/ts_serial_reader/ts_serial_reader.ino b/examples/ts_serial_reader/ts_serial_reader.ino new file mode 100644 index 0000000..643675f --- /dev/null +++ b/examples/ts_serial_reader/ts_serial_reader.ino @@ -0,0 +1,79 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static size_t constexpr NUM_THREADS = 5; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +void serial_thread_func(); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +static char thread_name[NUM_THREADS][32]; +#undef Serial +#ifdef ARDUINO_PORTENTA_H7_M4 + SerialDispatcher Serial(Serial1); /* No SerialUSB for Portenta H7 / M4 Core */ +#else + SerialDispatcher Serial(SerialUSB); +#endif + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + /* Fire up some threads all accessing the LSM6DSOX */ + for(size_t i = 0; i < NUM_THREADS; i++) + { + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); + t->start(serial_thread_func); + } +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +void serial_thread_func() +{ + Serial.begin(9600); + + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); + + /* Read data from the serial interface into a String. */ + String serial_msg; + while (Serial.available()) + serial_msg += (char)Serial.read(); + + /* Print thread id and chip id value to serial. */ + if (serial_msg.length()) + { + char msg[64] = {0}; + snprintf(msg, sizeof(msg), "[%05lu] %s: %s ...", millis(), rtos::ThisThread::get_name(), serial_msg.c_str()); + Serial.block(); + Serial.println(msg); + Serial.unblock(); + } + } +} diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 973a292..375c1fb 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -99,19 +99,37 @@ void SerialDispatcher::end() int SerialDispatcher::available() { mbed::ScopedLock lock(_mutex); - return _serial.available(); + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + if (iter == std::end(_thread_customer_list)) return 0; + + prepareSerialReader(iter); + handleSerialReader(); + + return iter->rx_buffer->available(); } int SerialDispatcher::peek() { mbed::ScopedLock lock(_mutex); - return _serial.peek(); + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + if (iter == std::end(_thread_customer_list)) return 0; + + prepareSerialReader(iter); + handleSerialReader(); + + return iter->rx_buffer->peek(); } int SerialDispatcher::read() { mbed::ScopedLock lock(_mutex); - return _serial.read(); + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + if (iter == std::end(_thread_customer_list)) return 0; + + prepareSerialReader(iter); + handleSerialReader(); + + return iter->rx_buffer->read_char(); } void SerialDispatcher::flush() @@ -203,4 +221,32 @@ std::list::iterator SerialDispatcher::find return std::find_if(std::begin(_thread_customer_list), std::end (_thread_customer_list), [thread_id](ThreadCustomerData const d) -> bool { return (d.thread_id == thread_id); }); -} \ No newline at end of file +} + +void SerialDispatcher::prepareSerialReader(std::list::iterator & iter) +{ + iter->is_reader = true; + if (!iter->rx_buffer) + iter->rx_buffer.reset(new arduino::RingBuffer()); +} + +void SerialDispatcher::handleSerialReader() +{ + while (_serial.available()) + { + int const c = _serial.read(); + + std::for_each(std::begin(_thread_customer_list), + std::end (_thread_customer_list), + [c](ThreadCustomerData & d) + { + if (!d.is_reader) + return; + + if (!d.rx_buffer->availableForStore()) + return; + + d.rx_buffer->store_char(c); + }); + } +} diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h index 1ea1492..a740de0 100644 --- a/src/serial/SerialDispatcher.h +++ b/src/serial/SerialDispatcher.h @@ -29,6 +29,8 @@ #include +#include + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -72,13 +74,16 @@ class SerialDispatcher : public arduino::HardwareSerial osThreadId_t thread_id; arduino::RingBuffer tx_buffer; bool block_tx_buffer; + bool is_reader; /* This thread has expressed interest to read from Serial via a call to either read() or available(). */ + mbed::SharedPtr rx_buffer; /* Only when a thread has expressed interested to read from serial a receive ringbuffer is allocated. */ } ThreadCustomerData; std::list _thread_customer_list; void threadFunc(); std::list::iterator findThreadCustomerDataById(osThreadId_t const thread_id); - + void prepareSerialReader(std::list::iterator & iter); + void handleSerialReader(); }; #endif /* SERIAL_DISPATCHER_H_ */ From d2a4fa4f353b80bf3c95b03c1342a350154178c2 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 9 Sep 2021 10:33:35 +0200 Subject: [PATCH 080/108] Eliminate dedicated status variable is_reader because checking whether or not the receive ringbuffer has been allocated contains the same status information. --- src/serial/SerialDispatcher.cpp | 3 +-- src/serial/SerialDispatcher.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 375c1fb..d1047df 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -225,7 +225,6 @@ std::list::iterator SerialDispatcher::find void SerialDispatcher::prepareSerialReader(std::list::iterator & iter) { - iter->is_reader = true; if (!iter->rx_buffer) iter->rx_buffer.reset(new arduino::RingBuffer()); } @@ -240,7 +239,7 @@ void SerialDispatcher::handleSerialReader() std::end (_thread_customer_list), [c](ThreadCustomerData & d) { - if (!d.is_reader) + if (!d.rx_buffer) return; if (!d.rx_buffer->availableForStore()) diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h index a740de0..fd7381c 100644 --- a/src/serial/SerialDispatcher.h +++ b/src/serial/SerialDispatcher.h @@ -74,7 +74,6 @@ class SerialDispatcher : public arduino::HardwareSerial osThreadId_t thread_id; arduino::RingBuffer tx_buffer; bool block_tx_buffer; - bool is_reader; /* This thread has expressed interest to read from Serial via a call to either read() or available(). */ mbed::SharedPtr rx_buffer; /* Only when a thread has expressed interested to read from serial a receive ringbuffer is allocated. */ } ThreadCustomerData; From 5ee1bb29b4c630301795d7cffaa7882b02746fa5 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 08:57:51 +0200 Subject: [PATCH 081/108] Enable the injection of a prefined message before after a message. (#19) --- .../ts_serial_prefix_suffix.ino | 83 +++++++++++++++++++ keywords.txt | 2 + src/serial/SerialDispatcher.cpp | 54 ++++++++++++ src/serial/SerialDispatcher.h | 9 ++ 4 files changed, 148 insertions(+) create mode 100644 examples/ts_serial_prefix_suffix/ts_serial_prefix_suffix.ino diff --git a/examples/ts_serial_prefix_suffix/ts_serial_prefix_suffix.ino b/examples/ts_serial_prefix_suffix/ts_serial_prefix_suffix.ino new file mode 100644 index 0000000..9ea6f9c --- /dev/null +++ b/examples/ts_serial_prefix_suffix/ts_serial_prefix_suffix.ino @@ -0,0 +1,83 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static size_t constexpr NUM_THREADS = 5; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +void serial_thread_func(); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +static char thread_name[NUM_THREADS][32]; +#undef Serial +#ifdef ARDUINO_PORTENTA_H7_M4 + SerialDispatcher Serial(Serial1); /* No SerialUSB for Portenta H7 / M4 Core */ +#else + SerialDispatcher Serial(SerialUSB); +#endif + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + /* Fire up some threads all accessing the LSM6DSOX */ + for(size_t i = 0; i < NUM_THREADS; i++) + { + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); + t->start(serial_thread_func); + } +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +void serial_thread_func() +{ + Serial.begin(9600); + + char const * thread_name = rtos::ThisThread::get_name(); + Serial.prefix([thread_name]() -> String + { + char msg[64] = {0}; + snprintf(msg, sizeof(msg), "[%05lu] %s ", millis(), thread_name); + return String(msg); + }); + Serial.suffix([]() -> String + { + return String("\r\n"); + }); + + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); + /* Print a unbroken log message including thread name and timestamp as a prefix. */ + Serial.block(); + Serial.print("My "); + Serial.print("unbroken "); + Serial.print("thread-safe "); + Serial.print("message!"); + Serial.unblock(); + } +} diff --git a/keywords.txt b/keywords.txt index 05231ff..674571a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -22,6 +22,8 @@ transfer KEYWORD2 create KEYWORD2 block KEYWORD2 unblock KEYWORD2 +prefix KEYWORD2 +suffix KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index d1047df..8e66c79 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -69,6 +69,8 @@ void SerialDispatcher::begin(unsigned long baudrate, uint16_t config) ThreadCustomerData data; data.thread_id = current_thread_id; data.block_tx_buffer = false; + data.prefix_func = nullptr; + data.suffix_func = nullptr; _thread_customer_list.push_back(data); } } @@ -184,6 +186,22 @@ void SerialDispatcher::unblock() _cond.notify_one(); } +void SerialDispatcher::prefix(PrefixInjectorCallbackFunc func) +{ + mbed::ScopedLock lock(_mutex); + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + if (iter == std::end(_thread_customer_list)) return; + iter->prefix_func = func; +} + +void SerialDispatcher::suffix(SuffixInjectorCallbackFunc func) +{ + mbed::ScopedLock lock(_mutex); + auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id()); + if (iter == std::end(_thread_customer_list)) return; + iter->suffix_func = func; +} + /************************************************************************************** * PRIVATE MEMBER FUNCTIONS **************************************************************************************/ @@ -208,10 +226,46 @@ void SerialDispatcher::threadFunc() if (d.block_tx_buffer) return; + /* Return if there's no data to be written to the + * serial interface. This statement is necessary + * because otherwise the prefix/suffix functions + * will be invoked and will be printing something, + * even though no data is actually to be printed for + * most threads. + */ + if (!d.tx_buffer.available()) + return; + + /* The prefix callback function allows the + * user to insert a custom message before + * a new message is written to the serial + * driver. This is useful e.g. for wrapping + * protocol (e.g. the 'AT' protocol) or providing + * a timestamp, a log level, ... + */ + if (d.prefix_func) + { + String const prefix_str = d.prefix_func(); + _serial.write(prefix_str.c_str()); + } + + /* Now it's time to actually write the message + * conveyed by the user via Serial.print/println. + */ while(d.tx_buffer.available()) { _serial.write(d.tx_buffer.read_char()); } + + /* Similar to the prefix function this callback + * allows the user to specify a specific message + * to be appended to each message, e.g. '\r\n'. + */ + if (d.suffix_func) + { + String const suffix_str = d.suffix_func(); + _serial.write(suffix_str.c_str()); + } }); } } diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h index fd7381c..1dd2500 100644 --- a/src/serial/SerialDispatcher.h +++ b/src/serial/SerialDispatcher.h @@ -28,6 +28,7 @@ #include #include +#include #include @@ -58,6 +59,12 @@ class SerialDispatcher : public arduino::HardwareSerial void block(); void unblock(); + typedef std::function PrefixInjectorCallbackFunc; + typedef PrefixInjectorCallbackFunc SuffixInjectorCallbackFunc; + void prefix(PrefixInjectorCallbackFunc func); + void suffix(SuffixInjectorCallbackFunc func); + + private: bool _is_initialized; @@ -75,6 +82,8 @@ class SerialDispatcher : public arduino::HardwareSerial arduino::RingBuffer tx_buffer; bool block_tx_buffer; mbed::SharedPtr rx_buffer; /* Only when a thread has expressed interested to read from serial a receive ringbuffer is allocated. */ + PrefixInjectorCallbackFunc prefix_func; + SuffixInjectorCallbackFunc suffix_func; } ThreadCustomerData; std::list _thread_customer_list; From b4e646229c0536a916bf5d7f7b5655234165badf Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 09:05:17 +0200 Subject: [PATCH 082/108] ts_spi -> Threadsafe_SPI --- examples/{ts_spi/ts_spi.ino => Threadsafe_SPI/Threadsafe_SPI.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ts_spi/ts_spi.ino => Threadsafe_SPI/Threadsafe_SPI.ino} (100%) diff --git a/examples/ts_spi/ts_spi.ino b/examples/Threadsafe_SPI/Threadsafe_SPI.ino similarity index 100% rename from examples/ts_spi/ts_spi.ino rename to examples/Threadsafe_SPI/Threadsafe_SPI.ino From 93ca11c34589a07cb41b74ad0734274f2d5df0ba Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 09:05:53 +0200 Subject: [PATCH 083/108] ts_wire -> Threadsafe_Wire --- .../{ts_wire/ts_wire.ino => Threadsafe_Wire/Threadsafe_Wire.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ts_wire/ts_wire.ino => Threadsafe_Wire/Threadsafe_Wire.ino} (100%) diff --git a/examples/ts_wire/ts_wire.ino b/examples/Threadsafe_Wire/Threadsafe_Wire.ino similarity index 100% rename from examples/ts_wire/ts_wire.ino rename to examples/Threadsafe_Wire/Threadsafe_Wire.ino From 39cdcea4287886f87105a13f38e5e5765f61ea59 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 09:06:51 +0200 Subject: [PATCH 084/108] ts_serial -> Threadsafe_Serial_Writer --- .../Threadsafe_Serial_Writer.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ts_serial/ts_serial.ino => Threadsafe_Serial_Writer/Threadsafe_Serial_Writer.ino} (100%) diff --git a/examples/ts_serial/ts_serial.ino b/examples/Threadsafe_Serial_Writer/Threadsafe_Serial_Writer.ino similarity index 100% rename from examples/ts_serial/ts_serial.ino rename to examples/Threadsafe_Serial_Writer/Threadsafe_Serial_Writer.ino From 992f3153ea4aa2b25019d63eff582df60d693c17 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 09:07:24 +0200 Subject: [PATCH 085/108] ts_serial_reader -> Threadsafe_Serial_Reader --- .../Threadsafe_Serial_Reader.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ts_serial_reader/ts_serial_reader.ino => Threadsafe_Serial_Reader/Threadsafe_Serial_Reader.ino} (100%) diff --git a/examples/ts_serial_reader/ts_serial_reader.ino b/examples/Threadsafe_Serial_Reader/Threadsafe_Serial_Reader.ino similarity index 100% rename from examples/ts_serial_reader/ts_serial_reader.ino rename to examples/Threadsafe_Serial_Reader/Threadsafe_Serial_Reader.ino From 3893f15f131fb0d5a57b29ea46849f9738b76bfd Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 09:08:15 +0200 Subject: [PATCH 086/108] ts_serial_prefix_suffix -> Threadsafe_Serial_Prefix_Suffix --- .../Threadsafe_Serial_Prefix_Suffix.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ts_serial_prefix_suffix/ts_serial_prefix_suffix.ino => Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino} (100%) diff --git a/examples/ts_serial_prefix_suffix/ts_serial_prefix_suffix.ino b/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino similarity index 100% rename from examples/ts_serial_prefix_suffix/ts_serial_prefix_suffix.ino rename to examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino From 5ac6fa77651998d81006f477ec1e7afdd28b3d3e Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 09:08:56 +0200 Subject: [PATCH 087/108] Release v0.5.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 1ee2332..6d37f2e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_ThreadsafeIO -version=0.4.0 +version=0.5.0 author=Alexander Entinger maintainer=Arduino sentence=Enable threadsafe peripheral access via pipes. From aa64ae201d3eb44a79066f2c3ed16e8557304340 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 17 Sep 2021 11:02:57 +0200 Subject: [PATCH 088/108] Provide message to be written to prefix/suffix callbacks: * Provide message to prefix function. * Provide prefix and message to suffix function. --- .../Threadsafe_Serial_Prefix_Suffix.ino | 4 +-- src/serial/SerialDispatcher.cpp | 35 ++++++++++--------- src/serial/SerialDispatcher.h | 4 +-- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino b/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino index 9ea6f9c..3aa9eb2 100644 --- a/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino +++ b/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino @@ -57,13 +57,13 @@ void serial_thread_func() Serial.begin(9600); char const * thread_name = rtos::ThisThread::get_name(); - Serial.prefix([thread_name]() -> String + Serial.prefix([thread_name](String const & /* msg */) -> String { char msg[64] = {0}; snprintf(msg, sizeof(msg), "[%05lu] %s ", millis(), thread_name); return String(msg); }); - Serial.suffix([]() -> String + Serial.suffix([](String const & /* prefix */, String const & /* msg */) -> String { return String("\r\n"); }); diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 8e66c79..368c60c 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -236,6 +236,14 @@ void SerialDispatcher::threadFunc() if (!d.tx_buffer.available()) return; + /* Retrieve all data stored in the transmit ringbuffer + * and store it into a String for usage by both suffix + * prefix callback functions. + */ + String msg; + while(d.tx_buffer.available()) + msg += static_cast(d.tx_buffer.read_char()); + /* The prefix callback function allows the * user to insert a custom message before * a new message is written to the serial @@ -243,29 +251,24 @@ void SerialDispatcher::threadFunc() * protocol (e.g. the 'AT' protocol) or providing * a timestamp, a log level, ... */ + String prefix; if (d.prefix_func) - { - String const prefix_str = d.prefix_func(); - _serial.write(prefix_str.c_str()); - } - - /* Now it's time to actually write the message - * conveyed by the user via Serial.print/println. - */ - while(d.tx_buffer.available()) - { - _serial.write(d.tx_buffer.read_char()); - } + prefix = d.prefix_func(msg); /* Similar to the prefix function this callback * allows the user to specify a specific message * to be appended to each message, e.g. '\r\n'. */ + String suffix; if (d.suffix_func) - { - String const suffix_str = d.suffix_func(); - _serial.write(suffix_str.c_str()); - } + suffix = d.suffix_func(prefix, msg); + + /* Now it's time to actually write the message + * conveyed by the user via Serial.print/println. + */ + _serial.write(prefix.c_str()); + _serial.write(msg.c_str()); + _serial.write(suffix.c_str()); }); } } diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h index 1dd2500..6ccf122 100644 --- a/src/serial/SerialDispatcher.h +++ b/src/serial/SerialDispatcher.h @@ -59,8 +59,8 @@ class SerialDispatcher : public arduino::HardwareSerial void block(); void unblock(); - typedef std::function PrefixInjectorCallbackFunc; - typedef PrefixInjectorCallbackFunc SuffixInjectorCallbackFunc; + typedef std::function PrefixInjectorCallbackFunc; + typedef std::function SuffixInjectorCallbackFunc; void prefix(PrefixInjectorCallbackFunc func); void suffix(SuffixInjectorCallbackFunc func); From 760e4b8ffd5069285b5c4ed36aaefac817c1eb07 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 21 Sep 2021 09:30:30 +0200 Subject: [PATCH 089/108] Rewrite suffix/prefix example to use for NMEA encoding of a message. --- .../Threadsafe_Serial_Prefix_Suffix.ino | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino b/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino index 3aa9eb2..1ffd789 100644 --- a/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino +++ b/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino @@ -56,28 +56,50 @@ void serial_thread_func() { Serial.begin(9600); - char const * thread_name = rtos::ThisThread::get_name(); - Serial.prefix([thread_name](String const & /* msg */) -> String + Serial.prefix([](String const & /* msg */) -> String { - char msg[64] = {0}; - snprintf(msg, sizeof(msg), "[%05lu] %s ", millis(), thread_name); - return String(msg); + return String("$"); }); - Serial.suffix([](String const & /* prefix */, String const & /* msg */) -> String + Serial.suffix([](String const & prefix, String const & msg) -> String { - return String("\r\n"); + /* NMEA checksum is calculated over the complete message + * starting with '$' and ending with the end of the message. + */ + byte checksum = 0; + std::for_each(msg.c_str(), + msg.c_str() + msg.length(), + [&checksum](char const c) + { + checksum ^= static_cast(c); + }); + /* Assemble the footer of the NMEA message. */ + char footer[16] = {0}; + snprintf(footer, sizeof(footer), "*%02X\r\n", checksum); + return String(footer); }); for(;;) { /* Sleep between 5 and 500 ms */ rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); - /* Print a unbroken log message including thread name and timestamp as a prefix. */ + /* Print a fake NMEA GPRMC message: + * $GPRMC,062101.714,A,5001.869,N,01912.114,E,955535.7,116.2,290520,000.0,W*45\r\n + */ Serial.block(); - Serial.print("My "); - Serial.print("unbroken "); - Serial.print("thread-safe "); - Serial.print("message!"); + + Serial.print("GPRMC,"); + Serial.print(millis()); + Serial.print(",A,"); + Serial.print("5001.869,"); + Serial.print("N,"); + Serial.print("01912.114,"); + Serial.print("E,"); + Serial.print("955535.7,"); + Serial.print("116.2,"); + Serial.print("290520,"); + Serial.print("000.0,"); + Serial.print("W"); + Serial.unblock(); } } From 4b02a9d4907325de11349f017266375672e53b9d Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 21 Sep 2021 09:33:02 +0200 Subject: [PATCH 090/108] We need a bigger serial transmit ringbuffer, if we are going to store messages there before writing them to the actual serial interface. --- src/serial/SerialDispatcher.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h index 6ccf122..d9a50f9 100644 --- a/src/serial/SerialDispatcher.h +++ b/src/serial/SerialDispatcher.h @@ -76,10 +76,13 @@ class SerialDispatcher : public arduino::HardwareSerial bool _has_tread_started; bool _terminate_thread; + static int constexpr THREADSAFE_SERIAL_TRANSMIT_RINGBUFFER_SIZE = 128; + typedef arduino::RingBufferN SerialTransmitRingbuffer; + typedef struct { osThreadId_t thread_id; - arduino::RingBuffer tx_buffer; + SerialTransmitRingbuffer tx_buffer; bool block_tx_buffer; mbed::SharedPtr rx_buffer; /* Only when a thread has expressed interested to read from serial a receive ringbuffer is allocated. */ PrefixInjectorCallbackFunc prefix_func; From d164c26d410fee194819d19dd62667975cc57c88 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 21 Sep 2021 09:35:27 +0200 Subject: [PATCH 091/108] Replace inline-lamda-implementation with regular function pointers. --- .../Threadsafe_Serial_Prefix_Suffix.ino | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino b/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino index 1ffd789..e6d7549 100644 --- a/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino +++ b/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino @@ -52,36 +52,41 @@ void loop() * FUNCTION DEFINITION **************************************************************************************/ -void serial_thread_func() +String nmea_message_prefix(String const & /* msg */) { - Serial.begin(9600); + return String("$"); +} - Serial.prefix([](String const & /* msg */) -> String - { - return String("$"); - }); - Serial.suffix([](String const & prefix, String const & msg) -> String +String nmea_message_suffix(String const & prefix, String const & msg) +{ + /* NMEA checksum is calculated over the complete message + * starting with '$' and ending with the end of the message. + */ + byte checksum = 0; + std::for_each(msg.c_str(), + msg.c_str() + msg.length(), + [&checksum](char const c) { - /* NMEA checksum is calculated over the complete message - * starting with '$' and ending with the end of the message. - */ - byte checksum = 0; - std::for_each(msg.c_str(), - msg.c_str() + msg.length(), - [&checksum](char const c) - { - checksum ^= static_cast(c); - }); - /* Assemble the footer of the NMEA message. */ - char footer[16] = {0}; - snprintf(footer, sizeof(footer), "*%02X\r\n", checksum); - return String(footer); + checksum ^= static_cast(c); }); + /* Assemble the footer of the NMEA message. */ + char footer[16] = {0}; + snprintf(footer, sizeof(footer), "*%02X\r\n", checksum); + return String(footer); +} + +void serial_thread_func() +{ + Serial.begin(9600); + + Serial.prefix(nmea_message_prefix); + Serial.suffix(nmea_message_suffix); for(;;) { /* Sleep between 5 and 500 ms */ rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); + /* Print a fake NMEA GPRMC message: * $GPRMC,062101.714,A,5001.869,N,01912.114,E,955535.7,116.2,290520,000.0,W*45\r\n */ From e55cdb9212ca7cab307940553af94336696339e5 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 21 Sep 2021 09:36:34 +0200 Subject: [PATCH 092/108] Rename example for better clarity about use-case. --- .../Threadsafe_Serial_ProtocolWrapping.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino => Threadsafe_Serial_ProtocolWrapping/Threadsafe_Serial_ProtocolWrapping.ino} (100%) diff --git a/examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino b/examples/Threadsafe_Serial_ProtocolWrapping/Threadsafe_Serial_ProtocolWrapping.ino similarity index 100% rename from examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino rename to examples/Threadsafe_Serial_ProtocolWrapping/Threadsafe_Serial_ProtocolWrapping.ino From 1b152ac0880db76f8f0d20c2709609086b6e47d7 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 22 Sep 2021 09:03:08 +0200 Subject: [PATCH 093/108] Allow registration of global prefix/suffix callbacks which take 2nd priority over per-thread-callbacks. --- src/serial/SerialDispatcher.cpp | 26 ++++++++++++++++++++++++++ src/serial/SerialDispatcher.h | 5 +++++ 2 files changed, 31 insertions(+) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index 368c60c..b6f0434 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -34,6 +34,8 @@ SerialDispatcher::SerialDispatcher(arduino::HardwareSerial & serial) , _thread(osPriorityRealtime, 4096, nullptr, "SerialDispatcher") , _has_tread_started{false} , _terminate_thread{false} +, _global_prefix_callback{nullptr} +, _global_suffix_callback{nullptr} { } @@ -202,6 +204,18 @@ void SerialDispatcher::suffix(SuffixInjectorCallbackFunc func) iter->suffix_func = func; } +void SerialDispatcher::global_prefix(PrefixInjectorCallbackFunc func) +{ + mbed::ScopedLock lock(_mutex); + _global_prefix_callback = func; +} + +void SerialDispatcher::global_suffix(SuffixInjectorCallbackFunc func) +{ + mbed::ScopedLock lock(_mutex); + _global_suffix_callback = func; +} + /************************************************************************************** * PRIVATE MEMBER FUNCTIONS **************************************************************************************/ @@ -254,6 +268,12 @@ void SerialDispatcher::threadFunc() String prefix; if (d.prefix_func) prefix = d.prefix_func(msg); + /* A prefix callback function defined per thread + * takes precendence over a globally defined prefix + * callback function. + */ + else if (_global_prefix_callback) + prefix = _global_prefix_callback(msg); /* Similar to the prefix function this callback * allows the user to specify a specific message @@ -262,6 +282,12 @@ void SerialDispatcher::threadFunc() String suffix; if (d.suffix_func) suffix = d.suffix_func(prefix, msg); + /* A suffix callback function defined per thread + * takes precendence over a globally defined suffix + * callback function. + */ + else if (_global_suffix_callback) + suffix = _global_suffix_callback(prefix, msg); /* Now it's time to actually write the message * conveyed by the user via Serial.print/println. diff --git a/src/serial/SerialDispatcher.h b/src/serial/SerialDispatcher.h index d9a50f9..ca17793 100644 --- a/src/serial/SerialDispatcher.h +++ b/src/serial/SerialDispatcher.h @@ -63,6 +63,8 @@ class SerialDispatcher : public arduino::HardwareSerial typedef std::function SuffixInjectorCallbackFunc; void prefix(PrefixInjectorCallbackFunc func); void suffix(SuffixInjectorCallbackFunc func); + void global_prefix(PrefixInjectorCallbackFunc func); + void global_suffix(SuffixInjectorCallbackFunc func); private: @@ -76,6 +78,9 @@ class SerialDispatcher : public arduino::HardwareSerial bool _has_tread_started; bool _terminate_thread; + PrefixInjectorCallbackFunc _global_prefix_callback; + SuffixInjectorCallbackFunc _global_suffix_callback; + static int constexpr THREADSAFE_SERIAL_TRANSMIT_RINGBUFFER_SIZE = 128; typedef arduino::RingBufferN SerialTransmitRingbuffer; From 206aa053c8c97aeae4dc572dec976b05d407ba03 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 22 Sep 2021 09:03:41 +0200 Subject: [PATCH 094/108] Example Threadsafe_Serial_GlobalPrefixSuffix demonstrates how to utilize such global callbacks. --- .../Threadsafe_Serial_GlobalPrefixSuffix.ino | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 examples/Threadsafe_Serial_GlobalPrefixSuffix/Threadsafe_Serial_GlobalPrefixSuffix.ino diff --git a/examples/Threadsafe_Serial_GlobalPrefixSuffix/Threadsafe_Serial_GlobalPrefixSuffix.ino b/examples/Threadsafe_Serial_GlobalPrefixSuffix/Threadsafe_Serial_GlobalPrefixSuffix.ino new file mode 100644 index 0000000..a22fe04 --- /dev/null +++ b/examples/Threadsafe_Serial_GlobalPrefixSuffix/Threadsafe_Serial_GlobalPrefixSuffix.ino @@ -0,0 +1,87 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static size_t constexpr NUM_THREADS = 5; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +String serial_log_message_prefix(String const & /* msg */); +String serial_log_message_suffix(String const & prefix, String const & msg); +void serial_thread_func(); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +static char thread_name[NUM_THREADS][32]; +#undef Serial +#ifdef ARDUINO_PORTENTA_H7_M4 + SerialDispatcher Serial(Serial1); /* No SerialUSB for Portenta H7 / M4 Core */ +#else + SerialDispatcher Serial(SerialUSB); +#endif + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + Serial.global_prefix(serial_log_message_prefix); + Serial.global_suffix(serial_log_message_suffix); + + /* Fire up some threads all accessing the LSM6DSOX */ + for(size_t i = 0; i < NUM_THREADS; i++) + { + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); + t->start(serial_thread_func); + } +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +String serial_log_message_prefix(String const & /* msg */) +{ + char msg[32] = {0}; + snprintf(msg, sizeof(msg), "[%05lu] ", millis()); + return String(msg); +} + +String serial_log_message_suffix(String const & prefix, String const & msg) +{ + return String("\r\n"); +} + +void serial_thread_func() +{ + Serial.begin(9600); + + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); + /* Print a unbroken log message including thread name and timestamp as a prefix. */ + Serial.block(); + Serial.print(rtos::ThisThread::get_name()); + Serial.print(": "); + Serial.print("Lorem ipsum ..."); + Serial.unblock(); + } +} From b3b39d5eb999a375ad84e17a5b231f81bf9c53bd Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 22 Sep 2021 09:04:02 +0200 Subject: [PATCH 095/108] Adding global_prefix/suffix as keywords for accurate syntax highlighting. --- keywords.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keywords.txt b/keywords.txt index 674571a..eef8178 100644 --- a/keywords.txt +++ b/keywords.txt @@ -24,6 +24,8 @@ block KEYWORD2 unblock KEYWORD2 prefix KEYWORD2 suffix KEYWORD2 +global_prefix KEYWORD2 +global_suffix KEYWORD2 ####################################### # Constants (LITERAL1) From 10348abffd12aba6f9add1646a465b3830672400 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 22 Sep 2021 09:09:24 +0200 Subject: [PATCH 096/108] Fix spelling of incorrectly spelled word 'precedence' --- src/serial/SerialDispatcher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serial/SerialDispatcher.cpp b/src/serial/SerialDispatcher.cpp index b6f0434..7fb6dea 100644 --- a/src/serial/SerialDispatcher.cpp +++ b/src/serial/SerialDispatcher.cpp @@ -269,7 +269,7 @@ void SerialDispatcher::threadFunc() if (d.prefix_func) prefix = d.prefix_func(msg); /* A prefix callback function defined per thread - * takes precendence over a globally defined prefix + * takes precedence over a globally defined prefix * callback function. */ else if (_global_prefix_callback) @@ -283,7 +283,7 @@ void SerialDispatcher::threadFunc() if (d.suffix_func) suffix = d.suffix_func(prefix, msg); /* A suffix callback function defined per thread - * takes precendence over a globally defined suffix + * takes precedence over a globally defined suffix * callback function. */ else if (_global_suffix_callback) From e3e793fbe33561fa51b6fde9a472788299105605 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 09:35:09 +0200 Subject: [PATCH 097/108] Bugfix: Only perform i2c write if the write buffer is > 0 (#28) --- src/wire/WireDispatcher.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/wire/WireDispatcher.cpp b/src/wire/WireDispatcher.cpp index 07822a5..9a8a664 100644 --- a/src/wire/WireDispatcher.cpp +++ b/src/wire/WireDispatcher.cpp @@ -136,19 +136,22 @@ void WireDispatcher::processWireIoRequest(WireIoTransaction * wire_io_transactio IoResponse io_response = wire_io_transaction->rsp; WireBusDeviceConfig * config = wire_io_transaction->config; - config->wire().beginTransmission(config->slave_addr()); - - size_t bytes_written = 0; - for (; bytes_written < io_request->bytes_to_write; bytes_written++) + if (io_request->bytes_to_write > 0) { - config->wire().write(io_request->write_buf[bytes_written]); - } - io_response->bytes_written = bytes_written; + config->wire().beginTransmission(config->slave_addr()); + + size_t bytes_written = 0; + for (; bytes_written < io_request->bytes_to_write; bytes_written++) + { + config->wire().write(io_request->write_buf[bytes_written]); + } + io_response->bytes_written = bytes_written; - if (config->restart() && (io_request->bytes_to_read > 0)) - config->wire().endTransmission(false /* stop */); - else - config->wire().endTransmission(true /* stop */); + if (config->restart() && (io_request->bytes_to_read > 0)) + config->wire().endTransmission(false /* stop */); + else + config->wire().endTransmission(true /* stop */); + } if (io_request->bytes_to_read > 0) { From 26b562b68600c9c045ad4dbdfa85b91a03e429a0 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 06:50:02 +0200 Subject: [PATCH 098/108] Implement write_then_read style API for threadsafe Wire. --- .../Threadsafe_Wire_BusIO.ino | 78 +++++++++++++++++++ keywords.txt | 2 + src/BusDevice.cpp | 5 ++ src/BusDevice.h | 4 + src/wire/WireBusDevice.h | 17 ++++ src/wire/WireDispatcher.h | 2 + 6 files changed, 108 insertions(+) create mode 100644 examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino diff --git a/examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino b/examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino new file mode 100644 index 0000000..16ebe1b --- /dev/null +++ b/examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino @@ -0,0 +1,78 @@ + /************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static byte constexpr LSM6DSOX_ADDRESS = 0x6A; +static byte constexpr LSM6DSOX_WHO_AM_I_REG = 0x0F; + +static size_t constexpr NUM_THREADS = 20; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +byte lsm6dsox_read_reg(byte const reg_addr); +void lsm6dsox_thread_func(); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +BusDevice lsm6dsox(Wire, LSM6DSOX_ADDRESS); + +static char thread_name[NUM_THREADS][32]; + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + Serial.begin(9600); + while (!Serial) { } + + /* Fire up some threads all accessing the LSM6DSOX */ + for(size_t i = 0; i < NUM_THREADS; i++) + { + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); + t->start(lsm6dsox_thread_func); + } +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +byte lsm6dsox_read_reg(byte const reg_addr) +{ + byte read_buf = 0; + lsm6dsox.wire().write_then_read(®_addr, 1, &read_buf, 1); + return read_buf; +} + +void lsm6dsox_thread_func() +{ + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); + /* Try to read some data from the LSM6DSOX. */ + byte const who_am_i = lsm6dsox_read_reg(LSM6DSOX_WHO_AM_I_REG); + /* Print thread id and chip id value to serial. */ + char msg[64] = {0}; + snprintf(msg, sizeof(msg), "%s: LSM6DSOX[WHO_AM_I] = 0x%X", rtos::ThisThread::get_name(), who_am_i); + Serial.println(msg); + } +} diff --git a/keywords.txt b/keywords.txt index 674571a..1bfdeeb 100644 --- a/keywords.txt +++ b/keywords.txt @@ -24,6 +24,8 @@ block KEYWORD2 unblock KEYWORD2 prefix KEYWORD2 suffix KEYWORD2 +wire KEYWORD2 +write_then_read KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/BusDevice.cpp b/src/BusDevice.cpp index 8bd8276..96e98ff 100644 --- a/src/BusDevice.cpp +++ b/src/BusDevice.cpp @@ -109,3 +109,8 @@ IoResponse BusDevice::transfer(IoRequest & req) { return _dev->transfer(req); } + +WireBusDevice & BusDevice::wire() +{ + return *reinterpret_cast(_dev.get()); +} diff --git a/src/BusDevice.h b/src/BusDevice.h index 31f4b0d..7d025c2 100644 --- a/src/BusDevice.h +++ b/src/BusDevice.h @@ -38,6 +38,7 @@ namespace arduino } class BusDevice; +class WireBusDevice; /************************************************************************************** * CLASS DECLARATION @@ -79,6 +80,9 @@ class BusDevice IoResponse transfer(IoRequest & req); + WireBusDevice & wire(); + + private: mbed::SharedPtr _dev; diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index d3ca3e0..cb8a202 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -50,6 +50,23 @@ class WireBusDevice : public BusDeviceBase } + bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop = false) + { + /* Copy the Wire parameters from the device and modify only those + * which can be modified via the parameters of this function. + */ + bool const restart = !stop; + WireBusDeviceConfig config(_config.wire(), _config.slave_addr(), restart, _config.stop()); + /* Fire off the IO request and await its response. */ + IoRequest req(write_buffer, write_len, read_buffer, read_len); + IoResponse rsp = WireDispatcher::instance().dispatch(&req, &config); + rsp->wait(); + /* TODO: Introduce error codes within the IoResponse and evaluate + * them here. + */ + return true; + } + private: WireBusDeviceConfig _config; diff --git a/src/wire/WireDispatcher.h b/src/wire/WireDispatcher.h index d75a75d..87fc88f 100644 --- a/src/wire/WireDispatcher.h +++ b/src/wire/WireDispatcher.h @@ -43,8 +43,10 @@ class WireDispatcher static WireDispatcher & instance(); static void destroy(); + IoResponse dispatch(IoRequest * req, WireBusDeviceConfig * config); + private: static WireDispatcher * _p_instance; From 2d1a6892373d3551ee8181ee06ebfb3a67300a3a Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 06:52:56 +0200 Subject: [PATCH 099/108] Move implementation from WireBusDevice.h to WireBusDevice.cpp --- src/wire/WireBusDevice.cpp | 59 ++++++++++++++++++++++++++++++++++++++ src/wire/WireBusDevice.h | 29 +++---------------- 2 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 src/wire/WireBusDevice.cpp diff --git a/src/wire/WireBusDevice.cpp b/src/wire/WireBusDevice.cpp new file mode 100644 index 0000000..6f43dd8 --- /dev/null +++ b/src/wire/WireBusDevice.cpp @@ -0,0 +1,59 @@ +/* + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "WireBusDevice.h" + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +WireBusDevice::WireBusDevice(WireBusDeviceConfig const & config) +: _config{config} +{ + +} + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +IoResponse WireBusDevice::transfer(IoRequest & req) +{ + return WireDispatcher::instance().dispatch(&req, &_config); +} + +bool WireBusDevice::write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop) +{ + /* Copy the Wire parameters from the device and modify only those + * which can be modified via the parameters of this function. + */ + bool const restart = !stop; + WireBusDeviceConfig config(_config.wire(), _config.slave_addr(), restart, _config.stop()); + /* Fire off the IO request and await its response. */ + IoRequest req(write_buffer, write_len, read_buffer, read_len); + IoResponse rsp = WireDispatcher::instance().dispatch(&req, &config); + rsp->wait(); + /* TODO: Introduce error codes within the IoResponse and evaluate + * them here. + */ + return true; +} diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index cb8a202..afc0716 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -39,33 +39,12 @@ class WireBusDevice : public BusDeviceBase { public: - WireBusDevice(WireBusDeviceConfig const & config) - : _config{config} - { } + WireBusDevice(WireBusDeviceConfig const & config); + virtual ~WireBusDevice() { } + virtual IoResponse transfer(IoRequest & req) override; - virtual IoResponse transfer(IoRequest & req) override - { - return WireDispatcher::instance().dispatch(&req, &_config); - } - - - bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop = false) - { - /* Copy the Wire parameters from the device and modify only those - * which can be modified via the parameters of this function. - */ - bool const restart = !stop; - WireBusDeviceConfig config(_config.wire(), _config.slave_addr(), restart, _config.stop()); - /* Fire off the IO request and await its response. */ - IoRequest req(write_buffer, write_len, read_buffer, read_len); - IoResponse rsp = WireDispatcher::instance().dispatch(&req, &config); - rsp->wait(); - /* TODO: Introduce error codes within the IoResponse and evaluate - * them here. - */ - return true; - } + bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop = false); private: From d492b23f4ebbf669ec6bf10486f8a60a7a9ec8cf Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 09:36:36 +0200 Subject: [PATCH 100/108] Implement Adafruit_BusIO-style read/write methods for I2C. --- src/wire/WireBusDevice.cpp | 19 +++++++++++++++++++ src/wire/WireBusDevice.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/wire/WireBusDevice.cpp b/src/wire/WireBusDevice.cpp index 6f43dd8..28d1821 100644 --- a/src/wire/WireBusDevice.cpp +++ b/src/wire/WireBusDevice.cpp @@ -41,6 +41,25 @@ IoResponse WireBusDevice::transfer(IoRequest & req) return WireDispatcher::instance().dispatch(&req, &_config); } +bool WireBusDevice::read(uint8_t * buffer, size_t len, bool stop) +{ + WireBusDeviceConfig config(_config.wire(), _config.slave_addr(), _config.restart(), stop); + IoRequest req(nullptr, 0, buffer, len); + IoResponse rsp = WireDispatcher::instance().dispatch(&req, &config); + rsp->wait(); + return true; +} + +bool WireBusDevice::write(const uint8_t * buffer, size_t len, bool stop) +{ + bool const restart = !stop; + WireBusDeviceConfig config(_config.wire(), _config.slave_addr(), restart, _config.stop()); + IoRequest req(buffer, len, nullptr, 0); + IoResponse rsp = WireDispatcher::instance().dispatch(&req, &config); + rsp->wait(); + return true; +} + bool WireBusDevice::write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop) { /* Copy the Wire parameters from the device and modify only those diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index afc0716..091b565 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -44,6 +44,8 @@ class WireBusDevice : public BusDeviceBase virtual IoResponse transfer(IoRequest & req) override; + bool read(uint8_t * buffer, size_t len, bool stop = true); + bool write(const uint8_t * buffer, size_t len, bool stop = true); bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop = false); private: From ec2eb39491cc4aa9500215561bb6df523060bc51 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 09:52:14 +0200 Subject: [PATCH 101/108] Move implementation from SpiBusDevice.h to SpiBusDevice.cpp --- src/spi/SpiBusDevice.cpp | 44 ++++++++++++++++++++++++++++++++++++++ src/spi/SpiBusDevice.h | 14 +++--------- src/wire/WireBusDevice.cpp | 2 ++ src/wire/WireBusDevice.h | 4 ---- 4 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 src/spi/SpiBusDevice.cpp diff --git a/src/spi/SpiBusDevice.cpp b/src/spi/SpiBusDevice.cpp new file mode 100644 index 0000000..6e11e05 --- /dev/null +++ b/src/spi/SpiBusDevice.cpp @@ -0,0 +1,44 @@ +/* + * This file is part of the Arduino_ThreadsafeIO library. + * Copyright (c) 2021 Arduino SA. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "SpiBusDevice.h" + +#include "SpiDispatcher.h" + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +SpiBusDevice::SpiBusDevice(SpiBusDeviceConfig const & config) +: _config{config} +{ + +} + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +IoResponse SpiBusDevice::transfer(IoRequest & req) +{ + return SpiDispatcher::instance().dispatch(&req, &_config); +} diff --git a/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h index f2ea7d2..a9ce264 100644 --- a/src/spi/SpiBusDevice.h +++ b/src/spi/SpiBusDevice.h @@ -23,12 +23,8 @@ * INCLUDE **************************************************************************************/ -#include -#include - #include "../BusDevice.h" -#include "SpiDispatcher.h" #include "SpiBusDeviceConfig.h" /************************************************************************************** @@ -39,15 +35,11 @@ class SpiBusDevice : public BusDeviceBase { public: - SpiBusDevice(SpiBusDeviceConfig const & config) - : _config{config} - { } + SpiBusDevice(SpiBusDeviceConfig const & config); + virtual ~SpiBusDevice() { } - virtual IoResponse transfer(IoRequest & req) override - { - return SpiDispatcher::instance().dispatch(&req, &_config); - } + virtual IoResponse transfer(IoRequest & req) override; private: diff --git a/src/wire/WireBusDevice.cpp b/src/wire/WireBusDevice.cpp index 28d1821..915b257 100644 --- a/src/wire/WireBusDevice.cpp +++ b/src/wire/WireBusDevice.cpp @@ -22,6 +22,8 @@ #include "WireBusDevice.h" +#include "WireDispatcher.h" + /************************************************************************************** * CTOR/DTOR **************************************************************************************/ diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index 091b565..f3b084f 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -23,12 +23,8 @@ * INCLUDE **************************************************************************************/ -#include -#include - #include "../BusDevice.h" -#include "WireDispatcher.h" #include "WireBusDeviceConfig.h" /************************************************************************************** From 58b6fb94d34b194d65971c9901ca0e94c0e81a2f Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 10:19:15 +0200 Subject: [PATCH 102/108] Implement Adafruit_BusIO-style write_then_read method for SPI. --- .../Threadsafe_SPI_BusIO.ino | 89 +++++++++++++++++++ keywords.txt | 3 + src/BusDevice.cpp | 5 ++ src/BusDevice.h | 2 + src/spi/SpiBusDevice.cpp | 9 ++ src/spi/SpiBusDevice.h | 5 +- src/spi/SpiBusDeviceConfig.h | 2 + src/wire/WireBusDevice.h | 3 + 8 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino diff --git a/examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino b/examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino new file mode 100644 index 0000000..e40f7ff --- /dev/null +++ b/examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino @@ -0,0 +1,89 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static int const BMP388_CS_PIN = 2; +static int const BMP388_INT_PIN = 6; +static byte const BMP388_CHIP_ID_REG_ADDR = 0x00; + +static size_t constexpr NUM_THREADS = 20; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +byte bmp388_read_reg(byte const reg_addr); +void bmp388_thread_func(); + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +BusDevice bmp388(SPI, BMP388_CS_PIN, 1000000, MSBFIRST, SPI_MODE0); + +static char thread_name[NUM_THREADS][32]; + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + Serial.begin(9600); + while (!Serial) { } + + pinMode(BMP388_CS_PIN, OUTPUT); + digitalWrite(BMP388_CS_PIN, HIGH); + + for(size_t i = 0; i < NUM_THREADS; i++) + { + snprintf(thread_name[i], sizeof(thread_name[i]), "Thread #%02d", i); + rtos::Thread * t = new rtos::Thread(osPriorityNormal, OS_STACK_SIZE, nullptr, thread_name[i]); + t->start(bmp388_thread_func); + } +} + +void loop() +{ + +} + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +byte bmp388_read_reg(byte const reg_addr) +{ + byte const write_buf[3] = + { + static_cast(0x80 | reg_addr), /* REG_ADDR, if MSBit is set -> READ access */ + 0, /* Dummy byte. */ + 0 /* REG_VAL is output on SDO */ + }; + byte read_buf[3] = {0}; + + bmp388.spi().write_then_read(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); + + return read_buf[2]; +} + +void bmp388_thread_func() +{ + for(;;) + { + /* Sleep between 5 and 500 ms */ + rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); + /* Try to read some data from the BMP3888. */ + byte const chip_id = bmp388_read_reg(BMP388_CHIP_ID_REG_ADDR); + /* Print thread id and chip id value to serial. */ + char msg[64] = {0}; + snprintf(msg, sizeof(msg), "%s: Chip ID = 0x%X", rtos::ThisThread::get_name(), chip_id); + Serial.println(msg); + } +} diff --git a/keywords.txt b/keywords.txt index 1bfdeeb..ccc3ab2 100644 --- a/keywords.txt +++ b/keywords.txt @@ -24,7 +24,10 @@ block KEYWORD2 unblock KEYWORD2 prefix KEYWORD2 suffix KEYWORD2 +spi KEYWORD2 wire KEYWORD2 +read KEYWORD2 +write KEYWORD2 write_then_read KEYWORD2 ####################################### diff --git a/src/BusDevice.cpp b/src/BusDevice.cpp index 96e98ff..6278aa0 100644 --- a/src/BusDevice.cpp +++ b/src/BusDevice.cpp @@ -110,6 +110,11 @@ IoResponse BusDevice::transfer(IoRequest & req) return _dev->transfer(req); } +SpiBusDevice & BusDevice::spi() +{ + return *reinterpret_cast(_dev.get()); +} + WireBusDevice & BusDevice::wire() { return *reinterpret_cast(_dev.get()); diff --git a/src/BusDevice.h b/src/BusDevice.h index 7d025c2..3767a51 100644 --- a/src/BusDevice.h +++ b/src/BusDevice.h @@ -38,6 +38,7 @@ namespace arduino } class BusDevice; +class SpiBusDevice; class WireBusDevice; /************************************************************************************** @@ -80,6 +81,7 @@ class BusDevice IoResponse transfer(IoRequest & req); + SpiBusDevice & spi(); WireBusDevice & wire(); diff --git a/src/spi/SpiBusDevice.cpp b/src/spi/SpiBusDevice.cpp index 6e11e05..31b3444 100644 --- a/src/spi/SpiBusDevice.cpp +++ b/src/spi/SpiBusDevice.cpp @@ -42,3 +42,12 @@ IoResponse SpiBusDevice::transfer(IoRequest & req) { return SpiDispatcher::instance().dispatch(&req, &_config); } + +bool SpiBusDevice::write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue) +{ + SpiBusDeviceConfig config(_config.spi(), _config.settings(), _config.select_func(), _config.deselect_func(), sendvalue); + IoRequest req(write_buffer, write_len, read_buffer, read_len); + IoResponse rsp = SpiDispatcher::instance().dispatch(&req, &config); + rsp->wait(); + return true; +} diff --git a/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h index a9ce264..037013f 100644 --- a/src/spi/SpiBusDevice.h +++ b/src/spi/SpiBusDevice.h @@ -35,13 +35,16 @@ class SpiBusDevice : public BusDeviceBase { public: - SpiBusDevice(SpiBusDeviceConfig const & config); + SpiBusDevice(SpiBusDeviceConfig const & config); virtual ~SpiBusDevice() { } virtual IoResponse transfer(IoRequest & req) override; + bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue = 0xFF); + + private: SpiBusDeviceConfig _config; diff --git a/src/spi/SpiBusDeviceConfig.h b/src/spi/SpiBusDeviceConfig.h index 90a1f5d..196fc43 100644 --- a/src/spi/SpiBusDeviceConfig.h +++ b/src/spi/SpiBusDeviceConfig.h @@ -66,6 +66,8 @@ class SpiBusDeviceConfig void deselect () const { if (_spi_deselect) _spi_deselect(); } byte fill_symbol() const { return _fill_symbol; } + SpiSelectFunc select_func () const { return _spi_select; } + SpiDeselectFunc deselect_func() const { return _spi_deselect; } private: diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index f3b084f..0d1eca2 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -38,12 +38,15 @@ class WireBusDevice : public BusDeviceBase WireBusDevice(WireBusDeviceConfig const & config); virtual ~WireBusDevice() { } + virtual IoResponse transfer(IoRequest & req) override; + bool read(uint8_t * buffer, size_t len, bool stop = true); bool write(const uint8_t * buffer, size_t len, bool stop = true); bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop = false); + private: WireBusDeviceConfig _config; From 98bb122352f9c74d6c0ceb8eda3f5e67a4b5964a Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 10:58:15 +0200 Subject: [PATCH 103/108] Implement Adafruit_BusIO-style write/read method for SPI. --- src/spi/SpiBusDevice.cpp | 17 +++++++++++++++++ src/spi/SpiBusDevice.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/spi/SpiBusDevice.cpp b/src/spi/SpiBusDevice.cpp index 31b3444..5e7016e 100644 --- a/src/spi/SpiBusDevice.cpp +++ b/src/spi/SpiBusDevice.cpp @@ -43,6 +43,23 @@ IoResponse SpiBusDevice::transfer(IoRequest & req) return SpiDispatcher::instance().dispatch(&req, &_config); } +bool SpiBusDevice::read(uint8_t * buffer, size_t len, uint8_t sendvalue) +{ + SpiBusDeviceConfig config(_config.spi(), _config.settings(), _config.select_func(), _config.deselect_func(), sendvalue); + IoRequest req(nullptr, 0, buffer, len); + IoResponse rsp = SpiDispatcher::instance().dispatch(&req, &config); + rsp->wait(); + return true; +} + +bool SpiBusDevice::write(const uint8_t * buffer, size_t len) +{ + IoRequest req(buffer, len, nullptr, 0); + IoResponse rsp = SpiDispatcher::instance().dispatch(&req, &_config); + rsp->wait(); + return true; +} + bool SpiBusDevice::write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue) { SpiBusDeviceConfig config(_config.spi(), _config.settings(), _config.select_func(), _config.deselect_func(), sendvalue); diff --git a/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h index 037013f..13da807 100644 --- a/src/spi/SpiBusDevice.h +++ b/src/spi/SpiBusDevice.h @@ -42,6 +42,8 @@ class SpiBusDevice : public BusDeviceBase virtual IoResponse transfer(IoRequest & req) override; + bool read(uint8_t * buffer, size_t len, uint8_t sendvalue = 0xFF); + bool write(const uint8_t * buffer, size_t len); bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue = 0xFF); From 414908d72affdf280133f096ce9e01ba24ad373e Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 28 Sep 2021 11:00:00 +0200 Subject: [PATCH 104/108] Prevent out-of-bound buffer access. --- src/spi/SpiDispatcher.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/spi/SpiDispatcher.cpp b/src/spi/SpiDispatcher.cpp index 456423c..4460380 100644 --- a/src/spi/SpiDispatcher.cpp +++ b/src/spi/SpiDispatcher.cpp @@ -143,20 +143,21 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) size_t bytes_received = 0, bytes_sent = 0; for(; - bytes_received < io_request->bytes_to_read; + bytes_received < std::max(io_request->bytes_to_read, io_request->bytes_to_write); bytes_received++, bytes_sent++) { byte tx_byte = 0; - if (bytes_sent < io_request->bytes_to_write) + if (io_request->write_buf && (bytes_sent < io_request->bytes_to_write)) tx_byte = io_request->write_buf[bytes_sent]; else tx_byte = config->fill_symbol(); byte const rx_byte = config->spi().transfer(tx_byte); - io_request->read_buf[bytes_received] = rx_byte; - } + if (io_request->read_buf && (bytes_received < io_request->bytes_to_read)) + io_request->read_buf[bytes_received] = rx_byte; + } config->spi().endTransaction(); config->deselect(); From 1fae13f6e1a54c86a7a8c7f768f825c45deb8e5c Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 30 Sep 2021 10:13:24 +0200 Subject: [PATCH 105/108] Redesiging SpiDispatcher to conform the write_then_read API of Adafruit_BusIO. * All data returned by spi.transfer() before the end of the write buffer are directly written into the write buffer. * All data returned by spi.transer() after the end of the write buffer are written into the read buffer. * After exhaustion of the write buffer only the fill_value is being sent. --- examples/Threadsafe_SPI/Threadsafe_SPI.ino | 13 +++---- .../Threadsafe_SPI_BusIO.ino | 15 +++----- .../Threadsafe_Wire_BusIO.ino | 2 +- src/IoTransaction.h | 6 ++-- src/spi/SpiBusDevice.cpp | 4 +-- src/spi/SpiBusDevice.h | 4 +-- src/spi/SpiDispatcher.cpp | 34 +++++++++++-------- src/wire/WireBusDevice.cpp | 4 +-- src/wire/WireBusDevice.h | 4 +-- 9 files changed, 41 insertions(+), 45 deletions(-) diff --git a/examples/Threadsafe_SPI/Threadsafe_SPI.ino b/examples/Threadsafe_SPI/Threadsafe_SPI.ino index a6e4604..ddd7b8c 100644 --- a/examples/Threadsafe_SPI/Threadsafe_SPI.ino +++ b/examples/Threadsafe_SPI/Threadsafe_SPI.ino @@ -60,22 +60,17 @@ void loop() byte bmp388_read_reg(byte const reg_addr) { - byte const write_buf[3] = - { - static_cast(0x80 | reg_addr), /* REG_ADDR, if MSBit is set -> READ access */ - 0, /* Dummy byte. */ - 0 /* REG_VAL is output on SDO */ - }; - byte read_buf[3] = {0}; + /* REG_ADDR | DUMMY_BYTE | REG_VAL is on SDO */ + byte read_write_buf[] = {static_cast(0x80 | reg_addr), 0, 0}; - IoRequest req(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); + IoRequest req(read_write_buf, sizeof(read_write_buf), nullptr, 0); IoResponse rsp = bmp388.transfer(req); /* Do other stuff */ rsp->wait(); - return read_buf[2]; + return read_write_buf[2]; } void bmp388_thread_func() diff --git a/examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino b/examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino index e40f7ff..6d5f0c5 100644 --- a/examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino +++ b/examples/Threadsafe_SPI_BusIO/Threadsafe_SPI_BusIO.ino @@ -60,17 +60,12 @@ void loop() byte bmp388_read_reg(byte const reg_addr) { - byte const write_buf[3] = - { - static_cast(0x80 | reg_addr), /* REG_ADDR, if MSBit is set -> READ access */ - 0, /* Dummy byte. */ - 0 /* REG_VAL is output on SDO */ - }; - byte read_buf[3] = {0}; - - bmp388.spi().write_then_read(write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); + /* REG_ADDR | DUMMY_BYTE | REG_VAL is on SDO */ + byte write_buf[2] = {static_cast(0x80 | reg_addr), 0}; + byte read_buf = 0; - return read_buf[2]; + bmp388.spi().write_then_read(write_buf, sizeof(write_buf), &read_buf, sizeof(read_buf)); + return read_buf; } void bmp388_thread_func() diff --git a/examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino b/examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino index 16ebe1b..ae934a4 100644 --- a/examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino +++ b/examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino @@ -55,7 +55,7 @@ void loop() * FUNCTION DEFINITION **************************************************************************************/ -byte lsm6dsox_read_reg(byte const reg_addr) +byte lsm6dsox_read_reg(byte reg_addr) { byte read_buf = 0; lsm6dsox.wire().write_then_read(®_addr, 1, &read_buf, 1); diff --git a/src/IoTransaction.h b/src/IoTransaction.h index 87dad0b..812f3f5 100644 --- a/src/IoTransaction.h +++ b/src/IoTransaction.h @@ -41,18 +41,18 @@ class IoRequest { public: - IoRequest(byte const * const write_buf_, size_t const bytes_to_write_, byte * read_buf_, size_t const bytes_to_read_) + IoRequest(byte * write_buf_, size_t const bytes_to_write_, byte * read_buf_, size_t const bytes_to_read_) : write_buf{write_buf_} , bytes_to_write{bytes_to_write_} , read_buf{read_buf_} , bytes_to_read{bytes_to_read_} { } - IoRequest(byte const & write_buf_, byte & read_buf_) + IoRequest(byte & write_buf_, byte & read_buf_) : IoRequest{&write_buf_, 1, &read_buf_, 1} { } - byte const * const write_buf{nullptr}; + byte * write_buf{nullptr}; size_t const bytes_to_write{0}; byte * read_buf{nullptr}; size_t const bytes_to_read{0}; diff --git a/src/spi/SpiBusDevice.cpp b/src/spi/SpiBusDevice.cpp index 5e7016e..42dd09b 100644 --- a/src/spi/SpiBusDevice.cpp +++ b/src/spi/SpiBusDevice.cpp @@ -52,7 +52,7 @@ bool SpiBusDevice::read(uint8_t * buffer, size_t len, uint8_t sendvalue) return true; } -bool SpiBusDevice::write(const uint8_t * buffer, size_t len) +bool SpiBusDevice::write(uint8_t * buffer, size_t len) { IoRequest req(buffer, len, nullptr, 0); IoResponse rsp = SpiDispatcher::instance().dispatch(&req, &_config); @@ -60,7 +60,7 @@ bool SpiBusDevice::write(const uint8_t * buffer, size_t len) return true; } -bool SpiBusDevice::write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue) +bool SpiBusDevice::write_then_read(uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue) { SpiBusDeviceConfig config(_config.spi(), _config.settings(), _config.select_func(), _config.deselect_func(), sendvalue); IoRequest req(write_buffer, write_len, read_buffer, read_len); diff --git a/src/spi/SpiBusDevice.h b/src/spi/SpiBusDevice.h index 13da807..f16347b 100644 --- a/src/spi/SpiBusDevice.h +++ b/src/spi/SpiBusDevice.h @@ -43,8 +43,8 @@ class SpiBusDevice : public BusDeviceBase bool read(uint8_t * buffer, size_t len, uint8_t sendvalue = 0xFF); - bool write(const uint8_t * buffer, size_t len); - bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue = 0xFF); + bool write(uint8_t * buffer, size_t len); + bool write_then_read(uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, uint8_t sendvalue = 0xFF); private: diff --git a/src/spi/SpiDispatcher.cpp b/src/spi/SpiDispatcher.cpp index 4460380..a5ab024 100644 --- a/src/spi/SpiDispatcher.cpp +++ b/src/spi/SpiDispatcher.cpp @@ -140,24 +140,30 @@ void SpiDispatcher::processSpiIoRequest(SpiIoTransaction * spi_io_transaction) config->spi().beginTransaction(config->settings()); - size_t bytes_received = 0, - bytes_sent = 0; - for(; - bytes_received < std::max(io_request->bytes_to_read, io_request->bytes_to_write); - bytes_received++, bytes_sent++) + /* In a first step transmit the complete write buffer and + * write back the receive data directly into the write buffer + */ + size_t bytes_sent = 0; + for(; bytes_sent < io_request->bytes_to_write; bytes_sent++) { - byte tx_byte = 0; + uint8_t const tx_byte = io_request->write_buf[bytes_sent]; + uint8_t const rx_byte = config->spi().transfer(tx_byte); + + io_request->write_buf[bytes_sent] = rx_byte; + } - if (io_request->write_buf && (bytes_sent < io_request->bytes_to_write)) - tx_byte = io_request->write_buf[bytes_sent]; - else - tx_byte = config->fill_symbol(); + /* In a second step, transmit the fill symbol and write the + * received data into the read buffer. + */ + size_t bytes_received = 0; + for(; bytes_received < io_request->bytes_to_read; bytes_received++) + { + uint8_t const tx_byte = config->fill_symbol(); + uint8_t const rx_byte = config->spi().transfer(tx_byte); - byte const rx_byte = config->spi().transfer(tx_byte); + io_request->read_buf[bytes_received] = rx_byte; + } - if (io_request->read_buf && (bytes_received < io_request->bytes_to_read)) - io_request->read_buf[bytes_received] = rx_byte; - } config->spi().endTransaction(); config->deselect(); diff --git a/src/wire/WireBusDevice.cpp b/src/wire/WireBusDevice.cpp index 915b257..19477fb 100644 --- a/src/wire/WireBusDevice.cpp +++ b/src/wire/WireBusDevice.cpp @@ -52,7 +52,7 @@ bool WireBusDevice::read(uint8_t * buffer, size_t len, bool stop) return true; } -bool WireBusDevice::write(const uint8_t * buffer, size_t len, bool stop) +bool WireBusDevice::write(uint8_t * buffer, size_t len, bool stop) { bool const restart = !stop; WireBusDeviceConfig config(_config.wire(), _config.slave_addr(), restart, _config.stop()); @@ -62,7 +62,7 @@ bool WireBusDevice::write(const uint8_t * buffer, size_t len, bool stop) return true; } -bool WireBusDevice::write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop) +bool WireBusDevice::write_then_read(uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop) { /* Copy the Wire parameters from the device and modify only those * which can be modified via the parameters of this function. diff --git a/src/wire/WireBusDevice.h b/src/wire/WireBusDevice.h index 0d1eca2..6c9f8bf 100644 --- a/src/wire/WireBusDevice.h +++ b/src/wire/WireBusDevice.h @@ -43,8 +43,8 @@ class WireBusDevice : public BusDeviceBase bool read(uint8_t * buffer, size_t len, bool stop = true); - bool write(const uint8_t * buffer, size_t len, bool stop = true); - bool write_then_read(const uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop = false); + bool write(uint8_t * buffer, size_t len, bool stop = true); + bool write_then_read(uint8_t * write_buffer, size_t write_len, uint8_t * read_buffer, size_t read_len, bool stop = false); private: From 01428448c9fc8ed3d63ca469fcdfa22f95792564 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 1 Oct 2021 09:11:06 +0200 Subject: [PATCH 106/108] Release v0.6.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 6d37f2e..11e579e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_ThreadsafeIO -version=0.5.0 +version=0.6.0 author=Alexander Entinger maintainer=Arduino sentence=Enable threadsafe peripheral access via pipes. From 40e2855f17f7882950df09251259e851de45c75b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 5 Oct 2021 06:52:31 +0200 Subject: [PATCH 107/108] Initial draft on a documentation within README. (#31) --- README.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/README.md b/README.md index fe3e009..bfae056 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,72 @@ + + `Arduino_ThreadsafeIO` ====================== [![Check Arduino status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/check-arduino.yml) [![Compile Examples status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/compile-examples-private.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/compile-examples-private.yml) [![Spell Check status](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml) + +This Arduino library provides thread-safe access to `Wire`, `SPI` and `Serial` which is relevant when creating multi-threaded sketches with `Arduino_Threads`. + +## :zap: Features +### :thread: Threadsafe +A key problem of multi-tasking is the **prevention of erroneous state when multiple threads share a single resource**. The following example borrowed from a typical application demonstrates the problems resulting from multiple threads sharing a single resource: + +Imagine a embedded system where multiple `Wire` client devices are physically connected to a single `Wire` server. Each `Wire` client device is managed by a separate software thread. Each thread polls its `Wire` client device periodically. Access to the I2C bus is managed via the `Wire` library and typically follows this pattern: + +```C++ +/* Wire Write Access */ +Wire.beginTransmission(addr); +Wire.write(val); +Wire.endTransmission(); + +/* Wire Read Access */ +Wire.beginTransmission(addr); +Wire.write(val); +Wire.endTransmission(); +Wire.requestFrom(addr, bytes) +while(Wire.available()) { + int val = Wire.read(); +} +``` + +Since we are using [ARM Mbed OS](https://os.mbed.com/mbed-os/) which is a [preemptive](https://en.wikipedia.org/wiki/Preemption_(computing)) [RTOS](https://en.wikipedia.org/wiki/Real-time_operating_system) for achieving multi-tasking capability and under the assumption that all threads share the same priority (which leads to a [round-robin](https://en.wikipedia.org/wiki/Round-robin_scheduling) scheduling) it can easily happen that one thread is half-way through its Wire IO access when the scheduler interrupts it and schedules the next thread which in turn starts/continues/ends its own Wire IO access. + +As a result this interruption by the scheduler will break Wire IO access for both devices and leave the Wire IO controller in an undefined state. :fire:. + +`Arduino_ThreadsafeIO` solves this problem by encapsulating a complete IO access (e.g. reading from a `Wire` client device) within a single function call which generates an IO request to be asynchronously executed by a high-priority IO thread. The high-priority IO thread is the **only** instance which actually directly communicates with physical hardware. + +### :zzz: Asynchronous + +The mechanisms implemented in this library allow any thread to dispatch an IO request asynchronously and either continue operation or [yield](https://en.wikipedia.org/wiki/Yield_(multithreading))-ing control to the next scheduled thread. All IO requests are stored in a queue and are executed within a high-priority IO thread after a context-switch. An example of this can be seen [here](examples/Threadsafe_SPI/Threadsafe_SPI.ino)). + +### :sparkling_heart: Convenient API + +Although you are free to directly manipulate IO requests and responses (e.g. [Threadsafe_Wire](examples/Threadsafe_Wire/Threadsafe_Wire.ino)) there do exist convenient `read`/`write`/`write_then_read` abstractions inspired by the [Adafruit_BusIO](https://github.com/adafruit/Adafruit_BusIO) library (e.g. [Threadsafe_Wire_BusIO](examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino)). + +## :mag_right: Resources + +* [How to install a library](https://www.arduino.cc/en/guide/libraries) +* [Help Center](https://support.arduino.cc/) +* [Forum](https://forum.arduino.cc) + +## :bug: Bugs & Issues + +If you want to report an issue with this library, you can submit it to the [issue tracker](issues) of this repository. Remember to include as much detail as you can about your hardware set-up, code and steps for reproducing the issue. Make sure you're using an original Arduino board. + +## :technologist: Development + +There are many ways to contribute: + +* Improve documentation and examples +* Fix a bug +* Test open Pull Requests +* Implement a new feature +* Discuss potential ways to improve this library + +You can submit your patches directly to this repository as Pull Requests. Please provide a detailed description of the problem you're trying to solve and make sure you test on real hardware. + +## :yellow_heart: Donations + +This open-source code is maintained by Arduino with the help of the community. We invest a considerable amount of time in testing code, optimizing it and introducing new features. Please consider [donating](https://www.arduino.cc/en/donate/) or [sponsoring](https://github.com/sponsors/arduino) to support our work, as well as [buying original Arduino boards](https://store.arduino.cc/) which is the best way to make sure our effort can continue in the long term. From d7e9dfecf092964e343b4240b3a096c48d41604b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 13 Oct 2021 07:08:23 +0200 Subject: [PATCH 108/108] Delete superfluous compile-examples-private.yml. --- .../workflows/compile-examples-private.yml | 97 ------------------- 1 file changed, 97 deletions(-) delete mode 100644 .github/workflows/compile-examples-private.yml diff --git a/.github/workflows/compile-examples-private.yml b/.github/workflows/compile-examples-private.yml deleted file mode 100644 index 9645d66..0000000 --- a/.github/workflows/compile-examples-private.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Compile Examples - -# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows -on: - push: - paths: - - ".github/workflows/compile-examples-private.ya?ml" - - "library.properties" - - "examples/**" - - "src/**" - pull_request: - paths: - - ".github/workflows/compile-examples-private.ya?ml" - - "library.properties" - - "examples/**" - - "src/**" - schedule: - # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). - - cron: "0 8 * * TUE" - workflow_dispatch: - repository_dispatch: - -env: - SKETCHES_REPORTS_PATH: sketches-reports - SKETCHES_REPORTS_ARTIFACT_NAME: sketches-reports - -jobs: - build: - name: ${{ matrix.board.fqbn }} - runs-on: ubuntu-latest - - strategy: - fail-fast: false - - matrix: - board: - - fqbn: arduino:mbed_nano:nano33ble - platforms: | - - name: arduino:mbed_nano - - fqbn: arduino:mbed_nano:nanorp2040connect - platforms: | - - name: arduino:mbed_nano - - fqbn: arduino:mbed_portenta:envie_m4 - platforms: | - - name: arduino:mbed_portenta - - fqbn: arduino:mbed_portenta:envie_m7 - platforms: | - - name: arduino:mbed_portenta - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Compile examples - uses: arduino/compile-sketches@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - fqbn: ${{ matrix.board.fqbn }} - platforms: ${{ matrix.board.platforms }} - libraries: | - # Install the library from the local path. - - source-path: ./ - # Additional library dependencies can be listed here. - # See: https://github.com/arduino/compile-sketches#libraries - sketch-paths: | - - examples - enable-deltas-report: true - sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} - - - name: Save sketches report as workflow artifact - uses: actions/upload-artifact@v2 - with: - if-no-files-found: error - path: ${{ env.SKETCHES_REPORTS_PATH }} - name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} - - report-size-deltas: - needs: build - # Run even if some compilations failed. - if: always() && github.event_name == 'pull_request' - runs-on: ubuntu-latest - - steps: - - name: Download sketches reports artifact - id: download-artifact - continue-on-error: true # If compilation failed for all boards then there are no artifacts - uses: actions/download-artifact@v2 - with: - name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} - path: ${{ env.SKETCHES_REPORTS_PATH }} - - - name: Comment size deltas report to PR - uses: arduino/report-size-deltas@v1 - # If actions/download-artifact failed, there are no artifacts to report from. - if: steps.download-artifact.outcome == 'success' - with: - sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }}