Files
1NiM-WatingRoom-WatchContro…/components/spit/src/spit_processor.cpp
T

1235 lines
48 KiB
C++

#include "spit_processor.hpp"
#include "esp_log.h"
namespace spit {
static const char *TAG = "SPIT";
/**
* Create a new SPIT_client instance, should be done once by the user app.
* @param p_SPITClientInterface the user app should implement the SPIT_ClientInterface.
*/
SProcessor::SProcessor(string name, string projName, string hostName, string guid, Callbacks calls) // @todo
: mCallbacks(calls),
mGuid(guid),
mName(name),
mProjName(projName),
mComputerName(hostName) {
}
SProcessor::~SProcessor() { // @todo
stopServerAutoDetect();
disconnectInternal(Connection::None);
}
void SProcessor::clientProjectClose() { // @todo
if (mConnectionStatus == Connection::Ok) {
ESP_LOGI(TAG, " ... tidy up ressources");
Message::CloseProject closeSPITProject(mProjName);
// if (sendSPITMessage(closeSPITProject) < 0) {
// ESP_LOGD(TAG, "Client could not send Client's ReportProject");
// }
}
}
void SProcessor::clientProjectLoaded() { // @todo
// set confirmed = false for all SPITTypes and SPITObjects
SType::setConfirmedFalse(mSpitTypes);
SObject::setConfirmedFalse(mSpitObjects);
if (mConnectionStatus == Connection::Ok) {
// send ReportProject to the server
Message::ReportProject reportSPITProject(mProjName, mProjName);
reportSPITProject.setFramesPerSecond(0);
// if (sendSPITMessage(reportSPITProject) < 0) {
// ESP_LOGD(TAG, "SPIT_CLient::clientProjectLoaded could not send Client's ReportProject");
// }
// send RequestProjectTransfer
Message::RequestProjectTransfer sMRequestProjectTransfer;
// if (sendSPITMessage(sMRequestProjectTransfer) < 0) {
// ESP_LOGD(TAG, "SPIT_CLient::clientProjectLoaded could not send RequestProjectTransfer");
// }
}
}
/**
* Virtual construct - means actionAssigned for SPITTypes is is not implemented in SPITProtocol.
* This can used to setActionAssigned to all SPITObjects with this SPITType.
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.
* This tells the server not what action is done, but it tells the server that there is an action.
* @param typeId the id of the SPITType
* @param actionAssigned
*/
void SProcessor::setActionSPITType(string typeId, bool actionAssigned) { // @todo
SType *spitType = mSpitTypes.getEntry(typeId);
if (spitType == nullptr)
return;
if (spitType->ActionAssigned.set(actionAssigned)) {
sendSPITTypeInternal(*spitType);
for (auto& [key, value] : mSpitObjects.getRepo()) {
if (value->SPITTypeID.get() == spitType->getID()) {
if (value->setActionAssignedType(actionAssigned) == true) {
sendSPITObjectInternal(value.get());
}
}
}
}
}
/** This should be called if the user wants to associate/remove an action with a SPITObject. */
void SProcessor::setActionSPITObject(string spitObjId, bool actionAssigned) { // @todo
SObject *spitObject = mSpitObjects.getEntry(spitObjId);
if (spitObject == nullptr)
return;
if (spitObject->setActionAssigned(actionAssigned) == true) {
sendSPITObjectInternal(spitObject);
}
}
//---------- ServerAutoDetection SAD -----------
/** Starts the autodetection of SPITServers in the local network. If a connection is tried, the autodetection should be stopped before.
* If a SPITServer is detected in the locale network an eventServerDetected occurs.
*/
void SProcessor::startServerAutoDetect() { // @todo
// if (mDisconnectedByServer == true) {
// // Server has previously disconnected -> do not start ServerAutodetect directly
// fos::Task::delayMs(1000); // sleep a little to give the SPITServer time to clean up its stuff
// }
// SadDetectedServer::clearDetectedServers();
// if (!sThread) {
// sThread = new fos::TaskT<SClient &>(SProcessor::processSocketTask, *this, "spitSock", fos::Task::DefaultStackSize * 2); // @todo
// }
// mAbortSearch = false;
// sStartSad.give();
}
/** Stops the auto detection of SPIT servers. */
void SProcessor::stopServerAutoDetect() { // @todo
mAbortSearch = true;
}
/**
* If a new server was found by the ServerAutoDetect mechanism, this function is called.
* To do so the SAD_Client ServerAutoDetect has to be startet - see SAD_Client::startServerAutoDetect.
* If a server can be reached via several IP addresses, the IP address is selected according to the following preference:
*/
void SProcessor::eventServerDetected(SadDetectedServer &server) { // @todo
mCallbacks.onServerEvent(ServerEvent::Detect, server);
// If a connection has been established and the connection is lost -> reconnect
if (_doReconnect) {
if (mServerID == server.getID()) {
stopServerAutoDetect();
ESP_LOGI(TAG, "reconnect to %s / %s", server.getIP().data(), server.getPort().data());
if (connect(server.getIP(), server.getPort(), server.getClientIP(), "0")) {
return;
}
}
}
// Stop auto detection because a suitable server was found
stopServerAutoDetect();
ESP_LOGI(TAG, "connect to %s / %s", server.getIP().data(), server.getPort().data());
if (!connect(server.getIP(), server.getPort(), server.getClientIP(), "0" /*= any port*/)) {
// connection message could not be sent -> better to restart AutoDetection
startServerAutoDetect();
}
}
/**
* If a SPITServer is not more found, this function is called.
* To do so the SAD_Client ServerAutoDetect has to be startet - see SAD_Client::startServerAutoDetect.
*/
void SProcessor::eventServerLost(SadDetectedServer &server) { // @todo
mCallbacks.onServerEvent(ServerEvent::Lost, server);
}
void SProcessor::eventServerChanged(SadDetectedServer &server) { // @todo
mCallbacks.onServerEvent(ServerEvent::Changed, server);
// tryConnection(detectedServer);
}
// void MyApp::tryConnection(const SadDetectedServer &detected) {
// // fetch the infoemations from the detected
// bool boolSuccess = false;
// bool boolPossibleConnect = checkPossibleConnection(detected);
// if (boolPossibleConnect == false)
// return;
// // --------------------------------------
// // You have three Options to use the detected server
// // OPTION 1 Use the first server found
// // OPTION 2 Use the first server found that fulfills specific conditions
// // OPTION 3 take a copy of the detected and do connection later
// // SadDetectedServer o_DetectedServer = detected; //this will call the copy constructor
// // ---------------------------------------
// // Excample use the first detected LOOPBACK server, means the server runs on the same computer as this client
// // if (detected.getIpIsLoopback() == true) { //omit the if condition if you want to use the first server found
// boolSuccess = false;
// // Stop auto detection because a suitable server was found
// stopServerAutoDetect();
// if (mSPIT_Client != nullptr) {
// mServerProjectName = detected.getProjectName();
// mServerIP = detected.getIP();
// #if defined(DEBUGOUTPUT)
// ESP_LOGD(TAG, "MySPITApp: connect to %s ", detected.getIP().data());
// #endif
// // Use the mBoardNumber as login name
// string stringLoginName = "";
// string stringLoginPassword = "";
// boolSuccess = mSPIT_Client->connect(detected.getIP(), detected.getPort(), detected.getClientIP(), stringLoginName, stringLoginPassword); // ClientPort = "0" meeans use any port
// }
// if (boolSuccess == false) {
// // connection message could not be sent
// // perhaps restart AutoDetection
// startServerAutoDetect();
// } else {
// // WAITING FOR CONNECTION ANSWER
// // If the Server is closed in the meantime no answer will return
// //-> connect(..) has started the watchdog
// }
// // } //Excample
// }
std::vector<char> SProcessor::createMessage(Message::OPPart &opPart) {
if (mMessageNumberSend == 255)
mMessageNumberSend = 1;
else
mMessageNumberSend++;
opPart.setMessageNumber(mMessageNumberSend);
opPart.setServerInfoInHeader(mGuid, mServerID);
int opFlag = opPart.getHeader()->getType();
try {
return Message::createMessage(opPart);
} catch (...) {
ESP_LOGD(TAG, "Exception client OPFlag: %d", opFlag);
}
return {};
}
// todo Delete SProcessor::sendSPITMessage(Message::OPPart &opPart
// void SProcessor::receiveSPITMessage(SClient &rM) { // @todo
// char buffer[MAXSPITMESSAGEBYTECOUNT + 1];
// int rdLen;
// while (rM.mStopReceiveMessages == false) {
// rdLen = rM.mSocket.receiveMessage(buffer, MAXSPITMESSAGEBYTECOUNT, nullptr);
// if (rdLen < 0) {
// if (rM.mStopReceiveMessages) {
// return;
// }
// continue;
// }
// auto vec = vector<char>(buffer, buffer + rdLen);
// rM.checkParseMessageData(move(spitMsg));
// // rM.checkParseMessage(move(spitMsg));
// }
// }
void SProcessor::resetMessageNumberReceived() { // @todo
mMessageNumberReceived = -1;
mOvertakingMessages.clear();
}
void SProcessor::checkParseMessageData(vector<char> data) {
auto message = make_unique<Message>(data);
answerWatchdog();
if (!message->getHeader() || !message->getOPPart()) {
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
return;
}
int msgNum = (int)(message->getHeader()->getMessageNumber() & 0xFF);
if (msgNum == 0) {
parseMessage(*message);
return;
}
if (mMessageNumberReceived < 0) {
mMessageNumberReceived = msgNum;
parseMessage(*message);
return;
}
int msgNumNext = mMessageNumberReceived + 1;
if (msgNumNext > 255 || msgNumNext < 1)
msgNumNext = 1;
if (msgNum == msgNumNext) {
mMessageNumberReceived = msgNum;
parseMessage(*message);
// check overtaking messages
auto it = mOvertakingMessages.begin();
while (mOvertakingMessages.size() > 0) {
msgNumNext = mMessageNumberReceived + 1;
if (msgNumNext > 255 || msgNumNext < 1)
msgNumNext = 1;
auto &overtakingMessage = *it;
msgNum = (int)(overtakingMessage->getHeader()->getMessageNumber() & 0xFF);
if (msgNum == msgNumNext) {
mMessageNumberReceived = msgNum;
parseMessage(*overtakingMessage);
mOvertakingMessages.erase(it);
it = mOvertakingMessages.begin();
} else {
break;
}
}
} else {
// p_SPITMessage has overtaken another message
addOvertakingMessage(move(message));
}
}
void SProcessor::addOvertakingMessage(unique_ptr<Message> message) { // @todo
if (!message) {
return;
}
if (mOvertakingMessages.size() > MAX_OVERTAKING_SPIT_MESSAGES) {
ESP_LOGD(TAG, "Client receiveing: perhaps message lost !!!!!");
}
int intMessageNumber = (int)(message->getHeader()->getMessageNumber() & 0xFF);
for (auto it = mOvertakingMessages.begin(); it != mOvertakingMessages.end(); ++it) {
const auto &overtaking = *it;
int intOvertakingMessageNumber = (int)(overtaking->getHeader()->getMessageNumber() & 0xFF);
if (intMessageNumber < intOvertakingMessageNumber) {
mOvertakingMessages.insert(it, move(message));
return;
}
}
mOvertakingMessages.push_back(move(message));
}
void SProcessor::parseMessage(Message& message) { // @todo
answerWatchdog();
if (!message.getHeader() || !message.getOPPart()) {
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
return;
}
switch (message.getType()) {
//----- Connection -----
case Message::ConnectAnswer::OPFLAG:
parseConnectAnswer(message.getAs<Message::ConnectAnswer>());
break;
case Message::Disconnect::OPFLAG:
parseDisconnect(message.getAs<Message::Disconnect>());
break;
case Message::ReportProject::OPFLAG:
parseReportProject(message.getAs<Message::ReportProject>());
break;
case Message::Watchdog::OPFLAG:
parseWatchdog(message.getAs<Message::Watchdog>());
break;
case Message::WatchdogAnswer::OPFLAG:
parseWatchdogAnswer(message.getAs<Message::WatchdogAnswer>());
break;
//----- SPIT Project -----
case Message::StartProjectTransfer::OPFLAG:
parseStartProjectTransfer(message.getAs<Message::StartProjectTransfer>());
break;
case Message::CloseProject::OPFLAG:
parseCloseProject(message.getAs<Message::CloseProject>());
break;
case Message::RequestProjectTransfer::OPFLAG:
parseRequestProjectTransfer(message.getAs<Message::RequestProjectTransfer>());
break;
case Message::EndProjectTransfer::OPFLAG:
parseEndProjectTransfer(message.getAs<Message::EndProjectTransfer>());
break;
//----- SPIT Types ------
case Message::ReportType::OPFLAG:
parseReportType(message.getAs<Message::ReportType>());
break;
case Message::RemoveType::OPFLAG:
parseRemoveSPITType(message.getAs<Message::RemoveType>());
//----- SPIT Objects ------
break;
case Message::ReportObject::OPFLAG:
parseReportSPITObject(message.getAs<Message::ReportObject>());
break;
case Message::RemoveObject::OPFLAG:
parseRemoveSPITObject(message.getAs<Message::RemoveObject>());
break;
//----- Play SPIT Objects ------
case Message::PlayStart::OPFLAG:
parsePlaySPITStart(message.getAs<Message::PlayStart>());
break;
case Message::PlayObject::OPFLAG:
parsePlaySPITObject(message.getAs<Message::PlayObject>());
break;
case Message::PlayEnd::OPFLAG:
parsePlaySPITEnd(message.getAs<Message::PlayEnd>());
break;
case Message::ReportPlayStatus::OPFLAG:
parseReportPlayStatus(message.getAs<Message::ReportPlayStatus>());
break;
default:
ESP_LOGD(TAG, "Client::parseMessage: Unknown Message");
}
}
//----- Connection ------
/**
* Tries to connect to a SPITServer.
* @param serverIP the ip address of the SPIT server
* @param serverPort the port number of the SPIT server
* @param clientIP the local IP address of the client
* @param clientPort the port number of the Client, if "0" the OS uses any possible port number
* @param loginName login user name (liveSHOW does not use this -> mayby ""
* @param loginPassword login user password (liveSHOW does not use this -> mayby ""
* @return false = an error has occured, true = the connect was sent to the server
*/
bool SProcessor::connect(string serverIP, string serverPort, string clientIP, string clientPort, string loginName, string loginPassword) { // @todo
disconnect();
// mSocket.setConnectionParams(serverIP, serverPort, clientIP, clientPort);
// if (mSocket.bindSocket(clientIP, clientPort) < 0) {
// mStopReceiveMessages = true;
// return false;
// }
Message::Connect sMConnect(mComputerName, mName);
sMConnect.setLoginName(loginName);
sMConnect.setLoginPassword(loginPassword);
sMConnect.setServerIP(serverIP);
if (serverPort.length() <= 0) {
serverPort = "0";
}
int intServerPort = stoi(serverPort);
sMConnect.setServerPort(intServerPort);
// if (startReceiveSPITMessages() == false) {
// mStopReceiveMessages = true;
// return false;
// }
resetMessageNumberReceived();
Connection intOldConnectionStatus = mConnectionStatus;
mConnectionStatus = Connection::TryConnection;
mCallbacks.onConnectionStatus(mServerID, mServerComputerName, mServerName, mServerStepTime,
mConnectionStatus, intOldConnectionStatus);
// sleep a little to make sure that the reception of the messages is started
// fos::Task::delayMs(500);
// if (sendSPITMessage(sMConnect) < 0) {
// mConnectionStatus = Connection::None;
// mStopReceiveMessages = true;
// return false;
// }
return true;
}
/**
* Terminates the connection to the SPITServer.
*/
void SProcessor::disconnect() { // @todo
disconnectInternal(Connection::None);
}
void SProcessor::disconnectInternal(Connection cause) { // @todo
Connection intOldConnectionStatus = mConnectionStatus;
mConnectionStatus = cause;
switch (mConnectionStatus) {
case Connection::Lost:
break;
case Connection::None: {
Message::Disconnect sMDisconnect;
// sendSPITMessage(sMDisconnect);
} break;
case Connection::NoneServer:
break;
default:
break;
}
// stopReceiveSPITMessages();
mCallbacks.onConnectionStatus(mServerID, mServerComputerName, mServerName, mServerStepTime,
mConnectionStatus, intOldConnectionStatus);
if (intOldConnectionStatus != Connection::None && intOldConnectionStatus != Connection::NoneServer) {
ESP_LOGI(TAG, "eventConnectionStatus %d ", (int)mConnectionStatus);
switch (mConnectionStatus) {
case SProcessor::Connection::None: // @todo
ESP_LOGD(TAG, "not connected");
break;
case SProcessor::Connection::NoneServer: // @todo
ESP_LOGD(TAG, "connection terminated by server");
// call eventProjectClosed because this may not be sended by the server,
// when the connection is closed
mCallbacks.onProjectUpdate(ProjUpdate::ServerClosed, mServerProjectID);
// Server has terminated the connection -> start a new game
// _doReconnect = false;
startServerAutoDetect();
break;
case SProcessor::Connection::Lost: // @todo
ESP_LOGD(TAG, "connection lost");
// Maybe you want to reconnect, see eventServerDetected(...)
// We have lost the connection -> set the flag to true and start the autodetection to reconnect at eventServerDetected(...)
// _doReconnect = true;
startServerAutoDetect();
break;
default:
break;
}
}
}
void SProcessor::parseConnectAnswer(Message::ConnectAnswer &message) { // @todo
if (message.getClientID() != mGuid)
return;
mServerID = message.getServerID();
mServerComputerName = message.getServerComputerName();
mServerName = message.getServerName();
mServerStepTime = message.getStepTime();
if (message.getConnected() == false) {
disconnectInternal(Connection::NoneServer);
} else {
message.getStepTime();
mConnectionStatus = Connection::Ok;
mDisconnectedByServer = false;
ESP_LOGD(TAG, "connection established");
stopServerAutoDetect(); // normally you should stop the autodetection before you try a connection
// This is redundand
// mStopReceiveMessages = false;
// Maybe you want to reconnect, see eventServerDetected(...)
// Here the connection is established -> don't reconnect at eventServerDetected(...)
// _doReconnect = false;
}
}
/**
* The SPIT server was closed
* @param message
*/
void SProcessor::parseDisconnect(Message::Disconnect &message) { // @todo
Connection intCauseDisconnect = Connection::NoneServer;
/*
function<void()> o_Callable = bind(&SProcessor::disconnectInternal, this, intCauseDisconnect); // @todo
SPIT_Handler::addCallable(o_Callable);
*/
mDisconnectedByServer = true;
SProcessor::disconnectInternal(intCauseDisconnect); // @todo
}
//----- Watchdog ------
/**
* The SPIT server sends a watchdog message at regular intervals. The client responds immediately with WatchdogAnswer
* Conversely, the client also sends a watchdog message at regular intervals and waits for a WatchdogAnswer message.
* This is used to check if the other side is still present.
* @param message
*/
void SProcessor::parseWatchdog(Message::Watchdog &message) { // @todo
// ESP_LOGD(TAG, "parse Watchdog ");
Message::WatchdogAnswer o_WatchdogAnswer;
// sendSPITMessage(o_WatchdogAnswer);
}
/**
* The SPIT server sends a watchdog message at regular intervals. The client responds immediately with WatchdogAnswer
* Conversely, the client also sends a watchdog message at regular intervals and waits for a WatchdogAnswer message.
* This is used to check if the other side is still present.
* @param message
*/
void SProcessor::parseWatchdogAnswer(Message::WatchdogAnswer &message) { // @todo
answerWatchdog(); // is also done by parseMessage
}
void SProcessor::sendWatchdog() { // @todo
int intResult{};
Message::Watchdog message;
// intResult = sendSPITMessage(message);
if (intResult < 0) {
ESP_LOGW("WDT", "Failed to send Watchdog msg");
}
}
void SProcessor::eventWatchdogLost() { // @todo
if (mConnectionStatus == Connection::TryConnection) {
disconnectInternal(Connection::NoneServer);
} else {
disconnectInternal(Connection::Lost);
}
}
//----- SPIT Project ------
void SProcessor::parseReportProject(Message::ReportProject &message) { // @todo
ESP_LOGD(TAG, "parse ReportProject");
mServerProjectID = message.getProjectID();
mServerProjectName = message.getProjectName();
mServerFramesPerSecond = message.getFramesPerSecond();
mCallbacks.onProjectUpdate(ProjUpdate::ServerLoaded, mServerProjectID);
// Set all SPITTypes and SPITObjects confirmed = false
SType::setConfirmedFalse(mSpitTypes);
SObject::setConfirmedFalse(mSpitObjects);
// Send RequestProjectTransfer
Message::RequestProjectTransfer sMRequestProjectTransfer;
// if (sendSPITMessage(sMRequestProjectTransfer) < 0) {
// ESP_LOGD(TAG, "Client::parseReportProject could not send RequestProjectTransfer");
// }
// todo Don't send the ReportProject here it should be sended after parseEndProjectTransfer
// Send client's ReportProject
Message::ReportProject reportProject(mProjName, mProjName);
reportProject.setFramesPerSecond(0);
// if (sendSPITMessage(reportProject) < 0) {
// ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
// }
}
void SProcessor::parseCloseProject(Message::CloseProject &p_CloseSPITProject) { // @todo
ESP_LOGD(TAG, "parse CloseProject");
string stringProjectID;
mCallbacks.onProjectUpdate(ProjUpdate::ServerClosed, p_CloseSPITProject.getProjectID());
SPlayer::clearPlayers();
}
string SProcessor::getServerProjectID() { return mServerProjectID; } // @todo
string SProcessor::getServerProjectName() { return mServerProjectName; } // @todo
int SProcessor::getServerFramesPerSecond() { return mServerFramesPerSecond; } // @todo
void SProcessor::parseRequestProjectTransfer(Message::RequestProjectTransfer &message) { // @todo
ESP_LOGD(TAG, "parse RequestProjectTransfer");
// StartProjectTransfer
Message::StartProjectTransfer sMStartProjectTransfer;
// if (sendSPITMessage(sMStartProjectTransfer) < 0) {
// return;
// }
// send all listes SPITTypes
for (const auto& [key, value] : mSpitTypes.getRepo()) {
sendSPITTypeInternal(*value);
// fos::Task::delayMs(10);
}
for (auto& [key, value] : mSpitObjects.getRepo()) {
sendSPITObjectInternal(value.get());
// fos::Task::delayMs(10);
}
// EndProjectTransfer
Message::EndProjectTransfer sMEndProjectTransfer;
// sendSPITMessage(sMEndProjectTransfer);
}
/* NEW IMPLEMENTATION
void SProcessor::parseRequestProjectTransfer(Message::RequestProjectTransfer* message) { // @todo
// ESP_LOGD(TAG, "parse RequestProjectTransfer");
thread* o_ThreadSend;
o_ThreadSend = new thread(&this->sendProject, this);
// int intResult;
// Message::StartProjectTransfer* ptrSMStartProjectTransfer;
// Message::EndProjectTransfer* ptrSMEndProjectTransfer;
// int intCount;
// SPITType* ptrSPITType;
// SObject* ptrSPITObject;
// //StartProjectTransfer
// NotifyStartProjectTransfer_Client* o_RunnableStart = new NotifyStartProjectTransfer_Client(mSPITClientInterface);
// SPIT_Handler::addRunnable(o_RunnableStart);
// ptrSMStartProjectTransfer = new Message::StartProjectTransfer();
// intResult = sendSPITMessage(ptrSMStartProjectTransfer);
// if (intResult < 0) {
// return;
// }
// mWatchdog->answerWatchdog();
// {
// //send all listes SPITTypes
// unique_lock<recursive_mutex> o_LockType(*SPITType::getMutex());
// intCount = SPITType::getSPITTypeCount();
// for (int i = 0; i < intCount; i++) {
// ptrSPITType = mSpitTypes.getEntry(i);
// if (ptrSPITType == nullptr) continue;
// intResult = sendSPITTypeInternal(ptrSPITType);
// if (intResult < 0) return;
// mWatchdog->answerWatchdog();
// this_thread::sleep_for(chrono::milliseconds(7));
// }
// }
// {
// unique_lock<recursive_mutex> o_LockObject(*SObject::getMutex());
// intCount = mSpitObjects.getEntryCount();
// for (int i = 0; i < intCount; i++) {
// ptrSPITObject = mSpitObjects.getEntry(i);
// if (ptrSPITObject == nullptr) continue;
// intResult = sendSPITObjectInternal(ptrSPITObject);
// if (intResult < 0) return;
// mWatchdog->answerWatchdog();
// this_thread::sleep_for(chrono::milliseconds(7));
// }
// }
// //EndProjectTransfer
// ptrSMEndProjectTransfer = new Message::EndProjectTransfer();
// intResult = sendSPITMessage(ptrSMEndProjectTransfer);
// if (intResult < 0) {
// return;
// }
// mWatchdog->answerWatchdog();
// NotifyEndProjectTransfer_Client* o_RunnableEnd = new NotifyEndProjectTransfer_Client(mSPITClientInterface);
// SPIT_Handler::addRunnable(o_RunnableEnd);
// //Send act
}
*/
// void SProcessor::sendProject(SClient *p_PtrSPIT_Client) { // @todo
// int intResult;
// Message::StartProjectTransfer* ptrSMStartProjectTransfer;
// Message::EndProjectTransfer* ptrSMEndProjectTransfer;
// int intCount;
// SPITType* ptrSPITType;
// SObject* ptrSPITObject;
// //StartProjectTransfer
// NotifyStartProjectTransfer_Client* o_RunnableStart = new NotifyStartProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface());
// SPIT_Handler::addRunnable(o_RunnableStart);
// ptrSMStartProjectTransfer = new Message::StartProjectTransfer();
// intResult = p_PtrSPIT_Client->sendSPITMessage(ptrSMStartProjectTransfer);
// if (intResult < 0) {
// return;
// }
// // mWatchdog->answerWatchdog();
// // {
// //send all listes SPITTypes
// // unique_lock<recursive_mutex> o_LockType(*SPITType::getMutex());
// intCount = SPITType::getSPITTypeCount();
// for (int i = 0; i < intCount; i++) {
// ptrSPITType = mSpitTypes.getEntry(i);
// if (ptrSPITType == nullptr) continue;
// if (ptrSPITType->getCreatedByClient() == false) continue;
// intResult = p_PtrSPIT_Client->sendSPITTypeInternal(ptrSPITType);
// if (intResult < 0) return;
// // mWatchdog->answerWatchdog();
// this_thread::sleep_for(chrono::milliseconds(7));
// }
// // }
// // {
// // unique_lock<recursive_mutex> o_LockObject(*SObject::getMutex());
// intCount = mSpitObjects.getEntryCount();
// for (int i = 0; i < intCount; i++) {
// ptrSPITObject = mSpitObjects.getEntry(i);
// if (ptrSPITObject == nullptr) continue;
// if (ptrSPITObject->getCreatedByClient() == false) continue;
// intResult = p_PtrSPIT_Client->sendSPITObjectInternal(ptrSPITObject);
// if (intResult < 0) return;
// // mWatchdog->answerWatchdog();
// this_thread::sleep_for(chrono::milliseconds(7));
// }
// // }
// //EndProjectTransfer
// ptrSMEndProjectTransfer = new Message::EndProjectTransfer();
// intResult = p_PtrSPIT_Client->sendSPITMessage(ptrSMEndProjectTransfer);
// if (intResult < 0) {
// return;
// }
// // mWatchdog->answerWatchdog();
// NotifyEndProjectTransfer_Client* o_RunnableEnd = new NotifyEndProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface());
// SPIT_Handler::addRunnable(o_RunnableEnd);
// //Send act
// }
void SProcessor::parseStartProjectTransfer(Message::StartProjectTransfer &message) { // @todo
mCallbacks.onProjectUpdate(ProjUpdate::StartTransfer, mServerProjectID);
}
void SProcessor::parseEndProjectTransfer(Message::EndProjectTransfer &message) { // @todo
SObject::clearUnconfirmedObjects(mSpitObjects);
mCallbacks.onProjectUpdate(ProjUpdate::EndTransfer, mServerProjectID);
// Send Message::ReportProject after the mSPITClientInterface is notfied of EndProjectTransfer
Message::ReportProject reportSPITProject(mProjName, mProjName);
reportSPITProject.setFramesPerSecond(0);
// if (sendSPITMessage(reportSPITProject) < 0) {
// ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
// }
}
//----- SPIT Types ------
void SProcessor::parseReportType(Message::ReportType &message) { // @todo
ESP_LOGD(TAG, "parse ReportType ID %s Name %s",message.getID().c_str(), message.getName().c_str());
SType *sType;
bool boolNew = false;
bool boolChanged = false;
{
if (message.getServerRemote() == false) {
sType = mSpitTypes.getEntry(message.getID());
if (sType == nullptr) {
// The user's app may veto the SPITType
bool createdByClient = false;
if (sType) {
createdByClient = sType->getCreatedByClient();
}
if (mCallbacks.onCheckSpitTypeVeto(false, createdByClient) == false) {
ESP_LOGW(TAG, "TypeVeto %s / %s", message.getID().c_str(), message.getName().c_str());
return;
}
auto spitType = make_unique<SType>(message.getID());
sType = spitType.get();
mSpitTypes.addEntry(move(spitType));
boolNew = true;
}
} else {
sType = mRemoteSpitTypes.getEntry(message.getID());
if (sType == nullptr) {
auto spitType = make_unique<SType>(message.getID());
sType = spitType.get();
mRemoteSpitTypes.addEntry(move(spitType));
boolNew = true;
}
}
if (!sType->setMessageOP(message)) {
// SPITType is not changable -> send back to the server
sendSPITTypeInternal(*sType);
return;
}
auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed;
// add or change SPITType
mCallbacks.onSpitType(eventType, sType->ServerRemote.get(), *sType);
if (sType != nullptr) {
if (sType->setConfirmed(true) == true || boolChanged == true) {
sendSPITTypeInternal(*sType);
}
}
}
}
void SProcessor::parseRemoveSPITType(Message::RemoveType &message) { // @todo
ESP_LOGD(TAG, "parse RemoveType %s", message.getID().c_str());
bool boolRemote = false;
string stringSPITTypeID = message.getID();
SType *ptrSPITType = mRemoteSpitTypes.getEntry(stringSPITTypeID);
if (!ptrSPITType) {
boolRemote = true;
} else {
ptrSPITType = mSpitTypes.getEntry(stringSPITTypeID);
if (!ptrSPITType) {
boolRemote = false;
} else {
// No SPITType with stringSPITTypeID is listet
return;
}
}
if (ptrSPITType->getCreatedByClient() && ptrSPITType->Fixed.get()) {
// the SPITyte is created by client himself and it is fixed -> don't remove the SPITType!!
// Send the SPITTyp back to the server
sendSPITTypeInternal(*ptrSPITType);
return;
}
mCallbacks.onSpitType(ObjectEvent::Deleted, boolRemote, *ptrSPITType);
if (boolRemote == false) {
mSpitTypes.removeEntry(*ptrSPITType);
} else {
mRemoteSpitTypes.removeEntry(*ptrSPITType);
}
}
/**
* If a client has changed a SPITType, it should send it to the server to transmit the changes.
* If the SPITType is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the changes.
* @param p_SPITType the pointer to the changed SPITType
* @return 0 = is sended, -1 = is not sended
*/
int SProcessor::sendSPITTypeInternal(SType &p_SPITType) { // @todo
Message::ReportType sMReportSPITType;
p_SPITType.fillMessageOP(sMReportSPITType);
// return sendSPITMessage(sMReportSPITType);
return 1;
}
/**
* Change an existing SPIT_Type.
* @param p_SPITType the SPITType vont
* @return true = changed, false = not changed maybe p_SPITType is NULL or the SPITType doesn't exists
*/
bool SProcessor::changeSPITType(SType *p_SPITType) { // @todo
if (p_SPITType == nullptr)
return false;
SType *ptrSPITType = mSpitTypes.getEntry(p_SPITType->getID());
if (ptrSPITType == nullptr)
return false;
ptrSPITType->DefaultDelay.set(p_SPITType->DefaultDelay.get());
ptrSPITType->DefaultDuration.set(p_SPITType->DefaultDuration.get());
ptrSPITType->Fixed.set(p_SPITType->Fixed.get());
ptrSPITType->GroupName.set(p_SPITType->GroupName.get());
ptrSPITType->Name.set(p_SPITType->Name.get());
ptrSPITType->ProjectIndepended.set(p_SPITType->ProjectIndepended.get());
mCallbacks.onSpitType(ObjectEvent::Changed, false, *ptrSPITType);
sendSPITTypeInternal(*ptrSPITType);
return true;
}
/**
* If a client has removed a SPITType where id == p_SPITTypeID, it should send it to the server.
* The corresponding SPITType if listet in SPITType will be deleted.
* An eventRemoveSPITType will occur.
* If a connection to a SPITServer is established, the SPITServer may dicard the deletion an an eventSPITType will occur
* -> the SPITType will be listet again.
* @param p_SPITType the id of the SPITType ro remove
* @return 0 = is sended, -1 = is not sended
*/
int SProcessor::removeSPITType(string p_SPITTypeID) { // @todo
if (p_SPITTypeID.length() <= 0)
return -1;
SType *ptrSPITType;
{
ptrSPITType = mSpitTypes.getEntry(p_SPITTypeID);
if (ptrSPITType == nullptr)
return -1;
Message::RemoveType sMRemoveSPITType;
ptrSPITType->fillMessageOP(sMRemoveSPITType);
mCallbacks.onSpitType(ObjectEvent::Deleted, false, *ptrSPITType);
mSpitTypes.removeEntry(*ptrSPITType);
// return sendSPITMessage(sMRemoveSPITType);
return 1;
}
return -1;
}
SType *SProcessor::createTypeFixed(string iD, string p_GroupName, string p_Name, uint64_t p_DefaultDelay, uint64_t p_DefaultDuration) { // @todo
return createType(iD, p_GroupName, p_Name, p_DefaultDelay, p_DefaultDuration, true, true);
}
SType *SProcessor::createType(string p_ID, string p_GroupName, string p_Name, uint64_t p_DefaultDelay, uint64_t p_DefaultDuration, bool p_FIxed, bool p_ProjectIndepended) { // @todo
bool boolNew;
SType *ptrSPITType = mSpitTypes.getEntry(p_ID);
if (ptrSPITType == nullptr) {
auto spitType = make_unique<SType>(p_ID, p_GroupName, p_Name, p_FIxed, p_ProjectIndepended, p_DefaultDelay, p_DefaultDuration);
ptrSPITType = spitType.get();
mSpitTypes.addEntry(move(spitType));
ptrSPITType->setCreatedByClient(true);
boolNew = true;
} else {
ptrSPITType->GroupName.set(p_GroupName);
ptrSPITType->Name.set(p_Name);
ptrSPITType->Fixed.set(p_FIxed);
ptrSPITType->ProjectIndepended.set(p_ProjectIndepended);
ptrSPITType->DefaultDelay.set(p_DefaultDelay);
ptrSPITType->DefaultDuration.set(p_DefaultDuration);
boolNew = false;
}
auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed;
mCallbacks.onSpitType(eventType, false, *ptrSPITType);
sendSPITTypeInternal(*ptrSPITType);
return ptrSPITType;
}
//----- SPIT Objects ------
void SProcessor::parseReportSPITObject(Message::ReportObject &message) { // @todo
ESP_LOGD(TAG, "parse ReportObject %s", message.getID().c_str());
SObject *ptrSPITObject;
SType *ptrSPITType;
bool boolNew = false;
bool boolRemote = false;
bool boolChanged = false;
{
ESP_LOGD(TAG, "parse ReportObject %s / %s", message.getID().c_str(), message.getName().c_str());
if (message.getServerRemote() == false) {
boolRemote = false;
ptrSPITObject = mSpitObjects.getEntry(message.getID());
ptrSPITType = mSpitTypes.getEntry(message.getSPITTypeID());
if (ptrSPITType == nullptr) {
// No associated SPITType found
if (ptrSPITObject != nullptr) {
// SpitObject exists but has no corresponding SPITType -> remove the SPITObject without sending a message
// Maybe the SPITObject has changed the SPITTypeID to a SPITTypeID of another board
mSpitObjects.removeEntry(*ptrSPITObject);
}
return;
}
bool isKnownType = ptrSPITType != nullptr;
if (ptrSPITObject == nullptr) {
// The user's app my veto the SPITType
if (mCallbacks.onCheckSpitObjectVeto(isKnownType) == false) {
ESP_LOGW(TAG, "ObjectVeto %s / %s", message.getID().c_str(), message.getName().c_str());
return;
}
auto spitObj = make_unique<SObject>(message.getID());
ptrSPITObject = spitObj.get();
mSpitObjects.addEntry(move(spitObj));
boolNew = true;
} else {
// The user's app my veto the SPITType
if (mCallbacks.onCheckSpitObjectVeto(isKnownType) == false) {
// SpitObject exists and User APp denied the SPITObject -> remove the SPITObject without sending a message
mSpitObjects.removeEntry(*ptrSPITObject);
ESP_LOGW(TAG, "TypeVeto %s / %s", message.getID().c_str(), message.getName().c_str());
return;
}
}
} else {
boolRemote = true;
ptrSPITObject = mRemoteSpitObjects.getEntry(message.getID());
ptrSPITType = mRemoteSpitTypes.getEntry(message.getSPITTypeID());
if (ptrSPITType == nullptr) {
// No associated SPITType found
return;
}
if (ptrSPITObject == nullptr) {
auto spitObj = make_unique<SObject>(message.getID());
ptrSPITObject = spitObj.get();
mRemoteSpitObjects.addEntry(move(spitObj));
boolNew = true;
}
}
if (!ptrSPITObject->setMessageOP(&message)) {
ESP_LOGE(TAG, "Change not allowed");
// setMessageOP error - the SPITObject can't be changed, it may be fixed and crated by this client
sendSPITObjectInternal(ptrSPITObject);
return;
}
if (boolRemote == false) {
// set the virtual action assignment
ptrSPITObject->setActionAssignedType(ptrSPITType->ActionAssigned.get());
}
auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed;
mCallbacks.onSpitObject(eventType, boolRemote, *ptrSPITType, *ptrSPITObject);
if (ptrSPITObject->setConfirmed(true) == true || boolChanged == true) {
// Confirmation has changed
sendSPITObjectInternal(ptrSPITObject);
}
}
}
void SProcessor::parseRemoveSPITObject(Message::RemoveObject &message) { // @todo
ESP_LOGD(TAG, "parse RemoveObject %s", message.getID().c_str());
SObject *ptrSPITObject = mRemoteSpitObjects.getEntry(message.getID());
if (ptrSPITObject != nullptr) {
SType *ptrSPITType = mRemoteSpitTypes.getEntry(ptrSPITObject->SPITTypeID.get());
if (ptrSPITType != nullptr) {
mCallbacks.onSpitObject(ObjectEvent::Deleted, true, *ptrSPITType, *ptrSPITObject);
}
mRemoteSpitObjects.removeEntry(*ptrSPITObject);
} else {
// call removeSPITObject, this will notify the server that the object is removed
removeSPITObject(message.getID());
}
}
int SProcessor::sendSPITObjectInternal(SObject *ptrSPITObject) { // @todo
if (ptrSPITObject == nullptr)
return -1;
Message::ReportObject sMReportSPITObject;
ptrSPITObject->fillMessageOP(sMReportSPITObject);
// return sendSPITMessage(sMReportSPITObject);
return 1;
}
/**
* When the client changes an existing SPITObject (normally the client should not do this), then he should send the changes to the SPITServer.
* An eventSPITObject occurs.
* The SPITServer may discard the changes and a second eventSPITObject occurs to correct the changes.
* @param obj the pointer to the changed SPITObject.
* CAUTION: The SPITObject must already exist.
* @return true = SPITObject is changed, false = not changed, maybe obj is NULL or the SPITObject doesn't exists
*/
bool SProcessor::changeSPITObject(SObject *obj) { // @todo
if (obj == nullptr)
return false;
SObject *ptrSPITObject;
SType *ptrSPITType;
{
ptrSPITObject = mSpitObjects.getEntry(obj->getID());
if (ptrSPITObject == nullptr)
return false;
ptrSPITType = mSpitTypes.getEntry(obj->getID());
if (ptrSPITObject == nullptr)
return false;
ptrSPITObject->setActionAssigned(obj->getActionAssigned());
;
ptrSPITObject->Delay.set(obj->Delay.get());
ptrSPITObject->Duration.set(obj->Delay.get());
ptrSPITObject->Fixed.set(obj->Fixed.get());
ptrSPITObject->FrameFadeInLength.set(obj->FrameFadeInLength.get());
ptrSPITObject->FrameFadeOutLength.set(obj->FrameFadeOutLength.get());
ptrSPITObject->FrameLength.set(obj->FrameLength.get());
ptrSPITObject->FrameStart.set(obj->FrameStart.get());
ptrSPITObject->Name.set(obj->Name.get());
ptrSPITObject->Remark.set(obj->Remark.get());
ptrSPITObject->SPITTypeID.set(obj->SPITTypeID.get());
ptrSPITObject->ServerParams.set(obj->ServerParams.get());
ptrSPITObject->Track.set(obj->Track.get());
ptrSPITObject->ValueFactor.set(obj->ValueFactor.get());
ptrSPITObject->ValueUse.set(obj->ValueUse.get());
mCallbacks.onSpitObject(ObjectEvent::Changed, false, *ptrSPITType, *ptrSPITObject);
sendSPITObjectInternal(ptrSPITObject);
}
return true;
}
/**
* When the client wants to remove a SPITObject with id == p_SPITObjectID (normally the client should not do this), then he should send it to the SPITServer.
* The corresponding SPITObject if listet in SPITObject will be deleted.
* An eventRemoveSPITType will occur.
* If an connection to a SPITServer is established, the SPITServer may discard the deletion and an eventSPITObject occurs
* -> the SPITObject is listet again.
* @param objId the id of the SPITObject to remove.
* @return 0 = sended to the SPITServer, -1 = not sended to the SPITServer or nos SPITObject with id == objId exists.
*/
int SProcessor::removeSPITObject(string objId) { // @todo
if (objId.length() <= 0)
return -1;
SType *ptrSPITType;
SObject *ptrSPITObject;
{
Message::RemoveObject sMRemoveSPITObject;
ptrSPITObject = mSpitObjects.getEntry(objId);
if (ptrSPITObject == nullptr)
return -1;
ptrSPITType = mSpitTypes.getEntry(ptrSPITObject->SPITTypeID.get());
if (ptrSPITType == nullptr)
return -1;
ptrSPITObject->fillMessageOP(sMRemoveSPITObject);
mCallbacks.onSpitObject(ObjectEvent::Deleted, false, *ptrSPITType, *ptrSPITObject);
mSpitObjects.removeEntry(*ptrSPITObject);
// return sendSPITMessage(sMRemoveSPITObject);
return 1;
}
return -1;
}
//----- Play SPIT Objects ------
void SProcessor::parsePlaySPITStart(Message::PlayStart &message) { // @todo
ESP_LOGD(TAG, "parse PlayStart ID: %s Name: %s Running: %d", message.getPlayerID().c_str(), message.getPlayerName().c_str(), (int)message.getPlayerIsRunning());
SPlayer &spitPlayer = SPlayer::getSPITPlayer(message.getPlayerID());
spitPlayer.setIsRunning(message.getPlayerIsRunning());
spitPlayer.setName(message.getPlayerName());
spitPlayer.setType(message.getPlayerType());
spitPlayer.setTime(message.getTime());
spitPlayer.startPlaySequence();
mCallbacks.onPlay(spitPlayer.getID(), spitPlayer.getName(), spitPlayer.getType(), spitPlayer.getIsRunning(), spitPlayer.getTime());
}
void SProcessor::parsePlaySPITObject(Message::PlayObject &message) { // @todo
SPlayer &ptrSPITPlayer = SPlayer::getSPITPlayer(message.getPlayerID());
SObject *ptrSPITObject = mSpitObjects.getEntry(message.getSPITObjectID());
if (ptrSPITObject == nullptr) {
return;
}
SPlayer::PlayType *ptrPlaySPITType = ptrSPITPlayer.addTypePlaying(ptrSPITObject->SPITTypeID.get());
if (ptrPlaySPITType == nullptr) {
return;
}
ptrPlaySPITType->setPlayerIsRunning(ptrSPITPlayer.getIsRunning());
ptrPlaySPITType->addValue(((double)message.getValue() / 1000000), ((double)ptrSPITObject->ValueFactor.get() / 1000000));
}
void SProcessor::parsePlaySPITEnd(Message::PlayEnd &message) { // @todo
SPlayer &ptrSPITPlayer = SPlayer::getSPITPlayer(message.getPlayerID());
auto &ptrPlaySPITTypes = ptrSPITPlayer.getPlaySPITTypes();
for (auto i = ptrPlaySPITTypes.begin(); i != ptrPlaySPITTypes.end(); i++) {
SPlayer::PlayType *ptrPlaySPITType = i->second.get();
bool boolStarted = ptrPlaySPITType->getIsNew();
bool boolStopped = (ptrPlaySPITType->getIsPlayed() == false);
SType *ptrSPITType = mSpitTypes.getEntry(ptrPlaySPITType->getSPITTypeID());
if (ptrSPITType == nullptr) {
// set isplayed to false, the ptrPlayObject will be removed by ptrSPITPlayer.endPlaySequence()
ptrPlaySPITType->setIsPlayed(false);
continue;
}
mCallbacks.onPlaySpitType(ptrPlaySPITType->getPlayerID(), ptrPlaySPITType->getSPITTypeID(), ptrPlaySPITType->getPlayerIsRunning(), boolStarted, boolStopped, ptrPlaySPITType->getValue());
}
ptrSPITPlayer.endPlaySequence();
}
void SProcessor::parseReportPlayStatus(Message::ReportPlayStatus &message) { // @todo
SType *ptrSPITType = NULL;
SObject *ptrSPITObject = mRemoteSpitObjects.getEntry(message.getID());
if (ptrSPITObject == nullptr) {
ptrSPITObject = mSpitObjects.getEntry(message.getID());
if (ptrSPITObject == nullptr) {
return;
}
}
if (ptrSPITObject->ServerRemote.get() == false) {
ptrSPITType = mSpitTypes.getEntry(ptrSPITObject->SPITTypeID.get());
} else {
ptrSPITType = mRemoteSpitTypes.getEntry(ptrSPITObject->SPITTypeID.get());
}
if (ptrSPITType == nullptr) {
return;
}
mCallbacks.onPlayRemoteObjectStatus(*ptrSPITType, *ptrSPITObject, message.getFrameInsideObject(), message.getValue());
}
//--------- Remote ----------
/**
* Send a remote control command to the SPITServer.
* There may be different command types:
* a) Some don't use value e.g. go to next scene, olay a jingle
* b) Some use values e.g. the main sound fader
* @param p_SPITObjectID the id of the remote SPITObject (this represents the remote control command)
* @param valuePpm the value in ppm
* in case a) the value is ignored
* in case b) the value is used
* @param valueFlag indicates how the server should use valuePpm:
* VALUEFLAG_DIRECT (0x00) The server overwrites its existing value with p_Value
* VALUEFLAG_INCREASE (0x01) The server increases his existing value by valuePpm
* VALUEFLAG_DECREASE (0x01) The server decreases his existing value by valuePpm
*/
void SProcessor::sendRemoteObject(string p_SPITObjectID, int valuePpm, char valueFlag) { // @todo
SObject *ptrRemoteSPITObject = mRemoteSpitObjects.getEntry(p_SPITObjectID);
if (ptrRemoteSPITObject == nullptr)
return;
Message::PlayStart playSPITStart(mGuid, mProjName, PLAYERTYPE_DISCRETE);
playSPITStart.setPlayerIsRunning(false);
playSPITStart.setTime(0);
// sendSPITMessage(playSPITStart);
Message::PlayObject playSPITObject;
playSPITObject.setID(ptrRemoteSPITObject->getID());
playSPITObject.setPlayPrePosition(false);
playSPITObject.setPlayerID(mGuid);
playSPITObject.setValue(valuePpm);
playSPITObject.setValueFlag(valueFlag);
// sendSPITMessage(playSPITObject);
Message::PlayEnd playSPITEnd(mGuid);
// sendSPITMessage(playSPITEnd);
}
}