Branching from Cathaswatch project

https://git.nerdyssey.de/exodus/1NiM-WatingRoom-WatchController
This commit is contained in:
2024-11-16 11:53:28 +01:00
parent 1a13428c9d
commit 8c49e2f11c
116 changed files with 14510 additions and 590 deletions
@@ -0,0 +1,155 @@
#pragma once
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
using namespace std;
namespace spit {
class SadDetectedServer;
class ISadClient {
public:
virtual void eventServerDetected(SadDetectedServer &server) = 0;
virtual void eventServerChanged(SadDetectedServer &server) = 0;
virtual void eventServerLost(SadDetectedServer &server) = 0;
};
class SadDetectedServer {
public:
SadDetectedServer(string name, string iD, string computerName,
string iP, string port, string clientIP,
string additions, string projName)
: mName(name),
mID(iD),
mComputerName(computerName),
mIP(iP),
mPort(port),
mClientIP(clientIP),
mAdditions(additions),
mServerProjectName(projName) {
}
private:
string mName{};
string mID{};
string mComputerName{};
string mIP{};
string mPort{};
string mClientIP{};
string mAdditions{};
string mServerProjectName{};
bool mNew{true};
bool mChanged{};
bool mFoundAgain{};
public:
string getID() const { return mID; }
string getName() const { return mName; }
string getComputerName() const { return mComputerName; }
string getIP() const { return mIP; }
string getPort() const { return mPort; }
string getClientIP() const { return mClientIP; }
string getAdditions() const { return mAdditions; }
string getProjectName() const { return mServerProjectName; }
bool getNew() const { return mNew; }
bool getChanged() const { return mChanged; }
bool getFoundAgain() const { return mFoundAgain; }
void setChanged() { mChanged = true; }
void setKnown() { mNew = false; }
void setFoundAgain() { mFoundAgain = true; }
void updateProjectName(string newProjectName) {
mServerProjectName = newProjectName;
if (mServerProjectName != newProjectName) {
mChanged = true;
}
}
// SAD_Client mThreadSend will send to Multicast addresses
void resetFlags() {
mChanged = false;
mFoundAgain = false;
mNew = false;
}
private:
static unordered_map<string, unique_ptr<SadDetectedServer>> sKnownServers;
public:
enum ParamIndex {
PARAM_PRECODE = 0,
PARAM_SPITTASKID = 1,
PARAM_NAME = 2,
PARAM_ID = 3,
PARAM_COMPUTERNAME = 4,
PARAM_PORT = 5,
PARAM_CLIENTIP = 6,
PARAM_ADDITIONS = 7,
PARAM_SERVERPROJECTNAME = 8,
PARAM_IP = 9,
};
/**
* Used by SAD_Client to add a found SPITServer - don't use this manually
* @param id the id of the server, every instance of a SPITServer has an own id
* @param p_ServerParams the server's parameter
*/
static void addDetectedServer(unique_ptr<SadDetectedServer> detected) {
if (auto i = sKnownServers.find(detected->getID()); i != sKnownServers.end()) {
auto &known = *(i->second.get());
known.setFoundAgain();
if (detected->getProjectName() != known.getProjectName()) {
known.updateProjectName(detected->getProjectName());
}
return;
}
sKnownServers[detected->getID()] = move(detected);
}
static void removeDetectedServer(SadDetectedServer &server) {
auto i = sKnownServers.find(server.getID());
if (i != sKnownServers.end()) {
sKnownServers.erase(i);
}
}
static void clearDetectedServers() {
sKnownServers.clear();
}
static void resetServerFlags() {
for (auto &srv : sKnownServers) {
srv.second->resetFlags();
}
}
/**
* Used by SAD_Client internally -don't use this manually
*/
static void evaluateDetectedServers(ISadClient &sadClient) {
for (auto &srv : sKnownServers) {
SadDetectedServer &known = *srv.second;
if (known.getNew()) {
known.setKnown();
sadClient.eventServerDetected(known);
} else if (known.getChanged()) {
sadClient.eventServerChanged(known);
} else if (known.getFoundAgain() == false) {
sadClient.eventServerLost(known);
removeDetectedServer(known);
}
}
}
/**
* Returns a reference of the DetectedServer with the id p_ServerID.<br>
* If no DetectedServer is found an eyception is thrown.
* @param id the id of the SPITServer
* @return the reference of the SadDetectedServer instance with getID() == p_ServerID
*/
static const SadDetectedServer &getRefDetectedServer(const string &id) {
return *sKnownServers.at(id);
}
};
}
+203
View File
@@ -0,0 +1,203 @@
#pragma once
#include "sad_DetectedServer.hpp"
#include "spit_message.hpp"
#include "spit_object.hpp"
#include "spit_player.hpp"
#include "spit_processor.hpp"
#include "spit_repo.hpp"
#include "spit_socket.hpp"
#include "spit_type.hpp"
#include <functional>
#include <memory>
#include <vector>
using namespace std;
namespace spit {
class SClient : ISadClient {
public:
using Callbacks = SProcessor::Callbacks;
using ProjUpdate = SProcessor::ProjUpdate;
using ServerEvent = SProcessor::ServerEvent;
using ObjectEvent = SProcessor::ObjectEvent;
using Connection = SProcessor::Connection;
using PlayerType = SPlayer::PTypes;
using ValueFlags = SPlayer::VFlags;
SClient(string name, string projName, ISocket &socket, Callbacks calls);
virtual ~SClient();
private:
Callbacks mCallbacks;
fos::TaskT<SClient &> *mThreadReceive{};
fos::TaskT<SClient &> *mThreadProcess{};
bool mStopReceiveMessages{};
Connection mConnectionStatus{Connection::None};
bool mDisconnectedByServer{}; // flag true = when server disconnects
SProcessor mProcessor;
string mClientProjectName;
uint8_t mMessageNumberSend{1};
int mMessageNumberReceived{-1}; // set to -1 because the first received message will set the number (1..255)
// Server's info filled by parseConnectAnswer
string mServerID{};
string mServerName{};
string mServerComputerName{};
int mServerStepTime{-1};
public:
/** The ID of the client.<br>Every client instance should set an unique id*/
string getID() { return mProcessor.getID(); }
/** The name of the client, should be set by the user app*/
string getName() { return mProcessor.getName(); }
/** The name of the client's host computer*/
string getComputerName() { return mProcessor.getComputerName(); }
void setClientProjectName(string clientProjectName) { mClientProjectName = clientProjectName; }
string getClientProjectName() { return mClientProjectName; }
// connected Server Infos
/** The ID of the connected SPITServer*/
string getServerID() { return mServerID; }
/** The host computername of the connected SPITServer*/
string getServerComputerName() { return mServerComputerName; }
/** The name of the connected SPITServer*/
string getServerName() { return mServerName; }
/** Expected Refreah Rate of the connectd SPITServer.<br>
* When the server plays objects, it will do so at discrete time steps.<br>
* Play events will take place in these time steps..
*/
int getServerStepTime() { return mServerStepTime; }
/** Should be called when the client wants to close his project*/
void clientProjectClose();
/**
* Should be called whenever the client has a project loaded
*/
void clientProjectLoaded();
void setActionType(string spitypeID, bool actionAssigned) {
mProcessor.setActionType(spitypeID, actionAssigned);
}
void setActionObject(string objectID, bool actionAssigned) {
mProcessor.setActionObject(objectID, actionAssigned);
}
//--------------- SPITMessage ---------------
private:
bool startReceiveSPITMessages();
void stopReceiveSPITMessages();
static void receiveSpitMessage(SClient &rM);
static void processSpitMessage(SClient &rM);
// Reconnect to the server when connection is lost see eventConnectionStatus and eventServerDetected
bool _doReconnect{}; // true = on eventServerDetected connect to the server identified by mServerID
public:
int sendMessage(Message::OPPart &spitMessageOPPart);
//--------------- ServerAutoDetection SAD ---------------
public:
/** Starts the autodetection of SPITServers in the local network. If a connection is tried, the autodetection should be stopped before.*/
void startServerAutoDetect();
/** Stops the autodetection of SPITServers in the local network*/
void stopServerAutoDetect();
/** Called every time a new SPITServer is detetced in the local network */
void eventServerDetected(SadDetectedServer &server);
/** Called every time a prior detected SPITServer is is no longer found.*/
void eventServerLost(SadDetectedServer &server);
void eventServerChanged(SadDetectedServer &server);
//--------------- Connection ---------------
public:
/**
* Tries a connection to the SPITServer
* @param p_ServerIP ip address of the SPITServer
* @param p_ServerPort port of the SPITServer
* @param p_ClientIP IP of the client
* @param p_ClientPort if "0" any free port will be used
* @param p_LoginName maybe some SPITServer need a login - liveSHOWsoftware will not.
* @param p_LoginPassword maybe some SPITServer need a login - liveSHOWsoftware will not
* @return true = the connection try is ok, SPITServer will answer with COnnectAnswer and an eventConnectionStatus will occur.<br>
* false = something is going wrong. (client could not bind)
*/
bool connect(string serverIP, string serverPort, string clientIP, string clientPort, string loginName = "", string loginPassword = "");
/**
* Terminates the connection to the SPITServer.
*/
void disconnect();
private:
void disconnectInternal(Connection cause);
void resetMessageNumberReceived();
void parseMessage(Message& message);
void checkParseMessage(unique_ptr<Message> message);
void addOvertakingMessage(unique_ptr<Message> message);
void parseConnectAnswer(Message::ConnectAnswer &message);
void parseDisconnect(Message::Disconnect &message);
void parseWatchdog(Message::Watchdog &message);
void parseWatchdogAnswer(Message::WatchdogAnswer &message);
public:
/** Used internally*/
void sendWatchdog();
/** Used internally. When the connection to the SPITServer is lost an eventConnectionStatus will occur*/
void eventWatchdogLost();
//--------------- SPIT Project ---------------
/** Returns the SPITServer's project ID - may be the same as the project's name*/
string getServerProjectID() { return mProcessor.getServerProjectID(); }
/** Returns the SPITServer's project name*/
string getServerProjectName() { return mProcessor.getServerProjectName(); }
/** Returns frame rate per second. This is the time resolution in which the server transmits time data. The unit of time data is always frames.*/
int getServerFramesPerSecond() { return mProcessor.getServerFramesPerSecond(); }
public:
static void sendProject(SClient *p_PtrSClient);
// --------------- SPIT Types ---------------
public:
/**
* Creates a fixed SPITType for application actions that are always present and project independent.<br>
* Fixed SPIT types cannot be changed or deleted by the server.<br>
* These SPITTypes will be automatically added to the SPITType-List and sended to the server.
* @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
* @param p_GroupName a name which groups the actions/SPITTypes
* @param p_Name the name of the Action/SPITType
* @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
* @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
* @return the pointer to the new SPITType.
*/
SType *createTypeFixed(string iD, string groupName, string name, uint64_t defaultDelay, uint64_t defaultDuration);
public:
bool changeType(SType *spitType) { return mProcessor.changeType(spitType); }
int removeType(string spitypeID) { return mProcessor.removeType(spitypeID); }
public:
public:
bool changeObject(SObject *sObject) { return mProcessor.changeObject(sObject); }
void sendRemoteObject(string objectID, int valuePpm = 0, char valueFlag = 0x00) {
mProcessor.sendRemoteObject(objectID, valuePpm, valueFlag);
}
private:
static void processSocketTask(SClient &instance);
fos::TaskT<SClient &> *sThread{};
bool mAbortSearch{};
bool sAnswered{};
static fos::Semaphore sStartSad;
ISocket &mSocket;
void answerWatchdog() {
sAnswered = true;
}
};
} // namespace spit
+720
View File
@@ -0,0 +1,720 @@
#pragma once
#include <cstdlib>
#include <memory>
#include <optional>
#include <string>
#include <vector>
using namespace std;
static const string SPITID = "#spit#";
namespace spit {
class Message {
//----------- Header -----------
public:
/** Maximal length of a SPITMessage*/
static const int MAX_MESSAGE_SIZE = 512;
class Header {
public:
static constexpr int BYTESLENGTH = 99;
Header(const Header &orig);
Header();
private:
string mID;
int mVersion{SPITVERSION};
unsigned char mMessageNumber{};
int mBytesCount{BYTESLENGTH};
string mServerId{};
string mClientId{};
int mOpFlag{-1};
int mParseOffset{};
public:
string getSPITID() const { return mID; }
int getSPITVersion() const { return mVersion; }
unsigned char getMessageNumber() const { return mMessageNumber; }
int getBytesCount() const { return mBytesCount; }
string getServerID() const { return mServerId; }
string getClientID() const { return mClientId; }
int getType() const { return mOpFlag; }
// Receive
bool parse(const std::vector<char> &message);
// Send
Header(int p_SPITVersion, int pOpFlag);
void setMessageNumber(unsigned char messageNumber) { mMessageNumber = messageNumber; }
void setServerID(string iD) { mServerId = iD; }
void setClientID(string iD) { mClientId = iD; }
void setOPFlag(int pOpFlag) { mOpFlag = pOpFlag; }
bool fillBytes(std::vector<char> &message);
};
//----------- OPPart -----------
public:
class OPPart {
// Members
protected:
unique_ptr<Header> mHeader{};
int mParseOffset{};
int mBytesCount;
public:
virtual ~OPPart();
Header *getHeader() const { return mHeader.get(); }
int getBytesCount() const { return mBytesCount; }
void setServerInfoInHeader(string clientId, string serverId) {
if (!mHeader) {
return;
}
mHeader->setClientID(clientId);
mHeader->setServerID(serverId);
}
void setMessageNumber(uint8_t no) {
if (!mHeader) {
return;
}
mHeader->setMessageNumber(no);
}
const string getServerID() const {
if (!mHeader) {
return "";
}
return mHeader->getServerID();
}
const string getClientID() const {
if (!mHeader) {
return "";
}
return mHeader->getClientID();
}
int getType() const {
if (!mHeader) {
return -1;
}
return mHeader->getType();
}
// Receive
OPPart(unique_ptr<Header> header, int pOpFlag, int size);
void setHeader(int opFlag);
virtual bool parse(const std::vector<char> &message) = 0;
// Send
OPPart(int size);
virtual bool fillBytes(std::vector<char> &message) = 0;
};
//----------- Message -----------
public:
static constexpr int SPITVERSION = 1;
// SPIT_Object value usage
static constexpr char VALUEUSE_DISCARD = 0x00; // value of SPITObejct is not used
static constexpr char VALUEUSE_INRANGE = 0x01; // value of SPITOBject in range 0 - 1000000ppm
static constexpr char VALUEUSE_OVERRIDE = 0x02; // value can be overridden
// SPIT Player type
static constexpr char PLAYERTYPE_MAIN = 0x02;
static constexpr char PLAYERTYPE_CONTINIOUS = 0x01;
static constexpr char PLAYERTYPE_DISCRETE = 0x00;
// PlayObject value usage
static constexpr char VALUEFLAG_DIRECT = 0x00; // use the vlue direct
static constexpr char VALUEFLAG_INCREASE = 0x01; // increase the value
static constexpr char VALUEFLAG_DECREASE = 0x02; // decrease the value
Message() = default;
// Members
private:
unique_ptr<OPPart> oPPart{};
// Receive
public:
Message(std::vector<char> message);
const Header *getHeader() const { return oPPart->getHeader(); }
int getType() const {
if (!oPPart || !oPPart->getHeader()) {
return -1;
}
return oPPart->getHeader()->getType();
}
const OPPart *getOPPart() const { return oPPart.get(); }
template<typename T>
T &getAs() const { return *reinterpret_cast<T *>(oPPart.get()); }
private:
bool parse(std::vector<char> message);
// Send
public:
static std::vector<char> createMessage(OPPart & p_OPPart);
//------------------------------ Connection ----------------------------------
//----------- Connect -----------
public:
class Connect : public OPPart {
public:
static constexpr int OPFLAG = 1;
static constexpr int BYTESLENGTH = 304;
private:
string mClientComputerName{};
string mClientName{};
string mLoginName{};
string mLoginPassword{};
string mServerIp{};
int mServerPort{};
public:
// Receive
Connect(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
string getClientComputerName() const { return mClientComputerName; }
string getClientName() const { return mClientName; }
string getLoginName() const { return mLoginName; }
string getLoginPassword() const { return mLoginPassword; }
string getServerIP() const { return mServerIp; }
int getServerPort() const { return mServerPort; }
// Send
Connect(string p_ComputerName, string p_ClientName);
void setLoginName(string p_LoginName) { mLoginName = p_LoginName; }
void setLoginPassword(string p_LoginPassword) { mLoginPassword = p_LoginPassword; }
void setServerIP(string p_ServerIP) { mServerIp = p_ServerIP; }
void setServerPort(int p_ServerPort);
bool fillBytes(std::vector<char> &message);
};
//----------- ConnectAnswer -----------
class ConnectAnswer : public OPPart {
public:
static constexpr int OPFLAG = 2;
static constexpr int BYTESLENGTH = 137;
private:
string mServerComputerName{};
string mServerName{};
bool mConnected{};
int mStepTime{40}; // ms step size the Server will send play sequences
public:
ConnectAnswer(const ConnectAnswer &orig);
// Receive
ConnectAnswer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getServerComputerName() const { return mServerComputerName; }
const string getServerName() const { return mServerName; }
bool getConnected() const { return mConnected; }
int getStepTime() const { return mStepTime; }
// Send
ConnectAnswer();
void setServerComputerName(string p_ServerComputerName) { mServerComputerName = p_ServerComputerName; }
void setServerName(string p_ServerName) { mServerName = p_ServerName; }
void setConnected(bool p_Connected) { mConnected = p_Connected; }
void setStepTime(int p_StepTime_ms);
bool fillBytes(std::vector<char> &message);
};
//----------- Disconnect -----------
class Disconnect : public OPPart {
public:
static constexpr int OPFLAG = 3;
static constexpr int BYTESLENGTH = 4;
Disconnect(const Disconnect &orig);
// Receive
Disconnect(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
Disconnect();
bool fillBytes(std::vector<char> &message);
};
//----------- Watchdog -----------
class Watchdog : public OPPart {
public:
static constexpr int OPFLAG = 8;
static constexpr int BYTESLENGTH = 4;
Watchdog(const Watchdog &orig);
// Receive
Watchdog(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
Watchdog();
bool fillBytes(std::vector<char> &message);
};
//----------- WatchdogAnswer -----------
class WatchdogAnswer : public OPPart {
public:
static constexpr int OPFLAG = 9;
static constexpr int BYTESLENGTH = 4;
// Receive
WatchdogAnswer(const WatchdogAnswer &orig);
WatchdogAnswer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
WatchdogAnswer();
bool fillBytes(std::vector<char> &message);
};
//------------------------------ SPITProject ----------------------------------
//----------- ReportProject -----------
class ReportProject : public OPPart {
public:
static constexpr int OPFLAG = 11;
static constexpr int BYTESLENGTH = 113;
private:
string mProjectID{};
string mProjectName{};
int mFramesPerSecond{1000}; // Frames per second
// Receive
public:
ReportProject(const ReportProject &orig);
ReportProject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getProjectID() const { return mProjectID; }
const string getProjectName() const { return mProjectName; }
int getFramesPerSecond() const { return mFramesPerSecond; }
// Send
ReportProject(string p_ProjectID, string p_ProjectName);
void setFramesPerSecond(const int p_FramesPerSecond) { mFramesPerSecond = p_FramesPerSecond; }
bool fillBytes(std::vector<char> &message);
};
//----------- CloseProject -----------
class CloseProject : public OPPart {
public:
static constexpr int OPFLAG = 13;
static constexpr int BYTESLENGTH = 45;
private:
string mProjectID{};
public:
CloseProject(const CloseProject &orig);
// Receive
CloseProject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getProjectID() const {
return mProjectID;
}
// Send
CloseProject(string projectID);
bool fillBytes(std::vector<char> &message);
};
//----------- StartProjectTransfer -----------
class RequestProjectTransfer : public OPPart {
public:
static constexpr int OPFLAG = 15;
static constexpr int BYTESLENGTH = 4;
RequestProjectTransfer(const RequestProjectTransfer &orig);
// Receive
RequestProjectTransfer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
RequestProjectTransfer();
bool fillBytes(std::vector<char> &message);
};
//----------- StartProjectTransfer -----------
class StartProjectTransfer : public OPPart {
public:
static constexpr int OPFLAG = 16;
static constexpr int BYTESLENGTH = 4;
StartProjectTransfer(const StartProjectTransfer &orig);
// Receive
StartProjectTransfer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
StartProjectTransfer();
bool fillBytes(std::vector<char> &message);
};
//----------- EndProjectTransfer -----------
class EndProjectTransfer : public OPPart {
public:
static constexpr int OPFLAG = 17;
static constexpr int BYTESLENGTH = 4;
EndProjectTransfer(const EndProjectTransfer &orig);
// Receive
EndProjectTransfer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
EndProjectTransfer();
bool fillBytes(std::vector<char> &message);
};
//---------------------------- SPIT_Types ----------------------------------
//----------- ReportType -----------
class ReportType : public OPPart {
public:
static constexpr int OPFLAG = 21;
static constexpr int BYTESLENGTH = 168;
private:
bool mConfirmed{};
string mTypeID{};
bool mFixed{};
bool mServerRemote{};
bool mServerProjectIndepended{};
string mTypeGroupName{};
string mSPITTypeName{};
uint64_t mDelay{};
uint64_t mDuration{};
public:
ReportType(const ReportType &orig);
// Receive
ReportType(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
bool getConfirmed() const { return mConfirmed; }
const string getID() const { return mTypeID; }
bool getFixed() const { return mFixed; }
bool getServerRemote() const { return mServerRemote; }
bool getServerProjectIndepended() const { return mServerProjectIndepended; }
const string getGroupName() const { return mTypeGroupName; }
const string getName() const { return mSPITTypeName; }
uint64_t getDelay() const { return mDelay; }
uint64_t getDuration() const { return mDuration; }
// Send
ReportType();
void setConfirmed(bool p_Confirmed) { mConfirmed = p_Confirmed; }
void setID(string iD) { mTypeID = iD; }
void setFixed(bool p_Fixed) { mFixed = p_Fixed; }
void setServerRemote(bool p_IsServerRemote) { mServerRemote = p_IsServerRemote; }
void setServerProjectIndepended(bool p_ProjectIndpended) { mServerProjectIndepended = p_ProjectIndpended; }
void setGroupName(string p_GroupName) { mTypeGroupName = p_GroupName; }
void setName(string p_Name) { mSPITTypeName = p_Name; }
void setDelay(uint64_t p_Delay) { mDelay = p_Delay; }
void setDuration(uint64_t p_Duration) { mDuration = p_Duration; }
bool fillBytes(std::vector<char> &message);
};
//----------- RemoveType -----------
class RemoveType : public OPPart {
public:
static constexpr int OPFLAG = 23;
static constexpr int BYTESLENGTH = 45;
private:
string mTypeID{};
public:
RemoveType(const RemoveType &orig);
// Receive
RemoveType(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getID() const { return mTypeID; }
// Send
RemoveType();
void setID(string iD) { mTypeID = iD; }
bool fillBytes(std::vector<char> &message);
};
//---------------------------- SPITObjects ----------------------------------
//----------- ReportObject -----------
class ReportObject : public OPPart {
public:
static constexpr int OPFLAG = 31;
static constexpr int BYTESLENGTH = 339;
private:
bool mConfirmed{};
string mSPITObjectID{};
bool mFixed{};
bool mServerRemote{};
string mSPITObjectName{};
string mTypeID{};
string mServerParams{};
uint64_t mFrameStart{};
uint64_t mFrameLength{};
uint64_t mFrameFadeInLength{};
uint64_t mFrameFadeOutLength{};
int mValueFactor{};
char mValueUse{VALUEUSE_DISCARD};
int mTrack{};
string mRemark{};
uint64_t mDelay{};
uint64_t mDuration{};
bool mActionAssigned{};
public:
ReportObject(const ReportObject &orig);
// Receive
ReportObject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
bool getConfirmed() const { return mConfirmed; }
const string getID() const { return mSPITObjectID; }
bool getFixed() const { return mFixed; }
bool getServerRemote() const { return mServerRemote; }
const string getName() const { return mSPITObjectName; }
const string getSPITTypeID() const { return mTypeID; }
const string getServerParams() const { return mServerParams; }
uint64_t getFrameStart() const { return mFrameStart; }
uint64_t getFrameLength() const { return mFrameLength; }
uint64_t getFrameFadeInLength() const { return mFrameFadeInLength; }
uint64_t getFrameFadeOutLength() const { return mFrameFadeOutLength; }
int getValueFactor() const { return mValueFactor; }
char getValueUse() const { return mValueUse; }
int getTrack() const { return mTrack; }
const string getRemark() const { return mRemark; }
uint64_t getDelay() const { return mDelay; }
uint64_t getDuration() const { return mDuration; }
bool getActionAssigned() const { return mActionAssigned; }
// Send
public:
ReportObject();
void setConfirmed(bool p_Confirmed) { mConfirmed = p_Confirmed; };
void setID(string iD) { mSPITObjectID = iD; };
void setFixed(bool p_Fixed) { mFixed = p_Fixed; };
void setServerRemote(bool p_IsRemote) { mServerRemote = p_IsRemote; };
void setName(string p_Name) { mSPITObjectName = p_Name; };
void setSPITTypeID(string iD) { mTypeID = iD; };
void setServerParams(string p_Parameters) { mServerParams = p_Parameters; };
void setFrameStart(uint64_t p_StartTime) { mFrameStart = p_StartTime; };
void setFrameLength(uint64_t p_Length) { mFrameLength = p_Length; };
void setFrameFadeInLength(uint64_t p_FadeInTime) { mFrameFadeInLength = p_FadeInTime; };
void setFrameFadeOutLength(uint64_t p_FadeOutTime) { mFrameFadeOutLength = p_FadeOutTime; };
void setValueFactor(int p_Volume) { mValueFactor = p_Volume; };
void setValueUse(char p_ValueUse) { mValueUse = p_ValueUse; };
void setTrack(int p_Track) { mTrack = p_Track; };
void setRemark(string p_Description) { mRemark = p_Description; };
void setDelay(uint64_t p_Delay);
void setDuration(uint64_t p_Duration);
void setActionAssigned(bool p_ActionAssigned) { mActionAssigned = p_ActionAssigned; }
bool fillBytes(std::vector<char> &message);
};
//----------- RemoveObject -----------
class RemoveObject : public OPPart {
public:
static constexpr int OPFLAG = 33;
static constexpr int BYTESLENGTH = 45;
private:
string mSPITObjectID{};
public:
RemoveObject(const RemoveObject &orig);
// Receive
RemoveObject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getID() const { return mSPITObjectID; }
// Send
public:
RemoveObject();
void setID(string iD) { mSPITObjectID = iD; }
bool fillBytes(std::vector<char> &message);
};
//---------------------------- SPITPlayer ----------------------------------
//----------- PlayStart -----------
class PlayStart : public OPPart {
public:
static constexpr int OPFLAG = 37;
static constexpr int BYTESLENGTH = 119;
private:
string mPlayerID{};
string mPlayerName{};
char mPlayerType{};
bool mPlayerIsRunning{};
uint64_t mTime; // Frames
public:
PlayStart(const PlayStart &orig);
// Receive
PlayStart(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getPlayerID() const { return mPlayerID; }
const string getPlayerName() const { return mPlayerName; }
char getPlayerType() const { return mPlayerType; }
bool getPlayerIsRunning() const { return mPlayerIsRunning; }
uint64_t getTime() const { return mTime; }
// Send
PlayStart(string p_PlayerID, string p_PlayerName, char p_PlayerType);
void setPlayerIsRunning(bool p_IsPlaying) { mPlayerIsRunning = p_IsPlaying; }
void setTime(uint64_t p_Time) { mTime = p_Time; }
bool fillBytes(std::vector<char> &message);
};
//----------- PlayObject -----------
class PlayObject : public OPPart {
public:
static constexpr int OPFLAG = 38;
static constexpr int BYTESLENGTH = 100;
private:
string mPlayerID{};
string mSPITObjectID{};
uint64_t mFrameInsideObject{}; // Frames
bool mPlayPrePosition{};
int mValue{};
char mValueFlag{VALUEFLAG_DIRECT};
public:
PlayObject(const PlayObject &orig);
// Receive
PlayObject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getPlayerID() const { return mPlayerID; }
const string getSPITObjectID() const { return mSPITObjectID; }
uint64_t getFrameInsideObject() const { return mFrameInsideObject; }
bool getPlayPrePosition() const { return mPlayPrePosition; }
int getValue() const { return mValue; }
char getValueFlag() const { return mValueFlag; }
// Send
PlayObject();
void setPlayerID(string p_PlayerID) { mPlayerID = p_PlayerID; }
void setID(string iD) { mSPITObjectID = iD; }
void setFrameInsideObject(uint64_t p_TimeInside) { mFrameInsideObject = p_TimeInside; }
void setPlayPrePosition(bool p_PlayOldPosition) { mPlayPrePosition = p_PlayOldPosition; }
void setValue(int p_Value) { mValue = p_Value; }
void setValueFlag(char p_ValueFlag) { mValueFlag = p_ValueFlag; }
bool fillBytes(std::vector<char> &message);
};
//----------- PlayEnd -----------
class PlayEnd : public OPPart {
public:
static constexpr int OPFLAG = 39;
static constexpr int BYTESLENGTH = 45;
private:
string mPlayerID{};
public:
PlayEnd(const PlayEnd &orig);
// Receive
PlayEnd(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getPlayerID() const { return mPlayerID; }
// Send
PlayEnd(string p_PlayerID);
bool fillBytes(std::vector<char> &message);
};
//----------- ReportPlayStatus -----------
class ReportPlayStatus : public OPPart {
public:
static constexpr int OPFLAG = 40;
static constexpr int BYTESLENGTH = 57;
private:
string mSPITObjectID{};
uint64_t mFrameInsideObject{};
int mValue{};
public:
ReportPlayStatus(const ReportPlayStatus &orig);
// Receive
ReportPlayStatus(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getID() const { return mSPITObjectID; }
uint64_t getFrameInsideObject() const { return mFrameInsideObject; }
int getValue() const { return mValue; }
// Send
ReportPlayStatus();
void setID(string iD);
void setFrameInsideObject(uint64_t p_TimeInside);
void setValue(int p_Value);
bool fillBytes(std::vector<char> &message);
};
//----------------------- static helper functions ----------------------------
public:
static bool isSystemLittleEndian();
static optional<int> getInt(const std::vector<char> &message, int &offset);
static optional<uint64_t> getLong(const std::vector<char> &message, int &offset);
static optional<bool> getBoolean(const std::vector<char> &message, int &offset);
static optional<char> getByte(const std::vector<char> &message, int &offset);
static int setInt(int value, std::vector<char> &message, int offset);
static int setLong(uint64_t value, std::vector<char> &message, int offset);
static int setBoolean(bool value, std::vector<char> &message, int offset);
static int setByte(int value, std::vector<char> &message, int offset);
/**
* Returns the string char* of the part of the byte sequence (0x00 null terminated).
* @param p_Bytes the byte array
* @param offset the startposition of strings bytes
* @param p_Length the length of the string included the null terminate byte (0x00).
* The length of the string will be p_Length -1.
*/
static optional<string> getString(const std::vector<char> &message, int &offset, int maxLength);
/**
* Fill the p_String in the byte array.
* If p_String length is greater than p_Length -1, the p_String will be truncated.
* CAUTION the return value should be freed after use.
* @param p_String the string
* @param p_Length the maximal length of the string included the null character.
* @throws Exception if p_String == nullptr, p_Bytes == nullptr
* p_Offset less than 0
* p_ByteCount less than p_Offset + p_Length
* @return p_Length
*/
static int setString(string p_String, std::vector<char> &message, int p_Offset, int p_Length);
};
}
+122
View File
@@ -0,0 +1,122 @@
#pragma once
#include "spit_type.hpp"
#include "spit_message.hpp"
#include "spit_repo.hpp"
using namespace std;
namespace spit {
class SObjectListener;
class SObject {
public:
template <typename T>
struct Property {
friend SObject;
Property(bool &confirmed)
: rConfirmed(confirmed) {
}
bool set(const T& val) {
if (mValue == val)
return false;
mValue = val;
rConfirmed = false;
return true;
}
T get () const {
return mValue;
}
private:
bool & rConfirmed;
T mValue{};
};
Property<string> Name{mConfirmed};
Property<string> Remark{mConfirmed};
Property<string> ServerParams{mConfirmed};
Property<string> SPITTypeID{mConfirmed};
// Returns if the SPITType triggers an action on the Server or on the client.
// @return false = the action is triggered on the client The client waits for the server to play objects of this SPITType
// true = the action is triggered on the server. The server waits for the client to play objects of this SPITType.
Property<bool> ServerRemote{mConfirmed};
Property<bool> Fixed{mConfirmed};
Property<uint64_t> FrameStart{mConfirmed};
Property<uint64_t> FrameLength{mConfirmed};
Property<uint64_t> FrameFadeInLength{mConfirmed};
Property<uint64_t> FrameFadeOutLength{mConfirmed};
Property<char> ValueUse{mConfirmed};
Property<int> ValueFactor{mConfirmed};
Property<int> Track{mConfirmed};
Property<uint64_t> Delay{mConfirmed};
Property<uint64_t> Duration{mConfirmed};
static void clearUnconfirmedObjects(SpitRepo<SObject> &repo);
static void setConfirmedFalse(SpitRepo<SObject> &repo);
static void eventProjectClosed(SpitRepo<SObject> &repo, SpitRepo<SObject> &remoteRepo);
SObject(string iD) {
mID = iD;
}
private:
string mID;
bool mConfirmed{};
bool mCreatedByClient{};
bool mActionAssigned{};
bool mActionAssignedType{}; // Virtual construct
char mValueUse{0x01};
int mValueFactor{1000000}; // Values are given in ppm -> 1000000 = 1/1;
bool mPlayPrePosition;
uint64_t mPlayTimeInsideFrames;
int mPlayValue;
char mPlayValueFlag;
public:
string getID() const { return mID; }
/**
* This is used by the server and client to tell if the other side has registered the changes.
* @return true = other side has registered the changes.
*/
bool getConfirmed() const { return mConfirmed; }
bool getCreatedByClient() const { return mCreatedByClient; }
/**
* This is a virtual construct - ActionAssignedType is not implemented in the SPITProtocol.
* This is used when an action is associated with a SPITType.
* Then this action is done for every SObject with the SPITType.
* @return true = an action is assigned for the SPITType.
*/
bool getActionAssignedType() const { return mActionAssignedType; }
/** Returns if this SObject has an associated action or not.
* @return true = the user has asscociated an action with this SObject or
* the user has asscociated an action with the SPITType of this SObject
*/
bool getActionAssigned() const { return mActionAssigned || mActionAssignedType; }
bool getProjectIndepended(SpitRepo<SType> &repo, SpitRepo<SType> &remoteRepo) const {
SType *ptrSPITType;
if (ServerRemote.get() == false) {
ptrSPITType = repo.getEntry(SPITTypeID.get());
if (ptrSPITType == nullptr)
return true;
return ptrSPITType->ProjectIndepended.get();
} else {
ptrSPITType = remoteRepo.getEntry(SPITTypeID.get());
if (ptrSPITType == nullptr)
return true;
return ptrSPITType->ProjectIndepended.get();
}
};
bool setConfirmed(bool confirmed);
void setCreatedByClient(bool createdByClient) { mCreatedByClient = createdByClient; }
bool setActionAssignedType(bool actionAssigned);
bool setActionAssigned(bool actionAssigned);
bool setMessageOP(Message::ReportObject *message);
void fillMessageOP(Message::ReportObject &message);
void fillMessageOP(Message::RemoveObject &message);
};
}
+98
View File
@@ -0,0 +1,98 @@
#pragma once
#include "spit_object.hpp"
#include <unordered_map>
namespace spit {
class SPlayer {
//----- PlayObject used in PlaySequences: PlaySPITStart, PlaySPITObject,..., PlaySPITEnd ------
public:
enum PTypes {
// diescrete player: This player is used to transmit single discrete values.
PTYPE_DISCRETE = 0x00,
// continous player: This player plays SPIT objects sometime during the project.
PTYPE_CONTINOUS = 0x01,
// continous main player: time value can be used like a timecode.<br>The time value is the position in server's project.<br>A server should use only one main player.
PTYPE_MAIN = 0x02,
};
enum VFlags {
// Set the given value directly
VFLAG_DIRECT = 0x00,
// Increase the existing value by the given value.<br>This is usefull e.g. when instead of a fader a endless wheel is used*/
VFLAG_INCREASE = 0x01,
// Decrease the existing value by the given value.<br>This is usefull e.g. when instead of a fader a endless wheel is used*/
VFLAG_DECREASE = 0x02,
};
class PlayType {
public:
PlayType(SPlayer *spitPlayer, string spitObjectID);
PlayType(const PlayType &orig);
string getSPITTypeID() const { return mSpitTypeID; }
void startPlaySequence();
bool getIsNew() const { return mIsNew; }
void setIsNew(bool isNew) { mIsNew = isNew; }
bool getIsPlayed() const { return mIsPlayed; }
void setIsPlayed(bool p_IsFound) { mIsPlayed = p_IsFound; }
string getPlayerID() const { return mPlayerID; }
string getPlayerName() const { return mPlayerName; }
bool getPlayerIsRunning() const { return mPlayerRuns; }
void setPlayerIsRunning(bool playerRuns) { mPlayerRuns = playerRuns; }
void setValue(double value) { mValue = value; }
void addValue(double value, double valueFactor) { mValue += (value * valueFactor); }
double getValue() const { return mValue; }
private:
string mPlayerID;
string mPlayerName;
bool mPlayerRuns;
string mSpitTypeID;
bool mIsPlayed;
bool mIsNew;
double mValue;
};
//----- SPlayer ------
public:
// list the SPITPlayers
static unordered_map<string, unique_ptr<SPlayer>> sSpitPlayers; // all actual played objects
static SPlayer &getSPITPlayer(string pPlayerID); // if a player does not exist creates a new one
static void clearPlayers() { sSpitPlayers.clear(); }
SPlayer(string pPlayerID);
virtual ~SPlayer();
void startPlaySequence(); // called by SPIT_Client::parsePlaySPITStart
PlayType *addTypePlaying(string spitTypeID); // called by SPIT_Client::parsePlaySPITStart
void endPlaySequence(); // called by SPIT_Client::parsePlaySPITEnd
string getID() {
return mId;
}
unordered_map<string, unique_ptr<PlayType>> &getPlaySPITTypes() { return mPlaySPITTypes; }
void setIsRunning(bool isRunning) { mIsRunning = isRunning; }
void setName(string name) { mName = name; }
void setType(char type) { mType = type; }
void setTime(uint64_t frames) { mTimeFrames = frames; }
bool getIsRunning() const { return mIsRunning; }
string getName() const { return mName; }
char getType() const { return mType; }
uint64_t getTime() const { return mTimeFrames; }
private:
string mId;
string mName;
char mType;
unordered_map<string, unique_ptr<PlayType>> mPlaySPITTypes;
bool mIsRunning;
uint64_t mTimeFrames;
};
} // namespace spit
+169
View File
@@ -0,0 +1,169 @@
#pragma once
#include "sad_DetectedServer.hpp"
#include "spit_message.hpp"
#include "spit_object.hpp"
#include "spit_player.hpp"
#include "spit_repo.hpp"
#include "spit_type.hpp"
#include <functional>
#include <memory>
#include <vector>
using namespace std;
namespace spit {
class SProcessor {
public:
enum class ProjUpdate {
ServerLoaded,
StartTransfer,
EndTransfer,
ServerClosed,
};
enum class ServerEvent {
Detect,
Lost,
Changed,
};
enum class ObjectEvent {
Created,
Changed,
Deleted
};
enum class Connection {
None = 0, // No Connection established.<br>Either no connect tried or disconnected
NoneServer = 1, // Server has disconnected
Lost = 2, // The connection is lost<br>Either because of a network crash or because the server no longer responds.
Ok = 3, // Connection to the serv er is established.
TryConnection = 4, // A connection to the server is tried.
};
struct Callbacks {
function<void(ServerEvent event, const SadDetectedServer &detectedServer)> onServerEvent;
function<void(string serverID, string serverComputerName, string serverName, int serverStepTime, Connection connectionStatus, Connection oldConnectionStatus)> onConnectionStatus;
function<void(ProjUpdate state, string projectId)> onProjectUpdate;
function<void(ObjectEvent event, bool isRemote, const SType &sType)> onSpitType;
function<void(ObjectEvent event, bool isRemote, const SType &sType, const SObject &sObject)> onSpitObject;
function<void(string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames)> onPlay;
function<void(string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value)> onPlaySpitType;
function<void(const SType &sType, const SObject &sObject, uint64_t p_FrameInsideObject, int value)> onPlayRemoteObjectStatus;
function<bool(bool knownType, bool createdByClient)> onCheckSpitTypeVeto;
function<bool(bool knownType)> onCheckSpitObjectVeto;
};
struct InternalCallbacks {
function<void(int ms)> delay;
function<int(Message::OPPart &msg)> sendMessage;
function<void(Message &msg)> parseMessage;
};
static constexpr int MAX_OVERTAKING_SPIT_MESSAGES = 10;
//----- SProcessor -----
public:
SProcessor(string name, string projName, string hostName, string guid,
Callbacks calls, InternalCallbacks intern);
virtual ~SProcessor();
private:
Callbacks mCallbacks;
InternalCallbacks mInternCallbacks;
string mName;
string mGuid;
string mProjName;
string mComputerName;
uint8_t mMessageNumberSend{1};
int mMessageNumberReceived{-1}; // set to -1 because the first received message will set the number (1..255)
vector<unique_ptr<Message>> mOvertakingMessages;
string mServerID{};
string mServerProjectID;
string mServerProjectName;
int mServerFramesPerSecond;
public:
string getID() { return mGuid; }
string getName() { return mName; }
string getProjName() { return mProjName; }
string getComputerName() { return mComputerName; }
void setActionType(string spitypeID, bool actionAssigned);
void setActionObject(string objectID, bool actionAssigned);
void checkParseMessageData(vector<char> data);
unique_ptr<Message::Connect> createConnectMessage(string serverIP, string serverPort, string loginName, string loginPassword);
std::vector<char> createMessage(Message::OPPart &spitMessageOPPart);
void parseMessage(Message &message);
void addOvertakingMessage(unique_ptr<Message> message);
int sendOvertakingMessage(int msgNumRec);
void resetMessageNumberReceived();
string getServerProjectID() { return mServerProjectID; }
string getServerProjectName() { return mServerProjectName; }
int getServerFramesPerSecond() { return mServerFramesPerSecond; }
// /**
// * Creates a SPITType for application actions.<br>
// * These SPITTypes will be automatically added to the SPITType-List and sended to the server.
// * @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
// * @param p_GroupName a name which groups the actions/SPITTypes
// * @param p_Name the name of the Action/SPITType
// * @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
// * @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
// * @param p_Fixed true = the server is not allowed to change this SPITType, false = the server may change or delete this SPITType
// * @param p_ProjectIndepended true = the SPITType belongs to a specific project, false = the SpitType always exists for every project
// * @return the pointer to the new SPITType.
// */
SType *createType(string iD, string groupName, string name, uint64_t defaultDelay, uint64_t defaultDuration, bool fixed, bool projectIndepended);
int sendTypeInternal(SType &sType);
/**
* If a client wants to change a SPITType, he should send it to the server.<br>
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the change.<br>
* @param spitypeID the id of the SPITType to remove.
* @return 0 = is sended, -1 = is not sended
*/
bool changeType(SType *spitType);
/**
* If a client wants to remove a SPITType, he should send it to the server.<br>
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the deletion.<br>
* @param spitypeID the id of the SPITType to remove.
* @return 0 = is sended, -1 = is not sended
*/
int removeType(string spitypeID);
int removeObject(string objectID);
bool changeObject(SObject *sObject);
void sendRemoteObject(string objectID, int valuePpm = 0, char valueFlag = 0x00);
void resetConfirmedFlags() {
SType::setConfirmedFalse(mSpitTypes);
SObject::setConfirmedFalse(mSpitObjects);
}
private:
void parseReportProject(Message::ReportProject &message);
void parseCloseProject(Message::CloseProject &message);
void parseRequestProjectTransfer(Message::RequestProjectTransfer &message);
void parseStartProjectTransfer(Message::StartProjectTransfer &message);
void parseEndProjectTransfer(Message::EndProjectTransfer &message);
void parseReportType(Message::ReportType &message);
void parseRemoveType(Message::RemoveType &message);
void parseReportObject(Message::ReportObject &message);
void parseRemoveObject(Message::RemoveObject &message);
void parsePlayStart(Message::PlayStart &message);
void parsePlayObject(Message::PlayObject &message);
void parsePlayEnd(Message::PlayEnd &message);
void parseReportPlayStatus(Message::ReportPlayStatus &message);
int sendObjectInternal(SObject *sObject);
SpitRepo<SObject> mSpitObjects;
SpitRepo<SType> mSpitTypes;
SpitRepo<SObject> mRemoteSpitObjects;
SpitRepo<SType> mRemoteSpitTypes;
};
} // namespace spit
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
using namespace std;
namespace spit {
template <typename T>
class SpitRepo {
public:
bool hasEntry(const string &id) {
return mEntries.contains(id);
}
T *getEntry(const string &id) {
auto i = mEntries.find(id);
if (i == mEntries.end()) {
return nullptr;
}
return i->second.get();
}
const T &getEntryRef(const string &id) {
return *mEntries.at(id);
}
void addEntry(unique_ptr<T> entry) {
mEntries[entry->getID()] = move(entry);
}
bool removeEntry(const T &entry) {
return removeEntry(entry.getID());
}
bool removeEntry(const string &id) {
auto i = mEntries.find(id);
if (i == mEntries.end()) {
return false;
}
mEntries.erase(i);
return true;
}
int getSize() {
return mEntries.size();
}
unordered_map<string, unique_ptr<T>> &getRepo() {
return mEntries;
}
void clearEntries() {
mEntries.clear();
}
private:
unordered_map<string, unique_ptr<T>> mEntries;
};
}
+149
View File
@@ -0,0 +1,149 @@
#pragma once
#include "Task.hpp"
#include "esp_log.h"
#include "esp_netif.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
using namespace std;
namespace spit {
/** Returns an guid */
string createGUID();
/** Returns the name of the client's host computer*/
string getClientHostName();
class ISocket {
public:
/**
* IpAddress class is used to fetch all available IP addresses of the computer
* This is for internal usage
*/
struct IpAddress {
public:
IpAddress(const string &iPAddress, const string &subnetMask)
: mIpAddress(iPAddress), mSubnetMask(subnetMask) {}
const string mIpAddress;
const string mSubnetMask;
/**
* Calculates the broadcast address from a ip4 address
* @param iPAddress the ip4 address
* @return returns the broadcast address
*/
string getBroadcastIP4() const {
struct in_addr broadcast;
unsigned long ipAddress;
unsigned long subnetMask;
ipAddress = inet_addr(mIpAddress.data());
subnetMask = inet_addr(mSubnetMask.data());
broadcast.s_addr = ipAddress | ~subnetMask;
return inet_ntoa(broadcast);
}
};
const IpAddress mOwnIp;
ISocket(IpAddress ip)
: mOwnIp(ip) {}
virtual int sendMessage(const char *message, int length) = 0;
virtual int receiveMessage(char *bu1ffer, int bufferLength, string *serverIp) const =0;
virtual void setConnectionParams(const string &serverIp, const string &serverPort, const string &clientIp, const string &clientPort) =0;
virtual int bindSocket(string clientIp, string clientPort) =0;
virtual int setBroadcast(bool broadcast) const =0;
virtual int sendMessageTo(const string &ip, const string &port, const char *message, int msgLength) =0;
bool getIsBound() const { return mIsBound; }
protected:
bool mIsBound{};
};
class Socket : public ISocket {
public:
static const int FAMILY_IP4 = AF_INET;
static IpAddress getAdaptersInfo();
bool createSocketUdp();
static const int INVALID_SOCKET = -1;
private:
int mUdpSocketIp4;
public:
//-------- class --------------
Socket(IpAddress ip) : ISocket(ip) {
mUdpSocketIp4 = INVALID_SOCKET;
createSocketUdp();
}
virtual ~Socket() {
ESP_LOGD("UDP", "Shutting down ...");
if (mUdpSocketIp4 != INVALID_SOCKET) {
shutdown(mUdpSocketIp4, 2);
close(mUdpSocketIp4);
mUdpSocketIp4 = INVALID_SOCKET;
}
fos::Task::delayMs(100);
mIsBound = false;
}
private:
string mServerIP{};
string mServerPort{};
string mClientIp{};
string mClientPort{}; // port given by the user maybe "0"
string mBoundClientPort{}; // port set after bind
public:
// Sets the ip address and port for server and client.
void setConnectionParams(const string &serverIp, const string &serverPort, const string &clientIp, const string &clientPort) override {
mServerIP = serverIp;
mServerPort = serverPort;
mClientIp = clientIp;
mClientPort = clientPort;
}
/**
* Send a message to the server as set by setConnectionParams
* @param message byte buffer containing the message
* @param length length of the message
* @return
*/
int sendMessage(const char *message, int length) override {
if (mServerPort.length() <= 0) {
return -1;
}
if (mIsBound == false) {
return -1;
}
int intResult = sendMessageTo(mServerIP, mServerPort, message, length);
return intResult;
}
int receiveMessage(char *bu1ffer, int bufferLength, string *serverIp) const override;
int setBroadcast(bool broadcast) const override;
int bindSocket(string clientIp, string clientPort) override;
int sendMessageTo(const string &ip, const string &port, const char *message, int msgLength) override;
string getServerIP() const { return mServerIP; }
string getServerPort() const { return mServerPort; }
string getClientIP() const { return mClientIp; }
string getClientPort() const { return mClientPort; }
string getBoundClientPort() const { return mBoundClientPort; }
void setBoundClientPort(const string &port) { mBoundClientPort = port; }
void setIsBound(bool isBound) { mIsBound = isBound; }
private:
};
}
+189
View File
@@ -0,0 +1,189 @@
#pragma once
#include "spit_message.hpp"
#include "spit_repo.hpp"
using namespace std;
namespace spit {
class STypeListener;
class SType {
public:
template <typename T>
struct Property {
friend SType;
Property(bool &confirmed)
: rConfirmed(confirmed) {
}
bool set(const T& val) {
if (mValue == val)
return false;
mValue = val;
rConfirmed = false;
return true;
}
T get () const {
return mValue;
}
private:
bool & rConfirmed;
T mValue{};
};
Property<string> GroupName{mConfirmed};
Property<string> Name{mConfirmed};
Property<bool> Fixed{mConfirmed};
Property<bool> ProjectIndepended{mConfirmed};
// Returns if the SType triggers an action on the Server or on the client.
// @return false = the action is triggered on the client The client waits for the server to play objects of this SType
// true = the action is triggered on the server. The server waits for the client to play objects of this SType.
Property<bool> ServerRemote{mConfirmed};
Property<uint64_t> DefaultDelay{mConfirmed};
Property<uint64_t> DefaultDuration{mConfirmed};
// Virtual construct - means ActionAssigned for STypes is is not implemented in SPITProtocol.
// This can used to setActionAssigned to all SPITObjects with this SType.
// This may be used in the case when the same action should be done for every SPITObject with this SType associated.
// @return true = the user has associated an action with this SType.
Property<bool> ActionAssigned{mConfirmed};
// Sets confirmed = false for all STypes.
// This should be called when the client has loaded a project.
static void setConfirmedFalse(SpitRepo<SType> &repo) {
auto &entries = repo.getRepo();
for (auto i = entries.begin(); i != entries.end(); i++) {
i->second->setConfirmed(false);
}
}
static void eventProjectClosed(SpitRepo<SType> &repo, SpitRepo<SType> &remoteRepo) {
auto &entries = repo.getRepo();
for (auto i = entries.begin(); i != entries.end();) {
SType *ptrSType = i->second.get();
if (ptrSType->getCreatedByClient() == true) {
i++;
continue;
}
i = entries.erase(i);
}
// Remote
remoteRepo.clearEntries();
}
SType(string iD) {
mID = iD;
}
SType(string iD, string grpName, string name, bool fixed, bool projectIndependent, uint64_t delay, uint64_t duration) {
mConfirmed = false;
mID = iD;
ActionAssigned.set(false);
GroupName.set(grpName);
Name.set(name);
Fixed.set(fixed);
ProjectIndepended.set(projectIndependent);
DefaultDelay.set(delay);
DefaultDuration.set(duration);
}
private:
bool mConfirmed{};
string mID;
bool mCreatedByClient{}; // flag true = the SPITTyype is created by the client
// false = the SType is received from the server
public:
string getID() const { return mID; }
// This is used by the server and client to tell if the other side has registered the changes.
// @return true = other side has registered the changes.
bool getConfirmed() const { return mConfirmed; }
bool getCreatedByClient() const { return mCreatedByClient; }
void setCreatedByClient(bool createdByClient) { mCreatedByClient = createdByClient; }
// Set the content of the SType as received from the server
// @param p_ReportSType
// @return true = the SType is changed
// false = the SType is NOT changed, because it is not allowed to change.
bool setMessageOP(Message::ReportType &message) {
bool changeAllowed;
if ((mCreatedByClient == true) && (Fixed.get() == true)) {
changeAllowed = false;
} else {
changeAllowed = true;
}
// Confirmation should be changeable
if (mCreatedByClient) {
// Server reports a client created SType -> the type is confirmed
mConfirmed = true;
} else {
// type is NOT client created -> the client has to confirm the SPITtype
mConfirmed = message.getConfirmed();
}
if (changeAllowed == false) {
return false;
}
bool changed = false;
if (DefaultDelay.mValue != message.getDelay()) {
DefaultDelay.mValue = message.getDelay();
changed = true;
}
if (DefaultDuration.mValue != message.getDuration()) {
DefaultDuration.mValue = message.getDuration();
changed = true;
}
if (Fixed.mValue != message.getFixed()) {
Fixed.mValue = message.getFixed();
changed = true;
}
if (GroupName.mValue != message.getGroupName()) {
GroupName.mValue = message.getGroupName();
changed = true;
}
if (mID != message.getID()) {
mID = message.getID();
changed = true;
}
if (Name.mValue != message.getName()) {
Name.mValue = message.getName();
changed = true;
}
if (ProjectIndepended.mValue != message.getServerProjectIndepended()) {
ProjectIndepended.mValue = message.getServerProjectIndepended();
changed = true;
}
if (ServerRemote.mValue != message.getServerRemote()) {
ServerRemote.mValue = message.getServerRemote();
changed = true;
}
return changed;
}
void fillMessageOP(Message::ReportType &message) const {
message.setConfirmed(mConfirmed);
message.setDelay(DefaultDelay.mValue);
message.setDuration(DefaultDuration.mValue);
message.setFixed(Fixed.mValue);
message.setGroupName(GroupName.mValue);
message.setID(mID);
message.setName(Name.mValue);
message.setServerProjectIndepended(ProjectIndepended.mValue);
message.setServerRemote(ServerRemote.mValue);
}
void fillMessageOP(Message::RemoveType &message) const {
message.setID(mID);
}
// This is used by the server and client to tell if the other side has registered the changes.
// @param confirmed
// @return if mConfirmed has changed
bool setConfirmed(bool confirmed) {
if (mConfirmed == confirmed)
return false;
mConfirmed = confirmed;
return true;
}
};
}