From 5c9341f7c4820b77c97434303e537a1676708289 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:41:56 -0500 Subject: [PATCH 01/36] (#387): Starting to breakout GPAP protocol functionality --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 26 ++++++++++++++ Firmware/GPAD_API/GPAD_API/protocol.h | 46 +++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 Firmware/GPAD_API/GPAD_API/protocol.cpp create mode 100644 Firmware/GPAD_API/GPAD_API/protocol.h diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp new file mode 100644 index 00000000..c3eac07a --- /dev/null +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -0,0 +1,26 @@ +#include + +using namespace protocol; + +const AlarmLevel DEFAULT_ALARM_LEVEL = AlarmLevel::Level1; + +AlarmCommand::AlarmCommand() : level(DEFAULT_ALARM_LEVEL) +{ +} + +AlarmCommand::AlarmCommand(AlarmLevel level) : level(level) {} + +AlarmCommand AlarmCommand::deserialize() +{ + AlarmLevel level = AlarmLevel::Level1; + return AlarmCommand(level); +} + +InfoCommand::InfoCommand() +{ +} + +InfoCommand InfoCommand::deserialize() +{ + return InfoCommand(); +} diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h new file mode 100644 index 00000000..fb5dc4ca --- /dev/null +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -0,0 +1,46 @@ +#ifndef _PROTOCOL_H +#define _PROTOCOL_H + +namespace protocol +{ + enum class CommandType : char + { + MUTE = 's', + UNMUTE = 'u', + HELP = 'h', + ALARM = 'a', + INFO = 'i', + }; + + enum class AlarmLevel : char + { + Level1 = 1, + Level2 = 2, + Level3 = 3, + Level4 = 4, + Level5 = 5, + }; + + class AlarmCommand + { + private: + AlarmLevel level; + + explicit AlarmCommand(); + explicit AlarmCommand(AlarmLevel level); + + public: + static AlarmCommand deserialize(); + }; + + class InfoCommand + { + private: + explicit InfoCommand(); + + public: + static InfoCommand deserialize(); + }; +} + +#endif From 8bec1d58df0ae478db9a1a57f04d654ce75c2c5a Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Tue, 3 Mar 2026 21:22:36 -0500 Subject: [PATCH 02/36] (#387): Added more constructors/deserialization methods --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 40 +++++++++++++++++------ Firmware/GPAD_API/GPAD_API/protocol.h | 43 ++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index c3eac07a..ded0bb0d 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -2,25 +2,45 @@ using namespace protocol; -const AlarmLevel DEFAULT_ALARM_LEVEL = AlarmLevel::Level1; +AlarmCommand::AlarmCommand(AlarmLevel alarmLevel, const char *const alarmMessage) : level(alarmLevel), alarm(alarmMessage) {} -AlarmCommand::AlarmCommand() : level(DEFAULT_ALARM_LEVEL) -{ -} - -AlarmCommand::AlarmCommand(AlarmLevel level) : level(level) {} - -AlarmCommand AlarmCommand::deserialize() +AlarmCommand AlarmCommand::deserialize(const char *const messageBytes) { AlarmLevel level = AlarmLevel::Level1; - return AlarmCommand(level); + return AlarmCommand(level, messageBytes); } InfoCommand::InfoCommand() { } -InfoCommand InfoCommand::deserialize() +InfoCommand InfoCommand::deserialize(const char *const messageBytes) { return InfoCommand(); } + +Command::Command(const InfoCommand infoCommand) : info(infoCommand) {} +Command::Command(const AlarmCommand alarmCommand) : alarm(alarmCommand) {} + +ProtocolMessage::ProtocolMessage(CommandType commandType, Command command) : commandType(commandType), command(command) {} + +ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes) +{ + CommandType commandType = static_cast(messageBytes[0]); + + const char *const remainingBytes = messageBytes + 1; + Command command = [commandType, remainingBytes]() + { + switch (commandType) + { + case CommandType::ALARM: + return Command(AlarmCommand::deserialize(remainingBytes)); + case CommandType::INFO: + return Command(InfoCommand::deserialize(remainingBytes)); + } + }(); + + Command command = Command(InfoCommand()); + + return ProtocolMessage(commandType, command); +} \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index fb5dc4ca..6407238c 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -3,6 +3,9 @@ namespace protocol { + union Command; + class ProtocolMessage; + enum class CommandType : char { MUTE = 's', @@ -23,23 +26,53 @@ namespace protocol class AlarmCommand { + private: - AlarmLevel level; + friend union Command; - explicit AlarmCommand(); - explicit AlarmCommand(AlarmLevel level); + private: + AlarmLevel level; + const char const *alarm; public: - static AlarmCommand deserialize(); + explicit AlarmCommand(AlarmLevel level, const char *const alarmMessage); + static AlarmCommand deserialize(const char *const messageBytes); }; class InfoCommand { private: + friend union Command; + friend class ProtocolMessage; + + public: explicit InfoCommand(); + static InfoCommand deserialize(const char *const messageBytes); + }; + + union Command + { + AlarmCommand alarm; + InfoCommand info; + + public: + explicit Command(const InfoCommand infoCommand); + explicit Command(const AlarmCommand alarmCommand); + }; + + class ProtocolMessage + { + // Methods + private: + explicit ProtocolMessage(CommandType commandType, Command command); + + // Data members + private: + CommandType commandType; + Command command; public: - static InfoCommand deserialize(); + static ProtocolMessage deserialize(const char *const messageBytes); }; } From da6522480589d6cd7b3ac5d4face9a8e35434945 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sat, 7 Mar 2026 11:59:32 -0500 Subject: [PATCH 03/36] (#387): Compiles with creating a new 'default' ProcotolMessage in the deserialize function --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 30 +++--------- Firmware/GPAD_API/GPAD_API/protocol.h | 63 ++++++++++++++++--------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index ded0bb0d..3a93a7e1 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -2,12 +2,12 @@ using namespace protocol; -AlarmCommand::AlarmCommand(AlarmLevel alarmLevel, const char *const alarmMessage) : level(alarmLevel), alarm(alarmMessage) {} +AlarmCommand::AlarmCommand(AlarmLevel alarmLevel, std::array alarmMessage) : level(alarmLevel), message(alarmMessage) {} AlarmCommand AlarmCommand::deserialize(const char *const messageBytes) { AlarmLevel level = AlarmLevel::Level1; - return AlarmCommand(level, messageBytes); + return AlarmCommand(level, std::array()); } InfoCommand::InfoCommand() @@ -19,28 +19,10 @@ InfoCommand InfoCommand::deserialize(const char *const messageBytes) return InfoCommand(); } -Command::Command(const InfoCommand infoCommand) : info(infoCommand) {} -Command::Command(const AlarmCommand alarmCommand) : alarm(alarmCommand) {} - -ProtocolMessage::ProtocolMessage(CommandType commandType, Command command) : commandType(commandType), command(command) {} - -ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes) +const ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes) { - CommandType commandType = static_cast(messageBytes[0]); - - const char *const remainingBytes = messageBytes + 1; - Command command = [commandType, remainingBytes]() - { - switch (commandType) - { - case CommandType::ALARM: - return Command(AlarmCommand::deserialize(remainingBytes)); - case CommandType::INFO: - return Command(InfoCommand::deserialize(remainingBytes)); - } - }(); - - Command command = Command(InfoCommand()); + ProtocolMessage protocolMessage = ProtocolMessage(); + protocolMessage.info = InfoCommand(); - return ProtocolMessage(commandType, command); + return protocolMessage; } \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 6407238c..4c329eb0 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -1,6 +1,8 @@ #ifndef _PROTOCOL_H #define _PROTOCOL_H +#include + namespace protocol { union Command; @@ -28,51 +30,66 @@ namespace protocol { private: - friend union Command; + AlarmCommand(); + friend struct ProtocolMessage; private: AlarmLevel level; - const char const *alarm; + std::array message; public: - explicit AlarmCommand(AlarmLevel level, const char *const alarmMessage); + explicit AlarmCommand(AlarmLevel level, std::array message); + + AlarmCommand(AlarmCommand &&other) = default; + AlarmCommand operator=(AlarmCommand &&other) + { + return std::move(other); + } + AlarmCommand(AlarmCommand &other) = delete; + static AlarmCommand deserialize(const char *const messageBytes); }; class InfoCommand { private: - friend union Command; - friend class ProtocolMessage; + InfoCommand(); + friend struct ProtocolMessage; public: - explicit InfoCommand(); + InfoCommand(InfoCommand &&other) = default; + InfoCommand operator=(InfoCommand &&other) + { + return std::move(other); + } + InfoCommand(InfoCommand &other) = delete; + static InfoCommand deserialize(const char *const messageBytes); }; - union Command + struct ProtocolMessage final { - AlarmCommand alarm; - InfoCommand info; + private: + enum + { + ALARM, + INFO + } command; + + union + { + AlarmCommand alarm; + InfoCommand info; + }; public: - explicit Command(const InfoCommand infoCommand); - explicit Command(const AlarmCommand alarmCommand); - }; + ProtocolMessage(ProtocolMessage &&other) = default; - class ProtocolMessage - { - // Methods - private: - explicit ProtocolMessage(CommandType commandType, Command command); + ProtocolMessage(ProtocolMessage &other) = delete; + static const ProtocolMessage deserialize(const char *const messageBytes); - // Data members private: - CommandType commandType; - Command command; - - public: - static ProtocolMessage deserialize(const char *const messageBytes); + ProtocolMessage(); }; } From 649a45820287c2515bc86178ff69f6db24ab1d27 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sat, 7 Mar 2026 12:38:39 -0500 Subject: [PATCH 04/36] (#387): Improved layout of class members and methods - The union in the ProtocolMessage is now const - This means the individual fields don't have to be const which makes the implementation a lot cleaner - The fields inside the AlarmCommand are const - Now instances of the AlarmCommand don't need to be const, the fields are always const, which it should be - The contents of an AlarmCommand should never change --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 21 +++++++-- Firmware/GPAD_API/GPAD_API/protocol.h | 63 ++++++++++++++----------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 3a93a7e1..5ee1541a 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -2,11 +2,14 @@ using namespace protocol; -AlarmCommand::AlarmCommand(AlarmLevel alarmLevel, std::array alarmMessage) : level(alarmLevel), message(alarmMessage) {} +AlarmCommand::AlarmCommand(const AlarmCommand::Level alarmLevel, const std::array alarmMessage) : level(alarmLevel), message(alarmMessage) {} AlarmCommand AlarmCommand::deserialize(const char *const messageBytes) { - AlarmLevel level = AlarmLevel::Level1; + // TODO: Throw error if there is no 0th element; + const auto level = static_cast(messageBytes[0]); + + const auto level = AlarmCommand::Level::Level1; return AlarmCommand(level, std::array()); } @@ -21,8 +24,16 @@ InfoCommand InfoCommand::deserialize(const char *const messageBytes) const ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes) { - ProtocolMessage protocolMessage = ProtocolMessage(); - protocolMessage.info = InfoCommand(); + // TODO: This should be wrapped in a try/catch if there isn't a 0th element + auto commandType = static_cast(messageBytes[0]); + + auto remainingBytes = messageBytes + 1; - return protocolMessage; + switch (commandType) + { + case CommandType::ALARM: + return ProtocolMessage(AlarmCommand::deserialize(remainingBytes)); + case CommandType::INFO: + return ProtocolMessage(InfoCommand::deserialize(remainingBytes)); + } } \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 4c329eb0..c6feaae7 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -17,75 +17,82 @@ namespace protocol INFO = 'i', }; - enum class AlarmLevel : char - { - Level1 = 1, - Level2 = 2, - Level3 = 3, - Level4 = 4, - Level5 = 5, - }; - class AlarmCommand { + public: + enum class Level : char + { + Level1 = 1, + Level2 = 2, + Level3 = 3, + Level4 = 4, + Level5 = 5, + }; + private: - AlarmCommand(); - friend struct ProtocolMessage; + const Level level; + const std::array message; private: - AlarmLevel level; - std::array message; + friend struct ProtocolMessage; + + // TODO: Throw error if the message cannot be deserialized from the bytes + static AlarmCommand deserialize(const char *const messageBytes); public: - explicit AlarmCommand(AlarmLevel level, std::array message); + explicit AlarmCommand(const Level level, const std::array message); AlarmCommand(AlarmCommand &&other) = default; - AlarmCommand operator=(AlarmCommand &&other) + AlarmCommand operator=(AlarmCommand &&other) noexcept { return std::move(other); } + AlarmCommand() = delete; AlarmCommand(AlarmCommand &other) = delete; - - static AlarmCommand deserialize(const char *const messageBytes); }; class InfoCommand { private: - InfoCommand(); friend struct ProtocolMessage; + InfoCommand(); + // TODO: Throw error if the message cannot be deserialized from the bytes + static InfoCommand deserialize(const char *const messageBytes); + public: InfoCommand(InfoCommand &&other) = default; - InfoCommand operator=(InfoCommand &&other) + InfoCommand operator=(InfoCommand &&other) noexcept { return std::move(other); } InfoCommand(InfoCommand &other) = delete; - - static InfoCommand deserialize(const char *const messageBytes); }; struct ProtocolMessage final { private: - enum - { - ALARM, - INFO - } command; - - union + const union { AlarmCommand alarm; InfoCommand info; }; + const CommandType commandType; + public: + ProtocolMessage(AlarmCommand alarmCommand) : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} + ProtocolMessage(InfoCommand infoCommand) : commandType(CommandType::INFO), info(std::move(infoCommand)) {} + ProtocolMessage(ProtocolMessage &&other) = default; + ProtocolMessage operator=(ProtocolMessage &&other) noexcept + { + return std::move(other); + } ProtocolMessage(ProtocolMessage &other) = delete; + // TODO: This needs to through an error if the message could not be deserialized static const ProtocolMessage deserialize(const char *const messageBytes); private: From 131188b3cede7508aa3a9ac40674236d22e40941 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 8 Mar 2026 21:31:54 -0400 Subject: [PATCH 05/36] (#387): Constructors/operators support const types as well now --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 30 +++++++---- Firmware/GPAD_API/GPAD_API/protocol.h | 72 ++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 15 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 5ee1541a..91836e56 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -2,27 +2,38 @@ using namespace protocol; -AlarmCommand::AlarmCommand(const AlarmCommand::Level alarmLevel, const std::array alarmMessage) : level(alarmLevel), message(alarmMessage) {} +AlarmMessage::AlarmMessage(const char *const messageBytes, const size_t numBytes) +{ + auto index = 0; + for (; index < numBytes; ++index) + { + this->messageBytes.at(index) = messageBytes[index]; + } +} + +AlarmCommand::AlarmCommand(const AlarmCommand::Level alarmLevel, const AlarmMessage alarmMessage) : level(alarmLevel), message(std::move(alarmMessage)) {} -AlarmCommand AlarmCommand::deserialize(const char *const messageBytes) +AlarmCommand AlarmCommand::deserialize(const char *const messageBytes, const size_t numBytes) { - // TODO: Throw error if there is no 0th element; + // TODO: This will throw if either there is no 0th element or the static cast fails + // Those should be differentiated into 2 exceptions for traceability const auto level = static_cast(messageBytes[0]); - const auto level = AlarmCommand::Level::Level1; - return AlarmCommand(level, std::array()); + const auto alarmMessage = AlarmMessage(messageBytes + 1, numBytes - 1); + + return AlarmCommand(level, std::move(alarmMessage)); } InfoCommand::InfoCommand() { } -InfoCommand InfoCommand::deserialize(const char *const messageBytes) +InfoCommand InfoCommand::deserialize(const char *const messageBytes, const size_t numBytes) { return InfoCommand(); } -const ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes) +const ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, const size_t numBytes) { // TODO: This should be wrapped in a try/catch if there isn't a 0th element auto commandType = static_cast(messageBytes[0]); @@ -32,8 +43,9 @@ const ProtocolMessage ProtocolMessage::deserialize(const char *const messageByte switch (commandType) { case CommandType::ALARM: - return ProtocolMessage(AlarmCommand::deserialize(remainingBytes)); + return ProtocolMessage(AlarmCommand::deserialize(remainingBytes, numBytes)); case CommandType::INFO: - return ProtocolMessage(InfoCommand::deserialize(remainingBytes)); + return ProtocolMessage(InfoCommand::deserialize(remainingBytes, numBytes)); } + return ProtocolMessage(); } \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index c6feaae7..b14504cb 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -17,6 +17,33 @@ namespace protocol INFO = 'i', }; + class AlarmMessage final + { + public: + static const size_t MAX_SIZE = 80; + + private: + std::array messageBytes; + + public: + AlarmMessage(const char *const messageBytes, const size_t numBytes); + + AlarmMessage(AlarmMessage &&other) = default; + AlarmMessage operator=(AlarmMessage &&other) + { + return std::move(other); + } + AlarmMessage(const AlarmMessage &&other) : messageBytes(std::move(other.messageBytes)) {} + const AlarmMessage operator=(const AlarmMessage &&other) + { + return std::move(other); + } + + AlarmMessage() = delete; + AlarmMessage(AlarmMessage &other) = delete; + AlarmMessage(const AlarmMessage &other) = delete; + }; + class AlarmCommand { @@ -32,22 +59,27 @@ namespace protocol private: const Level level; - const std::array message; + const AlarmMessage message; private: friend struct ProtocolMessage; // TODO: Throw error if the message cannot be deserialized from the bytes - static AlarmCommand deserialize(const char *const messageBytes); + static AlarmCommand deserialize(const char *const messageBytes, const size_t numBytes); public: - explicit AlarmCommand(const Level level, const std::array message); + explicit AlarmCommand(const Level level, const AlarmMessage message); AlarmCommand(AlarmCommand &&other) = default; + AlarmCommand(const AlarmCommand &&other) : level(other.level), message(std::move(other.message)) {} AlarmCommand operator=(AlarmCommand &&other) noexcept { return std::move(other); } + const AlarmCommand operator=(const AlarmCommand &&other) + { + return std::move(other); + } AlarmCommand() = delete; AlarmCommand(AlarmCommand &other) = delete; }; @@ -59,7 +91,7 @@ namespace protocol InfoCommand(); // TODO: Throw error if the message cannot be deserialized from the bytes - static InfoCommand deserialize(const char *const messageBytes); + static InfoCommand deserialize(const char *const messageBytes, const size_t numBytes); public: InfoCommand(InfoCommand &&other) = default; @@ -67,6 +99,15 @@ namespace protocol { return std::move(other); } + + InfoCommand(const InfoCommand &&other) + { + } + const InfoCommand operator=(const InfoCommand &&other) + { + return std::move(other); + } + InfoCommand(InfoCommand &other) = delete; }; @@ -83,17 +124,36 @@ namespace protocol public: ProtocolMessage(AlarmCommand alarmCommand) : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} - ProtocolMessage(InfoCommand infoCommand) : commandType(CommandType::INFO), info(std::move(infoCommand)) {} + ProtocolMessage(InfoCommand infoCommand) : commandType(CommandType::INFO), info(std::move(infoCommand)) + { + } ProtocolMessage(ProtocolMessage &&other) = default; ProtocolMessage operator=(ProtocolMessage &&other) noexcept { return std::move(other); } + ProtocolMessage(const ProtocolMessage &&other) : commandType(other.commandType) + { + switch (this->commandType) + { + case CommandType::ALARM: + this->alarm = std::move(other.alarm); + break; + case CommandType::INFO: + this->info = std::move(other.info); + break; + } + } + const ProtocolMessage operator=(const ProtocolMessage &&other) + { + return std::move(other); + } ProtocolMessage(ProtocolMessage &other) = delete; + // TODO: This needs to through an error if the message could not be deserialized - static const ProtocolMessage deserialize(const char *const messageBytes); + static const ProtocolMessage deserialize(const char *const messageBytes, const size_t numBytes); private: ProtocolMessage(); From f11dc66bd8842c3328c37cc04285a1c476662624 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 9 Mar 2026 19:30:22 -0400 Subject: [PATCH 06/36] (#387): Starting to parse the AlarmMessageId --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 64 +++++++++++++++++++++++-- Firmware/GPAD_API/GPAD_API/protocol.h | 61 ++++++++++++++++++++--- 2 files changed, 113 insertions(+), 12 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 91836e56..4092a921 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -4,14 +4,63 @@ using namespace protocol; AlarmMessage::AlarmMessage(const char *const messageBytes, const size_t numBytes) { + const auto messageLength = std::min(numBytes, AlarmMessage::MAX_SIZE); + auto index = 0; - for (; index < numBytes; ++index) + for (; index < messageLength; ++index) { - this->messageBytes.at(index) = messageBytes[index]; + this->message.at(index) = messageBytes[index]; } } -AlarmCommand::AlarmCommand(const AlarmCommand::Level alarmLevel, const AlarmMessage alarmMessage) : level(alarmLevel), message(std::move(alarmMessage)) {} +AlarmMessageId AlarmMessageId::deserialize(const char *const bytes, const size_t numBytes) +{ + std::array id = {}; + + auto idLength = [bytes, numBytes, &id]() + { + auto idLength = 0; + + auto foundStart = false; + auto foundEnd = false; + for (auto i = 0; i < numBytes; ++i) + { + if (foundEnd || idLength > AlarmMessageId::MAX_LENGTH) + { + break; + } + else if ((foundStart) && isxdigit(bytes[i])) + { + id.at(idLength) = bytes[i]; + idLength += 1; + } + else if (bytes[i] == AlarmMessageId::ID_START_CHARACTER) + { + foundStart = true; + } + else if (bytes[i] == AlarmMessageId::ID_END_CHARACTER) + { + foundEnd = true; + } + // If a character isn't hex and isn't a marker character, it is an error and should be thrown + else if (!isxdigit(bytes[i])) + { + throw; + } + } + + // If the start and end characters were not found then we are unable to deserialize the ID. + // This will result in throwing an error. + if (!(foundStart && foundEnd)) + { + throw; + } + + return idLength; + }(); + + return AlarmMessageId(idLength, id); +} AlarmCommand AlarmCommand::deserialize(const char *const messageBytes, const size_t numBytes) { @@ -19,9 +68,14 @@ AlarmCommand AlarmCommand::deserialize(const char *const messageBytes, const siz // Those should be differentiated into 2 exceptions for traceability const auto level = static_cast(messageBytes[0]); + // Parse message id. >= 1 characters indicating a hex value. + // Parse alarm type designator. == 3 digits + + const auto messageId = AlarmMessageId::deserialize(messageBytes + 1, numBytes - 1); + const auto alarmMessage = AlarmMessage(messageBytes + 1, numBytes - 1); - return AlarmCommand(level, std::move(alarmMessage)); + return AlarmCommand(level, std::move(alarmMessage), std::move(messageId)); } InfoCommand::InfoCommand() @@ -33,7 +87,7 @@ InfoCommand InfoCommand::deserialize(const char *const messageBytes, const size_ return InfoCommand(); } -const ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, const size_t numBytes) +ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, const size_t numBytes) { // TODO: This should be wrapped in a try/catch if there isn't a 0th element auto commandType = static_cast(messageBytes[0]); diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index b14504cb..791de540 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -23,7 +23,8 @@ namespace protocol static const size_t MAX_SIZE = 80; private: - std::array messageBytes; + std::array message; + size_t messageLength; public: AlarmMessage(const char *const messageBytes, const size_t numBytes); @@ -33,7 +34,10 @@ namespace protocol { return std::move(other); } - AlarmMessage(const AlarmMessage &&other) : messageBytes(std::move(other.messageBytes)) {} + AlarmMessage(const AlarmMessage &&other) + : message(std::move(other.message)), messageLength(other.messageLength) + { + } const AlarmMessage operator=(const AlarmMessage &&other) { return std::move(other); @@ -44,6 +48,42 @@ namespace protocol AlarmMessage(const AlarmMessage &other) = delete; }; + class AlarmMessageId final + { + public: + static const size_t MAX_LENGTH = 10; + static const char ID_START_CHARACTER = '{'; + static const char ID_END_CHARACTER = '}'; + + private: + const size_t idLength; + const std::array id; + + private: + explicit AlarmMessageId(const size_t idLength, const std::array id) + : idLength(idLength), + id(std::move(id)) + { + } + + public: + static AlarmMessageId deserialize(const char *const bytes, const size_t numBytes); + + AlarmMessageId(AlarmMessageId &&other) = default; + AlarmMessageId(const AlarmMessageId &&other) + : id(std::move(other.id)), idLength(other.idLength) + { + } + AlarmMessageId operator=(AlarmMessageId &&other) + { + return std::move(other); + } + AlarmMessageId operator=(const AlarmMessageId &&other) + { + return std::move(other); + } + }; + class AlarmCommand { @@ -59,6 +99,7 @@ namespace protocol private: const Level level; + const AlarmMessageId messageId; const AlarmMessage message; private: @@ -68,15 +109,21 @@ namespace protocol static AlarmCommand deserialize(const char *const messageBytes, const size_t numBytes); public: - explicit AlarmCommand(const Level level, const AlarmMessage message); + explicit AlarmCommand(const AlarmCommand::Level alarmLevel, const AlarmMessage alarmMessage, const AlarmMessageId messageId) + : level(alarmLevel), message(std::move(alarmMessage)), messageId(std::move(messageId)) + { + } AlarmCommand(AlarmCommand &&other) = default; - AlarmCommand(const AlarmCommand &&other) : level(other.level), message(std::move(other.message)) {} + AlarmCommand(const AlarmCommand &&other) + : level(other.level), message(std::move(other.message)), messageId(std::move(other.messageId)) + { + } AlarmCommand operator=(AlarmCommand &&other) noexcept { return std::move(other); } - const AlarmCommand operator=(const AlarmCommand &&other) + AlarmCommand operator=(const AlarmCommand &&other) { return std::move(other); } @@ -103,7 +150,7 @@ namespace protocol InfoCommand(const InfoCommand &&other) { } - const InfoCommand operator=(const InfoCommand &&other) + InfoCommand operator=(const InfoCommand &&other) { return std::move(other); } @@ -153,7 +200,7 @@ namespace protocol ProtocolMessage(ProtocolMessage &other) = delete; // TODO: This needs to through an error if the message could not be deserialized - static const ProtocolMessage deserialize(const char *const messageBytes, const size_t numBytes); + static ProtocolMessage deserialize(const char *const messageBytes, const size_t numBytes); private: ProtocolMessage(); From 0a45be7c1f9fee76c6e4b04f5f4b8ae7b513812a Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 13 Mar 2026 18:16:34 -0400 Subject: [PATCH 07/36] (#387): Parsing Alarm type designator --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 17 +++++++++ Firmware/GPAD_API/GPAD_API/protocol.h | 47 ++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 4092a921..095c0816 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -1,5 +1,7 @@ #include +#include + using namespace protocol; AlarmMessage::AlarmMessage(const char *const messageBytes, const size_t numBytes) @@ -62,6 +64,21 @@ AlarmMessageId AlarmMessageId::deserialize(const char *const bytes, const size_t return AlarmMessageId(idLength, id); } +AlarmTypeDesignator::AlarmTypeDesignator(const std::array designator) : designator(designator) +{ + bool allDigits = std::all_of( + this->designator.cbegin(), + this->designator.cend(), + [](char c) + { return isdigit(c); }); + + // if the characters are not all digits we want to throw + if (!allDigits) + { + throw; + } +} + AlarmCommand AlarmCommand::deserialize(const char *const messageBytes, const size_t numBytes) { // TODO: This will throw if either there is no 0th element or the static cast fails diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 791de540..3a090686 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -84,9 +84,35 @@ namespace protocol } }; - class AlarmCommand + class AlarmTypeDesignator final { + public: + static const size_t DESIGNATOR_LENGTH = 3; + + private: + const std::array designator; + public: + AlarmTypeDesignator(const std::array designator); + + AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; + AlarmTypeDesignator(const AlarmTypeDesignator &&other) : designator(std::move(other.designator)) {} + AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) + { + return std::move(source); + } + AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) + { + return std::move(source); + } + + AlarmTypeDesignator() = delete; + AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; + AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; + }; + + class AlarmCommand final + { public: enum class Level : char { @@ -100,6 +126,7 @@ namespace protocol private: const Level level; const AlarmMessageId messageId; + const AlarmTypeDesignator typeDesignator; const AlarmMessage message; private: @@ -109,14 +136,24 @@ namespace protocol static AlarmCommand deserialize(const char *const messageBytes, const size_t numBytes); public: - explicit AlarmCommand(const AlarmCommand::Level alarmLevel, const AlarmMessage alarmMessage, const AlarmMessageId messageId) - : level(alarmLevel), message(std::move(alarmMessage)), messageId(std::move(messageId)) + explicit AlarmCommand( + const AlarmCommand::Level alarmLevel, + const AlarmMessage alarmMessage, + const AlarmMessageId messageId, + const AlarmTypeDesignator typeDesignator) + : level(alarmLevel), + message(std::move(alarmMessage)), + messageId(std::move(messageId)), + typeDesignator(std::move(typeDesignator)) { } AlarmCommand(AlarmCommand &&other) = default; AlarmCommand(const AlarmCommand &&other) - : level(other.level), message(std::move(other.message)), messageId(std::move(other.messageId)) + : level(other.level), + message(std::move(other.message)), + messageId(std::move(other.messageId)), + typeDesignator(std::move(other.typeDesignator)) { } AlarmCommand operator=(AlarmCommand &&other) noexcept @@ -131,7 +168,7 @@ namespace protocol AlarmCommand(AlarmCommand &other) = delete; }; - class InfoCommand + class InfoCommand final { private: friend struct ProtocolMessage; From cb37421c9a12d5ef9b6d80b6a52a6ca127c6c4e1 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 15 Mar 2026 21:48:43 -0400 Subject: [PATCH 08/36] (#387): Cleaning up the constructors - Moving all the constructors to just taking std::array - Removing most of the 'deserialize' methods --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 175 +++++++++++++++--------- Firmware/GPAD_API/GPAD_API/protocol.h | 48 ++++--- 2 files changed, 131 insertions(+), 92 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 095c0816..cd24d0de 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -4,64 +4,32 @@ using namespace protocol; -AlarmMessage::AlarmMessage(const char *const messageBytes, const size_t numBytes) +AlarmMessageId::AlarmMessageId(const size_t idLength, const std::array id) + : idLength(idLength), id(std::move(id)) { - const auto messageLength = std::min(numBytes, AlarmMessage::MAX_SIZE); - - auto index = 0; - for (; index < messageLength; ++index) + // The recorded real-length of the message ID cannot me more than the max number of elements + if (this->idLength > this->id.size()) { - this->message.at(index) = messageBytes[index]; + throw; } -} - -AlarmMessageId AlarmMessageId::deserialize(const char *const bytes, const size_t numBytes) -{ - std::array id = {}; - auto idLength = [bytes, numBytes, &id]() - { - auto idLength = 0; + auto startIterator = this->id.cbegin(); + auto endIterator = this->id.cbegin() + this->idLength; - auto foundStart = false; - auto foundEnd = false; - for (auto i = 0; i < numBytes; ++i) + bool allHex = std::all_of( + startIterator, + endIterator, + [](char hexChar) { - if (foundEnd || idLength > AlarmMessageId::MAX_LENGTH) - { - break; - } - else if ((foundStart) && isxdigit(bytes[i])) - { - id.at(idLength) = bytes[i]; - idLength += 1; - } - else if (bytes[i] == AlarmMessageId::ID_START_CHARACTER) - { - foundStart = true; - } - else if (bytes[i] == AlarmMessageId::ID_END_CHARACTER) - { - foundEnd = true; - } - // If a character isn't hex and isn't a marker character, it is an error and should be thrown - else if (!isxdigit(bytes[i])) - { - throw; - } - } + return isxdigit(hexChar); + }); - // If the start and end characters were not found then we are unable to deserialize the ID. - // This will result in throwing an error. - if (!(foundStart && foundEnd)) - { - throw; - } - - return idLength; - }(); - - return AlarmMessageId(idLength, id); + // If all the characters are NOT hex characters we need to throw an error and cancel the creation of + // this instance. + if (!allHex) + { + throw; + } } AlarmTypeDesignator::AlarmTypeDesignator(const std::array designator) : designator(designator) @@ -70,7 +38,9 @@ AlarmTypeDesignator::AlarmTypeDesignator(const std::arraydesignator.cbegin(), this->designator.cend(), [](char c) - { return isdigit(c); }); + { + return isdigit(c); + }); // if the characters are not all digits we want to throw if (!allDigits) @@ -79,29 +49,100 @@ AlarmTypeDesignator::AlarmTypeDesignator(const std::array(messageBytes[0]); - - // Parse message id. >= 1 characters indicating a hex value. - // Parse alarm type designator. == 3 digits + auto idLength = 0; + std::array id = {}; - const auto messageId = AlarmMessageId::deserialize(messageBytes + 1, numBytes - 1); + auto foundStart = false; + auto foundEnd = false; - const auto alarmMessage = AlarmMessage(messageBytes + 1, numBytes - 1); + for (auto index = 0; index < numBytes; ++index) + { + if (foundEnd || idLength > AlarmMessageId::MAX_LENGTH) + { + break; + } + else if (foundStart) + { + id.at(idLength) = bytes[index]; + idLength += 1; + } + else if (bytes[index] == AlarmMessageId::ID_START_CHARACTER) + { + foundStart = true; + } + else if (bytes[index] == AlarmMessageId::ID_END_CHARACTER) + { + foundEnd = true; + } + } - return AlarmCommand(level, std::move(alarmMessage), std::move(messageId)); + return AlarmMessageId(idLength, id); } -InfoCommand::InfoCommand() +AlarmTypeDesignator ProtocolMessage::deserializeAlarmTypeDesignator(const char *const bytes, const size_t numBytes) { + // The bytes length is 2 more than the designator length due to do the '[' and ']' + // characters + static const size_t BYTES_LENGTH = AlarmTypeDesignator::DESIGNATOR_LENGTH + 2; + + // If the number of bytes is not equal to the exact length of the designator we throw an error + if (numBytes != BYTES_LENGTH) + { + throw; + } + + auto idLength = 0; + std::array id = {}; + + auto foundStart = false; + auto foundEnd = false; + + for (auto index = 0; index < numBytes; ++index) + { + if (foundEnd || idLength > AlarmTypeDesignator::DESIGNATOR_LENGTH) + { + break; + } + else if (foundStart) + { + id.at(idLength) = bytes[index]; + idLength += 1; + } + else if (bytes[index] == AlarmTypeDesignator::DESIGNATOR_START_CHARACTER) + { + foundStart = true; + } + else if (bytes[index] == AlarmTypeDesignator::DESIGNATOR_END_CHARACTER) + { + foundEnd = true; + } + } + + return AlarmTypeDesignator(id); } -InfoCommand InfoCommand::deserialize(const char *const messageBytes, const size_t numBytes) +AlarmCommand ProtocolMessage::deserializeAlarmCommand(const char *const bytes, const size_t numBytes) { - return InfoCommand(); + // TODO: This will throw if either there is no 0th element or the static cast fails + // Those should be differentiated into 2 exceptions for traceability + const auto level = static_cast(bytes[0]); + + // Parse message id. >= 1 characters indicating a hex value. + // Parse alarm type designator. == 3 digits + + // Characters a + b + c + d + 1 + 2 + 3 = 7 charactersf + const auto idLength = 7; + std::array id = {'a', 'b', 'c', 'd', 1, 2, 3}; + const std::array message = { + 'T', 'h', 'i', 's', ' ', + 'i', 's', ' ', + 't', 'h', 'e', ' ', + 'm', 'e', 's', 's', 'a', 'g', 'e', '.'}; + const std::array designator = {}; + + return AlarmCommand(level, AlarmMessage(message), AlarmMessageId(idLength, id), AlarmTypeDesignator(designator)); } ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, const size_t numBytes) @@ -114,9 +155,9 @@ ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, con switch (commandType) { case CommandType::ALARM: - return ProtocolMessage(AlarmCommand::deserialize(remainingBytes, numBytes)); + return ProtocolMessage(ProtocolMessage::deserializeAlarmCommand(remainingBytes, numBytes)); case CommandType::INFO: - return ProtocolMessage(InfoCommand::deserialize(remainingBytes, numBytes)); + return ProtocolMessage(InfoCommand()); } return ProtocolMessage(); } \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 3a090686..f85298e9 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -20,14 +20,15 @@ namespace protocol class AlarmMessage final { public: - static const size_t MAX_SIZE = 80; + static const size_t MAX_LENGTH = 80; private: - std::array message; + std::array message; size_t messageLength; public: - AlarmMessage(const char *const messageBytes, const size_t numBytes); + explicit AlarmMessage(const std::array message) + : message(std::move(message)) {}; AlarmMessage(AlarmMessage &&other) = default; AlarmMessage operator=(AlarmMessage &&other) @@ -51,6 +52,7 @@ namespace protocol class AlarmMessageId final { public: + // TODO: Find out what this value is SUPPOSED to be. static const size_t MAX_LENGTH = 10; static const char ID_START_CHARACTER = '{'; static const char ID_END_CHARACTER = '}'; @@ -59,16 +61,8 @@ namespace protocol const size_t idLength; const std::array id; - private: - explicit AlarmMessageId(const size_t idLength, const std::array id) - : idLength(idLength), - id(std::move(id)) - { - } - public: - static AlarmMessageId deserialize(const char *const bytes, const size_t numBytes); - + explicit AlarmMessageId(const size_t idLength, const std::array id); AlarmMessageId(AlarmMessageId &&other) = default; AlarmMessageId(const AlarmMessageId &&other) : id(std::move(other.id)), idLength(other.idLength) @@ -82,12 +76,18 @@ namespace protocol { return std::move(other); } + + AlarmMessageId() = delete; + AlarmMessageId(AlarmMessageId &other) = delete; + AlarmMessageId(const AlarmMessageId &other) = delete; }; class AlarmTypeDesignator final { public: static const size_t DESIGNATOR_LENGTH = 3; + static const char DESIGNATOR_START_CHARACTER = '{'; + static const char DESIGNATOR_END_CHARACTER = '}'; private: const std::array designator; @@ -129,12 +129,6 @@ namespace protocol const AlarmTypeDesignator typeDesignator; const AlarmMessage message; - private: - friend struct ProtocolMessage; - - // TODO: Throw error if the message cannot be deserialized from the bytes - static AlarmCommand deserialize(const char *const messageBytes, const size_t numBytes); - public: explicit AlarmCommand( const AlarmCommand::Level alarmLevel, @@ -164,20 +158,16 @@ namespace protocol { return std::move(other); } + AlarmCommand() = delete; AlarmCommand(AlarmCommand &other) = delete; + AlarmCommand(const AlarmCommand &other) = delete; }; class InfoCommand final { - private: - friend struct ProtocolMessage; - - InfoCommand(); - // TODO: Throw error if the message cannot be deserialized from the bytes - static InfoCommand deserialize(const char *const messageBytes, const size_t numBytes); - public: + explicit InfoCommand() = default; InfoCommand(InfoCommand &&other) = default; InfoCommand operator=(InfoCommand &&other) noexcept { @@ -193,6 +183,7 @@ namespace protocol } InfoCommand(InfoCommand &other) = delete; + InfoCommand(const InfoCommand &other) = delete; }; struct ProtocolMessage final @@ -206,6 +197,13 @@ namespace protocol const CommandType commandType; + // Methods and static functions + private: + static AlarmCommand deserializeAlarmCommand(const char *const buffer, const size_t numBytes); + static AlarmMessageId deserializeAlarmMessageId(const char *const buffer, const size_t numBytes); + static AlarmTypeDesignator deserializeAlarmTypeDesignator(const char *const buffer, const size_t numBytes); + + // Constructors and operator overloads public: ProtocolMessage(AlarmCommand alarmCommand) : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} ProtocolMessage(InfoCommand infoCommand) : commandType(CommandType::INFO), info(std::move(infoCommand)) From 82a4ed5a8be3cd0df5eebfc15f9ceda57a043d80 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Thu, 19 Mar 2026 22:13:00 -0400 Subject: [PATCH 09/36] (#387): Leveraging new 'protocol' namespace/module to deserialize GPAP messages --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 17 +++++++++++++++++ Firmware/GPAD_API/GPAD_API/protocol.cpp | 17 ++++++++++++++++- Firmware/GPAD_API/GPAD_API/protocol.h | 9 ++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 3860a916..14deb3a0 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -25,6 +25,7 @@ #include #include "WiFiManagerOTA.h" #include "GPAD_menu.h" +#include "protocol.h" using namespace gpad_hal; @@ -426,6 +427,22 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie printError(serialport); return; } + + const auto protocolMessage = protocol::ProtocolMessage::deserialize(buf, rlen); + + switch (protocolMessage.getCommandType()) + { + case protocol::CommandType::ALARM: + protocolMessage.processAlarmCommand( + [buf, serialport](const protocol::AlarmCommand &alarmCommand) + { + serialport->print("The received command: "); + serialport->print(buf); + serialport->print("\n"); + }); + break; + } + Command command = static_cast(buf[0]); char commandChar = static_cast(command); diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index cd24d0de..86e2571f 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -159,5 +159,20 @@ ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, con case CommandType::INFO: return ProtocolMessage(InfoCommand()); } - return ProtocolMessage(); + + // In the event the switch falls through, throw an error + throw; +} + +CommandType ProtocolMessage::getCommandType() const +{ + return this->commandType; +} + +void ProtocolMessage::processAlarmCommand(std::function callback) const +{ + if (this->commandType == CommandType::ALARM) + { + callback(this->alarm); + } } \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index f85298e9..29da994b 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -2,6 +2,7 @@ #define _PROTOCOL_H #include +#include namespace protocol { @@ -232,13 +233,15 @@ namespace protocol return std::move(other); } + ProtocolMessage() = delete; ProtocolMessage(ProtocolMessage &other) = delete; - // TODO: This needs to through an error if the message could not be deserialized + // TODO: This needs to throw an error if the message could not be deserialized static ProtocolMessage deserialize(const char *const messageBytes, const size_t numBytes); - private: - ProtocolMessage(); + public: + CommandType getCommandType() const; + void processAlarmCommand(std::function) const; }; } From 5ec0813e432baa6040456f90087dc23b74ac8d1a Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Thu, 19 Mar 2026 22:39:22 -0400 Subject: [PATCH 10/36] (#387): ProtocolMessage members are public to be more conventional tagged union --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 10 ++-------- Firmware/GPAD_API/GPAD_API/protocol.cpp | 13 ------------- Firmware/GPAD_API/GPAD_API/protocol.h | 6 +----- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 14deb3a0..e2844bdb 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -430,16 +430,10 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie const auto protocolMessage = protocol::ProtocolMessage::deserialize(buf, rlen); - switch (protocolMessage.getCommandType()) + switch (protocolMessage.commandType) { case protocol::CommandType::ALARM: - protocolMessage.processAlarmCommand( - [buf, serialport](const protocol::AlarmCommand &alarmCommand) - { - serialport->print("The received command: "); - serialport->print(buf); - serialport->print("\n"); - }); + break; } diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 86e2571f..40fe773a 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -163,16 +163,3 @@ ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, con // In the event the switch falls through, throw an error throw; } - -CommandType ProtocolMessage::getCommandType() const -{ - return this->commandType; -} - -void ProtocolMessage::processAlarmCommand(std::function callback) const -{ - if (this->commandType == CommandType::ALARM) - { - callback(this->alarm); - } -} \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 29da994b..3655fdf4 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -189,7 +189,7 @@ namespace protocol struct ProtocolMessage final { - private: + public: const union { AlarmCommand alarm; @@ -238,10 +238,6 @@ namespace protocol // TODO: This needs to throw an error if the message could not be deserialized static ProtocolMessage deserialize(const char *const messageBytes, const size_t numBytes); - - public: - CommandType getCommandType() const; - void processAlarmCommand(std::function) const; }; } From 28004eae34b42437ab31eda5f4204679350ddc5a Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 22 Mar 2026 12:55:17 -0400 Subject: [PATCH 11/36] (#387): Writing AlarmCommand contents to the serial --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 68 +++++++++++++++++++++++-- Firmware/GPAD_API/GPAD_API/protocol.h | 28 ++++++++-- 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 40fe773a..8af3bd23 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -2,6 +2,8 @@ #include +#include + using namespace protocol; AlarmMessageId::AlarmMessageId(const size_t idLength, const std::array id) @@ -32,14 +34,51 @@ AlarmMessageId::AlarmMessageId(const size_t idLength, const std::array designator) : designator(designator) +AlarmTypeDesignator::AlarmTypeDesignator(const std::array designator) + : designator(AlarmTypeDesignator::validateDesignator(designator)) +{ + + // bool allDigits = std::all_of( + // this->designator.cbegin(), + // this->designator.cend(), + // [](char c) + // { + // return isdigit(c); + // }); + + // // if the characters are not all digits we want to throw + // if (!allDigits) + // { + // throw; + // } +} + +AlarmTypeDesignator::~AlarmTypeDesignator() = default; + +const char *const AlarmTypeDesignator::getValue() const { + return this->designator.data(); +} + +size_t AlarmTypeDesignator::printTo(Print &print) const +{ + return print.print(this->getValue()); +} + +std::array +AlarmTypeDesignator::validateDesignator(const std::array inputDesignator) +{ + std::array designator = {}; + auto designatorIterator = designator.begin(); + bool allDigits = std::all_of( - this->designator.cbegin(), - this->designator.cend(), - [](char c) + inputDesignator.cbegin(), + inputDesignator.cend(), + [&](char inputCharacter) { - return isdigit(c); + *designatorIterator = inputCharacter; + designatorIterator = std::next(designatorIterator, 1); + return isdigit(inputCharacter); }); // if the characters are not all digits we want to throw @@ -47,6 +86,25 @@ AlarmTypeDesignator::AlarmTypeDesignator(const std::arraylevel) + { + case AlarmCommand::Level::Level1: + return 1; + case AlarmCommand::Level::Level2: + return 2; + case AlarmCommand::Level::Level3: + return 3; + case AlarmCommand::Level::Level4: + return 4; + case AlarmCommand::Level::Level5: + return 5; + } } AlarmMessageId ProtocolMessage::deserializeAlarmMessageId(const char *const bytes, const size_t numBytes) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 3655fdf4..51b895f1 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -4,6 +4,8 @@ #include #include +#include + namespace protocol { union Command; @@ -83,15 +85,16 @@ namespace protocol AlarmMessageId(const AlarmMessageId &other) = delete; }; - class AlarmTypeDesignator final + class AlarmTypeDesignator final : Printable { public: static const size_t DESIGNATOR_LENGTH = 3; - static const char DESIGNATOR_START_CHARACTER = '{'; - static const char DESIGNATOR_END_CHARACTER = '}'; + static const char DESIGNATOR_START_CHARACTER = '['; + static const char DESIGNATOR_END_CHARACTER = ']'; private: - const std::array designator; + static const size_t TOTAL_DESIGNATOR_LENGTH = AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; + const std::array designator; public: AlarmTypeDesignator(const std::array designator); @@ -110,6 +113,16 @@ namespace protocol AlarmTypeDesignator() = delete; AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; + + virtual ~AlarmTypeDesignator(); + // Methods + public: + const char *const getValue() const; + + size_t printTo(Print &print) const override; + + private: + static std::array validateDesignator(const std::array); }; class AlarmCommand final @@ -124,7 +137,6 @@ namespace protocol Level5 = 5, }; - private: const Level level; const AlarmMessageId messageId; const AlarmTypeDesignator typeDesignator; @@ -163,6 +175,8 @@ namespace protocol AlarmCommand() = delete; AlarmCommand(AlarmCommand &other) = delete; AlarmCommand(const AlarmCommand &other) = delete; + + char alarmLevelIntoChar() const; }; class InfoCommand final @@ -236,6 +250,10 @@ namespace protocol ProtocolMessage() = delete; ProtocolMessage(ProtocolMessage &other) = delete; + ~ProtocolMessage() + { + } + // TODO: This needs to throw an error if the message could not be deserialized static ProtocolMessage deserialize(const char *const messageBytes, const size_t numBytes); }; From df726ae257a333e4011efa3cdfd4201ac68ddc2e Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 22 Mar 2026 21:01:56 -0400 Subject: [PATCH 12/36] (#387): Properly deserializing AlarmCommand contents --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 9 - Firmware/GPAD_API/GPAD_API/protocol.cpp | 164 ++++---- Firmware/GPAD_API/GPAD_API/protocol.h | 490 ++++++++++++------------ 3 files changed, 329 insertions(+), 334 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index e2844bdb..5745ee6e 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -428,15 +428,6 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie return; } - const auto protocolMessage = protocol::ProtocolMessage::deserialize(buf, rlen); - - switch (protocolMessage.commandType) - { - case protocol::CommandType::ALARM: - - break; - } - Command command = static_cast(buf[0]); char commandChar = static_cast(command); diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 8af3bd23..25aac87e 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -3,26 +3,37 @@ #include #include +#include using namespace protocol; AlarmMessageId::AlarmMessageId(const size_t idLength, const std::array id) - : idLength(idLength), id(std::move(id)) + : idLength(idLength), id(AlarmMessageId::validateId(idLength, id)) { +} + +std::array +AlarmMessageId::validateId(const size_t idLength, const std::array id) +{ + std::array validatedId = {}; + auto validatedIdIterator = validatedId.begin(); + // The recorded real-length of the message ID cannot me more than the max number of elements - if (this->idLength > this->id.size()) + if (idLength > id.size()) { throw; } - auto startIterator = this->id.cbegin(); - auto endIterator = this->id.cbegin() + this->idLength; + auto startIterator = id.cbegin(); + auto endIterator = id.cbegin() + idLength; bool allHex = std::all_of( startIterator, endIterator, - [](char hexChar) + [&validatedIdIterator](char hexChar) { + *validatedIdIterator = hexChar; + validatedIdIterator = std::next(validatedIdIterator, 1); return isxdigit(hexChar); }); @@ -32,25 +43,14 @@ AlarmMessageId::AlarmMessageId(const size_t idLength, const std::array designator) : designator(AlarmTypeDesignator::validateDesignator(designator)) { - - // bool allDigits = std::all_of( - // this->designator.cbegin(), - // this->designator.cend(), - // [](char c) - // { - // return isdigit(c); - // }); - - // // if the characters are not all digits we want to throw - // if (!allDigits) - // { - // throw; - // } } AlarmTypeDesignator::~AlarmTypeDesignator() = default; @@ -87,7 +87,9 @@ AlarmTypeDesignator::validateDesignator(const std::arraylevel) { case AlarmCommand::Level::Level1: - return 1; + return '1'; case AlarmCommand::Level::Level2: - return 2; + return '2'; case AlarmCommand::Level::Level3: - return 3; + return '3'; case AlarmCommand::Level::Level4: - return 4; + return '4'; case AlarmCommand::Level::Level5: - return 5; + return '5'; } + + Serial.println("End of the level to char method"); + return '0'; } -AlarmMessageId ProtocolMessage::deserializeAlarmMessageId(const char *const bytes, const size_t numBytes) +AlarmMessageId ProtocolMessage::deserializeAlarmMessageId(ProtocolBuffer::const_iterator start, const ProtocolBuffer::const_iterator end) { + if (*start != AlarmMessageId::ID_START_CHARACTER) + { + throw; + } + + ++start; + auto idLength = 0; std::array id = {}; - auto foundStart = false; auto foundEnd = false; - for (auto index = 0; index < numBytes; ++index) + for (; index < numBytes; ++index) { if (foundEnd || idLength > AlarmMessageId::MAX_LENGTH) { @@ -139,81 +150,90 @@ AlarmMessageId ProtocolMessage::deserializeAlarmMessageId(const char *const byte return AlarmMessageId(idLength, id); } -AlarmTypeDesignator ProtocolMessage::deserializeAlarmTypeDesignator(const char *const bytes, const size_t numBytes) +AlarmTypeDesignator ProtocolMessage::deserializeAlarmTypeDesignator(ProtocolBuffer::const_iterator start, const ProtocolBuffer::const_iterator end) { - // The bytes length is 2 more than the designator length due to do the '[' and ']' - // characters - static const size_t BYTES_LENGTH = AlarmTypeDesignator::DESIGNATOR_LENGTH + 2; + // // The bytes length is 2 more than the designator length due to do the '[' and ']' + // // characters + // static const size_t BYTES_LENGTH = AlarmTypeDesignator::DESIGNATOR_LENGTH + 2; - // If the number of bytes is not equal to the exact length of the designator we throw an error - if (numBytes != BYTES_LENGTH) - { - throw; - } + // // If the number of bytes is not equal to the exact length of the designator we throw an error + // if (numBytes != BYTES_LENGTH || bytes[0] != AlarmTypeDesignator::DESIGNATOR_START_CHARACTER) + // { + // throw; + // } - auto idLength = 0; - std::array id = {}; + // auto idLength = 0; + // std::array id = {}; - auto foundStart = false; - auto foundEnd = false; + // auto foundEnd = false; - for (auto index = 0; index < numBytes; ++index) - { - if (foundEnd || idLength > AlarmTypeDesignator::DESIGNATOR_LENGTH) - { - break; - } - else if (foundStart) - { - id.at(idLength) = bytes[index]; - idLength += 1; - } - else if (bytes[index] == AlarmTypeDesignator::DESIGNATOR_START_CHARACTER) - { - foundStart = true; - } - else if (bytes[index] == AlarmTypeDesignator::DESIGNATOR_END_CHARACTER) - { - foundEnd = true; - } - } + // for (auto index = 0; index < numBytes; ++index) + // { + // if (foundEnd || idLength >= AlarmTypeDesignator::DESIGNATOR_LENGTH) + // { + // break; + // } + // else if (bytes[index] == AlarmTypeDesignator::DESIGNATOR_END_CHARACTER) + // { + // foundEnd = true; + // } + // else + // { + // id.at(idLength) = bytes[index]; + // idLength += 1; + // } + // } + + // if (!foundEnd) + // { + // throw; + // } - return AlarmTypeDesignator(id); + return AlarmTypeDesignator({'1', '2', '3'}); } -AlarmCommand ProtocolMessage::deserializeAlarmCommand(const char *const bytes, const size_t numBytes) +AlarmCommand ProtocolMessage::deserializeAlarmCommand(ProtocolBuffer::const_iterator start, const ProtocolBuffer::const_iterator end) { // TODO: This will throw if either there is no 0th element or the static cast fails // Those should be differentiated into 2 exceptions for traceability - const auto level = static_cast(bytes[0]); + const auto level = static_cast(*start); + ++start; + + std::array id = {}; // Parse message id. >= 1 characters indicating a hex value. // Parse alarm type designator. == 3 digits // Characters a + b + c + d + 1 + 2 + 3 = 7 charactersf const auto idLength = 7; - std::array id = {'a', 'b', 'c', 'd', 1, 2, 3}; const std::array message = { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', '.'}; - const std::array designator = {}; + const std::array designator = {'1', '2', '3'}; + + // TODO: Catch error from message ID + const auto messageId = ProtocolMessage::deserializeAlarmMessageId(start, end); - return AlarmCommand(level, AlarmMessage(message), AlarmMessageId(idLength, id), AlarmTypeDesignator(designator)); + // TODO: Catch error from type designator + const auto typeDesignator = ProtocolMessage::deserializeAlarmTypeDesignator(start, end); + + return AlarmCommand(level, AlarmMessage(message), std::move(messageId), std::move(typeDesignator)); } -ProtocolMessage ProtocolMessage::deserialize(const char *const messageBytes, const size_t numBytes) +ProtocolMessage ProtocolMessage::deserialize(const std::array buffer) { - // TODO: This should be wrapped in a try/catch if there isn't a 0th element - auto commandType = static_cast(messageBytes[0]); + auto bufferIterator = buffer.cbegin(); + const auto bufferIteratorEnd = buffer.cend(); - auto remainingBytes = messageBytes + 1; + // TODO: This should be wrapped in a try/catch if there isn't a 0th element + auto commandType = static_cast(*bufferIterator); switch (commandType) { case CommandType::ALARM: - return ProtocolMessage(ProtocolMessage::deserializeAlarmCommand(remainingBytes, numBytes)); + return ProtocolMessage(ProtocolMessage::deserializeAlarmCommand(bufferIterator += 1, bufferIteratorEnd)); case CommandType::INFO: return ProtocolMessage(InfoCommand()); } diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 51b895f1..01b0eeba 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -2,261 +2,245 @@ #define _PROTOCOL_H #include -#include #include -namespace protocol -{ - union Command; - class ProtocolMessage; - - enum class CommandType : char - { - MUTE = 's', - UNMUTE = 'u', - HELP = 'h', - ALARM = 'a', - INFO = 'i', - }; - - class AlarmMessage final - { - public: - static const size_t MAX_LENGTH = 80; - - private: - std::array message; - size_t messageLength; - - public: - explicit AlarmMessage(const std::array message) - : message(std::move(message)) {}; - - AlarmMessage(AlarmMessage &&other) = default; - AlarmMessage operator=(AlarmMessage &&other) - { - return std::move(other); - } - AlarmMessage(const AlarmMessage &&other) - : message(std::move(other.message)), messageLength(other.messageLength) - { - } - const AlarmMessage operator=(const AlarmMessage &&other) - { - return std::move(other); - } - - AlarmMessage() = delete; - AlarmMessage(AlarmMessage &other) = delete; - AlarmMessage(const AlarmMessage &other) = delete; - }; - - class AlarmMessageId final - { - public: - // TODO: Find out what this value is SUPPOSED to be. - static const size_t MAX_LENGTH = 10; - static const char ID_START_CHARACTER = '{'; - static const char ID_END_CHARACTER = '}'; - - private: - const size_t idLength; - const std::array id; - - public: - explicit AlarmMessageId(const size_t idLength, const std::array id); - AlarmMessageId(AlarmMessageId &&other) = default; - AlarmMessageId(const AlarmMessageId &&other) - : id(std::move(other.id)), idLength(other.idLength) - { - } - AlarmMessageId operator=(AlarmMessageId &&other) - { - return std::move(other); - } - AlarmMessageId operator=(const AlarmMessageId &&other) - { - return std::move(other); - } - - AlarmMessageId() = delete; - AlarmMessageId(AlarmMessageId &other) = delete; - AlarmMessageId(const AlarmMessageId &other) = delete; - }; - - class AlarmTypeDesignator final : Printable - { - public: - static const size_t DESIGNATOR_LENGTH = 3; - static const char DESIGNATOR_START_CHARACTER = '['; - static const char DESIGNATOR_END_CHARACTER = ']'; - - private: - static const size_t TOTAL_DESIGNATOR_LENGTH = AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; - const std::array designator; - - public: - AlarmTypeDesignator(const std::array designator); - - AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; - AlarmTypeDesignator(const AlarmTypeDesignator &&other) : designator(std::move(other.designator)) {} - AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) - { - return std::move(source); - } - AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) - { - return std::move(source); - } - - AlarmTypeDesignator() = delete; - AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; - AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; - - virtual ~AlarmTypeDesignator(); - // Methods - public: - const char *const getValue() const; - - size_t printTo(Print &print) const override; - - private: - static std::array validateDesignator(const std::array); - }; - - class AlarmCommand final - { - public: - enum class Level : char - { - Level1 = 1, - Level2 = 2, - Level3 = 3, - Level4 = 4, - Level5 = 5, - }; - - const Level level; - const AlarmMessageId messageId; - const AlarmTypeDesignator typeDesignator; - const AlarmMessage message; - - public: - explicit AlarmCommand( - const AlarmCommand::Level alarmLevel, - const AlarmMessage alarmMessage, - const AlarmMessageId messageId, - const AlarmTypeDesignator typeDesignator) - : level(alarmLevel), - message(std::move(alarmMessage)), - messageId(std::move(messageId)), - typeDesignator(std::move(typeDesignator)) - { - } - - AlarmCommand(AlarmCommand &&other) = default; - AlarmCommand(const AlarmCommand &&other) - : level(other.level), - message(std::move(other.message)), - messageId(std::move(other.messageId)), - typeDesignator(std::move(other.typeDesignator)) - { - } - AlarmCommand operator=(AlarmCommand &&other) noexcept - { - return std::move(other); - } - AlarmCommand operator=(const AlarmCommand &&other) - { - return std::move(other); - } - - AlarmCommand() = delete; - AlarmCommand(AlarmCommand &other) = delete; - AlarmCommand(const AlarmCommand &other) = delete; - - char alarmLevelIntoChar() const; - }; - - class InfoCommand final - { - public: - explicit InfoCommand() = default; - InfoCommand(InfoCommand &&other) = default; - InfoCommand operator=(InfoCommand &&other) noexcept - { - return std::move(other); - } - - InfoCommand(const InfoCommand &&other) - { - } - InfoCommand operator=(const InfoCommand &&other) - { - return std::move(other); - } - - InfoCommand(InfoCommand &other) = delete; - InfoCommand(const InfoCommand &other) = delete; - }; - - struct ProtocolMessage final - { - public: - const union - { - AlarmCommand alarm; - InfoCommand info; - }; - - const CommandType commandType; - - // Methods and static functions - private: - static AlarmCommand deserializeAlarmCommand(const char *const buffer, const size_t numBytes); - static AlarmMessageId deserializeAlarmMessageId(const char *const buffer, const size_t numBytes); - static AlarmTypeDesignator deserializeAlarmTypeDesignator(const char *const buffer, const size_t numBytes); - - // Constructors and operator overloads - public: - ProtocolMessage(AlarmCommand alarmCommand) : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} - ProtocolMessage(InfoCommand infoCommand) : commandType(CommandType::INFO), info(std::move(infoCommand)) - { - } - - ProtocolMessage(ProtocolMessage &&other) = default; - ProtocolMessage operator=(ProtocolMessage &&other) noexcept - { - return std::move(other); - } - ProtocolMessage(const ProtocolMessage &&other) : commandType(other.commandType) - { - switch (this->commandType) - { - case CommandType::ALARM: - this->alarm = std::move(other.alarm); - break; - case CommandType::INFO: - this->info = std::move(other.info); - break; - } - } - const ProtocolMessage operator=(const ProtocolMessage &&other) - { - return std::move(other); - } - - ProtocolMessage() = delete; - ProtocolMessage(ProtocolMessage &other) = delete; - - ~ProtocolMessage() - { - } - - // TODO: This needs to throw an error if the message could not be deserialized - static ProtocolMessage deserialize(const char *const messageBytes, const size_t numBytes); - }; -} +namespace protocol { + +union Command; +class ProtocolMessage; + +enum class CommandType : char { + MUTE = 's', + UNMUTE = 'u', + HELP = 'h', + ALARM = 'a', + INFO = 'i', +}; + +class AlarmMessage final { +public: + static const size_t MAX_LENGTH = 80; + +private: + std::array message; + size_t messageLength; + +public: + explicit AlarmMessage( + const std::array message) + : message(std::move(message)) {}; + + AlarmMessage(AlarmMessage &&other) = default; + AlarmMessage operator=(AlarmMessage &&other) { return std::move(other); } + AlarmMessage(const AlarmMessage &&other) + : message(std::move(other.message)), messageLength(other.messageLength) {} + const AlarmMessage operator=(const AlarmMessage &&other) { + return std::move(other); + } + + AlarmMessage() = delete; + AlarmMessage(AlarmMessage &other) = delete; + AlarmMessage(const AlarmMessage &other) = delete; +}; + +class AlarmMessageId final { +public: + // TODO: Find out what this value is SUPPOSED to be. + static const size_t MAX_LENGTH = 10; + static const char ID_START_CHARACTER = '{'; + static const char ID_END_CHARACTER = '}'; + +private: + static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; + +private: + const size_t idLength; + const std::array id; + +public: + explicit AlarmMessageId( + const size_t idLength, + const std::array id); + AlarmMessageId(AlarmMessageId &&other) = default; + AlarmMessageId(const AlarmMessageId &&other) + : id(std::move(other.id)), idLength(other.idLength) {} + AlarmMessageId operator=(AlarmMessageId &&other) { return std::move(other); } + AlarmMessageId operator=(const AlarmMessageId &&other) { + return std::move(other); + } + + AlarmMessageId() = delete; + AlarmMessageId(AlarmMessageId &other) = delete; + AlarmMessageId(const AlarmMessageId &other) = delete; + +private: + static std::array + validateId(const size_t idLength, + const std::array); +}; + +class AlarmTypeDesignator final : Printable { +public: + static const size_t DESIGNATOR_LENGTH = 3; + static const char DESIGNATOR_START_CHARACTER = '['; + static const char DESIGNATOR_END_CHARACTER = ']'; + +private: + static const size_t TOTAL_DESIGNATOR_LENGTH = + AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; + const std::array designator; + +public: + AlarmTypeDesignator( + const std::array + designator); + + AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; + AlarmTypeDesignator(const AlarmTypeDesignator &&other) + : designator(std::move(other.designator)) {} + AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) { + return std::move(source); + } + AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) { + return std::move(source); + } + + AlarmTypeDesignator() = delete; + AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; + AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; + + virtual ~AlarmTypeDesignator(); + // Methods +public: + const char *const getValue() const; + + size_t printTo(Print &print) const override; + +private: + static std::array + validateDesignator( + const std::array); +}; + +class AlarmCommand final { +public: + enum class Level : char { + Level1 = '1', + Level2 = '2', + Level3 = '3', + Level4 = '4', + Level5 = '5', + }; + + const Level level; + const AlarmMessageId messageId; + const AlarmTypeDesignator typeDesignator; + const AlarmMessage message; + +public: + explicit AlarmCommand(const AlarmCommand::Level alarmLevel, + const AlarmMessage alarmMessage, + const AlarmMessageId messageId, + const AlarmTypeDesignator typeDesignator) + : level(alarmLevel), message(std::move(alarmMessage)), + messageId(std::move(messageId)), + typeDesignator(std::move(typeDesignator)) {} + + AlarmCommand(AlarmCommand &&other) = default; + AlarmCommand(const AlarmCommand &&other) + : level(other.level), message(std::move(other.message)), + messageId(std::move(other.messageId)), + typeDesignator(std::move(other.typeDesignator)) {} + AlarmCommand operator=(AlarmCommand &&other) noexcept { + return std::move(other); + } + AlarmCommand operator=(const AlarmCommand &&other) { + return std::move(other); + } + + AlarmCommand() = delete; + AlarmCommand(AlarmCommand &other) = delete; + AlarmCommand(const AlarmCommand &other) = delete; + + char alarmLevelIntoChar() const; +}; + +class InfoCommand final { +public: + explicit InfoCommand() = default; + InfoCommand(InfoCommand &&other) = default; + InfoCommand operator=(InfoCommand &&other) noexcept { + return std::move(other); + } + + InfoCommand(const InfoCommand &&other) {} + InfoCommand operator=(const InfoCommand &&other) { return std::move(other); } + + InfoCommand(InfoCommand &other) = delete; + InfoCommand(const InfoCommand &other) = delete; +}; + +struct ProtocolMessage final { +public: + static const size_t BUFFER_LENGTH = 131; + + const union { + AlarmCommand alarm; + InfoCommand info; + }; + + const CommandType commandType; + + using ProtocolBuffer = std::array; + + // Methods and static functions +private: + static AlarmCommand + deserializeAlarmCommand(ProtocolBuffer::const_iterator start, + const ProtocolBuffer::const_iterator end); + static AlarmMessageId + deserializeAlarmMessageId(ProtocolBuffer::const_iterator start, + const ProtocolBuffer::const_iterator end); + static AlarmTypeDesignator + deserializeAlarmTypeDesignator(ProtocolBuffer::const_iterator start, + const ProtocolBuffer::const_iterator end); + + // Constructors and operator overloads +public: + ProtocolMessage(AlarmCommand alarmCommand) + : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} + ProtocolMessage(InfoCommand infoCommand) + : commandType(CommandType::INFO), info(std::move(infoCommand)) {} + + ProtocolMessage operator=(ProtocolMessage &&other) noexcept { + return std::move(other); + } + ProtocolMessage(const ProtocolMessage &&other) + : commandType(other.commandType) { + switch (this->commandType) { + case CommandType::ALARM: + this->alarm = std::move(other.alarm); + break; + case CommandType::INFO: + this->info = std::move(other.info); + break; + } + } + const ProtocolMessage operator=(const ProtocolMessage &&other) { + return std::move(other); + } + + ProtocolMessage() = delete; + ProtocolMessage(ProtocolMessage &other) = delete; + + ~ProtocolMessage() {} + + // TODO: This needs to throw an error if the message could not be deserialized + static ProtocolMessage + deserialize(const std::array buffer); +}; + +} // namespace protocol #endif From 8b0e47b0a522caa62197ca77366f546b69cab228 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 27 Mar 2026 16:02:33 -0400 Subject: [PATCH 13/36] (#387): AlarmMessageId now being parsed --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 31 +- Firmware/GPAD_API/GPAD_API/protocol.h | 469 +++++++++++++----------- 2 files changed, 253 insertions(+), 247 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 25aac87e..6c291578 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -119,32 +119,17 @@ AlarmMessageId ProtocolMessage::deserializeAlarmMessageId(ProtocolBuffer::const_ throw; } - ++start; - auto idLength = 0; std::array id = {}; - auto foundEnd = false; - - for (; index < numBytes; ++index) + ++start; + while ((idLength < AlarmMessageId::MAX_LENGTH) && (start != end) && (*start != AlarmMessageId::ID_END_CHARACTER)) { - if (foundEnd || idLength > AlarmMessageId::MAX_LENGTH) - { - break; - } - else if (foundStart) - { - id.at(idLength) = bytes[index]; - idLength += 1; - } - else if (bytes[index] == AlarmMessageId::ID_START_CHARACTER) - { - foundStart = true; - } - else if (bytes[index] == AlarmMessageId::ID_END_CHARACTER) - { - foundEnd = true; - } + Serial.printf("Current Message Id char: %c\n", *start); + id.at(idLength) = *start; + idLength += 1; + + ++start; } return AlarmMessageId(idLength, id); @@ -233,7 +218,7 @@ ProtocolMessage ProtocolMessage::deserialize(const std::array -namespace protocol { - -union Command; -class ProtocolMessage; - -enum class CommandType : char { - MUTE = 's', - UNMUTE = 'u', - HELP = 'h', - ALARM = 'a', - INFO = 'i', -}; - -class AlarmMessage final { -public: - static const size_t MAX_LENGTH = 80; - -private: - std::array message; - size_t messageLength; - -public: - explicit AlarmMessage( - const std::array message) - : message(std::move(message)) {}; - - AlarmMessage(AlarmMessage &&other) = default; - AlarmMessage operator=(AlarmMessage &&other) { return std::move(other); } - AlarmMessage(const AlarmMessage &&other) - : message(std::move(other.message)), messageLength(other.messageLength) {} - const AlarmMessage operator=(const AlarmMessage &&other) { - return std::move(other); - } - - AlarmMessage() = delete; - AlarmMessage(AlarmMessage &other) = delete; - AlarmMessage(const AlarmMessage &other) = delete; -}; - -class AlarmMessageId final { -public: - // TODO: Find out what this value is SUPPOSED to be. - static const size_t MAX_LENGTH = 10; - static const char ID_START_CHARACTER = '{'; - static const char ID_END_CHARACTER = '}'; - -private: - static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; - -private: - const size_t idLength; - const std::array id; - -public: - explicit AlarmMessageId( - const size_t idLength, - const std::array id); - AlarmMessageId(AlarmMessageId &&other) = default; - AlarmMessageId(const AlarmMessageId &&other) - : id(std::move(other.id)), idLength(other.idLength) {} - AlarmMessageId operator=(AlarmMessageId &&other) { return std::move(other); } - AlarmMessageId operator=(const AlarmMessageId &&other) { - return std::move(other); - } - - AlarmMessageId() = delete; - AlarmMessageId(AlarmMessageId &other) = delete; - AlarmMessageId(const AlarmMessageId &other) = delete; - -private: - static std::array - validateId(const size_t idLength, - const std::array); -}; - -class AlarmTypeDesignator final : Printable { -public: - static const size_t DESIGNATOR_LENGTH = 3; - static const char DESIGNATOR_START_CHARACTER = '['; - static const char DESIGNATOR_END_CHARACTER = ']'; - -private: - static const size_t TOTAL_DESIGNATOR_LENGTH = - AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; - const std::array designator; - -public: - AlarmTypeDesignator( - const std::array - designator); - - AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; - AlarmTypeDesignator(const AlarmTypeDesignator &&other) - : designator(std::move(other.designator)) {} - AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) { - return std::move(source); - } - AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) { - return std::move(source); - } - - AlarmTypeDesignator() = delete; - AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; - AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; - - virtual ~AlarmTypeDesignator(); - // Methods -public: - const char *const getValue() const; - - size_t printTo(Print &print) const override; - -private: - static std::array - validateDesignator( - const std::array); -}; - -class AlarmCommand final { -public: - enum class Level : char { - Level1 = '1', - Level2 = '2', - Level3 = '3', - Level4 = '4', - Level5 = '5', +namespace protocol +{ + + union Command; + class ProtocolMessage; + + enum class CommandType : char + { + MUTE = 's', + UNMUTE = 'u', + HELP = 'h', + ALARM = 'a', + INFO = 'i', }; - const Level level; - const AlarmMessageId messageId; - const AlarmTypeDesignator typeDesignator; - const AlarmMessage message; - -public: - explicit AlarmCommand(const AlarmCommand::Level alarmLevel, - const AlarmMessage alarmMessage, - const AlarmMessageId messageId, - const AlarmTypeDesignator typeDesignator) - : level(alarmLevel), message(std::move(alarmMessage)), - messageId(std::move(messageId)), - typeDesignator(std::move(typeDesignator)) {} - - AlarmCommand(AlarmCommand &&other) = default; - AlarmCommand(const AlarmCommand &&other) - : level(other.level), message(std::move(other.message)), - messageId(std::move(other.messageId)), - typeDesignator(std::move(other.typeDesignator)) {} - AlarmCommand operator=(AlarmCommand &&other) noexcept { - return std::move(other); - } - AlarmCommand operator=(const AlarmCommand &&other) { - return std::move(other); - } - - AlarmCommand() = delete; - AlarmCommand(AlarmCommand &other) = delete; - AlarmCommand(const AlarmCommand &other) = delete; - - char alarmLevelIntoChar() const; -}; - -class InfoCommand final { -public: - explicit InfoCommand() = default; - InfoCommand(InfoCommand &&other) = default; - InfoCommand operator=(InfoCommand &&other) noexcept { - return std::move(other); - } - - InfoCommand(const InfoCommand &&other) {} - InfoCommand operator=(const InfoCommand &&other) { return std::move(other); } - - InfoCommand(InfoCommand &other) = delete; - InfoCommand(const InfoCommand &other) = delete; -}; - -struct ProtocolMessage final { -public: - static const size_t BUFFER_LENGTH = 131; - - const union { - AlarmCommand alarm; - InfoCommand info; + class AlarmMessage final + { + public: + static const size_t MAX_LENGTH = 80; + + private: + std::array message; + size_t messageLength; + + public: + explicit AlarmMessage( + const std::array message) + : message(std::move(message)) {}; + + AlarmMessage(AlarmMessage &&other) = default; + AlarmMessage operator=(AlarmMessage &&other) { return std::move(other); } + AlarmMessage(const AlarmMessage &&other) + : message(std::move(other.message)), messageLength(other.messageLength) {} + const AlarmMessage operator=(const AlarmMessage &&other) + { + return std::move(other); + } + + AlarmMessage() = delete; + AlarmMessage(AlarmMessage &other) = delete; + AlarmMessage(const AlarmMessage &other) = delete; + }; + + class AlarmMessageId final + { + public: + // TODO: Find out what this value is SUPPOSED to be. + static const size_t MAX_LENGTH = 10; + static const char ID_START_CHARACTER = '{'; + static const char ID_END_CHARACTER = '}'; + + private: + static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; + + private: + const size_t idLength; + const std::array id; + + public: + explicit AlarmMessageId( + const size_t idLength, + const std::array id); + AlarmMessageId(AlarmMessageId &&other) = default; + AlarmMessageId(const AlarmMessageId &&other) + : id(std::move(other.id)), idLength(other.idLength) {} + AlarmMessageId operator=(AlarmMessageId &&other) { return std::move(other); } + AlarmMessageId operator=(const AlarmMessageId &&other) + { + return std::move(other); + } + + AlarmMessageId() = delete; + AlarmMessageId(AlarmMessageId &other) = delete; + AlarmMessageId(const AlarmMessageId &other) = delete; + + private: + static std::array + validateId(const size_t idLength, + const std::array); }; - const CommandType commandType; + class AlarmTypeDesignator final : Printable + { + public: + static const size_t DESIGNATOR_LENGTH = 3; + static const char DESIGNATOR_START_CHARACTER = '['; + static const char DESIGNATOR_END_CHARACTER = ']'; + + private: + static const size_t TOTAL_DESIGNATOR_LENGTH = + AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; + const std::array designator; + + public: + AlarmTypeDesignator( + const std::array + designator); + + AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; + AlarmTypeDesignator(const AlarmTypeDesignator &&other) + : designator(std::move(other.designator)) {} + AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) + { + return std::move(source); + } + AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) + { + return std::move(source); + } + + AlarmTypeDesignator() = delete; + AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; + AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; + + virtual ~AlarmTypeDesignator(); + // Methods + public: + const char *const getValue() const; + + size_t printTo(Print &print) const override; - using ProtocolBuffer = std::array; + private: + static std::array + validateDesignator( + const std::array); + }; + + class AlarmCommand final + { + public: + enum class Level : char + { + Level1 = '1', + Level2 = '2', + Level3 = '3', + Level4 = '4', + Level5 = '5', + }; + + const Level level; + const AlarmMessageId messageId; + const AlarmTypeDesignator typeDesignator; + const AlarmMessage message; + + public: + explicit AlarmCommand(const AlarmCommand::Level alarmLevel, + const AlarmMessage alarmMessage, + const AlarmMessageId messageId, + const AlarmTypeDesignator typeDesignator) + : level(alarmLevel), message(std::move(alarmMessage)), + messageId(std::move(messageId)), + typeDesignator(std::move(typeDesignator)) {} + + AlarmCommand(AlarmCommand &&other) = default; + AlarmCommand(const AlarmCommand &&other) + : level(other.level), message(std::move(other.message)), + messageId(std::move(other.messageId)), + typeDesignator(std::move(other.typeDesignator)) {} + AlarmCommand operator=(AlarmCommand &&other) noexcept + { + return std::move(other); + } + AlarmCommand operator=(const AlarmCommand &&other) + { + return std::move(other); + } - // Methods and static functions -private: - static AlarmCommand - deserializeAlarmCommand(ProtocolBuffer::const_iterator start, - const ProtocolBuffer::const_iterator end); - static AlarmMessageId - deserializeAlarmMessageId(ProtocolBuffer::const_iterator start, + AlarmCommand() = delete; + AlarmCommand(AlarmCommand &other) = delete; + AlarmCommand(const AlarmCommand &other) = delete; + + char alarmLevelIntoChar() const; + }; + + class InfoCommand final + { + public: + explicit InfoCommand() = default; + InfoCommand(InfoCommand &&other) = default; + InfoCommand operator=(InfoCommand &&other) noexcept + { + return std::move(other); + } + + InfoCommand(const InfoCommand &&other) {} + InfoCommand operator=(const InfoCommand &&other) { return std::move(other); } + + InfoCommand(InfoCommand &other) = delete; + InfoCommand(const InfoCommand &other) = delete; + }; + + struct ProtocolMessage final + { + public: + static const size_t BUFFER_LENGTH = 131; + + const union + { + AlarmCommand alarm; + InfoCommand info; + }; + + const CommandType commandType; + + using ProtocolBuffer = std::array; + + // Methods and static functions + private: + static AlarmCommand + deserializeAlarmCommand(ProtocolBuffer::const_iterator start, const ProtocolBuffer::const_iterator end); - static AlarmTypeDesignator - deserializeAlarmTypeDesignator(ProtocolBuffer::const_iterator start, - const ProtocolBuffer::const_iterator end); - - // Constructors and operator overloads -public: - ProtocolMessage(AlarmCommand alarmCommand) - : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} - ProtocolMessage(InfoCommand infoCommand) - : commandType(CommandType::INFO), info(std::move(infoCommand)) {} - - ProtocolMessage operator=(ProtocolMessage &&other) noexcept { - return std::move(other); - } - ProtocolMessage(const ProtocolMessage &&other) - : commandType(other.commandType) { - switch (this->commandType) { - case CommandType::ALARM: - this->alarm = std::move(other.alarm); - break; - case CommandType::INFO: - this->info = std::move(other.info); - break; + static AlarmMessageId + deserializeAlarmMessageId(ProtocolBuffer::const_iterator start, + const ProtocolBuffer::const_iterator end); + static AlarmTypeDesignator + deserializeAlarmTypeDesignator(ProtocolBuffer::const_iterator start, + const ProtocolBuffer::const_iterator end); + + // Constructors and operator overloads + public: + ProtocolMessage(AlarmCommand alarmCommand) + : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} + ProtocolMessage(InfoCommand infoCommand) + : commandType(CommandType::INFO), info(std::move(infoCommand)) {} + + ProtocolMessage operator=(ProtocolMessage &&other) noexcept + { + return std::move(other); + } + ProtocolMessage(const ProtocolMessage &&other) + : commandType(other.commandType) + { + switch (this->commandType) + { + case CommandType::ALARM: + this->alarm = std::move(other.alarm); + break; + case CommandType::INFO: + this->info = std::move(other.info); + break; + } + } + const ProtocolMessage operator=(const ProtocolMessage &&other) + { + return std::move(other); } - } - const ProtocolMessage operator=(const ProtocolMessage &&other) { - return std::move(other); - } - ProtocolMessage() = delete; - ProtocolMessage(ProtocolMessage &other) = delete; + ProtocolMessage() = delete; + ProtocolMessage(ProtocolMessage &other) = delete; - ~ProtocolMessage() {} + ~ProtocolMessage() {} - // TODO: This needs to throw an error if the message could not be deserialized - static ProtocolMessage - deserialize(const std::array buffer); -}; + // TODO: This needs to throw an error if the message could not be deserialized + static ProtocolMessage + deserialize(const std::array buffer); + }; } // namespace protocol From e21892b5eb358da05e57585185c49bc8841ac385 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:27:22 -0400 Subject: [PATCH 14/36] (#387): The AlarmCommand is now deserialized through its own "Builder" --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 226 +++++++++++++++--------- Firmware/GPAD_API/GPAD_API/protocol.h | 92 ++++++---- 2 files changed, 198 insertions(+), 120 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index 6c291578..a8275de8 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -48,8 +48,8 @@ AlarmMessageId::validateId(const size_t idLength, const std::array designator) - : designator(AlarmTypeDesignator::validateDesignator(designator)) +AlarmTypeDesignator::AlarmTypeDesignator(const std::array designator, const bool empty) + : designator(AlarmTypeDesignator::validateDesignator(designator, empty)), empty(empty) { } @@ -66,9 +66,14 @@ size_t AlarmTypeDesignator::printTo(Print &print) const } std::array -AlarmTypeDesignator::validateDesignator(const std::array inputDesignator) +AlarmTypeDesignator::validateDesignator(const std::array inputDesignator, const bool empty) { std::array designator = {}; + if (empty) + { + return designator; + } + auto designatorIterator = designator.begin(); bool allDigits = std::all_of( @@ -112,117 +117,164 @@ char AlarmCommand::alarmLevelIntoChar() const return '0'; } -AlarmMessageId ProtocolMessage::deserializeAlarmMessageId(ProtocolBuffer::const_iterator start, const ProtocolBuffer::const_iterator end) +ProtocolMessage ProtocolMessage::deserialize(const char *const buffer, const size_t numBytes) { - if (*start != AlarmMessageId::ID_START_CHARACTER) + // Can't determined the message type if there are no bytes + if (numBytes == 0) { throw; } - auto idLength = 0; - std::array id = {}; + // TODO: This should be wrapped in a try/catch if there isn't a 0th element + auto commandType = static_cast(buffer[0]); - ++start; - while ((idLength < AlarmMessageId::MAX_LENGTH) && (start != end) && (*start != AlarmMessageId::ID_END_CHARACTER)) + switch (commandType) { - Serial.printf("Current Message Id char: %c\n", *start); - id.at(idLength) = *start; - idLength += 1; - - ++start; + case CommandType::ALARM: + if ((numBytes - 1) >= 1) + { + return ProtocolMessage(AlarmCommandBuilder::buildAlarmCommand(buffer + 1, numBytes - 1)); + } + else + { + throw; + } + case CommandType::INFO: + return ProtocolMessage(InfoCommand()); } - return AlarmMessageId(idLength, id); + // In the event the switch falls through, throw an error + throw; } -AlarmTypeDesignator ProtocolMessage::deserializeAlarmTypeDesignator(ProtocolBuffer::const_iterator start, const ProtocolBuffer::const_iterator end) +AlarmCommandBuilder::AlarmCommandBuilder() + : level(AlarmCommand::Level::Level1), + idLength(0), + idBuffer({}), + designatorLength(0), + designatorBuffer({}), + messageLength(0), + messageBuffer({}) {} + +size_t AlarmCommandBuilder::deserializeLevelBytes(const char *const buffer, const size_t numBytes) { - // // The bytes length is 2 more than the designator length due to do the '[' and ']' - // // characters - // static const size_t BYTES_LENGTH = AlarmTypeDesignator::DESIGNATOR_LENGTH + 2; - - // // If the number of bytes is not equal to the exact length of the designator we throw an error - // if (numBytes != BYTES_LENGTH || bytes[0] != AlarmTypeDesignator::DESIGNATOR_START_CHARACTER) - // { - // throw; - // } - - // auto idLength = 0; - // std::array id = {}; - - // auto foundEnd = false; - - // for (auto index = 0; index < numBytes; ++index) - // { - // if (foundEnd || idLength >= AlarmTypeDesignator::DESIGNATOR_LENGTH) - // { - // break; - // } - // else if (bytes[index] == AlarmTypeDesignator::DESIGNATOR_END_CHARACTER) - // { - // foundEnd = true; - // } - // else - // { - // id.at(idLength) = bytes[index]; - // idLength += 1; - // } - // } - - // if (!foundEnd) - // { - // throw; - // } - - return AlarmTypeDesignator({'1', '2', '3'}); + if (numBytes == 0) + { + throw; + } + + this->level = static_cast(buffer[0]); + + return 1; } -AlarmCommand ProtocolMessage::deserializeAlarmCommand(ProtocolBuffer::const_iterator start, const ProtocolBuffer::const_iterator end) +size_t AlarmCommandBuilder::deserializeIdBytes(const char *const buffer, const size_t numBytes) { - // TODO: This will throw if either there is no 0th element or the static cast fails - // Those should be differentiated into 2 exceptions for traceability - const auto level = static_cast(*start); - ++start; + if (numBytes == 0 || (buffer[0] != AlarmCommandBuilder::ID_START_CHARACTER)) + { + return 0; + } - std::array id = {}; + auto idLength = 0; + auto foundEnd = false; - // Parse message id. >= 1 characters indicating a hex value. - // Parse alarm type designator. == 3 digits + // Going 1 more than the max since the end character, ], can be after the max length of the ID + while ((idLength < (AlarmMessageId::MAX_LENGTH + 1)) && (idLength < numBytes) && !foundEnd) + { + // Need to offset the index by 1 since we have to account for the starting character, [ + auto bufferIndex = idLength + 1; + if (buffer[bufferIndex] == AlarmCommandBuilder::ID_END_CHARACTER) + { + foundEnd = true; + } + else if (idLength < AlarmMessageId::MAX_LENGTH) + { + this->idBuffer.at(idLength) = buffer[bufferIndex]; + ++idLength; + } + } - // Characters a + b + c + d + 1 + 2 + 3 = 7 charactersf - const auto idLength = 7; - const std::array message = { - 'T', 'h', 'i', 's', ' ', - 'i', 's', ' ', - 't', 'h', 'e', ' ', - 'm', 'e', 's', 's', 'a', 'g', 'e', '.'}; - const std::array designator = {'1', '2', '3'}; + // If the terminating character, }, was not found then it is an invalid string + if (!foundEnd) + { + throw; + } + else + { + this->idLength = idLength; - // TODO: Catch error from message ID - const auto messageId = ProtocolMessage::deserializeAlarmMessageId(start, end); + // Add 2 to the index value since that will account for the deliminating characters, '[' and ']' + return idLength + 2; + } +} - // TODO: Catch error from type designator - const auto typeDesignator = ProtocolMessage::deserializeAlarmTypeDesignator(start, end); +size_t AlarmCommandBuilder::deserializeTypeDesignatorBytes(const char *const buffer, const size_t numBytes) +{ + if ((numBytes == 0) || buffer[0] != AlarmCommandBuilder::DESIGNATOR_START_CHARACTER) + { + return 0; + } + + auto designatorLength = 0; + auto foundEnd = false; + while ((designatorLength < (AlarmTypeDesignator::DESIGNATOR_LENGTH + 1)) && (designatorLength < numBytes) && !foundEnd) + { + // Need to offset the index by 1 since we have to account for the starting character, { + auto bufferIndex = designatorLength + 1; + if (buffer[bufferIndex] == AlarmCommandBuilder::DESIGNATOR_END_CHARACTER) + { + foundEnd = true; + } + else if (designatorLength < AlarmTypeDesignator::DESIGNATOR_LENGTH) + { + this->designatorBuffer.at(designatorLength) = buffer[bufferIndex]; + ++designatorLength; + } + } - return AlarmCommand(level, AlarmMessage(message), std::move(messageId), std::move(typeDesignator)); + if (!foundEnd || (designatorLength != AlarmTypeDesignator::DESIGNATOR_LENGTH && designatorLength != 0)) + { + throw; + } + else + { + this->designatorLength = designatorLength; + + // Add 2 to the index value since that will account for the deliminating characters, '{' and '}' + return designatorLength + 2; + } } -ProtocolMessage ProtocolMessage::deserialize(const std::array buffer) +size_t AlarmCommandBuilder::deserializeMessageBytes(const char *const buffer, const size_t numBytes) { - auto bufferIterator = buffer.cbegin(); - const auto bufferIteratorEnd = buffer.cend(); + return 0; +} - // TODO: This should be wrapped in a try/catch if there isn't a 0th element - auto commandType = static_cast(*bufferIterator); +AlarmCommand AlarmCommandBuilder::buildAlarmCommand(const char *const buffer, const size_t numBytes) +{ + AlarmCommandBuilder builder = AlarmCommandBuilder(); - switch (commandType) + auto totalBytes = builder.deserializeLevelBytes(buffer, numBytes); + + if ((numBytes - totalBytes) > 0) { - case CommandType::ALARM: - return ProtocolMessage(ProtocolMessage::deserializeAlarmCommand(++bufferIterator, bufferIteratorEnd)); - case CommandType::INFO: - return ProtocolMessage(InfoCommand()); + totalBytes += builder.deserializeIdBytes(buffer + totalBytes, numBytes - totalBytes); } - // In the event the switch falls through, throw an error - throw; + if ((numBytes - totalBytes) > 0) + { + totalBytes += builder.deserializeTypeDesignatorBytes(buffer + totalBytes, numBytes - totalBytes); + } + + if ((numBytes - totalBytes) > 0) + { + + totalBytes += builder.deserializeMessageBytes(buffer + totalBytes, numBytes - totalBytes); + } + + const auto messageId = AlarmMessageId(builder.idLength, std::move(builder.idBuffer)); + const auto typeDesignator = AlarmTypeDesignator(std::move(builder.designatorBuffer), (builder.designatorLength == 0)); + const auto message = AlarmMessage(builder.messageLength, std::move(builder.messageBuffer)); + + return AlarmCommand(builder.level, std::move(message), std::move(messageId), std::move(typeDesignator)); } diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 9c6f4d27..16bcf8ea 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -25,14 +25,15 @@ namespace protocol public: static const size_t MAX_LENGTH = 80; + using Buffer = std::array; + private: - std::array message; - size_t messageLength; + const size_t messageLength; + const std::array message; public: - explicit AlarmMessage( - const std::array message) - : message(std::move(message)) {}; + explicit AlarmMessage(const size_t messageLength, const Buffer message) + : messageLength(messageLength), message(std::move(message)) {}; AlarmMessage(AlarmMessage &&other) = default; AlarmMessage operator=(AlarmMessage &&other) { return std::move(other); } @@ -53,20 +54,18 @@ namespace protocol public: // TODO: Find out what this value is SUPPOSED to be. static const size_t MAX_LENGTH = 10; - static const char ID_START_CHARACTER = '{'; - static const char ID_END_CHARACTER = '}'; + + using Buffer = std::array; private: static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; - private: + public: const size_t idLength; const std::array id; public: - explicit AlarmMessageId( - const size_t idLength, - const std::array id); + explicit AlarmMessageId(const size_t idLength, const Buffer id); AlarmMessageId(AlarmMessageId &&other) = default; AlarmMessageId(const AlarmMessageId &&other) : id(std::move(other.id)), idLength(other.idLength) {} @@ -83,29 +82,27 @@ namespace protocol private: static std::array validateId(const size_t idLength, - const std::array); + const Buffer); }; class AlarmTypeDesignator final : Printable { public: static const size_t DESIGNATOR_LENGTH = 3; - static const char DESIGNATOR_START_CHARACTER = '['; - static const char DESIGNATOR_END_CHARACTER = ']'; + using Buffer = std::array; private: static const size_t TOTAL_DESIGNATOR_LENGTH = AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; const std::array designator; + const bool empty; public: - AlarmTypeDesignator( - const std::array - designator); + AlarmTypeDesignator(const Buffer designator, const bool empty); AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; AlarmTypeDesignator(const AlarmTypeDesignator &&other) - : designator(std::move(other.designator)) {} + : designator(std::move(other.designator)), empty(other.empty) {} AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) { return std::move(source); @@ -128,8 +125,7 @@ namespace protocol private: static std::array - validateDesignator( - const std::array); + validateDesignator(const Buffer buffer, const bool empty); }; class AlarmCommand final @@ -211,18 +207,6 @@ namespace protocol using ProtocolBuffer = std::array; - // Methods and static functions - private: - static AlarmCommand - deserializeAlarmCommand(ProtocolBuffer::const_iterator start, - const ProtocolBuffer::const_iterator end); - static AlarmMessageId - deserializeAlarmMessageId(ProtocolBuffer::const_iterator start, - const ProtocolBuffer::const_iterator end); - static AlarmTypeDesignator - deserializeAlarmTypeDesignator(ProtocolBuffer::const_iterator start, - const ProtocolBuffer::const_iterator end); - // Constructors and operator overloads public: ProtocolMessage(AlarmCommand alarmCommand) @@ -259,7 +243,49 @@ namespace protocol // TODO: This needs to throw an error if the message could not be deserialized static ProtocolMessage - deserialize(const std::array buffer); + deserialize(const char *const buffer, const size_t numBytes); + }; + + class AlarmCommandBuilder final + { + private: + static const char ID_START_CHARACTER = '{'; + static const char ID_END_CHARACTER = '}'; + + static const char DESIGNATOR_START_CHARACTER = '['; + static const char DESIGNATOR_END_CHARACTER = ']'; + + private: + AlarmCommand::Level level; + + size_t idLength; + AlarmMessageId::Buffer idBuffer; + + size_t designatorLength; + AlarmTypeDesignator::Buffer designatorBuffer; + + size_t messageLength; + AlarmMessage::Buffer messageBuffer; + + private: + AlarmCommandBuilder(); + + size_t deserializeLevelBytes(const char *const buffer, size_t numBytes); + size_t deserializeIdBytes(const char *const buffer, const size_t numBytes); + size_t deserializeTypeDesignatorBytes(const char *const buffer, const size_t numBytes); + size_t deserializeMessageBytes(const char *const buffer, const size_t numBytes); + + public: + static AlarmCommand buildAlarmCommand(const char *const buffer, const size_t numBytes); + + AlarmCommandBuilder(AlarmCommandBuilder &&other) = default; + AlarmCommandBuilder operator=(AlarmCommandBuilder &&other) + { + return std::move(other); + } + + AlarmCommandBuilder(AlarmCommandBuilder &other) = delete; + AlarmCommandBuilder operator=(AlarmCommandBuilder &other) = delete; }; } // namespace protocol From 75555c144a6113087debf7c17d4854eb242a64af Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:02:37 -0400 Subject: [PATCH 15/36] (#387): Adding the other commands and deserializing the AlarmMessage --- Firmware/GPAD_API/GPAD_API/protocol.cpp | 28 +++++++++++++------- Firmware/GPAD_API/GPAD_API/protocol.h | 34 +++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index a8275de8..c028b117 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -131,20 +131,24 @@ ProtocolMessage ProtocolMessage::deserialize(const char *const buffer, const siz switch (commandType) { case CommandType::ALARM: - if ((numBytes - 1) >= 1) - { - return ProtocolMessage(AlarmCommandBuilder::buildAlarmCommand(buffer + 1, numBytes - 1)); - } - else + if ((numBytes - 1) == 0) { throw; } + return ProtocolMessage(AlarmCommandBuilder::buildAlarmCommand(buffer + 1, numBytes - 1)); + case CommandType::INFO: return ProtocolMessage(InfoCommand()); - } - // In the event the switch falls through, throw an error - throw; + case CommandType::MUTE: + return ProtocolMessage(MuteCommand()); + + case CommandType::UNMUTE: + return ProtocolMessage(UnmuteCommand()); + + case CommandType::HELP: + return ProtocolMessage(HelpCommand()); + } } AlarmCommandBuilder::AlarmCommandBuilder() @@ -247,7 +251,13 @@ size_t AlarmCommandBuilder::deserializeTypeDesignatorBytes(const char *const buf size_t AlarmCommandBuilder::deserializeMessageBytes(const char *const buffer, const size_t numBytes) { - return 0; + auto messageLength = 0; + for (; messageLength < numBytes; ++messageLength) + { + this->messageBuffer.at(messageLength) = buffer[messageLength]; + } + + return messageLength; } AlarmCommand AlarmCommandBuilder::buildAlarmCommand(const char *const buffer, const size_t numBytes) diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index 16bcf8ea..eec704fc 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -192,6 +192,18 @@ namespace protocol InfoCommand(const InfoCommand &other) = delete; }; + class MuteCommand final + { + }; + + class UnmuteCommand final + { + }; + + class HelpCommand final + { + }; + struct ProtocolMessage final { public: @@ -201,6 +213,9 @@ namespace protocol { AlarmCommand alarm; InfoCommand info; + MuteCommand mute; + UnmuteCommand unmute; + HelpCommand help; }; const CommandType commandType; @@ -209,10 +224,16 @@ namespace protocol // Constructors and operator overloads public: - ProtocolMessage(AlarmCommand alarmCommand) + ProtocolMessage(AlarmCommand alarmCommand) noexcept : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} - ProtocolMessage(InfoCommand infoCommand) + ProtocolMessage(InfoCommand infoCommand) noexcept : commandType(CommandType::INFO), info(std::move(infoCommand)) {} + ProtocolMessage(MuteCommand muteCommand) noexcept + : commandType(CommandType::MUTE), mute(std::move(muteCommand)) {} + ProtocolMessage(UnmuteCommand unmuteCommand) noexcept + : commandType(CommandType::UNMUTE), unmute(std::move(unmuteCommand)) {} + ProtocolMessage(HelpCommand helpCommand) noexcept + : commandType(CommandType::HELP), help(std::move(helpCommand)) {} ProtocolMessage operator=(ProtocolMessage &&other) noexcept { @@ -229,6 +250,15 @@ namespace protocol case CommandType::INFO: this->info = std::move(other.info); break; + case CommandType::MUTE: + this->mute = std::move(other.mute); + break; + case CommandType::UNMUTE: + this->unmute = std::move(other.unmute); + break; + case CommandType::HELP: + this->help = std::move(other.help); + break; } } const ProtocolMessage operator=(const ProtocolMessage &&other) From dbe19f68c0f38890253f7a77f09799c2821d1457 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:18:40 -0400 Subject: [PATCH 16/36] (#387): Incorporating the new command types into the rest of the system --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 28 +- Firmware/GPAD_API/GPAD_API/GPAD_HAL.h | 9 - Firmware/GPAD_API/GPAD_API/protocol.cpp | 447 ++++++++++++------------ Firmware/GPAD_API/GPAD_API/protocol.h | 4 - 4 files changed, 245 insertions(+), 243 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 5745ee6e..b1c4c1bd 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -410,6 +410,8 @@ void GPAD_HAL_setup(Stream *serialport, wifi_mode_t wifiMode, IPAddress &deviceI // the Hardware Abstraction Layer. void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *client) { + using namespace protocol; + if (rlen < 1) { printError(serialport); @@ -428,25 +430,31 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie return; } - Command command = static_cast(buf[0]); - char commandChar = static_cast(command); + const auto protocolMessage = ProtocolMessage::deserialize(buf, rlen); serialport->print(F("Command: ")); - serialport->printf("%c\n", commandChar); - switch (command) + serialport->printf("%c\n", protocolMessage.commandType); + + switch (protocolMessage.commandType) + { + case CommandType::MUTE: { - case Command::MUTE: serialport->println(F("Muting Case!")); currentlyMuted = true; break; - case Command::UNMUTE: + } + case CommandType::UNMUTE: + { serialport->println(F("UnMuting Case!")); currentlyMuted = false; break; - case Command::HELP: // help + } + case CommandType::HELP: + { printInstructions(serialport); break; - case Command::ALARM: + } + case CommandType::ALARM: { // In the case of an alarm state, the rest of the buffer is a message. // we will read up to 60 characters from this buffer for display on our @@ -467,7 +475,7 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie break; } - case Command::INFO: // Information. Firmware Version, Mute Status, + case CommandType::INFO: { // Firmware Version // 81+23 = Maximum string length @@ -552,9 +560,11 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie break; // end of 'i' } default: + { serialport->println(F("Unknown Command")); break; } + } serialport->print(F("currentlyMuted : ")); serialport->println(currentlyMuted); serialport->println(F("interpret Done")); diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h index e2e62bb7..e912ab2d 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h @@ -130,15 +130,6 @@ namespace gpad_hal static const uint8_t API_MINOR_VERSION = 1; static const uint8_t API_PATCH_VERSION = 0; - enum class Command : char - { - MUTE = 's', - UNMUTE = 'u', - HELP = 'h', - ALARM = 'a', - INFO = 'i', - }; - /** * SemanticVersion stores a version following the "semantic versioning" convention * defined here: https://semver.org/ diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp index c028b117..60c34044 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ b/Firmware/GPAD_API/GPAD_API/protocol.cpp @@ -2,289 +2,294 @@ #include -#include #include +#include using namespace protocol; -AlarmMessageId::AlarmMessageId(const size_t idLength, const std::array id) - : idLength(idLength), id(AlarmMessageId::validateId(idLength, id)) -{ -} +AlarmMessageId::AlarmMessageId( + const size_t idLength, + const std::array id) + : idLength(idLength), id(AlarmMessageId::validateId(idLength, id)) {} -std::array -AlarmMessageId::validateId(const size_t idLength, const std::array id) +std::array AlarmMessageId::validateId( + const size_t idLength, + const std::array id) { - std::array validatedId = {}; - auto validatedIdIterator = validatedId.begin(); - - // The recorded real-length of the message ID cannot me more than the max number of elements - if (idLength > id.size()) - { - throw; - } - - auto startIterator = id.cbegin(); - auto endIterator = id.cbegin() + idLength; - - bool allHex = std::all_of( - startIterator, - endIterator, - [&validatedIdIterator](char hexChar) - { - *validatedIdIterator = hexChar; - validatedIdIterator = std::next(validatedIdIterator, 1); - return isxdigit(hexChar); - }); - - // If all the characters are NOT hex characters we need to throw an error and cancel the creation of - // this instance. - if (!allHex) - { - throw; - } - - *validatedIdIterator = '\0'; - return validatedId; + std::array validatedId = {}; + auto validatedIdIterator = validatedId.begin(); + + // The recorded real-length of the message ID cannot me more than the max + // number of elements + if (idLength > id.size()) + { + throw; + } + + auto startIterator = id.cbegin(); + auto endIterator = id.cbegin() + idLength; + + bool allHex = std::all_of( + startIterator, endIterator, [&validatedIdIterator](char hexChar) + { + *validatedIdIterator = hexChar; + validatedIdIterator = std::next(validatedIdIterator, 1); + return isxdigit(hexChar); }); + + // If all the characters are NOT hex characters we need to throw an error and + // cancel the creation of this instance. + if (!allHex) + { + throw; + } + + *validatedIdIterator = '\0'; + return validatedId; } -AlarmTypeDesignator::AlarmTypeDesignator(const std::array designator, const bool empty) - : designator(AlarmTypeDesignator::validateDesignator(designator, empty)), empty(empty) -{ -} +AlarmTypeDesignator::AlarmTypeDesignator( + const std::array designator, + const bool empty) + : designator(AlarmTypeDesignator::validateDesignator(designator, empty)), + empty(empty) {} AlarmTypeDesignator::~AlarmTypeDesignator() = default; const char *const AlarmTypeDesignator::getValue() const { - return this->designator.data(); + return this->designator.data(); } size_t AlarmTypeDesignator::printTo(Print &print) const { - return print.print(this->getValue()); + return print.print(this->getValue()); } std::array -AlarmTypeDesignator::validateDesignator(const std::array inputDesignator, const bool empty) +AlarmTypeDesignator::validateDesignator( + const std::array + inputDesignator, + const bool empty) { - std::array designator = {}; - if (empty) - { - return designator; - } - - auto designatorIterator = designator.begin(); + std::array designator = + {}; + if (empty) + { + return designator; + } - bool allDigits = std::all_of( - inputDesignator.cbegin(), - inputDesignator.cend(), - [&](char inputCharacter) - { - *designatorIterator = inputCharacter; - designatorIterator = std::next(designatorIterator, 1); - return isdigit(inputCharacter); - }); + auto designatorIterator = designator.begin(); - // if the characters are not all digits we want to throw - if (!allDigits) - { - throw; - } + bool allDigits = std::all_of(inputDesignator.cbegin(), inputDesignator.cend(), + [&](char inputCharacter) + { + *designatorIterator = inputCharacter; + designatorIterator = + std::next(designatorIterator, 1); + return isdigit(inputCharacter); + }); - *designatorIterator = '\0'; + // if the characters are not all digits we want to throw + if (!allDigits) + { + throw; + } - return designator; -} + *designatorIterator = '\0'; -char AlarmCommand::alarmLevelIntoChar() const -{ - switch (this->level) - { - case AlarmCommand::Level::Level1: - return '1'; - case AlarmCommand::Level::Level2: - return '2'; - case AlarmCommand::Level::Level3: - return '3'; - case AlarmCommand::Level::Level4: - return '4'; - case AlarmCommand::Level::Level5: - return '5'; - } - - Serial.println("End of the level to char method"); - return '0'; + return designator; } -ProtocolMessage ProtocolMessage::deserialize(const char *const buffer, const size_t numBytes) +ProtocolMessage ProtocolMessage::deserialize(const char *const buffer, + const size_t numBytes) { - // Can't determined the message type if there are no bytes - if (numBytes == 0) + // Can't determined the message type if there are no bytes + if (numBytes == 0) + { + throw; + } + + // TODO: This should be wrapped in a try/catch if there isn't a 0th element + auto commandType = static_cast(buffer[0]); + + Serial.println("asdfsdf"); + switch (commandType) + { + case CommandType::ALARM: + if ((numBytes - 1) == 0) { - throw; + throw; } + return ProtocolMessage( + AlarmCommandBuilder::buildAlarmCommand(buffer + 1, numBytes - 1)); - // TODO: This should be wrapped in a try/catch if there isn't a 0th element - auto commandType = static_cast(buffer[0]); - - switch (commandType) - { - case CommandType::ALARM: - if ((numBytes - 1) == 0) - { - throw; - } - return ProtocolMessage(AlarmCommandBuilder::buildAlarmCommand(buffer + 1, numBytes - 1)); - - case CommandType::INFO: - return ProtocolMessage(InfoCommand()); + case CommandType::INFO: + return ProtocolMessage(InfoCommand()); - case CommandType::MUTE: - return ProtocolMessage(MuteCommand()); + case CommandType::MUTE: + return ProtocolMessage(MuteCommand()); - case CommandType::UNMUTE: - return ProtocolMessage(UnmuteCommand()); + case CommandType::UNMUTE: + return ProtocolMessage(UnmuteCommand()); - case CommandType::HELP: - return ProtocolMessage(HelpCommand()); - } + case CommandType::HELP: + return ProtocolMessage(HelpCommand()); + } } AlarmCommandBuilder::AlarmCommandBuilder() - : level(AlarmCommand::Level::Level1), - idLength(0), - idBuffer({}), - designatorLength(0), - designatorBuffer({}), - messageLength(0), + : level(AlarmCommand::Level::Level1), idLength(0), idBuffer({}), + designatorLength(0), designatorBuffer({}), messageLength(0), messageBuffer({}) {} -size_t AlarmCommandBuilder::deserializeLevelBytes(const char *const buffer, const size_t numBytes) +size_t AlarmCommandBuilder::deserializeLevelBytes(const char *const buffer, + const size_t numBytes) { - if (numBytes == 0) - { - throw; - } + if (numBytes == 0) + { + throw; + } - this->level = static_cast(buffer[0]); + this->level = static_cast(buffer[0]); - return 1; + return 1; } -size_t AlarmCommandBuilder::deserializeIdBytes(const char *const buffer, const size_t numBytes) +size_t AlarmCommandBuilder::deserializeIdBytes(const char *const buffer, + const size_t numBytes) { - if (numBytes == 0 || (buffer[0] != AlarmCommandBuilder::ID_START_CHARACTER)) + if (numBytes == 0 || (buffer[0] != AlarmCommandBuilder::ID_START_CHARACTER)) + { + return 0; + } + + auto idLength = 0; + auto foundEnd = false; + + // Going 1 more than the max since the end character, ], can be after the max + // length of the ID + while ((idLength < (AlarmMessageId::MAX_LENGTH + 1)) && + (idLength < numBytes) && !foundEnd) + { + // Need to offset the index by 1 since we have to account for the starting + // character, [ + auto bufferIndex = idLength + 1; + if (buffer[bufferIndex] == AlarmCommandBuilder::ID_END_CHARACTER) { - return 0; + foundEnd = true; } - - auto idLength = 0; - auto foundEnd = false; - - // Going 1 more than the max since the end character, ], can be after the max length of the ID - while ((idLength < (AlarmMessageId::MAX_LENGTH + 1)) && (idLength < numBytes) && !foundEnd) - { - // Need to offset the index by 1 since we have to account for the starting character, [ - auto bufferIndex = idLength + 1; - if (buffer[bufferIndex] == AlarmCommandBuilder::ID_END_CHARACTER) - { - foundEnd = true; - } - else if (idLength < AlarmMessageId::MAX_LENGTH) - { - this->idBuffer.at(idLength) = buffer[bufferIndex]; - ++idLength; - } - } - - // If the terminating character, }, was not found then it is an invalid string - if (!foundEnd) - { - throw; - } - else + else if (idLength < AlarmMessageId::MAX_LENGTH) { - this->idLength = idLength; - - // Add 2 to the index value since that will account for the deliminating characters, '[' and ']' - return idLength + 2; + this->idBuffer.at(idLength) = buffer[bufferIndex]; + ++idLength; } + } + + // If the terminating character, }, was not found then it is an invalid string + if (!foundEnd) + { + throw; + } + else + { + this->idLength = idLength; + + // Add 2 to the index value since that will account for the deliminating + // characters, '[' and ']' + return idLength + 2; + } } -size_t AlarmCommandBuilder::deserializeTypeDesignatorBytes(const char *const buffer, const size_t numBytes) +size_t +AlarmCommandBuilder::deserializeTypeDesignatorBytes(const char *const buffer, + const size_t numBytes) { - if ((numBytes == 0) || buffer[0] != AlarmCommandBuilder::DESIGNATOR_START_CHARACTER) + if ((numBytes == 0) || + buffer[0] != AlarmCommandBuilder::DESIGNATOR_START_CHARACTER) + { + return 0; + } + + auto designatorLength = 0; + auto foundEnd = false; + while ((designatorLength < (AlarmTypeDesignator::DESIGNATOR_LENGTH + 1)) && + (designatorLength < numBytes) && !foundEnd) + { + // Need to offset the index by 1 since we have to account for the starting + // character, { + auto bufferIndex = designatorLength + 1; + if (buffer[bufferIndex] == AlarmCommandBuilder::DESIGNATOR_END_CHARACTER) { - return 0; + foundEnd = true; } - - auto designatorLength = 0; - auto foundEnd = false; - while ((designatorLength < (AlarmTypeDesignator::DESIGNATOR_LENGTH + 1)) && (designatorLength < numBytes) && !foundEnd) - { - // Need to offset the index by 1 since we have to account for the starting character, { - auto bufferIndex = designatorLength + 1; - if (buffer[bufferIndex] == AlarmCommandBuilder::DESIGNATOR_END_CHARACTER) - { - foundEnd = true; - } - else if (designatorLength < AlarmTypeDesignator::DESIGNATOR_LENGTH) - { - this->designatorBuffer.at(designatorLength) = buffer[bufferIndex]; - ++designatorLength; - } - } - - if (!foundEnd || (designatorLength != AlarmTypeDesignator::DESIGNATOR_LENGTH && designatorLength != 0)) + else if (designatorLength < AlarmTypeDesignator::DESIGNATOR_LENGTH) { - throw; - } - else - { - this->designatorLength = designatorLength; - - // Add 2 to the index value since that will account for the deliminating characters, '{' and '}' - return designatorLength + 2; + this->designatorBuffer.at(designatorLength) = buffer[bufferIndex]; + ++designatorLength; } + } + + if (!foundEnd || + (designatorLength != AlarmTypeDesignator::DESIGNATOR_LENGTH && + designatorLength != 0)) + { + throw; + } + else + { + this->designatorLength = designatorLength; + + // Add 2 to the index value since that will account for the deliminating + // characters, '{' and '}' + return designatorLength + 2; + } } -size_t AlarmCommandBuilder::deserializeMessageBytes(const char *const buffer, const size_t numBytes) +size_t AlarmCommandBuilder::deserializeMessageBytes(const char *const buffer, + const size_t numBytes) { - auto messageLength = 0; - for (; messageLength < numBytes; ++messageLength) - { - this->messageBuffer.at(messageLength) = buffer[messageLength]; - } + auto messageLength = 0; + for (; messageLength < numBytes; ++messageLength) + { + this->messageBuffer.at(messageLength) = buffer[messageLength]; + } - return messageLength; + return messageLength; } -AlarmCommand AlarmCommandBuilder::buildAlarmCommand(const char *const buffer, const size_t numBytes) +AlarmCommand AlarmCommandBuilder::buildAlarmCommand(const char *const buffer, + const size_t numBytes) { - AlarmCommandBuilder builder = AlarmCommandBuilder(); - - auto totalBytes = builder.deserializeLevelBytes(buffer, numBytes); - - if ((numBytes - totalBytes) > 0) - { - totalBytes += builder.deserializeIdBytes(buffer + totalBytes, numBytes - totalBytes); - } - - if ((numBytes - totalBytes) > 0) - { - totalBytes += builder.deserializeTypeDesignatorBytes(buffer + totalBytes, numBytes - totalBytes); - } - - if ((numBytes - totalBytes) > 0) - { - - totalBytes += builder.deserializeMessageBytes(buffer + totalBytes, numBytes - totalBytes); - } - - const auto messageId = AlarmMessageId(builder.idLength, std::move(builder.idBuffer)); - const auto typeDesignator = AlarmTypeDesignator(std::move(builder.designatorBuffer), (builder.designatorLength == 0)); - const auto message = AlarmMessage(builder.messageLength, std::move(builder.messageBuffer)); - - return AlarmCommand(builder.level, std::move(message), std::move(messageId), std::move(typeDesignator)); + AlarmCommandBuilder builder = AlarmCommandBuilder(); + + auto totalBytes = builder.deserializeLevelBytes(buffer, numBytes); + + if ((numBytes - totalBytes) > 0) + { + totalBytes += + builder.deserializeIdBytes(buffer + totalBytes, numBytes - totalBytes); + } + + if ((numBytes - totalBytes) > 0) + { + totalBytes += builder.deserializeTypeDesignatorBytes(buffer + totalBytes, + numBytes - totalBytes); + } + + if ((numBytes - totalBytes) > 0) + { + + totalBytes += builder.deserializeMessageBytes(buffer + totalBytes, + numBytes - totalBytes); + } + + const auto messageId = + AlarmMessageId(builder.idLength, std::move(builder.idBuffer)); + const auto typeDesignator = AlarmTypeDesignator( + std::move(builder.designatorBuffer), (builder.designatorLength == 0)); + const auto message = + AlarmMessage(builder.messageLength, std::move(builder.messageBuffer)); + + return AlarmCommand(builder.level, std::move(message), std::move(messageId), + std::move(typeDesignator)); } diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h index eec704fc..4d5f148a 100644 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ b/Firmware/GPAD_API/GPAD_API/protocol.h @@ -7,8 +7,6 @@ namespace protocol { - - union Command; class ProtocolMessage; enum class CommandType : char @@ -171,8 +169,6 @@ namespace protocol AlarmCommand() = delete; AlarmCommand(AlarmCommand &other) = delete; AlarmCommand(const AlarmCommand &other) = delete; - - char alarmLevelIntoChar() const; }; class InfoCommand final From e039cfa626b50b38a76578baf633dab9160c7088 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 29 Mar 2026 21:57:32 -0400 Subject: [PATCH 17/36] (#387): Moving the GPAP protocol stuff into its own library --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 20 +- Firmware/GPAD_API/GPAD_API/protocol.cpp | 295 ---------------- Firmware/GPAD_API/GPAD_API/protocol.h | 319 ------------------ .../lib/GPAP/AlarmMessage/AlarmContent.h | 35 ++ .../lib/GPAP/AlarmMessage/AlarmMessage.h | 59 ++++ .../lib/GPAP/AlarmMessage/AlarmMessageId.cpp | 45 +++ .../lib/GPAP/AlarmMessage/AlarmMessageId.h | 45 +++ .../GPAP/AlarmMessage/AlarmTypeDesignator.cpp | 60 ++++ .../GPAP/AlarmMessage/AlarmTypeDesignator.h | 54 +++ .../AlarmMessageBuilder.cpp | 163 +++++++++ .../AlarmMessageBuilder/AlarmMessageBuilder.h | 53 +++ Firmware/GPAD_API/lib/GPAP/GPAP.cpp | 38 +++ Firmware/GPAD_API/lib/GPAP/GPAP.h | 88 +++++ 13 files changed, 649 insertions(+), 625 deletions(-) delete mode 100644 Firmware/GPAD_API/GPAD_API/protocol.cpp delete mode 100644 Firmware/GPAD_API/GPAD_API/protocol.h create mode 100644 Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h create mode 100644 Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessage.h create mode 100644 Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp create mode 100644 Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h create mode 100644 Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp create mode 100644 Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h create mode 100644 Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp create mode 100644 Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h create mode 100644 Firmware/GPAD_API/lib/GPAP/GPAP.cpp create mode 100644 Firmware/GPAD_API/lib/GPAP/GPAP.h diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index b1c4c1bd..91e8652b 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -25,7 +25,7 @@ #include #include "WiFiManagerOTA.h" #include "GPAD_menu.h" -#include "protocol.h" +#include "GPAP.h" using namespace gpad_hal; @@ -410,8 +410,6 @@ void GPAD_HAL_setup(Stream *serialport, wifi_mode_t wifiMode, IPAddress &deviceI // the Hardware Abstraction Layer. void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *client) { - using namespace protocol; - if (rlen < 1) { printError(serialport); @@ -430,31 +428,31 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie return; } - const auto protocolMessage = ProtocolMessage::deserialize(buf, rlen); + const auto protocolMessage = gpap_message::GPAPMessage::deserialize(buf, rlen); serialport->print(F("Command: ")); - serialport->printf("%c\n", protocolMessage.commandType); + serialport->printf("%c\n", protocolMessage.messageType); - switch (protocolMessage.commandType) + switch (protocolMessage.messageType) { - case CommandType::MUTE: + case gpap_message::MessageType::MUTE: { serialport->println(F("Muting Case!")); currentlyMuted = true; break; } - case CommandType::UNMUTE: + case gpap_message::MessageType::UNMUTE: { serialport->println(F("UnMuting Case!")); currentlyMuted = false; break; } - case CommandType::HELP: + case gpap_message::MessageType::HELP: { printInstructions(serialport); break; } - case CommandType::ALARM: + case gpap_message::MessageType::ALARM: { // In the case of an alarm state, the rest of the buffer is a message. // we will read up to 60 characters from this buffer for display on our @@ -475,7 +473,7 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie break; } - case CommandType::INFO: + case gpap_message::MessageType::INFO: { // Firmware Version // 81+23 = Maximum string length diff --git a/Firmware/GPAD_API/GPAD_API/protocol.cpp b/Firmware/GPAD_API/GPAD_API/protocol.cpp deleted file mode 100644 index 60c34044..00000000 --- a/Firmware/GPAD_API/GPAD_API/protocol.cpp +++ /dev/null @@ -1,295 +0,0 @@ -#include - -#include - -#include -#include - -using namespace protocol; - -AlarmMessageId::AlarmMessageId( - const size_t idLength, - const std::array id) - : idLength(idLength), id(AlarmMessageId::validateId(idLength, id)) {} - -std::array AlarmMessageId::validateId( - const size_t idLength, - const std::array id) -{ - std::array validatedId = {}; - auto validatedIdIterator = validatedId.begin(); - - // The recorded real-length of the message ID cannot me more than the max - // number of elements - if (idLength > id.size()) - { - throw; - } - - auto startIterator = id.cbegin(); - auto endIterator = id.cbegin() + idLength; - - bool allHex = std::all_of( - startIterator, endIterator, [&validatedIdIterator](char hexChar) - { - *validatedIdIterator = hexChar; - validatedIdIterator = std::next(validatedIdIterator, 1); - return isxdigit(hexChar); }); - - // If all the characters are NOT hex characters we need to throw an error and - // cancel the creation of this instance. - if (!allHex) - { - throw; - } - - *validatedIdIterator = '\0'; - return validatedId; -} - -AlarmTypeDesignator::AlarmTypeDesignator( - const std::array designator, - const bool empty) - : designator(AlarmTypeDesignator::validateDesignator(designator, empty)), - empty(empty) {} - -AlarmTypeDesignator::~AlarmTypeDesignator() = default; - -const char *const AlarmTypeDesignator::getValue() const -{ - return this->designator.data(); -} - -size_t AlarmTypeDesignator::printTo(Print &print) const -{ - return print.print(this->getValue()); -} - -std::array -AlarmTypeDesignator::validateDesignator( - const std::array - inputDesignator, - const bool empty) -{ - std::array designator = - {}; - if (empty) - { - return designator; - } - - auto designatorIterator = designator.begin(); - - bool allDigits = std::all_of(inputDesignator.cbegin(), inputDesignator.cend(), - [&](char inputCharacter) - { - *designatorIterator = inputCharacter; - designatorIterator = - std::next(designatorIterator, 1); - return isdigit(inputCharacter); - }); - - // if the characters are not all digits we want to throw - if (!allDigits) - { - throw; - } - - *designatorIterator = '\0'; - - return designator; -} - -ProtocolMessage ProtocolMessage::deserialize(const char *const buffer, - const size_t numBytes) -{ - // Can't determined the message type if there are no bytes - if (numBytes == 0) - { - throw; - } - - // TODO: This should be wrapped in a try/catch if there isn't a 0th element - auto commandType = static_cast(buffer[0]); - - Serial.println("asdfsdf"); - switch (commandType) - { - case CommandType::ALARM: - if ((numBytes - 1) == 0) - { - throw; - } - return ProtocolMessage( - AlarmCommandBuilder::buildAlarmCommand(buffer + 1, numBytes - 1)); - - case CommandType::INFO: - return ProtocolMessage(InfoCommand()); - - case CommandType::MUTE: - return ProtocolMessage(MuteCommand()); - - case CommandType::UNMUTE: - return ProtocolMessage(UnmuteCommand()); - - case CommandType::HELP: - return ProtocolMessage(HelpCommand()); - } -} - -AlarmCommandBuilder::AlarmCommandBuilder() - : level(AlarmCommand::Level::Level1), idLength(0), idBuffer({}), - designatorLength(0), designatorBuffer({}), messageLength(0), - messageBuffer({}) {} - -size_t AlarmCommandBuilder::deserializeLevelBytes(const char *const buffer, - const size_t numBytes) -{ - if (numBytes == 0) - { - throw; - } - - this->level = static_cast(buffer[0]); - - return 1; -} - -size_t AlarmCommandBuilder::deserializeIdBytes(const char *const buffer, - const size_t numBytes) -{ - if (numBytes == 0 || (buffer[0] != AlarmCommandBuilder::ID_START_CHARACTER)) - { - return 0; - } - - auto idLength = 0; - auto foundEnd = false; - - // Going 1 more than the max since the end character, ], can be after the max - // length of the ID - while ((idLength < (AlarmMessageId::MAX_LENGTH + 1)) && - (idLength < numBytes) && !foundEnd) - { - // Need to offset the index by 1 since we have to account for the starting - // character, [ - auto bufferIndex = idLength + 1; - if (buffer[bufferIndex] == AlarmCommandBuilder::ID_END_CHARACTER) - { - foundEnd = true; - } - else if (idLength < AlarmMessageId::MAX_LENGTH) - { - this->idBuffer.at(idLength) = buffer[bufferIndex]; - ++idLength; - } - } - - // If the terminating character, }, was not found then it is an invalid string - if (!foundEnd) - { - throw; - } - else - { - this->idLength = idLength; - - // Add 2 to the index value since that will account for the deliminating - // characters, '[' and ']' - return idLength + 2; - } -} - -size_t -AlarmCommandBuilder::deserializeTypeDesignatorBytes(const char *const buffer, - const size_t numBytes) -{ - if ((numBytes == 0) || - buffer[0] != AlarmCommandBuilder::DESIGNATOR_START_CHARACTER) - { - return 0; - } - - auto designatorLength = 0; - auto foundEnd = false; - while ((designatorLength < (AlarmTypeDesignator::DESIGNATOR_LENGTH + 1)) && - (designatorLength < numBytes) && !foundEnd) - { - // Need to offset the index by 1 since we have to account for the starting - // character, { - auto bufferIndex = designatorLength + 1; - if (buffer[bufferIndex] == AlarmCommandBuilder::DESIGNATOR_END_CHARACTER) - { - foundEnd = true; - } - else if (designatorLength < AlarmTypeDesignator::DESIGNATOR_LENGTH) - { - this->designatorBuffer.at(designatorLength) = buffer[bufferIndex]; - ++designatorLength; - } - } - - if (!foundEnd || - (designatorLength != AlarmTypeDesignator::DESIGNATOR_LENGTH && - designatorLength != 0)) - { - throw; - } - else - { - this->designatorLength = designatorLength; - - // Add 2 to the index value since that will account for the deliminating - // characters, '{' and '}' - return designatorLength + 2; - } -} - -size_t AlarmCommandBuilder::deserializeMessageBytes(const char *const buffer, - const size_t numBytes) -{ - auto messageLength = 0; - for (; messageLength < numBytes; ++messageLength) - { - this->messageBuffer.at(messageLength) = buffer[messageLength]; - } - - return messageLength; -} - -AlarmCommand AlarmCommandBuilder::buildAlarmCommand(const char *const buffer, - const size_t numBytes) -{ - AlarmCommandBuilder builder = AlarmCommandBuilder(); - - auto totalBytes = builder.deserializeLevelBytes(buffer, numBytes); - - if ((numBytes - totalBytes) > 0) - { - totalBytes += - builder.deserializeIdBytes(buffer + totalBytes, numBytes - totalBytes); - } - - if ((numBytes - totalBytes) > 0) - { - totalBytes += builder.deserializeTypeDesignatorBytes(buffer + totalBytes, - numBytes - totalBytes); - } - - if ((numBytes - totalBytes) > 0) - { - - totalBytes += builder.deserializeMessageBytes(buffer + totalBytes, - numBytes - totalBytes); - } - - const auto messageId = - AlarmMessageId(builder.idLength, std::move(builder.idBuffer)); - const auto typeDesignator = AlarmTypeDesignator( - std::move(builder.designatorBuffer), (builder.designatorLength == 0)); - const auto message = - AlarmMessage(builder.messageLength, std::move(builder.messageBuffer)); - - return AlarmCommand(builder.level, std::move(message), std::move(messageId), - std::move(typeDesignator)); -} diff --git a/Firmware/GPAD_API/GPAD_API/protocol.h b/Firmware/GPAD_API/GPAD_API/protocol.h deleted file mode 100644 index 4d5f148a..00000000 --- a/Firmware/GPAD_API/GPAD_API/protocol.h +++ /dev/null @@ -1,319 +0,0 @@ -#ifndef _PROTOCOL_H -#define _PROTOCOL_H - -#include - -#include - -namespace protocol -{ - class ProtocolMessage; - - enum class CommandType : char - { - MUTE = 's', - UNMUTE = 'u', - HELP = 'h', - ALARM = 'a', - INFO = 'i', - }; - - class AlarmMessage final - { - public: - static const size_t MAX_LENGTH = 80; - - using Buffer = std::array; - - private: - const size_t messageLength; - const std::array message; - - public: - explicit AlarmMessage(const size_t messageLength, const Buffer message) - : messageLength(messageLength), message(std::move(message)) {}; - - AlarmMessage(AlarmMessage &&other) = default; - AlarmMessage operator=(AlarmMessage &&other) { return std::move(other); } - AlarmMessage(const AlarmMessage &&other) - : message(std::move(other.message)), messageLength(other.messageLength) {} - const AlarmMessage operator=(const AlarmMessage &&other) - { - return std::move(other); - } - - AlarmMessage() = delete; - AlarmMessage(AlarmMessage &other) = delete; - AlarmMessage(const AlarmMessage &other) = delete; - }; - - class AlarmMessageId final - { - public: - // TODO: Find out what this value is SUPPOSED to be. - static const size_t MAX_LENGTH = 10; - - using Buffer = std::array; - - private: - static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; - - public: - const size_t idLength; - const std::array id; - - public: - explicit AlarmMessageId(const size_t idLength, const Buffer id); - AlarmMessageId(AlarmMessageId &&other) = default; - AlarmMessageId(const AlarmMessageId &&other) - : id(std::move(other.id)), idLength(other.idLength) {} - AlarmMessageId operator=(AlarmMessageId &&other) { return std::move(other); } - AlarmMessageId operator=(const AlarmMessageId &&other) - { - return std::move(other); - } - - AlarmMessageId() = delete; - AlarmMessageId(AlarmMessageId &other) = delete; - AlarmMessageId(const AlarmMessageId &other) = delete; - - private: - static std::array - validateId(const size_t idLength, - const Buffer); - }; - - class AlarmTypeDesignator final : Printable - { - public: - static const size_t DESIGNATOR_LENGTH = 3; - using Buffer = std::array; - - private: - static const size_t TOTAL_DESIGNATOR_LENGTH = - AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; - const std::array designator; - const bool empty; - - public: - AlarmTypeDesignator(const Buffer designator, const bool empty); - - AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; - AlarmTypeDesignator(const AlarmTypeDesignator &&other) - : designator(std::move(other.designator)), empty(other.empty) {} - AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) - { - return std::move(source); - } - AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) - { - return std::move(source); - } - - AlarmTypeDesignator() = delete; - AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; - AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; - - virtual ~AlarmTypeDesignator(); - // Methods - public: - const char *const getValue() const; - - size_t printTo(Print &print) const override; - - private: - static std::array - validateDesignator(const Buffer buffer, const bool empty); - }; - - class AlarmCommand final - { - public: - enum class Level : char - { - Level1 = '1', - Level2 = '2', - Level3 = '3', - Level4 = '4', - Level5 = '5', - }; - - const Level level; - const AlarmMessageId messageId; - const AlarmTypeDesignator typeDesignator; - const AlarmMessage message; - - public: - explicit AlarmCommand(const AlarmCommand::Level alarmLevel, - const AlarmMessage alarmMessage, - const AlarmMessageId messageId, - const AlarmTypeDesignator typeDesignator) - : level(alarmLevel), message(std::move(alarmMessage)), - messageId(std::move(messageId)), - typeDesignator(std::move(typeDesignator)) {} - - AlarmCommand(AlarmCommand &&other) = default; - AlarmCommand(const AlarmCommand &&other) - : level(other.level), message(std::move(other.message)), - messageId(std::move(other.messageId)), - typeDesignator(std::move(other.typeDesignator)) {} - AlarmCommand operator=(AlarmCommand &&other) noexcept - { - return std::move(other); - } - AlarmCommand operator=(const AlarmCommand &&other) - { - return std::move(other); - } - - AlarmCommand() = delete; - AlarmCommand(AlarmCommand &other) = delete; - AlarmCommand(const AlarmCommand &other) = delete; - }; - - class InfoCommand final - { - public: - explicit InfoCommand() = default; - InfoCommand(InfoCommand &&other) = default; - InfoCommand operator=(InfoCommand &&other) noexcept - { - return std::move(other); - } - - InfoCommand(const InfoCommand &&other) {} - InfoCommand operator=(const InfoCommand &&other) { return std::move(other); } - - InfoCommand(InfoCommand &other) = delete; - InfoCommand(const InfoCommand &other) = delete; - }; - - class MuteCommand final - { - }; - - class UnmuteCommand final - { - }; - - class HelpCommand final - { - }; - - struct ProtocolMessage final - { - public: - static const size_t BUFFER_LENGTH = 131; - - const union - { - AlarmCommand alarm; - InfoCommand info; - MuteCommand mute; - UnmuteCommand unmute; - HelpCommand help; - }; - - const CommandType commandType; - - using ProtocolBuffer = std::array; - - // Constructors and operator overloads - public: - ProtocolMessage(AlarmCommand alarmCommand) noexcept - : commandType(CommandType::ALARM), alarm(std::move(alarmCommand)) {} - ProtocolMessage(InfoCommand infoCommand) noexcept - : commandType(CommandType::INFO), info(std::move(infoCommand)) {} - ProtocolMessage(MuteCommand muteCommand) noexcept - : commandType(CommandType::MUTE), mute(std::move(muteCommand)) {} - ProtocolMessage(UnmuteCommand unmuteCommand) noexcept - : commandType(CommandType::UNMUTE), unmute(std::move(unmuteCommand)) {} - ProtocolMessage(HelpCommand helpCommand) noexcept - : commandType(CommandType::HELP), help(std::move(helpCommand)) {} - - ProtocolMessage operator=(ProtocolMessage &&other) noexcept - { - return std::move(other); - } - ProtocolMessage(const ProtocolMessage &&other) - : commandType(other.commandType) - { - switch (this->commandType) - { - case CommandType::ALARM: - this->alarm = std::move(other.alarm); - break; - case CommandType::INFO: - this->info = std::move(other.info); - break; - case CommandType::MUTE: - this->mute = std::move(other.mute); - break; - case CommandType::UNMUTE: - this->unmute = std::move(other.unmute); - break; - case CommandType::HELP: - this->help = std::move(other.help); - break; - } - } - const ProtocolMessage operator=(const ProtocolMessage &&other) - { - return std::move(other); - } - - ProtocolMessage() = delete; - ProtocolMessage(ProtocolMessage &other) = delete; - - ~ProtocolMessage() {} - - // TODO: This needs to throw an error if the message could not be deserialized - static ProtocolMessage - deserialize(const char *const buffer, const size_t numBytes); - }; - - class AlarmCommandBuilder final - { - private: - static const char ID_START_CHARACTER = '{'; - static const char ID_END_CHARACTER = '}'; - - static const char DESIGNATOR_START_CHARACTER = '['; - static const char DESIGNATOR_END_CHARACTER = ']'; - - private: - AlarmCommand::Level level; - - size_t idLength; - AlarmMessageId::Buffer idBuffer; - - size_t designatorLength; - AlarmTypeDesignator::Buffer designatorBuffer; - - size_t messageLength; - AlarmMessage::Buffer messageBuffer; - - private: - AlarmCommandBuilder(); - - size_t deserializeLevelBytes(const char *const buffer, size_t numBytes); - size_t deserializeIdBytes(const char *const buffer, const size_t numBytes); - size_t deserializeTypeDesignatorBytes(const char *const buffer, const size_t numBytes); - size_t deserializeMessageBytes(const char *const buffer, const size_t numBytes); - - public: - static AlarmCommand buildAlarmCommand(const char *const buffer, const size_t numBytes); - - AlarmCommandBuilder(AlarmCommandBuilder &&other) = default; - AlarmCommandBuilder operator=(AlarmCommandBuilder &&other) - { - return std::move(other); - } - - AlarmCommandBuilder(AlarmCommandBuilder &other) = delete; - AlarmCommandBuilder operator=(AlarmCommandBuilder &other) = delete; - }; - -} // namespace protocol - -#endif diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h new file mode 100644 index 00000000..2a897a02 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h @@ -0,0 +1,35 @@ +#ifndef _ALARM_CONTENT_H +#define _ALARM_CONTENT_H + +#include + +class AlarmContent final +{ +public: + static const size_t MAX_LENGTH = 80; + + using Buffer = std::array; + +private: + const size_t messageLength; + const std::array message; + +public: + explicit AlarmContent(const size_t messageLength, const Buffer message) + : messageLength(messageLength), message(std::move(message)) {}; + + AlarmContent(AlarmContent &&other) = default; + AlarmContent operator=(AlarmContent &&other) { return std::move(other); } + AlarmContent(const AlarmContent &&other) + : message(std::move(other.message)), messageLength(other.messageLength) {} + const AlarmContent operator=(const AlarmContent &&other) + { + return std::move(other); + } + + AlarmContent() = delete; + AlarmContent(AlarmContent &other) = delete; + AlarmContent(const AlarmContent &other) = delete; +}; + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessage.h new file mode 100644 index 00000000..83e3ea56 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessage.h @@ -0,0 +1,59 @@ +#ifndef _ALARM_MESSAGE_H +#define _ALARM_MESSAGE_H + +#include "AlarmMessageId.h" +#include "AlarmTypeDesignator.h" +#include "AlarmContent.h" + +namespace gpap_message::alarm +{ + class AlarmMessage final + { + public: + enum class Level : char + { + Level1 = '1', + Level2 = '2', + Level3 = '3', + Level4 = '4', + Level5 = '5', + }; + + const Level level; + const AlarmMessageId messageId; + const AlarmTypeDesignator typeDesignator; + const AlarmContent content; + + public: + explicit AlarmMessage(const AlarmMessage::Level alarmLevel, + const AlarmContent alarmContent, + const AlarmMessageId messageId, + const AlarmTypeDesignator typeDesignator) + : level(alarmLevel), content(std::move(alarmContent)), + messageId(std::move(messageId)), + typeDesignator(std::move(typeDesignator)) {} + + AlarmMessage(AlarmMessage &&other) = default; + AlarmMessage(const AlarmMessage &&other) + : level(other.level), content(std::move(other.content)), + messageId(std::move(other.messageId)), + typeDesignator(std::move(other.typeDesignator)) {} + AlarmMessage operator=(AlarmMessage &&other) noexcept + { + return std::move(other); + } + AlarmMessage operator=(const AlarmMessage &&other) + { + return std::move(other); + } + + ~AlarmMessage() {} + + AlarmMessage() = delete; + AlarmMessage(AlarmMessage &other) = delete; + AlarmMessage(const AlarmMessage &other) = delete; + }; + +} // namespace alarm + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp new file mode 100644 index 00000000..0dd49eb5 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp @@ -0,0 +1,45 @@ +#include "AlarmMessageId.h" + +#include + +using namespace gpap_message::alarm; + +AlarmMessageId::AlarmMessageId( + const size_t idLength, + const std::array id) + : idLength(idLength), id(AlarmMessageId::validateId(idLength, id)) {} + +std::array AlarmMessageId::validateId( + const size_t idLength, + const std::array id) +{ + std::array validatedId = {}; + auto validatedIdIterator = validatedId.begin(); + + // The recorded real-length of the message ID cannot me more than the max + // number of elements + if (idLength > id.size()) + { + throw; + } + + auto startIterator = id.cbegin(); + auto endIterator = id.cbegin() + idLength; + + bool allHex = std::all_of( + startIterator, endIterator, [&validatedIdIterator](char hexChar) + { + *validatedIdIterator = hexChar; + validatedIdIterator = std::next(validatedIdIterator, 1); + return isxdigit(hexChar); }); + + // If all the characters are NOT hex characters we need to throw an error and + // cancel the creation of this instance. + if (!allHex) + { + throw; + } + + *validatedIdIterator = '\0'; + return validatedId; +} diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h new file mode 100644 index 00000000..f9906da2 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h @@ -0,0 +1,45 @@ +#ifndef _ALARM_MESSAGE_ID_H +#define _ALARM_MESSAGE_ID_H + +#include + +namespace gpap_message::alarm +{ + class AlarmMessageId final + { + public: + // TODO: Find out what this value is SUPPOSED to be. + static const size_t MAX_LENGTH = 10; + + using Buffer = std::array; + + private: + static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; + + public: + const size_t idLength; + const std::array id; + + public: + explicit AlarmMessageId(const size_t idLength, const Buffer id); + AlarmMessageId(AlarmMessageId &&other) = default; + AlarmMessageId(const AlarmMessageId &&other) + : id(std::move(other.id)), idLength(other.idLength) {} + AlarmMessageId operator=(AlarmMessageId &&other) { return std::move(other); } + AlarmMessageId operator=(const AlarmMessageId &&other) + { + return std::move(other); + } + + AlarmMessageId() = delete; + AlarmMessageId(AlarmMessageId &other) = delete; + AlarmMessageId(const AlarmMessageId &other) = delete; + + private: + static std::array + validateId(const size_t idLength, + const Buffer); + }; +} + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp new file mode 100644 index 00000000..f6ec66b6 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp @@ -0,0 +1,60 @@ +#include "AlarmTypeDesignator.h" + +#include + +#include + +using namespace gpap_message::alarm; + +AlarmTypeDesignator::AlarmTypeDesignator( + const std::array designator, + const bool empty) + : designator(AlarmTypeDesignator::validateDesignator(designator, empty)), + empty(empty) {} + +AlarmTypeDesignator::~AlarmTypeDesignator() = default; + +const char *const AlarmTypeDesignator::getValue() const +{ + return this->designator.data(); +} + +size_t AlarmTypeDesignator::printTo(Print &print) const +{ + return print.print(this->getValue()); +} + +std::array +AlarmTypeDesignator::validateDesignator( + const std::array + inputDesignator, + const bool empty) +{ + std::array designator = + {}; + if (empty) + { + return designator; + } + + auto designatorIterator = designator.begin(); + + bool allDigits = std::all_of(inputDesignator.cbegin(), inputDesignator.cend(), + [&](char inputCharacter) + { + *designatorIterator = inputCharacter; + designatorIterator = + std::next(designatorIterator, 1); + return isdigit(inputCharacter); + }); + + // if the characters are not all digits we want to throw + if (!allDigits) + { + throw; + } + + *designatorIterator = '\0'; + + return designator; +} diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h new file mode 100644 index 00000000..29ab38d6 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h @@ -0,0 +1,54 @@ +#ifndef _ALARM_TYPE_DESIGNATOR_H +#define _ALARM_TYPE_DESIGNATOR_H + +#include + +#include + +namespace gpap_message::alarm +{ + class AlarmTypeDesignator final : Printable + { + public: + static const size_t DESIGNATOR_LENGTH = 3; + using Buffer = std::array; + + private: + static const size_t TOTAL_DESIGNATOR_LENGTH = + AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; + const std::array designator; + const bool empty; + + public: + AlarmTypeDesignator(const Buffer designator, const bool empty); + + AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; + AlarmTypeDesignator(const AlarmTypeDesignator &&other) + : designator(std::move(other.designator)), empty(other.empty) {} + AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) + { + return std::move(source); + } + AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) + { + return std::move(source); + } + + AlarmTypeDesignator() = delete; + AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; + AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; + + virtual ~AlarmTypeDesignator(); + // Methods + public: + const char *const getValue() const; + + size_t printTo(Print &print) const override; + + private: + static std::array + validateDesignator(const Buffer buffer, const bool empty); + }; +} + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp new file mode 100644 index 00000000..66eccfba --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -0,0 +1,163 @@ +#include "AlarmMessageBuilder.h" + +using namespace gpap_message::alarm; +using namespace gpap_message::deserialize; + +AlarmMessageBuilder::AlarmMessageBuilder() + : level(AlarmMessage::Level::Level1), idLength(0), idBuffer({}), + designatorLength(0), designatorBuffer({}), messageLength(0), + messageBuffer({}) +{ +} + +size_t AlarmMessageBuilder::deserializeLevelBytes(const char *const buffer, + const size_t numBytes) +{ + if (numBytes == 0) + { + throw; + } + + this->level = static_cast(buffer[0]); + + return 1; +} + +size_t AlarmMessageBuilder::deserializeIdBytes(const char *const buffer, + const size_t numBytes) +{ + if (numBytes == 0 || (buffer[0] != AlarmMessageBuilder::ID_START_CHARACTER)) + { + return 0; + } + + auto idLength = 0; + auto foundEnd = false; + + // Going 1 more than the max since the end character, ], can be after the max + // length of the ID + while ((idLength < (AlarmMessageId::MAX_LENGTH + 1)) && + (idLength < numBytes) && !foundEnd) + { + // Need to offset the index by 1 since we have to account for the starting + // character, [ + auto bufferIndex = idLength + 1; + if (buffer[bufferIndex] == AlarmMessageBuilder::ID_END_CHARACTER) + { + foundEnd = true; + } + else if (idLength < AlarmMessageId::MAX_LENGTH) + { + this->idBuffer.at(idLength) = buffer[bufferIndex]; + ++idLength; + } + } + + // If the terminating character, }, was not found then it is an invalid string + if (!foundEnd) + { + throw; + } + else + { + this->idLength = idLength; + + // Add 2 to the index value since that will account for the deliminating + // characters, '[' and ']' + return idLength + 2; + } +} + +size_t +AlarmMessageBuilder::deserializeTypeDesignatorBytes(const char *const buffer, + const size_t numBytes) +{ + if ((numBytes == 0) || + buffer[0] != AlarmMessageBuilder::DESIGNATOR_START_CHARACTER) + { + return 0; + } + + auto designatorLength = 0; + auto foundEnd = false; + while ((designatorLength < (AlarmTypeDesignator::DESIGNATOR_LENGTH + 1)) && + (designatorLength < numBytes) && !foundEnd) + { + // Need to offset the index by 1 since we have to account for the starting + // character, { + auto bufferIndex = designatorLength + 1; + if (buffer[bufferIndex] == AlarmMessageBuilder::DESIGNATOR_END_CHARACTER) + { + foundEnd = true; + } + else if (designatorLength < AlarmTypeDesignator::DESIGNATOR_LENGTH) + { + this->designatorBuffer.at(designatorLength) = buffer[bufferIndex]; + ++designatorLength; + } + } + + if (!foundEnd || + (designatorLength != AlarmTypeDesignator::DESIGNATOR_LENGTH && + designatorLength != 0)) + { + throw; + } + else + { + this->designatorLength = designatorLength; + + // Add 2 to the index value since that will account for the deliminating + // characters, '{' and '}' + return designatorLength + 2; + } +} + +size_t AlarmMessageBuilder::deserializeMessageBytes(const char *const buffer, + const size_t numBytes) +{ + auto messageLength = 0; + for (; messageLength < numBytes; ++messageLength) + { + this->messageBuffer.at(messageLength) = buffer[messageLength]; + } + + return messageLength; +} + +AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, + const size_t numBytes) +{ + AlarmMessageBuilder builder = AlarmMessageBuilder(); + + auto totalBytes = builder.deserializeLevelBytes(buffer, numBytes); + + if ((numBytes - totalBytes) > 0) + { + totalBytes += + builder.deserializeIdBytes(buffer + totalBytes, numBytes - totalBytes); + } + + if ((numBytes - totalBytes) > 0) + { + totalBytes += builder.deserializeTypeDesignatorBytes(buffer + totalBytes, + numBytes - totalBytes); + } + + if ((numBytes - totalBytes) > 0) + { + + totalBytes += builder.deserializeMessageBytes(buffer + totalBytes, + numBytes - totalBytes); + } + + const auto messageId = + AlarmMessageId(builder.idLength, std::move(builder.idBuffer)); + const auto typeDesignator = AlarmTypeDesignator( + std::move(builder.designatorBuffer), (builder.designatorLength == 0)); + const auto content = + AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); + + return AlarmMessage(builder.level, std::move(content), std::move(messageId), + std::move(typeDesignator)); +} diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h new file mode 100644 index 00000000..dde31a9b --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -0,0 +1,53 @@ +#ifndef _ALARM_MESSAGE_BUILDER_H +#define _ALARM_MESSAGE_BUILDER_H + +#include "AlarmMessage/AlarmMessage.h" + +namespace gpap_message::deserialize +{ + + class AlarmMessageBuilder final + { + + private: + static const char ID_START_CHARACTER = '{'; + static const char ID_END_CHARACTER = '}'; + + static const char DESIGNATOR_START_CHARACTER = '['; + static const char DESIGNATOR_END_CHARACTER = ']'; + + private: + alarm::AlarmMessage::Level level; + + size_t idLength; + alarm::AlarmMessageId::Buffer idBuffer; + + size_t designatorLength; + alarm::AlarmTypeDesignator::Buffer designatorBuffer; + + size_t messageLength; + AlarmContent::Buffer messageBuffer; + + private: + AlarmMessageBuilder(); + + size_t deserializeLevelBytes(const char *const buffer, size_t numBytes); + size_t deserializeIdBytes(const char *const buffer, const size_t numBytes); + size_t deserializeTypeDesignatorBytes(const char *const buffer, const size_t numBytes); + size_t deserializeMessageBytes(const char *const buffer, const size_t numBytes); + + public: + static alarm::AlarmMessage buildAlarmMessage(const char *const buffer, const size_t numBytes); + + AlarmMessageBuilder(AlarmMessageBuilder &&other) = default; + AlarmMessageBuilder operator=(AlarmMessageBuilder &&other) + { + return std::move(other); + } + + AlarmMessageBuilder(AlarmMessageBuilder &other) = delete; + AlarmMessageBuilder operator=(AlarmMessageBuilder &other) = delete; + }; +} + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/GPAP.cpp b/Firmware/GPAD_API/lib/GPAP/GPAP.cpp new file mode 100644 index 00000000..43d02140 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/GPAP.cpp @@ -0,0 +1,38 @@ +#include "GPAP.h" +#include "Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h" + +using namespace gpap_message; +GPAPMessage GPAPMessage::deserialize(const char *const buffer, const size_t numBytes) +{ + // Can't determined the message type if there are no bytes + if (numBytes == 0) + { + throw; + } + + // TODO: This should be wrapped in a try/catch if there isn't a 0th element + auto messageType = static_cast(buffer[0]); + + switch (messageType) + { + case MessageType::ALARM: + if ((numBytes - 1) == 0) + { + throw; + } + return std::move(GPAPMessage(deserialize::AlarmMessageBuilder::buildAlarmMessage(buffer + 1, numBytes - 1))); + + // case MessageType::INFO: + // return ProtocolMessage(InfoCommand()); + + // case MessageType::MUTE: + // return ProtocolMessage(MuteCommand()); + + // case MessageType::UNMUTE: + // return ProtocolMessage(UnmuteCommand()); + + // case MessageType::HELP: + // return ProtocolMessage(HelpCommand()); + // } + } +} \ No newline at end of file diff --git a/Firmware/GPAD_API/lib/GPAP/GPAP.h b/Firmware/GPAD_API/lib/GPAP/GPAP.h new file mode 100644 index 00000000..6aa15340 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/GPAP.h @@ -0,0 +1,88 @@ +#ifndef _GPAP_MESSAGE_H +#define _GPAP_MESSAGE_H + +#include "AlarmMessage/AlarmMessage.h" + +namespace gpap_message +{ + + enum class MessageType : char + { + MUTE = 's', + UNMUTE = 'u', + HELP = 'h', + ALARM = 'a', + INFO = 'i', + }; + struct GPAPMessage final + { + public: + static const size_t BUFFER_LENGTH = 131; + + const union + { + alarm::AlarmMessage alarm; + // InfoCommand info; + // MuteCommand mute; + // UnmuteCommand unmute; + // HelpCommand help; + }; + + const MessageType messageType; + + using GPAPBuffer = std::array; + + // Constructors and operator overloads + public: + GPAPMessage(alarm::AlarmMessage alarmMessage) noexcept + : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) {} + // ProtocolMessage(InfoCommand infoCommand) noexcept + // : commandType(CommandType::INFO), info(std::move(infoCommand)) {} + // ProtocolMessage(MuteCommand muteCommand) noexcept + // : commandType(CommandType::MUTE), mute(std::move(muteCommand)) {} + // ProtocolMessage(UnmuteCommand unmuteCommand) noexcept + // : commandType(CommandType::UNMUTE), unmute(std::move(unmuteCommand)) {} + // ProtocolMessage(HelpCommand helpCommand) noexcept + // : commandType(CommandType::HELP), help(std::move(helpCommand)) {} + + GPAPMessage operator=(GPAPMessage &&other) noexcept + { + return std::move(other); + } + GPAPMessage(const GPAPMessage &&other) + : messageType(other.messageType) + { + switch (this->messageType) + { + case MessageType::ALARM: + this->alarm = std::move(other.alarm); + break; + // case CommandType::INFO: + // this->info = std::move(other.info); + // break; + // case CommandType::MUTE: + // this->mute = std::move(other.mute); + // break; + // case CommandType::UNMUTE: + // this->unmute = std::move(other.unmute); + // break; + // case CommandType::HELP: + // this->help = std::move(other.help); + // break; + } + } + const GPAPMessage operator=(const GPAPMessage &&other) + { + return std::move(other); + } + + ~GPAPMessage() {} + + GPAPMessage() = delete; + GPAPMessage(GPAPMessage &other) = delete; + + static GPAPMessage deserialize(const char *const buffer, const size_t numBytes); + }; +} + +#endif From f01e30fe186def60211e9f25c83823ef80da53f3 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 30 Mar 2026 18:58:01 -0400 Subject: [PATCH 18/36] (#387): Added in the other message types --- Firmware/GPAD_API/GPAD_API/GPAD_API.ino | 55 +++++++++++++++--- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 2 +- .../GPAP/{AlarmMessage => }/AlarmMessage.h | 7 ++- .../lib/GPAP/AlarmMessage/AlarmMessageId.cpp | 2 +- .../GPAP/AlarmMessage/AlarmTypeDesignator.cpp | 16 +++--- .../AlarmMessageBuilder.cpp | 56 ++++++++++++++++++- .../AlarmMessageBuilder/AlarmMessageBuilder.h | 2 +- .../lib/GPAP/{GPAP.cpp => GPAPMessage.cpp} | 21 ++++--- .../lib/GPAP/{GPAP.h => GPAPMessage.h} | 54 +++++++++--------- Firmware/GPAD_API/lib/GPAP/HelpMessage.h | 11 ++++ Firmware/GPAD_API/lib/GPAP/InfoMessage.h | 11 ++++ Firmware/GPAD_API/lib/GPAP/MuteMessage.h | 11 ++++ Firmware/GPAD_API/lib/GPAP/UnmuteMessage.h | 11 ++++ 13 files changed, 199 insertions(+), 60 deletions(-) rename Firmware/GPAD_API/lib/GPAP/{AlarmMessage => }/AlarmMessage.h (91%) rename Firmware/GPAD_API/lib/GPAP/{GPAP.cpp => GPAPMessage.cpp} (64%) rename Firmware/GPAD_API/lib/GPAP/{GPAP.h => GPAPMessage.h} (53%) create mode 100644 Firmware/GPAD_API/lib/GPAP/HelpMessage.h create mode 100644 Firmware/GPAD_API/lib/GPAP/InfoMessage.h create mode 100644 Firmware/GPAD_API/lib/GPAP/MuteMessage.h create mode 100644 Firmware/GPAD_API/lib/GPAP/UnmuteMessage.h diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino index 53cf5a60..69d95e79 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino +++ b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino @@ -55,6 +55,7 @@ #include "gpad_utility.h" #include "gpad_serial.h" #include "Wink.h" +#include "GPAPMessage.h" #include #include @@ -132,7 +133,7 @@ const int LED_COUNT = sizeof(LED_PINS) / sizeof(LED_PINS[0]); // const int SWITCH_COUNT = sizeof(SWITCH_PINS) / sizeof(SWITCH_PINS[0]); // MQTT Broker -//#define USE_HIVEMQ +// #define USE_HIVEMQ #ifdef USE_HIVEMQ const char *mqtt_broker_name = "broker.hivemq.com"; const char *mqtt_user = ""; @@ -245,7 +246,7 @@ void reconnect() { n++; Serial.print("Attempting MQTT connection at: "); - Serial.print(millis() ); + Serial.print(millis()); Serial.print("..... "); if (client.connect(COMPANY_NAME, mqtt_user, mqtt_password)) { @@ -456,6 +457,45 @@ void setup() char setupSsid[SETUP_SSID_LENGTH] = "Krake_"; strcat(setupSsid, macAddressString); + const char *const testMessage = "a5{a4ab}[444]Test message"; + + const auto gpapMessage = gpap_message::GPAPMessage::deserialize(testMessage, 25); + + switch (gpapMessage.messageType) + { + case gpap_message::MessageType::ALARM: + using gpap_message::alarm::AlarmMessage; + const gpap_message::alarm::AlarmMessage &alarm = gpapMessage.alarm; + Serial.println("Parsing Alarm Command"); + + switch (alarm.level) + { + case AlarmMessage::Level::Level1: + Serial.println("Level 1"); + break; + case AlarmMessage::Level::Level2: + Serial.println("Level 2"); + break; + case AlarmMessage::Level::Level3: + Serial.println("Level 3"); + break; + case AlarmMessage::Level::Level4: + Serial.println("Level 4"); + break; + case AlarmMessage::Level::Level5: + Serial.println("Level 5"); + break; + } + + Serial.printf("Alarm Level: %c\n", alarm.level); + + Serial.print("Alarm Type Designator: "); + alarm.typeDesignator.printTo(Serial); + Serial.print("\n"); + + break; + } + // We call this a second time to get the MAC on the screen // clearLCD(); // req for Wifi Man and OTA @@ -520,12 +560,13 @@ void loop() { #if defined HMWK || defined KRAKE -if (!client.loop()) { - Serial.print(mqtt_broker_name); - Serial.print(" lost MQTT at: "); - Serial.println(millis()); + if (!client.loop()) + { + Serial.print(mqtt_broker_name); + Serial.print(" lost MQTT at: "); + Serial.println(millis()); reconnect(); -} + } publishOnLineMsg(); wink(); // The builtin LED diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 91e8652b..6ac359ef 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -25,7 +25,7 @@ #include #include "WiFiManagerOTA.h" #include "GPAD_menu.h" -#include "GPAP.h" +#include "GPAPMessage.h" using namespace gpad_hal; diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h similarity index 91% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessage.h rename to Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index 83e3ea56..a1651aa6 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -1,9 +1,9 @@ #ifndef _ALARM_MESSAGE_H #define _ALARM_MESSAGE_H -#include "AlarmMessageId.h" -#include "AlarmTypeDesignator.h" -#include "AlarmContent.h" +#include "AlarmMessage/AlarmMessageId.h" +#include "AlarmMessage/AlarmTypeDesignator.h" +#include "AlarmMessage/AlarmContent.h" namespace gpap_message::alarm { @@ -12,6 +12,7 @@ namespace gpap_message::alarm public: enum class Level : char { + Level0 = '0', Level1 = '1', Level2 = '2', Level3 = '3', diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp index 0dd49eb5..42fc3559 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp @@ -26,7 +26,7 @@ std::array AlarmMessageId::validateId( auto startIterator = id.cbegin(); auto endIterator = id.cbegin() + idLength; - bool allHex = std::all_of( + const bool allHex = std::all_of( startIterator, endIterator, [&validatedIdIterator](char hexChar) { *validatedIdIterator = hexChar; diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp index f6ec66b6..2e12de87 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp @@ -39,14 +39,14 @@ AlarmTypeDesignator::validateDesignator( auto designatorIterator = designator.begin(); - bool allDigits = std::all_of(inputDesignator.cbegin(), inputDesignator.cend(), - [&](char inputCharacter) - { - *designatorIterator = inputCharacter; - designatorIterator = - std::next(designatorIterator, 1); - return isdigit(inputCharacter); - }); + const bool allDigits = std::all_of(inputDesignator.cbegin(), inputDesignator.cend(), + [&](char inputCharacter) + { + *designatorIterator = inputCharacter; + designatorIterator = + std::next(designatorIterator, 1); + return isdigit(inputCharacter); + }); // if the characters are not all digits we want to throw if (!allDigits) diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index 66eccfba..3a7d14a6 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -1,3 +1,5 @@ +#include + #include "AlarmMessageBuilder.h" using namespace gpap_message::alarm; @@ -18,8 +20,31 @@ size_t AlarmMessageBuilder::deserializeLevelBytes(const char *const buffer, throw; } + Serial.printf("The alarm level: %c\n", buffer[0]); + this->level = static_cast(buffer[0]); + Serial.println("Inside ::deserializeLevelBytes()"); + switch (this->level) + { + case AlarmMessage::Level::Level1: + Serial.println("Level 1"); + break; + case AlarmMessage::Level::Level2: + Serial.println("Level 2"); + break; + case AlarmMessage::Level::Level3: + Serial.println("Level 3"); + break; + case AlarmMessage::Level::Level4: + Serial.println("Level 4"); + break; + case AlarmMessage::Level::Level5: + Serial.println("Level 5"); + break; + } + Serial.println("Finish ::deserializeLevelBytes()"); + return 1; } @@ -132,6 +157,9 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, auto totalBytes = builder.deserializeLevelBytes(buffer, numBytes); + // Iterate through buffer multiple times to find the elements/components + // remove Bytes from the function names + if ((numBytes - totalBytes) > 0) { totalBytes += @@ -146,7 +174,6 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, if ((numBytes - totalBytes) > 0) { - totalBytes += builder.deserializeMessageBytes(buffer + totalBytes, numBytes - totalBytes); } @@ -158,6 +185,29 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, const auto content = AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); - return AlarmMessage(builder.level, std::move(content), std::move(messageId), - std::move(typeDesignator)); + auto alarmMessage = AlarmMessage(builder.level, std::move(content), std::move(messageId), + std::move(typeDesignator)); + + Serial.println("Inside ::buildAlarmMessage()"); + switch (alarmMessage.level) + { + case AlarmMessage::Level::Level1: + Serial.println("Level 1"); + break; + case AlarmMessage::Level::Level2: + Serial.println("Level 2"); + break; + case AlarmMessage::Level::Level3: + Serial.println("Level 3"); + break; + case AlarmMessage::Level::Level4: + Serial.println("Level 4"); + break; + case AlarmMessage::Level::Level5: + Serial.println("Level 5"); + break; + } + Serial.println("Finish ::buildAlarmMessage()"); + + return alarmMessage; } diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h index dde31a9b..93315bc0 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -1,7 +1,7 @@ #ifndef _ALARM_MESSAGE_BUILDER_H #define _ALARM_MESSAGE_BUILDER_H -#include "AlarmMessage/AlarmMessage.h" +#include "AlarmMessage.h" namespace gpap_message::deserialize { diff --git a/Firmware/GPAD_API/lib/GPAP/GPAP.cpp b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp similarity index 64% rename from Firmware/GPAD_API/lib/GPAP/GPAP.cpp rename to Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp index 43d02140..0e5ada4b 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAP.cpp +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp @@ -1,4 +1,4 @@ -#include "GPAP.h" +#include "GPAPMessage.h" #include "Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h" using namespace gpap_message; @@ -22,17 +22,16 @@ GPAPMessage GPAPMessage::deserialize(const char *const buffer, const size_t numB } return std::move(GPAPMessage(deserialize::AlarmMessageBuilder::buildAlarmMessage(buffer + 1, numBytes - 1))); - // case MessageType::INFO: - // return ProtocolMessage(InfoCommand()); + case MessageType::INFO: + return GPAPMessage(InfoMessage()); - // case MessageType::MUTE: - // return ProtocolMessage(MuteCommand()); + case MessageType::MUTE: + return GPAPMessage(MuteMessage()); - // case MessageType::UNMUTE: - // return ProtocolMessage(UnmuteCommand()); + case MessageType::UNMUTE: + return GPAPMessage(UnmuteMessage()); - // case MessageType::HELP: - // return ProtocolMessage(HelpCommand()); - // } + case MessageType::HELP: + return GPAPMessage(HelpMessage()); } -} \ No newline at end of file +} diff --git a/Firmware/GPAD_API/lib/GPAP/GPAP.h b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h similarity index 53% rename from Firmware/GPAD_API/lib/GPAP/GPAP.h rename to Firmware/GPAD_API/lib/GPAP/GPAPMessage.h index 6aa15340..d7385e12 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAP.h +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h @@ -1,7 +1,11 @@ #ifndef _GPAP_MESSAGE_H #define _GPAP_MESSAGE_H -#include "AlarmMessage/AlarmMessage.h" +#include "AlarmMessage.h" +#include "HelpMessage.h" +#include "InfoMessage.h" +#include "MuteMessage.h" +#include "UnmuteMessage.h" namespace gpap_message { @@ -22,10 +26,10 @@ namespace gpap_message const union { alarm::AlarmMessage alarm; - // InfoCommand info; - // MuteCommand mute; - // UnmuteCommand unmute; - // HelpCommand help; + InfoMessage info; + MuteMessage mute; + UnmuteMessage unmute; + HelpMessage help; }; const MessageType messageType; @@ -36,14 +40,14 @@ namespace gpap_message public: GPAPMessage(alarm::AlarmMessage alarmMessage) noexcept : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) {} - // ProtocolMessage(InfoCommand infoCommand) noexcept - // : commandType(CommandType::INFO), info(std::move(infoCommand)) {} - // ProtocolMessage(MuteCommand muteCommand) noexcept - // : commandType(CommandType::MUTE), mute(std::move(muteCommand)) {} - // ProtocolMessage(UnmuteCommand unmuteCommand) noexcept - // : commandType(CommandType::UNMUTE), unmute(std::move(unmuteCommand)) {} - // ProtocolMessage(HelpCommand helpCommand) noexcept - // : commandType(CommandType::HELP), help(std::move(helpCommand)) {} + GPAPMessage(InfoMessage infoMessage) noexcept + : messageType(MessageType::INFO), info(std::move(infoMessage)) {} + GPAPMessage(MuteMessage muteMessage) noexcept + : messageType(MessageType::MUTE), mute(std::move(muteMessage)) {} + GPAPMessage(UnmuteMessage unmuteCommand) noexcept + : messageType(MessageType::UNMUTE), unmute(std::move(unmuteCommand)) {} + GPAPMessage(HelpMessage helpCommand) noexcept + : messageType(MessageType::HELP), help(std::move(helpCommand)) {} GPAPMessage operator=(GPAPMessage &&other) noexcept { @@ -57,18 +61,18 @@ namespace gpap_message case MessageType::ALARM: this->alarm = std::move(other.alarm); break; - // case CommandType::INFO: - // this->info = std::move(other.info); - // break; - // case CommandType::MUTE: - // this->mute = std::move(other.mute); - // break; - // case CommandType::UNMUTE: - // this->unmute = std::move(other.unmute); - // break; - // case CommandType::HELP: - // this->help = std::move(other.help); - // break; + case MessageType::INFO: + this->info = std::move(other.info); + break; + case MessageType::MUTE: + this->mute = std::move(other.mute); + break; + case MessageType::UNMUTE: + this->unmute = std::move(other.unmute); + break; + case MessageType::HELP: + this->help = std::move(other.help); + break; } } const GPAPMessage operator=(const GPAPMessage &&other) diff --git a/Firmware/GPAD_API/lib/GPAP/HelpMessage.h b/Firmware/GPAD_API/lib/GPAP/HelpMessage.h new file mode 100644 index 00000000..8e79c1c2 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/HelpMessage.h @@ -0,0 +1,11 @@ +#ifndef _HELP_MESSAGE_H +#define _HELP_MESSAGE_H + +namespace gpap_message +{ + class HelpMessage final + { + }; +} + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/InfoMessage.h b/Firmware/GPAD_API/lib/GPAP/InfoMessage.h new file mode 100644 index 00000000..a60f6a2c --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/InfoMessage.h @@ -0,0 +1,11 @@ +#ifndef _INFO_MESSAGE_H +#define _INFO_MESSAGE_H + +namespace gpap_message +{ + class InfoMessage final + { + }; +} // namespace gpap_message + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/MuteMessage.h b/Firmware/GPAD_API/lib/GPAP/MuteMessage.h new file mode 100644 index 00000000..2a2ff183 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/MuteMessage.h @@ -0,0 +1,11 @@ +#ifndef _MUTE_MESSAGE_H +#define _MUTE_MESSAGE_H + +namespace gpap_message +{ + class MuteMessage final + { + }; +} // namespace gpap_message + +#endif diff --git a/Firmware/GPAD_API/lib/GPAP/UnmuteMessage.h b/Firmware/GPAD_API/lib/GPAP/UnmuteMessage.h new file mode 100644 index 00000000..fbd6aa29 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/UnmuteMessage.h @@ -0,0 +1,11 @@ +#ifndef _UNMUTE_MESSAGE_H +#define _UNMUTE_MESSAGE_H + +namespace gpap_message +{ + class UnmuteMessage final + { + }; +} + +#endif From 24be0d0e44471d3af867c996761c8a5af5872452 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:13:52 -0400 Subject: [PATCH 19/36] (#387): Added missing std::move when returning AlarmCommand - Since the Copy constructor is deleted from the AlarmCommand the Move construcctor must be used - in the ::buildAlarmMessage() method it was not using std::move so the returned AlarmMessage was in a invalid state --- Firmware/GPAD_API/GPAD_API/GPAD_API.ino | 19 ----- Firmware/GPAD_API/lib/GPAP/AlarmMessage.h | 1 - .../AlarmMessageBuilder.cpp | 79 ++++--------------- .../AlarmMessageBuilder/AlarmMessageBuilder.h | 8 +- Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp | 5 +- Firmware/GPAD_API/lib/GPAP/GPAPMessage.h | 16 ++-- 6 files changed, 30 insertions(+), 98 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino index 69d95e79..7dfd742b 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino +++ b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino @@ -468,25 +468,6 @@ void setup() const gpap_message::alarm::AlarmMessage &alarm = gpapMessage.alarm; Serial.println("Parsing Alarm Command"); - switch (alarm.level) - { - case AlarmMessage::Level::Level1: - Serial.println("Level 1"); - break; - case AlarmMessage::Level::Level2: - Serial.println("Level 2"); - break; - case AlarmMessage::Level::Level3: - Serial.println("Level 3"); - break; - case AlarmMessage::Level::Level4: - Serial.println("Level 4"); - break; - case AlarmMessage::Level::Level5: - Serial.println("Level 5"); - break; - } - Serial.printf("Alarm Level: %c\n", alarm.level); Serial.print("Alarm Type Designator: "); diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index a1651aa6..8d4a1158 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -34,7 +34,6 @@ namespace gpap_message::alarm messageId(std::move(messageId)), typeDesignator(std::move(typeDesignator)) {} - AlarmMessage(AlarmMessage &&other) = default; AlarmMessage(const AlarmMessage &&other) : level(other.level), content(std::move(other.content)), messageId(std::move(other.messageId)), diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index 3a7d14a6..a0dbfd0d 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -12,44 +12,21 @@ AlarmMessageBuilder::AlarmMessageBuilder() { } -size_t AlarmMessageBuilder::deserializeLevelBytes(const char *const buffer, - const size_t numBytes) +size_t AlarmMessageBuilder::deserializeLevel(const char *const buffer, + const size_t numBytes) { if (numBytes == 0) { throw; } - Serial.printf("The alarm level: %c\n", buffer[0]); - this->level = static_cast(buffer[0]); - Serial.println("Inside ::deserializeLevelBytes()"); - switch (this->level) - { - case AlarmMessage::Level::Level1: - Serial.println("Level 1"); - break; - case AlarmMessage::Level::Level2: - Serial.println("Level 2"); - break; - case AlarmMessage::Level::Level3: - Serial.println("Level 3"); - break; - case AlarmMessage::Level::Level4: - Serial.println("Level 4"); - break; - case AlarmMessage::Level::Level5: - Serial.println("Level 5"); - break; - } - Serial.println("Finish ::deserializeLevelBytes()"); - return 1; } -size_t AlarmMessageBuilder::deserializeIdBytes(const char *const buffer, - const size_t numBytes) +size_t AlarmMessageBuilder::deserializeId(const char *const buffer, + const size_t numBytes) { if (numBytes == 0 || (buffer[0] != AlarmMessageBuilder::ID_START_CHARACTER)) { @@ -94,8 +71,8 @@ size_t AlarmMessageBuilder::deserializeIdBytes(const char *const buffer, } size_t -AlarmMessageBuilder::deserializeTypeDesignatorBytes(const char *const buffer, - const size_t numBytes) +AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, + const size_t numBytes) { if ((numBytes == 0) || buffer[0] != AlarmMessageBuilder::DESIGNATOR_START_CHARACTER) @@ -138,8 +115,8 @@ AlarmMessageBuilder::deserializeTypeDesignatorBytes(const char *const buffer, } } -size_t AlarmMessageBuilder::deserializeMessageBytes(const char *const buffer, - const size_t numBytes) +size_t AlarmMessageBuilder::deserializeMessage(const char *const buffer, + const size_t numBytes) { auto messageLength = 0; for (; messageLength < numBytes; ++messageLength) @@ -155,7 +132,7 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, { AlarmMessageBuilder builder = AlarmMessageBuilder(); - auto totalBytes = builder.deserializeLevelBytes(buffer, numBytes); + auto totalBytes = builder.deserializeLevel(buffer, numBytes); // Iterate through buffer multiple times to find the elements/components // remove Bytes from the function names @@ -163,19 +140,19 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, if ((numBytes - totalBytes) > 0) { totalBytes += - builder.deserializeIdBytes(buffer + totalBytes, numBytes - totalBytes); + builder.deserializeId(buffer + totalBytes, numBytes - totalBytes); } if ((numBytes - totalBytes) > 0) { - totalBytes += builder.deserializeTypeDesignatorBytes(buffer + totalBytes, - numBytes - totalBytes); + totalBytes += builder.deserializeTypeDesignator(buffer + totalBytes, + numBytes - totalBytes); } if ((numBytes - totalBytes) > 0) { - totalBytes += builder.deserializeMessageBytes(buffer + totalBytes, - numBytes - totalBytes); + totalBytes += builder.deserializeMessage(buffer + totalBytes, + numBytes - totalBytes); } const auto messageId = @@ -185,29 +162,7 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, const auto content = AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); - auto alarmMessage = AlarmMessage(builder.level, std::move(content), std::move(messageId), - std::move(typeDesignator)); - - Serial.println("Inside ::buildAlarmMessage()"); - switch (alarmMessage.level) - { - case AlarmMessage::Level::Level1: - Serial.println("Level 1"); - break; - case AlarmMessage::Level::Level2: - Serial.println("Level 2"); - break; - case AlarmMessage::Level::Level3: - Serial.println("Level 3"); - break; - case AlarmMessage::Level::Level4: - Serial.println("Level 4"); - break; - case AlarmMessage::Level::Level5: - Serial.println("Level 5"); - break; - } - Serial.println("Finish ::buildAlarmMessage()"); - - return alarmMessage; + const auto alarmMessage = AlarmMessage(builder.level, std::move(content), std::move(messageId), + std::move(typeDesignator)); + return std::move(alarmMessage); } diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h index 93315bc0..4804389f 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -31,10 +31,10 @@ namespace gpap_message::deserialize private: AlarmMessageBuilder(); - size_t deserializeLevelBytes(const char *const buffer, size_t numBytes); - size_t deserializeIdBytes(const char *const buffer, const size_t numBytes); - size_t deserializeTypeDesignatorBytes(const char *const buffer, const size_t numBytes); - size_t deserializeMessageBytes(const char *const buffer, const size_t numBytes); + size_t deserializeLevel(const char *const buffer, size_t numBytes); + size_t deserializeId(const char *const buffer, const size_t numBytes); + size_t deserializeTypeDesignator(const char *const buffer, const size_t numBytes); + size_t deserializeMessage(const char *const buffer, const size_t numBytes); public: static alarm::AlarmMessage buildAlarmMessage(const char *const buffer, const size_t numBytes); diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp index 0e5ada4b..32c46a14 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp @@ -11,7 +11,7 @@ GPAPMessage GPAPMessage::deserialize(const char *const buffer, const size_t numB } // TODO: This should be wrapped in a try/catch if there isn't a 0th element - auto messageType = static_cast(buffer[0]); + const auto messageType = static_cast(buffer[0]); switch (messageType) { @@ -20,7 +20,8 @@ GPAPMessage GPAPMessage::deserialize(const char *const buffer, const size_t numB { throw; } - return std::move(GPAPMessage(deserialize::AlarmMessageBuilder::buildAlarmMessage(buffer + 1, numBytes - 1))); + + return GPAPMessage(deserialize::AlarmMessageBuilder::buildAlarmMessage(buffer + 1, numBytes - 1)); case MessageType::INFO: return GPAPMessage(InfoMessage()); diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h index d7385e12..575876f3 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h @@ -38,22 +38,18 @@ namespace gpap_message // Constructors and operator overloads public: - GPAPMessage(alarm::AlarmMessage alarmMessage) noexcept + explicit GPAPMessage(alarm::AlarmMessage alarmMessage) noexcept : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) {} - GPAPMessage(InfoMessage infoMessage) noexcept + explicit GPAPMessage(InfoMessage infoMessage) noexcept : messageType(MessageType::INFO), info(std::move(infoMessage)) {} - GPAPMessage(MuteMessage muteMessage) noexcept + explicit GPAPMessage(MuteMessage muteMessage) noexcept : messageType(MessageType::MUTE), mute(std::move(muteMessage)) {} - GPAPMessage(UnmuteMessage unmuteCommand) noexcept + explicit GPAPMessage(UnmuteMessage unmuteCommand) noexcept : messageType(MessageType::UNMUTE), unmute(std::move(unmuteCommand)) {} - GPAPMessage(HelpMessage helpCommand) noexcept + explicit GPAPMessage(HelpMessage helpCommand) noexcept : messageType(MessageType::HELP), help(std::move(helpCommand)) {} - GPAPMessage operator=(GPAPMessage &&other) noexcept - { - return std::move(other); - } - GPAPMessage(const GPAPMessage &&other) + GPAPMessage(const GPAPMessage &&other) noexcept : messageType(other.messageType) { switch (this->messageType) From b221ce41eb2068889de65a24dc39034edc6d9b2b Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:37:27 -0400 Subject: [PATCH 20/36] (#387): Removed manually added the null terminator to the type designator --- Firmware/GPAD_API/lib/GPAP/AlarmMessage.h | 8 +-- .../GPAP/AlarmMessage/AlarmTypeDesignator.cpp | 60 +++++++------------ .../GPAP/AlarmMessage/AlarmTypeDesignator.h | 17 +----- 3 files changed, 27 insertions(+), 58 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index 8d4a1158..5cbdb8c7 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -34,15 +34,11 @@ namespace gpap_message::alarm messageId(std::move(messageId)), typeDesignator(std::move(typeDesignator)) {} - AlarmMessage(const AlarmMessage &&other) + AlarmMessage(const AlarmMessage &&other) noexcept : level(other.level), content(std::move(other.content)), messageId(std::move(other.messageId)), typeDesignator(std::move(other.typeDesignator)) {} - AlarmMessage operator=(AlarmMessage &&other) noexcept - { - return std::move(other); - } - AlarmMessage operator=(const AlarmMessage &&other) + AlarmMessage operator=(const AlarmMessage &&other) noexcept { return std::move(other); } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp index 2e12de87..d4386ec7 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp @@ -9,8 +9,25 @@ using namespace gpap_message::alarm; AlarmTypeDesignator::AlarmTypeDesignator( const std::array designator, const bool empty) - : designator(AlarmTypeDesignator::validateDesignator(designator, empty)), - empty(empty) {} + : designator(designator), empty(empty) +{ + if (!this->empty) + { + auto designatorIterator = designator.begin(); + + const bool allDigits = std::all_of(this->designator.cbegin(), this->designator.cend(), + [](char inputCharacter) + { + return isdigit(inputCharacter); + }); + + // if the characters are not all digits we want to throw + if (!allDigits) + { + throw; + } + } +} AlarmTypeDesignator::~AlarmTypeDesignator() = default; @@ -21,40 +38,7 @@ const char *const AlarmTypeDesignator::getValue() const size_t AlarmTypeDesignator::printTo(Print &print) const { - return print.print(this->getValue()); -} - -std::array -AlarmTypeDesignator::validateDesignator( - const std::array - inputDesignator, - const bool empty) -{ - std::array designator = - {}; - if (empty) - { - return designator; - } - - auto designatorIterator = designator.begin(); - - const bool allDigits = std::all_of(inputDesignator.cbegin(), inputDesignator.cend(), - [&](char inputCharacter) - { - *designatorIterator = inputCharacter; - designatorIterator = - std::next(designatorIterator, 1); - return isdigit(inputCharacter); - }); - - // if the characters are not all digits we want to throw - if (!allDigits) - { - throw; - } - - *designatorIterator = '\0'; - - return designator; + auto bytesWritten = print.print(this->getValue()); + bytesWritten += print.print("\0"); + return bytesWritten; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h index 29ab38d6..3faeff87 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h @@ -14,22 +14,15 @@ namespace gpap_message::alarm using Buffer = std::array; private: - static const size_t TOTAL_DESIGNATOR_LENGTH = - AlarmTypeDesignator::DESIGNATOR_LENGTH + 1; - const std::array designator; + const std::array designator; const bool empty; public: AlarmTypeDesignator(const Buffer designator, const bool empty); - AlarmTypeDesignator(AlarmTypeDesignator &&other) = default; - AlarmTypeDesignator(const AlarmTypeDesignator &&other) + AlarmTypeDesignator(const AlarmTypeDesignator &&other) noexcept : designator(std::move(other.designator)), empty(other.empty) {} - AlarmTypeDesignator operator=(AlarmTypeDesignator &&source) - { - return std::move(source); - } - AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) + AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) noexcept { return std::move(source); } @@ -44,10 +37,6 @@ namespace gpap_message::alarm const char *const getValue() const; size_t printTo(Print &print) const override; - - private: - static std::array - validateDesignator(const Buffer buffer, const bool empty); }; } From a8de85ed0b3038780b47cef55b43c9c951f7c194 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:16:51 -0400 Subject: [PATCH 21/36] (#387): PossibleParameter added as an 'optional' type to alarm message parts - Since parts of the alarm message, like type designator, are optional, needed a way to indicate they are possibly present, possibly existent --- Firmware/GPAD_API/GPAD_API/GPAD_API.ino | 15 ++++++++-- Firmware/GPAD_API/lib/GPAP/AlarmMessage.h | 7 +++-- .../lib/GPAP/AlarmMessage/PossibleParameter.h | 30 +++++++++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino index 7dfd742b..9473fc05 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino +++ b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino @@ -465,14 +465,23 @@ void setup() { case gpap_message::MessageType::ALARM: using gpap_message::alarm::AlarmMessage; + using gpap_message::alarm::AlarmTypeDesignator; const gpap_message::alarm::AlarmMessage &alarm = gpapMessage.alarm; Serial.println("Parsing Alarm Command"); Serial.printf("Alarm Level: %c\n", alarm.level); - Serial.print("Alarm Type Designator: "); - alarm.typeDesignator.printTo(Serial); - Serial.print("\n"); + switch (alarm.typeDesignator.state) + { + case AlarmMessage::PossibleTypeDesignator::State::None: + Serial.println("No Alarm Type Designator"); + break; + case AlarmMessage::PossibleTypeDesignator::State::Some: + Serial.print("Alarm Type Designator: "); + alarm.typeDesignator.contents.printTo(Serial); + Serial.print("\n"); + break; + } break; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index 5cbdb8c7..a89fb0f3 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -4,6 +4,7 @@ #include "AlarmMessage/AlarmMessageId.h" #include "AlarmMessage/AlarmTypeDesignator.h" #include "AlarmMessage/AlarmContent.h" +#include "AlarmMessage/PossibleParameter.h" namespace gpap_message::alarm { @@ -20,16 +21,18 @@ namespace gpap_message::alarm Level5 = '5', }; + using PossibleTypeDesignator = PossibleParameter; + const Level level; const AlarmMessageId messageId; - const AlarmTypeDesignator typeDesignator; + const PossibleParameter typeDesignator; const AlarmContent content; public: explicit AlarmMessage(const AlarmMessage::Level alarmLevel, const AlarmContent alarmContent, const AlarmMessageId messageId, - const AlarmTypeDesignator typeDesignator) + const PossibleParameter typeDesignator) : level(alarmLevel), content(std::move(alarmContent)), messageId(std::move(messageId)), typeDesignator(std::move(typeDesignator)) {} diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h new file mode 100644 index 00000000..520bb2b4 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h @@ -0,0 +1,30 @@ +#ifndef _POSSIBLE_PARAMETER_H +#define _POSSIBLE_PARAMETER_H + +namespace gpap_message::alarm +{ + template + struct PossibleParameter + { + enum State + { + None, + Some + }; + + const State state; + const T contents; + + PossibleParameter() + { + this->state = State::None; + } + + PossibleParameter(T contents) : contents(std::move(contents)), state(State::Some) {} + PossibleParameter(const PossibleParameter &&other) : state(other.state), contents(std::move(other.contents)) {} + PossibleParameter(PossibleParameter &other) = delete; + PossibleParameter(const PossibleParameter &other) = delete; + }; +} + +#endif \ No newline at end of file From 06228f379f1daf10b1994226c7bfd136c203c76d Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 30 Mar 2026 22:09:46 -0400 Subject: [PATCH 22/36] (#387): Removing personal test code --- Firmware/GPAD_API/GPAD_API/GPAD_API.ino | 29 ------------------- .../GPAP/AlarmMessage/AlarmTypeDesignator.h | 2 ++ 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino index 9473fc05..2fd9c0d6 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino +++ b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino @@ -457,35 +457,6 @@ void setup() char setupSsid[SETUP_SSID_LENGTH] = "Krake_"; strcat(setupSsid, macAddressString); - const char *const testMessage = "a5{a4ab}[444]Test message"; - - const auto gpapMessage = gpap_message::GPAPMessage::deserialize(testMessage, 25); - - switch (gpapMessage.messageType) - { - case gpap_message::MessageType::ALARM: - using gpap_message::alarm::AlarmMessage; - using gpap_message::alarm::AlarmTypeDesignator; - const gpap_message::alarm::AlarmMessage &alarm = gpapMessage.alarm; - Serial.println("Parsing Alarm Command"); - - Serial.printf("Alarm Level: %c\n", alarm.level); - - switch (alarm.typeDesignator.state) - { - case AlarmMessage::PossibleTypeDesignator::State::None: - Serial.println("No Alarm Type Designator"); - break; - case AlarmMessage::PossibleTypeDesignator::State::Some: - Serial.print("Alarm Type Designator: "); - alarm.typeDesignator.contents.printTo(Serial); - Serial.print("\n"); - break; - } - - break; - } - // We call this a second time to get the MAC on the screen // clearLCD(); // req for Wifi Man and OTA diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h index 3faeff87..26c80681 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h @@ -15,6 +15,8 @@ namespace gpap_message::alarm private: const std::array designator; + /// @brief The `empty` field was a temporary solution to the situation where no Type Designator + /// was provided. With the addition of the `PossibleField` type then this field can be removed const bool empty; public: From 01752dfa796cf5e39e79cf4aef575567e99f4b91 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Thu, 2 Apr 2026 15:28:38 -0400 Subject: [PATCH 23/36] (#387): Better using the PossibleParameter type --- Firmware/GPAD_API/lib/GPAP/AlarmMessage.h | 4 +- .../GPAP/AlarmMessage/AlarmTypeDesignator.cpp | 30 ++++++-------- .../GPAP/AlarmMessage/AlarmTypeDesignator.h | 5 +-- .../lib/GPAP/AlarmMessage/PossibleParameter.h | 29 +++++++++---- .../AlarmMessageBuilder.cpp | 41 +++++++++++++++---- .../AlarmMessageBuilder/AlarmMessageBuilder.h | 2 +- 6 files changed, 71 insertions(+), 40 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index a89fb0f3..ec700a06 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -24,14 +24,14 @@ namespace gpap_message::alarm using PossibleTypeDesignator = PossibleParameter; const Level level; - const AlarmMessageId messageId; + const PossibleParameter messageId; const PossibleParameter typeDesignator; const AlarmContent content; public: explicit AlarmMessage(const AlarmMessage::Level alarmLevel, const AlarmContent alarmContent, - const AlarmMessageId messageId, + const PossibleParameter messageId, const PossibleParameter typeDesignator) : level(alarmLevel), content(std::move(alarmContent)), messageId(std::move(messageId)), diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp index d4386ec7..978b3891 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp @@ -6,26 +6,20 @@ using namespace gpap_message::alarm; -AlarmTypeDesignator::AlarmTypeDesignator( - const std::array designator, - const bool empty) - : designator(designator), empty(empty) +AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(designator) { - if (!this->empty) + auto designatorIterator = designator.begin(); + + const bool allDigits = std::all_of(this->designator.cbegin(), this->designator.cend(), + [](char inputCharacter) + { + return isdigit(inputCharacter); + }); + + // if the characters are not all digits we want to throw + if (!allDigits) { - auto designatorIterator = designator.begin(); - - const bool allDigits = std::all_of(this->designator.cbegin(), this->designator.cend(), - [](char inputCharacter) - { - return isdigit(inputCharacter); - }); - - // if the characters are not all digits we want to throw - if (!allDigits) - { - throw; - } + throw; } } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h index 26c80681..b9333e2b 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h @@ -17,13 +17,12 @@ namespace gpap_message::alarm const std::array designator; /// @brief The `empty` field was a temporary solution to the situation where no Type Designator /// was provided. With the addition of the `PossibleField` type then this field can be removed - const bool empty; public: - AlarmTypeDesignator(const Buffer designator, const bool empty); + explicit AlarmTypeDesignator(const Buffer designator); AlarmTypeDesignator(const AlarmTypeDesignator &&other) noexcept - : designator(std::move(other.designator)), empty(other.empty) {} + : designator(std::move(other.designator)) {} AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) noexcept { return std::move(source); diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h index 520bb2b4..34f28066 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h @@ -6,24 +6,39 @@ namespace gpap_message::alarm template struct PossibleParameter { + const union + { + T contents; + std::nullptr_t empty; + }; + enum State { None, Some }; - const State state; - const T contents; + State state; - PossibleParameter() + explicit PossibleParameter() : state(State::None), empty(nullptr) {} + + explicit PossibleParameter(T contents) : contents(std::move(contents)), state(State::Some) {} + PossibleParameter(const PossibleParameter &&other) : state(other.state) { - this->state = State::None; + switch (this->state) + { + case State::None: + this->empty = nullptr; + break; + case State::Some: + this->contents = std::move(other.contents); + break; + } } - - PossibleParameter(T contents) : contents(std::move(contents)), state(State::Some) {} - PossibleParameter(const PossibleParameter &&other) : state(other.state), contents(std::move(other.contents)) {} PossibleParameter(PossibleParameter &other) = delete; PossibleParameter(const PossibleParameter &other) = delete; + + ~PossibleParameter() {} }; } diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index a0dbfd0d..693a2c2e 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -134,9 +134,6 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, auto totalBytes = builder.deserializeLevel(buffer, numBytes); - // Iterate through buffer multiple times to find the elements/components - // remove Bytes from the function names - if ((numBytes - totalBytes) > 0) { totalBytes += @@ -155,14 +152,40 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, numBytes - totalBytes); } - const auto messageId = - AlarmMessageId(builder.idLength, std::move(builder.idBuffer)); - const auto typeDesignator = AlarmTypeDesignator( - std::move(builder.designatorBuffer), (builder.designatorLength == 0)); + // The use of the lambda function here, and for creating the `PossibleParameter allows + // for conditionally setting the variable value messageId. If messageId was assigned outside of a lambda it + // could not be const. The compiler will inline the lambda since it is called right away so there is no + // "inefficiency" due to leveraging this + const PossibleParameter messageId = [](size_t numBytes, const AlarmMessageId::Buffer buffer) + { + if (numBytes == 0) + { + return std::move(PossibleParameter()); + } + + const AlarmMessageId messageId(numBytes, std::move(buffer)); + return std::move(PossibleParameter(std::move(messageId))); + }(builder.idLength, std::move(builder.idBuffer)); + + const PossibleParameter typeDesignator = [](size_t numBytes, const AlarmTypeDesignator::Buffer buffer) + { + if (numBytes == 0) + { + return std::move(PossibleParameter()); + } + + const AlarmTypeDesignator typeDesignator(std::move(buffer)); + return std::move(PossibleParameter(std::move(typeDesignator))); + }(builder.designatorLength, std::move(builder.designatorBuffer)); + const auto content = AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); - const auto alarmMessage = AlarmMessage(builder.level, std::move(content), std::move(messageId), - std::move(typeDesignator)); + const auto alarmMessage = + AlarmMessage(builder.level, + std::move(content), + std::move(messageId), + std::move(typeDesignator)); + return std::move(alarmMessage); } diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h index 4804389f..fea46cd5 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -29,7 +29,7 @@ namespace gpap_message::deserialize AlarmContent::Buffer messageBuffer; private: - AlarmMessageBuilder(); + explicit AlarmMessageBuilder(); size_t deserializeLevel(const char *const buffer, size_t numBytes); size_t deserializeId(const char *const buffer, const size_t numBytes); From 352c733e2b23c64d54c6731574cd0c8ff5a457dd Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:01:53 -0400 Subject: [PATCH 24/36] (#387): MessageID and Type Designator can now appear anywhere --- Firmware/GPAD_API/lib/GPAP/AlarmMessage.h | 51 ++++++--- .../lib/GPAP/AlarmMessage/AlarmContent.h | 58 +++++----- .../lib/GPAP/AlarmMessage/AlarmMessageId.cpp | 8 +- .../lib/GPAP/AlarmMessage/AlarmMessageId.h | 12 +- .../GPAP/AlarmMessage/AlarmTypeDesignator.cpp | 26 +++-- .../GPAP/AlarmMessage/AlarmTypeDesignator.h | 14 ++- .../lib/GPAP/AlarmMessage/PossibleParameter.h | 42 +++++-- .../AlarmMessageBuilder.cpp | 106 +++++++++++------- .../AlarmMessageBuilder/AlarmMessageBuilder.h | 28 ++++- Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp | 2 +- Firmware/GPAD_API/lib/GPAP/GPAPMessage.h | 51 +++++++-- 11 files changed, 274 insertions(+), 124 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index ec700a06..73cb59ba 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -1,6 +1,8 @@ #ifndef _ALARM_MESSAGE_H #define _ALARM_MESSAGE_H +#include + #include "AlarmMessage/AlarmMessageId.h" #include "AlarmMessage/AlarmTypeDesignator.h" #include "AlarmMessage/AlarmContent.h" @@ -21,29 +23,50 @@ namespace gpap_message::alarm Level5 = '5', }; + // using PossibleMessageId = PossibleParameter; using PossibleTypeDesignator = PossibleParameter; const Level level; - const PossibleParameter messageId; - const PossibleParameter typeDesignator; - const AlarmContent content; + // const AlarmContent content; + // const PossibleMessageId messageId; + const PossibleTypeDesignator typeDesignator; public: explicit AlarmMessage(const AlarmMessage::Level alarmLevel, - const AlarmContent alarmContent, - const PossibleParameter messageId, - const PossibleParameter typeDesignator) - : level(alarmLevel), content(std::move(alarmContent)), - messageId(std::move(messageId)), - typeDesignator(std::move(typeDesignator)) {} + // const AlarmContent alarmContent, + // const PossibleMessageId messageId, + const PossibleTypeDesignator typeDesignator) + : level(alarmLevel), + // content(std::move(alarmContent)), + // messageId(std::move(messageId)), + typeDesignator(std::move(typeDesignator)) + { + Serial.println("In AlarmMessage ctor:"); + this->typeDesignator.contents.printTo(Serial); + Serial.print("\n"); + } + AlarmMessage(AlarmMessage &&other) noexcept + : level(other.level), + // content(std::move(other.content)), + // messageId(std::move(other.messageId)), + typeDesignator(std::move(other.typeDesignator)) + { + } + AlarmMessage &operator=(AlarmMessage &&other) noexcept + { + return *this; + } AlarmMessage(const AlarmMessage &&other) noexcept - : level(other.level), content(std::move(other.content)), - messageId(std::move(other.messageId)), - typeDesignator(std::move(other.typeDesignator)) {} - AlarmMessage operator=(const AlarmMessage &&other) noexcept + : level(other.level), + // content(std::move(other.content)), + // messageId(std::move(other.messageId)), + typeDesignator(std::move(other.typeDesignator)) + { + } + AlarmMessage &operator=(const AlarmMessage &&other) noexcept { - return std::move(other); + return *this; } ~AlarmMessage() {} diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h index 2a897a02..e823e36f 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h @@ -3,33 +3,41 @@ #include -class AlarmContent final +namespace gpap_message::alarm { -public: - static const size_t MAX_LENGTH = 80; - using Buffer = std::array; - -private: - const size_t messageLength; - const std::array message; - -public: - explicit AlarmContent(const size_t messageLength, const Buffer message) - : messageLength(messageLength), message(std::move(message)) {}; - - AlarmContent(AlarmContent &&other) = default; - AlarmContent operator=(AlarmContent &&other) { return std::move(other); } - AlarmContent(const AlarmContent &&other) - : message(std::move(other.message)), messageLength(other.messageLength) {} - const AlarmContent operator=(const AlarmContent &&other) + class AlarmContent final { - return std::move(other); - } - - AlarmContent() = delete; - AlarmContent(AlarmContent &other) = delete; - AlarmContent(const AlarmContent &other) = delete; -}; + public: + static const size_t MAX_LENGTH = 80; + + using Buffer = std::array; + + private: + const size_t messageLength; + const std::array message; + + public: + explicit AlarmContent(const size_t messageLength, const Buffer message) + : messageLength(messageLength), message(std::move(message)) {}; + + AlarmContent(AlarmContent &&other) + : messageLength(other.messageLength), message(std::move(other.message)) {} + AlarmContent &operator=(AlarmContent &&other) + { + return *this; + } + AlarmContent(const AlarmContent &&other) + : messageLength(other.messageLength), message(std::move(other.message)) {} + AlarmContent &operator=(const AlarmContent &&other) + { + return *this; + } + + AlarmContent() = delete; + AlarmContent(AlarmContent &other) = delete; + AlarmContent(const AlarmContent &other) = delete; + }; +} #endif diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp index 42fc3559..29c1f88a 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp @@ -6,12 +6,12 @@ using namespace gpap_message::alarm; AlarmMessageId::AlarmMessageId( const size_t idLength, - const std::array id) - : idLength(idLength), id(AlarmMessageId::validateId(idLength, id)) {} + const Buffer id) + : idLength(idLength), id(std::move(AlarmMessageId::validateId(idLength, id))) {} std::array AlarmMessageId::validateId( const size_t idLength, - const std::array id) + const Buffer id) { std::array validatedId = {}; auto validatedIdIterator = validatedId.begin(); @@ -41,5 +41,5 @@ std::array AlarmMessageId::validateId( } *validatedIdIterator = '\0'; - return validatedId; + return std::move(validatedId); } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h index f9906da2..2203453e 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h @@ -25,10 +25,13 @@ namespace gpap_message::alarm AlarmMessageId(AlarmMessageId &&other) = default; AlarmMessageId(const AlarmMessageId &&other) : id(std::move(other.id)), idLength(other.idLength) {} - AlarmMessageId operator=(AlarmMessageId &&other) { return std::move(other); } - AlarmMessageId operator=(const AlarmMessageId &&other) + AlarmMessageId &operator=(AlarmMessageId &&other) { - return std::move(other); + return *this; + } + AlarmMessageId &operator=(const AlarmMessageId &&other) + { + return *this; } AlarmMessageId() = delete; @@ -37,8 +40,7 @@ namespace gpap_message::alarm private: static std::array - validateId(const size_t idLength, - const Buffer); + validateId(const size_t idLength, const Buffer); }; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp index 978b3891..06f425df 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp @@ -6,15 +6,16 @@ using namespace gpap_message::alarm; -AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(designator) +AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(std::move(designator)) { auto designatorIterator = designator.begin(); - const bool allDigits = std::all_of(this->designator.cbegin(), this->designator.cend(), - [](char inputCharacter) - { - return isdigit(inputCharacter); - }); + const bool allDigits = + std::all_of(this->designator.cbegin(), this->designator.cend(), + [](char inputCharacter) + { + return isdigit(inputCharacter); + }); // if the characters are not all digits we want to throw if (!allDigits) @@ -23,16 +24,21 @@ AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(d } } -AlarmTypeDesignator::~AlarmTypeDesignator() = default; +AlarmTypeDesignator::~AlarmTypeDesignator() {} -const char *const AlarmTypeDesignator::getValue() const +const AlarmTypeDesignator::Buffer &AlarmTypeDesignator::getValue() const { - return this->designator.data(); + return this->designator; } size_t AlarmTypeDesignator::printTo(Print &print) const { - auto bytesWritten = print.print(this->getValue()); + auto bytesWritten = 0; + for (auto iter = this->getValue().cbegin(); iter != this->getValue().cend(); ++iter) + { + bytesWritten += print.print(*iter); + } + bytesWritten += print.print("\0"); return bytesWritten; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h index b9333e2b..8a066e74 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h @@ -15,17 +15,21 @@ namespace gpap_message::alarm private: const std::array designator; - /// @brief The `empty` field was a temporary solution to the situation where no Type Designator - /// was provided. With the addition of the `PossibleField` type then this field can be removed public: explicit AlarmTypeDesignator(const Buffer designator); + AlarmTypeDesignator(AlarmTypeDesignator &&other) noexcept + : designator(std::move(other.designator)) {} + AlarmTypeDesignator &operator=(AlarmTypeDesignator &&other) noexcept + { + return *this; + } AlarmTypeDesignator(const AlarmTypeDesignator &&other) noexcept : designator(std::move(other.designator)) {} - AlarmTypeDesignator operator=(const AlarmTypeDesignator &&source) noexcept + AlarmTypeDesignator &operator=(const AlarmTypeDesignator &&other) noexcept { - return std::move(source); + return *this; } AlarmTypeDesignator() = delete; @@ -35,7 +39,7 @@ namespace gpap_message::alarm virtual ~AlarmTypeDesignator(); // Methods public: - const char *const getValue() const; + const Buffer &getValue() const; size_t printTo(Print &print) const override; }; diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h index 34f28066..6f1754f5 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h @@ -1,40 +1,62 @@ #ifndef _POSSIBLE_PARAMETER_H #define _POSSIBLE_PARAMETER_H +#include + namespace gpap_message::alarm { template struct PossibleParameter { - const union + enum class State { - T contents; - std::nullptr_t empty; + Some, + None, }; - enum State + const union { - None, - Some + T contents; + std::nullptr_t empty; }; - State state; + const State state; explicit PossibleParameter() : state(State::None), empty(nullptr) {} - - explicit PossibleParameter(T contents) : contents(std::move(contents)), state(State::Some) {} - PossibleParameter(const PossibleParameter &&other) : state(other.state) + explicit PossibleParameter(T contents) : state(State::Some), contents(std::move(contents)) {} + PossibleParameter(PossibleParameter &&other) : state(other.state) { switch (this->state) { + case State::Some: + this->contents = std::move(other.contents); + break; case State::None: this->empty = nullptr; break; + } + } + PossibleParameter &operator=(PossibleParameter &&other) + { + return *this; + } + PossibleParameter(const PossibleParameter &&other) : state(other.state) + { + switch (this->state) + { case State::Some: this->contents = std::move(other.contents); break; + case State::None: + this->empty = nullptr; + break; } } + PossibleParameter &operator=(const PossibleParameter &&other) + { + return *this; + } + PossibleParameter(PossibleParameter &other) = delete; PossibleParameter(const PossibleParameter &other) = delete; diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index 693a2c2e..d7f8dbc8 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -80,6 +80,8 @@ AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, return 0; } + const auto currBuffer = buffer + 1; + auto designatorLength = 0; auto foundEnd = false; while ((designatorLength < (AlarmTypeDesignator::DESIGNATOR_LENGTH + 1)) && @@ -87,14 +89,13 @@ AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, { // Need to offset the index by 1 since we have to account for the starting // character, { - auto bufferIndex = designatorLength + 1; - if (buffer[bufferIndex] == AlarmMessageBuilder::DESIGNATOR_END_CHARACTER) + if (currBuffer[designatorLength] == AlarmMessageBuilder::DESIGNATOR_END_CHARACTER) { foundEnd = true; } else if (designatorLength < AlarmTypeDesignator::DESIGNATOR_LENGTH) { - this->designatorBuffer.at(designatorLength) = buffer[bufferIndex]; + this->designatorBuffer.at(designatorLength) = currBuffer[designatorLength]; ++designatorLength; } } @@ -121,6 +122,11 @@ size_t AlarmMessageBuilder::deserializeMessage(const char *const buffer, auto messageLength = 0; for (; messageLength < numBytes; ++messageLength) { + if (!AlarmMessageBuilder::isReservedCharacter(buffer[messageLength])) + { + return messageLength - 1; + } + this->messageBuffer.at(messageLength) = buffer[messageLength]; } @@ -134,58 +140,82 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, auto totalBytes = builder.deserializeLevel(buffer, numBytes); - if ((numBytes - totalBytes) > 0) - { - totalBytes += - builder.deserializeId(buffer + totalBytes, numBytes - totalBytes); - } + auto foundId = false; + auto foundDesignator = false; + auto foundMessage = false; - if ((numBytes - totalBytes) > 0) + while ((totalBytes < numBytes) && !(foundId && foundDesignator && foundMessage)) { - totalBytes += builder.deserializeTypeDesignator(buffer + totalBytes, - numBytes - totalBytes); - } + auto currBuffer = buffer + totalBytes; + auto currNumBytes = numBytes - totalBytes; + if (currBuffer[0] == AlarmMessageBuilder::ID_START_CHARACTER && !foundId) + { + totalBytes += builder.deserializeId(currBuffer, currNumBytes); - if ((numBytes - totalBytes) > 0) - { - totalBytes += builder.deserializeMessage(buffer + totalBytes, - numBytes - totalBytes); + foundId = true; + } + else if (currBuffer[0] == AlarmMessageBuilder::DESIGNATOR_START_CHARACTER && !foundDesignator) + { + totalBytes += builder.deserializeTypeDesignator(currBuffer, currNumBytes); + + foundDesignator = true; + } + else + { + totalBytes += builder.deserializeMessage(currBuffer, currNumBytes); + } } // The use of the lambda function here, and for creating the `PossibleParameter allows // for conditionally setting the variable value messageId. If messageId was assigned outside of a lambda it // could not be const. The compiler will inline the lambda since it is called right away so there is no // "inefficiency" due to leveraging this - const PossibleParameter messageId = [](size_t numBytes, const AlarmMessageId::Buffer buffer) - { - if (numBytes == 0) - { - return std::move(PossibleParameter()); - } - - const AlarmMessageId messageId(numBytes, std::move(buffer)); - return std::move(PossibleParameter(std::move(messageId))); - }(builder.idLength, std::move(builder.idBuffer)); - - const PossibleParameter typeDesignator = [](size_t numBytes, const AlarmTypeDesignator::Buffer buffer) + // const AlarmMessage::PossibleMessageId messageId = [](const size_t numBytes, const AlarmMessageId::Buffer buffer) + // { + // if (numBytes == 0) + // { + // return std::move(AlarmMessage::PossibleMessageId()); + // } + + // const AlarmMessageId messageId(numBytes, std::move(buffer)); + // const AlarmMessage::PossibleMessageId possibleMessageId(std::move(messageId)); + // return std::move(possibleMessageId); + // }(builder.idLength, std::move(builder.idBuffer)); + + const AlarmMessage::PossibleTypeDesignator typeDesignator = [](const size_t numBytes, const AlarmTypeDesignator::Buffer buffer) { if (numBytes == 0) { - return std::move(PossibleParameter()); + return AlarmMessage::PossibleTypeDesignator(); } const AlarmTypeDesignator typeDesignator(std::move(buffer)); - return std::move(PossibleParameter(std::move(typeDesignator))); + const AlarmMessage::PossibleTypeDesignator possibleTypeDesignator(std::move(typeDesignator)); + + return possibleTypeDesignator; }(builder.designatorLength, std::move(builder.designatorBuffer)); - const auto content = - AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); + // const auto content = + // AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); + + auto data = typeDesignator.contents.getValue(); + for (auto iter = data.cbegin(); iter != data.cend(); ++iter) + { + Serial.printf("Before creating AlarmMessage: %c\n", *iter); + } - const auto alarmMessage = - AlarmMessage(builder.level, - std::move(content), - std::move(messageId), - std::move(typeDesignator)); + const AlarmMessage alarmMessage = AlarmMessage(builder.level, + // std::move(content), + // std::move(messageId), + std::move(typeDesignator)); - return std::move(alarmMessage); + return alarmMessage; +} + +bool AlarmMessageBuilder::isReservedCharacter(const char character) +{ + return (character != AlarmMessageBuilder::DESIGNATOR_START_CHARACTER && + character != AlarmMessageBuilder::DESIGNATOR_END_CHARACTER && + character != AlarmMessageBuilder::ID_START_CHARACTER && + character != AlarmMessageBuilder::ID_END_CHARACTER); } diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h index fea46cd5..becc3c1a 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -26,7 +26,7 @@ namespace gpap_message::deserialize alarm::AlarmTypeDesignator::Buffer designatorBuffer; size_t messageLength; - AlarmContent::Buffer messageBuffer; + alarm::AlarmContent::Buffer messageBuffer; private: explicit AlarmMessageBuilder(); @@ -38,11 +38,31 @@ namespace gpap_message::deserialize public: static alarm::AlarmMessage buildAlarmMessage(const char *const buffer, const size_t numBytes); + static bool isReservedCharacter(const char character); - AlarmMessageBuilder(AlarmMessageBuilder &&other) = default; - AlarmMessageBuilder operator=(AlarmMessageBuilder &&other) + AlarmMessageBuilder(AlarmMessageBuilder &&other) + : level(other.level), + idLength(other.idLength), + idBuffer(std::move(other.idBuffer)), + designatorLength(other.designatorLength), + designatorBuffer(std::move(other.designatorBuffer)), + messageLength(other.messageLength), + messageBuffer(std::move(other.messageBuffer)) {}; + AlarmMessageBuilder &operator=(AlarmMessageBuilder &&other) { - return std::move(other); + return *this; + } + AlarmMessageBuilder(const AlarmMessageBuilder &&other) + : level(other.level), + idLength(other.idLength), + idBuffer(std::move(other.idBuffer)), + designatorLength(other.designatorLength), + designatorBuffer(std::move(other.designatorBuffer)), + messageLength(other.messageLength), + messageBuffer(std::move(other.messageBuffer)) {}; + AlarmMessageBuilder &operator=(const AlarmMessageBuilder &&other) + { + return *this; } AlarmMessageBuilder(AlarmMessageBuilder &other) = delete; diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp index 32c46a14..60e384ad 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp @@ -21,7 +21,7 @@ GPAPMessage GPAPMessage::deserialize(const char *const buffer, const size_t numB throw; } - return GPAPMessage(deserialize::AlarmMessageBuilder::buildAlarmMessage(buffer + 1, numBytes - 1)); + return GPAPMessage(std::move(deserialize::AlarmMessageBuilder::buildAlarmMessage(buffer + 1, numBytes - 1))); case MessageType::INFO: return GPAPMessage(InfoMessage()); diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h index 575876f3..55602530 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h @@ -1,6 +1,8 @@ #ifndef _GPAP_MESSAGE_H #define _GPAP_MESSAGE_H +#include + #include "AlarmMessage.h" #include "HelpMessage.h" #include "InfoMessage.h" @@ -38,17 +40,50 @@ namespace gpap_message // Constructors and operator overloads public: - explicit GPAPMessage(alarm::AlarmMessage alarmMessage) noexcept - : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) {} - explicit GPAPMessage(InfoMessage infoMessage) noexcept + explicit GPAPMessage(const alarm::AlarmMessage alarmMessage) noexcept + : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) + { + auto data = this->alarm.typeDesignator.contents.getValue(); + for (auto iter = data.cbegin(); iter != data.cend(); ++iter) + { + Serial.printf("In GPAPMessage ctor: %c\n", *iter); + } + } + explicit GPAPMessage(const InfoMessage infoMessage) noexcept : messageType(MessageType::INFO), info(std::move(infoMessage)) {} - explicit GPAPMessage(MuteMessage muteMessage) noexcept + explicit GPAPMessage(const MuteMessage muteMessage) noexcept : messageType(MessageType::MUTE), mute(std::move(muteMessage)) {} - explicit GPAPMessage(UnmuteMessage unmuteCommand) noexcept + explicit GPAPMessage(const UnmuteMessage unmuteCommand) noexcept : messageType(MessageType::UNMUTE), unmute(std::move(unmuteCommand)) {} - explicit GPAPMessage(HelpMessage helpCommand) noexcept + explicit GPAPMessage(const HelpMessage helpCommand) noexcept : messageType(MessageType::HELP), help(std::move(helpCommand)) {} + GPAPMessage(GPAPMessage &&other) noexcept + : messageType(other.messageType) + { + switch (this->messageType) + { + case MessageType::ALARM: + this->alarm = std::move(other.alarm); + break; + case MessageType::INFO: + this->info = std::move(other.info); + break; + case MessageType::MUTE: + this->mute = std::move(other.mute); + break; + case MessageType::UNMUTE: + this->unmute = std::move(other.unmute); + break; + case MessageType::HELP: + this->help = std::move(other.help); + break; + } + } + GPAPMessage &operator=(GPAPMessage &&other) + { + return *this; + } GPAPMessage(const GPAPMessage &&other) noexcept : messageType(other.messageType) { @@ -71,9 +106,9 @@ namespace gpap_message break; } } - const GPAPMessage operator=(const GPAPMessage &&other) + GPAPMessage &operator=(const GPAPMessage &&other) { - return std::move(other); + return *this; } ~GPAPMessage() {} From bd0c199f43b352ab9750017f401672644fc3e6a4 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:25:07 -0400 Subject: [PATCH 25/36] (#387): Corrected defintions of the Move Constructors and move assignment operators - Originally the move assignment operators simply returned `*this` - The operators had to first set the data members inside the operator and THEN return `*this` --- Firmware/GPAD_API/lib/GPAP/AlarmMessage.h | 46 ++++++-------- .../lib/GPAP/AlarmMessage/AlarmContent.h | 21 +++---- .../lib/GPAP/AlarmMessage/AlarmMessageId.h | 19 +++--- .../GPAP/AlarmMessage/AlarmTypeDesignator.h | 12 ++-- .../lib/GPAP/AlarmMessage/PossibleParameter.h | 37 +++++------ .../AlarmMessageBuilder.cpp | 43 ++++++------- .../AlarmMessageBuilder/AlarmMessageBuilder.h | 26 ++++---- Firmware/GPAD_API/lib/GPAP/GPAPMessage.h | 62 ++++++++----------- 8 files changed, 116 insertions(+), 150 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index 73cb59ba..1bd6ba7e 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -23,49 +23,41 @@ namespace gpap_message::alarm Level5 = '5', }; - // using PossibleMessageId = PossibleParameter; + using PossibleMessageId = PossibleParameter; using PossibleTypeDesignator = PossibleParameter; - const Level level; - // const AlarmContent content; - // const PossibleMessageId messageId; - const PossibleTypeDesignator typeDesignator; + Level level; + AlarmContent content; + PossibleMessageId messageId; + PossibleTypeDesignator typeDesignator; public: explicit AlarmMessage(const AlarmMessage::Level alarmLevel, - // const AlarmContent alarmContent, - // const PossibleMessageId messageId, - const PossibleTypeDesignator typeDesignator) + const AlarmContent alarmContent, + const PossibleMessageId messageId, + const PossibleTypeDesignator typeDesignator) noexcept : level(alarmLevel), - // content(std::move(alarmContent)), - // messageId(std::move(messageId)), + content(std::move(alarmContent)), + messageId(std::move(messageId)), typeDesignator(std::move(typeDesignator)) { - Serial.println("In AlarmMessage ctor:"); - this->typeDesignator.contents.printTo(Serial); - Serial.print("\n"); - } - - AlarmMessage(AlarmMessage &&other) noexcept - : level(other.level), - // content(std::move(other.content)), - // messageId(std::move(other.messageId)), - typeDesignator(std::move(other.typeDesignator)) - { - } - AlarmMessage &operator=(AlarmMessage &&other) noexcept - { - return *this; } AlarmMessage(const AlarmMessage &&other) noexcept : level(other.level), - // content(std::move(other.content)), - // messageId(std::move(other.messageId)), + content(std::move(other.content)), + messageId(std::move(other.messageId)), typeDesignator(std::move(other.typeDesignator)) { } AlarmMessage &operator=(const AlarmMessage &&other) noexcept { + if (this != &other) + { + this->level = other.level; + this->content = std::move(other.content); + this->messageId = std::move(other.messageId); + this->typeDesignator = std::move(other.typeDesignator); + } return *this; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h index e823e36f..0210096b 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h @@ -14,23 +14,22 @@ namespace gpap_message::alarm using Buffer = std::array; private: - const size_t messageLength; - const std::array message; + size_t messageLength; + std::array message; public: - explicit AlarmContent(const size_t messageLength, const Buffer message) + explicit AlarmContent(const size_t messageLength, const Buffer message) noexcept : messageLength(messageLength), message(std::move(message)) {}; - AlarmContent(AlarmContent &&other) + AlarmContent(const AlarmContent &&other) noexcept : messageLength(other.messageLength), message(std::move(other.message)) {} - AlarmContent &operator=(AlarmContent &&other) - { - return *this; - } - AlarmContent(const AlarmContent &&other) - : messageLength(other.messageLength), message(std::move(other.message)) {} - AlarmContent &operator=(const AlarmContent &&other) + AlarmContent &operator=(const AlarmContent &&other) noexcept { + if (this != &other) + { + this->messageLength = other.messageLength; + this->message = std::move(other.message); + } return *this; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h index 2203453e..61c6b694 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h @@ -17,20 +17,21 @@ namespace gpap_message::alarm static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; public: - const size_t idLength; - const std::array id; + size_t idLength; + std::array id; public: explicit AlarmMessageId(const size_t idLength, const Buffer id); - AlarmMessageId(AlarmMessageId &&other) = default; - AlarmMessageId(const AlarmMessageId &&other) + + AlarmMessageId(const AlarmMessageId &&other) noexcept : id(std::move(other.id)), idLength(other.idLength) {} - AlarmMessageId &operator=(AlarmMessageId &&other) - { - return *this; - } - AlarmMessageId &operator=(const AlarmMessageId &&other) + AlarmMessageId &operator=(const AlarmMessageId &&other) noexcept { + if (this != &other) + { + this->idLength = other.idLength; + this->id = std::move(other.id); + } return *this; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h index 8a066e74..d80af454 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h @@ -14,21 +14,19 @@ namespace gpap_message::alarm using Buffer = std::array; private: - const std::array designator; + std::array designator; public: explicit AlarmTypeDesignator(const Buffer designator); - AlarmTypeDesignator(AlarmTypeDesignator &&other) noexcept - : designator(std::move(other.designator)) {} - AlarmTypeDesignator &operator=(AlarmTypeDesignator &&other) noexcept - { - return *this; - } AlarmTypeDesignator(const AlarmTypeDesignator &&other) noexcept : designator(std::move(other.designator)) {} AlarmTypeDesignator &operator=(const AlarmTypeDesignator &&other) noexcept { + if (this != &other) + { + this->designator = std::move(other.designator); + } return *this; } diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h index 6f1754f5..88453cd9 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h @@ -1,8 +1,6 @@ #ifndef _POSSIBLE_PARAMETER_H #define _POSSIBLE_PARAMETER_H -#include - namespace gpap_message::alarm { template @@ -14,17 +12,19 @@ namespace gpap_message::alarm None, }; - const union + union { T contents; std::nullptr_t empty; }; - const State state; + State state; explicit PossibleParameter() : state(State::None), empty(nullptr) {} explicit PossibleParameter(T contents) : state(State::Some), contents(std::move(contents)) {} - PossibleParameter(PossibleParameter &&other) : state(other.state) + + PossibleParameter(const PossibleParameter &&other) noexcept + : state(other.state) { switch (this->state) { @@ -36,24 +36,21 @@ namespace gpap_message::alarm break; } } - PossibleParameter &operator=(PossibleParameter &&other) + PossibleParameter &operator=(const PossibleParameter &&other) noexcept { - return *this; - } - PossibleParameter(const PossibleParameter &&other) : state(other.state) - { - switch (this->state) + if (this != &other) { - case State::Some: - this->contents = std::move(other.contents); - break; - case State::None: - this->empty = nullptr; - break; + this->state = other.state; + switch (this->state) + { + case State::Some: + this->contents = std::move(other.contents); + break; + case State::None: + this->empty = nullptr; + break; + } } - } - PossibleParameter &operator=(const PossibleParameter &&other) - { return *this; } diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index d7f8dbc8..6e1a59d6 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -170,17 +170,18 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, // for conditionally setting the variable value messageId. If messageId was assigned outside of a lambda it // could not be const. The compiler will inline the lambda since it is called right away so there is no // "inefficiency" due to leveraging this - // const AlarmMessage::PossibleMessageId messageId = [](const size_t numBytes, const AlarmMessageId::Buffer buffer) - // { - // if (numBytes == 0) - // { - // return std::move(AlarmMessage::PossibleMessageId()); - // } - - // const AlarmMessageId messageId(numBytes, std::move(buffer)); - // const AlarmMessage::PossibleMessageId possibleMessageId(std::move(messageId)); - // return std::move(possibleMessageId); - // }(builder.idLength, std::move(builder.idBuffer)); + const AlarmMessage::PossibleMessageId messageId = [](const size_t numBytes, const AlarmMessageId::Buffer buffer) + { + if (numBytes == 0) + { + return std::move(AlarmMessage::PossibleMessageId()); + } + + const AlarmMessageId messageId(numBytes, std::move(buffer)); + const AlarmMessage::PossibleMessageId possibleMessageId(std::move(messageId)); + + return possibleMessageId; + }(builder.idLength, std::move(builder.idBuffer)); const AlarmMessage::PossibleTypeDesignator typeDesignator = [](const size_t numBytes, const AlarmTypeDesignator::Buffer buffer) { @@ -195,21 +196,13 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, return possibleTypeDesignator; }(builder.designatorLength, std::move(builder.designatorBuffer)); - // const auto content = - // AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); - - auto data = typeDesignator.contents.getValue(); - for (auto iter = data.cbegin(); iter != data.cend(); ++iter) - { - Serial.printf("Before creating AlarmMessage: %c\n", *iter); - } - - const AlarmMessage alarmMessage = AlarmMessage(builder.level, - // std::move(content), - // std::move(messageId), - std::move(typeDesignator)); + const auto content = + AlarmContent(builder.messageLength, std::move(builder.messageBuffer)); - return alarmMessage; + return AlarmMessage(builder.level, + std::move(content), + std::move(messageId), + std::move(typeDesignator)); } bool AlarmMessageBuilder::isReservedCharacter(const char character) diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h index becc3c1a..1f6db892 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -40,7 +40,7 @@ namespace gpap_message::deserialize static alarm::AlarmMessage buildAlarmMessage(const char *const buffer, const size_t numBytes); static bool isReservedCharacter(const char character); - AlarmMessageBuilder(AlarmMessageBuilder &&other) + AlarmMessageBuilder(const AlarmMessageBuilder &&other) noexcept : level(other.level), idLength(other.idLength), idBuffer(std::move(other.idBuffer)), @@ -48,20 +48,18 @@ namespace gpap_message::deserialize designatorBuffer(std::move(other.designatorBuffer)), messageLength(other.messageLength), messageBuffer(std::move(other.messageBuffer)) {}; - AlarmMessageBuilder &operator=(AlarmMessageBuilder &&other) - { - return *this; - } - AlarmMessageBuilder(const AlarmMessageBuilder &&other) - : level(other.level), - idLength(other.idLength), - idBuffer(std::move(other.idBuffer)), - designatorLength(other.designatorLength), - designatorBuffer(std::move(other.designatorBuffer)), - messageLength(other.messageLength), - messageBuffer(std::move(other.messageBuffer)) {}; - AlarmMessageBuilder &operator=(const AlarmMessageBuilder &&other) + AlarmMessageBuilder &operator=(const AlarmMessageBuilder &&other) noexcept { + if (this != &other) + { + this->level = other.level; + this->idLength = other.idLength; + this->idBuffer = std::move(other.idBuffer); + this->designatorLength = other.designatorLength; + this->designatorBuffer = std::move(other.designatorBuffer); + this->messageLength = other.messageLength; + this->messageBuffer = std::move(other.messageBuffer); + } return *this; } diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h index 55602530..c452305f 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h @@ -25,7 +25,7 @@ namespace gpap_message public: static const size_t BUFFER_LENGTH = 131; - const union + union { alarm::AlarmMessage alarm; InfoMessage info; @@ -34,21 +34,14 @@ namespace gpap_message HelpMessage help; }; - const MessageType messageType; + MessageType messageType; using GPAPBuffer = std::array; // Constructors and operator overloads public: explicit GPAPMessage(const alarm::AlarmMessage alarmMessage) noexcept - : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) - { - auto data = this->alarm.typeDesignator.contents.getValue(); - for (auto iter = data.cbegin(); iter != data.cend(); ++iter) - { - Serial.printf("In GPAPMessage ctor: %c\n", *iter); - } - } + : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) {} explicit GPAPMessage(const InfoMessage infoMessage) noexcept : messageType(MessageType::INFO), info(std::move(infoMessage)) {} explicit GPAPMessage(const MuteMessage muteMessage) noexcept @@ -57,8 +50,7 @@ namespace gpap_message : messageType(MessageType::UNMUTE), unmute(std::move(unmuteCommand)) {} explicit GPAPMessage(const HelpMessage helpCommand) noexcept : messageType(MessageType::HELP), help(std::move(helpCommand)) {} - - GPAPMessage(GPAPMessage &&other) noexcept + GPAPMessage(const GPAPMessage &&other) noexcept : messageType(other.messageType) { switch (this->messageType) @@ -80,34 +72,30 @@ namespace gpap_message break; } } - GPAPMessage &operator=(GPAPMessage &&other) + GPAPMessage &operator=(const GPAPMessage &&other) noexcept { - return *this; - } - GPAPMessage(const GPAPMessage &&other) noexcept - : messageType(other.messageType) - { - switch (this->messageType) + if (this != &other) { - case MessageType::ALARM: - this->alarm = std::move(other.alarm); - break; - case MessageType::INFO: - this->info = std::move(other.info); - break; - case MessageType::MUTE: - this->mute = std::move(other.mute); - break; - case MessageType::UNMUTE: - this->unmute = std::move(other.unmute); - break; - case MessageType::HELP: - this->help = std::move(other.help); - break; + this->messageType = other.messageType; + switch (this->messageType) + { + case MessageType::ALARM: + this->alarm = std::move(other.alarm); + break; + case MessageType::INFO: + this->info = std::move(other.info); + break; + case MessageType::MUTE: + this->mute = std::move(other.mute); + break; + case MessageType::UNMUTE: + this->unmute = std::move(other.unmute); + break; + case MessageType::HELP: + this->help = std::move(other.help); + break; + } } - } - GPAPMessage &operator=(const GPAPMessage &&other) - { return *this; } From d9163c93cfcb18410ecb98754beeba969f905757 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:49:19 -0400 Subject: [PATCH 26/36] (#387): Fixed logic for deserializing AlarmMessage with the components in any order --- .../AlarmMessageBuilder/AlarmMessageBuilder.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index 6e1a59d6..37a1b9ae 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -122,9 +122,10 @@ size_t AlarmMessageBuilder::deserializeMessage(const char *const buffer, auto messageLength = 0; for (; messageLength < numBytes; ++messageLength) { - if (!AlarmMessageBuilder::isReservedCharacter(buffer[messageLength])) + if (AlarmMessageBuilder::isReservedCharacter(buffer[messageLength])) { - return messageLength - 1; + messageLength - 1; + break; } this->messageBuffer.at(messageLength) = buffer[messageLength]; @@ -160,9 +161,11 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, foundDesignator = true; } - else + else if (!foundMessage) { totalBytes += builder.deserializeMessage(currBuffer, currNumBytes); + + foundMessage = true; } } @@ -207,8 +210,8 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, bool AlarmMessageBuilder::isReservedCharacter(const char character) { - return (character != AlarmMessageBuilder::DESIGNATOR_START_CHARACTER && - character != AlarmMessageBuilder::DESIGNATOR_END_CHARACTER && - character != AlarmMessageBuilder::ID_START_CHARACTER && - character != AlarmMessageBuilder::ID_END_CHARACTER); + return (character == AlarmMessageBuilder::DESIGNATOR_START_CHARACTER || + character == AlarmMessageBuilder::DESIGNATOR_END_CHARACTER || + character == AlarmMessageBuilder::ID_START_CHARACTER || + character == AlarmMessageBuilder::ID_END_CHARACTER); } From ec4cbd5281f386b7bc9e6229d01567345958a712 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:56:22 -0400 Subject: [PATCH 27/36] (#387): Chore: Added GPL license to top of all files --- Firmware/GPAD_API/lib/GPAP/AlarmMessage.h | 17 ++++++++++++ .../lib/GPAP/AlarmMessage/AlarmContent.h | 17 ++++++++++++ .../lib/GPAP/AlarmMessage/AlarmMessageId.cpp | 17 ++++++++++++ .../lib/GPAP/AlarmMessage/AlarmMessageId.h | 17 ++++++++++++ .../GPAP/AlarmMessage/AlarmTypeDesignator.cpp | 17 ++++++++++++ .../GPAP/AlarmMessage/AlarmTypeDesignator.h | 17 ++++++++++++ .../lib/GPAP/AlarmMessage/PossibleParameter.h | 17 ++++++++++++ .../AlarmMessageBuilder.cpp | 26 ++++++++++++++----- .../AlarmMessageBuilder/AlarmMessageBuilder.h | 17 ++++++++++++ Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp | 17 ++++++++++++ Firmware/GPAD_API/lib/GPAP/GPAPMessage.h | 17 ++++++++++++ 11 files changed, 189 insertions(+), 7 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h index 1bd6ba7e..56e8660d 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #ifndef _ALARM_MESSAGE_H #define _ALARM_MESSAGE_H diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h index 0210096b..e766d09f 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #ifndef _ALARM_CONTENT_H #define _ALARM_CONTENT_H diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp index 29c1f88a..586dbe33 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #include "AlarmMessageId.h" #include diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h index 61c6b694..8b321b01 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #ifndef _ALARM_MESSAGE_ID_H #define _ALARM_MESSAGE_ID_H diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp index 06f425df..ffe52232 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #include "AlarmTypeDesignator.h" #include diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h index d80af454..5f65f5a1 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #ifndef _ALARM_TYPE_DESIGNATOR_H #define _ALARM_TYPE_DESIGNATOR_H diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h index 88453cd9..c3d89bc2 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h +++ b/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #ifndef _POSSIBLE_PARAMETER_H #define _POSSIBLE_PARAMETER_H diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index 37a1b9ae..cfa6e6d8 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -1,4 +1,19 @@ -#include +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ #include "AlarmMessageBuilder.h" @@ -12,8 +27,7 @@ AlarmMessageBuilder::AlarmMessageBuilder() { } -size_t AlarmMessageBuilder::deserializeLevel(const char *const buffer, - const size_t numBytes) +size_t AlarmMessageBuilder::deserializeLevel(const char *const buffer, const size_t numBytes) { if (numBytes == 0) { @@ -25,8 +39,7 @@ size_t AlarmMessageBuilder::deserializeLevel(const char *const buffer, return 1; } -size_t AlarmMessageBuilder::deserializeId(const char *const buffer, - const size_t numBytes) +size_t AlarmMessageBuilder::deserializeId(const char *const buffer, const size_t numBytes) { if (numBytes == 0 || (buffer[0] != AlarmMessageBuilder::ID_START_CHARACTER)) { @@ -71,8 +84,7 @@ size_t AlarmMessageBuilder::deserializeId(const char *const buffer, } size_t -AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, - const size_t numBytes) +AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, const size_t numBytes) { if ((numBytes == 0) || buffer[0] != AlarmMessageBuilder::DESIGNATOR_START_CHARACTER) diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h index 1f6db892..2e270435 100644 --- a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h +++ b/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #ifndef _ALARM_MESSAGE_BUILDER_H #define _ALARM_MESSAGE_BUILDER_H diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp index 60e384ad..2c04cc2f 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #include "GPAPMessage.h" #include "Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h" diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h index c452305f..9d725e3f 100644 --- a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h @@ -1,3 +1,20 @@ +/* + Copyright (C) 2026 Public Invention + + This program includes free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + #ifndef _GPAP_MESSAGE_H #define _GPAP_MESSAGE_H From 056c553c4b93c25180543b04e9018564a9b82890 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 3 Apr 2026 12:51:43 -0400 Subject: [PATCH 28/36] (#387): GPAP source now in `src/` directory, adding README --- Firmware/GPAD_API/lib/GPAP/README | 0 Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage.h | 0 .../lib/GPAP/{ => src}/AlarmMessage/AlarmContent.h | 0 .../GPAP/{ => src}/AlarmMessage/AlarmMessageId.cpp | 0 .../lib/GPAP/{ => src}/AlarmMessage/AlarmMessageId.h | 0 .../{ => src}/AlarmMessage/AlarmTypeDesignator.cpp | 0 .../GPAP/{ => src}/AlarmMessage/AlarmTypeDesignator.h | 0 .../GPAP/{ => src}/AlarmMessage/PossibleParameter.h | 11 +++++++++++ .../AlarmMessageBuilder/AlarmMessageBuilder.cpp | 0 .../AlarmMessageBuilder/AlarmMessageBuilder.h | 0 Firmware/GPAD_API/lib/GPAP/{ => src}/GPAPMessage.cpp | 0 Firmware/GPAD_API/lib/GPAP/{ => src}/GPAPMessage.h | 0 Firmware/GPAD_API/lib/GPAP/{ => src}/HelpMessage.h | 0 Firmware/GPAD_API/lib/GPAP/{ => src}/InfoMessage.h | 0 Firmware/GPAD_API/lib/GPAP/{ => src}/MuteMessage.h | 0 Firmware/GPAD_API/lib/GPAP/{ => src}/UnmuteMessage.h | 0 16 files changed, 11 insertions(+) create mode 100644 Firmware/GPAD_API/lib/GPAP/README rename Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage/AlarmContent.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage/AlarmMessageId.cpp (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage/AlarmMessageId.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage/AlarmTypeDesignator.cpp (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage/AlarmTypeDesignator.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/AlarmMessage/PossibleParameter.h (77%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/GPAPMessage.cpp (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/GPAPMessage.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/HelpMessage.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/InfoMessage.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/MuteMessage.h (100%) rename Firmware/GPAD_API/lib/GPAP/{ => src}/UnmuteMessage.h (100%) diff --git a/Firmware/GPAD_API/lib/GPAP/README b/Firmware/GPAD_API/lib/GPAP/README new file mode 100644 index 00000000..e69de29b diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage.h rename to Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmContent.h rename to Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.cpp rename to Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmMessageId.h rename to Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.cpp rename to Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage/AlarmTypeDesignator.h rename to Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h diff --git a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/PossibleParameter.h similarity index 77% rename from Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h rename to Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/PossibleParameter.h index c3d89bc2..faee114f 100644 --- a/Firmware/GPAD_API/lib/GPAP/AlarmMessage/PossibleParameter.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/PossibleParameter.h @@ -15,6 +15,17 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/* + In the AlarmMessage, a couple of the fields are optional. The "message ID" and the "types designator". + Treating the concrete type of AlarmMessageId and AlarmTypeDesignator as both having a possible value + and also being empty can lead to many headaches and mistakes. To address this, an "optional" type has + been added to clearly indicate if a field in the AlarmMessage is present or not. + + Note: In C++17 there is a native "optional" type called `std::optional`. At the time of creation for + this library, it was compiled using C++11 so an "optional" type had to be manually implemented. + https://en.cppreference.com/w/cpp/utility/optional.html +*/ + #ifndef _POSSIBLE_PARAMETER_H #define _POSSIBLE_PARAMETER_H diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp rename to Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp diff --git a/Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h rename to Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/GPAPMessage.cpp rename to Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp diff --git a/Firmware/GPAD_API/lib/GPAP/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/GPAPMessage.h rename to Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h diff --git a/Firmware/GPAD_API/lib/GPAP/HelpMessage.h b/Firmware/GPAD_API/lib/GPAP/src/HelpMessage.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/HelpMessage.h rename to Firmware/GPAD_API/lib/GPAP/src/HelpMessage.h diff --git a/Firmware/GPAD_API/lib/GPAP/InfoMessage.h b/Firmware/GPAD_API/lib/GPAP/src/InfoMessage.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/InfoMessage.h rename to Firmware/GPAD_API/lib/GPAP/src/InfoMessage.h diff --git a/Firmware/GPAD_API/lib/GPAP/MuteMessage.h b/Firmware/GPAD_API/lib/GPAP/src/MuteMessage.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/MuteMessage.h rename to Firmware/GPAD_API/lib/GPAP/src/MuteMessage.h diff --git a/Firmware/GPAD_API/lib/GPAP/UnmuteMessage.h b/Firmware/GPAD_API/lib/GPAP/src/UnmuteMessage.h similarity index 100% rename from Firmware/GPAD_API/lib/GPAP/UnmuteMessage.h rename to Firmware/GPAD_API/lib/GPAP/src/UnmuteMessage.h From 9b21870c33eaf298f78852e84980eee7fdc3f66f Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 3 Apr 2026 13:11:42 -0400 Subject: [PATCH 29/36] (#387): Added content to the README explaining design choices --- Firmware/GPAD_API/lib/GPAP/README | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Firmware/GPAD_API/lib/GPAP/README b/Firmware/GPAD_API/lib/GPAP/README index e69de29b..d1bae677 100644 --- a/Firmware/GPAD_API/lib/GPAP/README +++ b/Firmware/GPAD_API/lib/GPAP/README @@ -0,0 +1,16 @@ +This library provides the types needed to deserialize messages as laid out in the [GPAP](https://github.com/PubInv/gpap) protocol. +At the time of the library's creation it leverages functionality of C++11 that is "more advanced" than other parts of this project. +Building the main class, `GPAPMessage`, heavily leverages the concept of "Return Value Optimization", or [RVO](https://sigcpp.github.io/2020/06/08/return-value-optimization) +(also known as [Copy elision](https://en.wikipedia.org/wiki/Copy_elision)). +Without RVO, when an instance is returned from a function that instances destructor is called and then a _new_ constructor is called +copying the data from the initial instance. **With** RVO, the initial instance's destructor is never called. Only a single constructor is called. +The article linked earlier for RVO has wonderful code explains highlighting the difference. + +In C++17 and later, RVO (or copy elision) happens more implicitly than C++11 (the current C++ version at the time of writing). Since C++11 is being +used we do have to be more explicit and leverage [`std::move()`](https://en.cppreference.com/w/cpp/utility/move.html). While it is _technically_ a function, +it is more an idication to the compiler saying "this value can be moved efficiently, don't copy it". `std::move()` is used through out the building of the +`GPAPMessage`, specifically the `AlarmMessage`, since a "builder pattern" is leveraged to constructor the types from a buffer of bytes. + +To facilitate being explicit about RVO and using `std::move()` the various `AlarmMessage*` types have defined move constructors and move assignment operators. +This does result in a substantial amount of "boiler plate" code but it's all quite straightforward. None of the types perform any sort of allocation, or hold +onto dynamically allocated memory, the move assignments and move constructors are just stating the data from one instance is moving to the new instance. \ No newline at end of file From 7f035c5dc7c4f9451de5e8791474e1474a4d0c31 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sat, 4 Apr 2026 10:16:29 -0400 Subject: [PATCH 30/36] (#387): Removed dependency on an Arduino specific library --- .../src/AlarmMessage/AlarmTypeDesignator.cpp | 16 ---------------- .../GPAP/src/AlarmMessage/AlarmTypeDesignator.h | 8 +------- Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h | 2 -- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp index ffe52232..56e90e5c 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp @@ -19,8 +19,6 @@ #include -#include - using namespace gpap_message::alarm; AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(std::move(designator)) @@ -41,21 +39,7 @@ AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(s } } -AlarmTypeDesignator::~AlarmTypeDesignator() {} - const AlarmTypeDesignator::Buffer &AlarmTypeDesignator::getValue() const { return this->designator; } - -size_t AlarmTypeDesignator::printTo(Print &print) const -{ - auto bytesWritten = 0; - for (auto iter = this->getValue().cbegin(); iter != this->getValue().cend(); ++iter) - { - bytesWritten += print.print(*iter); - } - - bytesWritten += print.print("\0"); - return bytesWritten; -} diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h index 5f65f5a1..6600e38d 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h @@ -20,11 +20,9 @@ #include -#include - namespace gpap_message::alarm { - class AlarmTypeDesignator final : Printable + class AlarmTypeDesignator final { public: static const size_t DESIGNATOR_LENGTH = 3; @@ -51,12 +49,8 @@ namespace gpap_message::alarm AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; - virtual ~AlarmTypeDesignator(); - // Methods public: const Buffer &getValue() const; - - size_t printTo(Print &print) const override; }; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h index 9d725e3f..922f87e8 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h @@ -18,8 +18,6 @@ #ifndef _GPAP_MESSAGE_H #define _GPAP_MESSAGE_H -#include - #include "AlarmMessage.h" #include "HelpMessage.h" #include "InfoMessage.h" From 8a7702d390883f41ae8bd883a3682e3682b2dd50 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sat, 4 Apr 2026 10:49:45 -0400 Subject: [PATCH 31/36] (#387): Converted uses of `size_t` to `std::size_t` - the portable use of `size_t` is actually `std::size_t` - the functions `std::isdigit()` and `std::isxdigit()` belong to the `cctype` library --- Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h | 2 -- .../lib/GPAP/src/AlarmMessage/AlarmContent.h | 6 +++--- .../GPAP/src/AlarmMessage/AlarmMessageId.cpp | 17 +++++++++++------ .../lib/GPAP/src/AlarmMessage/AlarmMessageId.h | 10 +++++----- .../src/AlarmMessage/AlarmTypeDesignator.cpp | 3 ++- .../src/AlarmMessage/AlarmTypeDesignator.h | 2 +- .../AlarmMessageBuilder.cpp | 18 ++++++++---------- .../AlarmMessageBuilder/AlarmMessageBuilder.h | 16 ++++++++-------- Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp | 2 +- Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h | 4 ++-- 10 files changed, 41 insertions(+), 39 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h index 56e8660d..df0072f7 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h @@ -18,8 +18,6 @@ #ifndef _ALARM_MESSAGE_H #define _ALARM_MESSAGE_H -#include - #include "AlarmMessage/AlarmMessageId.h" #include "AlarmMessage/AlarmTypeDesignator.h" #include "AlarmMessage/AlarmContent.h" diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h index e766d09f..41f90d72 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h @@ -26,16 +26,16 @@ namespace gpap_message::alarm class AlarmContent final { public: - static const size_t MAX_LENGTH = 80; + static const std::size_t MAX_LENGTH = 80; using Buffer = std::array; private: - size_t messageLength; + std::size_t messageLength; std::array message; public: - explicit AlarmContent(const size_t messageLength, const Buffer message) noexcept + explicit AlarmContent(const std::size_t messageLength, const Buffer message) noexcept : messageLength(messageLength), message(std::move(message)) {}; AlarmContent(const AlarmContent &&other) noexcept diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp index 586dbe33..12b0dca7 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp @@ -18,16 +18,17 @@ #include "AlarmMessageId.h" #include +#include using namespace gpap_message::alarm; AlarmMessageId::AlarmMessageId( - const size_t idLength, + const std::size_t idLength, const Buffer id) : idLength(idLength), id(std::move(AlarmMessageId::validateId(idLength, id))) {} std::array AlarmMessageId::validateId( - const size_t idLength, + const std::size_t idLength, const Buffer id) { std::array validatedId = {}; @@ -44,11 +45,15 @@ std::array AlarmMessageId::validateId( auto endIterator = id.cbegin() + idLength; const bool allHex = std::all_of( - startIterator, endIterator, [&validatedIdIterator](char hexChar) + startIterator, + endIterator, + [&validatedIdIterator](char hexChar) { - *validatedIdIterator = hexChar; - validatedIdIterator = std::next(validatedIdIterator, 1); - return isxdigit(hexChar); }); + *validatedIdIterator = hexChar; + validatedIdIterator = std::next(validatedIdIterator, 1); + + return std::isxdigit(static_cast(hexChar)); + }); // If all the characters are NOT hex characters we need to throw an error and // cancel the creation of this instance. diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h index 8b321b01..ca62c1a7 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h @@ -26,19 +26,19 @@ namespace gpap_message::alarm { public: // TODO: Find out what this value is SUPPOSED to be. - static const size_t MAX_LENGTH = 10; + static const std::size_t MAX_LENGTH = 10; using Buffer = std::array; private: - static const size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; + static const std::size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; public: - size_t idLength; + std::size_t idLength; std::array id; public: - explicit AlarmMessageId(const size_t idLength, const Buffer id); + explicit AlarmMessageId(const std::size_t idLength, const Buffer id); AlarmMessageId(const AlarmMessageId &&other) noexcept : id(std::move(other.id)), idLength(other.idLength) {} @@ -58,7 +58,7 @@ namespace gpap_message::alarm private: static std::array - validateId(const size_t idLength, const Buffer); + validateId(const std::size_t idLength, const Buffer); }; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp index 56e90e5c..08d996cd 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp @@ -18,6 +18,7 @@ #include "AlarmTypeDesignator.h" #include +#include using namespace gpap_message::alarm; @@ -29,7 +30,7 @@ AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(s std::all_of(this->designator.cbegin(), this->designator.cend(), [](char inputCharacter) { - return isdigit(inputCharacter); + return std::isdigit(static_cast(inputCharacter)); }); // if the characters are not all digits we want to throw diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h index 6600e38d..c504fa04 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h @@ -25,7 +25,7 @@ namespace gpap_message::alarm class AlarmTypeDesignator final { public: - static const size_t DESIGNATOR_LENGTH = 3; + static const std::size_t DESIGNATOR_LENGTH = 3; using Buffer = std::array; private: diff --git a/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index cfa6e6d8..55797dbc 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -27,7 +27,7 @@ AlarmMessageBuilder::AlarmMessageBuilder() { } -size_t AlarmMessageBuilder::deserializeLevel(const char *const buffer, const size_t numBytes) +std::size_t AlarmMessageBuilder::deserializeLevel(const char *const buffer, const std::size_t numBytes) { if (numBytes == 0) { @@ -39,7 +39,7 @@ size_t AlarmMessageBuilder::deserializeLevel(const char *const buffer, const siz return 1; } -size_t AlarmMessageBuilder::deserializeId(const char *const buffer, const size_t numBytes) +std::size_t AlarmMessageBuilder::deserializeId(const char *const buffer, const std::size_t numBytes) { if (numBytes == 0 || (buffer[0] != AlarmMessageBuilder::ID_START_CHARACTER)) { @@ -83,8 +83,8 @@ size_t AlarmMessageBuilder::deserializeId(const char *const buffer, const size_t } } -size_t -AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, const size_t numBytes) +std::size_t +AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, const std::size_t numBytes) { if ((numBytes == 0) || buffer[0] != AlarmMessageBuilder::DESIGNATOR_START_CHARACTER) @@ -128,8 +128,7 @@ AlarmMessageBuilder::deserializeTypeDesignator(const char *const buffer, const s } } -size_t AlarmMessageBuilder::deserializeMessage(const char *const buffer, - const size_t numBytes) +std::size_t AlarmMessageBuilder::deserializeMessage(const char *const buffer, const std::size_t numBytes) { auto messageLength = 0; for (; messageLength < numBytes; ++messageLength) @@ -146,8 +145,7 @@ size_t AlarmMessageBuilder::deserializeMessage(const char *const buffer, return messageLength; } -AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, - const size_t numBytes) +AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, const std::size_t numBytes) { AlarmMessageBuilder builder = AlarmMessageBuilder(); @@ -185,7 +183,7 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, // for conditionally setting the variable value messageId. If messageId was assigned outside of a lambda it // could not be const. The compiler will inline the lambda since it is called right away so there is no // "inefficiency" due to leveraging this - const AlarmMessage::PossibleMessageId messageId = [](const size_t numBytes, const AlarmMessageId::Buffer buffer) + const AlarmMessage::PossibleMessageId messageId = [](const std::size_t numBytes, const AlarmMessageId::Buffer buffer) { if (numBytes == 0) { @@ -198,7 +196,7 @@ AlarmMessage AlarmMessageBuilder::buildAlarmMessage(const char *const buffer, return possibleMessageId; }(builder.idLength, std::move(builder.idBuffer)); - const AlarmMessage::PossibleTypeDesignator typeDesignator = [](const size_t numBytes, const AlarmTypeDesignator::Buffer buffer) + const AlarmMessage::PossibleTypeDesignator typeDesignator = [](const std::size_t numBytes, const AlarmTypeDesignator::Buffer buffer) { if (numBytes == 0) { diff --git a/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h index 2e270435..47ddd36e 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h +++ b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h @@ -36,25 +36,25 @@ namespace gpap_message::deserialize private: alarm::AlarmMessage::Level level; - size_t idLength; + std::size_t idLength; alarm::AlarmMessageId::Buffer idBuffer; - size_t designatorLength; + std::size_t designatorLength; alarm::AlarmTypeDesignator::Buffer designatorBuffer; - size_t messageLength; + std::size_t messageLength; alarm::AlarmContent::Buffer messageBuffer; private: explicit AlarmMessageBuilder(); - size_t deserializeLevel(const char *const buffer, size_t numBytes); - size_t deserializeId(const char *const buffer, const size_t numBytes); - size_t deserializeTypeDesignator(const char *const buffer, const size_t numBytes); - size_t deserializeMessage(const char *const buffer, const size_t numBytes); + std::size_t deserializeLevel(const char *const buffer, std::size_t numBytes); + std::size_t deserializeId(const char *const buffer, const std::size_t numBytes); + std::size_t deserializeTypeDesignator(const char *const buffer, const std::size_t numBytes); + std::size_t deserializeMessage(const char *const buffer, const std::size_t numBytes); public: - static alarm::AlarmMessage buildAlarmMessage(const char *const buffer, const size_t numBytes); + static alarm::AlarmMessage buildAlarmMessage(const char *const buffer, const std::size_t numBytes); static bool isReservedCharacter(const char character); AlarmMessageBuilder(const AlarmMessageBuilder &&other) noexcept diff --git a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp index 2c04cc2f..3fdae3f4 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp @@ -19,7 +19,7 @@ #include "Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.h" using namespace gpap_message; -GPAPMessage GPAPMessage::deserialize(const char *const buffer, const size_t numBytes) +GPAPMessage GPAPMessage::deserialize(const char *const buffer, const std::size_t numBytes) { // Can't determined the message type if there are no bytes if (numBytes == 0) diff --git a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h index 922f87e8..5240eb91 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h @@ -38,7 +38,7 @@ namespace gpap_message struct GPAPMessage final { public: - static const size_t BUFFER_LENGTH = 131; + static const std::size_t BUFFER_LENGTH = 131; union { @@ -119,7 +119,7 @@ namespace gpap_message GPAPMessage() = delete; GPAPMessage(GPAPMessage &other) = delete; - static GPAPMessage deserialize(const char *const buffer, const size_t numBytes); + static GPAPMessage deserialize(const char *const buffer, const std::size_t numBytes); }; } From 20d075b77eeb0b454d9e7f49cb70d4fcfffa6f87 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sat, 4 Apr 2026 11:06:08 -0400 Subject: [PATCH 32/36] (#387): Adding unit tests --- Firmware/GPAD_API/platformio.ini | 5 +++ .../native/test_GPAP/test_gpap_message.cpp | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 2214a04f..7665538d 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -11,6 +11,10 @@ [platformio] src_dir = GPAD_API +[env:native] +platform = native +test_framework = googletest + [env:esp32dev] extra_scripts = pre:pre_extra_script.py @@ -33,3 +37,4 @@ lib_deps = tzapu/WiFiManager@^2.0.17 ayushsharma82/ElegantOTA@^3.1.7 marcoschwartz/LiquidCrystal_I2C@^1.1.4 +test_ignore = native/* diff --git a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp new file mode 100644 index 00000000..9f39cf32 --- /dev/null +++ b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp @@ -0,0 +1,32 @@ +#include + +#include "GPAPMessage.h" + +namespace gpap_message +{ + class GPAPMessageTest : public testing::Test + { + }; + + TEST_F(GPAPMessageTest, EmptyTestFunc) + { + static const char *alarmMessageStr = "a5Test message[444]{a4ab}"; + + const auto gpapMessage = GPAPMessage::deserialize(alarmMessageStr, strlen(alarmMessageStr)); + + EXPECT_EQ(gpapMessage.messageType, MessageType::ALARM); + } +}; + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + // if you plan to use GMock, replace the line above with + // ::testing::InitGoogleMock(&argc, argv); + + if (RUN_ALL_TESTS()) + ; + + // Always return zero-code and allow PlatformIO to parse results + return 0; +} From bdaf1dc6111440667d7aec9406f8b683d778b08e Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 5 Apr 2026 20:38:07 -0400 Subject: [PATCH 33/36] (#387): Message length is being updated in the builder --- .../GPAD_API/lib/GPAP/src/AlarmMessage.cpp | 8 +++++++ Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h | 3 +++ .../GPAP/src/AlarmMessage/AlarmContent.cpp | 12 ++++++++++ .../lib/GPAP/src/AlarmMessage/AlarmContent.h | 24 +++++++++++++++++-- .../AlarmMessageBuilder.cpp | 1 + .../GPAD_API/lib/GPAP/src/GPAPMessage.cpp | 16 +++++++++++++ Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h | 5 +++- .../native/test_GPAP/test_gpap_message.cpp | 15 ++++++++++-- 8 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp create mode 100644 Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp new file mode 100644 index 00000000..45d8fc42 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp @@ -0,0 +1,8 @@ +#include "AlarmMessage.h" + +using namespace gpap_message::alarm; + +const AlarmContent &AlarmMessage::getAlarmContent() const noexcept +{ + return this->content; +} \ No newline at end of file diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h index df0072f7..552be3c9 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h @@ -41,6 +41,7 @@ namespace gpap_message::alarm using PossibleMessageId = PossibleParameter; using PossibleTypeDesignator = PossibleParameter; + private: Level level; AlarmContent content; PossibleMessageId messageId; @@ -81,6 +82,8 @@ namespace gpap_message::alarm AlarmMessage() = delete; AlarmMessage(AlarmMessage &other) = delete; AlarmMessage(const AlarmMessage &other) = delete; + + const AlarmContent &getAlarmContent() const noexcept; }; } // namespace alarm diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp new file mode 100644 index 00000000..0ee4c905 --- /dev/null +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp @@ -0,0 +1,12 @@ +#include "AlarmContent.h" + +using namespace gpap_message::alarm; + +AlarmContent::AlarmContent(const std::size_t messageLength, const Buffer message) + : messageLength(messageLength), message(std::move(message)) +{ + if (this->messageLength > AlarmContent::MAX_LENGTH) + { + throw; + } +} diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h index 41f90d72..d9bd0a7a 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h @@ -18,7 +18,9 @@ #ifndef _ALARM_CONTENT_H #define _ALARM_CONTENT_H +#include #include +#include namespace gpap_message::alarm { @@ -35,8 +37,7 @@ namespace gpap_message::alarm std::array message; public: - explicit AlarmContent(const std::size_t messageLength, const Buffer message) noexcept - : messageLength(messageLength), message(std::move(message)) {}; + explicit AlarmContent(const std::size_t messageLength, const Buffer message); AlarmContent(const AlarmContent &&other) noexcept : messageLength(other.messageLength), message(std::move(other.message)) {} @@ -53,6 +54,25 @@ namespace gpap_message::alarm AlarmContent() = delete; AlarmContent(AlarmContent &other) = delete; AlarmContent(const AlarmContent &other) = delete; + + public: + friend std::ostream &operator<<(std::ostream &out, const AlarmContent &alarmContent) + { + auto beginIterator = alarmContent.message.cbegin(); + + const auto endIterator = std::next(beginIterator, alarmContent.messageLength); + + std::for_each( + beginIterator, + endIterator, + [&](const char &c) + { + std::cout << c << std::endl; + out << c; + }); + + return out; + } }; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp index 55797dbc..14b65880 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/Deserialize/AlarmMessageBuilder/AlarmMessageBuilder.cpp @@ -142,6 +142,7 @@ std::size_t AlarmMessageBuilder::deserializeMessage(const char *const buffer, co this->messageBuffer.at(messageLength) = buffer[messageLength]; } + this->messageLength = messageLength; return messageLength; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp index 3fdae3f4..ef20397a 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.cpp @@ -53,3 +53,19 @@ GPAPMessage GPAPMessage::deserialize(const char *const buffer, const std::size_t return GPAPMessage(HelpMessage()); } } + +MessageType GPAPMessage::getMessageType() const noexcept +{ + return this->messageType; +} + +const alarm::AlarmMessage &GPAPMessage::getAlarmMessage() const +{ + // Cannot access a field of the union when it's the incorrect type + if (this->messageType != MessageType::ALARM) + { + throw; + } + + return this->alarm; +} diff --git a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h index 5240eb91..6e766dac 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/src/GPAPMessage.h @@ -40,6 +40,7 @@ namespace gpap_message public: static const std::size_t BUFFER_LENGTH = 131; + private: union { alarm::AlarmMessage alarm; @@ -53,7 +54,6 @@ namespace gpap_message using GPAPBuffer = std::array; - // Constructors and operator overloads public: explicit GPAPMessage(const alarm::AlarmMessage alarmMessage) noexcept : messageType(MessageType::ALARM), alarm(std::move(alarmMessage)) {} @@ -120,6 +120,9 @@ namespace gpap_message GPAPMessage(GPAPMessage &other) = delete; static GPAPMessage deserialize(const char *const buffer, const std::size_t numBytes); + + MessageType getMessageType() const noexcept; + const alarm::AlarmMessage &getAlarmMessage() const; }; } diff --git a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp index 9f39cf32..c70cde69 100644 --- a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp +++ b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "GPAPMessage.h" @@ -8,13 +10,22 @@ namespace gpap_message { }; - TEST_F(GPAPMessageTest, EmptyTestFunc) + TEST_F(GPAPMessageTest, TestFunc) { static const char *alarmMessageStr = "a5Test message[444]{a4ab}"; const auto gpapMessage = GPAPMessage::deserialize(alarmMessageStr, strlen(alarmMessageStr)); - EXPECT_EQ(gpapMessage.messageType, MessageType::ALARM); + EXPECT_EQ(gpapMessage.getMessageType(), MessageType::ALARM); + + const std::string expectedString = "Test message"; + std::ostringstream receivedString; + receivedString << gpapMessage.getAlarmMessage().getAlarmContent(); + + std::cout << expectedString << std::endl; + std::cout << receivedString.str() << std::endl; + + EXPECT_EQ(receivedString.str().compare(expectedString), 0); } }; From b1d3d1f38a839e87ff2dae321919bbc55cd0cf78 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 6 Apr 2026 12:07:22 -0400 Subject: [PATCH 34/36] (#387): Leveraging Printable class again, setup mocking - including `iostream` greatly increased the size of the binary and ram usage - Going back to `Printable` class but now also mocking it so it can be used in tests --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 4 +- .../GPAD_API/lib/GPAP/src/AlarmMessage.cpp | 12 ++++- Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h | 2 + .../lib/GPAP/src/AlarmMessage/AlarmContent.h | 20 ------- .../src/AlarmMessage/AlarmTypeDesignator.cpp | 28 ++++++++++ .../src/AlarmMessage/AlarmTypeDesignator.h | 14 ++++- .../GPAP/src/AlarmMessage/PossibleParameter.h | 2 +- Firmware/GPAD_API/lib/mocking/MockPrint.h | 15 ++++++ Firmware/GPAD_API/lib/mocking/MockPrintable.h | 15 ++++++ Firmware/GPAD_API/platformio.ini | 5 +- .../native/test_GPAP/test_gpap_message.cpp | 54 +++++++++---------- 11 files changed, 118 insertions(+), 53 deletions(-) create mode 100644 Firmware/GPAD_API/lib/mocking/MockPrint.h create mode 100644 Firmware/GPAD_API/lib/mocking/MockPrintable.h diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 6ac359ef..bb4362bd 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -431,9 +431,9 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie const auto protocolMessage = gpap_message::GPAPMessage::deserialize(buf, rlen); serialport->print(F("Command: ")); - serialport->printf("%c\n", protocolMessage.messageType); + serialport->printf("%c\n", protocolMessage.getMessageType()); - switch (protocolMessage.messageType) + switch (protocolMessage.getMessageType()) { case gpap_message::MessageType::MUTE: { diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp index 45d8fc42..3b824f4e 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp @@ -5,4 +5,14 @@ using namespace gpap_message::alarm; const AlarmContent &AlarmMessage::getAlarmContent() const noexcept { return this->content; -} \ No newline at end of file +} + +AlarmMessage::Level AlarmMessage::getAlarmLevel() const noexcept +{ + return this->level; +} + +const AlarmMessage::PossibleTypeDesignator &AlarmMessage::getTypeDesignator() const noexcept +{ + return this->typeDesignator; +} diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h index 552be3c9..4aab409d 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h @@ -84,6 +84,8 @@ namespace gpap_message::alarm AlarmMessage(const AlarmMessage &other) = delete; const AlarmContent &getAlarmContent() const noexcept; + Level getAlarmLevel() const noexcept; + const PossibleTypeDesignator &getTypeDesignator() const noexcept; }; } // namespace alarm diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h index d9bd0a7a..83e85cdd 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h @@ -20,7 +20,6 @@ #include #include -#include namespace gpap_message::alarm { @@ -54,25 +53,6 @@ namespace gpap_message::alarm AlarmContent() = delete; AlarmContent(AlarmContent &other) = delete; AlarmContent(const AlarmContent &other) = delete; - - public: - friend std::ostream &operator<<(std::ostream &out, const AlarmContent &alarmContent) - { - auto beginIterator = alarmContent.message.cbegin(); - - const auto endIterator = std::next(beginIterator, alarmContent.messageLength); - - std::for_each( - beginIterator, - endIterator, - [&](const char &c) - { - std::cout << c << std::endl; - out << c; - }); - - return out; - } }; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp index 08d996cd..4c92dc64 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.cpp @@ -20,6 +20,13 @@ #include #include +#ifndef PIO_UNIT_TESTING +#include +#else +#include +using Print = MockPrint; +#endif + using namespace gpap_message::alarm; AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(std::move(designator)) @@ -40,7 +47,28 @@ AlarmTypeDesignator::AlarmTypeDesignator(const Buffer designator) : designator(s } } +AlarmTypeDesignator::~AlarmTypeDesignator() {} + const AlarmTypeDesignator::Buffer &AlarmTypeDesignator::getValue() const { return this->designator; } + +std::size_t AlarmTypeDesignator::printTo(Print &print) const +{ + auto beginIterator = this->designator.cbegin(); + auto const endIterator = this->designator.cend(); + + auto bytesWritten = 0; + + std::for_each( + beginIterator, + endIterator, + [&bytesWritten, &print](const char &currElement) + { + bytesWritten += print.print(currElement); + }); + + bytesWritten += print.print('\0'); + return bytesWritten; +} diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h index c504fa04..9aca1312 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h @@ -20,9 +20,18 @@ #include +#ifndef PIO_UNIT_TESTING +#include +#else +#include "MockPrintable.h" +#include "MockPrint.h" +using Printable = MockPrintable; +using Print = MockPrint; +#endif + namespace gpap_message::alarm { - class AlarmTypeDesignator final + class AlarmTypeDesignator final : Printable { public: static const std::size_t DESIGNATOR_LENGTH = 3; @@ -49,8 +58,11 @@ namespace gpap_message::alarm AlarmTypeDesignator(AlarmTypeDesignator &other) = delete; AlarmTypeDesignator(const AlarmTypeDesignator &other) = delete; + virtual ~AlarmTypeDesignator(); + public: const Buffer &getValue() const; + std::size_t printTo(Print &p) const; }; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/PossibleParameter.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/PossibleParameter.h index faee114f..aa10e46f 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/PossibleParameter.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/PossibleParameter.h @@ -32,7 +32,7 @@ namespace gpap_message::alarm { template - struct PossibleParameter + struct PossibleParameter final { enum class State { diff --git a/Firmware/GPAD_API/lib/mocking/MockPrint.h b/Firmware/GPAD_API/lib/mocking/MockPrint.h new file mode 100644 index 00000000..449a33e5 --- /dev/null +++ b/Firmware/GPAD_API/lib/mocking/MockPrint.h @@ -0,0 +1,15 @@ +#ifndef _MOCK_PRINT_H +#define _MOCK_PRINT_H + +#include + +class MockPrint +{ +public: + std::size_t print(char) + { + return 0; + } +}; + +#endif \ No newline at end of file diff --git a/Firmware/GPAD_API/lib/mocking/MockPrintable.h b/Firmware/GPAD_API/lib/mocking/MockPrintable.h new file mode 100644 index 00000000..2c6c0aa0 --- /dev/null +++ b/Firmware/GPAD_API/lib/mocking/MockPrintable.h @@ -0,0 +1,15 @@ +#ifndef _MOCK_PRINTABLE_H +#define _MOCK_PRINTABLE_H + +#include + +class MockPrint; + +class MockPrintable +{ +public: + virtual ~MockPrintable() {} + virtual std::size_t printTo(MockPrint &p) const = 0; +}; + +#endif diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 7665538d..d66ef455 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -10,10 +10,11 @@ [platformio] src_dir = GPAD_API +default_envs = esp32dev [env:native] platform = native -test_framework = googletest +build_flags = -std=gnu++11 [env:esp32dev] extra_scripts = @@ -37,4 +38,6 @@ lib_deps = tzapu/WiFiManager@^2.0.17 ayushsharma82/ElegantOTA@^3.1.7 marcoschwartz/LiquidCrystal_I2C@^1.1.4 +lib_ignore = + mocking test_ignore = native/* diff --git a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp index c70cde69..73bd28e9 100644 --- a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp +++ b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp @@ -1,43 +1,43 @@ -#include +#include #include -#include #include "GPAPMessage.h" -namespace gpap_message -{ - class GPAPMessageTest : public testing::Test - { - }; +// namespace gpap_message +// { +// class GPAPMessageTest : public testing::Test +// { +// }; + +// TEST_F(GPAPMessageTest, TestFunc) +// { +// static const char *alarmMessageStr = "a5Test message[444]{a4ab}"; - TEST_F(GPAPMessageTest, TestFunc) - { - static const char *alarmMessageStr = "a5Test message[444]{a4ab}"; +// const auto gpapMessage = GPAPMessage::deserialize(alarmMessageStr, strlen(alarmMessageStr)); - const auto gpapMessage = GPAPMessage::deserialize(alarmMessageStr, strlen(alarmMessageStr)); +// EXPECT_EQ(gpapMessage.getMessageType(), MessageType::ALARM); - EXPECT_EQ(gpapMessage.getMessageType(), MessageType::ALARM); +// const std::string expectedString = "Test message"; +// std::ostringstream receivedString; +// receivedString << gpapMessage.getAlarmMessage().getAlarmContent(); - const std::string expectedString = "Test message"; - std::ostringstream receivedString; - receivedString << gpapMessage.getAlarmMessage().getAlarmContent(); +// std::cout << expectedString << std::endl; +// std::cout << receivedString.str() << std::endl; - std::cout << expectedString << std::endl; - std::cout << receivedString.str() << std::endl; +// EXPECT_EQ(receivedString.str().compare(expectedString), 0); +// } +// }; - EXPECT_EQ(receivedString.str().compare(expectedString), 0); - } -}; +void test_alarm_message() +{ + TEST_ASSERT_TRUE(true); +} int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - // if you plan to use GMock, replace the line above with - // ::testing::InitGoogleMock(&argc, argv); + UNITY_BEGIN(); - if (RUN_ALL_TESTS()) - ; + RUN_TEST(test_alarm_message); - // Always return zero-code and allow PlatformIO to parse results - return 0; + UNITY_END(); } From 8ae954030b16b9ccfd700a1465f8d95b216235cf Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:31:02 -0400 Subject: [PATCH 35/36] (#387): Testing has been updated to leverage new mocking types --- .../GPAP/src/AlarmMessage/AlarmContent.cpp | 30 +++++++++++ .../lib/GPAP/src/AlarmMessage/AlarmContent.h | 15 +++++- .../src/AlarmMessage/AlarmTypeDesignator.h | 2 +- Firmware/GPAD_API/lib/mocking/MockPrint.h | 6 ++- .../native/test_GPAP/test_gpap_message.cpp | 54 +++++++++++-------- 5 files changed, 82 insertions(+), 25 deletions(-) diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp index 0ee4c905..82bc4780 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.cpp @@ -1,5 +1,14 @@ #include "AlarmContent.h" +#include + +#ifndef PIO_UNIT_TESTING +#include +#else +#include +using Print = MockPrint; +#endif + using namespace gpap_message::alarm; AlarmContent::AlarmContent(const std::size_t messageLength, const Buffer message) @@ -10,3 +19,24 @@ AlarmContent::AlarmContent(const std::size_t messageLength, const Buffer message throw; } } + +AlarmContent::~AlarmContent() {} + +std::size_t AlarmContent::printTo(Print &print) const +{ + auto beginIterator = this->message.cbegin(); + const auto endIterator = std::next(beginIterator, this->messageLength); + + auto bytesWritten = 0; + + std::for_each( + beginIterator, + endIterator, + [&bytesWritten, &print](const char &currElement) + { + bytesWritten += print.print(currElement); + }); + + bytesWritten += print.print('\0'); + return bytesWritten; +} diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h index 83e85cdd..db908795 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmContent.h @@ -21,10 +21,19 @@ #include #include +#ifndef PIO_UNIT_TESTING +#include +#else +#include "MockPrintable.h" +#include "MockPrint.h" +using Printable = MockPrintable; +using Print = MockPrint; +#endif + namespace gpap_message::alarm { - class AlarmContent final + class AlarmContent final : public Printable { public: static const std::size_t MAX_LENGTH = 80; @@ -53,6 +62,10 @@ namespace gpap_message::alarm AlarmContent() = delete; AlarmContent(AlarmContent &other) = delete; AlarmContent(const AlarmContent &other) = delete; + + virtual ~AlarmContent(); + + std::size_t printTo(Print &print) const; }; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h index 9aca1312..b81383e9 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h @@ -31,7 +31,7 @@ using Print = MockPrint; namespace gpap_message::alarm { - class AlarmTypeDesignator final : Printable + class AlarmTypeDesignator final : public Printable { public: static const std::size_t DESIGNATOR_LENGTH = 3; diff --git a/Firmware/GPAD_API/lib/mocking/MockPrint.h b/Firmware/GPAD_API/lib/mocking/MockPrint.h index 449a33e5..f2cd8a99 100644 --- a/Firmware/GPAD_API/lib/mocking/MockPrint.h +++ b/Firmware/GPAD_API/lib/mocking/MockPrint.h @@ -2,13 +2,15 @@ #define _MOCK_PRINT_H #include +#include class MockPrint { public: - std::size_t print(char) + virtual std::size_t write(uint8_t) = 0; + std::size_t print(char character) { - return 0; + return this->write((uint8_t)character); } }; diff --git a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp index 73bd28e9..b55e156f 100644 --- a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp +++ b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp @@ -1,36 +1,48 @@ #include #include +#include +#include + +#ifndef PIO_UNIT_TESTING +#define PIO_UNIT_TESTING +#endif #include "GPAPMessage.h" -// namespace gpap_message -// { -// class GPAPMessageTest : public testing::Test -// { -// }; +#include "MockPrint.h" + +class VectorMockPrint : public MockPrint +{ +private: + std::vector contents; + +public: + std::size_t write(uint8_t character) override + { + this->contents.push_back(character); + return 1; + } +}; -// TEST_F(GPAPMessageTest, TestFunc) -// { -// static const char *alarmMessageStr = "a5Test message[444]{a4ab}"; +void test_alarm_message() +{ + using namespace gpap_message; -// const auto gpapMessage = GPAPMessage::deserialize(alarmMessageStr, strlen(alarmMessageStr)); + static const char *alarmMessageStr = "a5Test message[444]{a4ab}"; + static const char *alarmContentStr = "Test Message"; + static const char *typeDesignatorStr = "444"; + static const char *messageIdStr = "a4ab"; -// EXPECT_EQ(gpapMessage.getMessageType(), MessageType::ALARM); + const auto gpapMessage = GPAPMessage::deserialize(alarmMessageStr, std::strlen(alarmMessageStr)); -// const std::string expectedString = "Test message"; -// std::ostringstream receivedString; -// receivedString << gpapMessage.getAlarmMessage().getAlarmContent(); + TEST_ASSERT_EQUAL(MessageType::ALARM, gpapMessage.getMessageType()); -// std::cout << expectedString << std::endl; -// std::cout << receivedString.str() << std::endl; + auto vectorMockPrint = VectorMockPrint(); -// EXPECT_EQ(receivedString.str().compare(expectedString), 0); -// } -// }; + const alarm::AlarmMessage &alarmMessage = gpapMessage.getAlarmMessage(); + auto alarmContentBytesWritten = alarmMessage.getAlarmContent().printTo(vectorMockPrint); -void test_alarm_message() -{ - TEST_ASSERT_TRUE(true); + TEST_ASSERT_EQUAL(std::strlen(alarmContentStr) + 1, alarmContentBytesWritten); } int main(int argc, char **argv) From 54d2173e5f8c272080094b13905fd592e24f3338 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:18:08 -0400 Subject: [PATCH 36/36] (#387): Completed unit test --- Firmware/GPAD_API/GPAD_API/GPAD_API.ino | 1 - .../GPAD_API/lib/GPAP/src/AlarmMessage.cpp | 5 + Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h | 1 + .../GPAP/src/AlarmMessage/AlarmMessageId.cpp | 28 +++ .../GPAP/src/AlarmMessage/AlarmMessageId.h | 17 +- .../src/AlarmMessage/AlarmTypeDesignator.h | 2 +- .../native/test_GPAP/test_gpap_message.cpp | 164 ++++++++++++++++-- 7 files changed, 199 insertions(+), 19 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino index 2fd9c0d6..a8d8251d 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino +++ b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino @@ -55,7 +55,6 @@ #include "gpad_utility.h" #include "gpad_serial.h" #include "Wink.h" -#include "GPAPMessage.h" #include #include diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp index 3b824f4e..6fa66b20 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.cpp @@ -16,3 +16,8 @@ const AlarmMessage::PossibleTypeDesignator &AlarmMessage::getTypeDesignator() co { return this->typeDesignator; } + +const AlarmMessage::PossibleMessageId &AlarmMessage::getMessageId() const noexcept +{ + return this->messageId; +} diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h index 4aab409d..384448da 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage.h @@ -86,6 +86,7 @@ namespace gpap_message::alarm const AlarmContent &getAlarmContent() const noexcept; Level getAlarmLevel() const noexcept; const PossibleTypeDesignator &getTypeDesignator() const noexcept; + const PossibleMessageId &getMessageId() const noexcept; }; } // namespace alarm diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp index 12b0dca7..680486eb 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.cpp @@ -20,6 +20,13 @@ #include #include +#ifndef PIO_UNIT_TESTING +#include +#else +#include +using Print = MockPrint; +#endif + using namespace gpap_message::alarm; AlarmMessageId::AlarmMessageId( @@ -65,3 +72,24 @@ std::array AlarmMessageId::validateId( *validatedIdIterator = '\0'; return std::move(validatedId); } + +AlarmMessageId::~AlarmMessageId() {} + +std::size_t AlarmMessageId::printTo(Print &print) const +{ + auto beginIterator = this->id.cbegin(); + const auto endIterator = std::next(beginIterator, this->idLength); + + auto bytesWritten = 0; + + std::for_each( + beginIterator, + endIterator, + [&bytesWritten, &print](const char &character) + { + bytesWritten += print.print(character); + }); + + bytesWritten += print.print('\0'); + return bytesWritten; +} diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h index ca62c1a7..c53934cd 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmMessageId.h @@ -20,9 +20,18 @@ #include +#ifndef PIO_UNIT_TESTING +#include +#else +#include "MockPrintable.h" +#include "MockPrint.h" +using Printable = MockPrintable; +using Print = MockPrint; +#endif + namespace gpap_message::alarm { - class AlarmMessageId final + class AlarmMessageId final : public Printable { public: // TODO: Find out what this value is SUPPOSED to be. @@ -33,7 +42,6 @@ namespace gpap_message::alarm private: static const std::size_t TOTAL_MAX_LENGTH = AlarmMessageId::MAX_LENGTH + 1; - public: std::size_t idLength; std::array id; @@ -56,9 +64,14 @@ namespace gpap_message::alarm AlarmMessageId(AlarmMessageId &other) = delete; AlarmMessageId(const AlarmMessageId &other) = delete; + virtual ~AlarmMessageId(); + private: static std::array validateId(const std::size_t idLength, const Buffer); + + public: + std::size_t printTo(Print &print) const; }; } diff --git a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h index b81383e9..953e78e9 100644 --- a/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h +++ b/Firmware/GPAD_API/lib/GPAP/src/AlarmMessage/AlarmTypeDesignator.h @@ -62,7 +62,7 @@ namespace gpap_message::alarm public: const Buffer &getValue() const; - std::size_t printTo(Print &p) const; + std::size_t printTo(Print &print) const; }; } diff --git a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp index b55e156f..a5915dbb 100644 --- a/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp +++ b/Firmware/GPAD_API/test/native/test_GPAP/test_gpap_message.cpp @@ -8,48 +8,182 @@ #endif #include "GPAPMessage.h" - #include "MockPrint.h" class VectorMockPrint : public MockPrint { private: - std::vector contents; + std::vector contents; public: std::size_t write(uint8_t character) override { - this->contents.push_back(character); + this->contents.push_back(static_cast(character)); + this->contents.shrink_to_fit(); return 1; } + + const char *data() + { + return this->contents.data(); + } + + void clear() + { + this->contents.clear(); + } }; -void test_alarm_message() +struct AlarmMessageData final { - using namespace gpap_message; + const gpap_message::alarm::AlarmMessage::Level alarmLevel; + const std::string alarmContentStr; + const std::string typeDesignatorStr; + const std::string messageIdStr; + + AlarmMessageData( + const gpap_message::alarm::AlarmMessage::Level alarmLevel, + const std::string alarmContentStr, + const std::string typeDesignatorStr, + const std::string messageIdStr) + : alarmLevel(alarmLevel), + alarmContentStr(alarmContentStr), + typeDesignatorStr(typeDesignatorStr), + messageIdStr(messageIdStr) {} +}; - static const char *alarmMessageStr = "a5Test message[444]{a4ab}"; - static const char *alarmContentStr = "Test Message"; - static const char *typeDesignatorStr = "444"; - static const char *messageIdStr = "a4ab"; +void alarm_test_helper(const AlarmMessageData &alarmMessageData, const std::string &fullMessageString) +{ + using namespace gpap_message; - const auto gpapMessage = GPAPMessage::deserialize(alarmMessageStr, std::strlen(alarmMessageStr)); + const auto gpapMessage = GPAPMessage::deserialize(fullMessageString.c_str(), fullMessageString.length()); + const alarm::AlarmMessage &alarmMessage = gpapMessage.getAlarmMessage(); TEST_ASSERT_EQUAL(MessageType::ALARM, gpapMessage.getMessageType()); + TEST_ASSERT_EQUAL(alarmMessageData.alarmLevel, alarmMessage.getAlarmLevel()); - auto vectorMockPrint = VectorMockPrint(); + auto printedData = VectorMockPrint(); + auto alarmContentBytesWritten = alarmMessage.getAlarmContent().printTo(printedData); - const alarm::AlarmMessage &alarmMessage = gpapMessage.getAlarmMessage(); - auto alarmContentBytesWritten = alarmMessage.getAlarmContent().printTo(vectorMockPrint); + // Have to add an additional 1 since AlarmContent handles printing the null terminator as well + TEST_ASSERT_EQUAL(alarmMessageData.alarmContentStr.size() + 1, alarmContentBytesWritten); + TEST_ASSERT_EQUAL(strcmp(alarmMessageData.alarmContentStr.c_str(), printedData.data()), 0); + printedData.clear(); + + if (alarmMessage.getTypeDesignator().state == alarm::PossibleParameter::State::Some) + { + auto typeDesignatorBytesWritten = alarmMessage.getTypeDesignator().contents.printTo(printedData); + // Have to add an additional 1 since AlarmContent handles printing the null terminator as well + TEST_ASSERT_EQUAL(alarmMessageData.typeDesignatorStr.size() + 1, typeDesignatorBytesWritten); + TEST_ASSERT_EQUAL(strcmp(alarmMessageData.typeDesignatorStr.c_str(), printedData.data()), 0); + printedData.clear(); + } + else + { + TEST_ASSERT_TRUE(alarmMessageData.typeDesignatorStr.empty()); + } + + if (alarmMessage.getMessageId().state == alarm::PossibleParameter::State::Some) + { + auto messageIdBytesWritten = alarmMessage.getMessageId().contents.printTo(printedData); + TEST_ASSERT_EQUAL(alarmMessageData.messageIdStr.size() + 1, messageIdBytesWritten); + TEST_ASSERT_EQUAL(strcmp(alarmMessageData.messageIdStr.c_str(), printedData.data()), 0); + } + else + { + TEST_ASSERT_TRUE(alarmMessageData.messageIdStr.empty()); + } +} + +void test_alarm_message_order_content_designator_id() +{ + static const std::string alarmMessageStr = "a5Test message[444]{a4ab}"; + static const std::string alarmContentStr = "Test message"; + static const std::string typeDesignatorStr = "444"; + static const std::string messageIdStr = "a4ab"; + + const auto alarmData = AlarmMessageData( + gpap_message::alarm::AlarmMessage::Level::Level5, + alarmContentStr, + typeDesignatorStr, + messageIdStr); + + alarm_test_helper(alarmData, alarmMessageStr); +} + +void test_alarm_message_order_designator_content_id() +{ + static const std::string alarmMessageStr = "a2[432]Testing more messages{abcdef}"; + static const std::string alarmContentStr = "Testing more messages"; + static const std::string typeDesignatorStr = "432"; + static const std::string messageIdStr = "abcdef"; + + const auto alarmData = AlarmMessageData( + gpap_message::alarm::AlarmMessage::Level::Level2, + alarmContentStr, + typeDesignatorStr, + messageIdStr); + + alarm_test_helper(alarmData, alarmMessageStr); +} + +void test_alarm_message_only_content() +{ + static const std::string alarmMessageStr = "a0Content only alarm"; + static const std::string alarmContentStr = "Content only alarm"; + static const std::string typeDesignatorStr = ""; + static const std::string messageIdStr = ""; + + const auto alarmData = AlarmMessageData( + gpap_message::alarm::AlarmMessage::Level::Level0, + alarmContentStr, + typeDesignatorStr, + messageIdStr); + + alarm_test_helper(alarmData, alarmMessageStr); +} + +void test_alarm_message_only_id() +{ + static const std::string alarmMessageStr = "a1{98765}"; + static const std::string alarmContentStr = ""; + static const std::string typeDesignatorStr = ""; + static const std::string messageIdStr = "98765"; + + const auto alarmData = AlarmMessageData( + gpap_message::alarm::AlarmMessage::Level::Level1, + alarmContentStr, + typeDesignatorStr, + messageIdStr); + + alarm_test_helper(alarmData, alarmMessageStr); +} + +void test_alarm_message_only_type_designator() +{ + static const std::string alarmMessageStr = "a3[000]"; + static const std::string alarmContentStr = ""; + static const std::string typeDesignatorStr = "000"; + static const std::string messageIdStr = ""; + + const auto alarmData = AlarmMessageData( + gpap_message::alarm::AlarmMessage::Level::Level3, + alarmContentStr, + typeDesignatorStr, + messageIdStr); - TEST_ASSERT_EQUAL(std::strlen(alarmContentStr) + 1, alarmContentBytesWritten); + alarm_test_helper(alarmData, alarmMessageStr); } int main(int argc, char **argv) { UNITY_BEGIN(); - RUN_TEST(test_alarm_message); + RUN_TEST(test_alarm_message_order_content_designator_id); + RUN_TEST(test_alarm_message_order_designator_content_id); + RUN_TEST(test_alarm_message_only_content); + RUN_TEST(test_alarm_message_only_id); + RUN_TEST(test_alarm_message_only_type_designator); UNITY_END(); }