2020-06-29 00:33:14 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <cctype>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
|
2020-07-03 18:45:04 +02:00
|
|
|
#include "light_sensors.hpp"
|
|
|
|
|
2020-06-29 00:33:14 +02:00
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
constexpr auto ENDL = "\r\n";
|
|
|
|
constexpr auto HELP_CMD = "help";
|
|
|
|
constexpr auto READ_CMD = "read";
|
|
|
|
|
|
|
|
constexpr auto VERSION_CMD = "version";
|
|
|
|
constexpr auto VERSION = "1.0";
|
|
|
|
|
|
|
|
static inline bool substringEquals(const char* str1, const char* str2, const size_t& size)
|
|
|
|
{
|
|
|
|
return (std::strncmp(str1, str2, size) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool stringEquals(const char* str1, const char* str2, const size_t& size)
|
|
|
|
{
|
|
|
|
if(size == std::strlen(str2)) {
|
|
|
|
return substringEquals(str1, str2, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
template<class Uart>
|
|
|
|
class Terminal {
|
|
|
|
public:
|
|
|
|
static void init()
|
|
|
|
{
|
|
|
|
m_serial.init();
|
|
|
|
|
|
|
|
m_serial << detail::ENDL;
|
|
|
|
printVersion();
|
|
|
|
m_serial << detail::ENDL << "$ ";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void callback()
|
|
|
|
{
|
|
|
|
if(receiveInput()) {
|
|
|
|
parseInput();
|
|
|
|
}
|
2020-07-03 18:45:04 +02:00
|
|
|
m_serial.flushTx();
|
2020-06-29 00:33:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr auto INPUT_BUFFER_SIZE = 128;
|
|
|
|
static constexpr auto BACKSPACE = uint8_t{0x7f};
|
|
|
|
static constexpr auto CTRL_C = uint8_t{0x03};
|
|
|
|
|
|
|
|
static Uart m_serial;
|
|
|
|
static char m_inputBuffer[INPUT_BUFFER_SIZE];
|
|
|
|
static uint16_t m_inputSize;
|
2020-07-03 18:45:04 +02:00
|
|
|
static LightSensors m_lightSensors;
|
2020-06-29 00:33:14 +02:00
|
|
|
|
|
|
|
static bool receiveInput()
|
|
|
|
{
|
|
|
|
uint8_t inputByte;
|
|
|
|
|
|
|
|
while(m_serial.rxByte(inputByte)) {
|
|
|
|
if(std::isprint(inputByte) || inputByte == CTRL_C) {
|
|
|
|
m_inputBuffer[m_inputSize++] = inputByte;
|
|
|
|
|
|
|
|
// Handle Ctrl + C
|
|
|
|
if(inputByte == CTRL_C) {
|
|
|
|
m_serial << "^C" << detail::ENDL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Echo
|
|
|
|
else {
|
|
|
|
m_serial << static_cast<char>(inputByte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle backspace
|
|
|
|
if(inputByte == BACKSPACE && m_inputSize > 0) {
|
|
|
|
m_serial << "\b \b";
|
|
|
|
--m_inputSize;
|
|
|
|
}
|
|
|
|
// Handle line terminator
|
|
|
|
else if(inputByte == '\r' || inputByte == '\n') {
|
|
|
|
// Consume possible second line terminator
|
|
|
|
if(m_serial.peek(inputByte) && (inputByte == '\r' || inputByte == '\n')) {
|
|
|
|
m_serial.rxByte(inputByte);
|
|
|
|
}
|
|
|
|
m_serial << detail::ENDL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_inputSize >= INPUT_BUFFER_SIZE) {
|
|
|
|
m_serial << detail::ENDL << "WARNING: Terminal input buffer overflow!" << detail::ENDL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void parseInput()
|
|
|
|
{
|
|
|
|
if(m_inputSize) {
|
|
|
|
if(m_inputBuffer[m_inputSize - 1] == CTRL_C) {
|
|
|
|
handleCtrlC();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(detail::substringEquals(m_inputBuffer, detail::HELP_CMD, m_inputSize)) {
|
|
|
|
printHelp();
|
|
|
|
}
|
|
|
|
else if(detail::substringEquals(m_inputBuffer, detail::READ_CMD, m_inputSize)) {
|
2020-07-03 18:45:04 +02:00
|
|
|
readSensors();
|
2020-06-29 00:33:14 +02:00
|
|
|
}
|
|
|
|
else if(detail::substringEquals(m_inputBuffer, detail::VERSION_CMD, m_inputSize)) {
|
|
|
|
printVersion();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printUnknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_inputSize = 0;
|
|
|
|
m_serial << "$ ";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handleCtrlC() { m_serial << "Abort!" << detail::ENDL; }
|
|
|
|
|
|
|
|
static void printHelp()
|
|
|
|
{
|
|
|
|
m_serial << "AdaptiveBrightness command overview: " << detail::ENDL;
|
|
|
|
m_serial << detail::HELP_CMD << " .......: prints this help message" << detail::ENDL;
|
|
|
|
m_serial << detail::READ_CMD << " .......: reads and displays all LDR values" << detail::ENDL;
|
|
|
|
m_serial << detail::VERSION_CMD << " ....: displays firmware version" << detail::ENDL;
|
|
|
|
}
|
|
|
|
|
2020-07-03 18:45:04 +02:00
|
|
|
static void readSensors()
|
|
|
|
{
|
|
|
|
const auto sensorValues = m_lightSensors.getValues();
|
2020-07-03 18:58:54 +02:00
|
|
|
m_serial << "Sensor values: " << detail::ENDL;
|
|
|
|
for(size_t i = 0; i < sensorValues.size(); ++i) {
|
|
|
|
m_serial << "LDR";
|
|
|
|
m_serial.txNumber(i + 1);
|
|
|
|
m_serial << ": ";
|
|
|
|
m_serial.template txNumber<uint16_t, 10, 4, ' '>(sensorValues[i]);
|
|
|
|
m_serial << " - ";
|
|
|
|
m_serial.template txNumber<uint8_t, 10, 3, ' '>(sensorValues[i] * 100 / m_lightSensors.MAX_VALUE);
|
|
|
|
m_serial << "%" << detail::ENDL;
|
2020-07-03 18:45:04 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-29 00:33:14 +02:00
|
|
|
|
|
|
|
static void printVersion() { m_serial << "AdaptiveBrightness v" << detail::VERSION << detail::ENDL; }
|
|
|
|
|
|
|
|
static void printUnknown()
|
|
|
|
{
|
|
|
|
m_serial << "Unknown command \"";
|
|
|
|
for(uint16_t i = 0; i < m_inputSize; ++i) {
|
|
|
|
m_serial << static_cast<char>(m_inputBuffer[i]);
|
|
|
|
}
|
|
|
|
m_serial << "\"" << detail::ENDL;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class Uart>
|
|
|
|
char Terminal<Uart>::m_inputBuffer[INPUT_BUFFER_SIZE];
|
|
|
|
|
|
|
|
template<class Uart>
|
|
|
|
uint16_t Terminal<Uart>::m_inputSize = 0;
|