Switch parser to self contained task class

This commit is contained in:
GHOSCHT 2023-03-30 17:53:56 +02:00
parent 076ee11c92
commit 9ebf41739e
2 changed files with 123 additions and 214 deletions

View file

@ -1,58 +1,23 @@
#include "Parser.h"
#include <FreeRTOS/Util.h>
#include <PinMap/PinMap.h>
#include <etl/vector.h>
message::parser::StateVisitor::StateVisitor(
etl::byte_stream_reader &&sreader,
etl::function<void, etl::string_view> invalidCallback,
etl::function<void, etl::span<const char>> messageLightDataCallback,
etl::function<void, etl::span<const char>> messageInfoCallback,
etl::function<void, etl::span<const char>> messageWarningCallback,
etl::function<void, etl::span<const char>> messageErrorCallback,
etl::function<void, etl::span<const char>> messageSuccessCallback,
etl::function<void, uint32_t> settingsSetBaudCallback,
etl::function<void, etl::span<const char>> settingsWifiPasswordCallback,
etl::function<void, etl::span<const char>> settingsWifiSSIDCallback,
etl::function<void, void> lightControlOnCallback,
etl::function<void, void> lightControlOffCallback,
etl::function<void, uint8_t> lightControlToggleCallback,
etl::function<void, uint8_t> lightControlIncreaseCallback,
etl::function<void, uint8_t> lightControlDecreaseCallback,
etl::function<void, void> commandRequestLightDataCallback,
etl::function<void, void> commandEnterConsoleFlashingCallback,
etl::function<void, void> commandExitConsoleFlashingCallback,
etl::function<void, void> commandPairBluetoothCallback,
etl::function<void, void> commandHelpCallback,
etl::function<void, void> commandVersionCallback)
: stream{etl::move(sreader)}, invalidCallback{invalidCallback},
messageLightDataCallback{messageLightDataCallback},
messageInfoCallback{messageInfoCallback},
messageWarningCallback{messageWarningCallback},
messageErrorCallback{messageErrorCallback},
messageSuccessCallback{messageSuccessCallback},
settingsSetBaudCallback{settingsSetBaudCallback},
settingsWifiPasswordCallback{settingsWifiPasswordCallback},
settingsWifiSSIDCallback{settingsWifiSSIDCallback},
lightControlOnCallback{lightControlOnCallback},
lightControlOffCallback{lightControlOffCallback},
lightControlToggleCallback{lightControlToggleCallback},
lightControlIncreaseCallback{lightControlIncreaseCallback},
lightControlDecreaseCallback{lightControlDecreaseCallback},
commandRequestLightDataCallback{commandRequestLightDataCallback},
commandEnterConsoleFlashingCallback{commandEnterConsoleFlashingCallback},
commandExitConsoleFlashingCallback{commandExitConsoleFlashingCallback},
commandPairBluetoothCallback{commandPairBluetoothCallback},
commandHelpCallback{commandHelpCallback}, commandVersionCallback{
commandVersionCallback} {}
message::Message *message,
freertos::Queue<LightController::LightAction> &lightActionQueue)
: stream{message->first.begin(), message->first.size(), etl::endian::big},
message{message}, lightActionQueue{lightActionQueue} {}
auto message::parser::StateVisitor::operator()(state::ModeSelection) -> State {
if (!stream.available<uint8_t>()) {
invalidCallback("ModeSelection: Stream not available");
// invalidCallback("ModeSelection: Stream not available");
return state::Invalid{};
}
auto mode = stream.read<uint8_t>();
if (!mode.has_value()) {
invalidCallback("ModeSelection: Mode has no value");
// invalidCallback("ModeSelection: Mode has no value");
return state::Invalid{};
}
@ -66,20 +31,20 @@ auto message::parser::StateVisitor::operator()(state::ModeSelection) -> State {
case static_cast<uint8_t>(protocol::Mode::Command):
return state::Command{};
default:
invalidCallback("ModeSelection: Invalid index");
// invalidCallback("ModeSelection: Invalid index");
return state::Invalid{};
}
}
auto message::parser::StateVisitor::operator()(state::Message) -> State {
if (!stream.available<uint8_t>()) {
invalidCallback("Message: Stream not available");
// invalidCallback("Message: Stream not available");
return state::Invalid{};
}
auto mode = stream.read<uint8_t>();
if (!mode.has_value()) {
invalidCallback("Message: Mode has no value");
// invalidCallback("Message: Mode has no value");
return state::Invalid{};
}
@ -95,7 +60,7 @@ auto message::parser::StateVisitor::operator()(state::Message) -> State {
case static_cast<uint8_t>(protocol::Message::Success):
return state::MessageSuccess{};
default:
invalidCallback("Message: Invalid index");
// invalidCallback("Message: Invalid index");
return state::Invalid{};
}
}
@ -103,84 +68,84 @@ auto message::parser::StateVisitor::operator()(state::Message) -> State {
auto message::parser::StateVisitor::operator()(state::MessageLightData)
-> State {
if (!stream.available<char>()) {
invalidCallback("MessageLightData: Stream not available");
// invalidCallback("MessageLightData: Stream not available");
return state::Invalid{};
}
auto msg = stream.read<char>(stream.available<char>());
if (!msg.has_value()) {
invalidCallback("MessageLightData: Message has no value");
// invalidCallback("MessageLightData: Message has no value");
return state::Invalid{};
}
messageLightDataCallback(msg.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::MessageInfo) -> State {
if (!stream.available<char>()) {
invalidCallback("MessageInfo: Stream not available");
// invalidCallback("MessageInfo: Stream not available");
return state::Invalid{};
}
auto msg = stream.read<char>(stream.available<char>());
if (!msg.has_value()) {
invalidCallback("MessageInfo: Message has no value");
// invalidCallback("MessageInfo: Message has no value");
return state::Invalid{};
}
messageInfoCallback(msg.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::MessageWarning) -> State {
if (!stream.available<char>()) {
invalidCallback("MessageWarning: Stream not available");
// invalidCallback("MessageWarning: Stream not available");
return state::Invalid{};
}
auto msg = stream.read<char>(stream.available<char>());
if (!msg.has_value()) {
invalidCallback("MessageWarning: Message has no value");
// invalidCallback("MessageWarning: Message has no value");
return state::Invalid{};
}
messageWarningCallback(msg.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::MessageError) -> State {
if (!stream.available<char>()) {
invalidCallback("MessageError: Stream not available");
// invalidCallback("MessageError: Stream not available");
return state::Invalid{};
}
auto msg = stream.read<char>(stream.available<char>());
if (!msg.has_value()) {
invalidCallback("MessageError: Message has no value");
// invalidCallback("MessageError: Message has no value");
return state::Invalid{};
}
messageErrorCallback(msg.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::MessageSuccess) -> State {
if (!stream.available<char>()) {
invalidCallback("MessageSuccess: Stream not available");
// invalidCallback("MessageSuccess: Stream not available");
return state::Invalid{};
}
auto msg = stream.read<char>(stream.available<char>());
if (!msg.has_value()) {
invalidCallback("MessageSuccess: Message has no value");
// invalidCallback("MessageSuccess: Message has no value");
return state::Invalid{};
}
messageSuccessCallback(msg.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::Settings) -> State {
if (!stream.available<uint8_t>()) {
invalidCallback("Settings: Stream not available");
// invalidCallback("Settings: Stream not available");
return state::Invalid{};
}
auto mode = stream.read<uint8_t>();
if (!mode.has_value()) {
invalidCallback("Settings: Mode has no value");
// invalidCallback("Settings: Mode has no value");
return state::Invalid{};
}
@ -192,69 +157,66 @@ auto message::parser::StateVisitor::operator()(state::Settings) -> State {
case static_cast<uint8_t>(protocol::Settings::SetWifiSSID):
return state::SettingsWifiSSID{};
default:
invalidCallback("Settings: Invalid index");
// invalidCallback("Settings: Invalid index");
return state::Invalid{};
}
}
auto message::parser::StateVisitor::operator()(state::SettingsSetBaud)
-> State {
if (!stream.available<uint32_t>()) {
invalidCallback("Settings: Stream not available");
// invalidCallback("Settings: Stream not available");
return state::Invalid{};
}
auto baud = stream.read<uint32_t>();
if (!baud.has_value()) {
invalidCallback("SettingsSetBaud: Baud has no value");
// invalidCallback("SettingsSetBaud: Baud has no value");
return state::Invalid{};
}
settingsSetBaudCallback(baud.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::SettingsWifiPassword)
-> State {
if (!stream.available<char>()) {
invalidCallback("SettingsWifiPassword: Stream not available");
// invalidCallback("SettingsWifiPassword: Stream not available");
return state::Invalid{};
}
auto passwd = stream.read<char>(stream.available<char>());
if (!passwd.has_value()) {
invalidCallback("SettingsWifiPassword: Passwd has no value");
// invalidCallback("SettingsWifiPassword: Passwd has no value");
return state::Invalid{};
}
settingsWifiPasswordCallback(passwd.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::SettingsWifiSSID)
-> State {
if (!stream.available<char>()) {
invalidCallback("SettingsWifiSSID: Stream not available");
// invalidCallback("SettingsWifiSSID: Stream not available");
return state::Invalid{};
}
auto ssid = stream.read<char>(stream.available<char>());
if (!ssid.has_value()) {
invalidCallback("SettingsWifiSSID: SSID has no value");
// invalidCallback("SettingsWifiSSID: SSID has no value");
return state::Invalid{};
}
settingsWifiSSIDCallback(ssid.value());
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::LightControl) -> State {
if (!stream.available<uint8_t>()) {
invalidCallback("LightControl: Stream not available");
// invalidCallback("LightControl: Stream not available");
return state::Invalid{};
}
auto mode = stream.read<uint8_t>();
if (!mode.has_value()) {
invalidCallback("LightControl: Mode has no value");
// invalidCallback("LightControl: Mode has no value");
return state::Invalid{};
}
@ -270,83 +232,92 @@ auto message::parser::StateVisitor::operator()(state::LightControl) -> State {
case static_cast<uint8_t>(protocol::LightControl::Decrease):
return state::LightControlDecrease{};
default:
invalidCallback("LightControl: Invalid index");
// invalidCallback("LightControl: Invalid index");
return state::Invalid{};
}
}
auto message::parser::StateVisitor::operator()(state::LightControlOn) -> State {
if (stream.available_bytes() > 0) {
invalidCallback("LightControlOn: Too many bytes left");
// invalidCallback("LightControlOn: Too many bytes left");
return state::Invalid{};
}
lightControlOnCallback();
message->second.give();
Serial.println("ON");
lightActionQueue.push({LightController::LightActionType::ON, etl::nullopt});
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::LightControlOff)
-> State {
if (stream.available_bytes() > 0) {
invalidCallback("LightControlOff: Too many bytes left");
// invalidCallback("LightControlOff: Too many bytes left");
return state::Invalid{};
}
lightControlOffCallback();
message->second.give();
Serial.println("OFF");
lightActionQueue.push({LightController::LightActionType::OFF, etl::nullopt});
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::LightControlToggle)
-> State {
if (stream.available_bytes() > 1) {
invalidCallback("LightControlToggle: Too many bytes left");
// invalidCallback("LightControlToggle: Too many bytes left");
return state::Invalid{};
} else if (!stream.available<uint8_t>()) {
invalidCallback("LightControlToggle: Stream not available");
// invalidCallback("LightControlToggle: Stream not available");
return state::Invalid{};
}
auto id = stream.read<uint8_t>();
lightControlToggleCallback(id.value());
message->second.give();
Serial.println("Toggle");
lightActionQueue.push({LightController::LightActionType::TOGGLE, id});
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::LightControlIncrease)
-> State {
if (stream.available_bytes() > 1) {
invalidCallback("LightControlIncrease: Too many bytes left");
// invalidCallback("LightControlIncrease: Too many bytes left");
return state::Invalid{};
} else if (!stream.available<uint8_t>()) {
invalidCallback("LightControlIncrease: Stream not available");
// invalidCallback("LightControlIncrease: Stream not available");
return state::Invalid{};
}
auto id = stream.read<uint8_t>();
lightControlIncreaseCallback(id.value());
message->second.give();
Serial.println("Increase");
lightActionQueue.push({LightController::LightActionType::INCREASE, id});
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::LightControlDecrease)
-> State {
if (stream.available_bytes() > 1) {
invalidCallback("LightControlDecrease: Too many bytes left");
// invalidCallback("LightControlDecrease: Too many bytes left");
return state::Invalid{};
} else if (!stream.available<uint8_t>()) {
invalidCallback("LightControlDecrease: Stream not available");
// invalidCallback("LightControlDecrease: Stream not available");
return state::Invalid{};
}
auto id = stream.read<uint8_t>();
lightControlDecreaseCallback(id.value());
message->second.give();
Serial.println("Decrease");
lightActionQueue.push({LightController::LightActionType::DECREASE, id});
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::Command) -> State {
if (!stream.available<uint8_t>()) {
invalidCallback("Command: Stream not available");
// invalidCallback("Command: Stream not available");
return state::Invalid{};
}
auto mode = stream.read<uint8_t>();
if (!mode.has_value()) {
invalidCallback("Command: Mode has no value");
// invalidCallback("Command: Mode has no value");
return state::Invalid{};
}
@ -364,58 +335,56 @@ auto message::parser::StateVisitor::operator()(state::Command) -> State {
case static_cast<uint8_t>(protocol::Command::Version):
return state::CommandVersion{};
default:
invalidCallback("Command: Invalid index");
// invalidCallback("Command: Invalid index");
return state::Invalid{};
}
}
auto message::parser::StateVisitor::operator()(state::CommandRequestLightData)
-> State {
commandRequestLightDataCallback();
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(
state::CommandEnterConsoleFlashing) -> State {
if (stream.available_bytes() > 0) {
invalidCallback("CommandEnterConsoleFlashing: Too many bytes left");
// invalidCallback("CommandEnterConsoleFlashing: Too many bytes left");
return state::Invalid{};
}
commandEnterConsoleFlashingCallback();
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(
state::CommandExitConsoleFlashing) -> State {
if (stream.available_bytes() > 0) {
invalidCallback("CommandExitConsoleFlashing: Too many bytes left");
// invalidCallback("CommandExitConsoleFlashing: Too many bytes left");
return state::Invalid{};
}
commandExitConsoleFlashingCallback();
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::CommandPairBluetooth)
-> State {
if (stream.available_bytes() > 0) {
invalidCallback("CommandPairBluetooth: Too many bytes left");
// invalidCallback("CommandPairBluetooth: Too many bytes left");
return state::Invalid{};
}
commandPairBluetoothCallback();
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::CommandHelp) -> State {
if (stream.available_bytes() > 0) {
invalidCallback("CommandHelp: Too many bytes left");
// invalidCallback("CommandHelp: Too many bytes left");
return state::Invalid{};
}
commandHelpCallback();
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::CommandVersion) -> State {
if (stream.available_bytes() > 0) {
invalidCallback("CommandVersion: Too many bytes left");
// invalidCallback("CommandVersion: Too many bytes left");
return state::Invalid{};
}
commandVersionCallback();
return state::Complete{};
}
@ -423,55 +392,36 @@ auto message::parser::StateVisitor::operator()(state::Complete) -> State {
return state::Complete{};
}
auto message::parser::StateVisitor::operator()(state::Invalid) -> State {
message->second.give();
return state::Invalid{};
}
auto message::parser::parse(
etl::byte_stream_reader &&reader,
etl::function<void, etl::string_view> invalidCallback,
etl::function<void, etl::span<const char>> messageLightDataCallback,
etl::function<void, etl::span<const char>> messageInfoCallback,
etl::function<void, etl::span<const char>> messageWarningCallback,
etl::function<void, etl::span<const char>> messageErrorCallback,
etl::function<void, etl::span<const char>> messageSuccessCallback,
etl::function<void, uint32_t> settingsSetBaudCallback,
etl::function<void, etl::span<const char>> settingsWifiPasswordCallback,
etl::function<void, etl::span<const char>> settingsWifiSSIDCallback,
etl::function<void, void> lightControlOnCallback,
etl::function<void, void> lightControlOffCallback,
etl::function<void, uint8_t> lightControlToggleCallback,
etl::function<void, uint8_t> lightControlIncreaseCallback,
etl::function<void, uint8_t> lightControlDecreaseCallback,
etl::function<void, void> commandRequestLightDataCallback,
etl::function<void, void> commandEnterConsoleFlashingCallback,
etl::function<void, void> commandExitConsoleFlashingCallback,
etl::function<void, void> commandPairBluetoothCallback,
etl::function<void, void> commandHelpCallback,
etl::function<void, void> commandVersionCallback) -> void {
StateVisitor visitor{etl::move(reader),
invalidCallback,
messageLightDataCallback,
messageInfoCallback,
messageWarningCallback,
messageErrorCallback,
messageSuccessCallback,
settingsSetBaudCallback,
settingsWifiPasswordCallback,
settingsWifiSSIDCallback,
lightControlOnCallback,
lightControlOffCallback,
lightControlToggleCallback,
lightControlIncreaseCallback,
lightControlDecreaseCallback,
commandRequestLightDataCallback,
commandEnterConsoleFlashingCallback,
commandExitConsoleFlashingCallback,
commandPairBluetoothCallback,
commandHelpCallback,
commandVersionCallback};
message::Message *message,
freertos::Queue<LightController::LightAction> &lightActionQueue) -> void {
StateVisitor visitor{message, lightActionQueue};
State state{state::ModeSelection{}};
while (!etl::holds_alternative<state::Invalid>(state) &&
!etl::holds_alternative<state::Complete>(state)) {
state = etl::visit(visitor, state);
}
}
message::parser::Parser::Parser(
freertos::Queue<LightController::LightAction> &lightActionQueue,
UBaseType_t queueCapacity, UBaseType_t priority, BaseType_t coreID)
: parserTask{exec, "parse received data", stackDepth, this, priority,
coreID},
messages{queueCapacity}, lightActionQueue{lightActionQueue} {}
void message::parser::Parser::exec(void *parserPtr) {
Parser *parser = static_cast<Parser *>(parserPtr);
while (true) {
auto message = parser->messages.pop();
Serial.println("starting parse");
if (message.has_value()) {
parse(message.value(), parser->lightActionQueue);
}
}
}

View file

@ -1,5 +1,9 @@
#pragma once
#include "Protocol.h"
#include <FreeRTOS/Queue.h>
#include <FreeRTOS/Task.h>
#include <LightController/Controller.h>
#include <Messages/Message.h>
#include <etl/byte_stream.h>
#include <etl/function.h>
#include <etl/span.h>
@ -49,53 +53,13 @@ using State = etl::variant<
state::CommandExitConsoleFlashing, state::CommandPairBluetooth,
state::CommandHelp, state::CommandVersion, state::Complete>;
void parse(
etl::byte_stream_reader &&reader,
etl::function<void, etl::string_view> invalidCallback,
etl::function<void, etl::span<const char>> messageLightDataCallback,
etl::function<void, etl::span<const char>> messageInfoCallback,
etl::function<void, etl::span<const char>> messageWarningCallback,
etl::function<void, etl::span<const char>> messageErrorCallback,
etl::function<void, etl::span<const char>> messageSuccessCallback,
etl::function<void, uint32_t> settingsSetBaudCallback,
etl::function<void, etl::span<const char>> settingsWifiPasswordCallback,
etl::function<void, etl::span<const char>> settingsWifiSSIDCallback,
etl::function<void, void> lightControlOnCallback,
etl::function<void, void> lightControlOffCallback,
etl::function<void, uint8_t> lightControlToggleCallback,
etl::function<void, uint8_t> lightControlIncreaseCallback,
etl::function<void, uint8_t> lightControlDecreaseCallback,
etl::function<void, void> commandRequestLightDataCallback,
etl::function<void, void> commandEnterConsoleFlashingCallback,
etl::function<void, void> commandExitConsoleFlashingCallback,
etl::function<void, void> commandPairBluetoothCallback,
etl::function<void, void> commandHelpCallback,
etl::function<void, void> commandVersionCallback);
void parse(message::Message *message,
freertos::Queue<LightController::LightAction> &lightActionQueue);
class StateVisitor {
public:
StateVisitor(
etl::byte_stream_reader &&sreader,
etl::function<void, etl::string_view> invalidCallback,
etl::function<void, etl::span<const char>> messageLightDataCallback,
etl::function<void, etl::span<const char>> messageInfoCallback,
etl::function<void, etl::span<const char>> messageWarningCallback,
etl::function<void, etl::span<const char>> messageErrorCallback,
etl::function<void, etl::span<const char>> messageSuccessCallback,
etl::function<void, uint32_t> settingsSetBaudCallback,
etl::function<void, etl::span<const char>> settingsWifiPasswordCallback,
etl::function<void, etl::span<const char>> settingsWifiSSIDCallback,
etl::function<void, void> lightControlOnCallback,
etl::function<void, void> lightControlOffCallback,
etl::function<void, uint8_t> lightControlToggleCallback,
etl::function<void, uint8_t> lightControlIncreaseCallback,
etl::function<void, uint8_t> lightControlDecreaseCallback,
etl::function<void, void> commandRequestLightDataCallback,
etl::function<void, void> commandEnterConsoleFlashingCallback,
etl::function<void, void> commandExitConsoleFlashingCallback,
etl::function<void, void> commandPairBluetoothCallback,
etl::function<void, void> commandHelpCallback,
etl::function<void, void> commandVersionCallback);
StateVisitor(message::Message *message,
freertos::Queue<LightController::LightAction> &lightActionQueue);
State operator()(state::ModeSelection);
State operator()(state::Message);
State operator()(state::MessageLightData);
@ -128,27 +92,22 @@ public:
private:
etl::byte_stream_reader stream;
// TODO: callback function parameter types
etl::function<void, etl::string_view> invalidCallback;
etl::function<void, etl::span<const char>> messageLightDataCallback;
etl::function<void, etl::span<const char>> messageInfoCallback;
etl::function<void, etl::span<const char>> messageWarningCallback;
etl::function<void, etl::span<const char>> messageErrorCallback;
etl::function<void, etl::span<const char>> messageSuccessCallback;
etl::function<void, uint32_t> settingsSetBaudCallback;
etl::function<void, etl::span<const char>> settingsWifiPasswordCallback;
etl::function<void, etl::span<const char>> settingsWifiSSIDCallback;
etl::function<void, void> lightControlOnCallback;
etl::function<void, void> lightControlOffCallback;
etl::function<void, uint8_t> lightControlToggleCallback;
etl::function<void, uint8_t> lightControlIncreaseCallback;
etl::function<void, uint8_t> lightControlDecreaseCallback;
etl::function<void, void> commandRequestLightDataCallback;
etl::function<void, void> commandEnterConsoleFlashingCallback;
etl::function<void, void> commandExitConsoleFlashingCallback;
etl::function<void, void> commandPairBluetoothCallback;
etl::function<void, void> commandHelpCallback;
etl::function<void, void> commandVersionCallback;
message::Message *message;
freertos::Queue<LightController::LightAction> &lightActionQueue;
};
class Parser {
public:
Parser(freertos::Queue<LightController::LightAction> &lightActionQueue,
UBaseType_t queueCapacity, UBaseType_t priority, BaseType_t coreID);
freertos::Queue<message::Message *> &getMessageQueue() { return messages; }
private:
static void exec(void *parserPtr);
freertos::Task parserTask;
static const uint32_t stackDepth = 2048;
freertos::Queue<message::Message *> messages;
freertos::Queue<LightController::LightAction> &lightActionQueue;
};
} // namespace parser
} // namespace message