diff --git a/lib/3rd_party_adapters/SerialInputHandler.cpp b/lib/3rd_party_adapters/SerialInputHandler.cpp new file mode 100644 index 000000000..a1f548d0e --- /dev/null +++ b/lib/3rd_party_adapters/SerialInputHandler.cpp @@ -0,0 +1,54 @@ +#include "SerialInputHandler.hpp" +#include + +SerialInputHandler::SerialInputHandler() +{ + // TODO Auto-generated constructor stub +} + +void SerialInputHandler::handleNewSerialData(Stream &stream) +{ + while (Serial.available() > 0) + { + const auto inData = Serial.read(); + if (inData < 0) + { + break; + } + else + { + const auto inChar = static_cast(inData); + static std::string begunLine; + begunLine += inChar; + if (inChar == '\n' || inChar == '\r') + { + 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/3rd_party_adapters/SerialInputHandler.hpp b/lib/3rd_party_adapters/SerialInputHandler.hpp new file mode 100644 index 000000000..55a0bef41 --- /dev/null +++ b/lib/3rd_party_adapters/SerialInputHandler.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +class Stream; + +class SerialInputHandler +{ + public: + 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(); + } +}; diff --git a/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp new file mode 100644 index 000000000..fa21dd5bb --- /dev/null +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.cpp @@ -0,0 +1,25 @@ +#include "SerialInputStreamBuffer.hpp" +#include "serial_port.hpp" +#include +#include +#include + +SerialInputStreamBuffer::SerialInputStreamBuffer(char_type *const buffer_begin, char_type *const buffer_end) + : buffer_begin(buffer_begin), buffer_end(buffer_end) +{ + setg(buffer_begin, buffer_end, buffer_end); +} + +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, bufferSize); + serial_port::cout << "Received: " << readBytes; + 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 new file mode 100644 index 000000000..9c7948a13 --- /dev/null +++ b/lib/3rd_party_adapters/SerialInputStreamBuffer.hpp @@ -0,0 +1,18 @@ +/** + * \file . + */ +#pragma once +#include + +class SerialInputStreamBuffer : public std::streambuf +{ + private: + char_type *const buffer_begin; + char_type *const buffer_end; + + public: + SerialInputStreamBuffer(char_type *const buffer_begin, char_type *const buffer_end); + + protected: + int_type underflow() override; +}; 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. */ 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() {