Skip to content

serial interface: add std::istream adpater for Arduino Serial #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
54 changes: 54 additions & 0 deletions lib/3rd_party_adapters/SerialInputHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "SerialInputHandler.hpp"
#include <Arduino.h>

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<char>(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);
}
26 changes: 26 additions & 0 deletions lib/3rd_party_adapters/SerialInputHandler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <queue>
#include <string>

class Stream;

class SerialInputHandler
{
public:
std::string getNextLine();
static SerialInputHandler &getInstance();

private:
std::queue<std::string> messageQueue;
SerialInputHandler();
void handleNewSerialData(Stream &stream);

friend void serialEvent();

public:
auto getNumberOfAvailableLines() const
{
return messageQueue.size();
}
};
25 changes: 25 additions & 0 deletions lib/3rd_party_adapters/SerialInputStreamBuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "SerialInputStreamBuffer.hpp"
#include "serial_port.hpp"
#include <Arduino.h>
#include <algorithm>
#include <iterator>

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());
}
18 changes: 18 additions & 0 deletions lib/3rd_party_adapters/SerialInputStreamBuffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* \file .
*/
#pragma once
#include <streambuf>

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;
};
11 changes: 11 additions & 0 deletions lib/3rd_party_adapters/serial_port.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
#include "serial_port.hpp"
#include "SerialInputStreamBuffer.hpp"
#include "SerialOutputStreamBuffer.hpp"
#include <Arduino.h>
#include <cstddef>
#include <iterator>

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()
{
Expand Down
3 changes: 3 additions & 0 deletions lib/application_business_rules/serial_port.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <array>
#include <istream>
#include <ostream>

namespace serial_port
Expand All @@ -10,6 +11,8 @@ namespace serial_port
*/
extern std::ostream &cout;

extern std::istream &cin;

/**
* Configures and initializes serial port.
*/
Expand Down
10 changes: 10 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "serial_port.hpp"
#include <Arduino.h>
#include <cstdint>
#include <string>

/**
* Events are the beginning of a pressed button.
Expand Down Expand Up @@ -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()
{
Expand Down