Files
Leo-ElixirLights/components/spit/src/spit_message.cpp
T
2025-11-10 10:43:13 +01:00

1349 lines
44 KiB
C++

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/*
* Message contains all SPIT messages.
* A Message contains a Header and an OPPart.
*
* File: Message.cpp
* Author: Hagi
*
* Created on 3. April 2019, 08:51
*/
#include "spit_message.hpp"
#include "esp_log.h"
#include <cstring>
const char *TAG = "SpitMsg";
namespace spit {
//---------- Receive ---------
Message::Message(std::vector<char> message) {
if (message.empty()) {
ESP_LOGE(TAG, "message is emtpy, nothing to parse");
return;
}
if (!parse(message)) {
ESP_LOGE(TAG, "Failed ot parse message");
return;
}
}
// Receive
bool Message::parse(std::vector<char> message) {
// parse Header
auto header = make_unique<Header>();
if (!header->parse(message)) {
return false;
}
// parse OP
switch (header->getType()) {
case Message::Connect::OPFLAG: { // Connection
m_OPPart = make_unique<Connect>(move(header));
} break;
case Message::ConnectAnswer::OPFLAG: {
m_OPPart = make_unique<ConnectAnswer>(move(header));
} break;
case Disconnect::OPFLAG: {
m_OPPart = make_unique<Disconnect>(move(header));
} break;
case Watchdog::OPFLAG: {
m_OPPart = make_unique<Watchdog>(move(header));
} break;
case WatchdogAnswer::OPFLAG: {
m_OPPart = make_unique<WatchdogAnswer>(move(header));
} break;
case ReportProject::OPFLAG: { // SpitProject
m_OPPart = make_unique<ReportProject>(move(header));
} break;
case CloseProject::OPFLAG: {
m_OPPart = make_unique<CloseProject>(move(header));
} break;
case RequestProjectTransfer::OPFLAG: {
m_OPPart = make_unique<RequestProjectTransfer>(move(header));
} break;
case StartProjectTransfer::OPFLAG: {
m_OPPart = make_unique<StartProjectTransfer>(move(header));
} break;
case EndProjectTransfer::OPFLAG: {
m_OPPart = make_unique<EndProjectTransfer>(move(header));
} break;
case ReportType::OPFLAG: { // SpitType
m_OPPart = make_unique<ReportType>(move(header));
} break;
case RemoveType::OPFLAG: {
m_OPPart = make_unique<RemoveType>(move(header));
} break;
case ReportObject::OPFLAG: { // SpitObject
m_OPPart = make_unique<ReportObject>(move(header));
} break;
case RemoveObject::OPFLAG: {
m_OPPart = make_unique<RemoveObject>(move(header));
} break;
case PlayStart::OPFLAG: { // PlaySpitObjects
m_OPPart = make_unique<PlayStart>(move(header));
} break;
case PlayObject::OPFLAG: {
m_OPPart = make_unique<PlayObject>(move(header));
} break;
case PlayEnd::OPFLAG: {
m_OPPart = make_unique<PlayEnd>(move(header));
} break;
case ReportPlayStatus::OPFLAG: {
m_OPPart = make_unique<ReportPlayStatus>(move(header));
} break;
default:
return false;
}
return m_OPPart->parse(message);
}
//---------- Send ----------
std::vector<char> Message::createMessage(OPPart &p_OPPart) {
if (!p_OPPart.getHeader()) {
return {};
}
try {
int totalSize = Header::BYTESLENGTH + p_OPPart.getBytesCount();
std::vector<char> msgByts(totalSize);
p_OPPart.fillBytes(msgByts);
return msgByts;
} catch (...) {
ESP_LOGE(TAG, "Failed to allocate memory");
}
return {};
}
//----------- Header -----------
Message::Header::Header(const Header &orig) {
mID = &SPITID[0];
mMessageNumber = orig.getMessageNumber();
mServerID = orig.getServerID();
mClientID = orig.getClientID();
}
Message::Header::Header() {
mID = &SPITID[0];
}
bool Message::Header::parse(const std::vector<char> &message) {
try {
mParseOffset = 0;
auto strID = getString(message, mParseOffset, 7).value();
if (strID != SPITID) {
return false;
}
auto iVer = getInt(message, mParseOffset).value();
if (iVer < 0) {
return false;
}
mMessageNumber = getByte(message, mParseOffset).value();
mBytesCount = getInt(message, mParseOffset).value();
if (mBytesCount < 0) {
return false;
}
mServerID = getString(message, mParseOffset, 41).value();
mClientID = getString(message, mParseOffset, 41).value();
mOpFlag = message[mParseOffset++] & 0xFF;
} catch (...) {
ESP_LOGE(TAG, "failed to parse Header");
return false;
}
return true;
}
// Send
Message::Header::Header(int p_SPITVersion, int p_OPFlag) {
mID = &SPITID[0];
mVersion = p_SPITVersion;
mOpFlag = p_OPFlag;
}
bool Message::Header::fillBytes(std::vector<char> &message) {
try {
mParseOffset = 0;
mParseOffset += setString(mID, message, mParseOffset, 7);
mParseOffset += setInt(SPITVERSION, message, mParseOffset);
mParseOffset += setByte(mMessageNumber, message, mParseOffset);
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(mServerID, message, mParseOffset, 41);
mParseOffset += setString(mClientID, message, mParseOffset, 41);
mParseOffset += setByte(mOpFlag, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create Header");
return false;
}
return true;
}
//----------- OPPart -----------
Message::OPPart::~OPPart() {
}
// Receive
Message::OPPart::OPPart(unique_ptr<Header> p_Header, int p_OPFlag, int size)
: mHeader(move(p_Header)),
mBytesCount(size) {
if (!mHeader) {
mParseOffset = Header::BYTESLENGTH;
mHeader->setOPFlag(p_OPFlag);
}
}
void Message::OPPart::setHeader(int opFlag) {
mHeader = make_unique<Header>(SPITVERSION, opFlag);
mParseOffset = Header::BYTESLENGTH;
}
// Send
Message::OPPart::OPPart(int size)
: mBytesCount(size) {}
//--------------------------- Connection --------------------------------
//----------- Connect -----------
// Receive
Message::Connect::Connect(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::Connect::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_ClientComputerName = getString(message, mParseOffset, 64).value();
m_ClientName = getString(message, mParseOffset, 64).value();
m_LoginName = getString(message, mParseOffset, 64).value();
m_LoginPassword = getString(message, mParseOffset, 64).value();
m_ServerIP = getString(message, mParseOffset, 40).value();
m_ServerPort = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse Connect message");
return false;
}
return true;
}
// Send
Message::Connect::Connect(string p_ComputerName, string p_ClientName)
: OPPart(BYTESLENGTH),
m_ClientComputerName(p_ComputerName),
m_ClientName(p_ClientName) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
void Message::Connect::setServerPort(int p_ServerPort) {
if (p_ServerPort < 0 || p_ServerPort > 65535)
p_ServerPort = 0;
m_ServerPort = p_ServerPort;
}
bool Message::Connect::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_ClientComputerName, message, mParseOffset, 64);
mParseOffset += setString(m_ClientName, message, mParseOffset, 64);
mParseOffset += setString(m_LoginName, message, mParseOffset, 64);
mParseOffset += setString(m_LoginPassword, message, mParseOffset, 64);
mParseOffset += setString(m_ServerIP, message, mParseOffset, 40);
mParseOffset += setInt(m_ServerPort, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create Connect message");
return false;
}
return true;
}
//----------- ConnectAnswer -----------
// Receive
Message::ConnectAnswer::ConnectAnswer(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {}
bool Message::ConnectAnswer::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_ServerComputerName = getString(message, mParseOffset, 64).value();
m_ServerName = getString(message, mParseOffset, 64).value();
m_StepTime = getInt(message, mParseOffset).value();
m_Connected = getBoolean(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse ConnectAnswer message");
return false;
}
return true;
}
// Send
Message::ConnectAnswer::ConnectAnswer()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
void Message::ConnectAnswer::setStepTime(int p_StepTime_ms) {
if (p_StepTime_ms < 0)
p_StepTime_ms = 1;
m_StepTime = p_StepTime_ms;
}
bool Message::ConnectAnswer::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_ServerComputerName, message, mParseOffset, 64);
mParseOffset += setString(m_ServerName, message, mParseOffset, 64);
mParseOffset += setInt(m_StepTime, message, mParseOffset);
mParseOffset += setBoolean(m_Connected, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create ConnectAnswer message");
return false;
}
return true;
}
//----------- Disconnect -----------
// Receive
Message::Disconnect::Disconnect(unique_ptr<Header> p_Header) : OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::Disconnect::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse Disconnect message");
return false;
}
return true;
}
// Send
Message::Disconnect::Disconnect()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
}
bool Message::Disconnect::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create Disconnect message");
return false;
}
return true;
}
//----------- Watchdog -----------
// Receive
Message::Watchdog::Watchdog(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::Watchdog::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse Watchdog message");
return false;
}
return true;
}
// Send
Message::Watchdog::Watchdog() : OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::Watchdog::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create Watchdog message");
return false;
}
return true;
}
//----------- WatchdogAnswer -----------
// Receive
Message::WatchdogAnswer::WatchdogAnswer(unique_ptr<Header> p_Header) : OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::WatchdogAnswer::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse WatchdogAnswer message");
return false;
}
return true;
}
// Send
Message::WatchdogAnswer::WatchdogAnswer() : OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::WatchdogAnswer::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create WatchdogAnswer message");
return false;
}
return true;
}
//--------------------------- SPITProject --------------------------------
//----------- ReportProject -----------
// Receive
Message::ReportProject::ReportProject(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::ReportProject::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_ProjectID = getString(message, mParseOffset, 41).value();
m_ProjectName = getString(message, mParseOffset, 64).value();
m_FramesPerSecond = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse ReportProject message");
return false;
}
return true;
}
// Send
Message::ReportProject::ReportProject(string p_ProjectID, string p_ProjectName)
: OPPart(BYTESLENGTH),
m_ProjectID(p_ProjectID),
m_ProjectName(p_ProjectName) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::ReportProject::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_ProjectID, message, mParseOffset, 41);
mParseOffset += setString(m_ProjectName, message, mParseOffset, 64);
mParseOffset += setInt(m_FramesPerSecond, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create ReportProject message");
return false;
}
return true;
}
//----------- StartProjectTransfer -----------
// Receive
Message::CloseProject::CloseProject(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::CloseProject::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_ProjectID = getString(message, mParseOffset, 41).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse CloseProject message");
return false;
}
return true;
}
// Send
Message::CloseProject::CloseProject(string projectID)
: OPPart(BYTESLENGTH),
m_ProjectID(projectID) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::CloseProject::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_ProjectID, message, mParseOffset, 41);
} catch (...) {
ESP_LOGE(TAG, "failed to create CloseProject message");
return false;
}
return true;
}
//----------- RequestProjectTransfer -----------
// Receive
Message::RequestProjectTransfer::RequestProjectTransfer(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::RequestProjectTransfer::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse RequestProjectTransfer message");
return false;
}
return true;
}
// Send
Message::RequestProjectTransfer::RequestProjectTransfer()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::RequestProjectTransfer::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create RequestProjectTransfer message");
return false;
}
return true;
}
//----------- StartProjectTransfer -----------
// Receive
Message::StartProjectTransfer::StartProjectTransfer(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::StartProjectTransfer::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse StartProjectTransfer message");
return false;
}
return true;
}
// Send
Message::StartProjectTransfer::StartProjectTransfer()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::StartProjectTransfer::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create StartProjectTransfer message");
return false;
}
return true;
}
//----------- ENdProjectTransfer -----------
// Receive
Message::EndProjectTransfer::EndProjectTransfer(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::EndProjectTransfer::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse EndProjectTransfer message");
return false;
}
return true;
}
// Send
Message::EndProjectTransfer::EndProjectTransfer()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::EndProjectTransfer::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create EndProjectTransfer message");
return false;
}
return true;
}
//--------------------------- SPITType ---------------------------------
//----------- ReportType -----------
// Receive
Message::ReportType::ReportType(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::ReportType::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_Confirmed = getBoolean(message, mParseOffset).value();
m_SPITTypeID = getString(message, mParseOffset, 41).value();
m_Fixed = getBoolean(message, mParseOffset).value();
m_ServerRemote = getBoolean(message, mParseOffset).value();
m_ServerProjectIndepended = getBoolean(message, mParseOffset).value();
m_SPITTypeGroupName = getString(message, mParseOffset, 39).value();
m_SPITTypeName = getString(message, mParseOffset, 64).value();
m_Delay = getLong(message, mParseOffset).value();
m_Duration = getLong(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse ReportType message");
return false;
}
return true;
}
// Send
Message::ReportType::ReportType()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::ReportType::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = mHeader->BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setBoolean(m_Confirmed, message, mParseOffset);
mParseOffset += setString(m_SPITTypeID, message, mParseOffset, 41);
mParseOffset += setBoolean(m_Fixed, message, mParseOffset);
mParseOffset += setBoolean(m_ServerRemote, message, mParseOffset);
mParseOffset += setBoolean(m_ServerProjectIndepended, message, mParseOffset);
mParseOffset += setString(m_SPITTypeGroupName, message, mParseOffset, 39);
mParseOffset += setString(m_SPITTypeName, message, mParseOffset, 64);
mParseOffset += setLong(m_Delay, message, mParseOffset);
mParseOffset += setLong(m_Duration, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create ReportType message");
return false;
}
return true;
}
//----------- ReportType -----------
// Receive
Message::RemoveType::RemoveType(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::RemoveType::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_SPITTypeID = getString(message, mParseOffset, 41).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse RemoveType message");
return false;
}
return true;
}
// Send
Message::RemoveType::RemoveType()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::RemoveType::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_SPITTypeID, message, mParseOffset, 41);
} catch (...) {
ESP_LOGE(TAG, "failed to create RemoveType message");
return false;
}
return true;
}
//---------------------------- SPITObjects ----------------------------------
//----------- ReportObject -----------
// Receive
Message::ReportObject::ReportObject(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::ReportObject::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_Confirmed = getBoolean(message, mParseOffset).value();
m_SPITObjectID = getString(message, mParseOffset, 41).value();
m_Fixed = getBoolean(message, mParseOffset).value();
m_ServerRemote = getBoolean(message, mParseOffset).value();
m_SPITObjectName = getString(message, mParseOffset, 64).value();
m_SPITTypeID = getString(message, mParseOffset, 41).value();
m_ServerParams = getString(message, mParseOffset, 64).value();
m_FrameStart = getLong(message, mParseOffset).value();
m_FrameLength = getLong(message, mParseOffset).value();
m_FrameFadeInLength = getLong(message, mParseOffset).value();
m_FrameFadeOutLength = getLong(message, mParseOffset).value();
m_ValueFactor = getInt(message, mParseOffset).value();
m_ValueUse = getByte(message, mParseOffset).value();
m_Track = getInt(message, mParseOffset).value();
m_Remark = getString(message, mParseOffset, 64).value();
m_Delay = getLong(message, mParseOffset).value();
m_Duration = getLong(message, mParseOffset).value();
m_ActionAssigned = getBoolean(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse ReportObject message");
return false;
}
return true;
}
// Send
Message::ReportObject::ReportObject() : OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
void Message::ReportObject::setDelay(uint64_t p_Delay) {
if (p_Delay < 0)
p_Delay = 0;
m_Delay = p_Delay;
}
void Message::ReportObject::setDuration(uint64_t p_Duration) {
if (p_Duration < 0)
p_Duration = 0;
m_Duration = p_Duration;
}
bool Message::ReportObject::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setBoolean(m_Confirmed, message, mParseOffset);
mParseOffset += setString(m_SPITObjectID, message, mParseOffset, 41);
mParseOffset += setBoolean(m_Fixed, message, mParseOffset);
mParseOffset += setBoolean(m_ServerRemote, message, mParseOffset);
mParseOffset += setString(m_SPITObjectName, message, mParseOffset, 64);
mParseOffset += setString(m_SPITTypeID, message, mParseOffset, 41);
mParseOffset += setString(m_ServerParams, message, mParseOffset, 64);
mParseOffset += setLong(m_FrameStart, message, mParseOffset);
mParseOffset += setLong(m_FrameLength, message, mParseOffset);
mParseOffset += setLong(m_FrameFadeInLength, message, mParseOffset);
mParseOffset += setLong(m_FrameFadeOutLength, message, mParseOffset);
mParseOffset += setInt(m_ValueFactor, message, mParseOffset);
mParseOffset += setByte(m_ValueUse, message, mParseOffset);
mParseOffset += setInt(m_Track, message, mParseOffset);
mParseOffset += setString(m_Remark, message, mParseOffset, 64);
mParseOffset += setLong(m_Delay, message, mParseOffset);
mParseOffset += setLong(m_Duration, message, mParseOffset);
mParseOffset += setBoolean(m_ActionAssigned, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create ReportObject message");
return false;
}
return true;
}
//----------- RemoveObject -----------
// Receive
Message::RemoveObject::RemoveObject(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::RemoveObject::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_SPITObjectID = getString(message, mParseOffset, 41).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse RemoveObject message");
return false;
}
return true;
}
// Send
Message::RemoveObject::RemoveObject() : OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::RemoveObject::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_SPITObjectID, message, mParseOffset, 41);
} catch (...) {
ESP_LOGE(TAG, "failed to create RemoveObject message");
return false;
}
return true;
}
//---------------------------- SPITPlayer ----------------------------------
//----------- PlayStart -----------
// Receive
Message::PlayStart::PlayStart(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::PlayStart::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_PlayerID = getString(message, mParseOffset, 41).value();
m_PlayerName = getString(message, mParseOffset, 64).value();
m_PlayerType = getByte(message, mParseOffset).value();
m_PlayerIsRunning = getBoolean(message, mParseOffset).value();
m_Time = getLong(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse PlayStart message");
return false;
}
return true;
}
// Send
Message::PlayStart::PlayStart(string p_PlayerID, string p_PlayerName, char p_PlayerType)
: OPPart(BYTESLENGTH),
m_PlayerID(p_PlayerID),
m_PlayerName(p_PlayerName),
m_PlayerType(p_PlayerType) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::PlayStart::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_PlayerID, message, mParseOffset, 41);
mParseOffset += setString(m_PlayerName, message, mParseOffset, 64);
mParseOffset += setByte(m_PlayerType, message, mParseOffset);
mParseOffset += setBoolean(m_PlayerIsRunning, message, mParseOffset);
mParseOffset += setLong(m_Time, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create PlayStart message");
return false;
}
return true;
}
//----------- PlayObject -----------
// Receive
Message::PlayObject::PlayObject(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::PlayObject::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_PlayerID = getString(message, mParseOffset, 41).value();
m_SPITObjectID = getString(message, mParseOffset, 41).value();
m_FrameInsideObject = getLong(message, mParseOffset).value();
m_PlayPrePosition = getBoolean(message, mParseOffset).value();
m_Value = getInt(message, mParseOffset).value();
m_ValueFlag = getByte(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse PlayObject message");
return false;
}
return true;
}
// Send
Message::PlayObject::PlayObject()
: OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::PlayObject::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_PlayerID, message, mParseOffset, 41);
mParseOffset += setString(m_SPITObjectID, message, mParseOffset, 41);
mParseOffset += setLong(m_FrameInsideObject, message, mParseOffset);
mParseOffset += setBoolean(m_PlayPrePosition, message, mParseOffset);
mParseOffset += setInt(m_Value, message, mParseOffset);
mParseOffset += setByte(m_ValueFlag, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create PlayObject message");
return false;
}
return true;
}
//----------- PlayEnd -----------
// Receive
Message::PlayEnd::PlayEnd(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::PlayEnd::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_PlayerID = getString(message, mParseOffset, 41).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse PlayEnd message");
return false;
}
return true;
}
// Send
Message::PlayEnd::PlayEnd(string p_PlayerID)
: OPPart(BYTESLENGTH),
m_PlayerID(p_PlayerID) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
bool Message::PlayEnd::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_PlayerID, message, mParseOffset, 41);
} catch (...) {
ESP_LOGE(TAG, "failed to create PlayEnd message");
return false;
}
return true;
}
//----------- ReportPlayStatus -----------
// Receive
Message::ReportPlayStatus::ReportPlayStatus(unique_ptr<Header> p_Header)
: OPPart(move(p_Header), OPFLAG, BYTESLENGTH) {
}
bool Message::ReportPlayStatus::parse(const std::vector<char> &message) {
if (!mHeader) {
return false;
}
int intOPFlag = mHeader->getType();
if (intOPFlag != OPFLAG)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mBytesCount = getInt(message, mParseOffset).value();
m_SPITObjectID = getString(message, mParseOffset, 41).value();
m_FrameInsideObject = getLong(message, mParseOffset).value();
m_Value = getInt(message, mParseOffset).value();
} catch (...) {
ESP_LOGE(TAG, "failed to parse ReportPlayStatus message");
return false;
}
return true;
}
// Send
Message::ReportPlayStatus::ReportPlayStatus() : OPPart(BYTESLENGTH) {
setHeader(OPFLAG);
mParseOffset = Header::BYTESLENGTH;
}
void Message::ReportPlayStatus::setID(string p_ID) {
m_SPITObjectID = p_ID;
}
void Message::ReportPlayStatus::setFrameInsideObject(uint64_t p_TimeInside) {
m_FrameInsideObject = p_TimeInside;
}
void Message::ReportPlayStatus::setValue(int p_Value) {
m_Value = p_Value;
}
bool Message::ReportPlayStatus::fillBytes(std::vector<char> &message) {
if (!mHeader) {
return false;
}
if (mHeader->fillBytes(message) == false)
return false;
try {
mParseOffset = Header::BYTESLENGTH;
mParseOffset += setInt(mBytesCount, message, mParseOffset);
mParseOffset += setString(m_SPITObjectID, message, mParseOffset, 41);
mParseOffset += setLong(m_FrameInsideObject, message, mParseOffset);
mParseOffset += setInt(m_Value, message, mParseOffset);
} catch (...) {
ESP_LOGE(TAG, "failed to create ReportPlayStatus message");
return false;
}
return true;
}
//---------------------------- static helper functions -----------------------
bool Message::isSystemLittleEndian() {
// todo replace with #include <bit> then if constexpr (std::endian::native == std::endian::big)
int intOne = 1;
char *firstByte;
firstByte = (char *)&intOne;
if (*firstByte > 0) {
return false;
}
return true;
}
optional<int> Message::getInt(const std::vector<char> &message, int &offset) {
if (offset < 0 || offset + 4 > message.size())
return std::nullopt;
// low byte first
int intValue = 0;
if (isSystemLittleEndian() == false) {
intValue += ((message[offset + 0] & 0x000000ff));
intValue += ((message[offset + 1] & 0x000000ff) << 8);
intValue += ((message[offset + 2] & 0x000000ff) << 16);
intValue += ((message[offset + 3] & 0x000000ff) << 24);
} else {
intValue += ((message[offset + 3] & 0x000000ff));
intValue += ((message[offset + 2] & 0x000000ff) << 8);
intValue += ((message[offset + 1] & 0x000000ff) << 16);
intValue += ((message[offset + 0] & 0x000000ff) << 24);
}
offset += 4;
return intValue;
}
int Message::setInt(int p_Value, std::vector<char> &message, int p_Offset) {
if ((p_Offset < 0) || (message.size() < p_Offset + 4))
throw "ParseError_send";
// low byte first
if (isSystemLittleEndian() == false) {
message[p_Offset + 0] = (char)(p_Value & 0x000000ff);
message[p_Offset + 1] = (char)((p_Value & 0x0000ff00) >> 8);
message[p_Offset + 2] = (char)((p_Value & 0x00ff0000) >> 16);
message[p_Offset + 3] = (char)((p_Value & 0xff000000) >> 24);
} else {
message[p_Offset + 3] = (char)(p_Value & 0x000000ff);
message[p_Offset + 2] = (char)((p_Value & 0x0000ff00) >> 8);
message[p_Offset + 1] = (char)((p_Value & 0x00ff0000) >> 16);
message[p_Offset + 0] = (char)((p_Value & 0xff000000) >> 24);
}
return 4;
}
optional<uint64_t> Message::getLong(const std::vector<char> &message, int &offset) {
if (offset < 0 || offset + 8 > message.size())
return std::nullopt;
// low byte first
uint64_t intValue = 0;
if (isSystemLittleEndian() == false) {
intValue += ((uint64_t)(message[offset] & 0x000000ff));
intValue += ((uint64_t)(message[offset + 1] & 0x000000ff) << 8);
intValue += ((uint64_t)(message[offset + 2] & 0x000000ff) << 16);
intValue += ((uint64_t)(message[offset + 3] & 0x000000ff) << 24);
intValue += ((uint64_t)(message[offset + 4] & 0x000000ff) << 32);
intValue += ((uint64_t)(message[offset + 5] & 0x000000ff) << 40);
intValue += ((uint64_t)(message[offset + 6] & 0x000000ff) << 48);
intValue += ((uint64_t)(message[offset + 7] & 0x000000ff) << 56);
} else {
intValue += ((uint64_t)(message[offset + 7] & 0x000000ff));
intValue += ((uint64_t)(message[offset + 6] & 0x000000ff) << 8);
intValue += ((uint64_t)(message[offset + 5] & 0x000000ff) << 16);
intValue += ((uint64_t)(message[offset + 4] & 0x000000ff) << 24);
intValue += ((uint64_t)(message[offset + 3] & 0x000000ff) << 32);
intValue += ((uint64_t)(message[offset + 2] & 0x000000ff) << 40);
intValue += ((uint64_t)(message[offset + 1] & 0x000000ff) << 48);
intValue += ((uint64_t)(message[offset + 0] & 0x000000ff) << 56);
}
offset += 8;
return intValue;
}
int Message::setLong(uint64_t p_Value, std::vector<char> &message, int p_Offset) {
if ((p_Offset < 0) || (message.size() < p_Offset + 8))
throw "ParseError_send";
// low byte first
if (isSystemLittleEndian() == false) {
message[p_Offset + 0] = (char)((p_Value & 0x00000000000000ff));
message[p_Offset + 1] = (char)((p_Value & 0x000000000000ff00) >> 8);
message[p_Offset + 2] = (char)((p_Value & 0x0000000000ff0000) >> 16);
message[p_Offset + 3] = (char)((p_Value & 0x00000000ff000000) >> 24);
message[p_Offset + 4] = (char)((p_Value & 0x000000ff00000000) >> 32);
message[p_Offset + 5] = (char)((p_Value & 0x0000ff0000000000) >> 40);
message[p_Offset + 6] = (char)((p_Value & 0x00ff000000000000) >> 48);
message[p_Offset + 7] = (char)((p_Value & 0xff00000000000000) >> 56);
} else {
message[p_Offset + 7] = (char)((p_Value & 0x00000000000000ff));
message[p_Offset + 6] = (char)((p_Value & 0x000000000000ff00) >> 8);
message[p_Offset + 5] = (char)((p_Value & 0x0000000000ff0000) >> 16);
message[p_Offset + 4] = (char)((p_Value & 0x00000000ff000000) >> 24);
message[p_Offset + 3] = (char)((p_Value & 0x000000ff00000000) >> 32);
message[p_Offset + 2] = (char)((p_Value & 0x0000ff0000000000) >> 40);
message[p_Offset + 1] = (char)((p_Value & 0x00ff000000000000) >> 48);
message[p_Offset + 0] = (char)((p_Value & 0xff00000000000000) >> 56);
}
return 8;
}
optional<bool> Message::getBoolean(const std::vector<char> &message, int &offset) {
if (offset < 0 || offset + 1 > message.size())
return std::nullopt;
return {message[offset++] > 0x00};
}
int Message::setBoolean(bool p_Value, std::vector<char> &message, int p_Offset) {
if ((p_Offset < 0) || (message.size() < p_Offset + 1))
throw "ParseError_send";
if (p_Value == false) {
message[p_Offset] = 0x00;
} else {
message[p_Offset] = 0x01;
}
return 1;
}
optional<char> Message::getByte(const std::vector<char> &message, int &offset) {
if (offset < 0 || offset + 1 > message.size())
return std::nullopt;
return {message[offset++]};
}
int Message::setByte(int p_Value, std::vector<char> &message, int p_Offset) {
if ((p_Offset < 0) || (message.size() < p_Offset + 1))
throw "ParseError_send";
message[p_Offset] = (char)(p_Value & 0xff);
return 1;
}
optional<string> Message::getString(const std::vector<char> &message, int &offset, int maxLength) {
if (offset < 0 || offset + maxLength > message.size())
return std::nullopt;
size_t len = strnlen(&message[offset], maxLength);
if (len >= maxLength)
return std::nullopt;
string str(&message[offset], len);
offset += maxLength;
return str;
}
int Message::setString(string p_String, std::vector<char> &message, int offset, int maxLength) {
if ((offset < 0) || (maxLength < 1) || (message.size() < offset + maxLength))
throw "ParseError_send";
int intLength;
if (p_String.length() + 1 > maxLength) {
intLength = maxLength;
} else {
intLength = p_String.length() + 1;
}
int intChar = 0;
bool boolNullChar = false;
while (intChar < intLength) {
message[offset + intChar] = p_String.data()[intChar];
if (p_String[intChar] == '\0') {
boolNullChar = true;
break;
}
intChar++;
}
if (boolNullChar == false) {
message[offset + intLength - 1] = '\0';
}
return maxLength;
}
}