From 5039dce04f944a51af8a3baf8ace5c285c796c75 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sat, 21 Oct 2023 22:48:07 +0200 Subject: [PATCH 01/11] Add empty class for future handler of serial input. (cherry picked from commit 605277444f22afb65a00116de680d328156f2222) --- lib/serial_interface/SerialInputHandler.cpp | 6 ++++++ lib/serial_interface/SerialInputHandler.hpp | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 lib/serial_interface/SerialInputHandler.cpp create mode 100644 lib/serial_interface/SerialInputHandler.hpp diff --git a/lib/serial_interface/SerialInputHandler.cpp b/lib/serial_interface/SerialInputHandler.cpp new file mode 100644 index 000000000..63daa804b --- /dev/null +++ b/lib/serial_interface/SerialInputHandler.cpp @@ -0,0 +1,6 @@ +#include "SerialInputHandler.hpp" + +SerialInputHandler::SerialInputHandler() +{ + // TODO Auto-generated constructor stub +} diff --git a/lib/serial_interface/SerialInputHandler.hpp b/lib/serial_interface/SerialInputHandler.hpp new file mode 100644 index 000000000..123a85aab --- /dev/null +++ b/lib/serial_interface/SerialInputHandler.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +class SerialInputHandler +{ + public: + SerialInputHandler(); +}; From 97f48607df7eb66c1adb1ac0eb997c2bba0d4552 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sat, 21 Oct 2023 22:55:19 +0200 Subject: [PATCH 02/11] Prepare serial input handler. (cherry picked from commit 7b90a9afb4a707ada531bc7bb08ac7f7df88fc0e) --- lib/serial_interface/SerialInputHandler.cpp | 5 +++++ lib/serial_interface/SerialInputHandler.hpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/lib/serial_interface/SerialInputHandler.cpp b/lib/serial_interface/SerialInputHandler.cpp index 63daa804b..3e77f6607 100644 --- a/lib/serial_interface/SerialInputHandler.cpp +++ b/lib/serial_interface/SerialInputHandler.cpp @@ -1,6 +1,11 @@ #include "SerialInputHandler.hpp" +#include SerialInputHandler::SerialInputHandler() { // TODO Auto-generated constructor stub } + +void SerialInputHandler::handleNewSerialData(Stream &stream) +{ +} diff --git a/lib/serial_interface/SerialInputHandler.hpp b/lib/serial_interface/SerialInputHandler.hpp index 123a85aab..2bc9f0d0b 100644 --- a/lib/serial_interface/SerialInputHandler.hpp +++ b/lib/serial_interface/SerialInputHandler.hpp @@ -1,9 +1,16 @@ #pragma once #include +#include + +class Stream; class SerialInputHandler { public: SerialInputHandler(); + void handleNewSerialData(Stream &stream); + + private: + std::queue messageQueue; }; From 6788b0512978bbe69076a78d4e97dfaac6aa5a84 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sat, 21 Oct 2023 22:59:31 +0200 Subject: [PATCH 03/11] Add example code for `serialEvent()`. Copied from https://github.com/dhebbeker/echo-device/blob/854a72840e42d53cf2f4d47449c9cf2603528956/src/main.cpp#L49 (cherry picked from commit 6e146d8b7f1b96be0ddb72914195d5a062dcdefe) --- lib/serial_interface/SerialInputHandler.cpp | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/serial_interface/SerialInputHandler.cpp b/lib/serial_interface/SerialInputHandler.cpp index 3e77f6607..bbf3d1869 100644 --- a/lib/serial_interface/SerialInputHandler.cpp +++ b/lib/serial_interface/SerialInputHandler.cpp @@ -9,3 +9,31 @@ SerialInputHandler::SerialInputHandler() void SerialInputHandler::handleNewSerialData(Stream &stream) { } + +/* + SerialEvent occurs whenever a new data comes in the hardware serial RX. This + routine is run between each time loop() runs, so using delay inside loop can + delay response. Multiple bytes of data may be available. +*/ +void serialEvent() +{ + while (Serial.available() > 0) + { + const auto inData = Serial.read(); + if (inData < 0) + { + break; + } + else + { + const auto inChar = static_cast(inData); + inputString += inChar; + // if the incoming character is a newline, set a flag so the main loop can + // do something about it: + if (inChar == '\n' || inChar == '\r') + { + stringComplete = true; + } + } + } +} From 3ec3dcdfa94ad1e20ccd7db8b547f188b60c1467 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sat, 21 Oct 2023 23:34:26 +0200 Subject: [PATCH 04/11] Implement SerialInputHandler. (cherry picked from commit 66c6d539e221f1a3e47d249c79be337959ccfdd2) --- lib/serial_interface/SerialInputHandler.cpp | 41 ++++++++++++++------- lib/serial_interface/SerialInputHandler.hpp | 14 ++++++- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/lib/serial_interface/SerialInputHandler.cpp b/lib/serial_interface/SerialInputHandler.cpp index bbf3d1869..a1f548d0e 100644 --- a/lib/serial_interface/SerialInputHandler.cpp +++ b/lib/serial_interface/SerialInputHandler.cpp @@ -7,15 +7,6 @@ SerialInputHandler::SerialInputHandler() } void SerialInputHandler::handleNewSerialData(Stream &stream) -{ -} - -/* - SerialEvent occurs whenever a new data comes in the hardware serial RX. This - routine is run between each time loop() runs, so using delay inside loop can - delay response. Multiple bytes of data may be available. -*/ -void serialEvent() { while (Serial.available() > 0) { @@ -27,13 +18,37 @@ void serialEvent() else { const auto inChar = static_cast(inData); - inputString += inChar; - // if the incoming character is a newline, set a flag so the main loop can - // do something about it: + static std::string begunLine; + begunLine += inChar; if (inChar == '\n' || inChar == '\r') { - stringComplete = true; + messageQueue.push(begunLine); + begunLine.clear(); } } } } + +std::string SerialInputHandler::getNextLine() +{ + const std::string line = messageQueue.front(); + messageQueue.pop(); + return line; +} + +SerialInputHandler &SerialInputHandler::getInstance() +{ + static SerialInputHandler instance; + return instance; +} + +/* + SerialEvent occurs whenever a new data comes in the hardware serial RX. This + routine is run between each time loop() runs, so using delay inside loop can + delay response. Multiple bytes of data may be available. +*/ +void serialEvent() +{ + auto handler = SerialInputHandler::getInstance(); + handler.handleNewSerialData(Serial); +} diff --git a/lib/serial_interface/SerialInputHandler.hpp b/lib/serial_interface/SerialInputHandler.hpp index 2bc9f0d0b..55a0bef41 100644 --- a/lib/serial_interface/SerialInputHandler.hpp +++ b/lib/serial_interface/SerialInputHandler.hpp @@ -8,9 +8,19 @@ class Stream; class SerialInputHandler { public: - SerialInputHandler(); - void handleNewSerialData(Stream &stream); + std::string getNextLine(); + static SerialInputHandler &getInstance(); private: std::queue messageQueue; + SerialInputHandler(); + void handleNewSerialData(Stream &stream); + + friend void serialEvent(); + + public: + auto getNumberOfAvailableLines() const + { + return messageQueue.size(); + } }; From d1ca285de0ed6eaeca14c1d3b3b9173c04c1e562 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 5 Nov 2023 01:50:10 +0100 Subject: [PATCH 05/11] Move to correct package. --- .../SerialInputHandler.cpp | 0 .../SerialInputHandler.hpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename lib/{serial_interface => 3rd_party_adapters}/SerialInputHandler.cpp (100%) rename lib/{serial_interface => 3rd_party_adapters}/SerialInputHandler.hpp (100%) diff --git a/lib/serial_interface/SerialInputHandler.cpp b/lib/3rd_party_adapters/SerialInputHandler.cpp similarity index 100% rename from lib/serial_interface/SerialInputHandler.cpp rename to lib/3rd_party_adapters/SerialInputHandler.cpp diff --git a/lib/serial_interface/SerialInputHandler.hpp b/lib/3rd_party_adapters/SerialInputHandler.hpp similarity index 100% rename from lib/serial_interface/SerialInputHandler.hpp rename to lib/3rd_party_adapters/SerialInputHandler.hpp From 2224053a6ad7f0de35618fb9085c27461f8a3e2e Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 5 Nov 2023 02:02:37 +0100 Subject: [PATCH 06/11] Begin work on adapter from Arduino's `Serial` to `std::istream`. --- .../SerialInputStreamBuffer.cpp | 14 ++++++++++++++ .../SerialInputStreamBuffer.hpp | 15 +++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 lib/3rd_party_adapters/SerialInputStreamBuffer.cpp create mode 100644 lib/3rd_party_adapters/SerialInputStreamBuffer.hpp diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp new file mode 100644 index 000000000..ce8e6ff8f --- /dev/null +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp @@ -0,0 +1,14 @@ +#include "SerialInputStreamBuffer.hpp" + +SerialInputStreamBuffer::SerialInputStreamBuffer() +{ + // TODO Auto-generated constructor stub +} + +SerialInputStreamBuffer::int_type SerialInputStreamBuffer::underflow() +{ +} + +int SerialInputStreamBuffer::sync() +{ +} diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp new file mode 100644 index 000000000..ba1d2f83c --- /dev/null +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp @@ -0,0 +1,15 @@ +/** + * \file . + */ +#pragma once +#include + +class SerialInputStreamBuffer : public std::streambuf +{ + public: + SerialInputStreamBuffer(); + + protected: + int_type underflow() override; + int sync() override; +}; From efaf05f83cae06192d8071edb3efbf4368b0b25f Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 5 Nov 2023 22:12:41 +0100 Subject: [PATCH 07/11] WIP: Write input stream buffer for serial. --- .../SerialInputStreamBuffer.cpp | 26 ++++++++++++++----- .../SerialInputStreamBuffer.hpp | 7 +++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp index ce8e6ff8f..4902eea6f 100644 --- a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp @@ -1,14 +1,28 @@ #include "SerialInputStreamBuffer.hpp" +#include +#include +#include -SerialInputStreamBuffer::SerialInputStreamBuffer() +SerialInputStreamBuffer::SerialInputStreamBuffer(char_type *const buffer_begin, char_type *const buffer_end) + : buffer_begin(buffer_begin), buffer_end(buffer_end) { - // TODO Auto-generated constructor stub + setg(buffer_begin, buffer_end, buffer_end); } SerialInputStreamBuffer::int_type SerialInputStreamBuffer::underflow() { -} - -int SerialInputStreamBuffer::sync() -{ + const auto availableBytes = Serial.available(); + if (availableBytes <= 0) + { + return traits_type::eof(); + } + static const auto bufferLength = std::distance(buffer_begin, buffer_end); + static const auto bufferSize = bufferLength / sizeof(*buffer_begin); + const auto readBytes = Serial.readBytes(buffer_begin, std::min(bufferSize, availableBytes)); + if (readBytes <= 0) + { + return traits_type::eof(); + } + setg(buffer_begin, buffer_begin, std::next(buffer_begin, readBytes / sizeof(*buffer_begin))); + return traits_type::to_int_type(*gptr()); } diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp index ba1d2f83c..9c7948a13 100644 --- a/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp @@ -6,10 +6,13 @@ class SerialInputStreamBuffer : public std::streambuf { + private: + char_type *const buffer_begin; + char_type *const buffer_end; + public: - SerialInputStreamBuffer(); + SerialInputStreamBuffer(char_type *const buffer_begin, char_type *const buffer_end); protected: int_type underflow() override; - int sync() override; }; From 86367576513b0eeb351e7fd355e20a6f2fc1971e Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Mon, 6 Nov 2023 08:16:08 +0100 Subject: [PATCH 08/11] Add serial port object for stream input. --- lib/3rd_party_adapters/serial_port.cpp | 11 +++++++++++ lib/application_business_rules/serial_port.hpp | 3 +++ 2 files changed, 14 insertions(+) diff --git a/lib/3rd_party_adapters/serial_port.cpp b/lib/3rd_party_adapters/serial_port.cpp index 4c7bf8ee1..8028bc644 100644 --- a/lib/3rd_party_adapters/serial_port.cpp +++ b/lib/3rd_party_adapters/serial_port.cpp @@ -1,15 +1,26 @@ #include "serial_port.hpp" +#include "SerialInputStreamBuffer.hpp" #include "SerialOutputStreamBuffer.hpp" #include +#include #include static SerialOutputStreamBuffer::char_type serial_output_buffer[255]; static SerialOutputStreamBuffer serialOutputStreamBuffer(std::begin(serial_output_buffer), std::end(serial_output_buffer)); static std::ostream serialOutputStream(&serialOutputStreamBuffer); +/** + * According to the Arduino reference, the input buffer has a size of 64 bytes. + */ +static constexpr std::size_t sizeOfInputBuffer = 64; +static SerialInputStreamBuffer::char_type serial_input_buffer[sizeOfInputBuffer]; +static SerialInputStreamBuffer serialInputStreamBuffer(std::begin(serial_input_buffer), std::end(serial_input_buffer)); +static std::istream serialInputStream(&serialInputStreamBuffer); + namespace serial_port { std::ostream &cout = serialOutputStream; +std::istream &cin = serialInputStream; void initialize() { diff --git a/lib/application_business_rules/serial_port.hpp b/lib/application_business_rules/serial_port.hpp index 65ac3795b..1a8fac61e 100644 --- a/lib/application_business_rules/serial_port.hpp +++ b/lib/application_business_rules/serial_port.hpp @@ -1,4 +1,5 @@ #include +#include #include namespace serial_port @@ -10,6 +11,8 @@ namespace serial_port */ extern std::ostream &cout; +extern std::istream &cin; + /** * Configures and initializes serial port. */ From ee7fbfc042387f927d0b5826aa9fa57611670973 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Mon, 6 Nov 2023 08:20:21 +0100 Subject: [PATCH 09/11] Fix non-fitting integer type for comparison. Casting from unsigned to signed integer is safe here. --- lib/3rd_party_adapters/SerialInputStreamBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp index 4902eea6f..028ba00af 100644 --- a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp @@ -18,7 +18,7 @@ SerialInputStreamBuffer::int_type SerialInputStreamBuffer::underflow() } static const auto bufferLength = std::distance(buffer_begin, buffer_end); static const auto bufferSize = bufferLength / sizeof(*buffer_begin); - const auto readBytes = Serial.readBytes(buffer_begin, std::min(bufferSize, availableBytes)); + const auto readBytes = Serial.readBytes(buffer_begin, std::min(static_cast(bufferSize), availableBytes)); if (readBytes <= 0) { return traits_type::eof(); From dc286e1d9a5b007af15c9919ee7550fa882e2ecd Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Wed, 8 Nov 2023 08:10:52 +0100 Subject: [PATCH 10/11] WIP: Test serial input stream buffer. --- lib/3rd_party_adapters/SerialInputStreamBuffer.cpp | 4 +++- src/main.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp index 028ba00af..14151c026 100644 --- a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp @@ -1,4 +1,5 @@ #include "SerialInputStreamBuffer.hpp" +#include "serial_port.hpp" #include #include #include @@ -18,7 +19,8 @@ SerialInputStreamBuffer::int_type SerialInputStreamBuffer::underflow() } static const auto bufferLength = std::distance(buffer_begin, buffer_end); static const auto bufferSize = bufferLength / sizeof(*buffer_begin); - const auto readBytes = Serial.readBytes(buffer_begin, std::min(static_cast(bufferSize), availableBytes)); + const auto readBytes = Serial.readBytes(buffer_begin, bufferSize); + serial_port::cout << "Received: " << readBytes; if (readBytes <= 0) { return traits_type::eof(); diff --git a/src/main.cpp b/src/main.cpp index 1401ddf9a..f76358e0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "serial_port.hpp" #include #include +#include /** * Events are the beginning of a pressed button. @@ -66,6 +67,15 @@ void setup(char const *programIdentificationString) setup_display(); serial_port::cout << std::endl << " begin program '" << programIdentificationString << std::endl; + std::string foo; + + Serial.setTimeout(3000); + for (unsigned int i = 0; i < 3;) + { + serial_port::cout << "Waiting for user input:" << std::endl; + serial_port::cin >> foo; + serial_port::cout << "Did read: '" << foo << "'" << std::endl; + } } void loop() { From de8b6744e2c7df68c121165938b928b990faa2be Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Wed, 8 Nov 2023 08:14:26 +0100 Subject: [PATCH 11/11] Do not check for available bytes. Instead use the timeout by `readBytes()` below. --- lib/3rd_party_adapters/SerialInputStreamBuffer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp index 14151c026..fa21dd5bb 100644 --- a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp @@ -12,11 +12,6 @@ SerialInputStreamBuffer::SerialInputStreamBuffer(char_type *const buffer_begin, SerialInputStreamBuffer::int_type SerialInputStreamBuffer::underflow() { - const auto availableBytes = Serial.available(); - if (availableBytes <= 0) - { - return traits_type::eof(); - } static const auto bufferLength = std::distance(buffer_begin, buffer_end); static const auto bufferSize = bufferLength / sizeof(*buffer_begin); const auto readBytes = Serial.readBytes(buffer_begin, bufferSize);