745 lines
28 KiB
C++
745 lines
28 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, InternalCallbacks intern)
|
|
: mCallbacks(calls),
|
|
mInternCallbacks(intern),
|
|
mName(name),
|
|
mGuid(guid),
|
|
mProjName(projName),
|
|
mComputerName(hostName) {
|
|
}
|
|
|
|
SProcessor::~SProcessor() {
|
|
}
|
|
|
|
unique_ptr<Message::Connect> SProcessor::createConnectMessage(string serverIP, string serverPort, string loginName, string loginPassword) {
|
|
auto msg = make_unique<Message::Connect>(getComputerName(), mName);
|
|
msg->setLoginName(loginName);
|
|
msg->setLoginPassword(loginPassword);
|
|
msg->setServerIP(serverIP);
|
|
if (serverPort.length() <= 0) {
|
|
serverPort = "0";
|
|
}
|
|
int intServerPort = stoi(serverPort);
|
|
msg->setServerPort(intServerPort);
|
|
return msg;
|
|
}
|
|
|
|
/**
|
|
* 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::setActionType(string typeId, bool actionAssigned) {
|
|
SType *spitType = mSpitTypes.getEntry(typeId);
|
|
if (spitType == nullptr)
|
|
return;
|
|
if (spitType->ActionAssigned.set(actionAssigned)) {
|
|
sendTypeInternal(*spitType);
|
|
for (auto &[key, value] : mSpitObjects.getRepo()) {
|
|
if (value->SPITTypeID.get() == spitType->getID()) {
|
|
if (value->setActionAssignedType(actionAssigned) == true) {
|
|
sendObjectInternal(value.get());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** This should be called if the user wants to associate/remove an action with a SPITObject. */
|
|
void SProcessor::setActionObject(string spitObjId, bool actionAssigned) {
|
|
SObject *spitObject = mSpitObjects.getEntry(spitObjId);
|
|
if (spitObject == nullptr)
|
|
return;
|
|
if (spitObject->setActionAssigned(actionAssigned) == true) {
|
|
sendObjectInternal(spitObject);
|
|
}
|
|
}
|
|
|
|
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 {};
|
|
}
|
|
|
|
void SProcessor::resetMessageNumberReceived() {
|
|
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);
|
|
|
|
mMessageNumberReceived = sendOvertakingMessage(mMessageNumberReceived);
|
|
} else {
|
|
// message has overtaken another message
|
|
addOvertakingMessage(move(message));
|
|
}
|
|
}
|
|
|
|
void SProcessor::addOvertakingMessage(unique_ptr<Message> message) {
|
|
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));
|
|
}
|
|
|
|
int SProcessor::sendOvertakingMessage(int msgNumRec) {
|
|
// check overtaking messages
|
|
auto it = mOvertakingMessages.begin();
|
|
while (mOvertakingMessages.size() > 0) {
|
|
|
|
int msgNumNext = msgNumRec + 1;
|
|
if (msgNumNext > 255 || msgNumNext < 1)
|
|
msgNumNext = 1;
|
|
|
|
auto &overtakingMessage = *it;
|
|
int msgNum = (int)(overtakingMessage->getHeader()->getMessageNumber() & 0xFF);
|
|
|
|
if (msgNum == msgNumNext) {
|
|
msgNumRec = msgNum;
|
|
parseMessage(*overtakingMessage);
|
|
mOvertakingMessages.erase(it);
|
|
it = mOvertakingMessages.begin();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return msgNumRec;
|
|
}
|
|
|
|
void SProcessor::parseMessage(Message &message) {
|
|
// answerWatchdog();
|
|
if (!message.getHeader() || !message.getOPPart()) {
|
|
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
|
|
return;
|
|
}
|
|
|
|
switch (message.getType()) {
|
|
//----- Connection -----
|
|
case Message::ReportProject::OPFLAG:
|
|
parseReportProject(message.getAs<Message::ReportProject>());
|
|
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:
|
|
parseRemoveType(message.getAs<Message::RemoveType>());
|
|
//----- SPIT Objects ------
|
|
break;
|
|
case Message::ReportObject::OPFLAG:
|
|
parseReportObject(message.getAs<Message::ReportObject>());
|
|
break;
|
|
case Message::RemoveObject::OPFLAG:
|
|
parseRemoveObject(message.getAs<Message::RemoveObject>());
|
|
break;
|
|
//----- Play SPIT Objects ------
|
|
case Message::PlayStart::OPFLAG:
|
|
parsePlayStart(message.getAs<Message::PlayStart>());
|
|
break;
|
|
case Message::PlayObject::OPFLAG:
|
|
parsePlayObject(message.getAs<Message::PlayObject>());
|
|
break;
|
|
case Message::PlayEnd::OPFLAG:
|
|
parsePlayEnd(message.getAs<Message::PlayEnd>());
|
|
break;
|
|
case Message::ReportPlayStatus::OPFLAG:
|
|
parseReportPlayStatus(message.getAs<Message::ReportPlayStatus>());
|
|
break;
|
|
default:
|
|
ESP_LOGD(TAG, "Client::parseMessage: Unknown Message");
|
|
}
|
|
}
|
|
|
|
//----- SPIT Project ------
|
|
void SProcessor::parseReportProject(Message::ReportProject &message) {
|
|
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 (mInternCallbacks.sendMessage(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 (mInternCallbacks.sendMessage(reportProject) < 0) {
|
|
ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
|
|
}
|
|
}
|
|
|
|
void SProcessor::parseCloseProject(Message::CloseProject &p_CloseSPITProject) {
|
|
ESP_LOGD(TAG, "parse CloseProject");
|
|
string stringProjectID;
|
|
mCallbacks.onProjectUpdate(ProjUpdate::ServerClosed, p_CloseSPITProject.getProjectID());
|
|
SPlayer::clearPlayers();
|
|
}
|
|
|
|
void SProcessor::parseRequestProjectTransfer(Message::RequestProjectTransfer &message) {
|
|
ESP_LOGD(TAG, "parse RequestProjectTransfer");
|
|
// StartProjectTransfer
|
|
Message::StartProjectTransfer sMStartProjectTransfer;
|
|
if (mInternCallbacks.sendMessage(sMStartProjectTransfer) < 0) {
|
|
return;
|
|
}
|
|
|
|
// send all listes SPITTypes
|
|
for (const auto &[key, value] : mSpitTypes.getRepo()) {
|
|
sendTypeInternal(*value);
|
|
mInternCallbacks.delay(10);
|
|
}
|
|
for (auto &[key, value] : mSpitObjects.getRepo()) {
|
|
sendObjectInternal(value.get());
|
|
mInternCallbacks.delay(10);
|
|
}
|
|
|
|
// EndProjectTransfer
|
|
Message::EndProjectTransfer sMEndProjectTransfer;
|
|
mInternCallbacks.sendMessage(sMEndProjectTransfer);
|
|
}
|
|
|
|
void SProcessor::parseStartProjectTransfer(Message::StartProjectTransfer &message) {
|
|
mCallbacks.onProjectUpdate(ProjUpdate::StartTransfer, mServerProjectID);
|
|
}
|
|
|
|
void SProcessor::parseEndProjectTransfer(Message::EndProjectTransfer &message) {
|
|
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 (mInternCallbacks.sendMessage(reportSPITProject) < 0) {
|
|
ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
|
|
}
|
|
}
|
|
|
|
void SProcessor::parseReportType(Message::ReportType &message) {
|
|
ESP_LOGD(TAG, "parse ReportType ID %s Name %s", message.getID().c_str(), message.getName().c_str());
|
|
SType *sType;
|
|
bool isNew = false;
|
|
bool isChanged = 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));
|
|
isNew = true;
|
|
}
|
|
} else {
|
|
sType = mRemoteSpitTypes.getEntry(message.getID());
|
|
if (sType == nullptr) {
|
|
auto spitType = make_unique<SType>(message.getID());
|
|
sType = spitType.get();
|
|
mRemoteSpitTypes.addEntry(move(spitType));
|
|
isNew = true;
|
|
}
|
|
}
|
|
if (!sType->setMessageOP(message)) {
|
|
// SPITType is not changable -> send back to the server
|
|
sendTypeInternal(*sType);
|
|
return;
|
|
}
|
|
|
|
auto eventType = isNew ? ObjectEvent::Created : ObjectEvent::Changed;
|
|
// add or change SPITType
|
|
mCallbacks.onSpitType(eventType, sType->ServerRemote.get(), *sType);
|
|
|
|
if (sType != nullptr) {
|
|
if (sType->setConfirmed(true) == true || isChanged == true) {
|
|
sendTypeInternal(*sType);
|
|
}
|
|
}
|
|
}
|
|
void SProcessor::parseRemoveType(Message::RemoveType &message) {
|
|
ESP_LOGD(TAG, "parse RemoveType %s", message.getID().c_str());
|
|
bool isRemote = false;
|
|
string sTypeID = message.getID();
|
|
|
|
SType *sType = mRemoteSpitTypes.getEntry(sTypeID);
|
|
if (!sType) {
|
|
isRemote = true;
|
|
} else {
|
|
sType = mSpitTypes.getEntry(sTypeID);
|
|
if (!sType) {
|
|
isRemote = false;
|
|
} else {
|
|
// No SType with sTypeID is listet
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (sType->getCreatedByClient() && sType->Fixed.get()) {
|
|
// the SPITyte is created by client himself and it is fixed -> don't remove the SType!!
|
|
// Send the SPITTyp back to the server
|
|
sendTypeInternal(*sType);
|
|
return;
|
|
}
|
|
|
|
mCallbacks.onSpitType(ObjectEvent::Deleted, isRemote, *sType);
|
|
if (isRemote == false) {
|
|
mSpitTypes.removeEntry(*sType);
|
|
} else {
|
|
mRemoteSpitTypes.removeEntry(*sType);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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::changeType(SType *sType) {
|
|
if (sType == nullptr)
|
|
return false;
|
|
SType *mod = mSpitTypes.getEntry(sType->getID());
|
|
if (mod == nullptr)
|
|
return false;
|
|
|
|
mod->DefaultDelay.set(sType->DefaultDelay.get());
|
|
mod->DefaultDuration.set(sType->DefaultDuration.get());
|
|
mod->Fixed.set(sType->Fixed.get());
|
|
mod->GroupName.set(sType->GroupName.get());
|
|
mod->Name.set(sType->Name.get());
|
|
mod->ProjectIndepended.set(sType->ProjectIndepended.get());
|
|
|
|
mCallbacks.onSpitType(ObjectEvent::Changed, false, *mod);
|
|
sendTypeInternal(*mod);
|
|
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::removeType(string sType) {
|
|
if (sType.length() <= 0)
|
|
return -1;
|
|
SType *mod = mSpitTypes.getEntry(sType);
|
|
if (mod == nullptr)
|
|
return -1;
|
|
Message::RemoveType sMRemoveSPITType;
|
|
mod->fillMessageOP(sMRemoveSPITType);
|
|
mCallbacks.onSpitType(ObjectEvent::Deleted, false, *mod);
|
|
mSpitTypes.removeEntry(*mod);
|
|
return mInternCallbacks.sendMessage(sMRemoveSPITType);
|
|
}
|
|
|
|
SType *SProcessor::createType(string id, string groupName, string name, uint64_t delay, uint64_t duration, bool fixed, bool projIndipendent) {
|
|
bool boolNew;
|
|
SType *sType = mSpitTypes.getEntry(id);
|
|
if (sType == nullptr) {
|
|
auto spitType = make_unique<SType>(id, groupName, name, fixed, projIndipendent, delay, duration);
|
|
sType = spitType.get();
|
|
mSpitTypes.addEntry(move(spitType));
|
|
sType->setCreatedByClient(true);
|
|
boolNew = true;
|
|
} else {
|
|
sType->GroupName.set(groupName);
|
|
sType->Name.set(name);
|
|
sType->Fixed.set(fixed);
|
|
sType->ProjectIndepended.set(projIndipendent);
|
|
sType->DefaultDelay.set(delay);
|
|
sType->DefaultDuration.set(duration);
|
|
boolNew = false;
|
|
}
|
|
|
|
auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed;
|
|
mCallbacks.onSpitType(eventType, false, *sType);
|
|
sendTypeInternal(*sType);
|
|
return sType;
|
|
}
|
|
|
|
/**
|
|
* 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 sType the pointer to the changed SPITType
|
|
* @return 0 = is sended, -1 = is not sended
|
|
*/
|
|
int SProcessor::sendTypeInternal(SType &sType) {
|
|
Message::ReportType reportType;
|
|
sType.fillMessageOP(reportType);
|
|
return mInternCallbacks.sendMessage(reportType);
|
|
}
|
|
|
|
//----- SPIT Objects ------
|
|
void SProcessor::parseReportObject(Message::ReportObject &message) {
|
|
ESP_LOGD(TAG, "parse ReportObject %s", message.getID().c_str());
|
|
SObject *sObject;
|
|
SType *sType;
|
|
bool isNew = false;
|
|
bool isRemote = false;
|
|
bool isChanged = false;
|
|
{
|
|
ESP_LOGD(TAG, "parse ReportObject %s / %s", message.getID().c_str(), message.getName().c_str());
|
|
if (message.getServerRemote() == false) {
|
|
isRemote = false;
|
|
sObject = mSpitObjects.getEntry(message.getID());
|
|
sType = mSpitTypes.getEntry(message.getSPITTypeID());
|
|
|
|
if (sType == nullptr) {
|
|
// No associated SPITType found
|
|
if (sObject != 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(*sObject);
|
|
}
|
|
return;
|
|
}
|
|
bool isKnownType = sType != nullptr;
|
|
if (sObject == 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());
|
|
sObject = spitObj.get();
|
|
mSpitObjects.addEntry(move(spitObj));
|
|
isNew = 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(*sObject);
|
|
ESP_LOGW(TAG, "TypeVeto %s / %s", message.getID().c_str(), message.getName().c_str());
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
isRemote = true;
|
|
sObject = mRemoteSpitObjects.getEntry(message.getID());
|
|
sType = mRemoteSpitTypes.getEntry(message.getSPITTypeID());
|
|
if (sType == nullptr) {
|
|
// No associated SPITType found
|
|
return;
|
|
}
|
|
if (sObject == nullptr) {
|
|
auto spitObj = make_unique<SObject>(message.getID());
|
|
sObject = spitObj.get();
|
|
mRemoteSpitObjects.addEntry(move(spitObj));
|
|
isNew = true;
|
|
}
|
|
}
|
|
|
|
if (!sObject->setMessageOP(&message)) {
|
|
ESP_LOGE(TAG, "Change not allowed %s", sObject->getID().c_str());
|
|
// setMessageOP error - the SPITObject can't be changed, it may be fixed and crated by this client
|
|
sendObjectInternal(sObject);
|
|
return;
|
|
}
|
|
|
|
if (isRemote == false) {
|
|
// set the virtual action assignment
|
|
sObject->setActionAssignedType(sType->ActionAssigned.get());
|
|
}
|
|
|
|
auto eventType = isNew ? ObjectEvent::Created : ObjectEvent::Changed;
|
|
mCallbacks.onSpitObject(eventType, isRemote, *sType, *sObject);
|
|
|
|
if (sObject->setConfirmed(true) == true || isChanged == true) {
|
|
// Confirmation has changed
|
|
sendObjectInternal(sObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SProcessor::parseRemoveObject(Message::RemoveObject &message) {
|
|
ESP_LOGD(TAG, "parse RemoveObject %s", message.getID().c_str());
|
|
SObject *sObject = mRemoteSpitObjects.getEntry(message.getID());
|
|
if (sObject != nullptr) {
|
|
SType *sType = mRemoteSpitTypes.getEntry(sObject->SPITTypeID.get());
|
|
if (sType != nullptr) {
|
|
mCallbacks.onSpitObject(ObjectEvent::Deleted, true, *sType, *sObject);
|
|
}
|
|
mRemoteSpitObjects.removeEntry(*sObject);
|
|
} else {
|
|
// call removeObject, this will notify the server that the object is removed
|
|
removeObject(message.getID());
|
|
}
|
|
}
|
|
|
|
int SProcessor::sendObjectInternal(SObject *sObject) {
|
|
if (sObject == nullptr)
|
|
return -1;
|
|
Message::ReportObject reportObject;
|
|
sObject->fillMessageOP(reportObject);
|
|
return mInternCallbacks.sendMessage(reportObject);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* @return 0 = sended, -1 = not sended
|
|
*/
|
|
bool SProcessor::changeObject(SObject *sObject) {
|
|
if (sObject == nullptr)
|
|
return false;
|
|
SObject *mod = mSpitObjects.getEntry(sObject->getID());
|
|
if (mod == nullptr)
|
|
return false;
|
|
SType *sType = mSpitTypes.getEntry(sObject->getID());
|
|
if (mod == nullptr)
|
|
return false;
|
|
|
|
mod->setActionAssigned(sObject->getActionAssigned());
|
|
mod->Delay.set(sObject->Delay.get());
|
|
mod->Duration.set(sObject->Delay.get());
|
|
mod->Fixed.set(sObject->Fixed.get());
|
|
mod->FrameFadeInLength.set(sObject->FrameFadeInLength.get());
|
|
mod->FrameFadeOutLength.set(sObject->FrameFadeOutLength.get());
|
|
mod->FrameLength.set(sObject->FrameLength.get());
|
|
mod->FrameStart.set(sObject->FrameStart.get());
|
|
mod->Name.set(sObject->Name.get());
|
|
mod->Remark.set(sObject->Remark.get());
|
|
mod->SPITTypeID.set(sObject->SPITTypeID.get());
|
|
mod->ServerParams.set(sObject->ServerParams.get());
|
|
mod->Track.set(sObject->Track.get());
|
|
mod->ValueFactor.set(sObject->ValueFactor.get());
|
|
mod->ValueUse.set(sObject->ValueUse.get());
|
|
|
|
mCallbacks.onSpitObject(ObjectEvent::Changed, false, *sType, *mod);
|
|
sendObjectInternal(mod);
|
|
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::removeObject(string objId) {
|
|
if (objId.length() <= 0)
|
|
return -1;
|
|
Message::RemoveObject remObj;
|
|
|
|
SObject *sObject = mSpitObjects.getEntry(objId);
|
|
if (sObject == nullptr)
|
|
return -1;
|
|
SType *sType = mSpitTypes.getEntry(sObject->SPITTypeID.get());
|
|
if (sType == nullptr)
|
|
return -1;
|
|
|
|
sObject->fillMessageOP(remObj);
|
|
mCallbacks.onSpitObject(ObjectEvent::Deleted, false, *sType, *sObject);
|
|
mSpitObjects.removeEntry(*sObject);
|
|
return mInternCallbacks.sendMessage(remObj);
|
|
}
|
|
|
|
// //----- Play SPIT Objects ------
|
|
|
|
void SProcessor::parsePlayStart(Message::PlayStart &message) {
|
|
ESP_LOGD(TAG, "parse PlayStart ID: %s Name: %s Running: %d", message.getPlayerID().c_str(), message.getPlayerName().c_str(), (int)message.getPlayerIsRunning());
|
|
SPlayer &player = SPlayer::getSPITPlayer(message.getPlayerID());
|
|
player.setIsRunning(message.getPlayerIsRunning());
|
|
player.setName(message.getPlayerName());
|
|
player.setType(message.getPlayerType());
|
|
player.setTime(message.getTime());
|
|
player.startPlaySequence();
|
|
|
|
mCallbacks.onPlay(player.getID(), player.getName(), player.getType(), player.getIsRunning(), player.getTime());
|
|
}
|
|
|
|
void SProcessor::parsePlayObject(Message::PlayObject &message) {
|
|
|
|
SPlayer &player = SPlayer::getSPITPlayer(message.getPlayerID());
|
|
SObject *sObject = mSpitObjects.getEntry(message.getSPITObjectID());
|
|
|
|
if (sObject == nullptr) {
|
|
return;
|
|
}
|
|
SPlayer::PlayType *playType = player.addTypePlaying(sObject->SPITTypeID.get());
|
|
if (playType == nullptr) {
|
|
return;
|
|
}
|
|
playType->setPlayerIsRunning(player.getIsRunning());
|
|
playType->addValue(((double)message.getValue() / 1000000), ((double)sObject->ValueFactor.get() / 1000000));
|
|
}
|
|
|
|
void SProcessor::parsePlayEnd(Message::PlayEnd &message) {
|
|
SPlayer &sPlayer = SPlayer::getSPITPlayer(message.getPlayerID());
|
|
|
|
auto &playTypes = sPlayer.getPlaySPITTypes();
|
|
for (auto i = playTypes.begin(); i != playTypes.end(); i++) {
|
|
SPlayer::PlayType *playType = i->second.get();
|
|
bool isStarted = playType->getIsNew();
|
|
bool iStopped = (playType->getIsPlayed() == false);
|
|
SType *ptrSPITType = mSpitTypes.getEntry(playType->getSPITTypeID());
|
|
if (ptrSPITType == nullptr) {
|
|
// set isplayed to false, the ptrPlayObject will be removed by sPlayer.endPlaySequence()
|
|
playType->setIsPlayed(false);
|
|
continue;
|
|
}
|
|
mCallbacks.onPlaySpitType(playType->getPlayerID(), playType->getSPITTypeID(), playType->getPlayerIsRunning(), isStarted, iStopped, playType->getValue());
|
|
}
|
|
sPlayer.endPlaySequence();
|
|
}
|
|
|
|
void SProcessor::parseReportPlayStatus(Message::ReportPlayStatus &message) {
|
|
SType *sType = NULL;
|
|
|
|
SObject *sObject = mRemoteSpitObjects.getEntry(message.getID());
|
|
if (sObject == nullptr) {
|
|
sObject = mSpitObjects.getEntry(message.getID());
|
|
if (sObject == nullptr) {
|
|
return;
|
|
}
|
|
}
|
|
if (sObject->ServerRemote.get() == false) {
|
|
sType = mSpitTypes.getEntry(sObject->SPITTypeID.get());
|
|
} else {
|
|
sType = mRemoteSpitTypes.getEntry(sObject->SPITTypeID.get());
|
|
}
|
|
|
|
if (sType == nullptr) {
|
|
return;
|
|
}
|
|
mCallbacks.onPlayRemoteObjectStatus(*sType, *sObject, 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 sObjectId 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 sObjectId, int valuePpm, char valueFlag) {
|
|
SObject *remoteObject = mRemoteSpitObjects.getEntry(sObjectId);
|
|
if (remoteObject == nullptr)
|
|
return;
|
|
|
|
Message::PlayStart playSPITStart(mGuid, mProjName, SPlayer::PTYPE_DISCRETE);
|
|
playSPITStart.setPlayerIsRunning(false);
|
|
playSPITStart.setTime(0);
|
|
mInternCallbacks.sendMessage(playSPITStart);
|
|
|
|
Message::PlayObject playSPITObject;
|
|
playSPITObject.setID(remoteObject->getID());
|
|
playSPITObject.setPlayPrePosition(false);
|
|
playSPITObject.setPlayerID(mGuid);
|
|
playSPITObject.setValue(valuePpm);
|
|
playSPITObject.setValueFlag(valueFlag);
|
|
mInternCallbacks.sendMessage(playSPITObject);
|
|
|
|
Message::PlayEnd playSPITEnd(mGuid);
|
|
mInternCallbacks.sendMessage(playSPITEnd);
|
|
}
|
|
|
|
} // namespace spit
|