Skip to content

Commit

Permalink
serial interface: add command parser for protocol (#82)
Browse files Browse the repository at this point in the history
### Purpose

Create a command parser which is capable to interpret the commands from
serial interface according to the [defined
protocol](https://github.com/Task-Tracker-Systems/Protocol-Serial-Interface/blob/631fc844a80ad5d707d14fb060660ac1e2c31cdd/serial-protocol.md#protocol-v001).

Resolves #60 

### Acceptance criteria

- [x] It is OK for this version to respond with dummy responses (format
does not need to follow protocol)
- [x] All arguments of the commands shall be understood (test by echo
the values to serial interface)
- [x] Dummy functions for the commands shall be called (test by echo a
string on serial interface)

### Todos

- [x] remove trim functionality as it is not used
- [x] add member function to `Command` which generates a string which is
intended to specify the correct use of the command (command line format)
- [x] handle the case that the command line can not be correctly
interpreted outside of `Command` by printing a message
- [x] refactoring: check which function shall be member functions
- [x] add documentation
- [x] test: add appropriate test cases (check for code coverage)
- [x] create dedicated namespace
- [x] add test case for string helper functions
- [x] add documentation for string helper functions
- [x] add documentation on how to use the command line interpreter

### Changes

- `.github/workflows/platformio.yml`: Added test execution to workflow.
- `lib/3rd_party_adapters/serial_port.cpp`: Change line extraction to
omit line ending characters and empty lines.
- `lib/application_business_rules/Protocol.*`: This implements the
protocol (here: dummies) by using the command line interpreter.
- `lib/application_business_rules/command_line_interpreter.hpp`:
Essentially provides `Option` and `Command` class templates which can be
used to call a function with some arguments based on a command line.
- `lib/enterprise_business_rules/string_helpers.*`: Add helper functions
which can be used to operate on strings.
- `platformio.ini`: Add configuration for unit tests.
- `src/main.cpp`: Attach `ProtocolHandler` to serial port.
- `test/test_cli/test_cli.cpp`: Unit test for command line interpreter.
- `test/test_serial_port/test_serial_port.cpp`: Adjust to changed
fetching of lines. The end of line character is omitted now.
- `test/test_string_helpers/test_string_helpers.cpp`: Unit test for
string helpers.
  • Loading branch information
dhebbeker authored Dec 17, 2023
2 parents ce1defd + 0626893 commit 1647566
Show file tree
Hide file tree
Showing 12 changed files with 822 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/platformio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ jobs:
run: platformio test --verbose --environment test_native_tasks
- name: On native platform run tests for 'serial_port'
run: platformio test --verbose --environment test_native_serial_port

- name: On native platform run tests for 'command line interpreter'
run: platformio test --verbose --environment test_native_cli
- name: On native platform run tests for 'string_helpers'
run: platformio test --verbose --environment test_native_string_helpers
10 changes: 8 additions & 2 deletions lib/3rd_party_adapters/serial_port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,19 @@ void serialEvent()
{
static serial_port::String inputBuffer{};
const serial_port::String::value_type inChar = inData;
inputBuffer += inChar;
// if the incoming character is a newline, call handler
if (inChar == '\n' || inChar == '\r')
{
serial_port::incomingStringHandler(inputBuffer);
if (!inputBuffer.empty())
{
serial_port::incomingStringHandler(inputBuffer);
}
inputBuffer.clear();
}
else
{
inputBuffer += inChar;
}
}
}
}
58 changes: 58 additions & 0 deletions lib/application_business_rules/Protocol.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "Protocol.hpp"
#include "command_line_interpreter.hpp"
#include "serial_port.hpp"
#include <array>

namespace cli = command_line_interpreter;

// --------------------------
// --- define commands ------
// --------------------------
#include <string>

// command for list
static const auto list = []() { serial_port::cout << "this is a list: a, b, c, ..." << std::endl; };
static const auto listCmd = cli::makeCommand("list", std::function(list));

// command for edit
static const auto edit = [](const int id, const std::basic_string<ProtocolHandler::CharType> label, const int duration) {
serial_port::cout << "Edit id(" << id << ") label('" << label << "') duration(" << duration << ")" << std::endl;
};
static const cli::Option<int> id = {.labels = {"--id"}, .defaultValue = 0};
static const cli::Option<std::basic_string<ProtocolHandler::CharType>> label = {.labels = {"--name"}, .defaultValue = "foo"};
static const cli::Option<int> duration = {.labels = {"--duration"}, .defaultValue = 0};
static const auto editCmd = cli::makeCommand("edit", std::function(edit), std::make_tuple(&id, &label, &duration));

static const std::array<const cli::BaseCommand<char> *, 2> commands = {&listCmd, &editCmd};

bool ProtocolHandler::execute(const CharType *const commandLine)
{
for (const auto command : commands)
{
try
{
const bool executed = command->execute(commandLine);
if (executed)
{
return executed;
}
}
catch (const std::runtime_error &e)
{
serial_port::cout << e.what() << std::endl;
serial_port::cout << command->generateHelpMessage() << std::endl;
}
}

// if we arrive here, no command has been executed
if (!commands.empty())
{
serial_port::cout << "No command has been executed!" << std::endl
<< "Possible commands are:" << std::endl;
for (const auto command : commands)
{
serial_port::cout << "\t " << command->commandName << std::endl;
}
}
return false;
}
8 changes: 8 additions & 0 deletions lib/application_business_rules/Protocol.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

class ProtocolHandler
{
public:
typedef char CharType;
static bool execute(const CharType *const commandLine);
};
Loading

0 comments on commit 1647566

Please sign in to comment.