From 04a8904cbe735d2de7766bc5999b158ca97c1150 Mon Sep 17 00:00:00 2001 From: Jakob Gegeniger Date: Sat, 29 Mar 2025 14:57:01 +0100 Subject: [PATCH] refactor/bringup: Bringup full project moving SPIT-App parts to main app LiveShowDemoProject added Debugging motor movements --- components/spit/include/I_SAD_Client.hpp | 62 +- components/spit/include/MyApp.h | 85 - .../spit/include/SAD_DetectedServer.hpp | 225 +- components/spit/include/SPITObject.h | 290 +- components/spit/include/SPITPlayer.h | 144 +- components/spit/include/SPITSocket.h | 253 +- components/spit/include/SPITType.h | 224 +- components/spit/include/SPIT_Client.h | 609 +-- components/spit/include/SPIT_Message.h | 1725 ++++---- components/spit/src/MyApp.cpp | 452 --- components/spit/src/SAD_DetectedServer.cpp | 246 +- components/spit/src/SPITObject.cpp | 983 ++--- components/spit/src/SPITPlayer.cpp | 194 +- components/spit/src/SPITSocket.cpp | 84 +- components/spit/src/SPITType.cpp | 830 ++-- components/spit/src/SPIT_Client.cpp | 2429 ++++++----- components/spit/src/SPIT_Message.cpp | 3564 +++++++++-------- components/watchFace/CMakeLists.txt | 4 + components/watchFace/watchFace.hpp | 50 + core | 2 +- doc/InitRun.md | 312 ++ doc/LSS-Icon.afdesign | Bin 88310 -> 89027 bytes doc/LSS-Icon.jpg | Bin 25848 -> 26214 bytes doc/LiveShowProject/CatasWatchProject.dpr | Bin 0 -> 38 bytes doc/LiveShowProject/CatasWatchProject.ldv | Bin 0 -> 9955 bytes doc/LiveShowProject/CatasWatchProject.lms | Bin 0 -> 14 bytes doc/LiveShowProject/CatasWatchProject.lmv | Bin 0 -> 2334 bytes doc/LiveShowProject/CatasWatchProject.lsb | Bin 0 -> 10011 bytes doc/LiveShowProject/CatasWatchProject.lsc | Bin 0 -> 213 bytes doc/LiveShowProject/CatasWatchProject.lsd | Bin 0 -> 169797 bytes doc/LiveShowProject/CatasWatchProject.lse | Bin 0 -> 96 bytes doc/LiveShowProject/CatasWatchProject.lsf | Bin 0 -> 14 bytes doc/LiveShowProject/CatasWatchProject.lsh | Bin 0 -> 212 bytes doc/LiveShowProject/CatasWatchProject.lsj | Bin 0 -> 38 bytes doc/LiveShowProject/CatasWatchProject.lsp | Bin 0 -> 644 bytes doc/LiveShowProject/CatasWatchProject.lss | Bin 0 -> 147 bytes doc/LiveShowProject/CatasWatchProject.lsu | Bin 0 -> 1104 bytes doc/LiveShowProject/CatasWatchProject.lsv | Bin 0 -> 1714 bytes doc/LiveShowProject/CatasWatchProject.lsx | Bin 0 -> 14 bytes doc/LiveShowProject/CatasWatchProject.rbo | Bin 0 -> 539 bytes doc/LiveShowProject/CatasWatchProject.rtf | 5 + doc/LiveShowProject/CatasWatchProject.spi | Bin 0 -> 2024 bytes doc/LiveShowProject/CatasWatchProject.ssj | Bin 0 -> 22 bytes doc/LiveShowProject/CatasWatchProject.uip | Bin 0 -> 150 bytes main/watchMain.cpp | 503 ++- main/watchMain.hpp | 18 +- test/integration/CMakeLists.txt | 12 + test/{ => integration}/dependencies.lock | 0 test/integration/main/CMakeLists.txt | 2 + test/integration/main/movementTests.cpp | 322 ++ test/integration/sdkconfig | 2159 ++++++++++ test/integration/sdkconfig.defaults | 18 + test/unitOnHost/.vscode/settings.json | 3 + {utest => test/unitOnHost}/CMakeLists.txt | 2 +- {utest => test/unitOnHost}/ReadMe.md | 0 {utest => test/unitOnHost}/test_core.cmake | 0 test/{ => unitOnTarget}/CMakeLists.txt | 5 +- test/{ => unitOnTarget}/ReadMe.md | 0 test/unitOnTarget/dependencies.lock | 9 + test/{ => unitOnTarget}/main/CMakeLists.txt | 0 test/{ => unitOnTarget}/main/unitTest.cpp | 0 test/{ => unitOnTarget}/sdkconfig | 0 test/{ => unitOnTarget}/sdkconfig.defaults | 0 63 files changed, 9220 insertions(+), 6605 deletions(-) delete mode 100644 components/spit/include/MyApp.h delete mode 100644 components/spit/src/MyApp.cpp create mode 100644 components/watchFace/CMakeLists.txt create mode 100644 components/watchFace/watchFace.hpp create mode 100644 doc/InitRun.md create mode 100644 doc/LiveShowProject/CatasWatchProject.dpr create mode 100644 doc/LiveShowProject/CatasWatchProject.ldv create mode 100644 doc/LiveShowProject/CatasWatchProject.lms create mode 100644 doc/LiveShowProject/CatasWatchProject.lmv create mode 100644 doc/LiveShowProject/CatasWatchProject.lsb create mode 100644 doc/LiveShowProject/CatasWatchProject.lsc create mode 100644 doc/LiveShowProject/CatasWatchProject.lsd create mode 100644 doc/LiveShowProject/CatasWatchProject.lse create mode 100644 doc/LiveShowProject/CatasWatchProject.lsf create mode 100644 doc/LiveShowProject/CatasWatchProject.lsh create mode 100644 doc/LiveShowProject/CatasWatchProject.lsj create mode 100644 doc/LiveShowProject/CatasWatchProject.lsp create mode 100644 doc/LiveShowProject/CatasWatchProject.lss create mode 100644 doc/LiveShowProject/CatasWatchProject.lsu create mode 100644 doc/LiveShowProject/CatasWatchProject.lsv create mode 100644 doc/LiveShowProject/CatasWatchProject.lsx create mode 100644 doc/LiveShowProject/CatasWatchProject.rbo create mode 100644 doc/LiveShowProject/CatasWatchProject.rtf create mode 100644 doc/LiveShowProject/CatasWatchProject.spi create mode 100644 doc/LiveShowProject/CatasWatchProject.ssj create mode 100644 doc/LiveShowProject/CatasWatchProject.uip create mode 100644 test/integration/CMakeLists.txt rename test/{ => integration}/dependencies.lock (100%) create mode 100644 test/integration/main/CMakeLists.txt create mode 100644 test/integration/main/movementTests.cpp create mode 100644 test/integration/sdkconfig create mode 100644 test/integration/sdkconfig.defaults create mode 100644 test/unitOnHost/.vscode/settings.json rename {utest => test/unitOnHost}/CMakeLists.txt (88%) rename {utest => test/unitOnHost}/ReadMe.md (100%) rename {utest => test/unitOnHost}/test_core.cmake (100%) rename test/{ => unitOnTarget}/CMakeLists.txt (86%) rename test/{ => unitOnTarget}/ReadMe.md (100%) create mode 100644 test/unitOnTarget/dependencies.lock rename test/{ => unitOnTarget}/main/CMakeLists.txt (100%) rename test/{ => unitOnTarget}/main/unitTest.cpp (100%) rename test/{ => unitOnTarget}/sdkconfig (100%) rename test/{ => unitOnTarget}/sdkconfig.defaults (100%) diff --git a/components/spit/include/I_SAD_Client.hpp b/components/spit/include/I_SAD_Client.hpp index 1a95070..1384906 100644 --- a/components/spit/include/I_SAD_Client.hpp +++ b/components/spit/include/I_SAD_Client.hpp @@ -3,35 +3,37 @@ #include using namespace std; +class SAD_DetectedServer; class I_SAD_Client { -public: - /** - * 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:
- * 1.) If a loopback address is available, it is used.
- * 2.) If an IP4 address is available, it is used.
- * 3.) In the other cases the IP6 address is used.
- * @param p_ID the id of the server (every started server should generate an id) - * @param p_Name the name of the SPIT server - * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running - * @param p_IP the selected ip address of the SPIT server - * @param p_Port the port of the SPIT server - * @param p_Addition sometimes server may have additional informations - * @param p_IsIP4 the server ip is a ip4 address - */ - virtual void eventServerDetected(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4) = 0; - /** - * 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.
- * @param p_ID the id of the server (every started server should generate an id) - * @param p_Name the name of the SPIT server - * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running - * @param p_IP the selected ip address of the SPIT server - * @param p_Port the port of the SPIT server - * @param p_Addition sometimes server may have additional informations - * @param p_IsIP4 the server ip is a ip4 address - */ - virtual void eventServerLost(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4) = 0; - virtual void eventServerChanged(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4) = 0; + public: + /** + * 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:
+ * 1.) If a loopback address is available, it is used.
+ * 2.) If an IP4 address is available, it is used.
+ * 3.) In the other cases the IP6 address is used.
+ * @param p_ID the id of the server (every started server should generate an id) + * @param p_Name the name of the SPIT server + * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running + * @param p_IP the selected ip address of the SPIT server + * @param p_Port the port of the SPIT server + * @param p_Addition sometimes server may have additional informations + * @param p_IsIP4 the server ip is a ip4 address + */ + virtual void eventServerDetected(SAD_DetectedServer &server) = 0; + /** + * 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.
+ * @param p_ID the id of the server (every started server should generate an id) + * @param p_Name the name of the SPIT server + * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running + * @param p_IP the selected ip address of the SPIT server + * @param p_Port the port of the SPIT server + * @param p_Addition sometimes server may have additional informations + * @param p_IsIP4 the server ip is a ip4 address + */ + virtual void eventServerChanged(SAD_DetectedServer &server) = 0; + + virtual void eventServerLost(SAD_DetectedServer &server) = 0; }; diff --git a/components/spit/include/MyApp.h b/components/spit/include/MyApp.h deleted file mode 100644 index 0cd168d..0000000 --- a/components/spit/include/MyApp.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ - -/* - * File: MySPITApp.h - * Author: Hagi - * - * Created on 17. April 2019, 18:24 - */ - -#ifndef MYSPITAPP_H -#define MYSPITAPP_H - -#include "SPIT_Client.h" -#include -#include -#include "SPITType.h" -#include "SPITObject.h" -#include "SPITPlayer.h" -#include "SAD_DetectedServer.hpp" - -using namespace std; - -class MyApp { - public: - MyApp(); - // Client's infos is set by the client - static string s_ClientName; - static string s_ProjectName; - void init(); - - private: - SPIT_Client _SpitClient; // pointer to an instance of the SPIT_Client, which do the main work for you - - // Server's project infos filled by eventProjectReport - static string m_ServerProjectID; - static string m_ServerProjectName; - static int m_ServerFramesPerSecond; // set when the server reports his project, see eventProjectReport - // liveSHOWsoftware will use 44100 frames per second as time resolution - // All times are given in frames, - - public: - static void onServerEvent(SPIT_Client::ServerEvent event, const SAD_DetectedServer &p_DetectedServer); - static void onConnectionStatus(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, int p_ConnectionStatus, int p_OldConnectionStatus); - - //----- Project ----- - static void onStartProjectTransfer(); - static void onEndProjectTransfer(); - static void onProjectReport(string p_ProjectID, string p_ProjectName, int p_FramesPerSeoond); - static void onProjectClosed(string p_ProjectID); - - //----- SPITType ----- - static bool onCheckSpitTypeVeto(SPIT_Message::ReportSPITType* p_ReportSPITType); - static void onSpitType(bool p_New, const SPITType &p_SPITType); - static void onSpitTypeRemote(bool p_New, const SPITType &p_SPITType); - static void onSpitTypeRemoved(const SPITType &p_SPITType); - static void onSpitTypeRemoteRemoved(const SPITType &p_SPITType); - - //----- SPITObject ----- - static bool onCheckSpitObjectVeto(SPIT_Message::ReportSPITObject* p_ReportSPITObject); - static void onSpitObject(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject); - static void onSpitObjectRemote(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject); - static void onSpitObjectRemoved(const SPITType &p_SPITType, const SPITObject &p_SPITObject); - static void onSpitObjectRemoteRemoved(const SPITType &p_SPITType, const SPITObject &p_SPITObject); - - //----- Play SPITObjects ----- - static void onPlay(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames); - static void onPlaySpitType(string p_PlayerID, string p_SPITTypeID, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value); - - //----- Server changes status of one of his REMOTE SPITObjects ----- - // REMOTE only Server->Client RemoteObject's play status - static void onPlayRemoteObjectStatus(const SPITType &p_SPITType, const SPITObject &p_SPITObject, long long p_FrameInsideObject, int p_Value); - - void sendRemoteObject(string p_SPITObjectID, int p_Valueppm = 0, char p_ValueFlag = 0x00); - //----- - void testLiveShowRemote(); - - //------ User's options normally should not be used, the server is master of things ------ - public: -}; - -#endif /* MYSPITAPP_H */ diff --git a/components/spit/include/SAD_DetectedServer.hpp b/components/spit/include/SAD_DetectedServer.hpp index 84f80e5..e0cb50a 100644 --- a/components/spit/include/SAD_DetectedServer.hpp +++ b/components/spit/include/SAD_DetectedServer.hpp @@ -1,138 +1,119 @@ #pragma once #include "I_SAD_Client.hpp" +#include #include #include -#include using namespace std; class SAD_DetectedServer { -public: - SAD_DetectedServer(); - SAD_DetectedServer(const SAD_DetectedServer& orig) { - m_ID = orig.getID(); - m_Name = orig.getName(); - m_ComputerName = orig.getComputerName(); - m_IP = orig.getIP(); - m_IPIsIP4 = orig.getIpIsIP4(); - m_ClientIP = orig.getClientIP(); - m_Port = orig.getPort(); - m_Additions = orig.getAdditions(); - } - ~SAD_DetectedServer(); - - private: - string m_ID; - string m_Name; - string m_ComputerName; - string m_IP; - bool m_IPIsIP4; - string m_ClientIP; - string m_Port; - string m_Additions; - string m_ServerProjectName; - bool m_New; - bool m_Changed; - bool m_FoundAgain; - - public: - string getID() const { return m_ID; } - string getName() const { return m_Name; } - string getComputerName() const { return m_ComputerName; } - string getIP() const { return m_IP; } - bool getIpIsIP4() const { return m_IPIsIP4; } - string getPort() const { return m_Port; } - string getClientIP() const { return m_ClientIP; } - string getAdditions() const { return m_Additions; } - string getProjectName() const {return m_ServerProjectName;} -private: - void setID(string p_ID) { m_ID = p_ID; } - void setName(string p_Name) { m_Name = p_Name; } - void setComputerName(string p_ComputerName) { m_ComputerName = p_ComputerName; } - void setIP(string p_IP) { m_IP = p_IP; } - void setClientIP(string p_IP) { m_ClientIP = p_IP; } - void setPort(string p_Port) { m_Port = p_Port; } - void setAdditions(string p_Additions) { m_Additions = p_Additions;} - void setProjectName(string p_ServerProjectName); + public: + SAD_DetectedServer(); + SAD_DetectedServer(const SAD_DetectedServer &orig) { + m_ID = orig.getID(); + m_Name = orig.getName(); + m_ComputerName = orig.getComputerName(); + m_IP = orig.getIP(); + m_ClientIP = orig.getClientIP(); + m_Port = orig.getPort(); + m_Additions = orig.getAdditions(); + } + ~SAD_DetectedServer(); - void setIPIsIP4(bool p_IsIP4) { m_IPIsIP4 = p_IsIP4; } - bool getNew() const { return m_New; } - bool getChanged() const { return m_Changed; } - bool getFoundAgain() const { return m_FoundAgain; } - void setChanged() { m_Changed = true; } - void setNew(bool p_New) { m_New = p_New; } - void setFoundAgain() { m_FoundAgain = true; } + private: + string m_ID; + string m_Name; + string m_ComputerName; + string m_IP; + string m_ClientIP; + string m_Port; + string m_Additions; + string m_ServerProjectName; + bool m_New; + bool m_Changed; + bool m_FoundAgain; - //SAD_Client m_ThreadSend will send to Multicast addresses - void startCycleSAD() { - m_IPIsIP4 = false; - m_Changed = false; - m_FoundAgain = false; - m_New = false; - } - //SAD_Client m_Thread_Send has paused in the meantime m_ThreadReceive may received messages from servers - void endCycleSAD() { } -private: - static unordered_map s_DetectedServers; -public: - static const int PARAMINDEX_PRECODE = 0; - static const int PARAMINDEX_SPITTASKID = 1; - static const int PARAMINDEX_NAME = 2; - static const int PARAMINDEX_ID = 3; - static const int PARAMINDEX_COMPUTERNAME = 4; - static const int PARAMINDEX_PORT = 5; - static const int PARAMINDEX_CLIENTIP = 6; - static const int PARAMINDEX_ADDITIONS = 7; - static const int PARAMINDEX_SERVERPROJECTNAME = 8; - static const int PARAMINDEX_IP = 9; - /** - * Used by SAD_Client to add a found SPITServer - don't use this manually - * @param p_IsIP4 true = the server is reached via a IP4 address
false = the server is reahed via a IP6 address - * @param p_ServerID the id of the server, every instance of a SPITServer has an own id - * @param p_ServerParams the server's parameter - */ - static void addDetectedServer(bool p_IsIP4, string p_ServerID, string p_ServerParams[]); - /** - * Used by SAD_Client to remove a SPITServer - don't use this manually - * @param p_DetectedServer - */ - static void removeDetectedServer(SAD_DetectedServer* p_DetectedServer); - /** - * Used by SAD_Client to clear all found SPITServers - don't use this manually - */ - static void clearDetectedServers(); - /** - * Used by SAD_Client internally - don't use this manually - */ - static void cycleStart(); - /** - * Used by SAD_Client internally -don't use this manually - * @param p_SADClientInterface - */ - static void cycleEnd(I_SAD_Client& p_SADClientInterface); + public: + string getID() const { return m_ID; } + string getName() const { return m_Name; } + string getComputerName() const { return m_ComputerName; } + string getIP() const { return m_IP; } + string getPort() const { return m_Port; } + string getClientIP() const { return m_ClientIP; } + string getAdditions() const { return m_Additions; } + string getProjectName() const { return m_ServerProjectName; } - /** - * Returns a reference of the DetectedServer with the id p_ServerID.
- * If no DetectedServer is found an eyception is thrown. - * @param p_ServerID the id of the SPITServer - * @return the reference of the SAD_DetectedServer instance with getID() == p_ServerID - */ - static const SAD_DetectedServer& getRefDetectedServer(string p_ServerID) { - SAD_DetectedServer* ptrDetectedServer = NULL; - { - auto i = s_DetectedServers.find(p_ServerID); - if (i != s_DetectedServers.end()) { - ptrDetectedServer = i->second; - } - if (ptrDetectedServer != NULL) { - return *ptrDetectedServer; - } + private: + void setID(string p_ID) { m_ID = p_ID; } + void setName(string p_Name) { m_Name = p_Name; } + void setComputerName(string p_ComputerName) { m_ComputerName = p_ComputerName; } + void setIP(string p_IP) { m_IP = p_IP; } + void setClientIP(string p_IP) { m_ClientIP = p_IP; } + void setPort(string p_Port) { m_Port = p_Port; } + void setAdditions(string p_Additions) { m_Additions = p_Additions; } + void setProjectName(string p_ServerProjectName); - throw new exception(); - } - } + bool getNew() const { return m_New; } + bool getChanged() const { return m_Changed; } + bool getFoundAgain() const { return m_FoundAgain; } + void setChanged() { m_Changed = true; } + void setNew(bool p_New) { m_New = p_New; } + void setFoundAgain() { m_FoundAgain = true; } + // SAD_Client m_ThreadSend will send to Multicast addresses + void startCycleSAD() { + m_Changed = false; + m_FoundAgain = false; + m_New = false; + } + + private: + static unordered_map s_DetectedServers; + + public: + static const int PARAMINDEX_PRECODE = 0; + static const int PARAMINDEX_SPITTASKID = 1; + static const int PARAMINDEX_NAME = 2; + static const int PARAMINDEX_ID = 3; + static const int PARAMINDEX_COMPUTERNAME = 4; + static const int PARAMINDEX_PORT = 5; + static const int PARAMINDEX_CLIENTIP = 6; + static const int PARAMINDEX_ADDITIONS = 7; + static const int PARAMINDEX_SERVERPROJECTNAME = 8; + static const int PARAMINDEX_IP = 9; + /** + * Used by SAD_Client to add a found SPITServer - don't use this manually + * @param p_IsIP4 true = the server is reached via a IP4 address
false = the server is reahed via a IP6 address + * @param p_ServerID the id of the server, every instance of a SPITServer has an own id + * @param p_ServerParams the server's parameter + */ + static void addDetectedServer(string p_ServerID, string p_ServerParams[]); + /** + * Used by SAD_Client to remove a SPITServer - don't use this manually + * @param p_DetectedServer + */ + static void removeDetectedServer(SAD_DetectedServer &server); + /** + * Used by SAD_Client to clear all found SPITServers - don't use this manually + */ + static void clearDetectedServers(); + /** + * Used by SAD_Client internally - don't use this manually + */ + static void cycleStart(); + /** + * Used by SAD_Client internally -don't use this manually + * @param p_SADClientInterface + */ + static void cycleEnd(I_SAD_Client &p_SADClientInterface); + + /** + * Returns a reference of the DetectedServer with the id p_ServerID.
+ * If no DetectedServer is found an eyception is thrown. + * @param p_ServerID the id of the SPITServer + * @return the reference of the SAD_DetectedServer instance with getID() == p_ServerID + */ + static const SAD_DetectedServer &getRefDetectedServer(string p_ServerID); }; - diff --git a/components/spit/include/SPITObject.h b/components/spit/include/SPITObject.h index 588a64b..8ae8232 100644 --- a/components/spit/include/SPITObject.h +++ b/components/spit/include/SPITObject.h @@ -4,7 +4,7 @@ * and open the template in the editor. */ -/* +/* * File: SPITObject.h * Author: Hagi * @@ -14,8 +14,8 @@ #ifndef SPITOBJECT_H #define SPITOBJECT_H -#include "SPIT_Message.h" #include "SPITType.h" +#include "SPIT_Message.h" #include #include @@ -24,153 +24,153 @@ using namespace std; class SPITObjectListener; class SPITObject { -private: - - static unordered_map s_SPITObjects; - static unordered_map s_SPITObjectsRemote; -public: - static SPITObject* getSPITObject(string p_ID); - static const SPITObject& getSPITObjectRef(string p_ID); - static bool addSPITObject(SPITObject* p_ptrSpitObject); - static bool removeSPITObject(SPITObject* p_ptrSpitObject); - static bool removeSPITObject(string p_SpitObjectID); - static int getSPITObjectCount(); - static SPITObject* getSPITObject(int p_Index); - static const SPITObject& getSPITObjectRef(int p_Index); - static void clearSPITObjects(); - static void clearUnconfirmedSPITObjects(); - static void setConfirmedFalse(); - - static SPITObject* getSPITObjectRemote(string p_ID); - static const SPITObject& getSPITObjectRemoteRef(string p_ID); - static bool addSPITObjectRemote(SPITObject* p_ptrSpitObject); - static bool removeSPITObjectRemote(SPITObject* p_ptrSpitObject); - static bool removeSPITObjectRemote(string p_SpitObjectID); - static int getSPITObjectRemoteCount(); - static SPITObject* getSPITObjectRemote(int p_Index); - static const SPITObject& getSPITObjectRemoteRef(int p_Index); - static void clearSPITObjectsRemote(); + private: + static unordered_map s_SPITObjects; + static unordered_map s_SPITObjectsRemote; - static void eventProjectClosed(); - - SPITObject(); -// SPITObject(const SPITObject& orig); - ~SPITObject(); -private: - string m_ID; - string m_Name; - string m_SPITTypeID; - string m_ServerParams; - string m_Remark; - bool m_Confirmed; - bool m_Fixed; - bool m_CreatedByClient; - bool m_ServerRemote; - bool m_ActionAssigned; - bool m_ActionAssignedType; //Virtual construct - long long m_FrameStart; - long long m_FrameLength; - long long m_FrameFadeInLength; - long long m_FrameFadeOutLength; - char m_ValueUse; - int m_ValueFactor; - int m_Track; - long long m_Delay; - long long m_Duration; - - bool m_PlayPrePosition; - long long m_PlayTimeInsideFrames; - int m_PlayValue; - char m_PlayValueFlag; - - - void initMembers(); -public: - string getID() const { return m_ID; } - string getName() const { return m_Name; } - string getRemark() const { return m_Remark; } - string getSPITTypeID() const { return m_SPITTypeID; } - string getServerParams() const { return m_ServerParams; } - - /** - * 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. - */ - bool getServerRemote() const { return m_ServerRemote; } - - /** - * 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 m_Confirmed; } - bool getFixed() const { return m_Fixed; } - bool getCreatedByClient() { return m_CreatedByClient; } - /** - * 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 SPITObject with the SPITType. - * @return true = an action is assigned for the SPITType. - */ - bool getActionAssignedType() const { return m_ActionAssignedType; } - /** Returns if this SPITObject has an associated action or not.
- * @return true = the user has asscociated an action with this SPITObject or
- * the user has asscociated an action with the SPITType of this SPITObject - */ - bool getActionAssigned() const { return m_ActionAssigned || m_ActionAssignedType; } - - long long getFrameStart() const { return m_FrameStart; } - // contains the length of the SPITObject - long long getFrameLength() const { return m_FrameLength; } - long long getFrameFadeInLength() const { return m_FrameFadeInLength; } - long long getFrameFadeOutLength() const { return m_FrameFadeOutLength; } - char getValueUse() const { return m_ValueUse; } - int getValueFactor() const { return m_ValueFactor; } - int getTrack() const { return m_Track; } + public: + static SPITObject *getSPITObject(string p_ID); + static const SPITObject &getSPITObjectRef(string p_ID); + static bool addSPITObject(SPITObject *p_ptrSpitObject); + static bool removeSPITObject(SPITObject *p_ptrSpitObject); + static bool removeSPITObject(string p_SpitObjectID); + static int getSPITObjectCount(); + static SPITObject *getSPITObject(int p_Index); + static const SPITObject &getSPITObjectRef(int p_Index); + static void clearSPITObjects(); + static void clearUnconfirmedSPITObjects(); + static void setConfirmedFalse(); - long long getDelay() const { return m_Delay; } - long long getDuration() const { return m_Duration; } - - bool getProjectIndepended() const { - SPITType* ptrSPITType; - if (m_ServerRemote == false) { - ptrSPITType = SPITType::getSPITType(m_SPITTypeID); - if (ptrSPITType == NULL) return true; - return ptrSPITType->getProjectIndepended(); - } - else { - ptrSPITType = SPITType::getSPITTypeRemote(m_SPITTypeID); - if (ptrSPITType == NULL) return true; - return ptrSPITType->getProjectIndepended(); - } - }; + static SPITObject *getSPITObjectRemote(string p_ID); + static const SPITObject &getSPITObjectRemoteRef(string p_ID); + static bool addSPITObjectRemote(SPITObject *p_ptrSpitObject); + static bool removeSPITObjectRemote(SPITObject *p_ptrSpitObject); + static bool removeSPITObjectRemote(string p_SpitObjectID); + static int getSPITObjectRemoteCount(); + static SPITObject *getSPITObjectRemote(int p_Index); + static const SPITObject &getSPITObjectRemoteRef(int p_Index); + static void clearSPITObjectsRemote(); - void setID(string p_ID); - bool setConfirmed(bool p_Confirmed); - void setCreatedByClient(bool p_CreatedByClient); - bool setName(string p_Name); - bool setRemark(string p_Remark); - bool setServerParams(string p_ServerParams); - bool setSPITTypeID(string p_GroupName); - bool setServerRemote(bool p_BelongstoServer); - bool setActionAssignedType(bool p_ActionAssigned); - bool setActionAssigned(bool p_ActionAssigned); - bool setFixed(bool p_Fixed); - bool setFrameStart(long long p_FrameStart); - bool setFrameLength(long long p_FrameLength); - bool setFrameFadeInLength(long long p_FrameFadeInLength); - bool setFrameFadeOutLength(long long p_FrameFadeOutLength); - bool setValueUse(char p_ValueUse); - bool setValueFactor(int p_ValueFactor); - bool setTrack(int p_Track); - bool setDelay(long long p_Delay); - bool setDuration(long long p_Duration); + static void eventProjectClosed(); - bool setMessageOP(SPIT_Message::ReportSPITObject* p_ReportSPITObject); - void fillMessageOP(SPIT_Message::ReportSPITObject* p_ReportSPITObject); - void fillMessageOP(SPIT_Message::RemoveSPITObject* p_RemoveSPITObject); + SPITObject(); + // SPITObject(const SPITObject& orig); + ~SPITObject(); + + private: + string m_ID; + string m_Name; + string m_SPITTypeID; + string m_ServerParams; + string m_Remark; + bool m_Confirmed; + bool m_Fixed; + bool m_CreatedByClient; + bool m_ServerRemote; + bool m_ActionAssigned; + bool m_ActionAssignedType; // Virtual construct + long long m_FrameStart; + long long m_FrameLength; + long long m_FrameFadeInLength; + long long m_FrameFadeOutLength; + char m_ValueUse; + int m_ValueFactor; + int m_Track; + long long m_Delay; + long long m_Duration; + + bool m_PlayPrePosition; + long long m_PlayTimeInsideFrames; + int m_PlayValue; + char m_PlayValueFlag; + + void initMembers(); + + public: + string getID() const { return m_ID; } + string getName() const { return m_Name; } + string getRemark() const { return m_Remark; } + string getSPITTypeID() const { return m_SPITTypeID; } + string getServerParams() const { return m_ServerParams; } + + /** + * 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. + */ + bool getServerRemote() const { return m_ServerRemote; } + + /** + * 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 m_Confirmed; } + bool getFixed() const { return m_Fixed; } + bool getCreatedByClient() { return m_CreatedByClient; } + /** + * 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 SPITObject with the SPITType. + * @return true = an action is assigned for the SPITType. + */ + bool getActionAssignedType() const { return m_ActionAssignedType; } + /** Returns if this SPITObject has an associated action or not.
+ * @return true = the user has asscociated an action with this SPITObject or
+ * the user has asscociated an action with the SPITType of this SPITObject + */ + bool getActionAssigned() const { return m_ActionAssigned || m_ActionAssignedType; } + + long long getFrameStart() const { return m_FrameStart; } + // contains the length of the SPITObject + long long getFrameLength() const { return m_FrameLength; } + long long getFrameFadeInLength() const { return m_FrameFadeInLength; } + long long getFrameFadeOutLength() const { return m_FrameFadeOutLength; } + char getValueUse() const { return m_ValueUse; } + int getValueFactor() const { return m_ValueFactor; } + int getTrack() const { return m_Track; } + + long long getDelay() const { return m_Delay; } + long long getDuration() const { return m_Duration; } + + bool getProjectIndepended() const { + SPITType *ptrSPITType; + if (m_ServerRemote == false) { + ptrSPITType = SPITType::getSPITType(m_SPITTypeID); + if (ptrSPITType == NULL) + return true; + return ptrSPITType->getProjectIndepended(); + } else { + ptrSPITType = SPITType::getSPITTypeRemote(m_SPITTypeID); + if (ptrSPITType == NULL) + return true; + return ptrSPITType->getProjectIndepended(); + } + }; + + void setID(string p_ID); + bool setConfirmed(bool p_Confirmed); + void setCreatedByClient(bool p_CreatedByClient); + bool setName(string p_Name); + bool setRemark(string p_Remark); + bool setServerParams(string p_ServerParams); + bool setSPITTypeID(string p_GroupName); + bool setServerRemote(bool p_BelongstoServer); + bool setActionAssignedType(bool p_ActionAssigned); + bool setActionAssigned(bool p_ActionAssigned); + bool setFixed(bool p_Fixed); + bool setFrameStart(long long p_FrameStart); + bool setFrameLength(long long p_FrameLength); + bool setFrameFadeInLength(long long p_FrameFadeInLength); + bool setFrameFadeOutLength(long long p_FrameFadeOutLength); + bool setValueUse(char p_ValueUse); + bool setValueFactor(int p_ValueFactor); + bool setTrack(int p_Track); + bool setDelay(long long p_Delay); + bool setDuration(long long p_Duration); + + bool setMessageOP(SPIT_Message::ReportSPITObject *p_ReportSPITObject); + void fillMessageOP(SPIT_Message::ReportSPITObject *p_ReportSPITObject); + void fillMessageOP(SPIT_Message::RemoveSPITObject *p_RemoveSPITObject); }; - #endif /* SPITOBJECT_H */ - diff --git a/components/spit/include/SPITPlayer.h b/components/spit/include/SPITPlayer.h index 94f4e53..1b74a00 100644 --- a/components/spit/include/SPITPlayer.h +++ b/components/spit/include/SPITPlayer.h @@ -4,7 +4,7 @@ * and open the template in the editor. */ -/* +/* * File: SPITPLayer.h * Author: Hagi * @@ -18,79 +18,77 @@ #include class SPITPlayer { - -//----- PlayObject used in PlaySequences: PlaySPITStart, PlaySPITObject,..., PlaySPITEnd ------ -public: - class PlaySPITType { - public: - PlaySPITType(); - PlaySPITType(SPITPlayer* p_SPITPlayer, string p_SPITObjectID); - PlaySPITType(const PlaySPITType& orig); - - string getSPITTypeID() const { - return m_SPITTypeID; - } - - void startPlaySequence(); - bool getIsNew() const { return m_IsNew; } - void setIsNew(bool p_IsNew) { m_IsNew = p_IsNew; } - bool getIsPlayed() const { return m_IsPlayed; } - void setIsPlayed(bool p_IsFound) { m_IsPlayed = p_IsFound; } - string getPlayerID() const { return m_PlayerID; } - string getPlayerName() const { return m_PlayerName; } - bool getPlayerIsRunning() const { return m_PlayerRuns; } - void setPlayerIsRunning(bool p_PlayerRuns) { m_PlayerRuns = p_PlayerRuns; } - void setValue(double p_Value) { m_Value = p_Value; } - void addValue(double p_Value, double p_ValueFactor) { m_Value += (p_Value * p_ValueFactor); } - double getValue() const { return m_Value; } - - private: - string m_PlayerID; - string m_PlayerName; - bool m_PlayerRuns; - string m_SPITTypeID; - bool m_IsPlayed; - bool m_IsNew; - double m_Value; - }; - -//----- SPITPlayer ------ -public: - //list the SPITPlayers - static unordered_map s_SPITPlayers; //all actual played objects - static SPITPlayer* getSPITPlayer(string p_PlayerID); //if a player does not exist creates a new one - static void clearPlayers(); - - SPITPlayer(string p_PlayerID); - virtual ~SPITPlayer(); - - - void startPlaySequence(); //called by SPIT_Client::parsePlaySPITStart - PlaySPITType* addSPITType_Playing (string p_SPITTypeID); //called by SPIT_Client::parsePlaySPITStart - void endPlaySequence(); //called by SPIT_Client::parsePlaySPITEnd - string getID() { - return m_ID; - } - - unordered_map* getPlaySPITTypes(); - void setIsRunning(bool p_IsRunning); - bool getIsRunning() { return m_IsRunning; } - void setName(string p_Name); - string getName() { return m_Name; } - void setType(char p_Type); - char getType() { return m_Type; } - void setTime(long long p_Frames); - long long getTime() { return m_TimeFrames; } - -private: - string m_ID; - string m_Name; - char m_Type; - unordered_map m_PlaySPITTypes; - bool m_IsRunning; - long long m_TimeFrames; + //----- PlayObject used in PlaySequences: PlaySPITStart, PlaySPITObject,..., PlaySPITEnd ------ + public: + class PlaySPITType { + public: + PlaySPITType(); + PlaySPITType(SPITPlayer *p_SPITPlayer, string p_SPITObjectID); + PlaySPITType(const PlaySPITType &orig); + + string getSPITTypeID() const { + return m_SPITTypeID; + } + + void startPlaySequence(); + bool getIsNew() const { return m_IsNew; } + void setIsNew(bool p_IsNew) { m_IsNew = p_IsNew; } + bool getIsPlayed() const { return m_IsPlayed; } + void setIsPlayed(bool p_IsFound) { m_IsPlayed = p_IsFound; } + string getPlayerID() const { return m_PlayerID; } + string getPlayerName() const { return m_PlayerName; } + bool getPlayerIsRunning() const { return m_PlayerRuns; } + void setPlayerIsRunning(bool p_PlayerRuns) { m_PlayerRuns = p_PlayerRuns; } + void setValue(double p_Value) { m_Value = p_Value; } + void addValue(double p_Value, double p_ValueFactor) { m_Value += (p_Value * p_ValueFactor); } + double getValue() const { return m_Value; } + + private: + string m_PlayerID; + string m_PlayerName; + bool m_PlayerRuns; + string m_SPITTypeID; + bool m_IsPlayed; + bool m_IsNew; + double m_Value; + }; + + //----- SPITPlayer ------ + public: + // list the SPITPlayers + static unordered_map s_SPITPlayers; // all actual played objects + static SPITPlayer *getSPITPlayer(string p_PlayerID); // if a player does not exist creates a new one + static void clearPlayers(); + + SPITPlayer(string p_PlayerID); + virtual ~SPITPlayer(); + + void startPlaySequence(); // called by SPIT_Client::parsePlaySPITStart + PlaySPITType *addSPITType_Playing(string p_SPITTypeID); // called by SPIT_Client::parsePlaySPITStart + void endPlaySequence(); // called by SPIT_Client::parsePlaySPITEnd + + string getID() { + return m_ID; + } + + unordered_map *getPlaySPITTypes(); + void setIsRunning(bool p_IsRunning) { m_IsRunning = p_IsRunning; } + void setName(string p_Name) { m_Name = p_Name; } + void setType(char p_Type) { m_Type = p_Type; } + void setTime(long long p_Frames) { m_TimeFrames = p_Frames; } + bool getIsRunning() { return m_IsRunning; } + string getName() { return m_Name; } + char getType() { return m_Type; } + long long getTime() { return m_TimeFrames; } + + private: + string m_ID; + string m_Name; + char m_Type; + unordered_map m_PlaySPITTypes; + bool m_IsRunning; + long long m_TimeFrames; }; #endif /* SPITPLAYER_H */ - diff --git a/components/spit/include/SPITSocket.h b/components/spit/include/SPITSocket.h index 4bbfcf2..189ddda 100644 --- a/components/spit/include/SPITSocket.h +++ b/components/spit/include/SPITSocket.h @@ -4,7 +4,7 @@ * and open the template in the editor. */ -/* +/* * SPITSocket is the base class for WindowsSocket, UnixSocket,. * Used by SPIT_Client and SAD_Client. * File: SPITSocket.h @@ -16,17 +16,17 @@ #ifndef SPITSOCKET_H #define SPITSOCKET_H -#include -#include "esp_netif.h" -#include -#include -#include -#include -#include -#include -#include #include "Task.hpp" #include "esp_log.h" +#include "esp_netif.h" +#include +#include +#include +#include +#include +#include +#include +#include using namespace std; @@ -35,133 +35,132 @@ string createGUID(); /** Returns the name of the client's host computer*/ string getClientHostName(); -class SPITSocket{ - public: - static const int FAMILY_IP4 = AF_INET; +class SPITSocket { + public: + static const int FAMILY_IP4 = AF_INET; - /** - * IPAddress class is used to fetch all available IP addresses of the computer - * This is for internal usage - */ - struct IPAddress { - public: - IPAddress(const string& p_IPAddress, const string& p_SubnetMask) - : m_IPAddress(p_IPAddress), m_SubnetMask(p_SubnetMask) { } - const string m_IPAddress; - const string m_SubnetMask; + /** + * IPAddress class is used to fetch all available IP addresses of the computer + * This is for internal usage + */ + struct IPAddress { + public: + IPAddress(const string &p_IPAddress, const string &p_SubnetMask) + : m_IPAddress(p_IPAddress), m_SubnetMask(p_SubnetMask) {} + const string m_IPAddress; + const string m_SubnetMask; - /** - * Calculates the broadcast address from a ip4 address - * @param p_IPAddress the ip4 address - * @return returns the broadcast address - */ - string getBroadcastIP4() const { - struct in_addr broadcast; - unsigned long ulIPAddress; - unsigned long ulSubnetMask; + /** + * Calculates the broadcast address from a ip4 address + * @param p_IPAddress the ip4 address + * @return returns the broadcast address + */ + string getBroadcastIP4() const { + struct in_addr broadcast; + unsigned long ulIPAddress; + unsigned long ulSubnetMask; - ulIPAddress = inet_addr(m_IPAddress.data()); - ulSubnetMask = inet_addr(m_SubnetMask.data()); - broadcast.s_addr = ulIPAddress | ~ulSubnetMask; + ulIPAddress = inet_addr(m_IPAddress.data()); + ulSubnetMask = inet_addr(m_SubnetMask.data()); + broadcast.s_addr = ulIPAddress | ~ulSubnetMask; - return inet_ntoa(broadcast); - } - }; - const IPAddress mOwnIp; - static IPAddress getAdaptersInfo(); - bool createSocket_UDP(); - static const int INVALID_SOCKET = -1; + return inet_ntoa(broadcast); + } + }; + const IPAddress mOwnIp; + static IPAddress getAdaptersInfo(); + bool createSocket_UDP(); + static const int INVALID_SOCKET = -1; -private: - int m_UDPSocketIP4; + private: + int m_UDPSocketIP4; -public: - //-------- class -------------- - SPITSocket(IPAddress ip) : mOwnIp(ip) { - m_UDPSocketIP4 = INVALID_SOCKET; - - m_ServerIP = ""; - m_ServerPort = ""; - m_ClientIP = ""; - m_ClientPort = ""; - m_BoundClientPort = ""; - m_BoundClientFamily = 0; - m_IsBound = false; - createSocket_UDP(); + public: + //-------- class -------------- + SPITSocket(IPAddress ip) : mOwnIp(ip) { + m_UDPSocketIP4 = INVALID_SOCKET; - } - virtual ~SPITSocket() { - ESP_LOGD("UDP", "Shutting down ..."); - - if (m_UDPSocketIP4 != INVALID_SOCKET) { - shutdown(m_UDPSocketIP4, 2); - close(m_UDPSocketIP4); - m_UDPSocketIP4 = INVALID_SOCKET; - } - fos::Task::delayMs(100); + m_ServerIP = ""; + m_ServerPort = ""; + m_ClientIP = ""; + m_ClientPort = ""; + m_BoundClientPort = ""; + m_BoundClientFamily = 0; m_IsBound = false; - } -private: - string m_ServerIP; - string m_ServerPort; - string m_ClientIP; - string m_ClientPort; //port given by the user maybe "0" - string m_BoundClientPort; //port set after bind - int m_BoundClientFamily; - bool m_IsBound; + createSocket_UDP(); + } + virtual ~SPITSocket() { + ESP_LOGD("UDP", "Shutting down ..."); -public: - /** - * Sets the ip address and port for server and client. - * @param p_ServerIP - * @param p_ServerPort - * @param p_ClientIP - * @param p_ClientPort - */ - void setConnectionParams(string p_ServerIP, string p_ServerPort, string p_ClientIP, string p_ClientPort) { - m_ServerIP = p_ServerIP; - m_ServerPort = p_ServerPort; - m_ClientIP = p_ClientIP; - m_ClientPort = p_ClientPort; - } - - /** - * Send a message to the server as set by setConnectionParams - * @param p_MessageBytes byte buffer containing the message - * @param p_MessageLength length of the messaeg - * @return - */ - int sendMessage(const char* p_MessageBytes, int p_MessageLength) { - if (m_ServerPort.length() <= 0) - return -1; - int intResult; - { - if (m_IsBound == false) - return -1; - intResult = sendMessageTo(m_BoundClientFamily, m_ServerIP, m_ServerPort, p_MessageBytes, p_MessageLength); - } - return intResult; - } + if (m_UDPSocketIP4 != INVALID_SOCKET) { + shutdown(m_UDPSocketIP4, 2); + close(m_UDPSocketIP4); + m_UDPSocketIP4 = INVALID_SOCKET; + } + fos::Task::delayMs(100); + m_IsBound = false; + } - int receiveMessage(int p_InetFamily, char* p_Buffer, int p_BufferLength, string* p_ServerIP); - int setBroadcast(bool p_Broadcast); - int bindSocket(string p_ServerIP, string p_ClientIP, string p_ClientPort); - - // * Internal usage - don't use this manually - // * Use sendMessage instead - int sendMessageTo(int p_InetFamily, string p_ServerIP, string p_Port, const char* p_MessageBytes, int p_MessageLength); - - string getServerIP() { return m_ServerIP; } - string getServerPort(){ return m_ServerPort; } - string getClientIP() { return m_ClientIP; } - string getClientPort() { return m_ClientPort; } - string getBoundClientPort() { return m_BoundClientPort; } - void setBoundClientPort(string p_Port) { m_BoundClientPort = p_Port; } - void setBoundClientFamily(int p_Family) { m_BoundClientFamily = p_Family; } - int getBoundClientFamily() { return m_BoundClientFamily; } - void setIsBound(bool p_IsBound) { m_IsBound = p_IsBound; } - bool getIsBound() { return m_IsBound; } + private: + string m_ServerIP; + string m_ServerPort; + string m_ClientIP; + string m_ClientPort; // port given by the user maybe "0" + string m_BoundClientPort; // port set after bind + int m_BoundClientFamily; + bool m_IsBound; + + public: + /** + * Sets the ip address and port for server and client. + * @param p_ServerIP + * @param p_ServerPort + * @param p_ClientIP + * @param p_ClientPort + */ + void setConnectionParams(string p_ServerIP, string p_ServerPort, string p_ClientIP, string p_ClientPort) { + m_ServerIP = p_ServerIP; + m_ServerPort = p_ServerPort; + m_ClientIP = p_ClientIP; + m_ClientPort = p_ClientPort; + } + + /** + * Send a message to the server as set by setConnectionParams + * @param p_MessageBytes byte buffer containing the message + * @param p_MessageLength length of the messaeg + * @return + */ + int sendMessage(const char *p_MessageBytes, int p_MessageLength) { + if (m_ServerPort.length() <= 0) + return -1; + int intResult; + { + if (m_IsBound == false) + return -1; + intResult = sendMessageTo(m_BoundClientFamily, m_ServerIP, m_ServerPort, p_MessageBytes, p_MessageLength); + } + return intResult; + } + + int receiveMessage(int p_InetFamily, char *p_Buffer, int p_BufferLength, string *p_ServerIP); + int setBroadcast(bool p_Broadcast); + int bindSocket(string p_ServerIP, string p_ClientIP, string p_ClientPort); + + // * Internal usage - don't use this manually + // * Use sendMessage instead + int sendMessageTo(int p_InetFamily, string p_ServerIP, string p_Port, const char *p_MessageBytes, int p_MessageLength); + + string getServerIP() { return m_ServerIP; } + string getServerPort() { return m_ServerPort; } + string getClientIP() { return m_ClientIP; } + string getClientPort() { return m_ClientPort; } + string getBoundClientPort() { return m_BoundClientPort; } + void setBoundClientPort(string p_Port) { m_BoundClientPort = p_Port; } + void setBoundClientFamily(int p_Family) { m_BoundClientFamily = p_Family; } + int getBoundClientFamily() { return m_BoundClientFamily; } + void setIsBound(bool p_IsBound) { m_IsBound = p_IsBound; } + bool getIsBound() { return m_IsBound; } }; #endif /* SPITSOCKET_H */ - diff --git a/components/spit/include/SPITType.h b/components/spit/include/SPITType.h index 4d436fe..6d27d91 100644 --- a/components/spit/include/SPITType.h +++ b/components/spit/include/SPITType.h @@ -4,7 +4,7 @@ * and open the template in the editor. */ -/* +/* * File: SPITType.h * Author: Hagi * @@ -24,119 +24,117 @@ using namespace std; class SPITTypeListener; class SPITType { -private: - static unordered_map s_SPITTypes; - static unordered_map s_SPITTypesRemote; - -public: - static SPITType* getSPITType(string p_ID); - static const SPITType& getSPITTypeRef(string p_ID); - static bool addSPITType(SPITType* p_ptrSpitType); - static bool removeSPITType(SPITType* p_ptrSpitType); - static int getSPITTypeCount(); - static SPITType* getSPITType(int p_Index); - static const SPITType& getSPITTypeRef(int p_Index); - static void clearSPITTypes(); - static void setConfirmedFalse(); + private: + static unordered_map s_SPITTypes; + static unordered_map s_SPITTypesRemote; - static SPITType* getSPITTypeRemote(string p_ID); - static const SPITType& getSPITTypeRemoteRef(string p_ID); - static bool addSPITTypeRemote(SPITType* p_ptrSpitType); - static bool removeSPITTypeRemote(SPITType* p_ptrSpitType); - static int getSPITTypeRemoteCount(); - static SPITType* getSPITTypeRemote(int p_Index); - static const SPITType& getSPITTypeRemoteRef(int p_Index); - static void clearSPITTypesRemote(); - - static void eventProjectClosed(); - - SPITType(); - SPITType(string p_ID, string p_GroupName, string p_Name, bool p_Fixed, bool p_ProjectIndepended,long long p_DefaultDelay, long long p_DefaultDuration); -// SPITType(const SPITType& orig); - ~SPITType(); -private: - - bool m_Confirmed; - string m_ID; - bool m_Fixed; - bool m_ServerRemote; - bool m_ServerProjectIndepended; - string m_GroupName; - string m_Name; - long long m_DefaultDelay; - long long m_DefaultDuration; - - bool m_CreatedByClient; //flag true = the SPITTyype is created by the client - //false = the SPITType is received from the server - - bool m_ActionAssigned; //This is a virtual flag if user associates an action with a SPITType. - //Can be used to setActionAssigned for all SPITObjects with this SPITType - - void initMembers(); - -public: - string getID() const{ return m_ID; } - string getGroupName() const { return m_GroupName; } - string getName() const { return m_Name; } - /** - * 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. - */ - bool getServerRemote() const { - return m_ServerRemote; - } - - bool getProjectIndepended() const { - return m_ServerProjectIndepended; - } - /** - * 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 m_Confirmed; } - bool getFixed() const { return m_Fixed; } - long long getDefaultDelay() const { return m_DefaultDelay; } - long long getDefaultDuration() const { return m_DefaultDuration; } - bool getCreatedByClient() const { return m_CreatedByClient; } - - /** - * 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.
- * @return true = the user has associated an action with this SPITType. - */ - bool getActionAssigned() const { - return m_ActionAssigned; - } - - -public: - void setID(string p_ID); - bool setGroupName(string p_GroupName); - bool setName(string p_Name); - bool setServerRemote(bool p_BelongstoServer); - bool setProjectIndepended(bool p_ProjectIndepeneded); - bool setConfirmed(bool p_Confirmed); - bool setFixed(bool p_Fixed); - bool setDefaultDelay(long long p_Delay); - bool setDefaultDuration(long long p_Duration); - - void setCreatedByClient(bool p_CreatedByClient); - - /** - * 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.
- * @return true = the m_ActionAssigned has changed. - */ - bool setActionAssigned(bool p_ActionAssigned); - - bool setMessageOP(SPIT_Message::ReportSPITType* p_ReportSPITType); - void fillMessageOP(SPIT_Message::ReportSPITType* p_ReportSPITType); - void fillMessageOP(SPIT_Message::RemoveSPITType* p_RemoveSPITType); -// static char* stringCopy(const char* p_String); + public: + static SPITType *getSPITType(string p_ID); + static const SPITType &getSPITTypeRef(string p_ID); + static bool addSPITType(SPITType *p_ptrSpitType); + static bool removeSPITType(SPITType *p_ptrSpitType); + static int getSPITTypeCount(); + static SPITType *getSPITType(int p_Index); + static const SPITType &getSPITTypeRef(int p_Index); + static void clearSPITTypes(); + static void setConfirmedFalse(); + + static SPITType *getSPITTypeRemote(string p_ID); + static const SPITType &getSPITTypeRemoteRef(string p_ID); + static bool addSPITTypeRemote(SPITType *p_ptrSpitType); + static bool removeSPITTypeRemote(SPITType *p_ptrSpitType); + static int getSPITTypeRemoteCount(); + static SPITType *getSPITTypeRemote(int p_Index); + static const SPITType &getSPITTypeRemoteRef(int p_Index); + static void clearSPITTypesRemote(); + + static void eventProjectClosed(); + + SPITType(); + SPITType(string p_ID, string p_GroupName, string p_Name, bool p_Fixed, bool p_ProjectIndepended, long long p_DefaultDelay, long long p_DefaultDuration); + // SPITType(const SPITType& orig); + ~SPITType(); + + private: + bool m_Confirmed; + string m_ID; + bool m_Fixed; + bool m_ServerRemote; + bool m_ServerProjectIndepended; + string m_GroupName; + string m_Name; + long long m_DefaultDelay; + long long m_DefaultDuration; + + bool m_CreatedByClient; // flag true = the SPITTyype is created by the client + // false = the SPITType is received from the server + + bool m_ActionAssigned; // This is a virtual flag if user associates an action with a SPITType. + // Can be used to setActionAssigned for all SPITObjects with this SPITType + + void initMembers(); + + public: + string getID() const { return m_ID; } + string getGroupName() const { return m_GroupName; } + string getName() const { return m_Name; } + /** + * 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. + */ + bool getServerRemote() const { + return m_ServerRemote; + } + + bool getProjectIndepended() const { + return m_ServerProjectIndepended; + } + /** + * 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 m_Confirmed; } + bool getFixed() const { return m_Fixed; } + long long getDefaultDelay() const { return m_DefaultDelay; } + long long getDefaultDuration() const { return m_DefaultDuration; } + bool getCreatedByClient() const { return m_CreatedByClient; } + + /** + * 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.
+ * @return true = the user has associated an action with this SPITType. + */ + bool getActionAssigned() const { + return m_ActionAssigned; + } + + public: + void setID(string p_ID); + bool setGroupName(string p_GroupName); + bool setName(string p_Name); + bool setServerRemote(bool p_BelongstoServer); + bool setProjectIndepended(bool p_ProjectIndepeneded); + bool setConfirmed(bool p_Confirmed); + bool setFixed(bool p_Fixed); + bool setDefaultDelay(long long p_Delay); + bool setDefaultDuration(long long p_Duration); + + void setCreatedByClient(bool p_CreatedByClient); + + /** + * 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.
+ * @return true = the m_ActionAssigned has changed. + */ + bool setActionAssigned(bool p_ActionAssigned); + + bool setMessageOP(SPIT_Message::ReportSPITType *p_ReportSPITType); + void fillMessageOP(SPIT_Message::ReportSPITType *p_ReportSPITType); + void fillMessageOP(SPIT_Message::RemoveSPITType *p_RemoveSPITType); + // static char* stringCopy(const char* p_String); }; - #endif /* SPITTYPE_H */ \ No newline at end of file diff --git a/components/spit/include/SPIT_Client.h b/components/spit/include/SPIT_Client.h index bf065b7..fd72916 100644 --- a/components/spit/include/SPIT_Client.h +++ b/components/spit/include/SPIT_Client.h @@ -4,7 +4,7 @@ * and open the template in the editor. */ -/* +/* * File: SPIT_Client.h * Author: Hagi * @@ -14,12 +14,12 @@ #ifndef SPIT_CLIENT_H #define SPIT_CLIENT_H -#include "SPITSocket.h" #include "SAD_DetectedServer.hpp" -#include "SPIT_Message.h" -#include "SPITType.h" #include "SPITObject.h" #include "SPITPlayer.h" +#include "SPITSocket.h" +#include "SPITType.h" +#include "SPIT_Message.h" #include #include @@ -27,316 +27,327 @@ using namespace std; class SPIT_Client : I_SAD_Client { -public: - /** Maximal length of a SPITMessage*/ - static const int MAXSPITMESSAGEBYTECOUNT = 512; - - enum ServerEvent { - Detect, - Lost, - Changed, - }; + public: + /** Maximal length of a SPITMessage*/ + static const int MAXSPITMESSAGEBYTECOUNT = 512; - struct Callbacks { - void(*onServerEvent)(ServerEvent event, const SAD_DetectedServer &p_DetectedServer); - void(*onConnectionStatus)(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, int p_ConnectionStatus, int p_OldConnectionStatus); - void(*onStartProjectTransfer)(); - void(*onEndProjectTransfer)(); - void(*onProjectClosed)(string); - void(*onProjectReport)(string p_ProjectID, string p_ProjectName, int p_FramesPerSeoond); - void(*onSpitType)(bool p_New, const SPITType &p_SPITType); - void(*onSpitTypeRemote)(bool p_New, const SPITType &p_SPITType); - void(*onSpitObject)(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject); - void(*onSpitObjectRemote)(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject); - void(*onSpitTypeRemoved)(const SPITType &p_SPITType); - void(*onSpitTypeRemoteRemoved)(const SPITType &p_SPITType); - void(*onSpitObjectRemoved)(const SPITType &p_SPITType, const SPITObject &p_SPITObject); - void(*onSpitObjectRemoteRemoved)(const SPITType &p_SPITType, const SPITObject &p_SPITObject); - void(*onPlay)(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames); - void(*onPlaySpitType)(string p_PlayerID, string p_SPITTypeID, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value); - void(*onPlayRemoteObjectStatus)(const SPITType &p_SPITType, const SPITObject &p_SPITObject, long long p_FrameInsideObject, int p_Value); - bool(*onCheckSpitTypeVeto)(SPIT_Message::ReportSPITType* p_ReportSPITType); - bool(*onCheckSpitObjectVeto)(SPIT_Message::ReportSPITObject* p_ReportSPITObject); - }; + enum class ProjUpdate { + ServerLoaded, + StartTransfer, + EndTransfer, + ServerClosed, + }; + enum class ServerEvent { + Detect, + Lost, + Changed, + }; + enum class ObjectEvent { + Created, + Changed, + Deleted + }; -//----- Connection Status ----- -public: - /** No Connection established.
Either no connect tried or disconnected*/ - static const int CONNECTION_NONE = 0; - /** Server has disconnected*/ - static const int CONNECTION_NONESERVER = 1; - /** The connection is lost
Either because of a network crash or because the server no longer responds.*/ - static const int CONNECTION_LOST = 2; - /** Connection to the serv er is established.*/ - static const int CONNECTION_OK = 3; - /** A connection to the server is tried.*/ - static const int CONNECTION_TRYCONNECTION = 4; - -//------ PlayerType ------ -public: - /** continous main player, time value can be used like a timecode.
The time value is the position in server's project.
A server should use only one main player.*/ - static const char PLAYERTYPE_MAIN = 0x02; - /** continous player. This player plays SPIT objects sometime during the project.*/ - static const char PLAYERTYPE_CONTINOUS = 0x01; - /** diescrete player. This player is used to transmit single discrete values.*/ - static const char PLAYERTYPE_DISCRETE = 0x00; + struct Callbacks { + void (*onServerEvent)(ServerEvent event, const SAD_DetectedServer &p_DetectedServer){}; + void (*onConnectionStatus)(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, int p_ConnectionStatus, int p_OldConnectionStatus){}; + void (*onProjectUpdate)(ProjUpdate state, string projectId){}; -//------ Value Flag ------ -//------ used by sendRemoteObject -public: - /**Set the given value directly*/ - static const char VALUEFLAG_DIRECT = 0x00; - /**Increase the existing value by the given value.
This is usefull e.g. when instead of a fader a endless wheel is used*/ - static const char VALUEFLAG_INCREASE = 0x01; - /**Decrease the existing value by the given value.
This is usefull e.g. when instead of a fader a endless wheel is used*/ - static const char VALUEFLAG_DECREASE = 0x02; + void (*onSpitType)(ObjectEvent event, const SPITType &p_SPITType){}; + void (*onSpitTypeRemote)(ObjectEvent event, const SPITType &p_SPITType){}; + void (*onSpitObject)(ObjectEvent event, const SPITType &p_SPITType, const SPITObject &p_SPITObject){}; + void (*onSpitObjectRemote)(ObjectEvent event, const SPITType &p_SPITType, const SPITObject &p_SPITObject){}; -//----- SPIT_Client ----- -public: - SPIT_Client(string name, string projName, Callbacks calls); - virtual ~SPIT_Client(); - static int s_MAX_OVERTAKING_SPIT_MESSAGES; -private: - Callbacks mCallbacks; + void (*onPlay)(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames){}; + void (*onPlaySpitType)(string p_PlayerID, string p_SPITTypeID, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value){}; + void (*onPlayRemoteObjectStatus)(const SPITType &p_SPITType, const SPITObject &p_SPITObject, long long p_FrameInsideObject, int p_Value){}; + bool (*onCheckSpitTypeVeto)(SPIT_Message::ReportSPITType *p_ReportSPITType){}; + bool (*onCheckSpitObjectVeto)(SPIT_Message::ReportSPITObject *p_ReportSPITObject){}; + }; - fos::TaskT * m_ThreadReceive{}; - bool m_StopReceiveSPITMessages; + //----- Connection Status ----- + public: + /** No Connection established.
Either no connect tried or disconnected*/ + static const int CONNECTION_NONE = 0; + /** Server has disconnected*/ + static const int CONNECTION_NONESERVER = 1; + /** The connection is lost
Either because of a network crash or because the server no longer responds.*/ + static const int CONNECTION_LOST = 2; + /** Connection to the serv er is established.*/ + static const int CONNECTION_OK = 3; + /** A connection to the server is tried.*/ + static const int CONNECTION_TRYCONNECTION = 4; - int m_ConnectionStatus; - bool m_DisconnectedByServer{}; //flag true = when server disconnects - string m_ID; - string m_Name; - string m_ProjName; - string m_ComputerName; + //------ PlayerType ------ + public: + /** continous main player, time value can be used like a timecode.
The time value is the position in server's project.
A server should use only one main player.*/ + static const char PLAYERTYPE_MAIN = 0x02; + /** continous player. This player plays SPIT objects sometime during the project.*/ + static const char PLAYERTYPE_CONTINOUS = 0x01; + /** diescrete player. This player is used to transmit single discrete values.*/ + static const char PLAYERTYPE_DISCRETE = 0x00; - string m_ClientProjectName; - - unsigned char m_MessageNumber_Send; - int m_MessageNumber_Received; - vector m_OvertakingSPIT_Messages; + //------ Value Flag ------ + //------ used by sendRemoteObject + public: + /**Set the given value directly*/ + static const char VALUEFLAG_DIRECT = 0x00; + /**Increase the existing value by the given value.
This is usefull e.g. when instead of a fader a endless wheel is used*/ + static const char VALUEFLAG_INCREASE = 0x01; + /**Decrease the existing value by the given value.
This is usefull e.g. when instead of a fader a endless wheel is used*/ + static const char VALUEFLAG_DECREASE = 0x02; - //Server's info filled by parseConnectAnswer - string m_ServerID{}; - string m_ServerName{}; - string m_ServerComputerName{}; - int m_ServerStepTime{-1}; - - //--- Server Project --- - string m_ServerProjectID; - string m_ServerProjectName; - int m_ServerFramesPerSecond; - -public: - /** The ID of the client.
Every client instance should set an unique id*/ - string getID() { return m_ID; } - /** The name of the client, should be set by the user app*/ - string getName() { return m_Name; } - //----- Computer Params ----- - /** The name of the client's host computer*/ - string getComputerName() { return m_ComputerName; } - void setClientProjectName(string p_ClientProjectName) { m_ClientProjectName = p_ClientProjectName; } - string getClientProjectName() { return m_ClientProjectName; } + //----- SPIT_Client ----- + public: + SPIT_Client(string name, string projName, Callbacks calls); + virtual ~SPIT_Client(); + static int s_MAX_OVERTAKING_SPIT_MESSAGES; - //connected Server Infos - /** The ID of the connected SPITServer*/ - string getServerID() { return m_ServerID; } - /** The host computername of the connected SPITServer*/ - string getServerComputerName() { return m_ServerComputerName; } - /** The name of the connected SPITServer*/ - string getServerName() { return m_ServerName; } + private: + Callbacks mCallbacks; - /** Expected Refreah Rate of the connectd SPITServer.
- * When the server plays objects, it will do so at discrete time steps.
- * Play events will take place in these time steps.. - */ - int getServerStepTime() { return m_ServerStepTime; } - - /** 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(); - - /** - * - * @param p_SPITTypeID - * @param p_ActionAssigned - */ - void setActionSPITType(string p_SPITTypeID, bool p_ActionAssigned); - void setActionSPITObject(string p_SPITObjectID, bool p_ActionAssigned); - -//--------------- SPITMessage --------------- -private: - bool startReceiveSPITMessages(); - void stopReceiveSPITMessages(); - static void receiveSPITMessage(SPIT_Client& rM); - // Reconnect to the server when connection is lost see eventConnectionStatus and eventServerDetected + fos::TaskT *m_ThreadReceive{}; + bool m_StopReceiveSPITMessages; + + int m_ConnectionStatus; + bool m_DisconnectedByServer{}; // flag true = when server disconnects + string m_ID; + string m_Name; + string m_ProjName; + string m_ComputerName; + + string m_ClientProjectName; + + unsigned char m_MessageNumber_Send; + int m_MessageNumber_Received; + vector m_OvertakingSPIT_Messages; + + // Server's info filled by parseConnectAnswer + string m_ServerID{}; + string m_ServerName{}; + string m_ServerComputerName{}; + int m_ServerStepTime{-1}; + + //--- Server Project --- + string m_ServerProjectID; + string m_ServerProjectName; + int m_ServerFramesPerSecond; + + public: + /** The ID of the client.
Every client instance should set an unique id*/ + string getID() { return m_ID; } + /** The name of the client, should be set by the user app*/ + string getName() { return m_Name; } + //----- Computer Params ----- + /** The name of the client's host computer*/ + string getComputerName() { return m_ComputerName; } + void setClientProjectName(string p_ClientProjectName) { m_ClientProjectName = p_ClientProjectName; } + string getClientProjectName() { return m_ClientProjectName; } + + // connected Server Infos + /** The ID of the connected SPITServer*/ + string getServerID() { return m_ServerID; } + /** The host computername of the connected SPITServer*/ + string getServerComputerName() { return m_ServerComputerName; } + /** The name of the connected SPITServer*/ + string getServerName() { return m_ServerName; } + + /** Expected Refreah Rate of the connectd SPITServer.
+ * When the server plays objects, it will do so at discrete time steps.
+ * Play events will take place in these time steps.. + */ + int getServerStepTime() { return m_ServerStepTime; } + + /** 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(); + + /** + * + * @param p_SPITTypeID + * @param p_ActionAssigned + */ + void setActionSPITType(string p_SPITTypeID, bool p_ActionAssigned); + void setActionSPITObject(string p_SPITObjectID, bool p_ActionAssigned); + + //--------------- SPITMessage --------------- + private: + bool startReceiveSPITMessages(); + void stopReceiveSPITMessages(); + static void receiveSPITMessage(SPIT_Client &rM); + // Reconnect to the server when connection is lost see eventConnectionStatus and eventServerDetected bool _doReconnect{}; // true = on eventServerDetected connect to the server identified by m_ServerID -public: - void fillHeader(SPIT_Message::Header* p_Header); - int sendSPITMessage(SPIT_Message::OPPart& p_SPITMessageOPPart); + public: + void fillHeader(SPIT_Message::Header *p_Header); + int sendSPITMessage(SPIT_Message::OPPart &p_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(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4); - /** Called every time a prior detected SPITServer is is no longer found.*/ - void eventServerLost(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4); - void eventServerChanged(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4); - -//--------------- 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.
- * false = something is going wrong. (client could not bind) - */ - bool connect(string p_ServerIP, string p_ServerPort, string p_ClientIP, string p_ClientPort, string p_LoginName = "", string p_LoginPassword = ""); - /** - * Terminates the connection to the SPITServer. - */ - void disconnect(); - -private: - void disconnectInternal(int p_Cause); - void resetMessageNumberReceived(); - void parseSPIT_Message(unique_ptr p_SPITMessage); - void checkParseSPIT_Message(unique_ptr p_SPITMessage); - void addOvertakingSPIT_Message(SPIT_Message* p_SPIT_Message); - void parseConnectAnswer(SPIT_Message::ConnectAnswer* p_ConnectAnswer); - void parseDisconnect(SPIT_Message::Disconnect* p_Disconnect); - void parseWatchdog(SPIT_Message::Watchdog* p_Watchdog); - void parseWatchdogAnswer(SPIT_Message::WatchdogAnswer* p_WatchdogAnswer); -public: - /** Used internally*/ - void sendWatchdog(); - /** Used internally. When the connection to the SPITServer is lost an eventConnectionStatus will occur*/ - void eventWatchdogLost(); -//--------------- SPIT Project --------------- -private: - void parseReportSPITProject(SPIT_Message::ReportSPITProject* p_ReportSPITProject); - void parseCloseSPITProject(SPIT_Message::CloseSPITProject* p_CloseSPITProject); -public: - /** Returns the SPITServer's project ID - may be the same as the project's name*/ - string getServerProjectID(); - /** Returns the SPITServer's project name*/ - string 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(); - -private: - void parseRequestProjectTransfer(SPIT_Message::RequestProjectTransfer* p_RequestProjectTransfer); - void parseStartProjectTransfer(SPIT_Message::StartProjectTransfer* p_StartProjectTransfer); - void parseEndProjectTransfer(SPIT_Message::EndProjectTransfer* p_EndProjectTransfer); -public: - static void sendProject(SPIT_Client* p_PtrSPIT_Client); - -// --------------- SPIT Types --------------- -public: - /** - * Creates a fixed SPITType for application actions that are always present and project independent.
- * Fixed SPIT types cannot be changed or deleted by the server.
- * 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. - */ - SPITType* createSPITTypeFixed(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration); + //--------------- 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(SAD_DetectedServer &server); + /** Called every time a prior detected SPITServer is is no longer found.*/ + void eventServerLost(SAD_DetectedServer &server); + void eventServerChanged(SAD_DetectedServer &server); - /** - * Creates a SPITType for application actions.
- * 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. - */ - SPITType* createSPITType(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration, bool p_Fixed, bool p_ProjectIndepended); -private: - //receive SPITTypes - void parseReportSPITType(SPIT_Message::ReportSPITType* p_ReportSPITType); - void parseRemoveSPITType(SPIT_Message::RemoveSPITType* p_RemoveSPITType); - int sendSPITTypeInternal(SPITType* p_SPITType); -public: - /** - * If a client wants to change a SPITType, he should send it to the server.
- * 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.
- * @param p_SPITTypeID the id of the SPITType to remove. - * @return 0 = is sended, -1 = is not sended - */ - bool changeSPITType(SPITType* p_SPITType); - /** - * If a client wants to remove a SPITType, he should send it to the server.
- * 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.
- * @param p_SPITTypeID the id of the SPITType to remove. - * @return 0 = is sended, -1 = is not sended - */ - int removeSPITType(string p_SPITTypeID); -public: - -//--------------- SPIT Objects --------------- -private: - void parseReportSPITObject(SPIT_Message::ReportSPITObject* p_ReportSPITObject); - void parseRemoveSPITObject(SPIT_Message::RemoveSPITObject* p_RemoveSPITObject); - int sendSPITObjectInternal(SPITObject* ptrSPITObject); -public: - /** - * When the client changes a SPITObject (normally the client should not do this), then it should send the changes to the SPITServer.
- * The SPITServer may discard the changes and an eventSPITObject occurs.
- * @param p_SPITObject the pointer to the changed SPITObject. - * @return 0 = sended, -1 = not sended - */ - bool changeSPITObject(SPITObject* p_SPITObject); - /** - * When the client removes a SPITObject (normally the client should not do this), then he should send it to the SPITServer.
- * The SPITServer may discard the deletion and an eventSPITObject occurs.
- * @param p_SPITObjectID the id of the SPITObject to remove. - * @return 0 = sended, -1 = not sended - */ - int removeSPITObject(string p_SPITObjectID); -public: - -//--------------- Play SPIT Objects --------------- -private: - void parsePlaySPITStart(SPIT_Message::PlaySPITStart* p_PlaySPITStart); - void parsePlaySPITObject(SPIT_Message::PlaySPITObject* p_PlaySPITObject); - void parsePlaySPITEnd(SPIT_Message::PlaySPITEnd* p_PlaySPITEnd); - void parseReportPlayStatus(SPIT_Message::ReportPlayStatus* p_ReportPlayStatus); - - public: - //--------- Remote ---------- - void sendRemoteObject(string p_SPITObjectID, int p_Valueppm = 0, char p_ValueFlag = 0x00); + //--------------- 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.
+ * false = something is going wrong. (client could not bind) + */ + bool connect(string p_ServerIP, string p_ServerPort, string p_ClientIP, string p_ClientPort, string p_LoginName = "", string p_LoginPassword = ""); + /** + * Terminates the connection to the SPITServer. + */ + void disconnect(); - private: - static void processSocketTask(SPIT_Client & instance); - fos::TaskT* sThread{}; - bool abortSearch{}; - bool sAnswered{}; - static fos::Semaphore sStartSad; - SPITSocket * mSPITSocket; - void answerWatchdog() { - sAnswered = true; - } + private: + void disconnectInternal(int p_Cause); + void resetMessageNumberReceived(); + void parseSPIT_Message(unique_ptr p_SPITMessage); + void checkParseSPIT_Message(unique_ptr p_SPITMessage); + void addOvertakingSPIT_Message(SPIT_Message *p_SPIT_Message); + void parseConnectAnswer(SPIT_Message::ConnectAnswer *p_ConnectAnswer); + void parseDisconnect(SPIT_Message::Disconnect *p_Disconnect); + void parseWatchdog(SPIT_Message::Watchdog *p_Watchdog); + void parseWatchdogAnswer(SPIT_Message::WatchdogAnswer *p_WatchdogAnswer); + public: + /** Used internally*/ + void sendWatchdog(); + /** Used internally. When the connection to the SPITServer is lost an eventConnectionStatus will occur*/ + void eventWatchdogLost(); + //--------------- SPIT Project --------------- + private: + void parseReportSPITProject(SPIT_Message::ReportSPITProject *p_ReportSPITProject); + void parseCloseSPITProject(SPIT_Message::CloseSPITProject *p_CloseSPITProject); + + public: + /** Returns the SPITServer's project ID - may be the same as the project's name*/ + string getServerProjectID(); + /** Returns the SPITServer's project name*/ + string 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(); + + private: + void parseRequestProjectTransfer(SPIT_Message::RequestProjectTransfer *p_RequestProjectTransfer); + void parseStartProjectTransfer(SPIT_Message::StartProjectTransfer *p_StartProjectTransfer); + void parseEndProjectTransfer(SPIT_Message::EndProjectTransfer *p_EndProjectTransfer); + + public: + static void sendProject(SPIT_Client *p_PtrSPIT_Client); + + // --------------- SPIT Types --------------- + public: + /** + * Creates a fixed SPITType for application actions that are always present and project independent.
+ * Fixed SPIT types cannot be changed or deleted by the server.
+ * 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. + */ + SPITType *createSPITTypeFixed(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration); + + /** + * Creates a SPITType for application actions.
+ * 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. + */ + SPITType *createSPITType(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration, bool p_Fixed, bool p_ProjectIndepended); + + private: + // receive SPITTypes + void parseReportSPITType(SPIT_Message::ReportSPITType *p_ReportSPITType); + void parseRemoveSPITType(SPIT_Message::RemoveSPITType *p_RemoveSPITType); + int sendSPITTypeInternal(SPITType *p_SPITType); + + public: + /** + * If a client wants to change a SPITType, he should send it to the server.
+ * 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.
+ * @param p_SPITTypeID the id of the SPITType to remove. + * @return 0 = is sended, -1 = is not sended + */ + bool changeSPITType(SPITType *p_SPITType); + /** + * If a client wants to remove a SPITType, he should send it to the server.
+ * 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.
+ * @param p_SPITTypeID the id of the SPITType to remove. + * @return 0 = is sended, -1 = is not sended + */ + int removeSPITType(string p_SPITTypeID); + + public: + //--------------- SPIT Objects --------------- + private: + void parseReportSPITObject(SPIT_Message::ReportSPITObject *p_ReportSPITObject); + void parseRemoveSPITObject(SPIT_Message::RemoveSPITObject *p_RemoveSPITObject); + int sendSPITObjectInternal(SPITObject *ptrSPITObject); + + public: + /** + * When the client changes a SPITObject (normally the client should not do this), then it should send the changes to the SPITServer.
+ * The SPITServer may discard the changes and an eventSPITObject occurs.
+ * @param p_SPITObject the pointer to the changed SPITObject. + * @return 0 = sended, -1 = not sended + */ + bool changeSPITObject(SPITObject *p_SPITObject); + /** + * When the client removes a SPITObject (normally the client should not do this), then he should send it to the SPITServer.
+ * The SPITServer may discard the deletion and an eventSPITObject occurs.
+ * @param p_SPITObjectID the id of the SPITObject to remove. + * @return 0 = sended, -1 = not sended + */ + int removeSPITObject(string p_SPITObjectID); + + public: + //--------------- Play SPIT Objects --------------- + private: + void parsePlaySPITStart(SPIT_Message::PlaySPITStart *p_PlaySPITStart); + void parsePlaySPITObject(SPIT_Message::PlaySPITObject *p_PlaySPITObject); + void parsePlaySPITEnd(SPIT_Message::PlaySPITEnd *p_PlaySPITEnd); + void parseReportPlayStatus(SPIT_Message::ReportPlayStatus *p_ReportPlayStatus); + + public: + //--------- Remote ---------- + void sendRemoteObject(string p_SPITObjectID, int p_Valueppm = 0, char p_ValueFlag = 0x00); + + private: + static void processSocketTask(SPIT_Client &instance); + fos::TaskT *sThread{}; + bool abortSearch{}; + bool sAnswered{}; + static fos::Semaphore sStartSad; + SPITSocket *mSPITSocket; + void answerWatchdog() { + sAnswered = true; + } }; #endif /* SPIT_CLIENT_H */ - diff --git a/components/spit/include/SPIT_Message.h b/components/spit/include/SPIT_Message.h index 9f6c9fd..9c3a0fb 100644 --- a/components/spit/include/SPIT_Message.h +++ b/components/spit/include/SPIT_Message.h @@ -4,7 +4,7 @@ * and open the template in the editor. */ -/* +/* * File: SPIT_Message.h * Author: Hagi * @@ -19,932 +19,843 @@ using namespace std; static const string SPITID = "#spit#"; -//static char stringEmpty[] = ""; +// static char stringEmpty[] = ""; static char nullChar[] = "\0"; -class SPIT_Message { -//----------- Header ----------- -public: - - class Header { - public: - static const int BYTESLENGTH = 99; - virtual ~Header(); - Header(const Header& orig); - Header(); - //Members - private: - string m_SPITID; - int m_SPITVersion; - unsigned char m_MessageNumber; - int m_BytesCount; - string m_ServerID; - string m_ClientID; - int m_OPFlag; - int m_ParseOffset = 0; +class SPIT_Message { + //----------- Header ----------- + public: + class Header { + public: + static const int BYTESLENGTH = 99; + virtual ~Header(); + Header(const Header &orig); + Header(); + // Members + private: + string m_SPITID; + int m_SPITVersion; + unsigned char m_MessageNumber; + int m_BytesCount; + string m_ServerID; + string m_ClientID; + int m_OPFlag; + int m_ParseOffset = 0; - void initMembers(); - - public: - const string getSPITID() const { - return m_SPITID; - } - int getSPITVersion() const { - return m_SPITVersion; - } - unsigned char getMessageNumber() const { - return m_MessageNumber; - } - int getBytesCount() const { - return m_BytesCount; - } - const string getServerID() const { - return m_ServerID; - } - const string getClientID() const { - return m_ClientID; - } - int getOPFlag() const { - return m_OPFlag; - } - - //Receive - public: - bool parse(char* p_Bytes, int p_ByteCount); - - //Send - public: - Header(int p_SPITVersion, int p_OPFlag); - void setMessageNumber(unsigned char p_MessageNumber); - void setServerID(string p_ServerID); - void setClientID(string p_ID); - void setOPFlag(int p_OPFlag); - bool fillBytes(char* p_Bytes, int p_ByteCount); - }; + void initMembers(); -//----------- OPPart ----------- -public: - class OPPart { - - //Members - protected: - Header* m_Header; - int m_ParseOffset; - int m_BytesCount; - private: - void initMembers(); - public: - virtual ~OPPart(); -// OPPart(const OPPart& orig); - Header* getHeader() const { - return m_Header; - } - - int getBytesCount() const { - return m_BytesCount; - } - const string getServerID() const { - if (m_Header == NULL) return ""; - return m_Header->getServerID(); - } - const string getClientID() const { - if (m_Header == NULL) return ""; - return m_Header->getClientID(); - } - - int getOPFlag() const { - if (m_Header == NULL) return -1; - return m_Header->getOPFlag(); - } - - //Receive - public: - OPPart(Header* p_Header, int p_OPFlag); - void setHeader(Header* p_Header); - virtual bool parse(char* p_Bytes, int p_ByteCounth)=0; - - //Send - public: - OPPart(); - virtual bool fillBytes(char* p_Bytes, int p_ByteCount)=0; - }; + public: + const string getSPITID() const { return m_SPITID; } + int getSPITVersion() const { return m_SPITVersion; } + unsigned char getMessageNumber() const { return m_MessageNumber; } + int getBytesCount() const { return m_BytesCount; } + const string getServerID() const { return m_ServerID; } + const string getClientID() const { return m_ClientID; } + int getOPFlag() const { return m_OPFlag; } - -//----------- SPIT_Message ----------- - -public: - static const int SPITVERSION = 1; + // Receive + public: + bool parse(char *p_Bytes, int p_ByteCount); - //SPIT_Object value usage - static const char VALUEUSE_DISCARD = 0x00; //value of SPITObejct is not used - static const char VALUEUSE_INRANGE = 0x01; //value of SPITOBject in range 0 - 1000000ppm - static const char VALUEUSE_OVERRIDE = 0x02; //value can be overridden - - //SPIT Player type - static const char PLAYERTYPE_MAIN = 0x02; - static const char PLAYERTYPE_CONTINIOUS = 0x01; - static const char PLAYERTYPE_DISCRETE = 0x00; + // Send + public: + Header(int p_SPITVersion, int p_OPFlag); + void setMessageNumber(unsigned char p_MessageNumber); + void setServerID(string p_ServerID); + void setClientID(string p_ID); + void setOPFlag(int p_OPFlag); + bool fillBytes(char *p_Bytes, int p_ByteCount); + }; - //PlayObject value usage - static const char VALUEFLAG_DIRECT = 0x00; //use the vlue direct - static const char VALUEFLAG_INCREASE = 0x01; //increase the value - static const char VALUEFLAG_DECREASE = 0x02; //decrease the value - - - SPIT_Message(); - virtual ~SPIT_Message(); -// SPIT_Message(const SPIT_Message& orig); - -//Members -private: - char* m_MessageBytes; - int m_MessageByteCount; - Header* m_Header; - OPPart* m_OPPart; - bool m_MessageBytesCreated; - - void initMembers(); - -//Receive -public: - SPIT_Message(char* p_MessageBytes, int p_MessageBytesLength); - -// SPIT_Message(const SPIT_Message& orig); - const Header* getHeader() const { - return m_Header; - } - int getOPFlag() const { - if (m_Header == NULL) return -1; - return m_Header->getOPFlag(); - } - const OPPart* getOPPart() const { - return m_OPPart; - } - int getMesageByteCount() const { - return m_MessageByteCount; - } - - OPPart* parse(); - -//Send -public: - SPIT_Message(OPPart* p_OPPart); - bool fillBytes(); - const char* getMessageBytes(); - - - - -//------------------------------ Connection ---------------------------------- - -//----------- Connect ----------- -public: - class Connect : public OPPart { - public: - static const int OPFLAG = 1; - static const int BYTESLENGTH = 304; + //----------- OPPart ----------- + public: + class OPPart { - private: - string m_ClientComputerName; - string m_ClientName; - string m_LoginName; - string m_LoginPassword; - string m_ServerIP; - int m_ServerPort; - void initMembers(); - public: - ~Connect(); -// Connect(const Connect& orig); - //Receive - public: - Connect(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - const string getClientComputerName() const { - return m_ClientComputerName; - } - const string getClientName() const { - return m_ClientName; - } - const string getLoginName() const { - return m_LoginName; - } - const string getLoginPassword() const { - return m_LoginPassword; - } - const string getServerIP() const { - return m_ServerIP; - } - int getServerPort() const { - return m_ServerPort; - } - - //Send - public: - Connect(); - void setClientComputerName(string p_ComputerName); - void setClientName(string p_ClientName); - void setLoginName(string p_LoginName); - void setLoginPassword(string p_LoginPassword); - void setServerIP(string p_ServerIP); - void setServerPort(int p_ServerPort); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//----------- ConnectAnswer ----------- + // Members + protected: + Header *m_Header; + int m_ParseOffset; + int m_BytesCount; - class ConnectAnswer : public OPPart { - public: - static const int OPFLAG = 2; - static const int BYTESLENGTH = 137; - private: - string m_ServerComputerName; - string m_ServerName; - bool m_Connected; - int m_StepTime; //ms step size the Server will send play sequences - - void initMembers(); - public: - ~ConnectAnswer(); - ConnectAnswer(const ConnectAnswer& orig); - //Receive - ConnectAnswer(Header* p_Header); - - bool parse(char* p_Bytes, int p_ByteCount); - - const string getServerComputerName() const { - return m_ServerComputerName; - } - const string getServerName() const { - return m_ServerName; - } - bool getConnected() const { - return m_Connected; - } - int getStepTime() const { - return m_StepTime; - } - - //Send - public: - ConnectAnswer(); - void setServerComputerName(string p_ServerComputerName); - void setServerName(string p_ContollerName); - void setConnected(bool p_Connected); - void setStepTime(int p_StepTime_ms); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; + private: + void initMembers(); -//----------- Disconnect ----------- + public: + virtual ~OPPart(); + // OPPart(const OPPart& orig); + Header *getHeader() const { return m_Header; } + int getBytesCount() const { return m_BytesCount; } - class Disconnect : public OPPart { - public: - static const int OPFLAG = 3; - static const int BYTESLENGTH = 4; - - private: - void initMembers(); - public: - ~Disconnect(); - Disconnect(const Disconnect& orig); - //Receive - Disconnect(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - // Send - public: - Disconnect(); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; + const string getServerID() const { + if (m_Header == NULL) + return ""; + return m_Header->getServerID(); + } + const string getClientID() const { + if (m_Header == NULL) + return ""; + return m_Header->getClientID(); + } -//----------- Watchdog ----------- - - class Watchdog : public OPPart { - public: - static const int OPFLAG = 8; - static const int BYTESLENGTH = 4; - private: - void initMembers(); - public: - ~Watchdog(); - Watchdog(const Watchdog& orig); - //Receive - Watchdog(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - // Send - public: - Watchdog(); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; + int getOPFlag() const { + if (m_Header == NULL) + return -1; + return m_Header->getOPFlag(); + } -//----------- WatchdogAnswer ----------- - - class WatchdogAnswer : public OPPart { - public: - static const int OPFLAG = 9; - static const int BYTESLENGTH = 4; - private: - void initMembers(); - //Receive - public: - ~WatchdogAnswer(); - WatchdogAnswer(const WatchdogAnswer& orig); - WatchdogAnswer(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - // Send - public: - WatchdogAnswer(); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - - -//------------------------------ SPITProject ---------------------------------- + // Receive + public: + OPPart(Header *p_Header, int p_OPFlag); + void setHeader(Header *p_Header); + virtual bool parse(char *p_Bytes, int p_ByteCounth) = 0; -//----------- ReportSPITProject ----------- - - class ReportSPITProject : public OPPart { - public: - static const int OPFLAG = 11; - static const int BYTESLENGTH = 113; - private: - string m_ProjectID; - string m_ProjectName; - int m_FramesPerSecond; //Frames per second - - void initMembers(); - //Receive - public: - ~ReportSPITProject(); - ReportSPITProject(const ReportSPITProject& orig); - ReportSPITProject(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - const string getProjectID() const { - return m_ProjectID; - } - const string getProjectName() const { - return m_ProjectName; - } - int getFramesPerSecond() const { - return m_FramesPerSecond; - } - // Send - ReportSPITProject(); - - void setProjectID(string p_ClientID); - void setProjectName(string p_ClientName); - void setFramesPerSecond(const int p_FramesPerSecond); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; + // Send + public: + OPPart(); + virtual bool fillBytes(char *p_Bytes, int p_ByteCount) = 0; + }; -//----------- CloseSPITProject ----------- - - class CloseSPITProject : public OPPart { - public: - static const int OPFLAG = 13; - static const int BYTESLENGTH = 45; - private: - string m_ProjectID; - - void initMembers(); - public: - ~CloseSPITProject(); - CloseSPITProject(const CloseSPITProject& orig); - //Receive - CloseSPITProject(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - const string getProjectID() const { - return m_ProjectID; - } - // Send - public: - CloseSPITProject(); - - void setProjectID(string p_ClientID); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//----------- StartProjectTransfer ----------- - class RequestProjectTransfer : public OPPart { - public: - static const int OPFLAG = 15; - static const int BYTESLENGTH = 4; - private: - void initMembers(); - public: - ~RequestProjectTransfer(); - RequestProjectTransfer(const RequestProjectTransfer& orig); - //Receive - RequestProjectTransfer(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - // Send - public: - RequestProjectTransfer(); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//----------- StartProjectTransfer ----------- - - class StartProjectTransfer : public OPPart { - public: - static const int OPFLAG = 16; - static const int BYTESLENGTH = 4; - - private: - void initMembers(); - public: - ~StartProjectTransfer(); - StartProjectTransfer(const StartProjectTransfer& orig); - //Receive - StartProjectTransfer(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - // Send - public: - StartProjectTransfer(); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; + //----------- SPIT_Message ----------- -//----------- EndProjectTransfer ----------- - class EndProjectTransfer : public OPPart { - public: - static const int OPFLAG = 17; - static const int BYTESLENGTH = 4; - private: - void initMembers(); - public: - ~EndProjectTransfer(); - EndProjectTransfer(const EndProjectTransfer& orig); - //Receive - EndProjectTransfer(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - // Send - EndProjectTransfer(); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//---------------------------- SPIT_Types ---------------------------------- - -//----------- ReportSPITType ----------- - class ReportSPITType : public OPPart { - public: - static const int OPFLAG = 21; - static const int BYTESLENGTH = 168; - private: - bool m_Confirmed; - string m_SPITTypeID; - bool m_Fixed; - bool m_ServerRemote; - bool m_ServerProjectIndepended; - string m_SPITTypeGroupName; - string m_SPITTypeName; - long long m_Delay; - long long m_Duration; - - void initMembers(); - public: - ~ReportSPITType(); - ReportSPITType(const ReportSPITType& orig); - //Receive - ReportSPITType(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - bool getConfirmed() const { - return m_Confirmed; - } - const string getID() const { - return m_SPITTypeID; - } - bool getFixed() const { - return m_Fixed; - } - bool getServerRemote() const { - return m_ServerRemote; - } - bool getServerProjectIndepended() const { - return m_ServerProjectIndepended; - } - const string getGroupName() const { - return m_SPITTypeGroupName; - } - const string getName() const { - return m_SPITTypeName; - } - long long getDelay() const { - return m_Delay; - } - long long getDuration() const { - return m_Duration; - } - // Send - public: - ReportSPITType(); - - void setConfirmed(bool p_Confirmed); - void setID(string p_ID); - void setFixed(bool p_Fixed); - void setServerRemote(bool p_IsServerRemote); - void setServerProjectIndepended(bool p_ProjectIndpended); - void setGroupName(string p_GroupName); - void setName(string p_Name); - void setDelay(long long p_Delay); - void setDuration(long long p_Duration); - - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//----------- RemoveSPITType ----------- - - class RemoveSPITType : public OPPart { - public: - static const int OPFLAG = 23; - static const int BYTESLENGTH = 45; - private: - string m_SPITTypeID; - - void initMembers(); - public: - ~RemoveSPITType(); - RemoveSPITType(const RemoveSPITType& orig); - //Receive - RemoveSPITType(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - const string getID() const { - return m_SPITTypeID; - } - // Send - RemoveSPITType(); - - void setID(string p_ID); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; + public: + static const int SPITVERSION = 1; + // SPIT_Object value usage + static const char VALUEUSE_DISCARD = 0x00; // value of SPITObejct is not used + static const char VALUEUSE_INRANGE = 0x01; // value of SPITOBject in range 0 - 1000000ppm + static const char VALUEUSE_OVERRIDE = 0x02; // value can be overridden + // SPIT Player type + static const char PLAYERTYPE_MAIN = 0x02; + static const char PLAYERTYPE_CONTINIOUS = 0x01; + static const char PLAYERTYPE_DISCRETE = 0x00; -//---------------------------- SPITObjects ---------------------------------- - -//----------- ReportSPITObject ----------- - - class ReportSPITObject : public OPPart { - public: - static const int OPFLAG = 31; - static const int BYTESLENGTH = 339; - private: - bool m_Confirmed; - string m_SPITObjectID; - bool m_Fixed; - bool m_ServerRemote; - string m_SPITObjectName; - string m_SPITTypeID; - string m_ServerParams; - long long m_FrameStart; - long long m_FrameLength; - long long m_FrameFadeInLength; - long long m_FrameFadeOutLength; - int m_ValueFactor; - char m_ValueUse; - int m_Track; - string m_Remark; - long long m_Delay; - long long m_Duration; - bool m_ActionAssigned; - - void initMembers(); - public: - ~ReportSPITObject(); - ReportSPITObject(const ReportSPITObject& orig); - //Receive - ReportSPITObject(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - bool getConfirmed() const { - return m_Confirmed; - } - const string getID() const { - return m_SPITObjectID; - } - bool getFixed() const { - return m_Fixed; - } - bool getServerRemote() const { - return m_ServerRemote; - } - const string getName() const { - return m_SPITObjectName; - } - const string getSPITTypeID() const { - return m_SPITTypeID; - } - const string getServerParams() const { - return m_ServerParams; - } - long long getFrameStart() const { - return m_FrameStart; - } - long long getFrameLength() const { - return m_FrameLength; - } - long long getFrameFadeInLength() const { - return m_FrameFadeInLength; - } - long long getFrameFadeOutLength() const { - return m_FrameFadeOutLength; - } - int getValueFactor() const { - return m_ValueFactor; - } - char getValueUse() const { - return m_ValueUse; - } - int getTrack() const { - return m_Track; - } - const string getRemark() const { - return m_Remark; - } - long long getDelay() const { - return m_Delay; - } - long long getDuration() const { - return m_Duration; - } - bool getActionAssigned() const { - return m_ActionAssigned; - } - // Send - public: - ReportSPITObject(); - - void setConfirmed(bool p_Confirmed); - void setID(string p_ID); - void setFixed(bool p_Fixed); - void setServerRemote(bool p_IsRemote); - void setName(string p_Name); - void setSPITTypeID(string p_ID); - void setServerParams(string p_Parameters); - void setFrameStart(long long p_StartTime); - void setFrameLength(long long p_Length); - void setFrameFadeInLength(long long p_FadeInTime); - void setFrameFadeOutLength(long long p_FadeOutTime); - void setValueFactor(int p_Volume); - void setValueUse(char p_ValueUse); - void setTrack(int p_Track); - void setRemark(string p_Description); - void setDelay(long long p_Delay); - void setDuration(long long p_Duration); - void setActionAssigned(bool p_ActionAssigned); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; + // PlayObject value usage + static const char VALUEFLAG_DIRECT = 0x00; // use the vlue direct + static const char VALUEFLAG_INCREASE = 0x01; // increase the value + static const char VALUEFLAG_DECREASE = 0x02; // decrease the value -//----------- RemoveSPITObject ----------- - - class RemoveSPITObject : public OPPart { - public: - static const int OPFLAG = 33; - static const int BYTESLENGTH = 45; - private: - string m_SPITObjectID; - - void initMembers(); - public: - ~RemoveSPITObject(); - RemoveSPITObject(const RemoveSPITObject& orig); - //Receive - RemoveSPITObject(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - const string getID() const { - return m_SPITObjectID; - } - // Send - public: - RemoveSPITObject(); - void setID(string p_ID); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//---------------------------- SPITPlayer ---------------------------------- + SPIT_Message(); + virtual ~SPIT_Message(); + // SPIT_Message(const SPIT_Message& orig); -//----------- PlaySPITStart ----------- - - class PlaySPITStart : public OPPart { - public: - static const int OPFLAG = 37; - static const int BYTESLENGTH = 119; - private: - string m_PlayerID; - string m_PlayerName; - char m_PlayerType; - bool m_PlayerIsRunning; - long long m_Time; //Frames - - void initMembers(); - public: - ~PlaySPITStart(); - PlaySPITStart(const PlaySPITStart& orig); - //Receive - PlaySPITStart(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - const string getPlayerID() const { - return m_PlayerID; - } - const string getPlayerName() const { - return m_PlayerName; - } - char getPlayerType() const { - return m_PlayerType; - } - bool getPlayerIsRunning() const { - return m_PlayerIsRunning; - } - long long getTime() const { - return m_Time; - } - - // Send - public: - PlaySPITStart(); - - void setPlayerID(string p_PlayerID); - void setPlayerName(string p_PlayerName); - void setPlayerType(char p_PlayerType); - void setPlayerIsRunning(bool p_IsPlaying); - void setTime(long long p_Time); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//----------- PlaySPITObject ----------- - - class PlaySPITObject : public OPPart { - public: - static const int OPFLAG = 38; - static const int BYTESLENGTH = 100; - private: - string m_PlayerID; - string m_SPITObjectID; - long long m_FrameInsideObject; //Frames - bool m_PlayPrePosition; - int m_Value; - char m_ValueFlag; - - void initMembers(); - public: - ~PlaySPITObject(); - PlaySPITObject(const PlaySPITObject& orig); - //Receive - PlaySPITObject(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - const string getPlayerID() const { - return m_PlayerID; - } - const string getSPITObjectID() const { - return m_SPITObjectID; - } - long long getFrameInsideObject() const { - return m_FrameInsideObject; - } - bool getPlayPrePosition() const { - return m_PlayPrePosition; - } - int getValue() const { - return m_Value; - } - char getValueFlag() const { - return m_ValueFlag; - } - // Send - PlaySPITObject(); - - void setPlayerID(string p_PlayerID); - void setID(string p_ID); - void setFrameInsideObject(long long p_TimeInside); - void setPlayPrePosition(bool p_PlayOldPosition); - void setValue(int p_Value); - void setValueFlag(char p_ValueFlag); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - -//----------- PlaySPITEnd ----------- - class PlaySPITEnd : public OPPart { - public: - static const int OPFLAG = 39; - static const int BYTESLENGTH = 45; - private: - string m_PlayerID; - - void initMembers(); - public: - ~PlaySPITEnd(); - PlaySPITEnd(const PlaySPITEnd& orig); - //Receive - PlaySPITEnd(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - const string getPlayerID() const { - return m_PlayerID; - } - // Send - public: - PlaySPITEnd(); - void setPlayerID(string p_PlayerID); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - - -//----------- ReportPlayStatus ----------- - - class ReportPlayStatus : public OPPart { - public: - static const int OPFLAG = 40; - static const int BYTESLENGTH = 57; - private: - string m_SPITObjectID; - long long m_FrameInsideObject; //Frames - int m_Value; - - void initMembers(); - public: - ~ReportPlayStatus(); - ReportPlayStatus(const ReportPlayStatus& orig); - //Receive - ReportPlayStatus(Header* p_Header); - bool parse(char* p_Bytes, int p_ByteCount); - - const string getID() const { - return m_SPITObjectID; - } - long long getFrameInsideObject() const { - return m_FrameInsideObject; - } - int getValue() const { - return m_Value; - } - // Send - ReportPlayStatus(); - - void setID(string p_ID); - void setFrameInsideObject(long long p_TimeInside); - void setValue(int p_Value); - bool fillBytes(char* p_MessageBytes, int p_ByteCount); - }; - - - - -//----------------------- static helper functions ---------------------------- -public: - static bool isSystemLittleEndian(); - static int getInt(char* p_Bytes, int p_ByteCount, int p_Offset); - static int setInt(int p_Value, char* p_Bytes, int p_ByteCount, int p_Offset); - static long long getLong(char* p_Bytes, int p_ByteCount, int p_Offset); - static int setLong(long long p_Value, char* p_Bytes, int p_ByteCount, int p_Offset); - static bool getBoolean(char* p_Bytes, int p_ByteCount, int p_Offset); - static int setBoolean(bool p_Value, char* p_Bytes, int p_ByteCount, int p_Offset); - static char getByte(char* p_Bytes, int p_ByteCount, int p_Offset); - static int setByte(int p_Value, char* p_Bytes, int p_ByteCount, int p_Offset); - /** - * Returns the string char* of the part of the byte sequence (0x00 null terminated). - * @param p_Bytes the byte array - * @param p_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. - * @return the String char* - * @throws Exception if p_Bytes == null
- * p_Offset less than 0
- * p_Bytes.length less than p_Offset + p_Length
- * No 0x00 null terminate byte is found - */ - static string getString(char* p_Bytes, int p_ByteCount, int p_Offset, int p_Length); - - /** - * 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_Bytes the byte array where the string is filled - * @param p_Offset the offset inside the byte array - * @param p_Length the maximal length of the string included the null character.
- * @throws Exception if p_String == NULL, p_Bytes == NULL
- * p_Offset less than 0
- * p_ByteCount less than p_Offset + p_Length - * @return p_Length - */ - static int setString(string p_String, char* p_Bytes, int p_ByteCount, int p_Offset, int p_Length); - /** - * Compares two strings for equality. - * @param p_String1 string terminated by null character - * @param p_String2 string terminated by null character - * @return true if both strings are equal
- * false if the strings are NULL or not equal or not terminated by "\0" - */ -// static bool stringEqual(const char* p_String1, const char* p_String2); -// static char* stringCopy(const char* p_String); - static char* createByteArray(const OPPart* p_OPPart, int* p_BytesCount); + // Members + private: + char *m_MessageBytes; + int m_MessageByteCount; + Header *m_Header; + OPPart *m_OPPart; + bool m_MessageBytesCreated; + + void initMembers(); + + // Receive + public: + SPIT_Message(char *p_MessageBytes, int p_MessageBytesLength); + + // SPIT_Message(const SPIT_Message& orig); + const Header *getHeader() const { return m_Header; } + int getOPFlag() const { + if (m_Header == NULL) + return -1; + return m_Header->getOPFlag(); + } + const OPPart *getOPPart() const { return m_OPPart; } + int getMesageByteCount() const { return m_MessageByteCount; } + + OPPart *parse(); + + // Send + public: + SPIT_Message(OPPart *p_OPPart); + bool fillBytes(); + const char *getMessageBytes(); + + //------------------------------ Connection ---------------------------------- + + //----------- Connect ----------- + public: + class Connect : public OPPart { + public: + static const int OPFLAG = 1; + static const int BYTESLENGTH = 304; + + private: + string m_ClientComputerName; + string m_ClientName; + string m_LoginName; + string m_LoginPassword; + string m_ServerIP; + int m_ServerPort; + void initMembers(); + + public: + ~Connect(); + // Connect(const Connect& orig); + // Receive + public: + Connect(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + const string getClientComputerName() const { return m_ClientComputerName; } + const string getClientName() const { return m_ClientName; } + const string getLoginName() const { return m_LoginName; } + const string getLoginPassword() const { return m_LoginPassword; } + const string getServerIP() const { return m_ServerIP; } + int getServerPort() const { return m_ServerPort; } + + // Send + public: + Connect(); + void setClientComputerName(string p_ComputerName); + void setClientName(string p_ClientName); + void setLoginName(string p_LoginName); + void setLoginPassword(string p_LoginPassword); + void setServerIP(string p_ServerIP); + void setServerPort(int p_ServerPort); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- ConnectAnswer ----------- + + class ConnectAnswer : public OPPart { + public: + static const int OPFLAG = 2; + static const int BYTESLENGTH = 137; + + private: + string m_ServerComputerName; + string m_ServerName; + bool m_Connected; + int m_StepTime; // ms step size the Server will send play sequences + + void initMembers(); + + public: + ~ConnectAnswer(); + ConnectAnswer(const ConnectAnswer &orig); + // Receive + ConnectAnswer(Header *p_Header); + + bool parse(char *p_Bytes, int p_ByteCount); + + const string getServerComputerName() const { return m_ServerComputerName; } + const string getServerName() const { return m_ServerName; } + bool getConnected() const { return m_Connected; } + int getStepTime() const { return m_StepTime; } + + // Send + public: + ConnectAnswer(); + void setServerComputerName(string p_ServerComputerName); + void setServerName(string p_ContollerName); + void setConnected(bool p_Connected); + void setStepTime(int p_StepTime_ms); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- Disconnect ----------- + + class Disconnect : public OPPart { + public: + static const int OPFLAG = 3; + static const int BYTESLENGTH = 4; + + private: + void initMembers(); + + public: + ~Disconnect(); + Disconnect(const Disconnect &orig); + // Receive + Disconnect(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + // Send + public: + Disconnect(); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- Watchdog ----------- + + class Watchdog : public OPPart { + public: + static const int OPFLAG = 8; + static const int BYTESLENGTH = 4; + + private: + void initMembers(); + + public: + ~Watchdog(); + Watchdog(const Watchdog &orig); + // Receive + Watchdog(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + // Send + public: + Watchdog(); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- WatchdogAnswer ----------- + + class WatchdogAnswer : public OPPart { + public: + static const int OPFLAG = 9; + static const int BYTESLENGTH = 4; + + private: + void initMembers(); + // Receive + public: + ~WatchdogAnswer(); + WatchdogAnswer(const WatchdogAnswer &orig); + WatchdogAnswer(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + // Send + public: + WatchdogAnswer(); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //------------------------------ SPITProject ---------------------------------- + + //----------- ReportSPITProject ----------- + + class ReportSPITProject : public OPPart { + public: + static const int OPFLAG = 11; + static const int BYTESLENGTH = 113; + + private: + string m_ProjectID; + string m_ProjectName; + int m_FramesPerSecond; // Frames per second + + void initMembers(); + // Receive + public: + ~ReportSPITProject(); + ReportSPITProject(const ReportSPITProject &orig); + ReportSPITProject(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + const string getProjectID() const { + return m_ProjectID; + } + const string getProjectName() const { + return m_ProjectName; + } + int getFramesPerSecond() const { + return m_FramesPerSecond; + } + // Send + ReportSPITProject(); + + void setProjectID(string p_ClientID); + void setProjectName(string p_ClientName); + void setFramesPerSecond(const int p_FramesPerSecond); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- CloseSPITProject ----------- + + class CloseSPITProject : public OPPart { + public: + static const int OPFLAG = 13; + static const int BYTESLENGTH = 45; + + private: + string m_ProjectID; + + void initMembers(); + + public: + ~CloseSPITProject(); + CloseSPITProject(const CloseSPITProject &orig); + // Receive + CloseSPITProject(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + const string getProjectID() const { + return m_ProjectID; + } + // Send + public: + CloseSPITProject(); + + void setProjectID(string p_ClientID); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- StartProjectTransfer ----------- + class RequestProjectTransfer : public OPPart { + public: + static const int OPFLAG = 15; + static const int BYTESLENGTH = 4; + + private: + void initMembers(); + + public: + ~RequestProjectTransfer(); + RequestProjectTransfer(const RequestProjectTransfer &orig); + // Receive + RequestProjectTransfer(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + // Send + public: + RequestProjectTransfer(); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- StartProjectTransfer ----------- + + class StartProjectTransfer : public OPPart { + public: + static const int OPFLAG = 16; + static const int BYTESLENGTH = 4; + + private: + void initMembers(); + + public: + ~StartProjectTransfer(); + StartProjectTransfer(const StartProjectTransfer &orig); + // Receive + StartProjectTransfer(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + // Send + public: + StartProjectTransfer(); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- EndProjectTransfer ----------- + class EndProjectTransfer : public OPPart { + public: + static const int OPFLAG = 17; + static const int BYTESLENGTH = 4; + + private: + void initMembers(); + + public: + ~EndProjectTransfer(); + EndProjectTransfer(const EndProjectTransfer &orig); + // Receive + EndProjectTransfer(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + // Send + EndProjectTransfer(); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //---------------------------- SPIT_Types ---------------------------------- + + //----------- ReportSPITType ----------- + class ReportSPITType : public OPPart { + public: + static const int OPFLAG = 21; + static const int BYTESLENGTH = 168; + + private: + bool m_Confirmed; + string m_SPITTypeID; + bool m_Fixed; + bool m_ServerRemote; + bool m_ServerProjectIndepended; + string m_SPITTypeGroupName; + string m_SPITTypeName; + long long m_Delay; + long long m_Duration; + + void initMembers(); + + public: + ~ReportSPITType(); + ReportSPITType(const ReportSPITType &orig); + // Receive + ReportSPITType(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + bool getConfirmed() const { + return m_Confirmed; + } + const string getID() const { + return m_SPITTypeID; + } + bool getFixed() const { + return m_Fixed; + } + bool getServerRemote() const { + return m_ServerRemote; + } + bool getServerProjectIndepended() const { + return m_ServerProjectIndepended; + } + const string getGroupName() const { + return m_SPITTypeGroupName; + } + const string getName() const { + return m_SPITTypeName; + } + long long getDelay() const { + return m_Delay; + } + long long getDuration() const { + return m_Duration; + } + // Send + public: + ReportSPITType(); + + void setConfirmed(bool p_Confirmed); + void setID(string p_ID); + void setFixed(bool p_Fixed); + void setServerRemote(bool p_IsServerRemote); + void setServerProjectIndepended(bool p_ProjectIndpended); + void setGroupName(string p_GroupName); + void setName(string p_Name); + void setDelay(long long p_Delay); + void setDuration(long long p_Duration); + + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- RemoveSPITType ----------- + + class RemoveSPITType : public OPPart { + public: + static const int OPFLAG = 23; + static const int BYTESLENGTH = 45; + + private: + string m_SPITTypeID; + + void initMembers(); + + public: + ~RemoveSPITType(); + RemoveSPITType(const RemoveSPITType &orig); + // Receive + RemoveSPITType(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + const string getID() const { + return m_SPITTypeID; + } + // Send + RemoveSPITType(); + + void setID(string p_ID); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //---------------------------- SPITObjects ---------------------------------- + + //----------- ReportSPITObject ----------- + + class ReportSPITObject : public OPPart { + public: + static const int OPFLAG = 31; + static const int BYTESLENGTH = 339; + + private: + bool m_Confirmed; + string m_SPITObjectID; + bool m_Fixed; + bool m_ServerRemote; + string m_SPITObjectName; + string m_SPITTypeID; + string m_ServerParams; + long long m_FrameStart; + long long m_FrameLength; + long long m_FrameFadeInLength; + long long m_FrameFadeOutLength; + int m_ValueFactor; + char m_ValueUse; + int m_Track; + string m_Remark; + long long m_Delay; + long long m_Duration; + bool m_ActionAssigned; + + void initMembers(); + + public: + ~ReportSPITObject(); + ReportSPITObject(const ReportSPITObject &orig); + // Receive + ReportSPITObject(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + bool getConfirmed() const { return m_Confirmed; } + const string getID() const { return m_SPITObjectID; } + bool getFixed() const { return m_Fixed; } + bool getServerRemote() const { return m_ServerRemote; } + const string getName() const { return m_SPITObjectName; } + const string getSPITTypeID() const { return m_SPITTypeID; } + const string getServerParams() const { return m_ServerParams; } + long long getFrameStart() const { return m_FrameStart; } + long long getFrameLength() const { return m_FrameLength; } + long long getFrameFadeInLength() const { return m_FrameFadeInLength; } + long long getFrameFadeOutLength() const { return m_FrameFadeOutLength; } + int getValueFactor() const { return m_ValueFactor; } + char getValueUse() const { return m_ValueUse; } + int getTrack() const { return m_Track; } + const string getRemark() const { return m_Remark; } + long long getDelay() const { return m_Delay; } + long long getDuration() const { return m_Duration; } + bool getActionAssigned() const { return m_ActionAssigned; } + // Send + public: + ReportSPITObject(); + + void setConfirmed(bool p_Confirmed); + void setID(string p_ID); + void setFixed(bool p_Fixed); + void setServerRemote(bool p_IsRemote); + void setName(string p_Name); + void setSPITTypeID(string p_ID); + void setServerParams(string p_Parameters); + void setFrameStart(long long p_StartTime); + void setFrameLength(long long p_Length); + void setFrameFadeInLength(long long p_FadeInTime); + void setFrameFadeOutLength(long long p_FadeOutTime); + void setValueFactor(int p_Volume); + void setValueUse(char p_ValueUse); + void setTrack(int p_Track); + void setRemark(string p_Description); + void setDelay(long long p_Delay); + void setDuration(long long p_Duration); + void setActionAssigned(bool p_ActionAssigned); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- RemoveSPITObject ----------- + + class RemoveSPITObject : public OPPart { + public: + static const int OPFLAG = 33; + static const int BYTESLENGTH = 45; + + private: + string m_SPITObjectID; + + void initMembers(); + + public: + ~RemoveSPITObject(); + RemoveSPITObject(const RemoveSPITObject &orig); + // Receive + RemoveSPITObject(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + const string getID() const { + return m_SPITObjectID; + } + // Send + public: + RemoveSPITObject(); + void setID(string p_ID); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //---------------------------- SPITPlayer ---------------------------------- + + //----------- PlaySPITStart ----------- + + class PlaySPITStart : public OPPart { + public: + static const int OPFLAG = 37; + static const int BYTESLENGTH = 119; + + private: + string m_PlayerID; + string m_PlayerName; + char m_PlayerType; + bool m_PlayerIsRunning; + long long m_Time; // Frames + + void initMembers(); + + public: + ~PlaySPITStart(); + PlaySPITStart(const PlaySPITStart &orig); + // Receive + PlaySPITStart(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + const string getPlayerID() const { return m_PlayerID; } + const string getPlayerName() const { return m_PlayerName; } + char getPlayerType() const { return m_PlayerType; } + bool getPlayerIsRunning() const { return m_PlayerIsRunning; } + long long getTime() const { return m_Time; } + + // Send + public: + PlaySPITStart(); + + void setPlayerID(string p_PlayerID); + void setPlayerName(string p_PlayerName); + void setPlayerType(char p_PlayerType); + void setPlayerIsRunning(bool p_IsPlaying); + void setTime(long long p_Time); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- PlaySPITObject ----------- + + class PlaySPITObject : public OPPart { + public: + static const int OPFLAG = 38; + static const int BYTESLENGTH = 100; + + private: + string m_PlayerID; + string m_SPITObjectID; + long long m_FrameInsideObject; // Frames + bool m_PlayPrePosition; + int m_Value; + char m_ValueFlag; + + void initMembers(); + + public: + ~PlaySPITObject(); + PlaySPITObject(const PlaySPITObject &orig); + // Receive + PlaySPITObject(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + const string getPlayerID() const { return m_PlayerID; } + const string getSPITObjectID() const { return m_SPITObjectID; } + long long getFrameInsideObject() const { return m_FrameInsideObject; } + bool getPlayPrePosition() const { return m_PlayPrePosition; } + int getValue() const { return m_Value; } + char getValueFlag() const { return m_ValueFlag; } + // Send + PlaySPITObject(); + + void setPlayerID(string p_PlayerID); + void setID(string p_ID); + void setFrameInsideObject(long long p_TimeInside); + void setPlayPrePosition(bool p_PlayOldPosition); + void setValue(int p_Value); + void setValueFlag(char p_ValueFlag); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- PlaySPITEnd ----------- + class PlaySPITEnd : public OPPart { + public: + static const int OPFLAG = 39; + static const int BYTESLENGTH = 45; + + private: + string m_PlayerID; + + void initMembers(); + + public: + ~PlaySPITEnd(); + PlaySPITEnd(const PlaySPITEnd &orig); + // Receive + PlaySPITEnd(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + const string getPlayerID() const { return m_PlayerID; } + // Send + public: + PlaySPITEnd(); + void setPlayerID(string p_PlayerID); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------- ReportPlayStatus ----------- + + class ReportPlayStatus : public OPPart { + public: + static const int OPFLAG = 40; + static const int BYTESLENGTH = 57; + + private: + string m_SPITObjectID; + long long m_FrameInsideObject; // Frames + int m_Value; + + void initMembers(); + + public: + ~ReportPlayStatus(); + ReportPlayStatus(const ReportPlayStatus &orig); + // Receive + ReportPlayStatus(Header *p_Header); + bool parse(char *p_Bytes, int p_ByteCount); + + const string getID() const { return m_SPITObjectID; } + long long getFrameInsideObject() const { return m_FrameInsideObject; } + int getValue() const { return m_Value; } + // Send + ReportPlayStatus(); + + void setID(string p_ID); + void setFrameInsideObject(long long p_TimeInside); + void setValue(int p_Value); + bool fillBytes(char *p_MessageBytes, int p_ByteCount); + }; + + //----------------------- static helper functions ---------------------------- + public: + static bool isSystemLittleEndian(); + static int getInt(char *p_Bytes, int p_ByteCount, int p_Offset); + static int setInt(int p_Value, char *p_Bytes, int p_ByteCount, int p_Offset); + static long long getLong(char *p_Bytes, int p_ByteCount, int p_Offset); + static int setLong(long long p_Value, char *p_Bytes, int p_ByteCount, int p_Offset); + static bool getBoolean(char *p_Bytes, int p_ByteCount, int p_Offset); + static int setBoolean(bool p_Value, char *p_Bytes, int p_ByteCount, int p_Offset); + static char getByte(char *p_Bytes, int p_ByteCount, int p_Offset); + static int setByte(int p_Value, char *p_Bytes, int p_ByteCount, int p_Offset); + /** + * Returns the string char* of the part of the byte sequence (0x00 null terminated). + * @param p_Bytes the byte array + * @param p_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. + * @return the String char* + * @throws Exception if p_Bytes == null
+ * p_Offset less than 0
+ * p_Bytes.length less than p_Offset + p_Length
+ * No 0x00 null terminate byte is found + */ + static string getString(char *p_Bytes, int p_ByteCount, int p_Offset, int p_Length); + + /** + * 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_Bytes the byte array where the string is filled + * @param p_Offset the offset inside the byte array + * @param p_Length the maximal length of the string included the null character.
+ * @throws Exception if p_String == NULL, p_Bytes == NULL
+ * p_Offset less than 0
+ * p_ByteCount less than p_Offset + p_Length + * @return p_Length + */ + static int setString(string p_String, char *p_Bytes, int p_ByteCount, int p_Offset, int p_Length); + /** + * Compares two strings for equality. + * @param p_String1 string terminated by null character + * @param p_String2 string terminated by null character + * @return true if both strings are equal
+ * false if the strings are NULL or not equal or not terminated by "\0" + */ + // static bool stringEqual(const char* p_String1, const char* p_String2); + // static char* stringCopy(const char* p_String); + static char *createByteArray(const OPPart *p_OPPart, int *p_BytesCount); }; #endif /* SPIT_MESSAGE_H */ - - - \ No newline at end of file diff --git a/components/spit/src/MyApp.cpp b/components/spit/src/MyApp.cpp deleted file mode 100644 index 6f25d82..0000000 --- a/components/spit/src/MyApp.cpp +++ /dev/null @@ -1,452 +0,0 @@ - -#include "MyApp.h" -#include "Task.hpp" -#include "esp_log.h" -#include "Semaphore.hpp" -#include "Queue.hpp" -#include - -const char *TAG = "SPIT"; - -MyApp::MyApp() : - _SpitClient ( - s_ClientName, s_ProjectName, - { - .onServerEvent = onServerEvent, - .onConnectionStatus = onConnectionStatus, - .onStartProjectTransfer = onStartProjectTransfer, - .onEndProjectTransfer = onEndProjectTransfer, - .onProjectClosed = onProjectClosed, - .onProjectReport = onProjectReport, - .onSpitType = onSpitType, - .onSpitTypeRemote = onSpitTypeRemote, - .onSpitObject = onSpitObject, - .onSpitObjectRemote = onSpitObjectRemote, - .onSpitTypeRemoved = onSpitTypeRemoved, - .onSpitTypeRemoteRemoved = onSpitTypeRemoteRemoved, - .onSpitObjectRemoved = onSpitObjectRemoved, - .onSpitObjectRemoteRemoved = onSpitObjectRemoteRemoved, - .onPlay = onPlay, - .onPlaySpitType = onPlaySpitType, - .onPlayRemoteObjectStatus = onPlayRemoteObjectStatus, - .onCheckSpitTypeVeto = onCheckSpitTypeVeto, - .onCheckSpitObjectVeto = onCheckSpitObjectVeto, - }) { - } - -string MyApp::m_ServerProjectID{}; -string MyApp::m_ServerProjectName{}; -int MyApp::m_ServerFramesPerSecond{44100}; // set when the server reports his project, see eventProjectReport - -void MyApp::init() { - SPITType *ptrSPITType1Fix = _SpitClient.createSPITTypeFixed("MySPITAPP_Action1ID", "ActionGroupName", "Action1Name", 0, 0); - SPITType *ptrSPITType2Fix = _SpitClient.createSPITTypeFixed("MySPITAPP_Action2ID", "ActionGroupName", "Action2Name", 0, 0); - - // When an action exist which should be done whenever a SPITObject with this SPITType is played, - // then you should 'setAssignedActionType' to true - _SpitClient.setActionSPITType(ptrSPITType1Fix->getID(), true); - _SpitClient.setActionSPITType(ptrSPITType2Fix->getID(), true); - _SpitClient.clientProjectLoaded(); - _SpitClient.startServerAutoDetect(); -} - -void MyApp::onServerEvent(SPIT_Client::ServerEvent event, const SAD_DetectedServer &p_DetectedServer) { - switch (event) - { - case SPIT_Client::ServerEvent::Detect: - ESP_LOGI(TAG, "SERVER DETECTED"); - ESP_LOGI(TAG, " Name: %s", p_DetectedServer.getName().data()); - ESP_LOGI(TAG, " ID: %s", p_DetectedServer.getID().data()); - ESP_LOGI(TAG, " Computer: %s", p_DetectedServer.getComputerName().data()); - ESP_LOGI(TAG, " IP: %s", p_DetectedServer.getIP().data()); - ESP_LOGI(TAG, " Port: %s", p_DetectedServer.getPort().data()); - ESP_LOGI(TAG, " Addition: %s", p_DetectedServer.getAdditions().data()); - ESP_LOGI(TAG, " ClientIP: %s", p_DetectedServer.getClientIP().data()); - break; - case SPIT_Client::ServerEvent::Lost: - ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data()); - - break; - case SPIT_Client::ServerEvent::Changed: - ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data()); - break; - - default: - break; - } -} - -//--------------------------------------- -//---------- Connecting event ---------- - -void MyApp::onConnectionStatus(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, int p_ConnectionStatus, int p_OldConnectionStatus) { - ESP_LOGI(TAG, "MySPITApp: eventConnectionStatus %d ", p_ConnectionStatus); -} - -//----------------------------------------------------------- -//---------- Server's Project events ------------------------ -/** - * The Server reports his loaded project - * Called when - * a) the connection to the server is established. - * b) server load a new project - * c) server saves the project under a new name - * @param p_ProjectID the server project's id (maybe the filename of the project or a part o it or the same as p_ProjectName) - * @param p_ProjectName the server project's name - * @param p_FramesPerSeoond All times in SPIT are given in frames. FramesPerSecond can be used to convert frames to seconds.... - */ -void MyApp::onProjectReport(string p_ProjectID, string p_ProjectName, int p_FramesPerSeoond) { - ESP_LOGI(TAG, "eventProjectReport ID: %s Name: %s FramesPerSecond: %d", p_ProjectID.data(), p_ProjectName.data(), p_FramesPerSeoond); - m_ServerProjectID = p_ProjectID; - m_ServerProjectName = p_ProjectName; - m_ServerFramesPerSecond = p_FramesPerSeoond; - // set the frames per second as the server - perhaps the client's time values have to be recalculated. -} - -/** - * Called when the server closes his project. - * @param p_ProjectID the id of the project - * The server loads only one project at time-> the ID is not actually necessary - */ -void MyApp::onProjectClosed(string p_ProjectID) { - ESP_LOGI(TAG, "eventProjectClosed ID: %s", p_ProjectID.data()); - // If we don't save SPITServer's project specific information - // perhaps close all SPITObjects and RemoteSPITObjects to avoid conflicts, when the SPITServer loads a new project - // SPITObject::clearSPITObjects(); - // SPITObject::clearSPITObjectsRemote(); -} - -// The server starts the transfer of its project, that means -// All SPITTypes and SPITObjects available on the server are transferred in the following. -void MyApp::onStartProjectTransfer() { - ESP_LOGI(TAG, "eventStartProjectTransfer"); -} -// The transfer of the server's SPITTypes and SPITObjects is finished. -void MyApp::onEndProjectTransfer() { - ESP_LOGI(TAG, "eventEndProjectTransfer"); -} - -//---------------------------------------------------- -//--------- SPITType events ---------- - - -/** - * The SPITCLientInterface (implemented by this) will be asked to veto the SPITType while SPIT_Client.parseReportSPITType.
- * @param p_ReportSPITType - * @return false = the SPITType is denied, true = the SPITType is accepted - */ -bool MyApp::onCheckSpitTypeVeto(SPIT_Message::ReportSPITType* p_ReportSPITType) { - if (p_ReportSPITType == NULL) return true; - SPITType* ptrSPITType; - ptrSPITType = SPITType::getSPITType(p_ReportSPITType->getID()); - - //Don't allow foreign SPITTypes - if (ptrSPITType == NULL) return false; - if (ptrSPITType->getCreatedByClient() == false) return false; - return true; -} - -bool MyApp::onCheckSpitObjectVeto(SPIT_Message::ReportSPITObject* p_ReportSPITObject) { - if (p_ReportSPITObject == NULL) return true; - SPITType* ptrSPITType; - ptrSPITType = SPITType::getSPITType(p_ReportSPITObject->getSPITTypeID()); - if (ptrSPITType == NULL) return false; - - //Don't allow SPITObjects which refers to a SPITType which is not created by this client - other SPITTypes cannot be handled here - //if (ptrSPITType->getCreatedByClient() == false) return false; - - // SPITObject* ptrSPITObject; -// ptrSPITObject = SPITObject::getSPITObject(p_ReportSPITOnject->getID()); - //Don't allow foreign SPITTypes -// if (ptrSPITObject == NULL) return false; - - return true; - -} - -/** - * Called when the server has created, loaded or changed a SPITType. - * May also occur when the server confirms a SPITType created or changed by the client. - * @param p_New true = server created a new SPITType - * false = server changed a existing SPITType - * @param p_SPITType a reference to a copy of the SPITType instance. - */ -void MyApp::onSpitType(bool p_New, const SPITType &p_SPITType) { - // fetch information of the SPITType - if (p_New) { - ESP_LOGD(TAG, "eventSPITType NEW"); - } else { - ESP_LOGD(TAG, "eventSPITType CHANGED"); - } - ESP_LOGI(TAG, " ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed()); - - // Check your actions - // Whenever you provide an action for this SPITType take this over in your code. - // call _SpitClient.setActionSPITType(p_SPITType.getID(), true); - - // for our little excample as described in loadClientProject we do following - // This may be redundand, because we defined the SPITTypes as fixed, so the server can't change them - // But foe all SPITTypes which are not fixed we need to setActionSPITType - - // if ("MySPITAPP_Action1ID" == p_SPITType.getID()) { - // _SpitClient.setActionSPITType(p_SPITType.getID(), true); - // } - // if ("MySPITAPP_Action2ID" == p_SPITType.getID()) { - // _SpitClient.setActionSPITType(p_SPITType.getID(), true); - // } -} -/** - * Called when the server has created or changed a Remote SPITType. - * Remote SPITType are used in Remote SPITObjects. A Remote SPITObject is used to remote control the SPITServer. - * @param p_New true = server created a new SPITType / false = server changed a existing SPITType - */ -void MyApp::onSpitTypeRemote(bool p_New, const SPITType &p_SPITType) { - if (p_New) { - ESP_LOGD(TAG, "eventSPITTypeRemote NEW"); - } else { - // we had to inform all Remote SPITObjects using the p_SPITType - // perhaps the SPITObject uses information from the SPITType - SPITObject *ptrSPITObject; - int intSPITObjectCount; - intSPITObjectCount = SPITObject::getSPITObjectRemoteCount(); - for (int intObject = 0; intObject < intSPITObjectCount; intObject++) { - ptrSPITObject = SPITObject::getSPITObjectRemote(intObject); - if (ptrSPITObject == NULL) - continue; - if (ptrSPITObject->getSPITTypeID() == p_SPITType.getID()) { - // call ecentSPITObjectRemote - onSpitObjectRemote(false, p_SPITType, *ptrSPITObject); - } - } - ESP_LOGD(TAG, "eventSPITTypeRemote CHANGED"); - } - ESP_LOGD(TAG, "ID: %s GroupName: %s Name: %s confirmed: %d", - p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed()); - // this is a remote SPITType, if you want you can list this for later remote use. -} - -/** - * Called when the server has removed a SPITType. - * After this function has been exited the SPITType is emeoved from the SPITType-List and the pointer is deleted. - * So use the pointer immediately or use the copyconstructor to make a copy for extended use. - * You have to release the copy yourself later (delete ptr...) - */ -void MyApp::onSpitTypeRemoved(const SPITType &p_SPITType) { - ESP_LOGD(TAG, "eventSPITType Removed"); - ESP_LOGD(TAG, " ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data()); - - // Check your actions - // take the removal of the SPITType over in your code - - // CAUTION: Deleted SPIT types can be added later again (perhaps per UNDO on the SPITServer) - //-> don't remove your assigned action immediately - keep it to reassign it later -} -/** - * Called when the server has removed a Remote SPITType. - * Remote SPITType are used in Remote SPITObjects. A Remote SPITObject is used to remote control the SPITServer. - * After this function has been exited the SPITType is emeoved from the Remote SPITType-List and the pointer is deleted. - * So use the pointer immediately or use the copyconstructor to make a copy for extended use. - * You have to release the copy yourself later (delete ptr...) - * @param p_SPITType a reference to a copy of the SPITType instance. - */ -void MyApp::onSpitTypeRemoteRemoved(const SPITType &p_SPITType) { - ESP_LOGD(TAG, "eventSPITTypeRemote Removed"); - ESP_LOGD(TAG, " ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data()); - - // This is a remote SPITType - // If you have listet this prior you should remove it from the list -} - -/** - * Called when the server has created, loaded or changed a SPITObject. - * May also occur when the server confirms a SPITObject created by the client, what the client should never do!!. - * @param p_New true = server created a new SPITObject - * false = server changed a existing SPITObject - * @param p_SPITType a reference to a copy of the associated SPITType instance. - * @param p_SPITObject a reference to a copy of the SPITObject instance. - */ -void MyApp::onSpitObject(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject) { - if (p_New) { - ESP_LOGI(TAG, "eventSPITObject NEW"); - } else { - ESP_LOGD(TAG, "eventSPITObject CHANGED"); - } - ESP_LOGI(TAG, " ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data()); - - // check your actions - // Whenever you provide an action for this SPITObject take this over in your code. - // call _SpitClient.setActionSPITObject(p_SPITObject.getID(), true); - - // for our little excample as described in loadClientProject: - // We have only actions for SPITTypes - means every SPITObject with the associated "Actionx"-SPITTypes will trigger the action when it is played - //-> no need to do something here, because setActionSPITType has been set prior and the SPITObject will automatically inherits this - // SPITObjects with other SPITTypes asscciated will trigger no actions -} -/** - * Called when the server has created or changed a Remote SPITObject. - * A Remote SPITObject is used to remote control the SPITServer. - * @param p_New true = server created a new remote SPITObject - * false = server changed a existing remote SPITObject - * @param p_SPITType a reference to a copy of the associated SPITType instance. - * @param p_SPITObject a reference to a copy of the SPITObject instance. - */ -void MyApp::onSpitObjectRemote(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject) { - if (p_New) { - ESP_LOGI(TAG, "eventSPITObjectRemote NEW"); - } else { - ESP_LOGD(TAG, "eventSPITObjectRemote CHANGED"); - } - ESP_LOGI(TAG, " ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data()); - - // This is a remote SPITObject which can be used to remote control the server. - // If you want you can list this for later use -} - -/** - * Called when the server has removed a SPITObject. - * After this function has been exited the SPITObject is emeoved from the SPITObject-List and the pointer is deleted. - * So use the pointer immediately or use the copyconstructor to make a copy for extended use. - * You have to release the copy yourself later (delete ptr...) - * @param p_SPITType a reference to a copy of the associated SPITType instance. - * @param p_SPITObject a reference to a copy of the SPITObject instance. - */ -void MyApp::onSpitObjectRemoved(const SPITType &p_SPITType, const SPITObject &p_SPITObject) { - ESP_LOGD(TAG, "eventSPITObject Removed"); - ESP_LOGD(TAG, " ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data()); - - // Check your actions - // take the removal of the SPITObject over in your code - - // CAUTION: Deleted SPITObjects can be added later again (perhaps per UNDO on the SPITServer) - //-> don't remove your assigned action immediately - keep it to reassign it later -} -/** - * Called when the server has removed a Remote SPITObject. - * A Remote SPITObject is used to remote control the SPITServer. - * After this function has been exited the SPITObject is emeoved from the SPITObject-List and the pointer is deleted. - * So use the pointer immediately or use the copyconstructor to make a copy for extended use. - * You have to release the copy yourself later (delete ptr...) - * @param p_SPITType a reference to a copy of the associated SPITType instance. - * @param p_SPITObject a reference to a copy of the SPITObject instance. - */ -void MyApp::onSpitObjectRemoteRemoved(const SPITType &p_SPITType, const SPITObject &p_SPITObject) { - ESP_LOGD(TAG, "eventSPITObjectRemote Removed"); - ESP_LOGD(TAG, " ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data()); - - // This is a remote SPITObject - // If you have listet this prior you should remove it from the list -} - -//-------------------------------------------------------------- -//---------------- Playing SPITObjects ---------------- -// Following is called when the SPITServer play SPITObjects. -// For every step the server does following sequence occurs: -// a) eventPlay -// b) several eventPlayObject for each actual played SPITObjectin this step -// NEXT STAP of the server -// a) eventPlay -// b) several eventPlayObject for each actual played SPITObject in this step -// ... - -// SPITServer may use several methods for playing SPITObjects. -// e.g. liveSHOWsoftware has the timeline and jingles which plays objects, where the timeline the main player is. -// SPIT distinguishes between the different players. All eventPlay... functions contain the information which player plays the SPIT object. - -void MyApp::onPlay(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames) { - ESP_LOGD(TAG, "eventPlay Player: %s Runs: %d Time: %lld", p_PlayerName.data(), p_PlayerIsRunning, p_TimeFrames); - - switch (p_PlayerType) { - case SPIT_Client::PLAYERTYPE_MAIN: - // p_FrameTimes contains the position inside the server's project, we can use it like a timecode - int intMilliseconds; - intMilliseconds = (int)(((double)p_TimeFrames / (double)m_ServerFramesPerSecond) * 1000); - break; - case SPIT_Client::PLAYERTYPE_CONTINOUS: - // The olayer is playing only single Object sequences sometime during the project - break; - case SPIT_Client::PLAYERTYPE_DISCRETE: - // Only discrete values where submitted, e.g the fader position of remote faders. - break; - } -} - -/** - * Called when the SPITServer plays a SPITObject. For every played SPITObject one eventPlayObject is called. - * You can decide here which action should be done or not. - * - * @param p_Started true = The SPITObject is newly played (e.g. in liveSHOWsoftware the cursor enters the SPITObject) - * @param p_Ended Das true = Playback of SPITObject finished (e.g. in liveSHOWsoftware the cursor has exited the SPIT object) - * @param p_SPITType the associated SPITType of p_SPITObject - * @param p_SPITObject the actual played or stopped SPITObject - * @param p_PlayObject contains information about the play status: - * frame where the cursor is inside the SPITObject - * whether the player is running or not - * the actual value of the SPITObject (in liveSHOWsoftware objects ma faded in or out or the main value is decreased, .. - */ -void MyApp::onPlaySpitType(string p_PlayerID, string p_SPITTypeID, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value) { - // double doubleValue = ((double)p_PlayObject.getValue() / 1000000) * ((double)p_PlayObject.getValueFactor() / 1000000); - - ESP_LOGD(TAG, "eventPlayObject Player: %s is running: %d Object Started: %d Stopped: %d", p_PlayerID.data(), p_PlayerIsRunning, p_Started, p_Ended); - // ESP_LOGD(TAG, " SPITType: %s SPITObject: %s Position: %lld Value: %f\n", p_SPITTypeID.data(), p_SPITObject.getName().data(), p_PlayObject.getFrameInside(), doubleValue); - ESP_LOGD(TAG, " SPITType: %s Value: %f\n", p_SPITTypeID.data(), p_Value); - - if (p_SPITTypeID == "MySPITAPP_Action1ID") { // do Action 1 - // we can get some information about the play status - if (p_Started == true) { - ESP_LOGI(TAG, "MyApp AKTION 1 started Value: %f and running: %d", p_Value, p_PlayerIsRunning); - } else if (p_Ended == true) { - ESP_LOGI(TAG, "MyApp AKTION 1 ended"); // p_PlayObject.getFrameInside() is -1 - } else { - ESP_LOGD(TAG, "MyApp AKTION 1 is played Value: %f and running: %d", p_Value, p_PlayerIsRunning); - } - } else if (p_SPITTypeID == "MySPITAPP_Action2ID") { // do Action 2 - if (p_Started == true) { - ESP_LOGI(TAG, "AKTION 2 started Value: %f and running: %d", p_Value, p_PlayerIsRunning); - } else if (p_Ended == true) { - ESP_LOGI(TAG, "AKTION 2 ended"); // p_PlayObject.getFrameInside() is -1 - } else { - ESP_LOGD(TAG, "AKTION 2 is played Value: %f and running: %d", p_Value, p_PlayerIsRunning); - } - } -} - -//-------------------------------------------------------------- -//---------------- Remote Control SPITServer ---------------- -// The SPITServer has sent all possibilities to control it remotely - remote SPITObjects - see eventSPITObjectRemote -// Some of them may control functionality with values (fader psotions for loudness of sound, ...). -// When the server changes one of these value objects, it sends an eventPlayRemoteObjectStatus. - -/** - * Called when a remote SpitObject which value function is changed by the server. - * This allows the Client to adjust its display for the remote command. - * @param p_SPITType the assigned remote SPITType of p_SPITObject - * @param p_SPITObject the remote SPITObject which is changed - * @param p_FrameInsideObject can be discarded - * @param p_Value the new value - */ -void MyApp::onPlayRemoteObjectStatus(const SPITType &p_SPITType, const SPITObject &p_SPITObject, long long p_FrameInsideObject, int p_Value) { - ESP_LOGD(TAG, "eventPlayRemoteObjectStatus RemoteSPITType: %s RemoteSPITObject: %s Position: %lld Value: %d", p_SPITType.getName().data(), p_SPITObject.getName().data(), p_FrameInsideObject, p_Value); -} - -/** - * 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 p_Valueppm the value in ppm - * in case a) the value is ignored - * in case b) the value is used - * @param p_ValueFlag indicates how the server should use p_Valueppm: - * VALUEFLAG_DIRECT (0x00) The server will overwrite his existing value with p_Value - * VALUEFLAG_INCREASE (0x01) The server increases his existing value by p_Valueppm - * VALUEFLAG_DECREASE (0x01) The server decreases his existing value by p_Valueppm - */ -void MyApp::sendRemoteObject(string p_SPITObjectID, int p_Valueppm, char p_ValueFlag) { - _SpitClient.sendRemoteObject(p_SPITObjectID, p_Valueppm, p_ValueFlag); -} - -void MyApp::testLiveShowRemote() { - // We jump to the next Scenebridge - no Value is needed - _SpitClient.sendRemoteObject("playControlStart"); -} diff --git a/components/spit/src/SAD_DetectedServer.cpp b/components/spit/src/SAD_DetectedServer.cpp index db85926..e50825f 100644 --- a/components/spit/src/SAD_DetectedServer.cpp +++ b/components/spit/src/SAD_DetectedServer.cpp @@ -4,174 +4,130 @@ * and open the template in the editor. */ -/* +/* * SAD_DetectedServer holds information about SPIT Server detected by ServerAutoDetection (SAD). * File: SAD_DetectedServer.cpp * Author: Hagi - * + * * Created on 4. Mai 2019, 13:51 */ #include "SAD_DetectedServer.hpp" #include "esp_log.h" -static const char * TAG = "SpitSrv"; +static const char *TAG = "SpitSrv"; -unordered_map SAD_DetectedServer::s_DetectedServers; +unordered_map SAD_DetectedServer::s_DetectedServers; SAD_DetectedServer::~SAD_DetectedServer() { } //----- Detected Server ----- SAD_DetectedServer::SAD_DetectedServer() { - m_ID = ""; - m_Name = ""; - m_ComputerName = ""; - m_ClientIP = ""; - m_Port = ""; - m_Additions = ""; - m_IPIsIP4 = false; + m_ID = ""; + m_Name = ""; + m_ComputerName = ""; + m_ClientIP = ""; + m_Port = ""; + m_Additions = ""; } void SAD_DetectedServer::setProjectName(string p_ServerProjectName) { - if (m_ServerProjectName.compare(p_ServerProjectName) != 0) { - if (m_New == false) { - m_Changed = true; - } - } - m_ServerProjectName = p_ServerProjectName; + if (m_ServerProjectName.compare(p_ServerProjectName) != 0) { + if (m_New == false) { + m_Changed = true; + } + } + m_ServerProjectName = p_ServerProjectName; } void SAD_DetectedServer::cycleStart() { - for (auto i = s_DetectedServers.begin(); i != s_DetectedServers.end(); i++) { - i->second->startCycleSAD(); - } + for (auto i = s_DetectedServers.begin(); i != s_DetectedServers.end(); i++) { + i->second->startCycleSAD(); + } } -void SAD_DetectedServer::cycleEnd(I_SAD_Client& sadClient) { - list o_LostServers; - list o_NewServers; - list o_ChangedServers; - SAD_DetectedServer* ptrDetectedServer; - { - for (auto i = s_DetectedServers.begin(); i != s_DetectedServers.end(); i++) { - ptrDetectedServer = i->second; - if (ptrDetectedServer->getFoundAgain() == false) { - o_LostServers.push_back(ptrDetectedServer); - ptrDetectedServer->endCycleSAD(); - } - else if (ptrDetectedServer->getNew()) { - o_NewServers.push_back(ptrDetectedServer); - ptrDetectedServer->setNew(false); - ptrDetectedServer->endCycleSAD(); - } - else if (ptrDetectedServer->getChanged()) { - o_ChangedServers.push_back(ptrDetectedServer); - ptrDetectedServer->endCycleSAD(); - } - else { - ptrDetectedServer->endCycleSAD(); - } - } - } - //Notify client interface about lost servers - for (auto i = o_LostServers.begin(); i != o_LostServers.end(); i++) { - ptrDetectedServer = *i; - sadClient.eventServerLost(ptrDetectedServer->getID(), ptrDetectedServer->getName(), - ptrDetectedServer->getComputerName(), ptrDetectedServer->getIP(), ptrDetectedServer->getPort(), ptrDetectedServer->getAdditions(),ptrDetectedServer->getProjectName(), - ptrDetectedServer->getClientIP(), - ptrDetectedServer->getIpIsIP4()); - } - //Remove lost servers - for (auto i = o_LostServers.begin(); i != o_LostServers.end(); i++) { - ptrDetectedServer = *i; - removeDetectedServer(ptrDetectedServer); - } - o_LostServers.clear(); - - for (auto i = o_NewServers.begin(); i != o_NewServers.end(); i++) { - ptrDetectedServer = *i; - sadClient.eventServerDetected(ptrDetectedServer->getID(), ptrDetectedServer->getName(), - ptrDetectedServer->getComputerName(), ptrDetectedServer->getIP(), ptrDetectedServer->getPort(), ptrDetectedServer->getAdditions(),ptrDetectedServer->getProjectName(), - ptrDetectedServer->getClientIP(), - ptrDetectedServer->getIpIsIP4()); - } - o_NewServers.clear(); - for (auto i = o_ChangedServers.begin(); i != o_ChangedServers.end(); i++) { - ptrDetectedServer = *i; - sadClient.eventServerChanged(ptrDetectedServer->getID(), ptrDetectedServer->getName(), - ptrDetectedServer->getComputerName(), ptrDetectedServer->getIP(), ptrDetectedServer->getPort(), ptrDetectedServer->getAdditions(),ptrDetectedServer->getProjectName(), - ptrDetectedServer->getClientIP(), - ptrDetectedServer->getIpIsIP4()); - } - o_ChangedServers.clear(); +void SAD_DetectedServer::cycleEnd(I_SAD_Client &sadClient) { + for (auto &srv : s_DetectedServers) { + SAD_DetectedServer *ptrDetectedServer = srv.second; + if (ptrDetectedServer->getFoundAgain() == false) { + sadClient.eventServerLost(*ptrDetectedServer); + removeDetectedServer(*ptrDetectedServer); + } else if (ptrDetectedServer->getNew()) { + ptrDetectedServer->setNew(false); + sadClient.eventServerDetected(*ptrDetectedServer); + } else if (ptrDetectedServer->getChanged()) { + sadClient.eventServerChanged(*ptrDetectedServer); + } + } } - /** - * Used by SAD_Client to add a found SPITServer - don't use this manually - * @param p_IsIP4 true = the server is reached via a IP4 address
false = the server is reahed via a IP6 address - * @param p_ServerID the id of the server, every instance of a SPITServer has an own id - * @param p_ServerParams the server's parameter - */ -void SAD_DetectedServer::addDetectedServer(bool p_IsIP4, string p_ServerID, string p_ServerParams[]) { - SAD_DetectedServer* ptrDetectedServer; - { - auto i = s_DetectedServers.find(p_ServerID); - if (i != s_DetectedServers.end()) { - ptrDetectedServer = i->second; - } - else { - ptrDetectedServer = new SAD_DetectedServer(); - ptrDetectedServer->setID(p_ServerParams[PARAMINDEX_ID]); - ptrDetectedServer->setNew(true); - } - ptrDetectedServer->setFoundAgain(); - //second prefer IP4 - if (p_IsIP4 == true) { - ptrDetectedServer->setIP(p_ServerParams[PARAMINDEX_IP]); - ptrDetectedServer->setIPIsIP4(true); - ptrDetectedServer->setClientIP(p_ServerParams[PARAMINDEX_CLIENTIP]); - } - else if (ptrDetectedServer->getIpIsIP4() == false){ - ptrDetectedServer->setIP(p_ServerParams[PARAMINDEX_IP]); - ptrDetectedServer->setClientIP(p_ServerParams[PARAMINDEX_CLIENTIP]); - } - ptrDetectedServer->setName(p_ServerParams[PARAMINDEX_NAME]); - ptrDetectedServer->setComputerName(p_ServerParams[PARAMINDEX_COMPUTERNAME]); - ptrDetectedServer->setPort(p_ServerParams[PARAMINDEX_PORT]); - ptrDetectedServer->setAdditions(p_ServerParams[PARAMINDEX_ADDITIONS]); - ptrDetectedServer->setProjectName(p_ServerParams[PARAMINDEX_SERVERPROJECTNAME]); +/** + * Used by SAD_Client to add a found SPITServer - don't use this manually + * @param p_IsIP4 true = the server is reached via a IP4 address
false = the server is reahed via a IP6 address + * @param p_ServerID the id of the server, every instance of a SPITServer has an own id + * @param p_ServerParams the server's parameter + */ +void SAD_DetectedServer::addDetectedServer(string p_ServerID, string p_ServerParams[]) { + SAD_DetectedServer *ptrDetectedServer; + { + auto i = s_DetectedServers.find(p_ServerID); + if (i != s_DetectedServers.end()) { + ptrDetectedServer = i->second; + } else { + ptrDetectedServer = new SAD_DetectedServer(); + ptrDetectedServer->setID(p_ServerParams[PARAMINDEX_ID]); + ptrDetectedServer->setNew(true); + } + ptrDetectedServer->setFoundAgain(); - s_DetectedServers[ptrDetectedServer->getID()] = ptrDetectedServer; - } - } - /** - * Used by SAD_Client to remove a SPITServer - don't use this manually - * @param p_DetectedServer - */ -void SAD_DetectedServer::removeDetectedServer(SAD_DetectedServer* p_DetectedServer) { - SAD_DetectedServer* o_DetectedServer; - { - auto i = s_DetectedServers.find(p_DetectedServer->getID()); - if (i != s_DetectedServers.end()) { - o_DetectedServer = i->second; - i = s_DetectedServers.erase(i); - delete o_DetectedServer; - } - } - } - - /** - * Used by SAD_Client to clear all found SPITServers - don't use this manually - */ + // second prefer IP4 + ptrDetectedServer->setIP(p_ServerParams[PARAMINDEX_IP]); + ptrDetectedServer->setClientIP(p_ServerParams[PARAMINDEX_CLIENTIP]); + ptrDetectedServer->setName(p_ServerParams[PARAMINDEX_NAME]); + ptrDetectedServer->setComputerName(p_ServerParams[PARAMINDEX_COMPUTERNAME]); + ptrDetectedServer->setPort(p_ServerParams[PARAMINDEX_PORT]); + ptrDetectedServer->setAdditions(p_ServerParams[PARAMINDEX_ADDITIONS]); + ptrDetectedServer->setProjectName(p_ServerParams[PARAMINDEX_SERVERPROJECTNAME]); + + s_DetectedServers[ptrDetectedServer->getID()] = ptrDetectedServer; + } +} +/** + * Used by SAD_Client to remove a SPITServer - don't use this manually + * @param p_DetectedServer + */ +void SAD_DetectedServer::removeDetectedServer(SAD_DetectedServer &server) { + auto i = s_DetectedServers.find(server.getID()); + if (i != s_DetectedServers.end()) { + SAD_DetectedServer *o_DetectedServer = i->second; + i = s_DetectedServers.erase(i); + delete o_DetectedServer; + } +} + +/** + * Used by SAD_Client to clear all found SPITServers - don't use this manually + */ void SAD_DetectedServer::clearDetectedServers() { - SAD_DetectedServer* ptrDetectedServer; - { - for (auto i = s_DetectedServers.begin(); i != s_DetectedServers.end(); i++) { - ptrDetectedServer = i->second; - i = s_DetectedServers.erase(i); - delete ptrDetectedServer; - if (i == s_DetectedServers.end()) { - break; - } - } - } - } + for (auto i = s_DetectedServers.begin(); i != s_DetectedServers.end(); i++) { + SAD_DetectedServer *ptrDetectedServer = i->second; + i = s_DetectedServers.erase(i); + delete ptrDetectedServer; + if (i == s_DetectedServers.end()) { + break; + } + } +} + +const SAD_DetectedServer &SAD_DetectedServer::getRefDetectedServer(string p_ServerID) { + SAD_DetectedServer *ptrDetectedServer = nullptr; + + auto i = s_DetectedServers.find(p_ServerID); + if (i != s_DetectedServers.end()) { + ptrDetectedServer = i->second; + } + if (ptrDetectedServer != NULL) { + return *ptrDetectedServer; + } + + throw new exception(); +} \ No newline at end of file diff --git a/components/spit/src/SPITObject.cpp b/components/spit/src/SPITObject.cpp index 03c3132..377945b 100644 --- a/components/spit/src/SPITObject.cpp +++ b/components/spit/src/SPITObject.cpp @@ -4,427 +4,438 @@ * and open the template in the editor. */ -/* - * SPITObject describes a SPIT Object +/* + * SPITObject describes a SPIT Object * File: SPITObject.cpp * Author: Hagi - * + * * Created on 9. April 2019, 12:11 */ #include "SPITObject.h" #include "SPITSocket.h" - unordered_map SPITObject::s_SPITObjects; - unordered_map SPITObject::s_SPITObjectsRemote; - - SPITObject* SPITObject::getSPITObject(string p_ID) { - { - auto i = s_SPITObjects.find(p_ID); - if (i == s_SPITObjects.end()) { - return NULL; - } - return i->second; - } - } - /** - * Returns the reference of the SPITObject with ID == p_ID.
- * Throws an exception if no SPITObject is not found.
- * @param p_ID the ID - * @return reference of the SPITType with ID == p_ID - */ - const SPITObject& SPITObject::getSPITObjectRef(string p_ID) { - { - auto i = s_SPITObjects.find(p_ID); - if (i == s_SPITObjects.end()) { - throw "SPITObject no SPITObject with given id"; - } - return *(i->second); - } - } - - SPITObject* SPITObject::getSPITObjectRemote(string p_ID) { - { - auto i = s_SPITObjectsRemote.find(p_ID); - if (i == s_SPITObjectsRemote.end()) { - return NULL; - } - return i->second; - } - } - /** - * Returns the reference of the remote SPITObject with ID == p_ID.
- * Throws an exception if no SPITObject is not found.
- * @param p_ID the ID - * @return reference of the SPITType with ID == p_ID - */ - const SPITObject& SPITObject::getSPITObjectRemoteRef(string p_ID) { - { - auto i = s_SPITObjectsRemote.find(p_ID); - if (i == s_SPITObjectsRemote.end()) { - throw "Remote SPITObject no SPITObject with given id"; - } - return *(i->second); - } - } +unordered_map SPITObject::s_SPITObjects; +unordered_map SPITObject::s_SPITObjectsRemote; - bool SPITObject::addSPITObject(SPITObject* p_ptrSPITObject) { - if (p_ptrSPITObject == NULL) return false; - { - s_SPITObjects[p_ptrSPITObject->getID()] = p_ptrSPITObject; - return true; - } - } - bool SPITObject::addSPITObjectRemote(SPITObject* p_ptrSPITObject) { - if (p_ptrSPITObject == NULL) return false; - { - s_SPITObjectsRemote[p_ptrSPITObject->getID()] = p_ptrSPITObject; - return true; - } - } - bool SPITObject::removeSPITObject(SPITObject* p_ptrSPITObject) { - if (p_ptrSPITObject == NULL) return false; - return removeSPITObject(p_ptrSPITObject->getID()); - } - bool SPITObject::removeSPITObject(string p_SPITObjectID) { - { - auto i = s_SPITObjects.find(p_SPITObjectID); - if (i == s_SPITObjects.end()) { - return false; - } - i = s_SPITObjects.erase(i); - return true; - } - } - bool SPITObject::removeSPITObjectRemote(SPITObject* p_ptrSPITObject) { - if (p_ptrSPITObject == NULL) return false; - return removeSPITObjectRemote(p_ptrSPITObject->getID()); - } - bool SPITObject::removeSPITObjectRemote(string p_ptrSPITObject) { - { - auto i = s_SPITObjectsRemote.find(p_ptrSPITObject); - if (i == s_SPITObjectsRemote.end()) { - return false; - } - i = s_SPITObjectsRemote.erase(i); - return true; - } - } +SPITObject *SPITObject::getSPITObject(string p_ID) { + { + auto i = s_SPITObjects.find(p_ID); + if (i == s_SPITObjects.end()) { + return NULL; + } + return i->second; + } +} +/** + * Returns the reference of the SPITObject with ID == p_ID.
+ * Throws an exception if no SPITObject is not found.
+ * @param p_ID the ID + * @return reference of the SPITType with ID == p_ID + */ +const SPITObject &SPITObject::getSPITObjectRef(string p_ID) { + { + auto i = s_SPITObjects.find(p_ID); + if (i == s_SPITObjects.end()) { + throw "SPITObject no SPITObject with given id"; + } + return *(i->second); + } +} - int SPITObject::getSPITObjectCount() { - return s_SPITObjects.size(); - } - int SPITObject::getSPITObjectRemoteCount() { - return s_SPITObjectsRemote.size(); - } - SPITObject* SPITObject::getSPITObject(int p_Index) { - SPITObject* ptrSPITObject = NULL; - { - if (p_Index >= 0 && p_Index < s_SPITObjects.size()) { - unordered_map::iterator i = next(s_SPITObjects.begin(), p_Index); - ptrSPITObject = i->second; - return ptrSPITObject; - } - else { - return NULL; - } - } - } - /** - * Returns a reference to the SPITObject at position p_Index.
- * Throws an exception if p_Index is out of range.
- * @param p_Index position - * @return the reference of the SPITObject at position. - */ - const SPITObject& SPITObject::getSPITObjectRef(int p_Index) { - SPITObject* ptrSPITObject = NULL; - { - if (p_Index >= 0 && p_Index < s_SPITObjects.size()) { - unordered_map::iterator i = next(s_SPITObjects.begin(), p_Index); - ptrSPITObject = i->second; - return *ptrSPITObject; - } - else { - throw "SPITObject index out of range"; - } - } - } - SPITObject* SPITObject::getSPITObjectRemote(int p_Index) { - SPITObject* ptrSPITObject = NULL; - { - if (p_Index >= 0 && p_Index < s_SPITObjectsRemote.size()) { - unordered_map::iterator i = next(s_SPITObjectsRemote.begin(), p_Index); - ptrSPITObject = i->second; - return ptrSPITObject; - } - else { - return NULL; - } - } - } - /** - * Returns a reference to the remote SPITObject at position p_Index.
- * Throws an exception if p_Index is out of range.
- * @param p_Index position - * @return the reference of the SPITObject at position. - */ - const SPITObject& SPITObject::getSPITObjectRemoteRef(int p_Index) { - SPITObject* ptrSPITObject = NULL; - { - if (p_Index >= 0 && p_Index < s_SPITObjectsRemote.size()) { - unordered_map::iterator i = next(s_SPITObjectsRemote.begin(), p_Index); - ptrSPITObject = i->second; - return *ptrSPITObject; - } - else { - throw "Remote SPITObject index out of range"; - } - } - } - - void SPITObject::clearSPITObjects() { - SPITObject* ptrSPITObject; - { - for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { - ptrSPITObject = i->second; - i = s_SPITObjects.erase(i); - delete ptrSPITObject; - if (i == s_SPITObjects.end()) { - break; - } - } - } - } - void SPITObject::clearSPITObjectsRemote() { - SPITObject* ptrSPITObject; - { - for (auto i = s_SPITObjectsRemote.begin(); i != s_SPITObjectsRemote.end(); i++) { - ptrSPITObject = i->second; - i = s_SPITObjectsRemote.erase(i); - delete ptrSPITObject; - if (i == s_SPITObjectsRemote.end()) { - break; - } - } - } - } +SPITObject *SPITObject::getSPITObjectRemote(string p_ID) { + { + auto i = s_SPITObjectsRemote.find(p_ID); + if (i == s_SPITObjectsRemote.end()) { + return NULL; + } + return i->second; + } +} +/** + * Returns the reference of the remote SPITObject with ID == p_ID.
+ * Throws an exception if no SPITObject is not found.
+ * @param p_ID the ID + * @return reference of the SPITType with ID == p_ID + */ +const SPITObject &SPITObject::getSPITObjectRemoteRef(string p_ID) { + { + auto i = s_SPITObjectsRemote.find(p_ID); + if (i == s_SPITObjectsRemote.end()) { + throw "Remote SPITObject no SPITObject with given id"; + } + return *(i->second); + } +} - /** - * clears all unconfirmed SPITObjects not created by this SPIT_Client. - */ - void SPITObject::clearUnconfirmedSPITObjects() { - for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { - SPITObject* ptrSPITObject = i->second; - if (ptrSPITObject->getCreatedByClient() == false && ptrSPITObject->getConfirmed() == false) { - i = s_SPITObjects.erase(i); - delete ptrSPITObject; - } - if (i == s_SPITObjects.end()) { - break; - } - } - } +bool SPITObject::addSPITObject(SPITObject *p_ptrSPITObject) { + if (p_ptrSPITObject == NULL) + return false; + { + s_SPITObjects[p_ptrSPITObject->getID()] = p_ptrSPITObject; + return true; + } +} +bool SPITObject::addSPITObjectRemote(SPITObject *p_ptrSPITObject) { + if (p_ptrSPITObject == NULL) + return false; + { + s_SPITObjectsRemote[p_ptrSPITObject->getID()] = p_ptrSPITObject; + return true; + } +} +bool SPITObject::removeSPITObject(SPITObject *p_ptrSPITObject) { + if (p_ptrSPITObject == NULL) + return false; + return removeSPITObject(p_ptrSPITObject->getID()); +} +bool SPITObject::removeSPITObject(string p_SPITObjectID) { + { + auto i = s_SPITObjects.find(p_SPITObjectID); + if (i == s_SPITObjects.end()) { + return false; + } + i = s_SPITObjects.erase(i); + return true; + } +} +bool SPITObject::removeSPITObjectRemote(SPITObject *p_ptrSPITObject) { + if (p_ptrSPITObject == NULL) + return false; + return removeSPITObjectRemote(p_ptrSPITObject->getID()); +} +bool SPITObject::removeSPITObjectRemote(string p_ptrSPITObject) { + { + auto i = s_SPITObjectsRemote.find(p_ptrSPITObject); + if (i == s_SPITObjectsRemote.end()) { + return false; + } + i = s_SPITObjectsRemote.erase(i); + return true; + } +} - void SPITObject::eventProjectClosed() { - for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { - SPITObject* ptrSPITObject = i->second; - if (ptrSPITObject->getCreatedByClient() == true) { - continue; - } - i = s_SPITObjects.erase(i); - delete ptrSPITObject; - if (i == s_SPITObjects.end()) { - break; - } - } - //Remote - for (auto i = s_SPITObjectsRemote.begin(); i != s_SPITObjectsRemote.end(); i++) { - SPITObject* ptrSPITObject = i->second; - i = s_SPITObjectsRemote.erase(i); - delete ptrSPITObject; - if (i == s_SPITObjectsRemote.end()) { - break; - } - } - } - /** - * sets confirmed = false for all SPITObjects.
- * This should be called when the client has loaded a project.
- */ - void SPITObject::setConfirmedFalse() { - SPITObject* ptrSPITObject; - { - for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { - ptrSPITObject = i->second; - ptrSPITObject->setConfirmed(false); - } - } - } +int SPITObject::getSPITObjectCount() { + return s_SPITObjects.size(); +} +int SPITObject::getSPITObjectRemoteCount() { + return s_SPITObjectsRemote.size(); +} +SPITObject *SPITObject::getSPITObject(int p_Index) { + SPITObject *ptrSPITObject = NULL; + { + if (p_Index >= 0 && p_Index < s_SPITObjects.size()) { + unordered_map::iterator i = next(s_SPITObjects.begin(), p_Index); + ptrSPITObject = i->second; + return ptrSPITObject; + } else { + return NULL; + } + } +} +/** + * Returns a reference to the SPITObject at position p_Index.
+ * Throws an exception if p_Index is out of range.
+ * @param p_Index position + * @return the reference of the SPITObject at position. + */ +const SPITObject &SPITObject::getSPITObjectRef(int p_Index) { + SPITObject *ptrSPITObject = NULL; + { + if (p_Index >= 0 && p_Index < s_SPITObjects.size()) { + unordered_map::iterator i = next(s_SPITObjects.begin(), p_Index); + ptrSPITObject = i->second; + return *ptrSPITObject; + } else { + throw "SPITObject index out of range"; + } + } +} +SPITObject *SPITObject::getSPITObjectRemote(int p_Index) { + SPITObject *ptrSPITObject = NULL; + { + if (p_Index >= 0 && p_Index < s_SPITObjectsRemote.size()) { + unordered_map::iterator i = next(s_SPITObjectsRemote.begin(), p_Index); + ptrSPITObject = i->second; + return ptrSPITObject; + } else { + return NULL; + } + } +} +/** + * Returns a reference to the remote SPITObject at position p_Index.
+ * Throws an exception if p_Index is out of range.
+ * @param p_Index position + * @return the reference of the SPITObject at position. + */ +const SPITObject &SPITObject::getSPITObjectRemoteRef(int p_Index) { + SPITObject *ptrSPITObject = NULL; + { + if (p_Index >= 0 && p_Index < s_SPITObjectsRemote.size()) { + unordered_map::iterator i = next(s_SPITObjectsRemote.begin(), p_Index); + ptrSPITObject = i->second; + return *ptrSPITObject; + } else { + throw "Remote SPITObject index out of range"; + } + } +} +void SPITObject::clearSPITObjects() { + SPITObject *ptrSPITObject; + { + for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { + ptrSPITObject = i->second; + i = s_SPITObjects.erase(i); + delete ptrSPITObject; + if (i == s_SPITObjects.end()) { + break; + } + } + } +} +void SPITObject::clearSPITObjectsRemote() { + SPITObject *ptrSPITObject; + { + for (auto i = s_SPITObjectsRemote.begin(); i != s_SPITObjectsRemote.end(); i++) { + ptrSPITObject = i->second; + i = s_SPITObjectsRemote.erase(i); + delete ptrSPITObject; + if (i == s_SPITObjectsRemote.end()) { + break; + } + } + } +} + +/** + * clears all unconfirmed SPITObjects not created by this SPIT_Client. + */ +void SPITObject::clearUnconfirmedSPITObjects() { + for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { + SPITObject *ptrSPITObject = i->second; + if (ptrSPITObject->getCreatedByClient() == false && ptrSPITObject->getConfirmed() == false) { + i = s_SPITObjects.erase(i); + delete ptrSPITObject; + } + if (i == s_SPITObjects.end()) { + break; + } + } +} + +void SPITObject::eventProjectClosed() { + for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { + SPITObject *ptrSPITObject = i->second; + if (ptrSPITObject->getCreatedByClient() == true) { + continue; + } + i = s_SPITObjects.erase(i); + delete ptrSPITObject; + if (i == s_SPITObjects.end()) { + break; + } + } + // Remote + for (auto i = s_SPITObjectsRemote.begin(); i != s_SPITObjectsRemote.end(); i++) { + SPITObject *ptrSPITObject = i->second; + i = s_SPITObjectsRemote.erase(i); + delete ptrSPITObject; + if (i == s_SPITObjectsRemote.end()) { + break; + } + } +} +/** + * sets confirmed = false for all SPITObjects.
+ * This should be called when the client has loaded a project.
+ */ +void SPITObject::setConfirmedFalse() { + SPITObject *ptrSPITObject; + { + for (auto i = s_SPITObjects.begin(); i != s_SPITObjects.end(); i++) { + ptrSPITObject = i->second; + ptrSPITObject->setConfirmed(false); + } + } +} - SPITObject::SPITObject() { - initMembers(); + initMembers(); } void SPITObject::initMembers() { - m_ActionAssigned = false; - m_ActionAssignedType = false; - m_Confirmed = false; - m_Delay = 0; - m_Duration = 0; - m_Fixed = false; - m_CreatedByClient = false; - m_FrameFadeInLength = 0; - m_FrameFadeOutLength = 0; - m_FrameLength = 0; - m_FrameStart = 0; - m_Remark = ""; - m_ID = createGUID(); - m_Name = ""; - m_SPITTypeID = ""; - m_ServerParams = ""; - m_ServerRemote = false; - m_Track = 0; - m_ValueFactor = 1000000; //Values are given in ppm -> 1000000 = 1/1; - m_ValueUse = 0x01; + m_ActionAssigned = false; + m_ActionAssignedType = false; + m_Confirmed = false; + m_Delay = 0; + m_Duration = 0; + m_Fixed = false; + m_CreatedByClient = false; + m_FrameFadeInLength = 0; + m_FrameFadeOutLength = 0; + m_FrameLength = 0; + m_FrameStart = 0; + m_Remark = ""; + m_ID = createGUID(); + m_Name = ""; + m_SPITTypeID = ""; + m_ServerParams = ""; + m_ServerRemote = false; + m_Track = 0; + m_ValueFactor = 1000000; // Values are given in ppm -> 1000000 = 1/1; + m_ValueUse = 0x01; } -SPITObject::~SPITObject() { } +SPITObject::~SPITObject() {} +bool SPITObject::setMessageOP(SPIT_Message::ReportSPITObject *p_ReportSPITObject) { + bool boolChangeAllowed; + bool boolChanged = false; -bool SPITObject::setMessageOP(SPIT_Message::ReportSPITObject* p_ReportSPITObject) { - bool boolChangeAllowed; - bool boolChanged = false; - - if (m_CreatedByClient == true && m_Fixed == true) { - boolChangeAllowed = false; - } - else { - boolChangeAllowed = true; - } - - //Confirmation should be changable - if (m_CreatedByClient) { - //Server reports a client created SPITType -> the type is confirmed - m_Confirmed = true; - } - else { - //type is NOT client created -> the client has to confirm the SPITtype - m_Confirmed = p_ReportSPITObject->getConfirmed(); - } - - if (m_Delay != p_ReportSPITObject->getDelay()) { - if (boolChangeAllowed == false) throw new exception(); - m_Delay = p_ReportSPITObject->getDelay(); - boolChanged = true; - } - if (m_Duration != p_ReportSPITObject->getDuration()) { - if (boolChangeAllowed == false) throw new exception(); - m_Duration = p_ReportSPITObject->getDuration(); - boolChanged = true; - } - if (m_Fixed != p_ReportSPITObject->getFixed()) { - if (boolChangeAllowed == false) throw new exception(); - m_Fixed = p_ReportSPITObject->getFixed(); - boolChanged = true; - } - if (m_FrameFadeInLength != p_ReportSPITObject->getFrameFadeInLength()) { - if (boolChangeAllowed == false) throw new exception(); - m_FrameFadeInLength = p_ReportSPITObject->getFrameFadeInLength(); - boolChanged= true; - } - if (m_FrameFadeOutLength != p_ReportSPITObject->getFrameFadeOutLength()) { - if (boolChangeAllowed == false) throw new exception(); - m_FrameFadeOutLength = p_ReportSPITObject->getFrameFadeOutLength(); - boolChanged = true; - } - if (m_FrameLength != p_ReportSPITObject->getFrameLength()) { - if (boolChangeAllowed == false) throw new exception(); - m_FrameLength = p_ReportSPITObject->getFrameLength(); - boolChanged = true; - } - if (m_FrameStart != p_ReportSPITObject->getFrameStart()) { - if (boolChangeAllowed == false) throw new exception(); - m_FrameStart = p_ReportSPITObject->getFrameStart(); - boolChanged = true; - } - if (m_Remark != p_ReportSPITObject->getRemark()) { - if (boolChangeAllowed == false) throw new exception(); - m_Remark = p_ReportSPITObject->getRemark(); - boolChanged = true; - } - if (m_ID != p_ReportSPITObject->getID()) { - if (boolChangeAllowed == false) throw new exception(); - m_ID = p_ReportSPITObject->getID(); - boolChanged = true; - } - if (m_Name != p_ReportSPITObject->getName()) { - if (boolChangeAllowed == false) throw new exception(); - m_Name = p_ReportSPITObject->getName(); - boolChanged = true; - } - if (m_SPITTypeID != p_ReportSPITObject->getSPITTypeID()) { - if (boolChangeAllowed == false) throw new exception(); - m_SPITTypeID = p_ReportSPITObject->getSPITTypeID(); - boolChanged = true; - } - if (m_ServerParams != p_ReportSPITObject->getServerParams()) { - if (boolChangeAllowed == false) throw new exception(); - m_ServerParams = p_ReportSPITObject->getServerParams(); - boolChanged = true; - } - if (m_ServerRemote != p_ReportSPITObject->getServerRemote()) { - if (boolChangeAllowed == false) throw new exception(); - m_ServerRemote = p_ReportSPITObject->getServerRemote(); - boolChanged = true; - } - if (m_Track != p_ReportSPITObject->getTrack()) { - if (boolChangeAllowed == false) throw new exception(); - m_Track = p_ReportSPITObject->getTrack(); - boolChanged = true; - } - if (m_ValueFactor != p_ReportSPITObject->getValueFactor()) { - if (boolChangeAllowed == false) throw new exception(); - m_ValueFactor = p_ReportSPITObject->getValueFactor(); - boolChanged = true; - } - if (m_ValueUse != p_ReportSPITObject->getValueUse()) { - if (boolChangeAllowed == false) throw new exception(); - m_ValueUse = p_ReportSPITObject->getValueUse(); - boolChanged = true; - } - return boolChanged; + if (m_CreatedByClient == true && m_Fixed == true) { + boolChangeAllowed = false; + } else { + boolChangeAllowed = true; + } + + // Confirmation should be changable + if (m_CreatedByClient) { + // Server reports a client created SPITType -> the type is confirmed + m_Confirmed = true; + } else { + // type is NOT client created -> the client has to confirm the SPITtype + m_Confirmed = p_ReportSPITObject->getConfirmed(); + } + + if (m_Delay != p_ReportSPITObject->getDelay()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Delay = p_ReportSPITObject->getDelay(); + boolChanged = true; + } + if (m_Duration != p_ReportSPITObject->getDuration()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Duration = p_ReportSPITObject->getDuration(); + boolChanged = true; + } + if (m_Fixed != p_ReportSPITObject->getFixed()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Fixed = p_ReportSPITObject->getFixed(); + boolChanged = true; + } + if (m_FrameFadeInLength != p_ReportSPITObject->getFrameFadeInLength()) { + if (boolChangeAllowed == false) + throw new exception(); + m_FrameFadeInLength = p_ReportSPITObject->getFrameFadeInLength(); + boolChanged = true; + } + if (m_FrameFadeOutLength != p_ReportSPITObject->getFrameFadeOutLength()) { + if (boolChangeAllowed == false) + throw new exception(); + m_FrameFadeOutLength = p_ReportSPITObject->getFrameFadeOutLength(); + boolChanged = true; + } + if (m_FrameLength != p_ReportSPITObject->getFrameLength()) { + if (boolChangeAllowed == false) + throw new exception(); + m_FrameLength = p_ReportSPITObject->getFrameLength(); + boolChanged = true; + } + if (m_FrameStart != p_ReportSPITObject->getFrameStart()) { + if (boolChangeAllowed == false) + throw new exception(); + m_FrameStart = p_ReportSPITObject->getFrameStart(); + boolChanged = true; + } + if (m_Remark != p_ReportSPITObject->getRemark()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Remark = p_ReportSPITObject->getRemark(); + boolChanged = true; + } + if (m_ID != p_ReportSPITObject->getID()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ID = p_ReportSPITObject->getID(); + boolChanged = true; + } + if (m_Name != p_ReportSPITObject->getName()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Name = p_ReportSPITObject->getName(); + boolChanged = true; + } + if (m_SPITTypeID != p_ReportSPITObject->getSPITTypeID()) { + if (boolChangeAllowed == false) + throw new exception(); + m_SPITTypeID = p_ReportSPITObject->getSPITTypeID(); + boolChanged = true; + } + if (m_ServerParams != p_ReportSPITObject->getServerParams()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ServerParams = p_ReportSPITObject->getServerParams(); + boolChanged = true; + } + if (m_ServerRemote != p_ReportSPITObject->getServerRemote()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ServerRemote = p_ReportSPITObject->getServerRemote(); + boolChanged = true; + } + if (m_Track != p_ReportSPITObject->getTrack()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Track = p_ReportSPITObject->getTrack(); + boolChanged = true; + } + if (m_ValueFactor != p_ReportSPITObject->getValueFactor()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ValueFactor = p_ReportSPITObject->getValueFactor(); + boolChanged = true; + } + if (m_ValueUse != p_ReportSPITObject->getValueUse()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ValueUse = p_ReportSPITObject->getValueUse(); + boolChanged = true; + } + return boolChanged; } -void SPITObject::fillMessageOP(SPIT_Message::ReportSPITObject* p_ReportSPITObject) { - p_ReportSPITObject->setActionAssigned(getActionAssigned()); //Action can be assigned to type or to this object - p_ReportSPITObject->setConfirmed(m_Confirmed); - p_ReportSPITObject->setDelay(m_Delay); - p_ReportSPITObject->setDuration(m_Duration); - p_ReportSPITObject->setFixed(m_Fixed); - p_ReportSPITObject->setFrameFadeInLength(m_FrameFadeInLength); - p_ReportSPITObject->setFrameFadeOutLength(m_FrameFadeOutLength); - p_ReportSPITObject->setFrameLength(m_FrameLength); - p_ReportSPITObject->setFrameStart(m_FrameStart); - p_ReportSPITObject->setID(m_ID); - p_ReportSPITObject->setName(m_Name); - p_ReportSPITObject->setRemark(m_Remark); - p_ReportSPITObject->setSPITTypeID(m_SPITTypeID); - p_ReportSPITObject->setServerParams(m_ServerParams); - p_ReportSPITObject->setServerRemote(m_ServerRemote); - p_ReportSPITObject->setTrack(m_Track); - p_ReportSPITObject->setValueFactor(m_ValueFactor); - p_ReportSPITObject->setValueUse(m_ValueUse); +void SPITObject::fillMessageOP(SPIT_Message::ReportSPITObject *p_ReportSPITObject) { + p_ReportSPITObject->setActionAssigned(getActionAssigned()); // Action can be assigned to type or to this object + p_ReportSPITObject->setConfirmed(m_Confirmed); + p_ReportSPITObject->setDelay(m_Delay); + p_ReportSPITObject->setDuration(m_Duration); + p_ReportSPITObject->setFixed(m_Fixed); + p_ReportSPITObject->setFrameFadeInLength(m_FrameFadeInLength); + p_ReportSPITObject->setFrameFadeOutLength(m_FrameFadeOutLength); + p_ReportSPITObject->setFrameLength(m_FrameLength); + p_ReportSPITObject->setFrameStart(m_FrameStart); + p_ReportSPITObject->setID(m_ID); + p_ReportSPITObject->setName(m_Name); + p_ReportSPITObject->setRemark(m_Remark); + p_ReportSPITObject->setSPITTypeID(m_SPITTypeID); + p_ReportSPITObject->setServerParams(m_ServerParams); + p_ReportSPITObject->setServerRemote(m_ServerRemote); + p_ReportSPITObject->setTrack(m_Track); + p_ReportSPITObject->setValueFactor(m_ValueFactor); + p_ReportSPITObject->setValueUse(m_ValueUse); } -void SPITObject::fillMessageOP(SPIT_Message::RemoveSPITObject* p_RemoveSPITObject) { - p_RemoveSPITObject->setID(m_ID); +void SPITObject::fillMessageOP(SPIT_Message::RemoveSPITObject *p_RemoveSPITObject) { + p_RemoveSPITObject->setID(m_ID); } void SPITObject::setID(string p_ID) { - m_ID = p_ID; + m_ID = p_ID; } void SPITObject::setCreatedByClient(bool p_CreatedByClient) { - m_CreatedByClient = p_CreatedByClient; + m_CreatedByClient = p_CreatedByClient; } /** @@ -433,122 +444,142 @@ void SPITObject::setCreatedByClient(bool p_CreatedByClient) { * @return if m_Confirmed has changed */ bool SPITObject::setConfirmed(bool p_Confirmed) { - if (m_Confirmed == p_Confirmed) return false; - m_Confirmed = p_Confirmed; - return true; + if (m_Confirmed == p_Confirmed) + return false; + m_Confirmed = p_Confirmed; + return true; } bool SPITObject::setName(string p_Name) { - if (m_Name == p_Name) return false; - m_Name = p_Name; - m_Confirmed = false; - return true; + if (m_Name == p_Name) + return false; + m_Name = p_Name; + m_Confirmed = false; + return true; } bool SPITObject::setRemark(string p_Remark) { - if (m_Remark == p_Remark) return false; - m_Remark = p_Remark; - m_Confirmed = false; - return true; + if (m_Remark == p_Remark) + return false; + m_Remark = p_Remark; + m_Confirmed = false; + return true; } bool SPITObject::setServerParams(string p_ServerParams) { - if (m_ServerParams == p_ServerParams) return false; - m_ServerParams = p_ServerParams; - m_Confirmed = false; - return true; + if (m_ServerParams == p_ServerParams) + return false; + m_ServerParams = p_ServerParams; + m_Confirmed = false; + return true; } bool SPITObject::setSPITTypeID(string p_SPITTypeID) { - if (m_SPITTypeID == p_SPITTypeID) return false; - m_SPITTypeID = p_SPITTypeID; - m_Confirmed = false; - return true; + if (m_SPITTypeID == p_SPITTypeID) + return false; + m_SPITTypeID = p_SPITTypeID; + m_Confirmed = false; + return true; } bool SPITObject::setServerRemote(bool p_BelongstoServer) { - if (m_ServerRemote == p_BelongstoServer) return false; - m_ServerRemote = p_BelongstoServer; - m_Confirmed = false; - return true; + if (m_ServerRemote == p_BelongstoServer) + return false; + m_ServerRemote = p_BelongstoServer; + m_Confirmed = false; + return true; } - /** - * 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 SPITObject with the SPITType. - * @return true = an action is assigned for the SPITType. - */ +/** + * 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 SPITObject with the SPITType. + * @return true = an action is assigned for the SPITType. + */ bool SPITObject::setActionAssignedType(bool p_ActionAssigned) { - if (m_ActionAssignedType == p_ActionAssigned) return false; - bool boolOldActionAssigend; - boolOldActionAssigend = getActionAssigned(); - m_ActionAssignedType = p_ActionAssigned; - if (getActionAssigned() == boolOldActionAssigend) return false; - m_Confirmed = false; - return true; + if (m_ActionAssignedType == p_ActionAssigned) + return false; + bool boolOldActionAssigend; + boolOldActionAssigend = getActionAssigned(); + m_ActionAssignedType = p_ActionAssigned; + if (getActionAssigned() == boolOldActionAssigend) + return false; + m_Confirmed = false; + return true; } bool SPITObject::setActionAssigned(bool p_ActionAssigned) { - if (m_ActionAssigned == p_ActionAssigned) return false; - bool boolOldActionAssigend; - boolOldActionAssigend = getActionAssigned(); - m_ActionAssigned = p_ActionAssigned; - if (getActionAssigned() == boolOldActionAssigend) return false; - m_Confirmed = false; - return true; + if (m_ActionAssigned == p_ActionAssigned) + return false; + bool boolOldActionAssigend; + boolOldActionAssigend = getActionAssigned(); + m_ActionAssigned = p_ActionAssigned; + if (getActionAssigned() == boolOldActionAssigend) + return false; + m_Confirmed = false; + return true; } bool SPITObject::setFixed(bool p_Fixed) { - if (m_Fixed == p_Fixed) return false; - m_Fixed = p_Fixed; - m_Confirmed = false; - return true; + if (m_Fixed == p_Fixed) + return false; + m_Fixed = p_Fixed; + m_Confirmed = false; + return true; } bool SPITObject::setFrameStart(long long p_FrameStart) { - if (m_FrameStart == p_FrameStart) return false; - m_FrameStart = p_FrameStart; - m_Confirmed = false; - return true; + if (m_FrameStart == p_FrameStart) + return false; + m_FrameStart = p_FrameStart; + m_Confirmed = false; + return true; } bool SPITObject::setFrameLength(long long p_FrameLength) { - if (m_FrameLength == p_FrameLength) return false; - m_FrameLength = p_FrameLength; - m_Confirmed = false; - return true; + if (m_FrameLength == p_FrameLength) + return false; + m_FrameLength = p_FrameLength; + m_Confirmed = false; + return true; } -bool SPITObject::setFrameFadeInLength(long long p_FrameFadeInLength) { - if (m_FrameFadeInLength == p_FrameFadeInLength) return false; - m_FrameFadeInLength = p_FrameFadeInLength; - m_Confirmed = false; - return true; +bool SPITObject::setFrameFadeInLength(long long p_FrameFadeInLength) { + if (m_FrameFadeInLength == p_FrameFadeInLength) + return false; + m_FrameFadeInLength = p_FrameFadeInLength; + m_Confirmed = false; + return true; } bool SPITObject::setFrameFadeOutLength(long long p_FrameFadeOutLength) { - if (m_FrameFadeOutLength == p_FrameFadeOutLength) return false; - m_FrameFadeOutLength = p_FrameFadeOutLength; - m_Confirmed = false; - return true; + if (m_FrameFadeOutLength == p_FrameFadeOutLength) + return false; + m_FrameFadeOutLength = p_FrameFadeOutLength; + m_Confirmed = false; + return true; } bool SPITObject::setValueUse(char p_ValueUse) { - if (m_ValueUse == p_ValueUse) return false; - m_ValueUse = p_ValueUse; - m_Confirmed = false; - return true; + if (m_ValueUse == p_ValueUse) + return false; + m_ValueUse = p_ValueUse; + m_Confirmed = false; + return true; } bool SPITObject::setValueFactor(int p_ValueFactor) { - if (m_ValueFactor == p_ValueFactor) return false; - m_ValueFactor = p_ValueFactor; - m_Confirmed = false; - return true; + if (m_ValueFactor == p_ValueFactor) + return false; + m_ValueFactor = p_ValueFactor; + m_Confirmed = false; + return true; } bool SPITObject::setTrack(int p_Track) { - if (m_Track == p_Track) return false; - m_Track = p_Track; - m_Confirmed = false; - return true; + if (m_Track == p_Track) + return false; + m_Track = p_Track; + m_Confirmed = false; + return true; } bool SPITObject::setDelay(long long p_Delay) { - if (m_Delay == p_Delay) return false; - m_Delay = p_Delay; - m_Confirmed = false; - return true; + if (m_Delay == p_Delay) + return false; + m_Delay = p_Delay; + m_Confirmed = false; + return true; } bool SPITObject::setDuration(long long p_Duration) { - if (m_Duration == p_Duration) return false; - m_Duration = p_Duration; - m_Confirmed = false; - return true; + if (m_Duration == p_Duration) + return false; + m_Duration = p_Duration; + m_Confirmed = false; + return true; } diff --git a/components/spit/src/SPITPlayer.cpp b/components/spit/src/SPITPlayer.cpp index d8d3119..4f7a513 100644 --- a/components/spit/src/SPITPlayer.cpp +++ b/components/spit/src/SPITPlayer.cpp @@ -4,150 +4,134 @@ * and open the template in the editor. */ -/* +/* * SPITPlayer describes a virtual SPIT Player. * File: SPITPLayer.cpp * Author: Hagi - * + * * Created on 30. April 2019, 11:44 */ #include "SPITPlayer.h" #include -unordered_map SPITPlayer::s_SPITPlayers; +unordered_map SPITPlayer::s_SPITPlayers; -SPITPlayer* SPITPlayer::getSPITPlayer(string p_PlayerID) { - { - auto i = s_SPITPlayers.find(p_PlayerID); - if (i == s_SPITPlayers.end()) { - s_SPITPlayers[p_PlayerID] = new SPITPlayer(p_PlayerID); - } - i = s_SPITPlayers.find(p_PlayerID); - if (i == s_SPITPlayers.end()) return NULL; - return i->second; - } +SPITPlayer *SPITPlayer::getSPITPlayer(string p_PlayerID) { + { + auto i = s_SPITPlayers.find(p_PlayerID); + if (i == s_SPITPlayers.end()) { + s_SPITPlayers[p_PlayerID] = new SPITPlayer(p_PlayerID); + } + i = s_SPITPlayers.find(p_PlayerID); + if (i == s_SPITPlayers.end()) + return NULL; + return i->second; + } } void SPITPlayer::clearPlayers() { - ; - vector o_SPITPlayers; - for (auto i = s_SPITPlayers.begin(); i != s_SPITPlayers.end(); i++) { - SPITPlayer* ptrSPITPlayer = i->second; - o_SPITPlayers.push_back(ptrSPITPlayer); - } - for (auto i = o_SPITPlayers.begin(); i != o_SPITPlayers.end(); i++) { - SPITPlayer* ptrSPITPlayer = *i; - delete ptrSPITPlayer; - } - o_SPITPlayers.clear(); + ; + vector o_SPITPlayers; + for (auto i = s_SPITPlayers.begin(); i != s_SPITPlayers.end(); i++) { + SPITPlayer *ptrSPITPlayer = i->second; + o_SPITPlayers.push_back(ptrSPITPlayer); + } + for (auto i = o_SPITPlayers.begin(); i != o_SPITPlayers.end(); i++) { + SPITPlayer *ptrSPITPlayer = *i; + delete ptrSPITPlayer; + } + o_SPITPlayers.clear(); } SPITPlayer::SPITPlayer(string p_PlayerID) { - m_ID = p_PlayerID; - s_SPITPlayers[p_PlayerID] = this; + m_ID = p_PlayerID; + s_SPITPlayers[p_PlayerID] = this; } SPITPlayer::~SPITPlayer() { - PlaySPITType* ptrPlaySPITType; - for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end(); i++) { - ptrPlaySPITType = i->second; - i = m_PlaySPITTypes.erase(i); - delete ptrPlaySPITType; - if (i == m_PlaySPITTypes.end()) { - break; - } - } - + PlaySPITType *ptrPlaySPITType; + for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end(); i++) { + ptrPlaySPITType = i->second; + i = m_PlaySPITTypes.erase(i); + delete ptrPlaySPITType; + if (i == m_PlaySPITTypes.end()) { + break; + } + } } -void SPITPlayer::setIsRunning(bool p_IsRunning) { - m_IsRunning = p_IsRunning; -} -void SPITPlayer::setName(string p_Name) { - m_Name = p_Name; -} -void SPITPlayer::setType(char p_Type) { - m_Type = p_Type; -} -void SPITPlayer::setTime(long long p_Frames) { - m_TimeFrames = p_Frames; -} - -unordered_map* SPITPlayer::getPlaySPITTypes() { - return &m_PlaySPITTypes; +unordered_map *SPITPlayer::getPlaySPITTypes() { + return &m_PlaySPITTypes; } /** - * + * * @param p_SPITObjectID * @return true = new PlayObject added
- * false = PlayObject exists + * false = PlayObject exists */ -SPITPlayer::PlaySPITType* SPITPlayer::addSPITType_Playing (string p_SPITTypeID) { - PlaySPITType* ptrPlaySPITType; - - auto i = m_PlaySPITTypes.find(p_SPITTypeID); - if (i == m_PlaySPITTypes.end()) { - ptrPlaySPITType = new PlaySPITType(this, p_SPITTypeID); - ptrPlaySPITType->setIsPlayed(true); - ptrPlaySPITType->setIsNew(true); - m_PlaySPITTypes[p_SPITTypeID] = ptrPlaySPITType; - } - else { - ptrPlaySPITType = i->second; - ptrPlaySPITType->setIsPlayed(true); - } - return ptrPlaySPITType; - +SPITPlayer::PlaySPITType *SPITPlayer::addSPITType_Playing(string p_SPITTypeID) { + PlaySPITType *ptrPlaySPITType; + + auto i = m_PlaySPITTypes.find(p_SPITTypeID); + if (i == m_PlaySPITTypes.end()) { + ptrPlaySPITType = new PlaySPITType(this, p_SPITTypeID); + ptrPlaySPITType->setIsPlayed(true); + ptrPlaySPITType->setIsNew(true); + m_PlaySPITTypes[p_SPITTypeID] = ptrPlaySPITType; + } else { + ptrPlaySPITType = i->second; + ptrPlaySPITType->setIsPlayed(true); + } + return ptrPlaySPITType; } void SPITPlayer::startPlaySequence() { - PlaySPITType* ptrPlaySPITType; - for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end(); i++) { - ptrPlaySPITType = i->second; - ptrPlaySPITType->startPlaySequence(); - } + PlaySPITType *ptrPlaySPITType; + for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end(); i++) { + ptrPlaySPITType = i->second; + ptrPlaySPITType->startPlaySequence(); + } } void SPITPlayer::endPlaySequence() { - PlaySPITType* ptrPlaySPITType; - - for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end(); i++) { - ptrPlaySPITType = i->second; - if (ptrPlaySPITType->getIsPlayed() == false) { - i = m_PlaySPITTypes.erase(i); - delete ptrPlaySPITType; - if (i == m_PlaySPITTypes.end()) { - break; - } - } - } - + PlaySPITType *ptrPlaySPITType; + + for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end(); i++) { + ptrPlaySPITType = i->second; + if (ptrPlaySPITType->getIsPlayed() == false) { + i = m_PlaySPITTypes.erase(i); + delete ptrPlaySPITType; + if (i == m_PlaySPITTypes.end()) { + break; + } + } + } } SPITPlayer::PlaySPITType::PlaySPITType() { } -SPITPlayer::PlaySPITType::PlaySPITType(SPITPlayer* p_SPITPlayer, string p_SPITTypeID) { - m_SPITTypeID = p_SPITTypeID; - m_PlayerID = p_SPITPlayer->getID(); - m_PlayerName = p_SPITPlayer->getName(); - startPlaySequence(); - m_IsNew = true; +SPITPlayer::PlaySPITType::PlaySPITType(SPITPlayer *p_SPITPlayer, string p_SPITTypeID) { + m_SPITTypeID = p_SPITTypeID; + m_PlayerID = p_SPITPlayer->getID(); + m_PlayerName = p_SPITPlayer->getName(); + startPlaySequence(); + m_IsNew = true; } -SPITPlayer::PlaySPITType::PlaySPITType(const PlaySPITType& orig) { - m_SPITTypeID = orig.getSPITTypeID(); - m_IsPlayed = orig.getIsPlayed(); - m_IsNew = orig.getIsNew(); +SPITPlayer::PlaySPITType::PlaySPITType(const PlaySPITType &orig) { + m_SPITTypeID = orig.getSPITTypeID(); + m_IsPlayed = orig.getIsPlayed(); + m_IsNew = orig.getIsNew(); - m_PlayerID = orig.getPlayerID(); - m_PlayerName = orig.getPlayerName(); - m_PlayerRuns = orig.getPlayerIsRunning(); + m_PlayerID = orig.getPlayerID(); + m_PlayerName = orig.getPlayerName(); + m_PlayerRuns = orig.getPlayerIsRunning(); - m_Value = orig.getValue(); + m_Value = orig.getValue(); } void SPITPlayer::PlaySPITType::startPlaySequence() { - m_IsPlayed = false; - m_IsNew = false; - - m_Value = 0; + m_IsPlayed = false; + m_IsNew = false; + + m_Value = 0; } \ No newline at end of file diff --git a/components/spit/src/SPITSocket.cpp b/components/spit/src/SPITSocket.cpp index 0d05480..b93b695 100644 --- a/components/spit/src/SPITSocket.cpp +++ b/components/spit/src/SPITSocket.cpp @@ -15,11 +15,11 @@ #include "SPITSocket.h" #include "Task.hpp" +#include "esp/uuid.h" #include "esp_log.h" #include "esp_netif.h" -#include "esp/uuid.h" -#include #include +#include using namespace std; /** @@ -43,14 +43,14 @@ bool SPITSocket::createSocket_UDP() { } else { intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_REUSEADDR, (void *)&intOptionValue4, sizeof(intOptionValue4)); } - if (intResult < 0) { - boolSuccess = false; - } + if (intResult < 0) { + boolSuccess = false; + } if (boolSuccess == true) { struct timeval tv; - tv.tv_sec = 1; // seconds - tv.tv_usec = 0; // microseconds (0.0 sec) + tv.tv_sec = 1; // seconds + tv.tv_usec = 0; // microseconds (0.0 sec) // This sets the receive timeout setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); @@ -61,8 +61,8 @@ bool SPITSocket::createSocket_UDP() { // fcntl(m_UDPSocketIP4, F_SETFL, intFlags | O_NONBLOCK); // int intBufferSize = 2046 * 512; - // intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_RCVBUF, (void*)&intBufferSize, sizeof(intBufferSize)); - // intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_SNDBUF, (void*)&intBufferSize, sizeof(intBufferSize)); + // intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_RCVBUF, (void*)&intBufferSize, sizeof(intBufferSize)); + // intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_SNDBUF, (void*)&intBufferSize, sizeof(intBufferSize)); } return boolSuccess; } @@ -186,8 +186,8 @@ int SPITSocket::sendMessageTo(int p_InetFamily, string p_ServerIP, string p_Serv intResult = sendto(m_UDPSocketIP4, p_MessageBytes, p_MessageLength, 0, (const sockaddr *)&o_IP4SocketAddress, (socklen_t)intSocklen); if (intResult < 0) { printf("UnixSocket::sendMessageTo IP4 sendto %s FAILED %s\n", p_ServerIP.data(), strerror(errno)); - printf("UnixSocket::sendMessageTo ret=%d %s / %s / %d\n", intResult, - p_ServerPort.data(), p_MessageBytes, p_MessageLength); + printf("UnixSocket::sendMessageTo ret=%d %s / %s / %d\n", intResult, + p_ServerPort.data(), p_MessageBytes, p_MessageLength); } freeaddrinfo(ptrAddressInfo); } @@ -196,23 +196,23 @@ int SPITSocket::sendMessageTo(int p_InetFamily, string p_ServerIP, string p_Serv intResult = -1; } - if (intResult < 0) { - return -1; - } + if (intResult < 0) { + return -1; + } return 0; } - /** - * Call this for receiving a message - * This will block until a message is received or the underlying socket is closed - * @param p_InetFamily either AF_INET or AF_INET6
- * The SPITSocket creates two udp sockets, one for IP4 and one for IP6 - * This parameter decides from which socket should a message recieved - * @param p_Buffer the buffer containing the received message later. - * @param p_BufferLength the size of the buffer - * @param p_ServerIP a pointer to a string, when a messages is received the string will contain the ip address of the sender/server - * if p_ServerIP is NULL - no detection of the server will be done. - * @return - */ +/** + * Call this for receiving a message + * This will block until a message is received or the underlying socket is closed + * @param p_InetFamily either AF_INET or AF_INET6
+ * The SPITSocket creates two udp sockets, one for IP4 and one for IP6 + * This parameter decides from which socket should a message recieved + * @param p_Buffer the buffer containing the received message later. + * @param p_BufferLength the size of the buffer + * @param p_ServerIP a pointer to a string, when a messages is received the string will contain the ip address of the sender/server + * if p_ServerIP is NULL - no detection of the server will be done. + * @return + */ int SPITSocket::receiveMessage(int p_InetFamily, char *p_Buffer, int p_BufferLength, string *p_ServerIP) { int intResult = -1; // ADDRINFO *AI; @@ -226,7 +226,7 @@ int SPITSocket::receiveMessage(int p_InetFamily, char *p_Buffer, int p_BufferLen } intSocklen = sizeof(o_IP4SocketAddress); memset(&o_IP4SocketAddress, 0, intSocklen); - intResult = recvfrom(m_UDPSocketIP4, (void *)p_Buffer, p_BufferLength, 0 , (sockaddr *)&o_IP4SocketAddress, (socklen_t *)&intSocklen); + intResult = recvfrom(m_UDPSocketIP4, (void *)p_Buffer, p_BufferLength, 0, (sockaddr *)&o_IP4SocketAddress, (socklen_t *)&intSocklen); if (intResult >= 0) { if (p_ServerIP != NULL) { char bufferIP4[INET_ADDRSTRLEN]; @@ -239,7 +239,6 @@ int SPITSocket::receiveMessage(int p_InetFamily, char *p_Buffer, int p_BufferLen return intResult; } - SPITSocket::IPAddress SPITSocket::getAdaptersInfo() { // iterate over active interfaces, and print out IPs esp_netif_t *netif = NULL; @@ -261,12 +260,12 @@ SPITSocket::IPAddress SPITSocket::getAdaptersInfo() { } string createGUID() { - // uuid_t id; - // uuid_generate(id); - // char *guid_string = new char[100]; - // uuid_unparse(id, guid_string); - // string stringGUID = guid_string; - // return stringGUID; + // uuid_t id; + // uuid_generate(id); + // char *guid_string = new char[100]; + // uuid_unparse(id, guid_string); + // string stringGUID = guid_string; + // return stringGUID; uuid_t uu; char uu_str[UUID_STR_LEN]; @@ -274,15 +273,16 @@ string createGUID() { uuid_generate(uu); uuid_unparse(uu, uu_str); string stringGUID = uu_str; - return stringGUID; + return stringGUID; } /** The name of the client's host computer*/ string getClientHostName() { - string stringHostName = ""; - const char * hostname; - esp_netif_get_hostname(esp_netif_get_default_netif(), &hostname); - if (hostname != nullptr) { - stringHostName = hostname; - } - return stringHostName;; + string stringHostName = ""; + const char *hostname; + esp_netif_get_hostname(esp_netif_get_default_netif(), &hostname); + if (hostname != nullptr) { + stringHostName = hostname; + } + return stringHostName; + ; } diff --git a/components/spit/src/SPITType.cpp b/components/spit/src/SPITType.cpp index 5e71ea2..6883456 100644 --- a/components/spit/src/SPITType.cpp +++ b/components/spit/src/SPITType.cpp @@ -4,447 +4,455 @@ * and open the template in the editor. */ -/* +/* * SPITType describes a SPIT Type * File: SPITType.cpp * Author: Hagi - * + * * Created on 8. April 2019, 08:40 */ - #include "SPITType.h" #include "esp_log.h" -static const char * TAG = "SPIT"; +static const char *TAG = "SPIT"; - unordered_map SPITType::s_SPITTypes; - unordered_map SPITType::s_SPITTypesRemote; - - SPITType* SPITType::getSPITType(string p_ID) { - { - auto i = s_SPITTypes.find(p_ID); - if (i == s_SPITTypes.end()) { - return NULL; - } - return i->second; - } - } - /** - * Returns the reference of the SPITType with ID == p_ID.
- * Throws an exception if no SPITType is not found.
- * @param p_ID the ID - * @return reference of the SPITType with ID == p_ID - */ - const SPITType& SPITType::getSPITTypeRef(string p_ID) { - { - auto i = s_SPITTypes.find(p_ID); - if (i == s_SPITTypes.end()) { - throw "SPITType no SPITType with given ID"; - } - return *(i->second); - } - } +unordered_map SPITType::s_SPITTypes; +unordered_map SPITType::s_SPITTypesRemote; - SPITType* SPITType::getSPITTypeRemote(string p_ID) { - { - auto i = s_SPITTypesRemote.find(p_ID); - if (i == s_SPITTypesRemote.end()) { - return NULL; - } - return i->second; - } - } - /** - * Returns the reference of the remote SPITType with ID == p_ID.
- * Throws an exception if no SPITType is not found.
- * @param p_ID the ID - * @return reference of the SPITType with ID == p_ID - */ - const SPITType& SPITType::getSPITTypeRemoteRef(string p_ID) { - { - auto i = s_SPITTypesRemote.find(p_ID); - if (i == s_SPITTypesRemote.end()) { - throw "Remote SPITType no SPITType with given ID"; - } - return *(i->second); - } - } +SPITType *SPITType::getSPITType(string p_ID) { + { + auto i = s_SPITTypes.find(p_ID); + if (i == s_SPITTypes.end()) { + return NULL; + } + return i->second; + } +} +/** + * Returns the reference of the SPITType with ID == p_ID.
+ * Throws an exception if no SPITType is not found.
+ * @param p_ID the ID + * @return reference of the SPITType with ID == p_ID + */ +const SPITType &SPITType::getSPITTypeRef(string p_ID) { + { + auto i = s_SPITTypes.find(p_ID); + if (i == s_SPITTypes.end()) { + throw "SPITType no SPITType with given ID"; + } + return *(i->second); + } +} - bool SPITType::addSPITType(SPITType* p_ptrSpitType) { - if (p_ptrSpitType == NULL) return false; - { - s_SPITTypes[p_ptrSpitType->getID()] = p_ptrSpitType; - return true; - } - } - bool SPITType::addSPITTypeRemote(SPITType* p_ptrSpitType) { - if (p_ptrSpitType == NULL) return false; - { - s_SPITTypesRemote[p_ptrSpitType->getID()] = p_ptrSpitType; - return true; - } - } - bool SPITType::removeSPITType(SPITType* p_ptrSpitType) { - if (p_ptrSpitType == NULL) return false; - { - auto i = s_SPITTypes.find(p_ptrSpitType->getID()); - if (i == s_SPITTypes.end()) { - return false; - } - i = s_SPITTypes.erase(i); - return true; - } - } - bool SPITType::removeSPITTypeRemote(SPITType* p_ptrSpitType) { - if (p_ptrSpitType == NULL) return false; - { - auto i = s_SPITTypesRemote.find(p_ptrSpitType->getID()); - if (i == s_SPITTypesRemote.end()) { - return false; - } - i = s_SPITTypesRemote.erase(i); - return true; - } - } +SPITType *SPITType::getSPITTypeRemote(string p_ID) { + { + auto i = s_SPITTypesRemote.find(p_ID); + if (i == s_SPITTypesRemote.end()) { + return NULL; + } + return i->second; + } +} +/** + * Returns the reference of the remote SPITType with ID == p_ID.
+ * Throws an exception if no SPITType is not found.
+ * @param p_ID the ID + * @return reference of the SPITType with ID == p_ID + */ +const SPITType &SPITType::getSPITTypeRemoteRef(string p_ID) { + { + auto i = s_SPITTypesRemote.find(p_ID); + if (i == s_SPITTypesRemote.end()) { + throw "Remote SPITType no SPITType with given ID"; + } + return *(i->second); + } +} - int SPITType::getSPITTypeCount() { - return s_SPITTypes.size(); - } - int SPITType::getSPITTypeRemoteCount() { - return s_SPITTypesRemote.size(); - } - SPITType* SPITType::getSPITType(int p_Index) { - SPITType* ptrSPITType = NULL; - { - if (p_Index < s_SPITTypes.size()) { - unordered_map::iterator i = next(s_SPITTypes.begin(), p_Index); - ptrSPITType = i->second; - } - return ptrSPITType; - } - } - /** - * Returns a reference to the SPITType at position p_Index.
- * Throws an exception if p_Index is out of range.
- * @param p_Index position - * @return the reference of the SPITType at position. - */ - const SPITType& SPITType::getSPITTypeRef(int p_Index) { - SPITType* ptrSPITType = NULL; - { - if (p_Index >= 0 && p_Index < s_SPITTypes.size()) { - unordered_map::iterator i = next(s_SPITTypes.begin(), p_Index); - ptrSPITType = i->second; - return *ptrSPITType; - } - else { - throw "SPITType index out of range"; - } - } - } - SPITType* SPITType::getSPITTypeRemote(int p_Index) { - SPITType* ptrSPITType = NULL; - { - if (p_Index < s_SPITTypesRemote.size()) { - unordered_map::iterator i = next(s_SPITTypesRemote.begin(), p_Index); - ptrSPITType = i->second; - } - return ptrSPITType; - } - } - /** - * Returns a reference to the remote SPITType at position p_Index.
- * Throws an exception if p_Index is out of range.
- * @param p_Index position - * @return the reference of the SPITType at position. - */ - const SPITType& SPITType::getSPITTypeRemoteRef(int p_Index) { - SPITType* ptrSPITType = NULL; - { - if (p_Index >= 0 && p_Index < s_SPITTypesRemote.size()) { - unordered_map::iterator i = next(s_SPITTypesRemote.begin(), p_Index); - ptrSPITType = i->second; - return *ptrSPITType; - } - else { - throw "Remote SPITType index out of range"; - } - } - } - - void SPITType::clearSPITTypes() { - SPITType* ptrSPITType; - { - for (auto i = s_SPITTypes.begin(); i != s_SPITTypes.end(); i++) { - ptrSPITType = i->second; - i = s_SPITTypes.erase(i); - delete ptrSPITType; - if (i == s_SPITTypes.end()) { - break; - } - } - } - } - void SPITType::clearSPITTypesRemote() { - SPITType* ptrSPITType; - { - for (auto i = s_SPITTypesRemote.begin(); i != s_SPITTypesRemote.end(); i++) { - ptrSPITType = i->second; - i = s_SPITTypesRemote.erase(i); - delete ptrSPITType; - if (i == s_SPITTypesRemote.end()) { - break; - } - } - } - } - - void SPITType::eventProjectClosed() { - SPITType* ptrSPITType; - for (auto i = s_SPITTypes.begin(); i != s_SPITTypes.end(); i++) { - ptrSPITType = i->second; - if (ptrSPITType->getCreatedByClient() == true) { - continue; - } - i = s_SPITTypes.erase(i); - delete ptrSPITType; - if (i == s_SPITTypes.end()) { - break; - } - } - //Remote - for (auto i = s_SPITTypesRemote.begin(); i != s_SPITTypesRemote.end(); i++) { - ptrSPITType = i->second; - i = s_SPITTypesRemote.erase(i); - delete ptrSPITType; - if (i == s_SPITTypesRemote.end()) { - break; - } - } - } +bool SPITType::addSPITType(SPITType *p_ptrSpitType) { + if (p_ptrSpitType == NULL) + return false; + { + s_SPITTypes[p_ptrSpitType->getID()] = p_ptrSpitType; + return true; + } +} +bool SPITType::addSPITTypeRemote(SPITType *p_ptrSpitType) { + if (p_ptrSpitType == NULL) + return false; + { + s_SPITTypesRemote[p_ptrSpitType->getID()] = p_ptrSpitType; + return true; + } +} +bool SPITType::removeSPITType(SPITType *p_ptrSpitType) { + if (p_ptrSpitType == NULL) + return false; + { + auto i = s_SPITTypes.find(p_ptrSpitType->getID()); + if (i == s_SPITTypes.end()) { + return false; + } + i = s_SPITTypes.erase(i); + return true; + } +} +bool SPITType::removeSPITTypeRemote(SPITType *p_ptrSpitType) { + if (p_ptrSpitType == NULL) + return false; + { + auto i = s_SPITTypesRemote.find(p_ptrSpitType->getID()); + if (i == s_SPITTypesRemote.end()) { + return false; + } + i = s_SPITTypesRemote.erase(i); + return true; + } +} + +int SPITType::getSPITTypeCount() { + return s_SPITTypes.size(); +} +int SPITType::getSPITTypeRemoteCount() { + return s_SPITTypesRemote.size(); +} +SPITType *SPITType::getSPITType(int p_Index) { + SPITType *ptrSPITType = NULL; + { + if (p_Index < s_SPITTypes.size()) { + unordered_map::iterator i = next(s_SPITTypes.begin(), p_Index); + ptrSPITType = i->second; + } + return ptrSPITType; + } +} +/** + * Returns a reference to the SPITType at position p_Index.
+ * Throws an exception if p_Index is out of range.
+ * @param p_Index position + * @return the reference of the SPITType at position. + */ +const SPITType &SPITType::getSPITTypeRef(int p_Index) { + SPITType *ptrSPITType = NULL; + { + if (p_Index >= 0 && p_Index < s_SPITTypes.size()) { + unordered_map::iterator i = next(s_SPITTypes.begin(), p_Index); + ptrSPITType = i->second; + return *ptrSPITType; + } else { + throw "SPITType index out of range"; + } + } +} +SPITType *SPITType::getSPITTypeRemote(int p_Index) { + SPITType *ptrSPITType = NULL; + { + if (p_Index < s_SPITTypesRemote.size()) { + unordered_map::iterator i = next(s_SPITTypesRemote.begin(), p_Index); + ptrSPITType = i->second; + } + return ptrSPITType; + } +} +/** + * Returns a reference to the remote SPITType at position p_Index.
+ * Throws an exception if p_Index is out of range.
+ * @param p_Index position + * @return the reference of the SPITType at position. + */ +const SPITType &SPITType::getSPITTypeRemoteRef(int p_Index) { + SPITType *ptrSPITType = NULL; + { + if (p_Index >= 0 && p_Index < s_SPITTypesRemote.size()) { + unordered_map::iterator i = next(s_SPITTypesRemote.begin(), p_Index); + ptrSPITType = i->second; + return *ptrSPITType; + } else { + throw "Remote SPITType index out of range"; + } + } +} + +void SPITType::clearSPITTypes() { + SPITType *ptrSPITType; + { + for (auto i = s_SPITTypes.begin(); i != s_SPITTypes.end(); i++) { + ptrSPITType = i->second; + i = s_SPITTypes.erase(i); + delete ptrSPITType; + if (i == s_SPITTypes.end()) { + break; + } + } + } +} +void SPITType::clearSPITTypesRemote() { + SPITType *ptrSPITType; + { + for (auto i = s_SPITTypesRemote.begin(); i != s_SPITTypesRemote.end(); i++) { + ptrSPITType = i->second; + i = s_SPITTypesRemote.erase(i); + delete ptrSPITType; + if (i == s_SPITTypesRemote.end()) { + break; + } + } + } +} + +void SPITType::eventProjectClosed() { + SPITType *ptrSPITType; + for (auto i = s_SPITTypes.begin(); i != s_SPITTypes.end(); i++) { + ptrSPITType = i->second; + if (ptrSPITType->getCreatedByClient() == true) { + continue; + } + i = s_SPITTypes.erase(i); + delete ptrSPITType; + if (i == s_SPITTypes.end()) { + break; + } + } + // Remote + for (auto i = s_SPITTypesRemote.begin(); i != s_SPITTypesRemote.end(); i++) { + ptrSPITType = i->second; + i = s_SPITTypesRemote.erase(i); + delete ptrSPITType; + if (i == s_SPITTypesRemote.end()) { + break; + } + } +} + +/** + * Sets confirmed = false for all SPITTypes.
+ * This should be called when the client has loaded a project.
+ */ +void SPITType::setConfirmedFalse() { + SPITType *ptrSPITType; + { + for (auto i = s_SPITTypes.begin(); i != s_SPITTypes.end(); i++) { + ptrSPITType = i->second; + ptrSPITType->setConfirmed(false); + } + } +} - /** - * Sets confirmed = false for all SPITTypes.
- * This should be called when the client has loaded a project.
- */ - void SPITType::setConfirmedFalse() { - SPITType* ptrSPITType; - { - for (auto i = s_SPITTypes.begin(); i != s_SPITTypes.end(); i++) { - ptrSPITType = i->second; - ptrSPITType->setConfirmed(false); - } - } - } - - - - - - SPITType::SPITType() { - initMembers(); + initMembers(); } /* SPITType::SPITType(const SPITType& orig) { - m_Confirmed = orig.getConfirmed(); - m_DefaultDelay = orig.getDefaultDelay(); - m_DefaultDuration = orig.getDefaultDuration(); - m_Fixed = orig.getFixed(); - m_GroupName = orig.getGroupName(); - m_ID = orig.getID(); - m_Name = orig.getName(); - m_ServerProjectIndepended = orig.getProjectIndepended(); - m_ServerRemote = orig.getServerRemote(); + m_Confirmed = orig.getConfirmed(); + m_DefaultDelay = orig.getDefaultDelay(); + m_DefaultDuration = orig.getDefaultDuration(); + m_Fixed = orig.getFixed(); + m_GroupName = orig.getGroupName(); + m_ID = orig.getID(); + m_Name = orig.getName(); + m_ServerProjectIndepended = orig.getProjectIndepended(); + m_ServerRemote = orig.getServerRemote(); } */ -SPITType::SPITType(string p_ID, string p_GroupName, string p_Name, bool p_Fixed, bool p_ProjectIndepended,long long p_DefaultDelay, long long p_DefaultDuration) { - initMembers(); - m_ActionAssigned = false; - m_Confirmed = false; - m_ID = p_ID; - m_GroupName = p_GroupName; - m_Name = p_Name; - m_Fixed = p_Fixed; - m_ServerProjectIndepended = p_ProjectIndepended; - m_DefaultDelay = p_DefaultDelay; - m_DefaultDuration = p_DefaultDuration; +SPITType::SPITType(string p_ID, string p_GroupName, string p_Name, bool p_Fixed, bool p_ProjectIndepended, long long p_DefaultDelay, long long p_DefaultDuration) { + initMembers(); + m_ActionAssigned = false; + m_Confirmed = false; + m_ID = p_ID; + m_GroupName = p_GroupName; + m_Name = p_Name; + m_Fixed = p_Fixed; + m_ServerProjectIndepended = p_ProjectIndepended; + m_DefaultDelay = p_DefaultDelay; + m_DefaultDuration = p_DefaultDuration; } SPITType::~SPITType() { } void SPITType::initMembers() { - m_Confirmed = false; - m_DefaultDelay = 0; - m_DefaultDuration = 0; - m_Fixed = false; - m_GroupName = ""; - m_ID = createGUID(); - m_Name = ""; - m_ServerProjectIndepended = false; - m_ServerRemote = false; + m_Confirmed = false; + m_DefaultDelay = 0; + m_DefaultDuration = 0; + m_Fixed = false; + m_GroupName = ""; + m_ID = createGUID(); + m_Name = ""; + m_ServerProjectIndepended = false; + m_ServerRemote = false; } - - void SPITType::setCreatedByClient(bool p_CreatedByClient) { - m_CreatedByClient = p_CreatedByClient; + m_CreatedByClient = p_CreatedByClient; } +void SPITType::setID(string p_ID) { + m_ID = p_ID; +} - void SPITType::setID(string p_ID) { - m_ID = p_ID; - } - - /** - * This is used by the server and client to tell if the other side has registered the changes. - * @param p_Confirmed - * @return if m_Confirmed has changed - */ - bool SPITType::setConfirmed(bool p_Confirmed) { - if (m_Confirmed == p_Confirmed) return false; - m_Confirmed = p_Confirmed; - return true; - } - - bool SPITType::setGroupName(string p_GroupName) { - if (m_GroupName == p_GroupName) return false; - m_GroupName = p_GroupName; - m_Confirmed = false; - return true; - } - bool SPITType::setName(string p_Name) { - if (m_Name == p_Name) return false; - m_Name = p_Name; - m_Confirmed = false; - return true; - } - bool SPITType::setServerRemote(bool p_BelongstoServer) { - if (m_ServerRemote == p_BelongstoServer) return false; - m_ServerRemote = p_BelongstoServer; - m_Confirmed = false; - return true; - } - bool SPITType::setProjectIndepended(bool p_ProjectIndepended) { - if (m_ServerProjectIndepended == p_ProjectIndepended) return false; - m_ServerProjectIndepended = p_ProjectIndepended; - m_Confirmed = false; - return true; - } - bool SPITType::setFixed(bool p_Fixed) { - if (m_Fixed == p_Fixed) return false; - m_Fixed = p_Fixed; - m_Confirmed = false; - return true; - } - bool SPITType::setDefaultDelay(long long p_Delay) { - if (m_DefaultDelay == p_Delay) return false; - m_DefaultDelay = p_Delay; - m_Confirmed = false; - return true; - } - bool SPITType::setDefaultDuration(long long p_Duration) { - if (m_DefaultDuration == p_Duration) return false; - m_DefaultDuration = p_Duration; - m_Confirmed = false; - return true; - } - - /** - * 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.
- * @return true = the m_ActionAssigned has changed. - */ - bool SPITType::setActionAssigned(bool p_ActionAssigned) { - if (m_ActionAssigned == p_ActionAssigned) return false; - m_ActionAssigned = p_ActionAssigned; - m_Confirmed = false; - return true; - } +/** + * This is used by the server and client to tell if the other side has registered the changes. + * @param p_Confirmed + * @return if m_Confirmed has changed + */ +bool SPITType::setConfirmed(bool p_Confirmed) { + if (m_Confirmed == p_Confirmed) + return false; + m_Confirmed = p_Confirmed; + return true; +} - /** - * Set the content of the SPITType as received from the server - * @param p_ReportSPITType - * @return true = the SPITType is changed
- * false = the SPITType is NOT changed, because it is not allowed to change. - */ - bool SPITType::setMessageOP(SPIT_Message::ReportSPITType* p_ReportSPITType) { - bool boolChangeAllowed; - bool boolChanged = false; - - if (m_CreatedByClient == true && m_Fixed == true) { - boolChangeAllowed = false; - } - else { - boolChangeAllowed = true; - } - - //Confirmation should be changable - if (m_CreatedByClient) { - //Server reports a client created SPITType -> the type is confirmed - m_Confirmed = true; - } - else { - //type is NOT client created -> the client has to confirm the SPITtype - m_Confirmed = p_ReportSPITType->getConfirmed(); - } - if (m_DefaultDelay != p_ReportSPITType->getDelay()) { - if (boolChangeAllowed == false) throw new exception(); - m_DefaultDelay = p_ReportSPITType->getDelay(); - boolChanged = true; - } - if (m_DefaultDuration != p_ReportSPITType->getDuration()) { - if (boolChangeAllowed == false) throw new exception(); - m_DefaultDuration = p_ReportSPITType->getDuration(); - boolChanged = true; - } - if (m_Fixed != p_ReportSPITType->getFixed()) { - if (boolChangeAllowed == false) throw new exception(); - m_Fixed = p_ReportSPITType->getFixed(); - boolChanged = true; - } - if (m_GroupName != p_ReportSPITType->getGroupName()) { - if (boolChangeAllowed == false) throw new exception(); - m_GroupName = p_ReportSPITType->getGroupName(); - boolChanged = true; - } - if (m_ID != p_ReportSPITType->getID()) { - if (boolChangeAllowed == false) throw new exception(); - m_ID = p_ReportSPITType->getID(); - boolChanged = true; - } - if (m_Name != p_ReportSPITType->getName()) { - if (boolChangeAllowed == false) throw new exception(); - m_Name = p_ReportSPITType->getName(); - boolChanged = true; - } - if (m_ServerProjectIndepended != p_ReportSPITType->getServerProjectIndepended()) { - if (boolChangeAllowed == false) throw new exception(); - m_ServerProjectIndepended = p_ReportSPITType->getServerProjectIndepended(); - boolChanged = true; - } - if (m_ServerRemote != p_ReportSPITType->getServerRemote()) { - if (boolChangeAllowed == false) throw new exception(); - m_ServerRemote = p_ReportSPITType->getServerRemote(); - boolChanged = true; - } - return boolChanged; - } - - void SPITType::fillMessageOP(SPIT_Message::ReportSPITType* ptrSMReportSPITType) { - ptrSMReportSPITType->setConfirmed(m_Confirmed); - ptrSMReportSPITType->setDelay(m_DefaultDelay); - ptrSMReportSPITType->setDuration(m_DefaultDuration); - ptrSMReportSPITType->setFixed(m_Fixed); - ptrSMReportSPITType->setGroupName(m_GroupName); - ptrSMReportSPITType->setID(m_ID); - ptrSMReportSPITType->setName(m_Name); - ptrSMReportSPITType->setServerProjectIndepended(m_ServerProjectIndepended); - ptrSMReportSPITType->setServerRemote(m_ServerRemote); - } - void SPITType::fillMessageOP(SPIT_Message::RemoveSPITType* ptrSMRemoveSPITType) { - ptrSMRemoveSPITType->setID(m_ID); - } +bool SPITType::setGroupName(string p_GroupName) { + if (m_GroupName == p_GroupName) + return false; + m_GroupName = p_GroupName; + m_Confirmed = false; + return true; +} +bool SPITType::setName(string p_Name) { + if (m_Name == p_Name) + return false; + m_Name = p_Name; + m_Confirmed = false; + return true; +} +bool SPITType::setServerRemote(bool p_BelongstoServer) { + if (m_ServerRemote == p_BelongstoServer) + return false; + m_ServerRemote = p_BelongstoServer; + m_Confirmed = false; + return true; +} +bool SPITType::setProjectIndepended(bool p_ProjectIndepended) { + if (m_ServerProjectIndepended == p_ProjectIndepended) + return false; + m_ServerProjectIndepended = p_ProjectIndepended; + m_Confirmed = false; + return true; +} +bool SPITType::setFixed(bool p_Fixed) { + if (m_Fixed == p_Fixed) + return false; + m_Fixed = p_Fixed; + m_Confirmed = false; + return true; +} +bool SPITType::setDefaultDelay(long long p_Delay) { + if (m_DefaultDelay == p_Delay) + return false; + m_DefaultDelay = p_Delay; + m_Confirmed = false; + return true; +} +bool SPITType::setDefaultDuration(long long p_Duration) { + if (m_DefaultDuration == p_Duration) + return false; + m_DefaultDuration = p_Duration; + m_Confirmed = false; + return true; +} + +/** + * 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.
+ * @return true = the m_ActionAssigned has changed. + */ +bool SPITType::setActionAssigned(bool p_ActionAssigned) { + if (m_ActionAssigned == p_ActionAssigned) + return false; + m_ActionAssigned = p_ActionAssigned; + m_Confirmed = false; + return true; +} + +/** + * Set the content of the SPITType as received from the server + * @param p_ReportSPITType + * @return true = the SPITType is changed
+ * false = the SPITType is NOT changed, because it is not allowed to change. + */ +bool SPITType::setMessageOP(SPIT_Message::ReportSPITType *p_ReportSPITType) { + bool boolChangeAllowed; + bool boolChanged = false; + + if (m_CreatedByClient == true && m_Fixed == true) { + boolChangeAllowed = false; + } else { + boolChangeAllowed = true; + } + + // Confirmation should be changable + if (m_CreatedByClient) { + // Server reports a client created SPITType -> the type is confirmed + m_Confirmed = true; + } else { + // type is NOT client created -> the client has to confirm the SPITtype + m_Confirmed = p_ReportSPITType->getConfirmed(); + } + if (m_DefaultDelay != p_ReportSPITType->getDelay()) { + if (boolChangeAllowed == false) + throw new exception(); + m_DefaultDelay = p_ReportSPITType->getDelay(); + boolChanged = true; + } + if (m_DefaultDuration != p_ReportSPITType->getDuration()) { + if (boolChangeAllowed == false) + throw new exception(); + m_DefaultDuration = p_ReportSPITType->getDuration(); + boolChanged = true; + } + if (m_Fixed != p_ReportSPITType->getFixed()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Fixed = p_ReportSPITType->getFixed(); + boolChanged = true; + } + if (m_GroupName != p_ReportSPITType->getGroupName()) { + if (boolChangeAllowed == false) + throw new exception(); + m_GroupName = p_ReportSPITType->getGroupName(); + boolChanged = true; + } + if (m_ID != p_ReportSPITType->getID()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ID = p_ReportSPITType->getID(); + boolChanged = true; + } + if (m_Name != p_ReportSPITType->getName()) { + if (boolChangeAllowed == false) + throw new exception(); + m_Name = p_ReportSPITType->getName(); + boolChanged = true; + } + if (m_ServerProjectIndepended != p_ReportSPITType->getServerProjectIndepended()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ServerProjectIndepended = p_ReportSPITType->getServerProjectIndepended(); + boolChanged = true; + } + if (m_ServerRemote != p_ReportSPITType->getServerRemote()) { + if (boolChangeAllowed == false) + throw new exception(); + m_ServerRemote = p_ReportSPITType->getServerRemote(); + boolChanged = true; + } + return boolChanged; +} + +void SPITType::fillMessageOP(SPIT_Message::ReportSPITType *ptrSMReportSPITType) { + ptrSMReportSPITType->setConfirmed(m_Confirmed); + ptrSMReportSPITType->setDelay(m_DefaultDelay); + ptrSMReportSPITType->setDuration(m_DefaultDuration); + ptrSMReportSPITType->setFixed(m_Fixed); + ptrSMReportSPITType->setGroupName(m_GroupName); + ptrSMReportSPITType->setID(m_ID); + ptrSMReportSPITType->setName(m_Name); + ptrSMReportSPITType->setServerProjectIndepended(m_ServerProjectIndepended); + ptrSMReportSPITType->setServerRemote(m_ServerRemote); +} +void SPITType::fillMessageOP(SPIT_Message::RemoveSPITType *ptrSMRemoveSPITType) { + ptrSMRemoveSPITType->setID(m_ID); +} diff --git a/components/spit/src/SPIT_Client.cpp b/components/spit/src/SPIT_Client.cpp index f9ac013..ad14445 100644 --- a/components/spit/src/SPIT_Client.cpp +++ b/components/spit/src/SPIT_Client.cpp @@ -4,78 +4,75 @@ * and open the template in the editor. */ -/* - * SPIt_Client handles the SPIT_Message transfer and - * fires eventxxx functions to the SPIT_ClientInterface (implemented by the user app). - * +/* + * SPIt_Client handles the SPIT_Message transfer and + * fires eventxxx functions to the SPIT_ClientInterface (implemented by the user app). + * * File: SPIT_Client.cpp * Author: Hagi - * + * * Created on 7. April 2019, 08:50 */ - #include "SPIT_Client.h" #include "esp_log.h" -static const char * TAG = "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. */ SPIT_Client::SPIT_Client(string name, string projName, Callbacks calls) - : I_SAD_Client(), mCallbacks(calls), m_Name(name), m_ProjName(projName) { - m_ConnectionStatus = CONNECTION_NONE; + : I_SAD_Client(), mCallbacks(calls), m_Name(name), m_ProjName(projName) { + m_ConnectionStatus = CONNECTION_NONE; - m_ID = createGUID(); - m_ComputerName = getClientHostName(); - auto ip = SPITSocket::getAdaptersInfo(); - mSPITSocket = new SPITSocket(ip); - m_MessageNumber_Send = 1; - m_MessageNumber_Received = -1; //set to -1 because the first received message will set the number (1..255) + m_ID = createGUID(); + m_ComputerName = getClientHostName(); + auto ip = SPITSocket::getAdaptersInfo(); + mSPITSocket = new SPITSocket(ip); + m_MessageNumber_Send = 1; + m_MessageNumber_Received = -1; // set to -1 because the first received message will set the number (1..255) } SPIT_Client::~SPIT_Client() { - stopServerAutoDetect(); - disconnectInternal(CONNECTION_NONE); + stopServerAutoDetect(); + disconnectInternal(CONNECTION_NONE); } - -void SPIT_Client::clientProjectClose() { - if (m_ConnectionStatus == CONNECTION_OK) { - ESP_LOGI(TAG, " ... tidy up ressources"); - SPIT_Message::CloseSPITProject sMCloseSPITProject; - sMCloseSPITProject.setProjectID(m_ProjName); - if (sendSPITMessage(sMCloseSPITProject) < 0) { - ESP_LOGD(TAG, "SPIT_Client could not send Client's ReportSPITProject"); - } - } +void SPIT_Client::clientProjectClose() { + if (m_ConnectionStatus == CONNECTION_OK) { + ESP_LOGI(TAG, " ... tidy up ressources"); + SPIT_Message::CloseSPITProject sMCloseSPITProject; + sMCloseSPITProject.setProjectID(m_ProjName); + if (sendSPITMessage(sMCloseSPITProject) < 0) { + ESP_LOGD(TAG, "SPIT_Client could not send Client's ReportSPITProject"); + } + } } void SPIT_Client::clientProjectLoaded() { - //set confirmed = false for all SPITTypes and SPITObjects - SPITType::setConfirmedFalse(); - SPITObject::setConfirmedFalse(); - - if (m_ConnectionStatus == CONNECTION_OK) { - //send ReportSPITProject to the server - SPIT_Message::ReportSPITProject sMReportSPITProject; - sMReportSPITProject.setProjectID(m_ProjName); - sMReportSPITProject.setProjectName(m_ProjName); - sMReportSPITProject.setFramesPerSecond(0); - if (sendSPITMessage(sMReportSPITProject) < 0) { - ESP_LOGD(TAG, "SPIT_CLient::clientProjectLoaded could not send Client's ReportSPITProject"); - } - - //send RequestProjectTransfer - SPIT_Message::RequestProjectTransfer sMRequestProjectTransfer; - if (sendSPITMessage(sMRequestProjectTransfer) < 0) { - ESP_LOGD(TAG, "SPIT_CLient::clientProjectLoaded could not send RequestProjectTransfer"); - } - } -} + // set confirmed = false for all SPITTypes and SPITObjects + SPITType::setConfirmedFalse(); + SPITObject::setConfirmedFalse(); + if (m_ConnectionStatus == CONNECTION_OK) { + // send ReportSPITProject to the server + SPIT_Message::ReportSPITProject sMReportSPITProject; + sMReportSPITProject.setProjectID(m_ProjName); + sMReportSPITProject.setProjectName(m_ProjName); + sMReportSPITProject.setFramesPerSecond(0); + if (sendSPITMessage(sMReportSPITProject) < 0) { + ESP_LOGD(TAG, "SPIT_CLient::clientProjectLoaded could not send Client's ReportSPITProject"); + } + + // send RequestProjectTransfer + SPIT_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.
@@ -86,25 +83,27 @@ void SPIT_Client::clientProjectLoaded() { * @param p_ActionAssigned */ void SPIT_Client::setActionSPITType(string p_SPITTypeID, bool p_ActionAssigned) { - SPITType* ptrSPITType; - SPITObject* ptrSPITObject; - { - ptrSPITType = SPITType::getSPITType(p_SPITTypeID); - if (ptrSPITType == NULL) return; - if (ptrSPITType->setActionAssigned(p_ActionAssigned) == true) { - sendSPITTypeInternal(ptrSPITType); + SPITType *ptrSPITType; + SPITObject *ptrSPITObject; + { + ptrSPITType = SPITType::getSPITType(p_SPITTypeID); + if (ptrSPITType == NULL) + return; + if (ptrSPITType->setActionAssigned(p_ActionAssigned) == true) { + sendSPITTypeInternal(ptrSPITType); - for (int i = 0; i < SPITObject::getSPITObjectCount(); i++) { - ptrSPITObject = SPITObject::getSPITObject(i); - if (ptrSPITObject == NULL) continue; - if (ptrSPITObject->getSPITTypeID() == ptrSPITType->getID()) { - if (ptrSPITObject->setActionAssignedType(p_ActionAssigned) == true) { - sendSPITObjectInternal(ptrSPITObject); - } - } - } - } - } + for (int i = 0; i < SPITObject::getSPITObjectCount(); i++) { + ptrSPITObject = SPITObject::getSPITObject(i); + if (ptrSPITObject == NULL) + continue; + if (ptrSPITObject->getSPITTypeID() == ptrSPITType->getID()) { + if (ptrSPITObject->setActionAssignedType(p_ActionAssigned) == true) { + sendSPITObjectInternal(ptrSPITObject); + } + } + } + } + } } /** @@ -113,14 +112,15 @@ void SPIT_Client::setActionSPITType(string p_SPITTypeID, bool p_ActionAssigned) * @param p_ActionAssigned */ void SPIT_Client::setActionSPITObject(string p_SPITObjectID, bool p_ActionAssigned) { - SPITObject* ptrSPITObject; - { - ptrSPITObject = SPITObject::getSPITObject(p_SPITObjectID); - if (ptrSPITObject == NULL) return; - if (ptrSPITObject->setActionAssigned(p_ActionAssigned) == true) { - sendSPITObjectInternal(ptrSPITObject); - } - } + SPITObject *ptrSPITObject; + { + ptrSPITObject = SPITObject::getSPITObject(p_SPITObjectID); + if (ptrSPITObject == NULL) + return; + if (ptrSPITObject->setActionAssigned(p_ActionAssigned) == true) { + sendSPITObjectInternal(ptrSPITObject); + } + } } //---------- ServerAutoDetection SAD ----------- @@ -128,54 +128,49 @@ void SPIT_Client::setActionSPITObject(string p_SPITObjectID, bool p_ActionAssign * If a SPITServer is detected in the locale network an eventServerDetected occurs. */ void SPIT_Client::startServerAutoDetect() { - if (m_DisconnectedByServer == true) { - //Server has previously disconnected -> do not start ServerAutodetect directly - //sleep a little to give the SPITServer time to clean up its stuff - - fos::Task::delayMs(1000); - } + if (m_DisconnectedByServer == true) { + // Server has previously disconnected -> do not start ServerAutodetect directly + // sleep a little to give the SPITServer time to clean up its stuff - + fos::Task::delayMs(1000); + } SAD_DetectedServer::clearDetectedServers(); if (!sThread) { - sThread = new fos::TaskT(SPIT_Client::processSocketTask, *this, "spitSock", fos::Task::DefaultStackSize*2 ); + sThread = new fos::TaskT(SPIT_Client::processSocketTask, *this, "spitSock", fos::Task::DefaultStackSize * 2); } abortSearch = false; sStartSad.give(); - } /** * Stops the auto detection of SPIT servers. */ void SPIT_Client::stopServerAutoDetect() { - abortSearch = true; + abortSearch = 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:
- * 1.) If a loopback address is available, it is used.
- * 2.) If an IP4 address is available, it is used.
- * 3.) In the other cases the IP6 address is used.
- * @param p_ID the id of the server (every started server should generate an id) - * @param p_Name the name of the SPIT server - * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running - * @param p_IP the selected ip address of the SPIT server - * @param p_Port the port of the SPIT server - * @param p_Addition sometimes server may have additional informations - * @param p_IsIP4 the server ip is a ip4 address - */ -void SPIT_Client::eventServerDetected(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4) { - try { - SAD_DetectedServer o_RefDetectedServer = SAD_DetectedServer::getRefDetectedServer(p_ID); - mCallbacks.onServerEvent(ServerEvent::Detect, o_RefDetectedServer); - +/** + * 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:
+ * 1.) If a loopback address is available, it is used.
+ * 2.) If an IP4 address is available, it is used.
+ * 3.) In the other cases the IP6 address is used.
+ * @param p_ID the id of the server (every started server should generate an id) + * @param p_Name the name of the SPIT server + * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running + * @param p_IP the selected ip address of the SPIT server + * @param p_Port the port of the SPIT server + * @param p_Addition sometimes server may have additional informations + */ +void SPIT_Client::eventServerDetected(SAD_DetectedServer &server) { + mCallbacks.onServerEvent(ServerEvent::Detect, server); // If a connection has been established and the connection is lost -> reconnect if (_doReconnect) { - if (m_ServerID == o_RefDetectedServer.getID()) { + if (m_ServerID == server.getID()) { stopServerAutoDetect(); - ESP_LOGI(TAG, "reconnect to %s", o_RefDetectedServer.getIP().data()); + ESP_LOGI(TAG, "reconnect to %s", server.getIP().data()); // ClientPort = "0" meeans use any port - if (connect(o_RefDetectedServer.getIP(), o_RefDetectedServer.getPort(), o_RefDetectedServer.getClientIP(), "0")) { + if (connect(server.getIP(), server.getPort(), server.getClientIP(), "0")) { return; } } @@ -183,72 +178,52 @@ void SPIT_Client::eventServerDetected(string p_ID, string p_Name, string p_Compu // Stop auto detection because a suitable server was found stopServerAutoDetect(); - ESP_LOGI(TAG, "connect to %s", o_RefDetectedServer.getIP().data()); + ESP_LOGI(TAG, "connect to %s", server.getIP().data()); // ClientPort = "0" meeans use any port - if (not connect(o_RefDetectedServer.getIP(), o_RefDetectedServer.getPort(), o_RefDetectedServer.getClientIP(), "0")) { + if (not connect(server.getIP(), server.getPort(), server.getClientIP(), "0")) { // connection message could not be sent -> better to restart AutoDetection startServerAutoDetect(); } - - } - catch (...) { - return; - } } - /** - * 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.
- * @param p_ID the id of the server (every started server should generate an id) - * @param p_Name the name of the SPIT server - * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running - * @param p_IP the selected ip address of the SPIT server - * @param p_Port the port of the SPIT server - * @param p_Addition sometimes server may have additional informations - * @param p_IsIP4 the server ip is a ip4 address - */ -void SPIT_Client::eventServerLost(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4) { - try { - SAD_DetectedServer o_RefDetectedServer = SAD_DetectedServer::getRefDetectedServer(p_ID); - mCallbacks.onServerEvent(ServerEvent::Lost, o_RefDetectedServer); - } - catch (...) { - return; - } +/** + * 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.
+ * @param p_ID the id of the server (every started server should generate an id) + * @param p_Name the name of the SPIT server + * @param p_ComputerName the Hostname of the cpmputer on which the SPIT server is running + * @param p_IP the selected ip address of the SPIT server + * @param p_Port the port of the SPIT server + * @param p_Addition sometimes server may have additional informations + */ +void SPIT_Client::eventServerLost(SAD_DetectedServer &server) { + mCallbacks.onServerEvent(ServerEvent::Lost, server); } -void SPIT_Client::eventServerChanged(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4) { - try { - SAD_DetectedServer o_RefDetectedServer = SAD_DetectedServer::getRefDetectedServer(p_ID); - mCallbacks.onServerEvent(ServerEvent::Changed, o_RefDetectedServer); - // tryConnection(p_DetectedServer); - } - catch (...) { - return; - } +void SPIT_Client::eventServerChanged(SAD_DetectedServer &server) { + mCallbacks.onServerEvent(ServerEvent::Changed, server); + // tryConnection(p_DetectedServer); } - - // void MyApp::tryConnection(const SAD_DetectedServer& p_DetectedServer) { // //fetch the infoemations from the p_DetectedServer // bool boolPossibleConnect; // bool boolSuccess; - + // boolPossibleConnect = checkPossibleConnection(p_DetectedServer); - + // 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 p_DetectedServer and do connection later -// // SAD_DetectedServer o_DetectedServer = p_DetectedServer; //this will call the copy constructor +// // SAD_DetectedServer o_DetectedServer = p_DetectedServer; //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 (p_DetectedServer.getIpIsLoopback() == true) { //omit the if condition if you want to use the first server found - +// //if (p_DetectedServer.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(); @@ -272,817 +247,802 @@ void SPIT_Client::eventServerChanged(string p_ID, string p_Name, string p_Comput // else { // //WAITING FOR CONNECTION ANSWER // //If the Server is closed in the meantime no answer will return -// //-> connect(..) has started the watchdog +// //-> connect(..) has started the watchdog // } - + // // } //Excample // } -void SPIT_Client::fillHeader(SPIT_Message::Header* p_Header) { - if (p_Header == NULL) return; - p_Header->setClientID(m_ID); - p_Header->setServerID(m_ServerID); +void SPIT_Client::fillHeader(SPIT_Message::Header *p_Header) { + if (p_Header == NULL) + return; + p_Header->setClientID(m_ID); + p_Header->setServerID(m_ServerID); } -int SPIT_Client::sendSPITMessage(SPIT_Message::OPPart& spitMessageOPPart) { - if (m_StopReceiveSPITMessages == true) { - return -1; - } +int SPIT_Client::sendSPITMessage(SPIT_Message::OPPart &spitMessageOPPart) { + if (m_StopReceiveSPITMessages == true) { + return -1; + } - fillHeader(spitMessageOPPart.getHeader()); + fillHeader(spitMessageOPPart.getHeader()); - if (m_MessageNumber_Send == 255) m_MessageNumber_Send = 1; - else m_MessageNumber_Send++; - spitMessageOPPart.getHeader()->setMessageNumber(m_MessageNumber_Send); + if (m_MessageNumber_Send == 255) + m_MessageNumber_Send = 1; + else + m_MessageNumber_Send++; + spitMessageOPPart.getHeader()->setMessageNumber(m_MessageNumber_Send); - SPIT_Message* ptrSPIT_Message; - ptrSPIT_Message = new SPIT_Message(&spitMessageOPPart); - const char* ptrMessageBytes = ptrSPIT_Message->getMessageBytes(); - int intByteCount = ptrSPIT_Message->getMesageByteCount(); + SPIT_Message *ptrSPIT_Message; + ptrSPIT_Message = new SPIT_Message(&spitMessageOPPart); + const char *ptrMessageBytes = ptrSPIT_Message->getMessageBytes(); + int intByteCount = ptrSPIT_Message->getMesageByteCount(); - if (ptrMessageBytes == NULL) { - return -1; - } - try { - int intResult = mSPITSocket->sendMessage(ptrMessageBytes, intByteCount); - if (intResult < 0) { - ESP_LOGD(TAG, "SPIT_Client::sendSPITMessage could not send message OPFlage: %d", ptrSPIT_Message->getOPFlag()); - } - return intResult; - } - catch (...) { - ESP_LOGD(TAG, "Exception SPIT_Client::sendSPITMessage OPFlag: %d", ptrSPIT_Message->getOPFlag()); - return -1; - } + if (ptrMessageBytes == NULL) { + return -1; + } + try { + int intResult = mSPITSocket->sendMessage(ptrMessageBytes, intByteCount); + if (intResult < 0) { + ESP_LOGD(TAG, "SPIT_Client::sendSPITMessage could not send message OPFlage: %d", ptrSPIT_Message->getOPFlag()); + } + return intResult; + } catch (...) { + ESP_LOGD(TAG, "Exception SPIT_Client::sendSPITMessage OPFlag: %d", ptrSPIT_Message->getOPFlag()); + return -1; + } } bool SPIT_Client::startReceiveSPITMessages() { - { - if (mSPITSocket->getBoundClientFamily() <= 0) return false; - m_StopReceiveSPITMessages = false; - m_ThreadReceive = new fos::TaskT(receiveSPITMessage, *this, "receiveTask", fos::Task::DefaultStackSize *4); - } - return true; + { + if (mSPITSocket->getBoundClientFamily() <= 0) + return false; + m_StopReceiveSPITMessages = false; + m_ThreadReceive = new fos::TaskT(receiveSPITMessage, *this, "receiveTask", fos::Task::DefaultStackSize * 4); + } + return true; } void SPIT_Client::stopReceiveSPITMessages() { - { - if (m_StopReceiveSPITMessages == true) return; - m_StopReceiveSPITMessages = true; - } + { + if (m_StopReceiveSPITMessages == true) + return; + m_StopReceiveSPITMessages = true; + } } -void SPIT_Client::receiveSPITMessage(SPIT_Client& rM) { - - char buffer[MAXSPITMESSAGEBYTECOUNT]; - int intResult; - while (rM.m_StopReceiveSPITMessages == false) { - if ( rM.m_StopReceiveSPITMessages == true) { - return; - } - intResult = rM.mSPITSocket->receiveMessage(rM.mSPITSocket->getBoundClientFamily(), buffer, MAXSPITMESSAGEBYTECOUNT, NULL); - if (intResult < 0) { - if (rM.m_StopReceiveSPITMessages) { - return;; - } - continue; - } - auto ptrSPIT_Message = make_unique(buffer, intResult); - unsigned int intActualMessageNumber = (int)(ptrSPIT_Message->getHeader()->getMessageNumber() & 0xFF); - rM.parseSPIT_Message(move(ptrSPIT_Message)); - // rM.checkParseSPIT_Message(move(ptrSPIT_Message)); - } +void SPIT_Client::receiveSPITMessage(SPIT_Client &rM) { + + char buffer[MAXSPITMESSAGEBYTECOUNT]; + int intResult; + while (rM.m_StopReceiveSPITMessages == false) { + if (rM.m_StopReceiveSPITMessages == true) { + return; + } + intResult = rM.mSPITSocket->receiveMessage(rM.mSPITSocket->getBoundClientFamily(), buffer, MAXSPITMESSAGEBYTECOUNT, NULL); + if (intResult < 0) { + if (rM.m_StopReceiveSPITMessages) { + return; + ; + } + continue; + } + auto ptrSPIT_Message = make_unique(buffer, intResult); + unsigned int intActualMessageNumber = (int)(ptrSPIT_Message->getHeader()->getMessageNumber() & 0xFF); + rM.parseSPIT_Message(move(ptrSPIT_Message)); + // rM.checkParseSPIT_Message(move(ptrSPIT_Message)); + } } void SPIT_Client::resetMessageNumberReceived() { - SPIT_Message* ptrOvertakingSPIT_Message; - - m_MessageNumber_Received = -1; - for (auto it = m_OvertakingSPIT_Messages.begin(); it != m_OvertakingSPIT_Messages.end(); it++) { - ptrOvertakingSPIT_Message = *it; - delete ptrOvertakingSPIT_Message; -// m_OvertakingSPIT_Messages.erase(it); - } - m_OvertakingSPIT_Messages.clear(); + SPIT_Message *ptrOvertakingSPIT_Message; + + m_MessageNumber_Received = -1; + for (auto it = m_OvertakingSPIT_Messages.begin(); it != m_OvertakingSPIT_Messages.end(); it++) { + ptrOvertakingSPIT_Message = *it; + delete ptrOvertakingSPIT_Message; + // m_OvertakingSPIT_Messages.erase(it); + } + m_OvertakingSPIT_Messages.clear(); } void SPIT_Client::checkParseSPIT_Message(unique_ptr p_SPITMessage) { - answerWatchdog(); - if (p_SPITMessage == NULL) { - ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message Parameter == NULL\n"); - return; - } - if (p_SPITMessage->getHeader() == NULL) { - ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no Header\n"); - return; - } - if (p_SPITMessage->getOPPart() == NULL) { - ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no OPPart\n"); - return; - } - - int intActualMessageNumber; - int intNextMessageNumber; - SPIT_Message* ptrOvertakingSPIT_Message; + answerWatchdog(); + if (p_SPITMessage == NULL) { + ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message Parameter == NULL\n"); + return; + } + if (p_SPITMessage->getHeader() == NULL) { + ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no Header\n"); + return; + } + if (p_SPITMessage->getOPPart() == NULL) { + ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no OPPart\n"); + return; + } - intActualMessageNumber = (int)(p_SPITMessage->getHeader()->getMessageNumber() & 0xFF); + int intActualMessageNumber; + int intNextMessageNumber; + SPIT_Message *ptrOvertakingSPIT_Message; - if (intActualMessageNumber == 0) { - parseSPIT_Message(std::move(p_SPITMessage)); - return; - } - if (m_MessageNumber_Received < 0) { - m_MessageNumber_Received = intActualMessageNumber; - parseSPIT_Message(std::move(p_SPITMessage)); - return; - } - - intNextMessageNumber = m_MessageNumber_Received +1; - if (intNextMessageNumber > 255 || intNextMessageNumber < 1) intNextMessageNumber = 1; - - if (intActualMessageNumber == intNextMessageNumber) { - m_MessageNumber_Received = intActualMessageNumber; - parseSPIT_Message(std::move(p_SPITMessage)); - - //check overtaking messages - auto it = m_OvertakingSPIT_Messages.begin(); - while (m_OvertakingSPIT_Messages.size() > 0) { - - intNextMessageNumber = m_MessageNumber_Received +1; - if (intNextMessageNumber > 255 || intNextMessageNumber < 1) intNextMessageNumber = 1; - - ptrOvertakingSPIT_Message = *it; - intActualMessageNumber = (int)(ptrOvertakingSPIT_Message->getHeader()->getMessageNumber() & 0xFF); - - if (intActualMessageNumber == intNextMessageNumber) { - m_MessageNumber_Received = intActualMessageNumber; - // parseSPIT_Message(ptrOvertakingSPIT_Message); - m_OvertakingSPIT_Messages.erase(it); - - it = m_OvertakingSPIT_Messages.begin(); - } - else { - break; - } - } - - } - else { - //p_SPITMessage has overtaken another message - addOvertakingSPIT_Message(p_SPITMessage.get()); - } + intActualMessageNumber = (int)(p_SPITMessage->getHeader()->getMessageNumber() & 0xFF); + + if (intActualMessageNumber == 0) { + parseSPIT_Message(std::move(p_SPITMessage)); + return; + } + if (m_MessageNumber_Received < 0) { + m_MessageNumber_Received = intActualMessageNumber; + parseSPIT_Message(std::move(p_SPITMessage)); + return; + } + + intNextMessageNumber = m_MessageNumber_Received + 1; + if (intNextMessageNumber > 255 || intNextMessageNumber < 1) + intNextMessageNumber = 1; + + if (intActualMessageNumber == intNextMessageNumber) { + m_MessageNumber_Received = intActualMessageNumber; + parseSPIT_Message(std::move(p_SPITMessage)); + + // check overtaking messages + auto it = m_OvertakingSPIT_Messages.begin(); + while (m_OvertakingSPIT_Messages.size() > 0) { + + intNextMessageNumber = m_MessageNumber_Received + 1; + if (intNextMessageNumber > 255 || intNextMessageNumber < 1) + intNextMessageNumber = 1; + + ptrOvertakingSPIT_Message = *it; + intActualMessageNumber = (int)(ptrOvertakingSPIT_Message->getHeader()->getMessageNumber() & 0xFF); + + if (intActualMessageNumber == intNextMessageNumber) { + m_MessageNumber_Received = intActualMessageNumber; + // parseSPIT_Message(ptrOvertakingSPIT_Message); + m_OvertakingSPIT_Messages.erase(it); + + it = m_OvertakingSPIT_Messages.begin(); + } else { + break; + } + } + + } else { + // p_SPITMessage has overtaken another message + addOvertakingSPIT_Message(p_SPITMessage.get()); + } } int SPIT_Client::s_MAX_OVERTAKING_SPIT_MESSAGES = 10; -void SPIT_Client::addOvertakingSPIT_Message(SPIT_Message* p_SPIT_Message) { - if (p_SPIT_Message == nullptr) return; - int intMessageNumber; - SPIT_Message* ptrOvertakingSPIT_Message; - int intOvertakingMessageNumber; - - if (m_OvertakingSPIT_Messages.size() > s_MAX_OVERTAKING_SPIT_MESSAGES) { - printf("SPIT_Client receiveing: perhaps message lost !!!!!"); - } - - intMessageNumber = (int)(p_SPIT_Message->getHeader()->getMessageNumber() & 0xFF); - for (auto it = m_OvertakingSPIT_Messages.begin(); it != m_OvertakingSPIT_Messages.end(); it++) { - ptrOvertakingSPIT_Message = *it; - intOvertakingMessageNumber = (int)(ptrOvertakingSPIT_Message->getHeader()->getMessageNumber() & 0xFF); - if (intMessageNumber < intOvertakingMessageNumber) { - m_OvertakingSPIT_Messages.insert(it, p_SPIT_Message); - return; - } - } - m_OvertakingSPIT_Messages.push_back(p_SPIT_Message); +void SPIT_Client::addOvertakingSPIT_Message(SPIT_Message *p_SPIT_Message) { + if (p_SPIT_Message == nullptr) + return; + int intMessageNumber; + SPIT_Message *ptrOvertakingSPIT_Message; + int intOvertakingMessageNumber; + + if (m_OvertakingSPIT_Messages.size() > s_MAX_OVERTAKING_SPIT_MESSAGES) { + ESP_LOGD(TAG, "SPIT_Client receiveing: perhaps message lost !!!!!"); + } + + intMessageNumber = (int)(p_SPIT_Message->getHeader()->getMessageNumber() & 0xFF); + for (auto it = m_OvertakingSPIT_Messages.begin(); it != m_OvertakingSPIT_Messages.end(); it++) { + ptrOvertakingSPIT_Message = *it; + intOvertakingMessageNumber = (int)(ptrOvertakingSPIT_Message->getHeader()->getMessageNumber() & 0xFF); + if (intMessageNumber < intOvertakingMessageNumber) { + m_OvertakingSPIT_Messages.insert(it, p_SPIT_Message); + return; + } + } + m_OvertakingSPIT_Messages.push_back(p_SPIT_Message); } void SPIT_Client::parseSPIT_Message(unique_ptr p_SPITMessage) { - answerWatchdog(); - if (!p_SPITMessage) { - ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message Parameter == NULL"); - return; - } - if (p_SPITMessage->getHeader() == nullptr) { - ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no Header"); - return; - } - if (p_SPITMessage->getOPPart() == nullptr) { - ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no OPPart"); - return; - } - //----- Connection ----- - if (p_SPITMessage->getOPFlag() == SPIT_Message::ConnectAnswer::OPFLAG) { - SPIT_Message::ConnectAnswer* o_ConnectAnswer = (SPIT_Message::ConnectAnswer*) p_SPITMessage->getOPPart(); - parseConnectAnswer(o_ConnectAnswer); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::Disconnect::OPFLAG) { - SPIT_Message::Disconnect* o_Disconnect = (SPIT_Message::Disconnect*) p_SPITMessage->getOPPart(); - parseDisconnect(o_Disconnect); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportSPITProject::OPFLAG) { - SPIT_Message::ReportSPITProject* o_ReportSPITProject = (SPIT_Message::ReportSPITProject*) p_SPITMessage->getOPPart(); - parseReportSPITProject(o_ReportSPITProject); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::Watchdog::OPFLAG) { - SPIT_Message::Watchdog* o_Watchdog = (SPIT_Message::Watchdog*) p_SPITMessage->getOPPart(); - parseWatchdog(o_Watchdog); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::WatchdogAnswer::OPFLAG) { - SPIT_Message::WatchdogAnswer* o_WatchdogAnswer = (SPIT_Message::WatchdogAnswer*) p_SPITMessage->getOPPart(); - parseWatchdogAnswer(o_WatchdogAnswer); - } - //----- SPIT Project ----- - else if (p_SPITMessage->getOPFlag() == SPIT_Message::StartProjectTransfer::OPFLAG) { - SPIT_Message::StartProjectTransfer* o_StartProjectTransfer = (SPIT_Message::StartProjectTransfer*) p_SPITMessage->getOPPart(); - parseStartProjectTransfer(o_StartProjectTransfer); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::CloseSPITProject::OPFLAG) { - SPIT_Message::CloseSPITProject* o_CloseSPITProjectr = (SPIT_Message::CloseSPITProject*) p_SPITMessage->getOPPart(); - parseCloseSPITProject(o_CloseSPITProjectr); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::RequestProjectTransfer::OPFLAG) { - SPIT_Message::RequestProjectTransfer* o_RequestProjectTransfer = (SPIT_Message::RequestProjectTransfer*) p_SPITMessage->getOPPart(); - parseRequestProjectTransfer(o_RequestProjectTransfer); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::StartProjectTransfer::OPFLAG) { - SPIT_Message::StartProjectTransfer* o_StartProjectTransfer = (SPIT_Message::StartProjectTransfer*) p_SPITMessage->getOPPart(); - parseStartProjectTransfer(o_StartProjectTransfer); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::EndProjectTransfer::OPFLAG) { - SPIT_Message::EndProjectTransfer* o_EndProjectTransfer = (SPIT_Message::EndProjectTransfer*) p_SPITMessage->getOPPart(); - parseEndProjectTransfer(o_EndProjectTransfer); - } - //----- SPIT Types ------ - else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportSPITType::OPFLAG) { - SPIT_Message::ReportSPITType* o_ReportSPITType = (SPIT_Message::ReportSPITType*) p_SPITMessage->getOPPart(); - parseReportSPITType(o_ReportSPITType); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::RemoveSPITType::OPFLAG) { - SPIT_Message::RemoveSPITType* o_RemoveSPITType = (SPIT_Message::RemoveSPITType*) p_SPITMessage->getOPPart(); - parseRemoveSPITType(o_RemoveSPITType); - } - //----- SPIT Objects ------ - else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportSPITObject::OPFLAG) { - SPIT_Message::ReportSPITObject* o_ReportSPITObject = (SPIT_Message::ReportSPITObject*) p_SPITMessage->getOPPart(); - parseReportSPITObject(o_ReportSPITObject); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::RemoveSPITObject::OPFLAG) { - SPIT_Message::RemoveSPITObject* o_RemoveSPITObject = (SPIT_Message::RemoveSPITObject*) p_SPITMessage->getOPPart(); - parseRemoveSPITObject(o_RemoveSPITObject); - } - //----- Play SPIT Objects ------ - else if (p_SPITMessage->getOPFlag() == SPIT_Message::PlaySPITStart::OPFLAG) { - SPIT_Message::PlaySPITStart* o_PlaySPITStart = (SPIT_Message::PlaySPITStart*) p_SPITMessage->getOPPart(); - parsePlaySPITStart(o_PlaySPITStart); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::PlaySPITObject::OPFLAG) { - SPIT_Message::PlaySPITObject* o_PlaySPITObject = (SPIT_Message::PlaySPITObject*) p_SPITMessage->getOPPart(); - parsePlaySPITObject(o_PlaySPITObject); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::PlaySPITEnd::OPFLAG) { - SPIT_Message::PlaySPITEnd* o_PlaySPITEnd = (SPIT_Message::PlaySPITEnd*) p_SPITMessage->getOPPart(); - parsePlaySPITEnd(o_PlaySPITEnd); - } - else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportPlayStatus::OPFLAG) { - SPIT_Message::ReportPlayStatus* o_ReportPlayStatus = (SPIT_Message::ReportPlayStatus*) p_SPITMessage->getOPPart(); - parseReportPlayStatus(o_ReportPlayStatus); - } - else { - ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message: Unknown Message"); - } + answerWatchdog(); + if (!p_SPITMessage) { + ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message Parameter == NULL"); + return; + } + if (p_SPITMessage->getHeader() == nullptr) { + ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no Header"); + return; + } + if (p_SPITMessage->getOPPart() == nullptr) { + ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message no OPPart"); + return; + } + //----- Connection ----- + if (p_SPITMessage->getOPFlag() == SPIT_Message::ConnectAnswer::OPFLAG) { + SPIT_Message::ConnectAnswer *o_ConnectAnswer = (SPIT_Message::ConnectAnswer *)p_SPITMessage->getOPPart(); + parseConnectAnswer(o_ConnectAnswer); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::Disconnect::OPFLAG) { + SPIT_Message::Disconnect *o_Disconnect = (SPIT_Message::Disconnect *)p_SPITMessage->getOPPart(); + parseDisconnect(o_Disconnect); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportSPITProject::OPFLAG) { + SPIT_Message::ReportSPITProject *o_ReportSPITProject = (SPIT_Message::ReportSPITProject *)p_SPITMessage->getOPPart(); + parseReportSPITProject(o_ReportSPITProject); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::Watchdog::OPFLAG) { + SPIT_Message::Watchdog *o_Watchdog = (SPIT_Message::Watchdog *)p_SPITMessage->getOPPart(); + parseWatchdog(o_Watchdog); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::WatchdogAnswer::OPFLAG) { + SPIT_Message::WatchdogAnswer *o_WatchdogAnswer = (SPIT_Message::WatchdogAnswer *)p_SPITMessage->getOPPart(); + parseWatchdogAnswer(o_WatchdogAnswer); + } + //----- SPIT Project ----- + else if (p_SPITMessage->getOPFlag() == SPIT_Message::StartProjectTransfer::OPFLAG) { + SPIT_Message::StartProjectTransfer *o_StartProjectTransfer = (SPIT_Message::StartProjectTransfer *)p_SPITMessage->getOPPart(); + parseStartProjectTransfer(o_StartProjectTransfer); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::CloseSPITProject::OPFLAG) { + SPIT_Message::CloseSPITProject *o_CloseSPITProjectr = (SPIT_Message::CloseSPITProject *)p_SPITMessage->getOPPart(); + parseCloseSPITProject(o_CloseSPITProjectr); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::RequestProjectTransfer::OPFLAG) { + SPIT_Message::RequestProjectTransfer *o_RequestProjectTransfer = (SPIT_Message::RequestProjectTransfer *)p_SPITMessage->getOPPart(); + parseRequestProjectTransfer(o_RequestProjectTransfer); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::StartProjectTransfer::OPFLAG) { + SPIT_Message::StartProjectTransfer *o_StartProjectTransfer = (SPIT_Message::StartProjectTransfer *)p_SPITMessage->getOPPart(); + parseStartProjectTransfer(o_StartProjectTransfer); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::EndProjectTransfer::OPFLAG) { + SPIT_Message::EndProjectTransfer *o_EndProjectTransfer = (SPIT_Message::EndProjectTransfer *)p_SPITMessage->getOPPart(); + parseEndProjectTransfer(o_EndProjectTransfer); + } + //----- SPIT Types ------ + else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportSPITType::OPFLAG) { + SPIT_Message::ReportSPITType *o_ReportSPITType = (SPIT_Message::ReportSPITType *)p_SPITMessage->getOPPart(); + parseReportSPITType(o_ReportSPITType); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::RemoveSPITType::OPFLAG) { + SPIT_Message::RemoveSPITType *o_RemoveSPITType = (SPIT_Message::RemoveSPITType *)p_SPITMessage->getOPPart(); + parseRemoveSPITType(o_RemoveSPITType); + } + //----- SPIT Objects ------ + else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportSPITObject::OPFLAG) { + SPIT_Message::ReportSPITObject *o_ReportSPITObject = (SPIT_Message::ReportSPITObject *)p_SPITMessage->getOPPart(); + parseReportSPITObject(o_ReportSPITObject); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::RemoveSPITObject::OPFLAG) { + SPIT_Message::RemoveSPITObject *o_RemoveSPITObject = (SPIT_Message::RemoveSPITObject *)p_SPITMessage->getOPPart(); + parseRemoveSPITObject(o_RemoveSPITObject); + } + //----- Play SPIT Objects ------ + else if (p_SPITMessage->getOPFlag() == SPIT_Message::PlaySPITStart::OPFLAG) { + SPIT_Message::PlaySPITStart *o_PlaySPITStart = (SPIT_Message::PlaySPITStart *)p_SPITMessage->getOPPart(); + parsePlaySPITStart(o_PlaySPITStart); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::PlaySPITObject::OPFLAG) { + SPIT_Message::PlaySPITObject *o_PlaySPITObject = (SPIT_Message::PlaySPITObject *)p_SPITMessage->getOPPart(); + parsePlaySPITObject(o_PlaySPITObject); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::PlaySPITEnd::OPFLAG) { + SPIT_Message::PlaySPITEnd *o_PlaySPITEnd = (SPIT_Message::PlaySPITEnd *)p_SPITMessage->getOPPart(); + parsePlaySPITEnd(o_PlaySPITEnd); + } else if (p_SPITMessage->getOPFlag() == SPIT_Message::ReportPlayStatus::OPFLAG) { + SPIT_Message::ReportPlayStatus *o_ReportPlayStatus = (SPIT_Message::ReportPlayStatus *)p_SPITMessage->getOPPart(); + parseReportPlayStatus(o_ReportPlayStatus); + } else { + ESP_LOGD(TAG, "SPIT_Client::parseSPIT_Message: Unknown Message"); + } } - //----- Connection ------ /** * Tries to connect to a SPITServer.
* @param p_ServerIP the ip address of the SPIT server * @param p_ServerPort the port number of the SPIT server * @param p_ClientIP the local IP address of the client - * @param p_ClientPort the port number of the Client, if "0" the OS uses any possible port number + * @param p_ClientPort the port number of the Client, if "0" the OS uses any possible port number * @param p_LoginName login user name (liveSHOW does not use this -> mayby "" * @param p_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 SPIT_Client::connect(string p_ServerIP, string p_ServerPort, string p_ClientIP, string p_ClientPort, string p_LoginName, string p_LoginPassword) { - int intResult; - disconnect(); - { - mSPITSocket->setConnectionParams(p_ServerIP, p_ServerPort, p_ClientIP, p_ClientPort); - intResult = mSPITSocket->bindSocket(p_ServerIP, p_ClientIP, p_ClientPort); - if (intResult < 0) { - m_StopReceiveSPITMessages = true; - return false; - } - } - SPIT_Message::Connect sMConnect; - sMConnect.setClientComputerName(m_ComputerName); - sMConnect.setClientName(m_Name); - sMConnect.setLoginName(p_LoginName); - sMConnect.setLoginPassword(p_LoginPassword); - sMConnect.setServerIP(p_ServerIP); - if (p_ServerPort.length() <= 0) { - p_ServerPort = "0"; - } - int intServerPort; - intServerPort = stoi(p_ServerPort); - sMConnect.setServerPort(intServerPort); - - if (startReceiveSPITMessages() == false) { - m_StopReceiveSPITMessages = true; - return false; - } - resetMessageNumberReceived(); - int intOldConnectionStatus = m_ConnectionStatus; + int intResult; + disconnect(); + { + mSPITSocket->setConnectionParams(p_ServerIP, p_ServerPort, p_ClientIP, p_ClientPort); + intResult = mSPITSocket->bindSocket(p_ServerIP, p_ClientIP, p_ClientPort); + if (intResult < 0) { + m_StopReceiveSPITMessages = true; + return false; + } + } + SPIT_Message::Connect sMConnect; + sMConnect.setClientComputerName(m_ComputerName); + sMConnect.setClientName(m_Name); + sMConnect.setLoginName(p_LoginName); + sMConnect.setLoginPassword(p_LoginPassword); + sMConnect.setServerIP(p_ServerIP); + if (p_ServerPort.length() <= 0) { + p_ServerPort = "0"; + } + int intServerPort; + intServerPort = stoi(p_ServerPort); + sMConnect.setServerPort(intServerPort); - m_ConnectionStatus = CONNECTION_TRYCONNECTION; - mCallbacks.onConnectionStatus(m_ServerID, m_ServerComputerName, m_ServerName, m_ServerStepTime, - m_ConnectionStatus, intOldConnectionStatus); + if (startReceiveSPITMessages() == false) { + m_StopReceiveSPITMessages = true; + return false; + } + resetMessageNumberReceived(); + int intOldConnectionStatus = m_ConnectionStatus; - //sleep a little to make sure that the reception of the messages is started - fos::Task::delayMs(500); - intResult = sendSPITMessage(sMConnect); - if (intResult < 0) { - m_ConnectionStatus = CONNECTION_NONE; - m_StopReceiveSPITMessages = true; - return false; - } - return true; + m_ConnectionStatus = CONNECTION_TRYCONNECTION; + mCallbacks.onConnectionStatus(m_ServerID, m_ServerComputerName, m_ServerName, m_ServerStepTime, + m_ConnectionStatus, intOldConnectionStatus); + + // sleep a little to make sure that the reception of the messages is started + fos::Task::delayMs(500); + intResult = sendSPITMessage(sMConnect); + if (intResult < 0) { + m_ConnectionStatus = CONNECTION_NONE; + m_StopReceiveSPITMessages = true; + return false; + } + return true; } /** * Terminates the connection to the SPITServer. */ void SPIT_Client::disconnect() { - disconnectInternal(CONNECTION_NONE); + disconnectInternal(CONNECTION_NONE); } void SPIT_Client::disconnectInternal(int p_Cause) { - int intOldConnectionStatus = m_ConnectionStatus; - int intResult; - - m_ConnectionStatus = p_Cause; - switch (m_ConnectionStatus) { - case CONNECTION_LOST: - break; - case CONNECTION_NONE: - { - SPIT_Message::Disconnect sMDisconnect; - intResult = sendSPITMessage(sMDisconnect); - if (intResult < 0) { - } - } - break; - case CONNECTION_NONESERVER: - break; - } - stopReceiveSPITMessages(); - mCallbacks.onConnectionStatus(m_ServerID, m_ServerComputerName, m_ServerName, m_ServerStepTime, - m_ConnectionStatus, intOldConnectionStatus); + int intOldConnectionStatus = m_ConnectionStatus; + int intResult; - if (intOldConnectionStatus != CONNECTION_NONE && intOldConnectionStatus != CONNECTION_NONESERVER) { - ESP_LOGI(TAG, "eventConnectionStatus %d ", m_ConnectionStatus); - switch (m_ConnectionStatus) { - case SPIT_Client::CONNECTION_NONE: - ESP_LOGD(TAG, "not connected"); - break; - case SPIT_Client::CONNECTION_NONESERVER: - ESP_LOGD(TAG, "connection terminated by server"); - // call eventProjectClosed because this may not be sended by the server, - // when the connection is closed - mCallbacks.onProjectClosed(m_ServerProjectID); + m_ConnectionStatus = p_Cause; + switch (m_ConnectionStatus) { + case CONNECTION_LOST: + break; + case CONNECTION_NONE: { + SPIT_Message::Disconnect sMDisconnect; + intResult = sendSPITMessage(sMDisconnect); + if (intResult < 0) { + } + } break; + case CONNECTION_NONESERVER: + break; + } + stopReceiveSPITMessages(); + mCallbacks.onConnectionStatus(m_ServerID, m_ServerComputerName, m_ServerName, m_ServerStepTime, + m_ConnectionStatus, intOldConnectionStatus); - // Server has terminated the connection -> start a new game - // _doReconnect = false; - startServerAutoDetect(); - break; - case SPIT_Client::CONNECTION_LOST: - 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; - } - } + if (intOldConnectionStatus != CONNECTION_NONE && intOldConnectionStatus != CONNECTION_NONESERVER) { + ESP_LOGI(TAG, "eventConnectionStatus %d ", m_ConnectionStatus); + switch (m_ConnectionStatus) { + case SPIT_Client::CONNECTION_NONE: + ESP_LOGD(TAG, "not connected"); + break; + case SPIT_Client::CONNECTION_NONESERVER: + 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, m_ServerProjectID); + + // Server has terminated the connection -> start a new game + // _doReconnect = false; + startServerAutoDetect(); + break; + case SPIT_Client::CONNECTION_LOST: + 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; + } + } } -void SPIT_Client::parseConnectAnswer(SPIT_Message::ConnectAnswer* p_ConnectAnswer) { - int intOldConnectionStatus; - intOldConnectionStatus = m_ConnectionStatus; +void SPIT_Client::parseConnectAnswer(SPIT_Message::ConnectAnswer *p_ConnectAnswer) { + int intOldConnectionStatus; + intOldConnectionStatus = m_ConnectionStatus; - if (p_ConnectAnswer->getClientID() != m_ID) return; + if (p_ConnectAnswer->getClientID() != m_ID) + return; - m_ServerID = p_ConnectAnswer->getServerID(); - m_ServerComputerName = p_ConnectAnswer->getServerComputerName(); - m_ServerName = p_ConnectAnswer->getServerName(); - m_ServerStepTime = p_ConnectAnswer->getStepTime(); - - if (p_ConnectAnswer->getConnected() == false) { - disconnectInternal(CONNECTION_NONESERVER); - } - else { - p_ConnectAnswer->getStepTime(); - m_ConnectionStatus = CONNECTION_OK; - m_DisconnectedByServer = false; - ESP_LOGD(TAG, "connection established"); - stopServerAutoDetect(); // normally you should stop the autodetection before you try a connection - // This is redundand - m_StopReceiveSPITMessages = false; + m_ServerID = p_ConnectAnswer->getServerID(); + m_ServerComputerName = p_ConnectAnswer->getServerComputerName(); + m_ServerName = p_ConnectAnswer->getServerName(); + m_ServerStepTime = p_ConnectAnswer->getStepTime(); - // Maybe you want to reconnect, see eventServerDetected(...) - // Here the connection is established -> don't reconnect at eventServerDetected(...) - // _doReconnect = false; - } + if (p_ConnectAnswer->getConnected() == false) { + disconnectInternal(CONNECTION_NONESERVER); + } else { + p_ConnectAnswer->getStepTime(); + m_ConnectionStatus = CONNECTION_OK; + m_DisconnectedByServer = false; + ESP_LOGD(TAG, "connection established"); + stopServerAutoDetect(); // normally you should stop the autodetection before you try a connection + // This is redundand + m_StopReceiveSPITMessages = 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 p_Disconnect */ -void SPIT_Client::parseDisconnect(SPIT_Message::Disconnect* p_Disconnect) { - int intCauseDisconnect = CONNECTION_NONESERVER; - /* - function o_Callable = bind(&SPIT_Client::disconnectInternal, this, intCauseDisconnect); - SPIT_Handler::addCallable(o_Callable); - */ - m_DisconnectedByServer = true; - SPIT_Client::disconnectInternal(intCauseDisconnect); +void SPIT_Client::parseDisconnect(SPIT_Message::Disconnect *p_Disconnect) { + int intCauseDisconnect = CONNECTION_NONESERVER; + /* + function o_Callable = bind(&SPIT_Client::disconnectInternal, this, intCauseDisconnect); + SPIT_Handler::addCallable(o_Callable); + */ + m_DisconnectedByServer = true; + SPIT_Client::disconnectInternal(intCauseDisconnect); } - //----- 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.
+ * This is used to check if the other side is still present.
* @param p_Watchdog */ -void SPIT_Client::parseWatchdog(SPIT_Message::Watchdog* p_Watchdog) { -// printf("parse Watchdog \n"); - SPIT_Message::WatchdogAnswer o_WatchdogAnswer; - ; - int intResult = sendSPITMessage(o_WatchdogAnswer); - if (intResult < 0) { - } +void SPIT_Client::parseWatchdog(SPIT_Message::Watchdog *p_Watchdog) { + // printf("parse Watchdog \n"); + SPIT_Message::WatchdogAnswer o_WatchdogAnswer; + ; + int intResult = sendSPITMessage(o_WatchdogAnswer); + if (intResult < 0) { + } } /** * 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.
+ * This is used to check if the other side is still present.
* @param p_Watchdog */ -void SPIT_Client::parseWatchdogAnswer(SPIT_Message::WatchdogAnswer* p_WatchdogAnswer) { - answerWatchdog();; //is also done by parseSPIT_Message +void SPIT_Client::parseWatchdogAnswer(SPIT_Message::WatchdogAnswer *p_WatchdogAnswer) { + answerWatchdog(); + ; // is also done by parseSPIT_Message } void SPIT_Client::sendWatchdog() { - int intResult; - SPIT_Message::Watchdog sMWatchdog; - intResult = sendSPITMessage(sMWatchdog); - if (intResult < 0) { + int intResult; + SPIT_Message::Watchdog sMWatchdog; + intResult = sendSPITMessage(sMWatchdog); + if (intResult < 0) { ESP_LOGW("WDT", "Failed to send Watchdog msg"); - } + } } void SPIT_Client::eventWatchdogLost() { - if (m_ConnectionStatus == CONNECTION_TRYCONNECTION) { - disconnectInternal(CONNECTION_NONESERVER); - } - else { - disconnectInternal(CONNECTION_LOST); - } + if (m_ConnectionStatus == CONNECTION_TRYCONNECTION) { + disconnectInternal(CONNECTION_NONESERVER); + } else { + disconnectInternal(CONNECTION_LOST); + } } //----- SPIT Project ------ -void SPIT_Client::parseReportSPITProject(SPIT_Message::ReportSPITProject* p_ReportSPITProject) { -// printf("parse ReportSPITProject \n"); - if (p_ReportSPITProject == NULL) return; - m_ServerProjectID = p_ReportSPITProject->getProjectID(); - m_ServerProjectName = p_ReportSPITProject->getProjectName(); - m_ServerFramesPerSecond = p_ReportSPITProject->getFramesPerSecond(); - mCallbacks.onProjectReport(m_ServerProjectID, m_ServerProjectName, m_ServerFramesPerSecond); - - //Set all SPITTypes and SPITObjects confirmed = false - SPITType::setConfirmedFalse(); - SPITObject::setConfirmedFalse(); - - - //Send RequestProjectTransfer - SPIT_Message::RequestProjectTransfer sMRequestProjectTransfer; - if (sendSPITMessage(sMRequestProjectTransfer) < 0) { - printf("SPIT_Client::parseReportSPITProject could not send RequestProjectTransfer\n"); - } +void SPIT_Client::parseReportSPITProject(SPIT_Message::ReportSPITProject *p_ReportSPITProject) { + // printf("parse ReportSPITProject \n"); + if (p_ReportSPITProject == NULL) + return; + m_ServerProjectID = p_ReportSPITProject->getProjectID(); + m_ServerProjectName = p_ReportSPITProject->getProjectName(); + m_ServerFramesPerSecond = p_ReportSPITProject->getFramesPerSecond(); + mCallbacks.onProjectUpdate(ProjUpdate::ServerLoaded, m_ServerProjectID); - // todo Don't send the ReportSPITProject here it should be sended after parseEndProjectTransfer - //Send client's ReportSPITProject - SPIT_Message::ReportSPITProject sMReportSPITProject; - sMReportSPITProject.setProjectID(m_ProjName); - sMReportSPITProject.setProjectName(m_ProjName); - sMReportSPITProject.setFramesPerSecond(0); - if (sendSPITMessage(sMReportSPITProject) < 0) { - printf("SPIT_Client::parseReportSPITProject could not send Client's ReportSPITProject"); - } -} -void SPIT_Client::parseCloseSPITProject(SPIT_Message::CloseSPITProject* p_CloseSPITProject) { -// printf("parse CloseSPITProject \n"); - if (p_CloseSPITProject == NULL) return; - string stringProjectID; - mCallbacks.onProjectClosed(p_CloseSPITProject->getProjectID()); -} + // Set all SPITTypes and SPITObjects confirmed = false + SPITType::setConfirmedFalse(); + SPITObject::setConfirmedFalse(); + // Send RequestProjectTransfer + SPIT_Message::RequestProjectTransfer sMRequestProjectTransfer; + if (sendSPITMessage(sMRequestProjectTransfer) < 0) { + ESP_LOGD(TAG, "SPIT_Client::parseReportSPITProject could not send RequestProjectTransfer\n"); + } + + // todo Don't send the ReportSPITProject here it should be sended after parseEndProjectTransfer + // Send client's ReportSPITProject + SPIT_Message::ReportSPITProject sMReportSPITProject; + sMReportSPITProject.setProjectID(m_ProjName); + sMReportSPITProject.setProjectName(m_ProjName); + sMReportSPITProject.setFramesPerSecond(0); + if (sendSPITMessage(sMReportSPITProject) < 0) { + ESP_LOGD(TAG, "SPIT_Client::parseReportSPITProject could not send Client's ReportSPITProject"); + } +} +void SPIT_Client::parseCloseSPITProject(SPIT_Message::CloseSPITProject *p_CloseSPITProject) { + // printf("parse CloseSPITProject \n"); + if (p_CloseSPITProject == NULL) + return; + string stringProjectID; + mCallbacks.onProjectUpdate(ProjUpdate::ServerClosed, p_CloseSPITProject->getProjectID()); +} string SPIT_Client::getServerProjectID() { return m_ServerProjectID; } string SPIT_Client::getServerProjectName() { return m_ServerProjectName; } int SPIT_Client::getServerFramesPerSecond() { return m_ServerFramesPerSecond; } -void SPIT_Client::parseRequestProjectTransfer(SPIT_Message::RequestProjectTransfer* p_RequestProjectTransfer) { -// printf("parse RequestProjectTransfer \n"); - //StartProjectTransfer - SPIT_Message::StartProjectTransfer sMStartProjectTransfer; - fillHeader(sMStartProjectTransfer.getHeader()); - int intResult = sendSPITMessage(sMStartProjectTransfer); - if (intResult < 0) { - return; - } - - { - //send all listes SPITTypes - int intCount = SPITType::getSPITTypeCount(); - for (int i = 0; i < intCount; i++) { - SPITType* ptrSPITType = SPITType::getSPITType(i); - if (ptrSPITType == NULL) break; - sendSPITTypeInternal(ptrSPITType); - fos::Task::delayMs(10); - } - } - - { - int intCount = SPITObject::getSPITObjectCount(); - for (int i = 0; i < intCount; i++) { - SPITObject* ptrSPITObject = SPITObject::getSPITObject(i); - if (ptrSPITObject == NULL) break; - sendSPITObjectInternal(ptrSPITObject); - fos::Task::delayMs(10); - } - } +void SPIT_Client::parseRequestProjectTransfer(SPIT_Message::RequestProjectTransfer *p_RequestProjectTransfer) { + // printf("parse RequestProjectTransfer \n"); + // StartProjectTransfer + SPIT_Message::StartProjectTransfer sMStartProjectTransfer; + fillHeader(sMStartProjectTransfer.getHeader()); + int intResult = sendSPITMessage(sMStartProjectTransfer); + if (intResult < 0) { + return; + } - //EndProjectTransfer - SPIT_Message::EndProjectTransfer sMEndProjectTransfer; - fillHeader(sMEndProjectTransfer.getHeader()); - intResult = sendSPITMessage(sMEndProjectTransfer); - if (intResult < 0) { - } + { + // send all listes SPITTypes + int intCount = SPITType::getSPITTypeCount(); + for (int i = 0; i < intCount; i++) { + SPITType *ptrSPITType = SPITType::getSPITType(i); + if (ptrSPITType == NULL) + break; + sendSPITTypeInternal(ptrSPITType); + fos::Task::delayMs(10); + } + } + + { + int intCount = SPITObject::getSPITObjectCount(); + for (int i = 0; i < intCount; i++) { + SPITObject *ptrSPITObject = SPITObject::getSPITObject(i); + if (ptrSPITObject == NULL) + break; + sendSPITObjectInternal(ptrSPITObject); + fos::Task::delayMs(10); + } + } + + // EndProjectTransfer + SPIT_Message::EndProjectTransfer sMEndProjectTransfer; + fillHeader(sMEndProjectTransfer.getHeader()); + intResult = sendSPITMessage(sMEndProjectTransfer); + if (intResult < 0) { + } } - -/* NEW IMPLEMENTATION +/* NEW IMPLEMENTATION void SPIT_Client::parseRequestProjectTransfer(SPIT_Message::RequestProjectTransfer* p_RequestProjectTransfer) { // printf("parse RequestProjectTransfer \n"); - thread* o_ThreadSend; - o_ThreadSend = new thread(&this->sendProject, this); - // int intResult; - // SPIT_Message::StartProjectTransfer* ptrSMStartProjectTransfer; - // SPIT_Message::EndProjectTransfer* ptrSMEndProjectTransfer; - // int intCount; - // SPITType* ptrSPITType; - // SPITObject* ptrSPITObject; - - - // //StartProjectTransfer - // NotifyStartProjectTransfer_Client* o_RunnableStart = new NotifyStartProjectTransfer_Client(m_SPITClientInterface); - // SPIT_Handler::addRunnable(o_RunnableStart); + thread* o_ThreadSend; + o_ThreadSend = new thread(&this->sendProject, this); + // int intResult; + // SPIT_Message::StartProjectTransfer* ptrSMStartProjectTransfer; + // SPIT_Message::EndProjectTransfer* ptrSMEndProjectTransfer; + // int intCount; + // SPITType* ptrSPITType; + // SPITObject* ptrSPITObject; - // ptrSMStartProjectTransfer = new SPIT_Message::StartProjectTransfer(); - // intResult = sendSPITMessage(ptrSMStartProjectTransfer); - // if (intResult < 0) { - // return; - // } - // m_Watchdog->answerWatchdog(); - // { - // //send all listes SPITTypes - // unique_lock o_LockType(*SPITType::getMutex()); - // intCount = SPITType::getSPITTypeCount(); - // for (int i = 0; i < intCount; i++) { - // ptrSPITType = SPITType::getSPITType(i); - // if (ptrSPITType == NULL) continue; - // intResult = sendSPITTypeInternal(ptrSPITType); - // if (intResult < 0) return; - // m_Watchdog->answerWatchdog(); - // this_thread::sleep_for(chrono::milliseconds(7)); - // } - // } - - // { - // unique_lock o_LockObject(*SPITObject::getMutex()); - // intCount = SPITObject::getSPITObjectCount(); - // for (int i = 0; i < intCount; i++) { - // ptrSPITObject = SPITObject::getSPITObject(i); - // if (ptrSPITObject == NULL) continue; - // intResult = sendSPITObjectInternal(ptrSPITObject); - // if (intResult < 0) return; - // m_Watchdog->answerWatchdog(); - // this_thread::sleep_for(chrono::milliseconds(7)); - // } - // } - // //EndProjectTransfer - // ptrSMEndProjectTransfer = new SPIT_Message::EndProjectTransfer(); - // intResult = sendSPITMessage(ptrSMEndProjectTransfer); - // if (intResult < 0) { - // return; - // } - // m_Watchdog->answerWatchdog(); - // NotifyEndProjectTransfer_Client* o_RunnableEnd = new NotifyEndProjectTransfer_Client(m_SPITClientInterface); - // SPIT_Handler::addRunnable(o_RunnableEnd); - - // //Send act + // //StartProjectTransfer + // NotifyStartProjectTransfer_Client* o_RunnableStart = new NotifyStartProjectTransfer_Client(m_SPITClientInterface); + // SPIT_Handler::addRunnable(o_RunnableStart); + + // ptrSMStartProjectTransfer = new SPIT_Message::StartProjectTransfer(); + // intResult = sendSPITMessage(ptrSMStartProjectTransfer); + // if (intResult < 0) { + // return; + // } + // m_Watchdog->answerWatchdog(); + // { + // //send all listes SPITTypes + // unique_lock o_LockType(*SPITType::getMutex()); + // intCount = SPITType::getSPITTypeCount(); + // for (int i = 0; i < intCount; i++) { + // ptrSPITType = SPITType::getSPITType(i); + // if (ptrSPITType == NULL) continue; + // intResult = sendSPITTypeInternal(ptrSPITType); + // if (intResult < 0) return; + // m_Watchdog->answerWatchdog(); + // this_thread::sleep_for(chrono::milliseconds(7)); + // } + // } + + // { + // unique_lock o_LockObject(*SPITObject::getMutex()); + // intCount = SPITObject::getSPITObjectCount(); + // for (int i = 0; i < intCount; i++) { + // ptrSPITObject = SPITObject::getSPITObject(i); + // if (ptrSPITObject == NULL) continue; + // intResult = sendSPITObjectInternal(ptrSPITObject); + // if (intResult < 0) return; + // m_Watchdog->answerWatchdog(); + // this_thread::sleep_for(chrono::milliseconds(7)); + // } + // } + + // //EndProjectTransfer + // ptrSMEndProjectTransfer = new SPIT_Message::EndProjectTransfer(); + // intResult = sendSPITMessage(ptrSMEndProjectTransfer); + // if (intResult < 0) { + // return; + // } + // m_Watchdog->answerWatchdog(); + // NotifyEndProjectTransfer_Client* o_RunnableEnd = new NotifyEndProjectTransfer_Client(m_SPITClientInterface); + // SPIT_Handler::addRunnable(o_RunnableEnd); + + // //Send act } */ -void SPIT_Client::sendProject(SPIT_Client* p_PtrSPIT_Client) { -// int intResult; -// SPIT_Message::StartProjectTransfer* ptrSMStartProjectTransfer; -// SPIT_Message::EndProjectTransfer* ptrSMEndProjectTransfer; -// int intCount; -// SPITType* ptrSPITType; -// SPITObject* ptrSPITObject; - -// //StartProjectTransfer -// NotifyStartProjectTransfer_Client* o_RunnableStart = new NotifyStartProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface()); -// SPIT_Handler::addRunnable(o_RunnableStart); +void SPIT_Client::sendProject(SPIT_Client *p_PtrSPIT_Client) { + // int intResult; + // SPIT_Message::StartProjectTransfer* ptrSMStartProjectTransfer; + // SPIT_Message::EndProjectTransfer* ptrSMEndProjectTransfer; + // int intCount; + // SPITType* ptrSPITType; + // SPITObject* ptrSPITObject; -// ptrSMStartProjectTransfer = new SPIT_Message::StartProjectTransfer(); -// intResult = p_PtrSPIT_Client->sendSPITMessage(ptrSMStartProjectTransfer); -// if (intResult < 0) { -// return; -// } + // //StartProjectTransfer + // NotifyStartProjectTransfer_Client* o_RunnableStart = new NotifyStartProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface()); + // SPIT_Handler::addRunnable(o_RunnableStart); -// // m_Watchdog->answerWatchdog(); -// // { -// //send all listes SPITTypes -// // unique_lock o_LockType(*SPITType::getMutex()); -// intCount = SPITType::getSPITTypeCount(); -// for (int i = 0; i < intCount; i++) { -// ptrSPITType = SPITType::getSPITType(i); -// if (ptrSPITType == NULL) continue; -// if (ptrSPITType->getCreatedByClient() == false) continue; -// intResult = p_PtrSPIT_Client->sendSPITTypeInternal(ptrSPITType); -// if (intResult < 0) return; -// // m_Watchdog->answerWatchdog(); -// this_thread::sleep_for(chrono::milliseconds(7)); -// } -// // } - -// // { -// // unique_lock o_LockObject(*SPITObject::getMutex()); -// intCount = SPITObject::getSPITObjectCount(); -// for (int i = 0; i < intCount; i++) { -// ptrSPITObject = SPITObject::getSPITObject(i); -// if (ptrSPITObject == NULL) continue; -// if (ptrSPITObject->getCreatedByClient() == false) continue; -// intResult = p_PtrSPIT_Client->sendSPITObjectInternal(ptrSPITObject); -// if (intResult < 0) return; -// // m_Watchdog->answerWatchdog(); -// this_thread::sleep_for(chrono::milliseconds(7)); -// } -// // } + // ptrSMStartProjectTransfer = new SPIT_Message::StartProjectTransfer(); + // intResult = p_PtrSPIT_Client->sendSPITMessage(ptrSMStartProjectTransfer); + // if (intResult < 0) { + // return; + // } -// //EndProjectTransfer -// ptrSMEndProjectTransfer = new SPIT_Message::EndProjectTransfer(); -// intResult = p_PtrSPIT_Client->sendSPITMessage(ptrSMEndProjectTransfer); -// if (intResult < 0) { -// return; -// } -// // m_Watchdog->answerWatchdog(); -// NotifyEndProjectTransfer_Client* o_RunnableEnd = new NotifyEndProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface()); -// SPIT_Handler::addRunnable(o_RunnableEnd); - -// //Send act + // // m_Watchdog->answerWatchdog(); + // // { + // //send all listes SPITTypes + // // unique_lock o_LockType(*SPITType::getMutex()); + // intCount = SPITType::getSPITTypeCount(); + // for (int i = 0; i < intCount; i++) { + // ptrSPITType = SPITType::getSPITType(i); + // if (ptrSPITType == NULL) continue; + // if (ptrSPITType->getCreatedByClient() == false) continue; + // intResult = p_PtrSPIT_Client->sendSPITTypeInternal(ptrSPITType); + // if (intResult < 0) return; + // // m_Watchdog->answerWatchdog(); + // this_thread::sleep_for(chrono::milliseconds(7)); + // } + // // } + + // // { + // // unique_lock o_LockObject(*SPITObject::getMutex()); + // intCount = SPITObject::getSPITObjectCount(); + // for (int i = 0; i < intCount; i++) { + // ptrSPITObject = SPITObject::getSPITObject(i); + // if (ptrSPITObject == NULL) continue; + // if (ptrSPITObject->getCreatedByClient() == false) continue; + // intResult = p_PtrSPIT_Client->sendSPITObjectInternal(ptrSPITObject); + // if (intResult < 0) return; + // // m_Watchdog->answerWatchdog(); + // this_thread::sleep_for(chrono::milliseconds(7)); + // } + // // } + + // //EndProjectTransfer + // ptrSMEndProjectTransfer = new SPIT_Message::EndProjectTransfer(); + // intResult = p_PtrSPIT_Client->sendSPITMessage(ptrSMEndProjectTransfer); + // if (intResult < 0) { + // return; + // } + // // m_Watchdog->answerWatchdog(); + // NotifyEndProjectTransfer_Client* o_RunnableEnd = new NotifyEndProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface()); + // SPIT_Handler::addRunnable(o_RunnableEnd); + + // //Send act } - -void SPIT_Client::parseStartProjectTransfer(SPIT_Message::StartProjectTransfer* p_StartProjectTransfer) { - mCallbacks.onStartProjectTransfer(); +void SPIT_Client::parseStartProjectTransfer(SPIT_Message::StartProjectTransfer *p_StartProjectTransfer) { + mCallbacks.onProjectUpdate(ProjUpdate::StartTransfer, m_ServerProjectID); } -void SPIT_Client::parseEndProjectTransfer(SPIT_Message::EndProjectTransfer* p_EndProjectTransfer) { - SPITObject::clearUnconfirmedSPITObjects(); - mCallbacks.onEndProjectTransfer(); +void SPIT_Client::parseEndProjectTransfer(SPIT_Message::EndProjectTransfer *p_EndProjectTransfer) { + SPITObject::clearUnconfirmedSPITObjects(); + mCallbacks.onProjectUpdate(ProjUpdate::EndTransfer, m_ServerProjectID); - //Send SPIT_Message::ReportSPITProject after the m_SPITClientInterface is notfied of EndProjectTransfer - SPIT_Message::ReportSPITProject ptrSMReportSPITProject; - ptrSMReportSPITProject.setProjectID(m_ProjName); - ptrSMReportSPITProject.setProjectName(m_ProjName); - ptrSMReportSPITProject.setFramesPerSecond(0); - if (sendSPITMessage(ptrSMReportSPITProject) < 0) { - printf("SPIT_Client::parseReportSPITProject could not send Client's ReportSPITProject"); - } + // Send SPIT_Message::ReportSPITProject after the m_SPITClientInterface is notfied of EndProjectTransfer + SPIT_Message::ReportSPITProject ptrSMReportSPITProject; + ptrSMReportSPITProject.setProjectID(m_ProjName); + ptrSMReportSPITProject.setProjectName(m_ProjName); + ptrSMReportSPITProject.setFramesPerSecond(0); + if (sendSPITMessage(ptrSMReportSPITProject) < 0) { + ESP_LOGD(TAG, "SPIT_Client::parseReportSPITProject could not send Client's ReportSPITProject"); + } } //----- SPIT Types ------ -void SPIT_Client::parseReportSPITType(SPIT_Message::ReportSPITType* p_ReportSPITType) { -// printf("parse ReportSPITType ID %s Name %s \n",p_ReportSPITType->getID(), p_ReportSPITType->getName()); - if (p_ReportSPITType == NULL) return; - SPITType* ptrSPITType; - bool boolNew = false; - bool boolChanged = false; - { - if (p_ReportSPITType->getServerRemote() == false) { - ptrSPITType = SPITType::getSPITType(p_ReportSPITType->getID()); - if (ptrSPITType == NULL) { - //The user's app my veto the SPITType - if (mCallbacks.onCheckSpitTypeVeto(p_ReportSPITType) == false) { - return; - } - ptrSPITType = new SPITType(); - boolNew = true; - } - } - else { - ptrSPITType = SPITType::getSPITTypeRemote(p_ReportSPITType->getID()); - if (ptrSPITType == NULL) { - ptrSPITType = new SPITType(); - boolNew = true; - } - } - try { - boolChanged = ptrSPITType->setMessageOP(p_ReportSPITType); - } - catch (...) { - //SPITType is not changable -> send back to the server - sendSPITTypeInternal(ptrSPITType); - return; - } - - //add or change SPITType - if (ptrSPITType->getServerRemote() == false) { - SPITType::addSPITType(ptrSPITType); - mCallbacks.onSpitType(boolNew, *ptrSPITType); - } - else { - SPITType::addSPITTypeRemote(ptrSPITType); - mCallbacks.onSpitTypeRemote(boolNew, *ptrSPITType); - } - - if (ptrSPITType != NULL) { - if (ptrSPITType->setConfirmed(true) == true || boolChanged == true) { - sendSPITTypeInternal(ptrSPITType); - } - } - } -} -void SPIT_Client::parseRemoveSPITType(SPIT_Message::RemoveSPITType* p_RemoveSPITType) { -// printf("parse RemoveSPITType %s\n", p_RemoveSPITType->getID()); - if (p_RemoveSPITType == NULL) return; - string stringSPITTypeID; - bool boolRemote = false; - SPITType* ptrSPITType; - stringSPITTypeID = p_RemoveSPITType->getID(); - - { - ptrSPITType = SPITType::getSPITTypeRemote(stringSPITTypeID); - if (ptrSPITType != NULL) { - boolRemote = true; - } - else { - ptrSPITType = SPITType::getSPITType(stringSPITTypeID); - if (ptrSPITType != NULL) { - boolRemote = false; - } - else { - //No SPITType with stringSPITTypeID is listet - return; - } - } - - if (ptrSPITType->getCreatedByClient() && ptrSPITType->getFixed()) { - //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; - } +void SPIT_Client::parseReportSPITType(SPIT_Message::ReportSPITType *p_ReportSPITType) { + // printf("parse ReportSPITType ID %s Name %s \n",p_ReportSPITType->getID(), p_ReportSPITType->getName()); + if (p_ReportSPITType == NULL) + return; + SPITType *ptrSPITType; + bool boolNew = false; + bool boolChanged = false; + { + if (p_ReportSPITType->getServerRemote() == false) { + ptrSPITType = SPITType::getSPITType(p_ReportSPITType->getID()); + if (ptrSPITType == NULL) { + // The user's app my veto the SPITType + if (mCallbacks.onCheckSpitTypeVeto(p_ReportSPITType) == false) { + return; + } + ptrSPITType = new SPITType(); + boolNew = true; + } + } else { + ptrSPITType = SPITType::getSPITTypeRemote(p_ReportSPITType->getID()); + if (ptrSPITType == NULL) { + ptrSPITType = new SPITType(); + boolNew = true; + } + } + try { + boolChanged = ptrSPITType->setMessageOP(p_ReportSPITType); + } catch (...) { + // SPITType is not changable -> send back to the server + sendSPITTypeInternal(ptrSPITType); + return; + } - if (boolRemote == false) { - mCallbacks.onSpitTypeRemoved(*ptrSPITType); - SPITType::removeSPITType(ptrSPITType); - } - else { - mCallbacks.onSpitTypeRemoteRemoved(*ptrSPITType); - SPITType::removeSPITTypeRemote(ptrSPITType); - } - delete ptrSPITType; - } -} + auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed; + // add or change SPITType + if (ptrSPITType->getServerRemote() == false) { + SPITType::addSPITType(ptrSPITType); + mCallbacks.onSpitType(eventType, *ptrSPITType); + } else { + SPITType::addSPITTypeRemote(ptrSPITType); + mCallbacks.onSpitTypeRemote(eventType, *ptrSPITType); + } + if (ptrSPITType != NULL) { + if (ptrSPITType->setConfirmed(true) == true || boolChanged == true) { + sendSPITTypeInternal(ptrSPITType); + } + } + } +} +void SPIT_Client::parseRemoveSPITType(SPIT_Message::RemoveSPITType *p_RemoveSPITType) { + // printf("parse RemoveSPITType %s\n", p_RemoveSPITType->getID()); + if (p_RemoveSPITType == NULL) + return; + string stringSPITTypeID; + bool boolRemote = false; + SPITType *ptrSPITType; + stringSPITTypeID = p_RemoveSPITType->getID(); + + { + ptrSPITType = SPITType::getSPITTypeRemote(stringSPITTypeID); + if (ptrSPITType != NULL) { + boolRemote = true; + } else { + ptrSPITType = SPITType::getSPITType(stringSPITTypeID); + if (ptrSPITType != NULL) { + boolRemote = false; + } else { + // No SPITType with stringSPITTypeID is listet + return; + } + } + + if (ptrSPITType->getCreatedByClient() && ptrSPITType->getFixed()) { + // 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; + } + + if (boolRemote == false) { + mCallbacks.onSpitType(ObjectEvent::Deleted, *ptrSPITType); + SPITType::removeSPITType(ptrSPITType); + } else { + mCallbacks.onSpitTypeRemote(ObjectEvent::Deleted, *ptrSPITType); + SPITType::removeSPITTypeRemote(ptrSPITType); + } + delete 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 + * @param p_SPITType the pointer to the changed SPITType * @return 0 = is sended, -1 = is not sended */ -int SPIT_Client::sendSPITTypeInternal(SPITType* p_SPITType) { - if (p_SPITType == NULL) return -1; - SPIT_Message::ReportSPITType ptrSMReportSPITType; - p_SPITType->fillMessageOP(&ptrSMReportSPITType); - return sendSPITMessage(ptrSMReportSPITType); +int SPIT_Client::sendSPITTypeInternal(SPITType *p_SPITType) { + if (p_SPITType == NULL) + return -1; + SPIT_Message::ReportSPITType ptrSMReportSPITType; + p_SPITType->fillMessageOP(&ptrSMReportSPITType); + return sendSPITMessage(ptrSMReportSPITType); } /** @@ -1090,255 +1050,256 @@ int SPIT_Client::sendSPITTypeInternal(SPITType* p_SPITType) { * @param p_SPITType the SPITType vont * @return true = changed, false = not changed maybe p_SPITType is NULL or the SPITType doesn't exists */ -bool SPIT_Client::changeSPITType(SPITType* p_SPITType) { - if (p_SPITType == NULL) return false; - SPITType* ptrSPITType; - { - ptrSPITType = SPITType::getSPITType(p_SPITType->getID()); - if (ptrSPITType == NULL) return false; - - ptrSPITType->setDefaultDelay(p_SPITType->getDefaultDelay()); - ptrSPITType->setDefaultDuration(p_SPITType->getDefaultDuration()); - ptrSPITType->setFixed(p_SPITType->getFixed()); - ptrSPITType->setGroupName(p_SPITType->getGroupName()); - ptrSPITType->setName(p_SPITType->getName()); - ptrSPITType->setProjectIndepended(p_SPITType->getProjectIndepended()); - - mCallbacks.onSpitType(false, *ptrSPITType); - sendSPITTypeInternal(ptrSPITType); - } - return true; +bool SPIT_Client::changeSPITType(SPITType *p_SPITType) { + if (p_SPITType == NULL) + return false; + SPITType *ptrSPITType; + { + ptrSPITType = SPITType::getSPITType(p_SPITType->getID()); + if (ptrSPITType == NULL) + return false; + + ptrSPITType->setDefaultDelay(p_SPITType->getDefaultDelay()); + ptrSPITType->setDefaultDuration(p_SPITType->getDefaultDuration()); + ptrSPITType->setFixed(p_SPITType->getFixed()); + ptrSPITType->setGroupName(p_SPITType->getGroupName()); + ptrSPITType->setName(p_SPITType->getName()); + ptrSPITType->setProjectIndepended(p_SPITType->getProjectIndepended()); + + mCallbacks.onSpitType(ObjectEvent::Changed, *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 + * -> 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 SPIT_Client::removeSPITType(string p_SPITTypeID) { - if (p_SPITTypeID.length() <= 0) return -1; - SPITType* ptrSPITType; - { - ptrSPITType = SPITType::getSPITType(p_SPITTypeID); - if (ptrSPITType == NULL) return -1; - SPIT_Message::RemoveSPITType sMRemoveSPITType; - ptrSPITType->fillMessageOP(&sMRemoveSPITType); - mCallbacks.onSpitTypeRemoved(*ptrSPITType); - SPITType::removeSPITType(ptrSPITType); - delete ptrSPITType; - return sendSPITMessage(sMRemoveSPITType); - } - return -1; + if (p_SPITTypeID.length() <= 0) + return -1; + SPITType *ptrSPITType; + { + ptrSPITType = SPITType::getSPITType(p_SPITTypeID); + if (ptrSPITType == NULL) + return -1; + SPIT_Message::RemoveSPITType sMRemoveSPITType; + ptrSPITType->fillMessageOP(&sMRemoveSPITType); + mCallbacks.onSpitType(ObjectEvent::Deleted, *ptrSPITType); + SPITType::removeSPITType(ptrSPITType); + delete ptrSPITType; + return sendSPITMessage(sMRemoveSPITType); + } + return -1; } - -SPITType* SPIT_Client::createSPITTypeFixed(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration) { - return createSPITType(p_ID, p_GroupName, p_Name, p_DefaultDelay, p_DefaultDuration, true, true); +SPITType *SPIT_Client::createSPITTypeFixed(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration) { + return createSPITType(p_ID, p_GroupName, p_Name, p_DefaultDelay, p_DefaultDuration, true, true); } -SPITType* SPIT_Client::createSPITType(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration, bool p_FIxed, bool p_ProjectIndepended) { - SPITType* ptrSPITType; - bool boolNew; - { - ptrSPITType = SPITType::getSPITType(p_ID); - if (ptrSPITType == NULL) { - ptrSPITType = new SPITType(p_ID, p_GroupName, p_Name, p_FIxed, p_ProjectIndepended, p_DefaultDelay, p_DefaultDuration); - ptrSPITType->setCreatedByClient(true); - boolNew = true; - } - else { - ptrSPITType->setID(p_ID); - ptrSPITType->setGroupName(p_GroupName); - ptrSPITType->setName(p_Name); - ptrSPITType->setFixed(p_FIxed); - ptrSPITType->setProjectIndepended(p_ProjectIndepended); - ptrSPITType->setDefaultDelay(p_DefaultDelay); - ptrSPITType->setDefaultDuration(p_DefaultDuration); - boolNew = false; - } - } - SPITType::addSPITType(ptrSPITType); - mCallbacks.onSpitType(boolNew, *ptrSPITType); - sendSPITTypeInternal(ptrSPITType); - return ptrSPITType; +SPITType *SPIT_Client::createSPITType(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration, bool p_FIxed, bool p_ProjectIndepended) { + SPITType *ptrSPITType; + bool boolNew; + { + ptrSPITType = SPITType::getSPITType(p_ID); + if (ptrSPITType == NULL) { + ptrSPITType = new SPITType(p_ID, p_GroupName, p_Name, p_FIxed, p_ProjectIndepended, p_DefaultDelay, p_DefaultDuration); + ptrSPITType->setCreatedByClient(true); + boolNew = true; + } else { + ptrSPITType->setID(p_ID); + ptrSPITType->setGroupName(p_GroupName); + ptrSPITType->setName(p_Name); + ptrSPITType->setFixed(p_FIxed); + ptrSPITType->setProjectIndepended(p_ProjectIndepended); + ptrSPITType->setDefaultDelay(p_DefaultDelay); + ptrSPITType->setDefaultDuration(p_DefaultDuration); + boolNew = false; + } + } + + auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed; + SPITType::addSPITType(ptrSPITType); + mCallbacks.onSpitType(eventType, *ptrSPITType); + sendSPITTypeInternal(ptrSPITType); + return ptrSPITType; } //----- SPIT Objects ------ -void SPIT_Client::parseReportSPITObject(SPIT_Message::ReportSPITObject* p_ReportSPITObject) { - -//printf("parse ReportSPITObject %s\n", p_ReportSPITObject->getID()); - if (p_ReportSPITObject == NULL) return; - SPITObject* ptrSPITObject; - SPITType* ptrSPITType; - bool boolNew = false; - bool boolRemote = false; - bool boolChanged = false; - { - if (p_ReportSPITObject->getServerRemote() == false) { - boolRemote = false; - ptrSPITObject = SPITObject::getSPITObject(p_ReportSPITObject->getID()); - ptrSPITType = SPITType::getSPITType(p_ReportSPITObject->getSPITTypeID()); - +void SPIT_Client::parseReportSPITObject(SPIT_Message::ReportSPITObject *p_ReportSPITObject) { + ESP_LOGD(TAG, "parse ReportSPITObject %s\n", p_ReportSPITObject->getID().c_str()); + if (p_ReportSPITObject == NULL) + return; + SPITObject *ptrSPITObject; + SPITType *ptrSPITType; + bool boolNew = false; + bool boolRemote = false; + bool boolChanged = false; + { + if (p_ReportSPITObject->getServerRemote() == false) { + boolRemote = false; + ptrSPITObject = SPITObject::getSPITObject(p_ReportSPITObject->getID()); + ptrSPITType = SPITType::getSPITType(p_ReportSPITObject->getSPITTypeID()); - if (ptrSPITType == NULL) { - //No associated SPITType found - if (ptrSPITObject != NULL) { - //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 - SPITObject::removeSPITObject(ptrSPITObject); - delete ptrSPITObject; - } - return; - } - if (ptrSPITObject == NULL) { - //The user's app my veto the SPITType - if (mCallbacks.onCheckSpitObjectVeto(p_ReportSPITObject) == false) { - return; - } - - ptrSPITObject = new SPITObject(); - boolNew = true; - } - else { - //The user's app my veto the SPITType - if (mCallbacks.onCheckSpitObjectVeto(p_ReportSPITObject) == false) { - //SpitObject exists and User APp denied the SPITObject -> remove the SPITObject without sending a message - SPITObject::removeSPITObject(ptrSPITObject); - delete ptrSPITObject; - return; - } - } - } - else { - boolRemote = true; - ptrSPITObject = SPITObject::getSPITObjectRemote(p_ReportSPITObject->getID()); - ptrSPITType = SPITType::getSPITTypeRemote(p_ReportSPITObject->getSPITTypeID()); - if (ptrSPITType == NULL) { - //No associated SPITType found - return; - } - if (ptrSPITObject == NULL) { - ptrSPITObject = new SPITObject(); - boolNew = true; - } - } - - try { - boolChanged = ptrSPITObject->setMessageOP(p_ReportSPITObject); - } - catch (...) { - //setMessageOP error - the SPITObject can't be changed, it may be fixed and crated by this client - sendSPITObjectInternal(ptrSPITObject); - return; - } + if (ptrSPITType == NULL) { + // No associated SPITType found + if (ptrSPITObject != NULL) { + // 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 + SPITObject::removeSPITObject(ptrSPITObject); + delete ptrSPITObject; + } + return; + } + if (ptrSPITObject == NULL) { + // The user's app my veto the SPITType + if (mCallbacks.onCheckSpitObjectVeto(p_ReportSPITObject) == false) { + ESP_LOGD(TAG, "ObjectVeto %s / %s", p_ReportSPITObject->getID().c_str(), p_ReportSPITObject->getName().c_str()); + return; + } + ptrSPITObject = new SPITObject(); + boolNew = true; + } else { + // The user's app my veto the SPITType + if (mCallbacks.onCheckSpitObjectVeto(p_ReportSPITObject) == false) { + // SpitObject exists and User APp denied the SPITObject -> remove the SPITObject without sending a message + SPITObject::removeSPITObject(ptrSPITObject); + ESP_LOGD(TAG, "TypeVeto %s / %s", p_ReportSPITObject->getID().c_str(), p_ReportSPITObject->getName().c_str()); + delete ptrSPITObject; + return; + } + } + } else { + boolRemote = true; + ptrSPITObject = SPITObject::getSPITObjectRemote(p_ReportSPITObject->getID()); + ptrSPITType = SPITType::getSPITTypeRemote(p_ReportSPITObject->getSPITTypeID()); + if (ptrSPITType == NULL) { + // No associated SPITType found + return; + } + if (ptrSPITObject == NULL) { + ptrSPITObject = new SPITObject(); + boolNew = true; + } + } - if (boolRemote == false) { - //set the virtual action assignment - ptrSPITObject->setActionAssignedType(ptrSPITType->getActionAssigned()); - SPITObject::addSPITObject(ptrSPITObject); - } - else { - SPITObject::addSPITObjectRemote(ptrSPITObject); - } - - if (boolRemote) { - mCallbacks.onSpitObjectRemote(boolNew, *ptrSPITType, *ptrSPITObject); - } - else { - mCallbacks.onSpitObject(boolNew, *ptrSPITType, *ptrSPITObject); - } + try { + boolChanged = ptrSPITObject->setMessageOP(p_ReportSPITObject); + } catch (...) { + // setMessageOP error - the SPITObject can't be changed, it may be fixed and crated by this client + sendSPITObjectInternal(ptrSPITObject); + return; + } - if (ptrSPITObject->setConfirmed(true) == true || boolChanged == true) { - //Confirmation has changed - sendSPITObjectInternal(ptrSPITObject); - } - - } + if (boolRemote == false) { + // set the virtual action assignment + ptrSPITObject->setActionAssignedType(ptrSPITType->getActionAssigned()); + SPITObject::addSPITObject(ptrSPITObject); + } else { + SPITObject::addSPITObjectRemote(ptrSPITObject); + } + + auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed; + if (boolRemote) { + mCallbacks.onSpitObjectRemote(eventType, *ptrSPITType, *ptrSPITObject); + } else { + mCallbacks.onSpitObject(eventType, *ptrSPITType, *ptrSPITObject); + } + + if (ptrSPITObject->setConfirmed(true) == true || boolChanged == true) { + // Confirmation has changed + sendSPITObjectInternal(ptrSPITObject); + } + } } -void SPIT_Client::parseRemoveSPITObject(SPIT_Message::RemoveSPITObject* p_RemoveSPITObject) { -//printf("parse RemoveSPITObject %s\n", p_RemoveSPITObject->getID()); - if (p_RemoveSPITObject == NULL) return; - bool boolRemote = false; - SPITObject* ptrSPITObject; - SPITType* ptrSPITType; - - { - ptrSPITObject = SPITObject::getSPITObjectRemote(p_RemoveSPITObject->getID()); - if (ptrSPITObject != NULL) { - boolRemote = true; - ptrSPITType = SPITType::getSPITTypeRemote(ptrSPITObject->getSPITTypeID()); - if (ptrSPITType != NULL) { - if (boolRemote) { - mCallbacks.onSpitObjectRemoteRemoved(*ptrSPITType, *ptrSPITObject); - } - else { - mCallbacks.onSpitObjectRemoved(*ptrSPITType, *ptrSPITObject); - } - } - else { - //No associated SPITType found - //delete the SPITObject without a notification - } - SPITObject::removeSPITObjectRemote(ptrSPITObject); - delete ptrSPITObject; - } - else { - //call removeSPITObject, this will notify the server that the object is removed - removeSPITObject(p_RemoveSPITObject->getID()); - } +void SPIT_Client::parseRemoveSPITObject(SPIT_Message::RemoveSPITObject *p_RemoveSPITObject) { + // printf("parse RemoveSPITObject %s\n", p_RemoveSPITObject->getID()); + if (p_RemoveSPITObject == NULL) + return; + bool boolRemote = false; + SPITObject *ptrSPITObject; + SPITType *ptrSPITType; - } + { + ptrSPITObject = SPITObject::getSPITObjectRemote(p_RemoveSPITObject->getID()); + if (ptrSPITObject != NULL) { + boolRemote = true; + ptrSPITType = SPITType::getSPITTypeRemote(ptrSPITObject->getSPITTypeID()); + if (ptrSPITType != NULL) { + if (boolRemote) { + mCallbacks.onSpitObjectRemote(ObjectEvent::Deleted, *ptrSPITType, *ptrSPITObject); + } else { + mCallbacks.onSpitObject(ObjectEvent::Deleted, *ptrSPITType, *ptrSPITObject); + } + } else { + // No associated SPITType found + // delete the SPITObject without a notification + } + SPITObject::removeSPITObjectRemote(ptrSPITObject); + delete ptrSPITObject; + } else { + // call removeSPITObject, this will notify the server that the object is removed + removeSPITObject(p_RemoveSPITObject->getID()); + } + } } -int SPIT_Client::sendSPITObjectInternal(SPITObject* ptrSPITObject) { - if (ptrSPITObject == NULL) return -1; - SPIT_Message::ReportSPITObject ptrSMReportSPITObject; - ptrSPITObject->fillMessageOP(&ptrSMReportSPITObject); +int SPIT_Client::sendSPITObjectInternal(SPITObject *ptrSPITObject) { + if (ptrSPITObject == NULL) + return -1; + SPIT_Message::ReportSPITObject ptrSMReportSPITObject; + ptrSPITObject->fillMessageOP(&ptrSMReportSPITObject); - return sendSPITMessage(ptrSMReportSPITObject); + return sendSPITMessage(ptrSMReportSPITObject); } /** * 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 p_SPITObject the pointer to the changed SPITObject.
- * CAUTION: The SPITObject must already exist. + * CAUTION: The SPITObject must already exist. * @return true = SPITObject is changed, false = not changed, maybe p_SPITObject is NULL or the SPITObject doesn't exists */ -bool SPIT_Client::changeSPITObject(SPITObject* p_SPITObject) { - if (p_SPITObject == NULL) return false; - SPITObject* ptrSPITObject; - SPITType* ptrSPITType; - { - ptrSPITObject = SPITObject::getSPITObject(p_SPITObject->getID()); - if (ptrSPITObject == NULL) return false; - ptrSPITType = SPITType::getSPITType(p_SPITObject->getID()); - if(ptrSPITObject == NULL) return false; - - ptrSPITObject->setActionAssigned(p_SPITObject->getActionAssigned());; - ptrSPITObject->setDelay(p_SPITObject->getDelay()); - ptrSPITObject->setDuration(p_SPITObject->getDelay()); - ptrSPITObject->setFixed(p_SPITObject->getFixed()); - ptrSPITObject->setFrameFadeInLength(p_SPITObject->getFrameFadeInLength()); - ptrSPITObject->setFrameFadeOutLength(p_SPITObject->getFrameFadeOutLength()); - ptrSPITObject->setFrameLength(p_SPITObject->getFrameLength()); - ptrSPITObject->setFrameStart(p_SPITObject->getFrameStart()); - ptrSPITObject->setName(p_SPITObject->getName()); - ptrSPITObject->setRemark(p_SPITObject->getRemark()); - ptrSPITObject->setSPITTypeID(p_SPITObject->getSPITTypeID()); - ptrSPITObject->setServerParams(p_SPITObject->getServerParams()); - ptrSPITObject->setTrack(p_SPITObject->getTrack()); - ptrSPITObject->setValueFactor(p_SPITObject->getValueFactor()); - ptrSPITObject->setValueUse(p_SPITObject->getValueUse()); +bool SPIT_Client::changeSPITObject(SPITObject *p_SPITObject) { + if (p_SPITObject == NULL) + return false; + SPITObject *ptrSPITObject; + SPITType *ptrSPITType; + { + ptrSPITObject = SPITObject::getSPITObject(p_SPITObject->getID()); + if (ptrSPITObject == NULL) + return false; + ptrSPITType = SPITType::getSPITType(p_SPITObject->getID()); + if (ptrSPITObject == NULL) + return false; - mCallbacks.onSpitObject(false, *ptrSPITType, *ptrSPITObject); - sendSPITObjectInternal(ptrSPITObject); - } - return true; + ptrSPITObject->setActionAssigned(p_SPITObject->getActionAssigned()); + ; + ptrSPITObject->setDelay(p_SPITObject->getDelay()); + ptrSPITObject->setDuration(p_SPITObject->getDelay()); + ptrSPITObject->setFixed(p_SPITObject->getFixed()); + ptrSPITObject->setFrameFadeInLength(p_SPITObject->getFrameFadeInLength()); + ptrSPITObject->setFrameFadeOutLength(p_SPITObject->getFrameFadeOutLength()); + ptrSPITObject->setFrameLength(p_SPITObject->getFrameLength()); + ptrSPITObject->setFrameStart(p_SPITObject->getFrameStart()); + ptrSPITObject->setName(p_SPITObject->getName()); + ptrSPITObject->setRemark(p_SPITObject->getRemark()); + ptrSPITObject->setSPITTypeID(p_SPITObject->getSPITTypeID()); + ptrSPITObject->setServerParams(p_SPITObject->getServerParams()); + ptrSPITObject->setTrack(p_SPITObject->getTrack()); + ptrSPITObject->setValueFactor(p_SPITObject->getValueFactor()); + ptrSPITObject->setValueUse(p_SPITObject->getValueUse()); + + mCallbacks.onSpitObject(ObjectEvent::Changed, *ptrSPITType, *ptrSPITObject); + sendSPITObjectInternal(ptrSPITObject); + } + return true; } /** @@ -1349,168 +1310,150 @@ bool SPIT_Client::changeSPITObject(SPITObject* p_SPITObject) { * -> the SPITObject is listet again.
* @param p_SPITObjectID the id of the SPITObject to remove. * @return 0 = sended to the SPITServer, -1 = not sended to the SPITServer or nos SPITObject with id == p_SPITObjectID exists. - */ + */ int SPIT_Client::removeSPITObject(string p_SPITObjectID) { - if (p_SPITObjectID.length() <= 0) return -1; - SPITType* ptrSPITType; - SPITObject* ptrSPITObject; - { - SPIT_Message::RemoveSPITObject sMRemoveSPITObject; - - ptrSPITObject = SPITObject::getSPITObject(p_SPITObjectID); - if (ptrSPITObject == NULL) return -1; - ptrSPITType = SPITType::getSPITType(ptrSPITObject->getSPITTypeID()); - if (ptrSPITType == NULL) return -1; - ptrSPITObject->fillMessageOP(&sMRemoveSPITObject); - mCallbacks.onSpitObjectRemoved(*ptrSPITType, *ptrSPITObject); - SPITObject::removeSPITObject(ptrSPITObject); - delete ptrSPITObject; - return sendSPITMessage(sMRemoveSPITObject); - } - return -1; -} + if (p_SPITObjectID.length() <= 0) + return -1; + SPITType *ptrSPITType; + SPITObject *ptrSPITObject; + { + SPIT_Message::RemoveSPITObject sMRemoveSPITObject; + ptrSPITObject = SPITObject::getSPITObject(p_SPITObjectID); + if (ptrSPITObject == NULL) + return -1; + ptrSPITType = SPITType::getSPITType(ptrSPITObject->getSPITTypeID()); + if (ptrSPITType == NULL) + return -1; + ptrSPITObject->fillMessageOP(&sMRemoveSPITObject); + mCallbacks.onSpitObject(ObjectEvent::Deleted, *ptrSPITType, *ptrSPITObject); + SPITObject::removeSPITObject(ptrSPITObject); + delete ptrSPITObject; + return sendSPITMessage(sMRemoveSPITObject); + } + return -1; +} //----- Play SPIT Objects ------ -void SPIT_Client::parsePlaySPITStart(SPIT_Message::PlaySPITStart* p_PlaySPITStart) { -// printf("parse PlaySPITStart ID: %s Name: %s Running: %d\n", p_PlaySPITStart->getPlayerID(), p_PlaySPITStart->getPlayerName(), p_PlaySPITStart->getPlayerIsRunning()); - SPITPlayer* ptrSPITPlayer; - { - ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITStart->getPlayerID()); - if (ptrSPITPlayer == NULL) return; - ptrSPITPlayer->setIsRunning(p_PlaySPITStart->getPlayerIsRunning()); - ptrSPITPlayer->setName(p_PlaySPITStart->getPlayerName()); - ptrSPITPlayer->setType(p_PlaySPITStart->getPlayerType()); - ptrSPITPlayer->setTime(p_PlaySPITStart->getTime()); - ptrSPITPlayer->startPlaySequence(); +void SPIT_Client::parsePlaySPITStart(SPIT_Message::PlaySPITStart *p_PlaySPITStart) { + ESP_LOGD(TAG, "parse PlaySPITStart ID: %s Name: %s Running: %d", p_PlaySPITStart->getPlayerID().c_str(), p_PlaySPITStart->getPlayerName().c_str(), (int)p_PlaySPITStart->getPlayerIsRunning()); + SPITPlayer *ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITStart->getPlayerID()); + if (ptrSPITPlayer == NULL) + return; + ptrSPITPlayer->setIsRunning(p_PlaySPITStart->getPlayerIsRunning()); + ptrSPITPlayer->setName(p_PlaySPITStart->getPlayerName()); + ptrSPITPlayer->setType(p_PlaySPITStart->getPlayerType()); + ptrSPITPlayer->setTime(p_PlaySPITStart->getTime()); + ptrSPITPlayer->startPlaySequence(); - mCallbacks.onPlay(ptrSPITPlayer->getID(), ptrSPITPlayer->getName(), ptrSPITPlayer->getType(), ptrSPITPlayer->getIsRunning(), ptrSPITPlayer->getTime()); - } + mCallbacks.onPlay(ptrSPITPlayer->getID(), ptrSPITPlayer->getName(), ptrSPITPlayer->getType(), ptrSPITPlayer->getIsRunning(), ptrSPITPlayer->getTime()); } -void SPIT_Client::parsePlaySPITObject(SPIT_Message::PlaySPITObject* p_PlaySPITObject) { -// printf("parse RPlaySPITObject Object:%s\n", p_PlaySPITObject->getSPITObjectID()); - SPITPlayer* ptrSPITPlayer; - SPITPlayer::PlaySPITType* ptrPlaySPITType; - SPITObject* ptrSPITObject; - { - ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITObject->getPlayerID()); - if (ptrSPITPlayer == NULL) return; +void SPIT_Client::parsePlaySPITObject(SPIT_Message::PlaySPITObject *p_PlaySPITObject) { + SPITPlayer *ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITObject->getPlayerID()); + if (ptrSPITPlayer == NULL) + return; - //Fetch infoemations from SPITObject - ptrSPITObject = SPITObject::getSPITObject(p_PlaySPITObject->getSPITObjectID()); - if (ptrSPITObject == NULL) { - return; - } - ptrPlaySPITType = ptrSPITPlayer->addSPITType_Playing(ptrSPITObject->getSPITTypeID()); - if (ptrPlaySPITType == NULL) { - - return; - } - ptrPlaySPITType->setPlayerIsRunning(ptrSPITPlayer->getIsRunning()); - ptrPlaySPITType->addValue(((double)p_PlaySPITObject->getValue()/1000000), ((double)ptrSPITObject->getValueFactor()/1000000)); - } - + SPITObject *ptrSPITObject = SPITObject::getSPITObject(p_PlaySPITObject->getSPITObjectID()); + if (ptrSPITObject == NULL) { + return; + } + SPITPlayer::PlaySPITType *ptrPlaySPITType = ptrSPITPlayer->addSPITType_Playing(ptrSPITObject->getSPITTypeID()); + if (ptrPlaySPITType == NULL) { + return; + } + ptrPlaySPITType->setPlayerIsRunning(ptrSPITPlayer->getIsRunning()); + ptrPlaySPITType->addValue(((double)p_PlaySPITObject->getValue() / 1000000), ((double)ptrSPITObject->getValueFactor() / 1000000)); } -void SPIT_Client::parsePlaySPITEnd(SPIT_Message::PlaySPITEnd* p_PlaySPITEnd) { -// printf("parse PlaySPITEnd \n"); - SPITPlayer* ptrSPITPlayer; - SPITType* ptrSPITType = NULL; - - // { - // ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITEnd->getPlayerID()); - // if (ptrSPITPlayer == NULL) return; +void SPIT_Client::parsePlaySPITEnd(SPIT_Message::PlaySPITEnd *p_PlaySPITEnd) { + SPITPlayer *ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITEnd->getPlayerID()); + if (ptrSPITPlayer == NULL) + return; - // unordered_map* ptrPlayObjects; - // SPITPlayer::PlayObject* ptrPlayObject; - // bool boolStarted; - // bool boolStopped; + // unordered_map* ptrPlayObjects; + // bool boolStarted; + // bool boolStopped; - // ptrPlayObjects = ptrSPITPlayer->getPlayObjects(); - // for (auto i = ptrPlayObjects->begin(); i != ptrPlayObjects->end(); i++) { - // ptrPlayObject = i->second; - // boolStarted = false; - // boolStopped = false; - // if (ptrPlayObject->getIsNew()) { - // boolStarted = true; - // } - // if (ptrPlayObject->getIsPlayed() == false) { - // boolStopped = true; - // } - // { - // ptrSPITObject = SPITObject::getSPITObject(ptrPlayObject->getSPITObjectID()); - // if (ptrSPITObject == NULL) { - // return; - // } - // ptrSPITType = SPITType::getSPITType(ptrSPITObject->getSPITTypeID()); - // if (ptrSPITType == NULL) { - // return; - // } + // SPITPlayer::PlaySPITType* ptrPlayObject = ptrSPITPlayer->getPlayObjects(); + // for (auto i = ptrPlayObjects->begin(); i != ptrPlayObjects->end(); i++) { + // ptrPlayObject = i->second; + // boolStarted = false; + // boolStopped = false; + // if (ptrPlayObject->getIsNew()) { + // boolStarted = true; + // } + // if (ptrPlayObject->getIsPlayed() == false) { + // boolStopped = true; + // } + // { + // ptrSPITObject = SPITObject::getSPITObject(ptrPlayObject->getSPITObjectID()); + // if (ptrSPITObject == NULL) { + // return; + // } + // SPITType *ptrSPITType = SPITType::getSPITType(ptrSPITObject->getSPITTypeID()); + // if (ptrSPITType == NULL) { + // return; + // } - // mCallbacks.onPlaySpitType(ptrPlayObject->getPlayerID(), boolStarted, boolStopped, *ptrSPITType, *ptrSPITObject, *ptrPlayObject); - // } - // } - // ptrSPITPlayer->endPlaySequence(); - // } + // mCallbacks.onPlaySpitType(ptrPlayObject->getPlayerID(), boolStarted, boolStopped, *ptrSPITType, *ptrSPITObject, *ptrPlayObject); + // } + // } + // ptrSPITPlayer->endPlaySequence(); - ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITEnd->getPlayerID()); - if (ptrSPITPlayer == NULL) return; - - unordered_map* ptrPlaySPITTypes = ptrSPITPlayer->getPlaySPITTypes(); - for (auto i = ptrPlaySPITTypes->begin(); i != ptrPlaySPITTypes->end(); i++) { - SPITPlayer::PlaySPITType* ptrPlaySPITType = i->second; - bool boolStarted = false; - bool boolStopped = false; - if (ptrPlaySPITType->getIsNew()) { - boolStarted = true; - } - if (ptrPlaySPITType->getIsPlayed() == false) { - boolStopped = true; - } - { - ptrSPITType = SPITType::getSPITType(ptrPlaySPITType->getSPITTypeID()); - if (ptrSPITType == NULL) { - //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(); + // SPITPlayer *ptrSPITPlayer = SPITPlayer::getSPITPlayer(p_PlaySPITEnd->getPlayerID()); + // if (ptrSPITPlayer == NULL) + // return; + unordered_map *ptrPlaySPITTypes = ptrSPITPlayer->getPlaySPITTypes(); + for (auto i = ptrPlaySPITTypes->begin(); i != ptrPlaySPITTypes->end(); i++) { + SPITPlayer::PlaySPITType *ptrPlaySPITType = i->second; + bool boolStarted = false; + bool boolStopped = false; + if (ptrPlaySPITType->getIsNew()) { + boolStarted = true; + } + if (ptrPlaySPITType->getIsPlayed() == false) { + boolStopped = true; + } + { + SPITType *ptrSPITType = SPITType::getSPITType(ptrPlaySPITType->getSPITTypeID()); + if (ptrSPITType == NULL) { + // 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 SPIT_Client::parseReportPlayStatus(SPIT_Message::ReportPlayStatus* p_ReportPlayStatus) { - //only REMOTE server -> client - //printf(" parseReportPlayStatus "); - SPITType* ptrSPITType = NULL; - SPITObject* ptrSPITObject = NULL; - { - +void SPIT_Client::parseReportPlayStatus(SPIT_Message::ReportPlayStatus *p_ReportPlayStatus) { + ESP_LOGD(TAG, "parseReportPlayStatus"); + SPITType *ptrSPITType = NULL; + { - ptrSPITObject = SPITObject::getSPITObjectRemote(p_ReportPlayStatus->getID()); - if (ptrSPITObject == NULL) { - ptrSPITObject = SPITObject::getSPITObject(p_ReportPlayStatus->getID()); - if (ptrSPITObject == NULL) { - return; - } - } - if (ptrSPITObject->getServerRemote() == false) { - ptrSPITType = SPITType::getSPITType(ptrSPITObject->getSPITTypeID()); - } - else { - ptrSPITType = SPITType::getSPITTypeRemote(ptrSPITObject->getSPITTypeID()); - } + SPITObject *ptrSPITObject = SPITObject::getSPITObjectRemote(p_ReportPlayStatus->getID()); + if (ptrSPITObject == NULL) { + ptrSPITObject = SPITObject::getSPITObject(p_ReportPlayStatus->getID()); + if (ptrSPITObject == NULL) { + return; + } + } + if (ptrSPITObject->getServerRemote() == false) { + ptrSPITType = SPITType::getSPITType(ptrSPITObject->getSPITTypeID()); + } else { + ptrSPITType = SPITType::getSPITTypeRemote(ptrSPITObject->getSPITTypeID()); + } - if (ptrSPITType == NULL) { - return; - } - mCallbacks.onPlayRemoteObjectStatus(*ptrSPITType, *ptrSPITObject, p_ReportPlayStatus->getFrameInsideObject(), p_ReportPlayStatus->getValue()); - } + if (ptrSPITType == NULL) { + return; + } + mCallbacks.onPlayRemoteObjectStatus(*ptrSPITType, *ptrSPITObject, p_ReportPlayStatus->getFrameInsideObject(), p_ReportPlayStatus->getValue()); + } } - //--------- Remote ---------- +//--------- Remote ---------- /** * Send a remote control command to the SPITServer.
@@ -1527,43 +1470,44 @@ void SPIT_Client::parseReportPlayStatus(SPIT_Message::ReportPlayStatus* p_Report * VALUEFLAG_DECREASE (0x01) The server decreases his existing value by p_Valueppm */ void SPIT_Client::sendRemoteObject(string p_SPITObjectID, int p_Valueppm, char p_ValueFlag) { - SPITObject* ptrRemoteSPITObject; - { - ptrRemoteSPITObject = SPITObject::getSPITObjectRemote(p_SPITObjectID); - if (ptrRemoteSPITObject == NULL) return; - - SPIT_Message::PlaySPITStart playSPITStart; - playSPITStart.setPlayerID(m_ID); - playSPITStart.setPlayerName(m_ProjName); - playSPITStart.setPlayerIsRunning(false); - playSPITStart.setPlayerType(PLAYERTYPE_DISCRETE); - playSPITStart.setTime(0); - sendSPITMessage(playSPITStart); - - SPIT_Message::PlaySPITObject playSPITObject; - playSPITObject.setID(ptrRemoteSPITObject->getID()); - playSPITObject.setPlayPrePosition(false); - playSPITObject.setPlayerID(m_ID); - playSPITObject.setValue(p_Valueppm); - playSPITObject.setValueFlag(p_ValueFlag); - sendSPITMessage(playSPITObject); - - SPIT_Message::PlaySPITEnd playSPITEnd; - playSPITEnd.setPlayerID(m_ID); - sendSPITMessage(playSPITEnd); - } + SPITObject *ptrRemoteSPITObject; + { + ptrRemoteSPITObject = SPITObject::getSPITObjectRemote(p_SPITObjectID); + if (ptrRemoteSPITObject == NULL) + return; + + SPIT_Message::PlaySPITStart playSPITStart; + playSPITStart.setPlayerID(m_ID); + playSPITStart.setPlayerName(m_ProjName); + playSPITStart.setPlayerIsRunning(false); + playSPITStart.setPlayerType(PLAYERTYPE_DISCRETE); + playSPITStart.setTime(0); + sendSPITMessage(playSPITStart); + + SPIT_Message::PlaySPITObject playSPITObject; + playSPITObject.setID(ptrRemoteSPITObject->getID()); + playSPITObject.setPlayPrePosition(false); + playSPITObject.setPlayerID(m_ID); + playSPITObject.setValue(p_Valueppm); + playSPITObject.setValueFlag(p_ValueFlag); + sendSPITMessage(playSPITObject); + + SPIT_Message::PlaySPITEnd playSPITEnd; + playSPITEnd.setPlayerID(m_ID); + sendSPITMessage(playSPITEnd); + } } fos::Semaphore SPIT_Client::sStartSad; -void SPIT_Client::processSocketTask(SPIT_Client & instance) { - ESP_LOGI(TAG, "Starting Socket managing"); +void SPIT_Client::processSocketTask(SPIT_Client &instance) { + ESP_LOGI(TAG, "Starting Socket managing"); -static const string SERVERAUTODETECT_PRECODE = "#SAD#"; -static const string SERVERAUTODETECT_SEPERATOR = "#,#"; -static const string SERVERAUTODETECT_TASKID = "#spit#"; // -> "#SAD##,##spit#" -static const string SERVERAUTODETECT_PORT = "15110"; -static constexpr int WATCHDOGTIME = 3000; + static const string SERVERAUTODETECT_PRECODE = "#SAD#"; + static const string SERVERAUTODETECT_SEPERATOR = "#,#"; + static const string SERVERAUTODETECT_TASKID = "#spit#"; // -> "#SAD##,##spit#" + static const string SERVERAUTODETECT_PORT = "15110"; + static constexpr int WATCHDOGTIME = 3000; string stringDatagram = SERVERAUTODETECT_PRECODE + SERVERAUTODETECT_SEPERATOR + SERVERAUTODETECT_TASKID; int intDatagramLength = stringDatagram.length(); @@ -1623,14 +1567,14 @@ static constexpr int WATCHDOGTIME = 3000; intIndex++; } stringParts[SAD_DetectedServer::PARAMINDEX_IP] = stringServerIP; - SAD_DetectedServer::addDetectedServer(true, stringParts[SAD_DetectedServer::PARAMINDEX_ID], stringParts); + SAD_DetectedServer::addDetectedServer(stringParts[SAD_DetectedServer::PARAMINDEX_ID], stringParts); } fos::Task::delayMs(100); SAD_DetectedServer::cycleEnd(instance); - + instance.abortSearch = false; - // if(instance.m_ConnectionStatus == CONNECTION_OK) break; - fos::Task::delayMs(1000); + // if(instance.m_ConnectionStatus == CONNECTION_OK) break; + fos::Task::delayMs(1000); } instance.mSPITSocket->setBroadcast(false); @@ -1639,23 +1583,24 @@ static constexpr int WATCHDOGTIME = 3000; auto nextWdTrigger = fos::Timing::getMilliSec() + WATCHDOGTIME; auto nextWdCheck = nextWdTrigger + WATCHDOGTIME; while (true) { - auto time = fos::Timing::getMilliSec(); - if (time > nextWdTrigger) { - instance.sAnswered = false; - instance.sendWatchdog(); - nextWdTrigger = nextWdCheck + WATCHDOGTIME; - } + // auto time = fos::Timing::getMilliSec(); + // if (time > nextWdTrigger) { + // instance.sAnswered = false; + // // instance.sendWatchdog(); + // nextWdTrigger = nextWdCheck + WATCHDOGTIME; + // } - if (time > nextWdCheck) { - if (!instance.sAnswered) { - ESP_LOGW(TAG, "TimeOut"); - instance.eventWatchdogLost(); - break; - } - nextWdCheck = nextWdTrigger + WATCHDOGTIME; - } + // if (time > nextWdCheck) { + // if (!instance.sAnswered) { + // ESP_LOGW(TAG, "TimeOut"); + // instance.eventWatchdogLost(); + // break; + // } + // nextWdCheck = nextWdTrigger + WATCHDOGTIME; + // } fos::Task::delayMs(25); - if(instance.m_StopReceiveSPITMessages) break; + // if (instance.m_StopReceiveSPITMessages) + // break; } } } \ No newline at end of file diff --git a/components/spit/src/SPIT_Message.cpp b/components/spit/src/SPIT_Message.cpp index 8aef300..b88d531 100644 --- a/components/spit/src/SPIT_Message.cpp +++ b/components/spit/src/SPIT_Message.cpp @@ -4,1830 +4,1890 @@ * and open the template in the editor. */ -/* +/* * SPIT_Message contains all SPIT messages. * A SPIT_Message contains a Header and an OPPart. - * + * * File: SPIT_Message.cpp * Author: Hagi - * + * * Created on 3. April 2019, 08:51 */ #include "SPIT_Message.h" SPIT_Message::SPIT_Message() { - initMembers(); + initMembers(); } //---------- Receive --------- -SPIT_Message::SPIT_Message(char* p_MessageBytes, int p_MessageByteCount) { - initMembers(); - m_MessageBytes = p_MessageBytes; - if (m_MessageBytes == NULL) { - m_MessageByteCount = 0; - return; - } - m_MessageByteCount = p_MessageByteCount; - if (parse() == NULL) { - } +SPIT_Message::SPIT_Message(char *p_MessageBytes, int p_MessageByteCount) { + initMembers(); + m_MessageBytes = p_MessageBytes; + if (m_MessageBytes == NULL) { + m_MessageByteCount = 0; + return; + } + m_MessageByteCount = p_MessageByteCount; + if (parse() == NULL) { + } } SPIT_Message::~SPIT_Message() { - delete m_OPPart; - if (m_MessageBytesCreated && m_MessageBytes != NULL) { - free(m_MessageBytes); - } + delete m_OPPart; + if (m_MessageBytesCreated && m_MessageBytes != NULL) { + free(m_MessageBytes); + } } void SPIT_Message::initMembers() { - m_MessageBytes = NULL; - m_MessageByteCount = 0; - m_Header = NULL; - m_OPPart = NULL; - m_MessageBytesCreated = false; + m_MessageBytes = NULL; + m_MessageByteCount = 0; + m_Header = NULL; + m_OPPart = NULL; + m_MessageBytesCreated = false; } - - //Receive -SPIT_Message::OPPart* SPIT_Message::parse() { - if (m_MessageBytes == NULL) return NULL; - m_OPPart = NULL; - m_MessageBytesCreated = false; - //parse Header - m_Header = new Header(); - if (m_Header->parse(m_MessageBytes, m_MessageByteCount) == false) { - m_Header = NULL; - m_OPPart = NULL; - return NULL; - } - - //parse OP - switch (m_Header->getOPFlag()) { - //Connection - case SPIT_Message::Connect::OPFLAG: { - m_OPPart = new Connect(m_Header); - } - break; - case SPIT_Message::ConnectAnswer::OPFLAG: { - m_OPPart = new ConnectAnswer(m_Header); - } - break; - case Disconnect::OPFLAG: { - m_OPPart = new Disconnect(m_Header); - } - break; - case Watchdog::OPFLAG: { - m_OPPart = new Watchdog(m_Header); - } - break; - case WatchdogAnswer::OPFLAG: { - m_OPPart = new WatchdogAnswer(m_Header); - } - break; - - //SPITProject - case ReportSPITProject::OPFLAG: { - m_OPPart = new ReportSPITProject(m_Header); - } - break; - case CloseSPITProject::OPFLAG: { - m_OPPart = new CloseSPITProject(m_Header); - } - break; - case RequestProjectTransfer::OPFLAG: { - m_OPPart = new RequestProjectTransfer(m_Header); - } - break; - case StartProjectTransfer::OPFLAG: { - m_OPPart = new StartProjectTransfer(m_Header); - } - break; - case EndProjectTransfer::OPFLAG: { - m_OPPart = new EndProjectTransfer(m_Header); - } - break; - - //SPITType - case ReportSPITType::OPFLAG: { - m_OPPart = new ReportSPITType(m_Header); - } - break; - case RemoveSPITType::OPFLAG: { - m_OPPart = new RemoveSPITType(m_Header); - } - break; - - //SPITObject - case ReportSPITObject::OPFLAG: { - m_OPPart = new ReportSPITObject(m_Header); - } - break; - case RemoveSPITObject::OPFLAG: { - m_OPPart = new RemoveSPITObject(m_Header); - } - break; - //PlaySPITObjects - case PlaySPITStart::OPFLAG: { - m_OPPart = new PlaySPITStart(m_Header); - } - break; - case PlaySPITObject::OPFLAG: { - m_OPPart = new PlaySPITObject(m_Header); - } - break; - case PlaySPITEnd::OPFLAG: { - m_OPPart = new PlaySPITEnd(m_Header); - } - break; - case ReportPlayStatus::OPFLAG: { - m_OPPart = new ReportPlayStatus(m_Header); - } - break; - default: - m_OPPart = NULL; - break; - } - if (m_OPPart != NULL) { - if (m_OPPart->parse(m_MessageBytes, m_MessageByteCount) == false) { - delete m_OPPart; - m_Header = NULL; - m_OPPart = NULL; - return NULL; - } - } - return m_OPPart; +// Receive + +SPIT_Message::OPPart *SPIT_Message::parse() { + if (m_MessageBytes == NULL) + return NULL; + m_OPPart = NULL; + m_MessageBytesCreated = false; + // parse Header + m_Header = new Header(); + if (m_Header->parse(m_MessageBytes, m_MessageByteCount) == false) { + m_Header = NULL; + m_OPPart = NULL; + return NULL; + } + + // parse OP + switch (m_Header->getOPFlag()) { + // Connection + case SPIT_Message::Connect::OPFLAG: { + m_OPPart = new Connect(m_Header); + } break; + case SPIT_Message::ConnectAnswer::OPFLAG: { + m_OPPart = new ConnectAnswer(m_Header); + } break; + case Disconnect::OPFLAG: { + m_OPPart = new Disconnect(m_Header); + } break; + case Watchdog::OPFLAG: { + m_OPPart = new Watchdog(m_Header); + } break; + case WatchdogAnswer::OPFLAG: { + m_OPPart = new WatchdogAnswer(m_Header); + } break; + + // SPITProject + case ReportSPITProject::OPFLAG: { + m_OPPart = new ReportSPITProject(m_Header); + } break; + case CloseSPITProject::OPFLAG: { + m_OPPart = new CloseSPITProject(m_Header); + } break; + case RequestProjectTransfer::OPFLAG: { + m_OPPart = new RequestProjectTransfer(m_Header); + } break; + case StartProjectTransfer::OPFLAG: { + m_OPPart = new StartProjectTransfer(m_Header); + } break; + case EndProjectTransfer::OPFLAG: { + m_OPPart = new EndProjectTransfer(m_Header); + } break; + + // SPITType + case ReportSPITType::OPFLAG: { + m_OPPart = new ReportSPITType(m_Header); + } break; + case RemoveSPITType::OPFLAG: { + m_OPPart = new RemoveSPITType(m_Header); + } break; + + // SPITObject + case ReportSPITObject::OPFLAG: { + m_OPPart = new ReportSPITObject(m_Header); + } break; + case RemoveSPITObject::OPFLAG: { + m_OPPart = new RemoveSPITObject(m_Header); + } break; + // PlaySPITObjects + case PlaySPITStart::OPFLAG: { + m_OPPart = new PlaySPITStart(m_Header); + } break; + case PlaySPITObject::OPFLAG: { + m_OPPart = new PlaySPITObject(m_Header); + } break; + case PlaySPITEnd::OPFLAG: { + m_OPPart = new PlaySPITEnd(m_Header); + } break; + case ReportPlayStatus::OPFLAG: { + m_OPPart = new ReportPlayStatus(m_Header); + } break; + default: + m_OPPart = NULL; + break; + } + if (m_OPPart != NULL) { + if (m_OPPart->parse(m_MessageBytes, m_MessageByteCount) == false) { + delete m_OPPart; + m_Header = NULL; + m_OPPart = NULL; + return NULL; + } + } + return m_OPPart; } //---------- Send ---------- -SPIT_Message::SPIT_Message(OPPart* p_OPPart) { - initMembers(); - if (p_OPPart == NULL) return; - m_OPPart = p_OPPart; - m_Header = m_OPPart->getHeader(); - if (m_Header == NULL) { - m_OPPart = NULL; - return; - } +SPIT_Message::SPIT_Message(OPPart *p_OPPart) { + initMembers(); + if (p_OPPart == NULL) + return; + m_OPPart = p_OPPart; + m_Header = m_OPPart->getHeader(); + if (m_Header == NULL) { + m_OPPart = NULL; + return; + } } bool SPIT_Message::fillBytes() { - if (m_OPPart == NULL) return false; - try { - if (m_MessageBytes == NULL) m_MessageBytes = createByteArray(m_OPPart, &m_MessageByteCount); - if (m_MessageBytes == NULL) return false; - m_MessageBytesCreated = true; - return m_OPPart->fillBytes(m_MessageBytes, m_MessageByteCount); - } - catch(...) { - return false; - } - return true; + if (m_OPPart == NULL) + return false; + try { + if (m_MessageBytes == NULL) + m_MessageBytes = createByteArray(m_OPPart, &m_MessageByteCount); + if (m_MessageBytes == NULL) + return false; + m_MessageBytesCreated = true; + return m_OPPart->fillBytes(m_MessageBytes, m_MessageByteCount); + } catch (...) { + return false; + } + return true; } -const char* SPIT_Message::getMessageBytes() { - if (m_OPPart == NULL) return NULL; - if (fillBytes() == false) return NULL; - return m_MessageBytes; +const char *SPIT_Message::getMessageBytes() { + if (m_OPPart == NULL) + return NULL; + if (fillBytes() == false) + return NULL; + return m_MessageBytes; } - - //----------- Header ----------- - SPIT_Message::Header::~Header() { - } - SPIT_Message::Header::Header(const Header& orig) { - initMembers(); - m_MessageNumber = orig.getMessageNumber(); - m_ServerID = orig.getServerID(); - m_ClientID = orig.getClientID(); - } - //Receive - SPIT_Message::Header::Header() { - initMembers(); - } - - void SPIT_Message::Header::initMembers() { - m_SPITID = &SPITID[0]; - m_SPITVersion = SPITVERSION; - m_MessageNumber = 0; - m_BytesCount = BYTESLENGTH; - m_ServerID = ""; - m_ClientID = ""; - } - - bool SPIT_Message::Header::parse(char* p_MessageBytes, int p_MessageBytesLength) { - if (p_MessageBytes == NULL) return false; - string stringSPIT_ID; - try { - m_ParseOffset = 0; - //SPIT ID - stringSPIT_ID = getString(p_MessageBytes, p_MessageBytesLength, m_ParseOffset, 7); - m_ParseOffset += 7; - if (SPITID != stringSPIT_ID) return false; - m_SPITVersion = getInt(p_MessageBytes, p_MessageBytesLength, m_ParseOffset); - if (m_SPITVersion < 0) return false; - m_ParseOffset += 4; - m_MessageNumber = getByte(p_MessageBytes, p_MessageBytesLength, m_ParseOffset); - m_ParseOffset += 1; - m_BytesCount = getInt(p_MessageBytes, p_MessageBytesLength, m_ParseOffset); - if (m_BytesCount < 0) return false; - m_ParseOffset += 4; - m_ServerID = getString(p_MessageBytes, p_MessageBytesLength, m_ParseOffset, 41); - m_ParseOffset += 41; - m_ClientID = getString(p_MessageBytes, p_MessageBytesLength, m_ParseOffset, 41); - m_ParseOffset += 41; - m_OPFlag = p_MessageBytes[m_ParseOffset] & 0xFF; - m_ParseOffset += 1; - } - catch (...) { - return false; - } - return true; - } - - //Send - SPIT_Message::Header::Header(int p_SPITVersion, int p_OPFlag) { - initMembers(); - m_SPITVersion = p_SPITVersion; - m_OPFlag = p_OPFlag; - } - - void SPIT_Message::Header::setMessageNumber(unsigned char p_MessageNumber) { - m_MessageNumber = p_MessageNumber; - } - - void SPIT_Message::Header::setServerID(string p_ID) { - m_ServerID = p_ID; - } - void SPIT_Message::Header::setClientID(string p_ID) { - m_ClientID = p_ID; - } - void SPIT_Message::Header::setOPFlag(int p_OPFlag) { - m_OPFlag = p_OPFlag; - } - bool SPIT_Message::Header::fillBytes(char* p_Bytes, int p_ByteCount) { - if (p_Bytes == NULL) return false; - try { - m_ParseOffset = 0; - m_ParseOffset += setString(m_SPITID, p_Bytes, p_ByteCount, m_ParseOffset, 7); - m_ParseOffset += setInt(SPITVERSION, p_Bytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setByte(m_MessageNumber, p_Bytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setInt(m_BytesCount, p_Bytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_ServerID, p_Bytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setString(m_ClientID, p_Bytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setByte(m_OPFlag, p_Bytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } +SPIT_Message::Header::~Header() { +} +SPIT_Message::Header::Header(const Header &orig) { + initMembers(); + m_MessageNumber = orig.getMessageNumber(); + m_ServerID = orig.getServerID(); + m_ClientID = orig.getClientID(); +} +// Receive +SPIT_Message::Header::Header() { + initMembers(); +} + +void SPIT_Message::Header::initMembers() { + m_SPITID = &SPITID[0]; + m_SPITVersion = SPITVERSION; + m_MessageNumber = 0; + m_BytesCount = BYTESLENGTH; + m_ServerID = ""; + m_ClientID = ""; +} + +bool SPIT_Message::Header::parse(char *p_MessageBytes, int p_MessageBytesLength) { + if (p_MessageBytes == NULL) + return false; + string stringSPIT_ID; + try { + m_ParseOffset = 0; + // SPIT ID + stringSPIT_ID = getString(p_MessageBytes, p_MessageBytesLength, m_ParseOffset, 7); + m_ParseOffset += 7; + if (SPITID != stringSPIT_ID) + return false; + m_SPITVersion = getInt(p_MessageBytes, p_MessageBytesLength, m_ParseOffset); + if (m_SPITVersion < 0) + return false; + m_ParseOffset += 4; + m_MessageNumber = getByte(p_MessageBytes, p_MessageBytesLength, m_ParseOffset); + m_ParseOffset += 1; + m_BytesCount = getInt(p_MessageBytes, p_MessageBytesLength, m_ParseOffset); + if (m_BytesCount < 0) + return false; + m_ParseOffset += 4; + m_ServerID = getString(p_MessageBytes, p_MessageBytesLength, m_ParseOffset, 41); + m_ParseOffset += 41; + m_ClientID = getString(p_MessageBytes, p_MessageBytesLength, m_ParseOffset, 41); + m_ParseOffset += 41; + m_OPFlag = p_MessageBytes[m_ParseOffset] & 0xFF; + m_ParseOffset += 1; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::Header::Header(int p_SPITVersion, int p_OPFlag) { + initMembers(); + m_SPITVersion = p_SPITVersion; + m_OPFlag = p_OPFlag; +} + +void SPIT_Message::Header::setMessageNumber(unsigned char p_MessageNumber) { + m_MessageNumber = p_MessageNumber; +} + +void SPIT_Message::Header::setServerID(string p_ID) { + m_ServerID = p_ID; +} +void SPIT_Message::Header::setClientID(string p_ID) { + m_ClientID = p_ID; +} +void SPIT_Message::Header::setOPFlag(int p_OPFlag) { + m_OPFlag = p_OPFlag; +} +bool SPIT_Message::Header::fillBytes(char *p_Bytes, int p_ByteCount) { + if (p_Bytes == NULL) + return false; + try { + m_ParseOffset = 0; + m_ParseOffset += setString(m_SPITID, p_Bytes, p_ByteCount, m_ParseOffset, 7); + m_ParseOffset += setInt(SPITVERSION, p_Bytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setByte(m_MessageNumber, p_Bytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setInt(m_BytesCount, p_Bytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_ServerID, p_Bytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setString(m_ClientID, p_Bytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setByte(m_OPFlag, p_Bytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} - - //----------- OPPart ----------- - SPIT_Message::OPPart::~OPPart() { - if (m_Header != NULL) { - delete m_Header; - } - m_Header = NULL; - } - void SPIT_Message::OPPart::initMembers() { - m_Header = NULL; - m_ParseOffset = 0; - m_BytesCount = 0; - } +SPIT_Message::OPPart::~OPPart() { + if (m_Header != NULL) { + delete m_Header; + } + m_Header = NULL; +} +void SPIT_Message::OPPart::initMembers() { + m_Header = NULL; + m_ParseOffset = 0; + m_BytesCount = 0; +} + +// Receive +SPIT_Message::OPPart::OPPart(Header *p_Header, int p_OPFlag) { + initMembers(); + m_Header = p_Header; + if (m_Header != NULL) { + m_ParseOffset = Header::BYTESLENGTH; + m_Header->setOPFlag(p_OPFlag); + } +} +void SPIT_Message::OPPart::setHeader(Header *p_Header) { + m_Header = p_Header; + if (m_Header != NULL) { + m_ParseOffset = Header::BYTESLENGTH; + } +} + +// Send +SPIT_Message::OPPart::OPPart() { + initMembers(); +} - //Receive - SPIT_Message::OPPart::OPPart(Header* p_Header, int p_OPFlag) { - initMembers(); - m_Header = p_Header; - if (m_Header != NULL) { - m_ParseOffset = Header::BYTESLENGTH; - m_Header->setOPFlag(p_OPFlag); - } - } - void SPIT_Message::OPPart::setHeader(Header* p_Header) { - m_Header = p_Header; - if (m_Header != NULL) { - m_ParseOffset = Header::BYTESLENGTH; - } - } - - //Send - SPIT_Message::OPPart::OPPart() { - initMembers(); - } - //--------------------------- Connection -------------------------------- - - + //----------- Connect ----------- - SPIT_Message::Connect::~Connect(){ - } +SPIT_Message::Connect::~Connect() { +} /* SPIT_Message::Connect::Connect(const Connect& orig) : OPPart(new Header(*orig.getHeader()), OPFLAG) { - initMembers(); - if (orig.getHeader() == NULL) return; - m_ClientComputerName = stringCopy(orig.getClientComputerName()); - m_ClientName = stringCopy(orig.getClientName()); - m_LoginName = stringCopy(orig.getLoginName()); - m_LoginPassword = stringCopy(orig.getLoginPassword()); - m_ServerIP = stringCopy(orig.getServerIP()); - m_ServerPort = orig.getServerPort(); - } + initMembers(); + if (orig.getHeader() == NULL) return; + m_ClientComputerName = stringCopy(orig.getClientComputerName()); + m_ClientName = stringCopy(orig.getClientName()); + m_LoginName = stringCopy(orig.getLoginName()); + m_LoginPassword = stringCopy(orig.getLoginPassword()); + m_ServerIP = stringCopy(orig.getServerIP()); + m_ServerPort = orig.getServerPort(); + } */ - //Receive - SPIT_Message::Connect::Connect(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - - void SPIT_Message::Connect::initMembers() { - m_ClientComputerName = ""; - m_ClientName = ""; - m_LoginName = ""; - m_LoginPassword = ""; - m_ServerIP = ""; - m_ServerPort = 0; - m_BytesCount = BYTESLENGTH; - } - - bool SPIT_Message::Connect::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_ClientComputerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_ClientName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_LoginName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_LoginPassword = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_ServerIP = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 40); - m_ParseOffset += 40; - m_ServerPort = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - - //Send - SPIT_Message::Connect::Connect() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - void SPIT_Message::Connect::setClientComputerName(string p_ComputerName) { - m_ClientComputerName = p_ComputerName; - } - void SPIT_Message::Connect::setClientName(string p_ClientName) { - m_ClientName = p_ClientName; - } - void SPIT_Message::Connect::setLoginName(string p_LoginName) { - m_LoginName = p_LoginName; - } - void SPIT_Message::Connect::setLoginPassword(string p_LoginPassword) { - m_LoginPassword = p_LoginPassword; - } - void SPIT_Message::Connect::setServerIP(string p_ServerIP) { - m_ServerIP = p_ServerIP; - } - void SPIT_Message::Connect::setServerPort(int p_ServerPort) { - if (p_ServerPort < 0 || p_ServerPort > 65535) p_ServerPort = 0; - m_ServerPort = p_ServerPort; - } - bool SPIT_Message::Connect::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_ClientComputerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setString(m_ClientName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setString(m_LoginName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setString(m_LoginPassword, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setString(m_ServerIP, p_MessageBytes, p_ByteCount, m_ParseOffset, 40); - m_ParseOffset += setInt(m_ServerPort, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - +// Receive +SPIT_Message::Connect::Connect(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} + +void SPIT_Message::Connect::initMembers() { + m_ClientComputerName = ""; + m_ClientName = ""; + m_LoginName = ""; + m_LoginPassword = ""; + m_ServerIP = ""; + m_ServerPort = 0; + m_BytesCount = BYTESLENGTH; +} + +bool SPIT_Message::Connect::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_ClientComputerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_ClientName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_LoginName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_LoginPassword = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_ServerIP = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 40); + m_ParseOffset += 40; + m_ServerPort = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::Connect::Connect() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} +void SPIT_Message::Connect::setClientComputerName(string p_ComputerName) { + m_ClientComputerName = p_ComputerName; +} +void SPIT_Message::Connect::setClientName(string p_ClientName) { + m_ClientName = p_ClientName; +} +void SPIT_Message::Connect::setLoginName(string p_LoginName) { + m_LoginName = p_LoginName; +} +void SPIT_Message::Connect::setLoginPassword(string p_LoginPassword) { + m_LoginPassword = p_LoginPassword; +} +void SPIT_Message::Connect::setServerIP(string p_ServerIP) { + m_ServerIP = p_ServerIP; +} +void SPIT_Message::Connect::setServerPort(int p_ServerPort) { + if (p_ServerPort < 0 || p_ServerPort > 65535) + p_ServerPort = 0; + m_ServerPort = p_ServerPort; +} +bool SPIT_Message::Connect::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_ClientComputerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setString(m_ClientName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setString(m_LoginName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setString(m_LoginPassword, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setString(m_ServerIP, p_MessageBytes, p_ByteCount, m_ParseOffset, 40); + m_ParseOffset += setInt(m_ServerPort, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + //----------- ConnectAnswer ----------- - - void SPIT_Message::ConnectAnswer::initMembers() { - m_ServerComputerName = ""; - m_ServerName = ""; - m_Connected = false; - m_BytesCount = BYTESLENGTH; - m_StepTime = 40; - } - SPIT_Message::ConnectAnswer::~ConnectAnswer() { - } - SPIT_Message::ConnectAnswer::ConnectAnswer(const ConnectAnswer& orig) { - - } - //Receive - SPIT_Message::ConnectAnswer::ConnectAnswer(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::ConnectAnswer::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_ServerComputerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_ServerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_StepTime = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_Connected = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - } - catch (...) { - return false; - } - return true; - } - - //Send - SPIT_Message::ConnectAnswer::ConnectAnswer() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - void SPIT_Message::ConnectAnswer::setServerComputerName(string p_ServerComputerName) { - m_ServerComputerName = p_ServerComputerName; - } - void SPIT_Message::ConnectAnswer::setServerName(string p_ServerName) { - m_ServerName = p_ServerName; - } - void SPIT_Message::ConnectAnswer::setConnected(bool p_Connected) { - m_Connected = p_Connected; - } - void SPIT_Message::ConnectAnswer::setStepTime(int p_StepTime_ms) { - if (p_StepTime_ms < 0) p_StepTime_ms = 1; - m_StepTime = p_StepTime_ms; - } - bool SPIT_Message::ConnectAnswer::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_ServerComputerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setString(m_ServerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setInt(m_StepTime, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_Connected, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - + +void SPIT_Message::ConnectAnswer::initMembers() { + m_ServerComputerName = ""; + m_ServerName = ""; + m_Connected = false; + m_BytesCount = BYTESLENGTH; + m_StepTime = 40; +} +SPIT_Message::ConnectAnswer::~ConnectAnswer() { +} +SPIT_Message::ConnectAnswer::ConnectAnswer(const ConnectAnswer &orig) { +} +// Receive +SPIT_Message::ConnectAnswer::ConnectAnswer(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::ConnectAnswer::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_ServerComputerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_ServerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_StepTime = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_Connected = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::ConnectAnswer::ConnectAnswer() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} +void SPIT_Message::ConnectAnswer::setServerComputerName(string p_ServerComputerName) { + m_ServerComputerName = p_ServerComputerName; +} +void SPIT_Message::ConnectAnswer::setServerName(string p_ServerName) { + m_ServerName = p_ServerName; +} +void SPIT_Message::ConnectAnswer::setConnected(bool p_Connected) { + m_Connected = p_Connected; +} +void SPIT_Message::ConnectAnswer::setStepTime(int p_StepTime_ms) { + if (p_StepTime_ms < 0) + p_StepTime_ms = 1; + m_StepTime = p_StepTime_ms; +} +bool SPIT_Message::ConnectAnswer::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_ServerComputerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setString(m_ServerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setInt(m_StepTime, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_Connected, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + //----------- Disconnect ----------- - - void SPIT_Message::Disconnect::initMembers() { - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::Disconnect::~Disconnect() { - } - //Receive - SPIT_Message::Disconnect::Disconnect(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::Disconnect::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - - // Send - SPIT_Message::Disconnect::Disconnect() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - } - - bool SPIT_Message::Disconnect::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - +void SPIT_Message::Disconnect::initMembers() { + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::Disconnect::~Disconnect() { +} +// Receive +SPIT_Message::Disconnect::Disconnect(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::Disconnect::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::Disconnect::Disconnect() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); +} + +bool SPIT_Message::Disconnect::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} + //----------- Watchdog ----------- - void SPIT_Message::Watchdog::initMembers() { - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::Watchdog::~Watchdog() { - - } +void SPIT_Message::Watchdog::initMembers() { + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::Watchdog::~Watchdog() { +} + +// Receive +SPIT_Message::Watchdog::Watchdog(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::Watchdog::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::Watchdog::Watchdog() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} +bool SPIT_Message::Watchdog::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} - //Receive - SPIT_Message::Watchdog::Watchdog(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::Watchdog::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - - // Send - SPIT_Message::Watchdog::Watchdog() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - bool SPIT_Message::Watchdog::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - //----------- WatchdogAnswer ----------- - void SPIT_Message::WatchdogAnswer::initMembers() { - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::WatchdogAnswer::~WatchdogAnswer() { +void SPIT_Message::WatchdogAnswer::initMembers() { + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::WatchdogAnswer::~WatchdogAnswer() { +} - } +// Receive +SPIT_Message::WatchdogAnswer::WatchdogAnswer(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::WatchdogAnswer::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::WatchdogAnswer::WatchdogAnswer() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} +bool SPIT_Message::WatchdogAnswer::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} - //Receive - SPIT_Message::WatchdogAnswer::WatchdogAnswer(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::WatchdogAnswer::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - - - // Send - SPIT_Message::WatchdogAnswer::WatchdogAnswer() : OPPart(){ - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - bool SPIT_Message::WatchdogAnswer::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - - - - - //--------------------------- SPITProject -------------------------------- - + //----------- ReportSPITProject ----------- - void SPIT_Message::ReportSPITProject::initMembers() { - m_ProjectID = ""; - m_ProjectName = ""; - m_BytesCount = BYTESLENGTH; - m_FramesPerSecond = 1000; - } - SPIT_Message::ReportSPITProject::~ReportSPITProject() { - } - //Receive - SPIT_Message::ReportSPITProject::ReportSPITProject(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::ReportSPITProject::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_ProjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_ProjectName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_FramesPerSecond = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::ReportSPITProject::ReportSPITProject() : OPPart(){ - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::ReportSPITProject::setProjectID(string p_ProjectID) { - m_ProjectID = p_ProjectID; - } - void SPIT_Message::ReportSPITProject::setProjectName(string p_ProjectName) { - m_ProjectName = p_ProjectName; - } - void SPIT_Message::ReportSPITProject::setFramesPerSecond(const int p_FramesPerSecond) { - m_FramesPerSecond = p_FramesPerSecond; - } - bool SPIT_Message::ReportSPITProject::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_ProjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setString(m_ProjectName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setInt(m_FramesPerSecond, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } +void SPIT_Message::ReportSPITProject::initMembers() { + m_ProjectID = ""; + m_ProjectName = ""; + m_BytesCount = BYTESLENGTH; + m_FramesPerSecond = 1000; +} +SPIT_Message::ReportSPITProject::~ReportSPITProject() { +} +// Receive +SPIT_Message::ReportSPITProject::ReportSPITProject(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::ReportSPITProject::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_ProjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_ProjectName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_FramesPerSecond = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::ReportSPITProject::ReportSPITProject() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::ReportSPITProject::setProjectID(string p_ProjectID) { + m_ProjectID = p_ProjectID; +} +void SPIT_Message::ReportSPITProject::setProjectName(string p_ProjectName) { + m_ProjectName = p_ProjectName; +} +void SPIT_Message::ReportSPITProject::setFramesPerSecond(const int p_FramesPerSecond) { + m_FramesPerSecond = p_FramesPerSecond; +} +bool SPIT_Message::ReportSPITProject::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_ProjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setString(m_ProjectName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setInt(m_FramesPerSecond, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} //----------- StartProjectTransfer ----------- - void SPIT_Message::CloseSPITProject::initMembers() { - m_ProjectID = ""; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::CloseSPITProject::~CloseSPITProject() { - } - //Receive - SPIT_Message::CloseSPITProject::CloseSPITProject(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::CloseSPITProject::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_ProjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::CloseSPITProject::CloseSPITProject() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::CloseSPITProject::setProjectID(string p_ProjectID) { - m_ProjectID = p_ProjectID; - } - bool SPIT_Message::CloseSPITProject::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_ProjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - } - catch (...) { - return false; - } - return true; - } +void SPIT_Message::CloseSPITProject::initMembers() { + m_ProjectID = ""; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::CloseSPITProject::~CloseSPITProject() { +} +// Receive +SPIT_Message::CloseSPITProject::CloseSPITProject(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::CloseSPITProject::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_ProjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::CloseSPITProject::CloseSPITProject() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::CloseSPITProject::setProjectID(string p_ProjectID) { + m_ProjectID = p_ProjectID; +} +bool SPIT_Message::CloseSPITProject::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_ProjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + } catch (...) { + return false; + } + return true; +} //----------- RequestProjectTransfer ----------- - - void SPIT_Message::RequestProjectTransfer::initMembers() { - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::RequestProjectTransfer::~RequestProjectTransfer() { - - } - //Receive - SPIT_Message::RequestProjectTransfer::RequestProjectTransfer(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::RequestProjectTransfer::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::RequestProjectTransfer::RequestProjectTransfer() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - bool SPIT_Message::RequestProjectTransfer::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - + +void SPIT_Message::RequestProjectTransfer::initMembers() { + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::RequestProjectTransfer::~RequestProjectTransfer() { +} +// Receive +SPIT_Message::RequestProjectTransfer::RequestProjectTransfer(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::RequestProjectTransfer::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::RequestProjectTransfer::RequestProjectTransfer() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} +bool SPIT_Message::RequestProjectTransfer::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + //----------- StartProjectTransfer ----------- - - void SPIT_Message::StartProjectTransfer::initMembers() { - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::StartProjectTransfer::~StartProjectTransfer() { - } - //Receive - SPIT_Message::StartProjectTransfer::StartProjectTransfer(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::StartProjectTransfer::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::StartProjectTransfer::StartProjectTransfer() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - bool SPIT_Message::StartProjectTransfer::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } + +void SPIT_Message::StartProjectTransfer::initMembers() { + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::StartProjectTransfer::~StartProjectTransfer() { +} +// Receive +SPIT_Message::StartProjectTransfer::StartProjectTransfer(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::StartProjectTransfer::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::StartProjectTransfer::StartProjectTransfer() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +bool SPIT_Message::StartProjectTransfer::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} //----------- ENdProjectTransfer ----------- - - void SPIT_Message::EndProjectTransfer::initMembers() { - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::EndProjectTransfer::~EndProjectTransfer() { - - } - //Receive - SPIT_Message::EndProjectTransfer::EndProjectTransfer(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::EndProjectTransfer::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::EndProjectTransfer::EndProjectTransfer() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - bool SPIT_Message::EndProjectTransfer::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - - - - - +void SPIT_Message::EndProjectTransfer::initMembers() { + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::EndProjectTransfer::~EndProjectTransfer() { +} +// Receive +SPIT_Message::EndProjectTransfer::EndProjectTransfer(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::EndProjectTransfer::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::EndProjectTransfer::EndProjectTransfer() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} +bool SPIT_Message::EndProjectTransfer::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + //--------------------------- SPITType --------------------------------- - //----------- ReportSPITType ----------- - - void SPIT_Message::ReportSPITType::initMembers() { - m_Confirmed = false; - m_SPITTypeID = ""; - m_Fixed = false; - m_ServerRemote = false; - m_ServerProjectIndepended = false; - m_SPITTypeGroupName = ""; - m_SPITTypeName = ""; - m_Delay = 0; - m_Duration = 0; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::ReportSPITType::~ReportSPITType() { - } - //Receive - SPIT_Message::ReportSPITType::ReportSPITType(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::ReportSPITType::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_Confirmed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_SPITTypeID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_Fixed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_ServerRemote = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_ServerProjectIndepended = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_SPITTypeGroupName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 39); - m_ParseOffset += 39; - m_SPITTypeName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_Delay = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_Duration = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::ReportSPITType::ReportSPITType() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::ReportSPITType::setConfirmed(bool p_Confirmed) { - m_Confirmed = p_Confirmed; - } - void SPIT_Message::ReportSPITType::setID(string p_ID) { - m_SPITTypeID = p_ID; - } - void SPIT_Message::ReportSPITType::setFixed(bool p_Fixed) { - m_Fixed = p_Fixed; - } - void SPIT_Message::ReportSPITType::setServerRemote(bool p_IsServerRemote) { - m_ServerRemote = p_IsServerRemote; - } - void SPIT_Message::ReportSPITType::setServerProjectIndepended(bool p_ProjectIndpended) { - m_ServerProjectIndepended = p_ProjectIndpended; - } - void SPIT_Message::ReportSPITType::setGroupName(string p_GroupName) { - m_SPITTypeGroupName = p_GroupName; - } - void SPIT_Message::ReportSPITType::setName(string p_Name) { - m_SPITTypeName = p_Name; - } - void SPIT_Message::ReportSPITType::setDelay(long long p_Delay) { - m_Delay = p_Delay; - } - void SPIT_Message::ReportSPITType::setDuration(long long p_Duration) { - m_Duration = p_Duration; - } - bool SPIT_Message::ReportSPITType::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = m_Header->BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_Confirmed, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_SPITTypeID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setBoolean(m_Fixed, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_ServerRemote, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_ServerProjectIndepended, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_SPITTypeGroupName, p_MessageBytes, p_ByteCount, m_ParseOffset, 39); - m_ParseOffset += setString(m_SPITTypeName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setLong(m_Delay, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setLong(m_Duration, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - - //----------- ReportSPITType ----------- - - void SPIT_Message::RemoveSPITType::initMembers() { - m_SPITTypeID = ""; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::RemoveSPITType::~RemoveSPITType() { - } - //Receive - SPIT_Message::RemoveSPITType::RemoveSPITType(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::RemoveSPITType::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_SPITTypeID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::RemoveSPITType::RemoveSPITType() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::RemoveSPITType::setID(string p_ID) { - m_SPITTypeID = p_ID; - } - bool SPIT_Message::RemoveSPITType::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_SPITTypeID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - } - catch (...) { - return false; - } - return true; - } - +void SPIT_Message::ReportSPITType::initMembers() { + m_Confirmed = false; + m_SPITTypeID = ""; + m_Fixed = false; + m_ServerRemote = false; + m_ServerProjectIndepended = false; + m_SPITTypeGroupName = ""; + m_SPITTypeName = ""; + m_Delay = 0; + m_Duration = 0; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::ReportSPITType::~ReportSPITType() { +} +// Receive +SPIT_Message::ReportSPITType::ReportSPITType(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::ReportSPITType::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_Confirmed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_SPITTypeID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_Fixed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_ServerRemote = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_ServerProjectIndepended = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_SPITTypeGroupName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 39); + m_ParseOffset += 39; + m_SPITTypeName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_Delay = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_Duration = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::ReportSPITType::ReportSPITType() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::ReportSPITType::setConfirmed(bool p_Confirmed) { + m_Confirmed = p_Confirmed; +} +void SPIT_Message::ReportSPITType::setID(string p_ID) { + m_SPITTypeID = p_ID; +} +void SPIT_Message::ReportSPITType::setFixed(bool p_Fixed) { + m_Fixed = p_Fixed; +} +void SPIT_Message::ReportSPITType::setServerRemote(bool p_IsServerRemote) { + m_ServerRemote = p_IsServerRemote; +} +void SPIT_Message::ReportSPITType::setServerProjectIndepended(bool p_ProjectIndpended) { + m_ServerProjectIndepended = p_ProjectIndpended; +} +void SPIT_Message::ReportSPITType::setGroupName(string p_GroupName) { + m_SPITTypeGroupName = p_GroupName; +} +void SPIT_Message::ReportSPITType::setName(string p_Name) { + m_SPITTypeName = p_Name; +} +void SPIT_Message::ReportSPITType::setDelay(long long p_Delay) { + m_Delay = p_Delay; +} +void SPIT_Message::ReportSPITType::setDuration(long long p_Duration) { + m_Duration = p_Duration; +} +bool SPIT_Message::ReportSPITType::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = m_Header->BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_Confirmed, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_SPITTypeID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setBoolean(m_Fixed, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_ServerRemote, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_ServerProjectIndepended, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_SPITTypeGroupName, p_MessageBytes, p_ByteCount, m_ParseOffset, 39); + m_ParseOffset += setString(m_SPITTypeName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setLong(m_Delay, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setLong(m_Duration, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + +//----------- ReportSPITType ----------- + +void SPIT_Message::RemoveSPITType::initMembers() { + m_SPITTypeID = ""; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::RemoveSPITType::~RemoveSPITType() { +} +// Receive +SPIT_Message::RemoveSPITType::RemoveSPITType(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::RemoveSPITType::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_SPITTypeID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::RemoveSPITType::RemoveSPITType() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::RemoveSPITType::setID(string p_ID) { + m_SPITTypeID = p_ID; +} +bool SPIT_Message::RemoveSPITType::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_SPITTypeID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + } catch (...) { + return false; + } + return true; +} + //---------------------------- SPITObjects ---------------------------------- - + //----------- ReportSPITObject ----------- - void SPIT_Message::ReportSPITObject::initMembers() { - m_Confirmed = false; - m_SPITObjectID = ""; - m_Fixed = false; - m_ServerRemote = false; - m_SPITObjectName = ""; - m_SPITTypeID = ""; - m_ServerParams = ""; - m_FrameStart = 0; - m_FrameLength = 0; - m_FrameFadeInLength = 0; - m_FrameFadeOutLength = 0; - m_ValueFactor = 0; - m_ValueUse = VALUEUSE_DISCARD; - m_Track = 0; - m_Remark = ""; - m_Delay = 0; - m_Duration = 0; - m_ActionAssigned = false; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::ReportSPITObject::~ReportSPITObject() { - } - //Receive - SPIT_Message::ReportSPITObject::ReportSPITObject(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::ReportSPITObject::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_Confirmed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_Fixed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_ServerRemote = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_SPITObjectName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_SPITTypeID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_ServerParams = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_FrameStart = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_FrameLength = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_FrameFadeInLength = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_FrameFadeOutLength = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_ValueFactor = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_ValueUse = getByte(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_Track = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_Remark = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_Delay = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_Duration = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_ActionAssigned = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::ReportSPITObject::ReportSPITObject() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::ReportSPITObject::setConfirmed(bool p_Confirmed) { - m_Confirmed = p_Confirmed; - } - void SPIT_Message::ReportSPITObject::setID(string p_ID) { - m_SPITObjectID = p_ID; - } - void SPIT_Message::ReportSPITObject::setFixed(bool p_Fixed) { - m_Fixed = p_Fixed; - } - void SPIT_Message::ReportSPITObject::setServerRemote(bool p_IsRemote) { - m_ServerRemote = p_IsRemote; - } - void SPIT_Message::ReportSPITObject::setName(string p_Name) { - m_SPITObjectName = p_Name; - } - void SPIT_Message::ReportSPITObject::setSPITTypeID(string p_ID) { - m_SPITTypeID = p_ID; - } - void SPIT_Message::ReportSPITObject::setServerParams(string p_Parameters) { - m_ServerParams = p_Parameters; - } - void SPIT_Message::ReportSPITObject::setFrameStart(long long p_StartTime) { - m_FrameStart = p_StartTime; - } - void SPIT_Message::ReportSPITObject::setFrameLength(long long p_Length) { - m_FrameLength = p_Length; - } - void SPIT_Message::ReportSPITObject::setFrameFadeInLength(long long p_FadeInTime) { - m_FrameFadeInLength = p_FadeInTime; - } - void SPIT_Message::ReportSPITObject::setFrameFadeOutLength(long long p_FadeOutTime) { - m_FrameFadeOutLength = p_FadeOutTime; - } - void SPIT_Message::ReportSPITObject::setValueFactor(int p_Volume) { - m_ValueFactor = p_Volume; - } - void SPIT_Message::ReportSPITObject::setValueUse(char p_ValueUse) { - m_ValueUse = p_ValueUse; - } - void SPIT_Message::ReportSPITObject::setTrack(int p_Track) { - m_Track = p_Track; - } - void SPIT_Message::ReportSPITObject::setRemark(string p_Description) { - m_Remark = p_Description; - } - void SPIT_Message::ReportSPITObject::setDelay(long long p_Delay) { - if (p_Delay < 0) p_Delay = 0; - m_Delay = p_Delay; - } - void SPIT_Message::ReportSPITObject::setDuration(long long p_Duration) { - if (p_Duration < 0) p_Duration = 0; - m_Duration = p_Duration; - } - - void SPIT_Message::ReportSPITObject::setActionAssigned(bool p_ActionAssigned) { - m_ActionAssigned = p_ActionAssigned; - } - bool SPIT_Message::ReportSPITObject::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_Confirmed, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setBoolean(m_Fixed, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_ServerRemote, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_SPITObjectName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setString(m_SPITTypeID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setString(m_ServerParams, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setLong(m_FrameStart, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setLong(m_FrameLength, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setLong(m_FrameFadeInLength, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setLong(m_FrameFadeOutLength, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setInt(m_ValueFactor, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setByte(m_ValueUse, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setInt(m_Track, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_Remark, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setLong(m_Delay, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setLong(m_Duration, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_ActionAssigned, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } +void SPIT_Message::ReportSPITObject::initMembers() { + m_Confirmed = false; + m_SPITObjectID = ""; + m_Fixed = false; + m_ServerRemote = false; + m_SPITObjectName = ""; + m_SPITTypeID = ""; + m_ServerParams = ""; + m_FrameStart = 0; + m_FrameLength = 0; + m_FrameFadeInLength = 0; + m_FrameFadeOutLength = 0; + m_ValueFactor = 0; + m_ValueUse = VALUEUSE_DISCARD; + m_Track = 0; + m_Remark = ""; + m_Delay = 0; + m_Duration = 0; + m_ActionAssigned = false; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::ReportSPITObject::~ReportSPITObject() { +} +// Receive +SPIT_Message::ReportSPITObject::ReportSPITObject(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::ReportSPITObject::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_Confirmed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_Fixed = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_ServerRemote = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_SPITObjectName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_SPITTypeID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_ServerParams = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_FrameStart = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_FrameLength = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_FrameFadeInLength = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_FrameFadeOutLength = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_ValueFactor = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_ValueUse = getByte(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_Track = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_Remark = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_Delay = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_Duration = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_ActionAssigned = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::ReportSPITObject::ReportSPITObject() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::ReportSPITObject::setConfirmed(bool p_Confirmed) { + m_Confirmed = p_Confirmed; +} +void SPIT_Message::ReportSPITObject::setID(string p_ID) { + m_SPITObjectID = p_ID; +} +void SPIT_Message::ReportSPITObject::setFixed(bool p_Fixed) { + m_Fixed = p_Fixed; +} +void SPIT_Message::ReportSPITObject::setServerRemote(bool p_IsRemote) { + m_ServerRemote = p_IsRemote; +} +void SPIT_Message::ReportSPITObject::setName(string p_Name) { + m_SPITObjectName = p_Name; +} +void SPIT_Message::ReportSPITObject::setSPITTypeID(string p_ID) { + m_SPITTypeID = p_ID; +} +void SPIT_Message::ReportSPITObject::setServerParams(string p_Parameters) { + m_ServerParams = p_Parameters; +} +void SPIT_Message::ReportSPITObject::setFrameStart(long long p_StartTime) { + m_FrameStart = p_StartTime; +} +void SPIT_Message::ReportSPITObject::setFrameLength(long long p_Length) { + m_FrameLength = p_Length; +} +void SPIT_Message::ReportSPITObject::setFrameFadeInLength(long long p_FadeInTime) { + m_FrameFadeInLength = p_FadeInTime; +} +void SPIT_Message::ReportSPITObject::setFrameFadeOutLength(long long p_FadeOutTime) { + m_FrameFadeOutLength = p_FadeOutTime; +} +void SPIT_Message::ReportSPITObject::setValueFactor(int p_Volume) { + m_ValueFactor = p_Volume; +} +void SPIT_Message::ReportSPITObject::setValueUse(char p_ValueUse) { + m_ValueUse = p_ValueUse; +} +void SPIT_Message::ReportSPITObject::setTrack(int p_Track) { + m_Track = p_Track; +} +void SPIT_Message::ReportSPITObject::setRemark(string p_Description) { + m_Remark = p_Description; +} +void SPIT_Message::ReportSPITObject::setDelay(long long p_Delay) { + if (p_Delay < 0) + p_Delay = 0; + m_Delay = p_Delay; +} +void SPIT_Message::ReportSPITObject::setDuration(long long p_Duration) { + if (p_Duration < 0) + p_Duration = 0; + m_Duration = p_Duration; +} + +void SPIT_Message::ReportSPITObject::setActionAssigned(bool p_ActionAssigned) { + m_ActionAssigned = p_ActionAssigned; +} +bool SPIT_Message::ReportSPITObject::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_Confirmed, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setBoolean(m_Fixed, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_ServerRemote, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_SPITObjectName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setString(m_SPITTypeID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setString(m_ServerParams, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setLong(m_FrameStart, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setLong(m_FrameLength, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setLong(m_FrameFadeInLength, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setLong(m_FrameFadeOutLength, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setInt(m_ValueFactor, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setByte(m_ValueUse, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setInt(m_Track, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_Remark, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setLong(m_Delay, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setLong(m_Duration, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_ActionAssigned, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} //----------- RemoveSPITObject ----------- - void SPIT_Message::RemoveSPITObject::initMembers() { - m_SPITObjectID = ""; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::RemoveSPITObject::~RemoveSPITObject() { - } - //Receive - SPIT_Message::RemoveSPITObject::RemoveSPITObject(Header* p_Header) : OPPart(p_Header, OPFLAG) { - initMembers(); - } - bool SPIT_Message::RemoveSPITObject::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - } - catch (...) { - return false; - } - return true; - } - - // Send - SPIT_Message::RemoveSPITObject::RemoveSPITObject() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::RemoveSPITObject::setID(string p_ID) { - m_SPITObjectID = p_ID; - } - bool SPIT_Message::RemoveSPITObject::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - } - catch (...) { - return false; - } - return true; - } - +void SPIT_Message::RemoveSPITObject::initMembers() { + m_SPITObjectID = ""; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::RemoveSPITObject::~RemoveSPITObject() { +} +// Receive +SPIT_Message::RemoveSPITObject::RemoveSPITObject(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::RemoveSPITObject::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::RemoveSPITObject::RemoveSPITObject() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::RemoveSPITObject::setID(string p_ID) { + m_SPITObjectID = p_ID; +} +bool SPIT_Message::RemoveSPITObject::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + } catch (...) { + return false; + } + return true; +} + //---------------------------- SPITPlayer ---------------------------------- - + //----------- PlaySPITStart ----------- - void SPIT_Message::PlaySPITStart::initMembers() { - m_PlayerID = ""; - m_PlayerName = ""; - m_PlayerType = 0x00; - m_Time = 0; - m_PlayerIsRunning = false; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::PlaySPITStart::~PlaySPITStart() { - } - //Receive - SPIT_Message::PlaySPITStart::PlaySPITStart(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::PlaySPITStart::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_PlayerID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_PlayerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += 64; - m_PlayerType = getByte(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_PlayerIsRunning = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_Time = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset+= 8; - } - catch (...) { - return false; - } - return true; - } - - // Send - SPIT_Message::PlaySPITStart::PlaySPITStart() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::PlaySPITStart::setPlayerID(string p_PlayerID) { - m_PlayerID = p_PlayerID; - } - void SPIT_Message::PlaySPITStart::setPlayerName(string p_PlayerName) { - m_PlayerName = p_PlayerName; - } - void SPIT_Message::PlaySPITStart::setPlayerType(char p_PlayerType) { - m_PlayerType = p_PlayerType; - } - void SPIT_Message::PlaySPITStart::setPlayerIsRunning(bool p_IsPlaying) { - m_PlayerIsRunning = p_IsPlaying; - } - void SPIT_Message::PlaySPITStart::setTime(long long p_Time) { - m_Time = p_Time; - } - bool SPIT_Message::PlaySPITStart::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_PlayerID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setString(m_PlayerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); - m_ParseOffset += setByte(m_PlayerType, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_PlayerIsRunning, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setLong(m_Time, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - +void SPIT_Message::PlaySPITStart::initMembers() { + m_PlayerID = ""; + m_PlayerName = ""; + m_PlayerType = 0x00; + m_Time = 0; + m_PlayerIsRunning = false; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::PlaySPITStart::~PlaySPITStart() { +} +// Receive +SPIT_Message::PlaySPITStart::PlaySPITStart(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::PlaySPITStart::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_PlayerID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_PlayerName = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += 64; + m_PlayerType = getByte(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_PlayerIsRunning = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_Time = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + } catch (...) { + return false; + } + return true; +} + +// Send +SPIT_Message::PlaySPITStart::PlaySPITStart() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::PlaySPITStart::setPlayerID(string p_PlayerID) { + m_PlayerID = p_PlayerID; +} +void SPIT_Message::PlaySPITStart::setPlayerName(string p_PlayerName) { + m_PlayerName = p_PlayerName; +} +void SPIT_Message::PlaySPITStart::setPlayerType(char p_PlayerType) { + m_PlayerType = p_PlayerType; +} +void SPIT_Message::PlaySPITStart::setPlayerIsRunning(bool p_IsPlaying) { + m_PlayerIsRunning = p_IsPlaying; +} +void SPIT_Message::PlaySPITStart::setTime(long long p_Time) { + m_Time = p_Time; +} +bool SPIT_Message::PlaySPITStart::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_PlayerID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setString(m_PlayerName, p_MessageBytes, p_ByteCount, m_ParseOffset, 64); + m_ParseOffset += setByte(m_PlayerType, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_PlayerIsRunning, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setLong(m_Time, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + //----------- PlaySPITObject ----------- - void SPIT_Message::PlaySPITObject::initMembers() { - m_PlayerID = ""; - m_SPITObjectID = ""; - m_FrameInsideObject = 0; - m_Value = 0; - m_ValueFlag = VALUEFLAG_DIRECT; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::PlaySPITObject::~PlaySPITObject() { - } - //Receive - SPIT_Message::PlaySPITObject::PlaySPITObject(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::PlaySPITObject::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_PlayerID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_FrameInsideObject = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_PlayPrePosition = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - m_Value = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_ValueFlag = getByte(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 1; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::PlaySPITObject::PlaySPITObject() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - void SPIT_Message::PlaySPITObject::setPlayerID(string p_PlayerID) { - m_PlayerID = p_PlayerID; - } - void SPIT_Message::PlaySPITObject::setID(string p_ID) { - m_SPITObjectID = p_ID; - } - void SPIT_Message::PlaySPITObject::setFrameInsideObject(long long p_TimeInside) { - m_FrameInsideObject = p_TimeInside; - } - void SPIT_Message::PlaySPITObject::setPlayPrePosition(bool p_PlayOldPosition) { - m_PlayPrePosition = p_PlayOldPosition; - } - void SPIT_Message::PlaySPITObject::setValue(int p_Value) { - m_Value = p_Value; - } - void SPIT_Message::PlaySPITObject::setValueFlag(char p_ValueFlag) { - m_ValueFlag = p_ValueFlag; - } - bool SPIT_Message::PlaySPITObject::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_PlayerID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setLong(m_FrameInsideObject, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setBoolean(m_PlayPrePosition, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setInt(m_Value, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setByte(m_ValueFlag, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - +void SPIT_Message::PlaySPITObject::initMembers() { + m_PlayerID = ""; + m_SPITObjectID = ""; + m_FrameInsideObject = 0; + m_Value = 0; + m_ValueFlag = VALUEFLAG_DIRECT; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::PlaySPITObject::~PlaySPITObject() { +} +// Receive +SPIT_Message::PlaySPITObject::PlaySPITObject(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::PlaySPITObject::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_PlayerID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_FrameInsideObject = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_PlayPrePosition = getBoolean(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + m_Value = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_ValueFlag = getByte(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 1; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::PlaySPITObject::PlaySPITObject() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} +void SPIT_Message::PlaySPITObject::setPlayerID(string p_PlayerID) { + m_PlayerID = p_PlayerID; +} +void SPIT_Message::PlaySPITObject::setID(string p_ID) { + m_SPITObjectID = p_ID; +} +void SPIT_Message::PlaySPITObject::setFrameInsideObject(long long p_TimeInside) { + m_FrameInsideObject = p_TimeInside; +} +void SPIT_Message::PlaySPITObject::setPlayPrePosition(bool p_PlayOldPosition) { + m_PlayPrePosition = p_PlayOldPosition; +} +void SPIT_Message::PlaySPITObject::setValue(int p_Value) { + m_Value = p_Value; +} +void SPIT_Message::PlaySPITObject::setValueFlag(char p_ValueFlag) { + m_ValueFlag = p_ValueFlag; +} +bool SPIT_Message::PlaySPITObject::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_PlayerID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setLong(m_FrameInsideObject, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setBoolean(m_PlayPrePosition, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setInt(m_Value, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setByte(m_ValueFlag, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + //----------- PlaySPITEnd ----------- - void SPIT_Message::PlaySPITEnd::initMembers() { - m_PlayerID = ""; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::PlaySPITEnd::~PlaySPITEnd() { - } - //Receive - SPIT_Message::PlaySPITEnd::PlaySPITEnd(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::PlaySPITEnd::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_PlayerID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::PlaySPITEnd::PlaySPITEnd() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::PlaySPITEnd::setPlayerID(string p_PlayerID) { - m_PlayerID = p_PlayerID; - } - bool SPIT_Message::PlaySPITEnd::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_PlayerID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - } - catch (...) { - return false; - } - return true; - } +void SPIT_Message::PlaySPITEnd::initMembers() { + m_PlayerID = ""; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::PlaySPITEnd::~PlaySPITEnd() { +} +// Receive +SPIT_Message::PlaySPITEnd::PlaySPITEnd(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::PlaySPITEnd::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_PlayerID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::PlaySPITEnd::PlaySPITEnd() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::PlaySPITEnd::setPlayerID(string p_PlayerID) { + m_PlayerID = p_PlayerID; +} +bool SPIT_Message::PlaySPITEnd::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_PlayerID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + } catch (...) { + return false; + } + return true; +} //----------- ReportPlayStatus ----------- - - void SPIT_Message::ReportPlayStatus::initMembers() { - m_SPITObjectID = ""; - m_FrameInsideObject = 0; - m_Value = 0; - m_BytesCount = BYTESLENGTH; - } - SPIT_Message::ReportPlayStatus::~ReportPlayStatus() { - } - //Receive - SPIT_Message::ReportPlayStatus::ReportPlayStatus(Header* p_Header) : OPPart(p_Header, OPFLAG){ - initMembers(); - } - bool SPIT_Message::ReportPlayStatus::parse(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - int intOPFlag = m_Header->getOPFlag(); - if (intOPFlag != OPFLAG) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += 41; - m_FrameInsideObject = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 8; - m_Value = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += 4; - } - catch (...) { - return false; - } - return true; - } - // Send - SPIT_Message::ReportPlayStatus::ReportPlayStatus() : OPPart() { - initMembers(); - m_Header = new Header(SPITVERSION, OPFLAG); - setHeader(m_Header); - m_ParseOffset = Header::BYTESLENGTH; - } - - void SPIT_Message::ReportPlayStatus::setID(string p_ID) { - m_SPITObjectID = p_ID; - } - void SPIT_Message::ReportPlayStatus::setFrameInsideObject(long long p_TimeInside) { - m_FrameInsideObject = p_TimeInside; - } - void SPIT_Message::ReportPlayStatus::setValue(int p_Value) { - m_Value = p_Value; - } - bool SPIT_Message::ReportPlayStatus::fillBytes(char* p_MessageBytes, int p_ByteCount) { - if (p_MessageBytes == NULL) return false; - if (m_Header == NULL) return false; - if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) return false; - try { - m_ParseOffset = Header::BYTESLENGTH; - m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); - m_ParseOffset += setLong(m_FrameInsideObject, p_MessageBytes, p_ByteCount, m_ParseOffset); - m_ParseOffset += setInt(m_Value, p_MessageBytes, p_ByteCount, m_ParseOffset); - } - catch (...) { - return false; - } - return true; - } - - + +void SPIT_Message::ReportPlayStatus::initMembers() { + m_SPITObjectID = ""; + m_FrameInsideObject = 0; + m_Value = 0; + m_BytesCount = BYTESLENGTH; +} +SPIT_Message::ReportPlayStatus::~ReportPlayStatus() { +} +// Receive +SPIT_Message::ReportPlayStatus::ReportPlayStatus(Header *p_Header) : OPPart(p_Header, OPFLAG) { + initMembers(); +} +bool SPIT_Message::ReportPlayStatus::parse(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + int intOPFlag = m_Header->getOPFlag(); + if (intOPFlag != OPFLAG) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_BytesCount = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + m_SPITObjectID = getString(p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += 41; + m_FrameInsideObject = getLong(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 8; + m_Value = getInt(p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += 4; + } catch (...) { + return false; + } + return true; +} +// Send +SPIT_Message::ReportPlayStatus::ReportPlayStatus() : OPPart() { + initMembers(); + m_Header = new Header(SPITVERSION, OPFLAG); + setHeader(m_Header); + m_ParseOffset = Header::BYTESLENGTH; +} + +void SPIT_Message::ReportPlayStatus::setID(string p_ID) { + m_SPITObjectID = p_ID; +} +void SPIT_Message::ReportPlayStatus::setFrameInsideObject(long long p_TimeInside) { + m_FrameInsideObject = p_TimeInside; +} +void SPIT_Message::ReportPlayStatus::setValue(int p_Value) { + m_Value = p_Value; +} +bool SPIT_Message::ReportPlayStatus::fillBytes(char *p_MessageBytes, int p_ByteCount) { + if (p_MessageBytes == NULL) + return false; + if (m_Header == NULL) + return false; + if (m_Header->fillBytes(p_MessageBytes, p_ByteCount) == false) + return false; + try { + m_ParseOffset = Header::BYTESLENGTH; + m_ParseOffset += setInt(m_BytesCount, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setString(m_SPITObjectID, p_MessageBytes, p_ByteCount, m_ParseOffset, 41); + m_ParseOffset += setLong(m_FrameInsideObject, p_MessageBytes, p_ByteCount, m_ParseOffset); + m_ParseOffset += setInt(m_Value, p_MessageBytes, p_ByteCount, m_ParseOffset); + } catch (...) { + return false; + } + return true; +} + //---------------------------- static helper functions ----------------------- - bool SPIT_Message::isSystemLittleEndian() { - // todo replace with #include then if constexpr (std::endian::native == std::endian::big) - int intOne = 1; - char* firstByte; - firstByte = (char*)&intOne; - if (*firstByte > 0) { - return false; - } - return true; - } - - int SPIT_Message::getInt(char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_received"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 4) throw "ParseError_received"; - //low byte first - int intValue = 0; - if (isSystemLittleEndian() == false) { - intValue += ((p_Bytes[p_Offset+0] & 0x000000ff)); - intValue += ((p_Bytes[p_Offset+1] & 0x000000ff)<<8); - intValue += ((p_Bytes[p_Offset+2] & 0x000000ff)<<16); - intValue += ((p_Bytes[p_Offset+3] & 0x000000ff)<<24); - } - else { - intValue += ((p_Bytes[p_Offset+3] & 0x000000ff)); - intValue += ((p_Bytes[p_Offset+2] & 0x000000ff)<<8); - intValue += ((p_Bytes[p_Offset+1] & 0x000000ff)<<16); - intValue += ((p_Bytes[p_Offset+0] & 0x000000ff)<<24); - } - return intValue; - } +bool SPIT_Message::isSystemLittleEndian() { + // todo replace with #include then if constexpr (std::endian::native == std::endian::big) + int intOne = 1; + char *firstByte; + firstByte = (char *)&intOne; + if (*firstByte > 0) { + return false; + } + return true; +} - int SPIT_Message::setInt(int p_Value, char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_send"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 4) throw "ParseError_send"; - //low byte first - int intTest; - if (isSystemLittleEndian() == false) { - p_Bytes[p_Offset+0] = (char)(p_Value & 0x000000ff); - p_Bytes[p_Offset+1] = (char)((p_Value & 0x0000ff00)>>8); - p_Bytes[p_Offset+2] = (char)((p_Value & 0x00ff0000)>>16); - p_Bytes[p_Offset+3] = (char)((p_Value & 0xff000000)>>24); - - intTest = getInt(p_Bytes, p_ByteCount, p_Offset); - } - else { - p_Bytes[p_Offset+3] = (char)(p_Value & 0x000000ff); - p_Bytes[p_Offset+2] = (char)((p_Value & 0x0000ff00)>>8); - p_Bytes[p_Offset+1] = (char)((p_Value & 0x00ff0000)>>16); - p_Bytes[p_Offset+0] = (char)((p_Value & 0xff000000)>>24); +int SPIT_Message::getInt(char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_received"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 4) + throw "ParseError_received"; + // low byte first + int intValue = 0; + if (isSystemLittleEndian() == false) { + intValue += ((p_Bytes[p_Offset + 0] & 0x000000ff)); + intValue += ((p_Bytes[p_Offset + 1] & 0x000000ff) << 8); + intValue += ((p_Bytes[p_Offset + 2] & 0x000000ff) << 16); + intValue += ((p_Bytes[p_Offset + 3] & 0x000000ff) << 24); + } else { + intValue += ((p_Bytes[p_Offset + 3] & 0x000000ff)); + intValue += ((p_Bytes[p_Offset + 2] & 0x000000ff) << 8); + intValue += ((p_Bytes[p_Offset + 1] & 0x000000ff) << 16); + intValue += ((p_Bytes[p_Offset + 0] & 0x000000ff) << 24); + } + return intValue; +} - intTest = getInt(p_Bytes, p_ByteCount, p_Offset); - } - return 4; - } - long long SPIT_Message::getLong(char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_received"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 8) throw "ParseError_received"; - //low byte first - long long intValue = 0; - if (isSystemLittleEndian() == false) { - intValue += ((long long)(p_Bytes[p_Offset] & 0x000000ff)); - intValue += ((long long)(p_Bytes[p_Offset+1] & 0x000000ff)<<8); - intValue += ((long long)(p_Bytes[p_Offset+2] & 0x000000ff)<<16); - intValue += ((long long)(p_Bytes[p_Offset+3] & 0x000000ff)<<24); - intValue += ((long long)(p_Bytes[p_Offset+4] & 0x000000ff)<<32); - intValue += ((long long)(p_Bytes[p_Offset+5] & 0x000000ff)<<40); - intValue += ((long long)(p_Bytes[p_Offset+6] & 0x000000ff)<<48); - intValue += ((long long)(p_Bytes[p_Offset+7] & 0x000000ff)<<56); - } - else { - intValue += ((long long)(p_Bytes[p_Offset+7] & 0x000000ff)); - intValue += ((long long)(p_Bytes[p_Offset+6] & 0x000000ff)<<8); - intValue += ((long long)(p_Bytes[p_Offset+5] & 0x000000ff)<<16); - intValue += ((long long)(p_Bytes[p_Offset+4] & 0x000000ff)<<24); - intValue += ((long long)(p_Bytes[p_Offset+3] & 0x000000ff)<<32); - intValue += ((long long)(p_Bytes[p_Offset+2] & 0x000000ff)<<40); - intValue += ((long long)(p_Bytes[p_Offset+1] & 0x000000ff)<<48); - intValue += ((long long)(p_Bytes[p_Offset+0] & 0x000000ff)<<56); - } - return intValue; - } - int SPIT_Message::setLong(long long p_Value, char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_send"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 8) throw "ParseError_send"; - //low byte first - if (isSystemLittleEndian() == false) { - p_Bytes[p_Offset+0] = (char)((p_Value & 0x00000000000000ff)); - p_Bytes[p_Offset+1] = (char)((p_Value & 0x000000000000ff00)>>8); - p_Bytes[p_Offset+2] = (char)((p_Value & 0x0000000000ff0000)>>16); - p_Bytes[p_Offset+3] = (char)((p_Value & 0x00000000ff000000)>>24); - p_Bytes[p_Offset+4] = (char)((p_Value & 0x000000ff00000000)>>32); - p_Bytes[p_Offset+5] = (char)((p_Value & 0x0000ff0000000000)>>40); - p_Bytes[p_Offset+6] = (char)((p_Value & 0x00ff000000000000)>>48); - p_Bytes[p_Offset+7] = (char)((p_Value & 0xff00000000000000)>>56); - } - else { - p_Bytes[p_Offset+7] = (char)((p_Value & 0x00000000000000ff)); - p_Bytes[p_Offset+6] = (char)((p_Value & 0x000000000000ff00)>>8); - p_Bytes[p_Offset+5] = (char)((p_Value & 0x0000000000ff0000)>>16); - p_Bytes[p_Offset+4] = (char)((p_Value & 0x00000000ff000000)>>24); - p_Bytes[p_Offset+3] = (char)((p_Value & 0x000000ff00000000)>>32); - p_Bytes[p_Offset+2] = (char)((p_Value & 0x0000ff0000000000)>>40); - p_Bytes[p_Offset+1] = (char)((p_Value & 0x00ff000000000000)>>48); - p_Bytes[p_Offset+0] = (char)((p_Value & 0xff00000000000000)>>56); - } - return 8; - } - bool SPIT_Message::getBoolean(char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_received"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) throw "ParseError_received"; - //low byte first - if (p_Bytes[p_Offset] > 0x00) return true; - else return false; - } - int SPIT_Message::setBoolean(bool p_Value, char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_send"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) throw "ParseError_send"; - if (p_Value == false) { - p_Bytes[p_Offset] = 0x00; - } - else { - p_Bytes[p_Offset] = 0x01; - } - return 1; - } - char SPIT_Message::getByte(char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_received"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) throw "ParseError_received"; - //low byte first - return p_Bytes[p_Offset]; - } - int SPIT_Message::setByte(int p_Value, char* p_Bytes, int p_ByteCount, int p_Offset) { - if (p_Offset < 0) throw "ParseError_send"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) throw "ParseError_send"; - p_Bytes[p_Offset] = (char)(p_Value & 0xff); - return 1; - } - string SPIT_Message::getString(char* p_Bytes, int p_ByteCount, int p_Offset, int p_Length) { - if (p_Offset < 0) throw "ParseError_received getString()"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + p_Length) throw "ParseError_received getString()"; - int intPos; - //get Length of String - for (intPos = 0; intPos < p_Length; intPos++) { - if (p_Bytes[p_Offset + intPos] == 0x00) break; - } - if (intPos >= p_Length) throw "ParseError_received getString()"; - string stringResult; - stringResult = &p_Bytes[p_Offset]; - return stringResult; - } - - int SPIT_Message::setString(string p_String, char* p_Bytes, int p_ByteCount, int p_Offset, int p_Length) { - if (p_Offset < 0) throw "ParseError_send"; - int intChar = 0; - bool boolNullChar = false; - if (p_Length < 1) throw "ParseError_send"; - if (p_Bytes == NULL || p_ByteCount < p_Offset + p_Length) throw "ParseError_send"; - - int intLength; - if (p_String.length()+1 > p_Length) { - intLength = p_Length; - } - else { - intLength = p_String.length()+1; - } - while(intChar < intLength) { - p_Bytes[p_Offset + intChar] = p_String.data()[intChar]; - if (p_String[intChar] == nullChar[0]) { - boolNullChar = true; - break; - } - intChar++; - } - if (boolNullChar == false) { - p_Bytes[p_Offset + intLength -1] = nullChar[0]; - } - return p_Length; - } - - - - char* SPIT_Message::createByteArray(const OPPart* p_OPPart, int* p_ByteCount) { - if (p_OPPart == NULL) return NULL; - int intBytesCount = 0; - char* o_ByteArray; - try { - intBytesCount = Header::BYTESLENGTH; - intBytesCount += p_OPPart->getBytesCount(); - o_ByteArray = (char*) malloc(intBytesCount); - *p_ByteCount = intBytesCount; - } - catch (...) { - return NULL; - } - return o_ByteArray; - } +int SPIT_Message::setInt(int p_Value, char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_send"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 4) + throw "ParseError_send"; + // low byte first + int intTest; + if (isSystemLittleEndian() == false) { + p_Bytes[p_Offset + 0] = (char)(p_Value & 0x000000ff); + p_Bytes[p_Offset + 1] = (char)((p_Value & 0x0000ff00) >> 8); + p_Bytes[p_Offset + 2] = (char)((p_Value & 0x00ff0000) >> 16); + p_Bytes[p_Offset + 3] = (char)((p_Value & 0xff000000) >> 24); + + intTest = getInt(p_Bytes, p_ByteCount, p_Offset); + } else { + p_Bytes[p_Offset + 3] = (char)(p_Value & 0x000000ff); + p_Bytes[p_Offset + 2] = (char)((p_Value & 0x0000ff00) >> 8); + p_Bytes[p_Offset + 1] = (char)((p_Value & 0x00ff0000) >> 16); + p_Bytes[p_Offset + 0] = (char)((p_Value & 0xff000000) >> 24); + + intTest = getInt(p_Bytes, p_ByteCount, p_Offset); + } + return 4; +} +long long SPIT_Message::getLong(char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_received"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 8) + throw "ParseError_received"; + // low byte first + long long intValue = 0; + if (isSystemLittleEndian() == false) { + intValue += ((long long)(p_Bytes[p_Offset] & 0x000000ff)); + intValue += ((long long)(p_Bytes[p_Offset + 1] & 0x000000ff) << 8); + intValue += ((long long)(p_Bytes[p_Offset + 2] & 0x000000ff) << 16); + intValue += ((long long)(p_Bytes[p_Offset + 3] & 0x000000ff) << 24); + intValue += ((long long)(p_Bytes[p_Offset + 4] & 0x000000ff) << 32); + intValue += ((long long)(p_Bytes[p_Offset + 5] & 0x000000ff) << 40); + intValue += ((long long)(p_Bytes[p_Offset + 6] & 0x000000ff) << 48); + intValue += ((long long)(p_Bytes[p_Offset + 7] & 0x000000ff) << 56); + } else { + intValue += ((long long)(p_Bytes[p_Offset + 7] & 0x000000ff)); + intValue += ((long long)(p_Bytes[p_Offset + 6] & 0x000000ff) << 8); + intValue += ((long long)(p_Bytes[p_Offset + 5] & 0x000000ff) << 16); + intValue += ((long long)(p_Bytes[p_Offset + 4] & 0x000000ff) << 24); + intValue += ((long long)(p_Bytes[p_Offset + 3] & 0x000000ff) << 32); + intValue += ((long long)(p_Bytes[p_Offset + 2] & 0x000000ff) << 40); + intValue += ((long long)(p_Bytes[p_Offset + 1] & 0x000000ff) << 48); + intValue += ((long long)(p_Bytes[p_Offset + 0] & 0x000000ff) << 56); + } + return intValue; +} +int SPIT_Message::setLong(long long p_Value, char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_send"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 8) + throw "ParseError_send"; + // low byte first + if (isSystemLittleEndian() == false) { + p_Bytes[p_Offset + 0] = (char)((p_Value & 0x00000000000000ff)); + p_Bytes[p_Offset + 1] = (char)((p_Value & 0x000000000000ff00) >> 8); + p_Bytes[p_Offset + 2] = (char)((p_Value & 0x0000000000ff0000) >> 16); + p_Bytes[p_Offset + 3] = (char)((p_Value & 0x00000000ff000000) >> 24); + p_Bytes[p_Offset + 4] = (char)((p_Value & 0x000000ff00000000) >> 32); + p_Bytes[p_Offset + 5] = (char)((p_Value & 0x0000ff0000000000) >> 40); + p_Bytes[p_Offset + 6] = (char)((p_Value & 0x00ff000000000000) >> 48); + p_Bytes[p_Offset + 7] = (char)((p_Value & 0xff00000000000000) >> 56); + } else { + p_Bytes[p_Offset + 7] = (char)((p_Value & 0x00000000000000ff)); + p_Bytes[p_Offset + 6] = (char)((p_Value & 0x000000000000ff00) >> 8); + p_Bytes[p_Offset + 5] = (char)((p_Value & 0x0000000000ff0000) >> 16); + p_Bytes[p_Offset + 4] = (char)((p_Value & 0x00000000ff000000) >> 24); + p_Bytes[p_Offset + 3] = (char)((p_Value & 0x000000ff00000000) >> 32); + p_Bytes[p_Offset + 2] = (char)((p_Value & 0x0000ff0000000000) >> 40); + p_Bytes[p_Offset + 1] = (char)((p_Value & 0x00ff000000000000) >> 48); + p_Bytes[p_Offset + 0] = (char)((p_Value & 0xff00000000000000) >> 56); + } + return 8; +} +bool SPIT_Message::getBoolean(char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_received"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) + throw "ParseError_received"; + // low byte first + if (p_Bytes[p_Offset] > 0x00) + return true; + else + return false; +} +int SPIT_Message::setBoolean(bool p_Value, char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_send"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) + throw "ParseError_send"; + if (p_Value == false) { + p_Bytes[p_Offset] = 0x00; + } else { + p_Bytes[p_Offset] = 0x01; + } + return 1; +} +char SPIT_Message::getByte(char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_received"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) + throw "ParseError_received"; + // low byte first + return p_Bytes[p_Offset]; +} +int SPIT_Message::setByte(int p_Value, char *p_Bytes, int p_ByteCount, int p_Offset) { + if (p_Offset < 0) + throw "ParseError_send"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + 1) + throw "ParseError_send"; + p_Bytes[p_Offset] = (char)(p_Value & 0xff); + return 1; +} +string SPIT_Message::getString(char *p_Bytes, int p_ByteCount, int p_Offset, int p_Length) { + if (p_Offset < 0) + throw "ParseError_received getString()"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + p_Length) + throw "ParseError_received getString()"; + int intPos; + // get Length of String + for (intPos = 0; intPos < p_Length; intPos++) { + if (p_Bytes[p_Offset + intPos] == 0x00) + break; + } + if (intPos >= p_Length) + throw "ParseError_received getString()"; + string stringResult; + stringResult = &p_Bytes[p_Offset]; + return stringResult; +} + +int SPIT_Message::setString(string p_String, char *p_Bytes, int p_ByteCount, int p_Offset, int p_Length) { + if (p_Offset < 0) + throw "ParseError_send"; + int intChar = 0; + bool boolNullChar = false; + if (p_Length < 1) + throw "ParseError_send"; + if (p_Bytes == NULL || p_ByteCount < p_Offset + p_Length) + throw "ParseError_send"; + + int intLength; + if (p_String.length() + 1 > p_Length) { + intLength = p_Length; + } else { + intLength = p_String.length() + 1; + } + while (intChar < intLength) { + p_Bytes[p_Offset + intChar] = p_String.data()[intChar]; + if (p_String[intChar] == nullChar[0]) { + boolNullChar = true; + break; + } + intChar++; + } + if (boolNullChar == false) { + p_Bytes[p_Offset + intLength - 1] = nullChar[0]; + } + return p_Length; +} + +char *SPIT_Message::createByteArray(const OPPart *p_OPPart, int *p_ByteCount) { + if (p_OPPart == NULL) + return NULL; + int intBytesCount = 0; + char *o_ByteArray; + try { + intBytesCount = Header::BYTESLENGTH; + intBytesCount += p_OPPart->getBytesCount(); + o_ByteArray = (char *)malloc(intBytesCount); + *p_ByteCount = intBytesCount; + } catch (...) { + return NULL; + } + return o_ByteArray; +} diff --git a/components/watchFace/CMakeLists.txt b/components/watchFace/CMakeLists.txt new file mode 100644 index 0000000..8af9e6b --- /dev/null +++ b/components/watchFace/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register( + INCLUDE_DIRS "." + REQUIRES devHal +) diff --git a/components/watchFace/watchFace.hpp b/components/watchFace/watchFace.hpp new file mode 100644 index 0000000..c7ceca3 --- /dev/null +++ b/components/watchFace/watchFace.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "StepperDrv8833.hpp" +#include "stepperMotor.hpp" +#include + +class WatchMotor { + static constexpr uint8_t Positions = 6; + + public: + WatchMotor(StepperMotor &stepper, OutputPort &sleep) + : _stepper(stepper), + _motorSleep(sleep) { + _motorSleep.write(false); + } + + void moveTo(uint8_t sign, uint8_t profile = 0) { + sign = sign % 6; + + float delta = 2.0F * std::numbers::pi; + float corr = 0.0F; + float currentPos = _stepper.getScaledPos() * 6; + if ((_currentIndex > 4) && (currentPos < 2)) { + corr = 6 - _currentIndex - currentPos; + } else if ((_currentIndex < 2) && (currentPos > 2)) { + corr = _currentIndex + 6 - currentPos; + } else { + corr = _currentIndex - currentPos; + } + + // stepper.getScaledPos() * 6 + if (_currentIndex < sign) { + delta = delta / 6 * (sign - _currentIndex); + } else if (_currentIndex > sign) { + delta = delta / 6 * (sign + 6 - _currentIndex); + } + ESP_LOGD("MV", "Moving to %d by %.2f + %.2f", sign, delta, corr); + + _stepper.moveBy(delta + corr, profile); + _currentIndex = sign; + } + + float getScaled() { return _stepper.getScaledPos() * 6; } + uint8_t getIndex() { return _currentIndex; } + + private: + StepperMotor &_stepper; + OutputPort &_motorSleep; + uint8_t _currentIndex{}; +}; diff --git a/core b/core index 3041a17..c85bfa2 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 3041a17851ae8a9ddfe420134affa5517edb52c2 +Subproject commit c85bfa2afc665dbfc2b80af81e4919f613001ed4 diff --git a/doc/InitRun.md b/doc/InitRun.md new file mode 100644 index 0000000..c4538e5 --- /dev/null +++ b/doc/InitRun.md @@ -0,0 +1,312 @@ +I (23) boot: ESP-IDF v5.3 2nd stage bootloader +I (24) boot: compile time Feb 15 2025 17:51:30 +I (24) boot: chip revision: v0.0 +I (26) boot.esp32c6: SPI Speed : 80MHz +I (31) boot.esp32c6: SPI Mode : DIO +I (36) boot.esp32c6: SPI Flash Size : 8MB +I (41) boot: Enabling RNG early entropy source... +I (46) boot: Partition Table: +I (50) boot: ## Label Usage Type ST Offset Length +I (57) boot: 0 nvs WiFi data 01 02 00009000 00006000 +I (64) boot: 1 phy_init RF data 01 01 0000f000 00001000 +I (72) boot: 2 factory factory app 00 00 00010000 00100000 +I (79) boot: End of partition table +I (83) esp_image: segment 0: paddr=00010020 vaddr=42070020 size=29b54h (170836) map +I (127) esp_image: segment 1: paddr=00039b7c vaddr=40800000 size=0649ch ( 25756) load +I (134) esp_image: segment 2: paddr=00040020 vaddr=42000020 size=6a434h (435252) map +I (225) esp_image: segment 3: paddr=000aa45c vaddr=4080649c size=07d28h ( 32040) load +I (233) esp_image: segment 4: paddr=000b218c vaddr=4080e1d0 size=01c00h ( 7168) load +I (239) boot: Loaded app from partition at offset 0x10000 +I (239) boot: Disabling RNG early entropy source... +I (253) cpu_start: Unicore app +I (262) cpu_start: Pro cpu start user code +I (262) cpu_start: cpu freq: 160000000 Hz +I (263) app_init: Application information: +I (265) app_init: Project name: X_WatchController_FW +I (271) app_init: App version: 3ec39a2-dirty +I (277) app_init: Compile time: Mar 29 2025 16:21:16 +I (283) app_init: ELF file SHA256: c5ad318a2... +I (288) app_init: ESP-IDF: v5.3 +I (292) efuse_init: Min chip rev: v0.0 +I (297) efuse_init: Max chip rev: v0.99 +I (302) efuse_init: Chip rev: v0.0 +I (307) heap_init: Initializing. RAM available for dynamic allocation: +I (314) heap_init: At 40812190 len 0006A480 (425 KiB): RAM +I (320) heap_init: At 4087C610 len 00002F54 (11 KiB): RAM +I (326) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM +I (334) spi_flash: detected chip: generic +I (337) spi_flash: flash io: dio +I (343) sleep: Configure to isolate all GPIO pins in sleep state +I (348) sleep: Enable automatic switching of GPIO sleep configuration +I (355) coexist: coex firmware version: dab85ae96 +I (383) coexist: coexist rom version 5b8dcfa +I (383) main_task: Started on CPU0 +I (383) main_task: Calling app_main() +I (393) esp_eth.netif.netif_glue: 42:4c:ca:ff:fe:4e +I (393) esp_eth.netif.netif_glue: ethernet attached to netif +I (403) Watch: Ethernet Started +I (403) Watch: Start Lighting +I (403) gpio: GPIO[10]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 +I (413) gpio: GPIO[11]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 +I (423) Watch: Start Stepper +I (423) gpio: GPIO[18]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 +I (433) gpio: GPIO[8]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 +I (443) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 +I (453) TMR: Create timer handle +I (453) TMR: Setup timer +I (453) Stepper: Find Home +I (463) Stepper: Homing ... +I (463) Stepper: Fast find right side of home sensor +I (483) gpio: GPIO[1]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 +I (2133) Stepper: Find right side of home sensor +I (2313) Stepper: Find end of sensor +I (2403) Watch: Ethernet Link Up +I (2403) Watch: Ethernet Link Up +I (2403) Watch: Ethernet HW Addr 00:00:00:00:00:00 +I (3403) esp_netif_handlers: eth ip: 172.16.17.56, mask: 255.255.0.0, gw: 172.16.0.1 +I (3403) Watch: Ethernet Got IP Address +I (3403) Watch: ~~~~~~~~~~~ +I (3403) Watch: ETHIP:172.16.17.56 +I (3413) Watch: ETHMASK:255.255.0.0 +I (3413) Watch: ETHGW:172.16.0.1 +I (3413) Watch: ~~~~~~~~~~~ +I (3423) Watch: Start net services +I (3423) Watch: Starting Telnet task +I (3423) Watch: Starting ArtNet task +I (3423) Watch: Starting SPIT task +I (3433) SPIT: Connected to eth +I (3443) SPIT: - IPv4 address: 172.16.17.56, +I (3443) SPIT: - IPv4 netmask: 255.255.0.0, +I (3423) UDP: Starting syslog session to 172.16.16.10 +I (3433) TCP: Socket created +I (3433) UDP: Socket bound, port 6454 +I (3453) Watch: NEW SPIT-Type ID: ActionStartShuffle GroupName: CatasWatchMovement Name: ActionStartShuffle confirmed: 0 +I (3453) SysLog: Starting Syslog Task +I (3463) TCP: Socket bound, port 23 +I (3473) Watch: NEW SPIT-Type ID: ActionMoveTo1 GroupName: CatasWatchMovement Name: ActionMoveTo1 confirmed: 0 +I (3493) Watch: NEW SPIT-Type ID: ActionMoveTo2 GroupName: CatasWatchMovement Name: ActionMoveTo2 confirmed: 0 +I (3483) Telnet: Socket waiting for connect +I (3483) UDP: Socket bound, port 514 +I (3503) Watch: NEW SPIT-Type ID: ActionMoveTo3 GroupName: CatasWatchMovement Name: ActionMoveTo3 confirmed: 0 +I (3523) Watch: NEW SPIT-Type ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 0 +I (3533) Watch: NEW SPIT-Type ID: ActionMoveTo5 GroupName: CatasWatchMovement Name: ActionMoveTo5 confirmed: 0 +I (3543) Watch: NEW SPIT-Type ID: ActionMoveTo6 GroupName: CatasWatchMovement Name: ActionMoveTo6 confirmed: 0 +I (3553) SPIT: Starting Socket managing +I (5713) Stepper: Find left side of home sensor +I (6183) Stepper: Move back to mid position 145 +I (7633) Stepper: Reset position +I (7633) Watch: Fist Position is 0.000000.2 +I (7663) Watch: SERVER DETECTED +I (7663) Watch: Name: liveShowSPIT +I (7663) Watch: ID: 698a3e4f-1ae9-4dd8-9015-29332d29629e +I (7663) Watch: Computer: GgP17 +I (7663) Watch: IP: 172.16.16.10 +I (7673) Watch: Port: 15120 +I (7673) Watch: Addition: +I (7673) Watch: ClientIP: 172.16.17.56 +I (7683) SPIT: connect to 172.16.16.10 +I (7683) Watch: MySPITApp: eventConnectionStatus 0 +I (7663) Watch: Changing picto-Illum to pos = 1 +I (7693) Watch: Current color set r128 g128 b128 +I (7693) Watch: MySPITApp: eventConnectionStatus 4 +I (8203) Watch: eventProjectReport ID: CatasWatchProject Name: CatasWatchProject FramesPerSecond: 44100 +I (8203) Watch: eventStartProjectTransfer +I (8283) Watch: SPIT-Type CHANGED ID: ActionMoveTo5 GroupName: CatasWatchMovement Name: ActionMoveTo5 confirmed: 1 +I (8283) Watch: SPIT-Type CHANGED ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 1 +I (8293) Watch: SPIT-Type CHANGED ID: ActionMoveTo3 GroupName: CatasWatchMovement Name: ActionMoveTo3 confirmed: 1 +I (8303) Watch: SPIT-Type CHANGED ID: ActionMoveTo6 GroupName: CatasWatchMovement Name: ActionMoveTo6 confirmed: 1 +I (8313) Watch: NEW SPIT-REMOTE-Type ID: playControlStart GroupName: Playcontrol Name: start confirmed: 1 +I (8323) Watch: NEW SPIT-REMOTE-Type ID: playControlPause GroupName: Playcontrol Name: pause confirmed: 1 +I (8343) Watch: NEW SPIT-REMOTE-Type ID: nextSceneBridge GroupName: Playcontrol Name: next scene confirmed: 1 +I (8353) Watch: NEW SPIT-REMOTE-Type ID: nextMainSceneBridge GroupName: Playcontrol Name: next main scene confirmed: 1 +I (8373) Watch: NEW SPIT-REMOTE-Type ID: previuosSceneBridge GroupName: Playcontrol Name: previous scene confirmed: 1 +I (8383) Watch: NEW SPIT-REMOTE-Type ID: previousMainSceneBridge GroupName: Playcontrol Name: previous main scene confirmed: 1 +I (8403) Watch: NEW SPIT-REMOTE-Type ID: mainmixerSound_Volume00 GroupName: Main Mixer Name: Sound confirmed: 1 +I (8423) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_Dimmer00 GroupName: Main Mixer Name: confirmed: 1 +I (8433) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB00 GroupName: Main Mixer Name: confirmed: 1 +I (8453) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB10 GroupName: Main Mixer Name: confirmed: 1 +I (8463) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB20 GroupName: Main Mixer Name: confirmed: 1 +I (8483) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB30 GroupName: Main Mixer Name: confirmed: 1 +I (8503) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB40 GroupName: Main Mixer Name: confirmed: 1 +I (8513) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB50 GroupName: Main Mixer Name: confirmed: 1 +I (8533) Watch: NEW SPIT-REMOTE-Type ID: mainmixerMedia_SoundVolume00 GroupName: Main Mixer Name: Media confirmed: 1 +I (8543) Watch: NEW SPIT-REMOTE-Type ID: mainmixerMedia_Transparency00 GroupName: Main Mixer Name: Media confirmed: 1 +I (8563) Watch: NEW SPIT-REMOTE-Type ID: selectedJingles GroupName: Playcontrol Name: selected Jingles confirmed: 1 +I (8573) Watch: NEW SPIT-REMOTE-Type ID: selectedJingleGroups GroupName: Playcontrol Name: selected Jinglegroups confirmed: 1 +I (8593) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000lo0va8bom GroupName: MainScene Name: ChangingPositionScene confirmed: 1 +I (8603) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000m70va8bom GroupName: MainScene Name: InPosition1Scene confirmed: 1 +I (8623) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000mh0va8bom GroupName: MainScene Name: InPosition2Scene confirmed: 1 +I (8633) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000mr0va8bom GroupName: MainScene Name: InPosition3Scene confirmed: 1 +I (8653) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000nk0va8bom GroupName: MainScene Name: InPosition4Scene confirmed: 1 +I (8673) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000nu0va8bom GroupName: MainScene Name: InPosition5Scene confirmed: 1 +I (8683) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000o40va8bom GroupName: MainScene Name: InPosition6Scene confirmed: 1 +I (8703) Watch: NEW SPIT-REMOTE-Object ID: playControlStart Name: start -> SPITType: start +I (8703) Watch: eventPlayRemoteObjectStatus RemoteSPITType: start RemoteSPITObject: start Position: 0 Value: 0 +I (8713) Watch: NEW SPIT-REMOTE-Object ID: playControlPause Name: pause -> SPITType: pause +I (8723) Watch: eventPlayRemoteObjectStatus RemoteSPITType: pause RemoteSPITObject: pause Position: 0 Value: 0 +I (8733) Watch: NEW SPIT-REMOTE-Object ID: nextSceneBridge Name: next scene -> SPITType: next scene +I (8743) Watch: eventPlayRemoteObjectStatus RemoteSPITType: next scene RemoteSPITObject: next scene Position: 0 Value: 0 +I (8753) Watch: NEW SPIT-REMOTE-Object ID: nextMainSceneBridge Name: next main scene -> SPITType: next main scene +I (8763) Watch: eventPlayRemoteObjectStatus RemoteSPITType: next main scene RemoteSPITObject: next main scene Position: 0 Value: 0 +I (8773) Watch: NEW SPIT-REMOTE-Object ID: previuosSceneBridge Name: previous scene -> SPITType: previous scene +I (8783) Watch: eventPlayRemoteObjectStatus RemoteSPITType: previous scene RemoteSPITObject: previous scene Position: 0 Value: 0 +I (8793) Watch: NEW SPIT-REMOTE-Object ID: previousMainSceneBridge Name: previous main scene -> SPITType: previous main scene +I (8813) Watch: eventPlayRemoteObjectStatus RemoteSPITType: previous main scene RemoteSPITObject: previous main scene Position: 0 Value: 0 +I (8823) Watch: NEW SPIT-REMOTE-Object ID: mainmixerSound_Volume00 Name: Sound Volume -> SPITType: Sound +I (8833) Watch: eventPlayRemoteObjectStatus RemoteSPITType: Sound RemoteSPITObject: Sound Volume Position: 0 Value: 500000 +I (8843) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_Dimmer00 Name: Dimmer -> SPITType: +I (8853) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Dimmer Position: 0 Value: 1000000 +I (8863) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB00 Name: Red -> SPITType: +I (8873) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Red Position: 0 Value: 1000000 +I (8883) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB10 Name: Green -> SPITType: +I (8893) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Green Position: 0 Value: 1000000 +I (8903) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB20 Name: Blue -> SPITType: +I (8913) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Blue Position: 0 Value: 1000000 +I (8923) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB30 Name: Cyan -> SPITType: +I (8933) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB40 Name: Magenta -> SPITType: +I (8943) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Magenta Position: 0 Value: 0 +I (8953) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB50 Name: Yellow -> SPITType: +I (8963) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Yellow Position: 0 Value: 0 +I (8973) Watch: NEW SPIT-REMOTE-Object ID: mainmixerMedia_SoundVolume00 Name: Sound Volume -> SPITType: Media +I (8983) Watch: NEW SPIT-REMOTE-Object ID: mainmixerMedia_Transparency00 Name: Media Transparency -> SPITType: Media +I (8993) Watch: eventPlayRemoteObjectStatus RemoteSPITType: Media RemoteSPITObject: Media Transparency Position: 0 Value: 1000000 +I (9003) Watch: NEW SPIT-REMOTE-Object ID: selectedJinglesps Name: Play / Stop -> SPITType: selected Jingles +I (9013) Watch: eventPlayRemoteObjectStatus RemoteSPITType: selected Jingles RemoteSPITObject: Play / Stop Position: 0 Value: 0 +I (9023) Watch: NEW SPIT-REMOTE-Object ID: selectedJinglespf Name: Play / Fade Out -> SPITType: selected Jingles +I (9033) Watch: NEW SPIT-REMOTE-Object ID: selectedJingleGroupsps Name: Play / Stop -> SPITType: selected Jinglegroups +I (9053) Watch: eventPlayRemoteObjectStatus RemoteSPITType: selected Jinglegroups RemoteSPITObject: Play / Stop Position: 0 Value: 0 +I (9063) Watch: NEW SPIT-REMOTE-Object ID: selectedJingleGroupspf Name: Play / Fade Out -> SPITType: selected Jinglegroups +I (9073) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000lo0va8bom Name: play -> SPITType: ChangingPositionScene +I (9083) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000m70va8bom Name: play -> SPITType: InPosition1Scene +I (9093) Watch: eventPlayRemoteObjectStatus RemoteSPITType: InPosition1Scene RemoteSPITObject: play Position: 0 Value: 0 +I (9103) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000mh0va8bom Name: play -> SPITType: InPosition2Scene +I (9123) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000mr0va8bom Name: play -> SPITType: InPosition3Scene +I (9133) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000nk0va8bom Name: play -> SPITType: InPosition4Scene +I (9143) Watch: eventPlayRemoteObjectStatus RemoteSPITType: InPosition4Scene RemoteSPITObject: play Position: 0 Value: 0 +I (9153) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000nu0va8bom Name: play -> SPITType: InPosition5Scene +I (9163) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000o40va8bom Name: play -> SPITType: InPosition6Scene +I (9183) Watch: eventEndProjectTransfer +W (9203) SPIT: Finished searching +W (9203) SPIT: Start working +I (9253) Watch: SPIT-Type CHANGED ID: ActionMoveTo5 GroupName: CatasWatchMovement Name: ActionMoveTo5 confirmed: 1 +I (9253) Watch: SPIT-Type CHANGED ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 1 +I (9263) Watch: SPIT-Type CHANGED ID: ActionMoveTo3 GroupName: CatasWatchMovement Name: ActionMoveTo3 confirmed: 1 +I (9273) Watch: SPIT-Type CHANGED ID: ActionMoveTo6 GroupName: CatasWatchMovement Name: ActionMoveTo6 confirmed: 1 +I (9283) Watch: SPIT-Type CHANGED ID: ActionMoveTo2 GroupName: CatasWatchMovement Name: ActionMoveTo2 confirmed: 1 +I (9293) Watch: SPIT-Type CHANGED ID: ActionMoveTo1 GroupName: CatasWatchMovement Name: ActionMoveTo1 confirmed: 1 +I (459853) Watch: SPIT-Type CHANGED ID: ActionMoveTo1 GroupName: CatasWatchMovement Name: ActionMoveTo1 confirmed: 1 +I (459853) Watch: SPIT-Type CHANGED ID: ActionMoveTo1 GroupName: CatasWatchMovement Name: ActionMoveTo1 confirmed: 1 +I (459863) Watch: SPIT-Type CHANGED ID: ActionMoveTo6 GroupName: CatasWatchMovement Name: ActionMoveTo6 confirmed: 1 +I (459883) Watch: SPIT-Type CHANGED ID: ActionMoveTo6 GroupName: CatasWatchMovement Name: ActionMoveTo6 confirmed: 1 +I (459893) Watch: SPIT-Type CHANGED ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 1 +I (459903) Watch: SPIT-Type CHANGED ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 1 +I (466093) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000000zq0va8bom Name: -> SPITType: ActionStartShuffle +I (466733) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000000zq0va8bom Name: -> SPITType: ActionStartShuffle +I (468643) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000000zq0va8bom Name: -> SPITType: ActionStartShuffle +I (471243) Watch: NEW SPIT-Object ID: 00000m8uedyyt00000000000000010u0va8bom Name: -> SPITType: ActionMoveTo1 +I (472153) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000010u0va8bom Name: -> SPITType: ActionMoveTo1 +I (473403) Watch: NEW SPIT-Object ID: 00000m8uedyyt00000000000000011a0va8bom Name: -> SPITType: ActionMoveTo2 +I (474763) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000011a0va8bom Name: -> SPITType: ActionMoveTo2 +I (483183) Watch: NEW SPIT-Object ID: 00000m8uedyyt00000000000000011s0va8bom Name: -> SPITType: ActionMoveTo3 +I (483283) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000011s0va8bom Name: -> SPITType: ActionMoveTo3 +I (483333) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000011s0va8bom Name: -> SPITType: ActionMoveTo3 +I (483703) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000011s0va8bom Name: -> SPITType: ActionMoveTo3 +I (484613) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000011s0va8bom Name: -> SPITType: ActionMoveTo3 +I (485993) Watch: NEW SPIT-Object ID: 00000m8uedyyt00000000000000012m0va8bom Name: -> SPITType: ActionMoveTo4 +I (486063) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000012m0va8bom Name: -> SPITType: ActionMoveTo4 +I (486593) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000012m0va8bom Name: -> SPITType: ActionMoveTo4 +I (488103) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000001330va8bom Name: -> SPITType: ActionMoveTo5 +I (489273) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000001330va8bom Name: -> SPITType: ActionMoveTo5 +I (490913) Watch: NEW SPIT-Object ID: 00000m8uedyyt00000000000000013r0va8bom Name: -> SPITType: ActionMoveTo6 +I (491043) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000013r0va8bom Name: -> SPITType: ActionMoveTo6 +I (491083) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000013r0va8bom Name: -> SPITType: ActionMoveTo6 +I (493163) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000001470va8bom Name: -> SPITType: ActionMoveTo6 +I (493243) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000001470va8bom Name: -> SPITType: ActionMoveTo6 +I (493353) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000001470va8bom Name: -> SPITType: ActionMoveTo6 +I (493883) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000001470va8bom Name: -> SPITType: ActionMoveTo6 +I (503223) Watch: eventProjectReport ID: CatasWatchProject Name: CatasWatchProject FramesPerSecond: 44100 +I (503373) Watch: eventStartProjectTransfer +I (503373) Watch: SPIT-Type CHANGED ID: ActionStartShuffle GroupName: CatasWatchMovement Name: ActionStartShuffle confirmed: 1 +I (503373) Watch: SPIT-Type CHANGED ID: ActionMoveTo5 GroupName: CatasWatchMovement Name: ActionMoveTo5 confirmed: 1 +I (503383) Watch: SPIT-Type CHANGED ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 1 +I (503393) Watch: SPIT-Type CHANGED ID: ActionMoveTo1 GroupName: CatasWatchMovement Name: ActionMoveTo1 confirmed: 1 +I (503413) Watch: SPIT-Type CHANGED ID: ActionMoveTo3 GroupName: CatasWatchMovement Name: ActionMoveTo3 confirmed: 1 +I (503423) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000011s0va8bom Name: -> SPITType: ActionMoveTo3 +I (503433) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt00000000000000012m0va8bom Name: -> SPITType: ActionMoveTo4 +I (503443) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000001330va8bom Name: -> SPITType: ActionMoveTo5 +I (503453) Watch: SPIT-Object CHANGED ID: 00000m8uedyyt0000000000000001470va8bom Name: -> SPITType: ActionMoveTo6 +I (503463) Watch: SPIT-REMOTE-Type CHANGED ID: playControlStart GroupName: Playcontrol Name: start confirmed: 1 +I (503473) Watch: SPIT-REMOTE-Type CHANGED ID: playControlPause GroupName: Playcontrol Name: pause confirmed: 1 +I (503483) Watch: SPIT-REMOTE-Type CHANGED ID: nextSceneBridge GroupName: Playcontrol Name: next scene confirmed: 1 +I (503493) Watch: SPIT-REMOTE-Type CHANGED ID: nextMainSceneBridge GroupName: Playcontrol Name: next main scene confirmed: 1 +I (503513) Watch: SPIT-REMOTE-Type CHANGED ID: previuosSceneBridge GroupName: Playcontrol Name: previous scene confirmed: 1 +I (503523) Watch: SPIT-REMOTE-Type CHANGED ID: previousMainSceneBridge GroupName: Playcontrol Name: previous main scene confirmed: 1 +I (503543) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerSound_Volume00 GroupName: Main Mixer Name: Sound confirmed: 1 +I (503553) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerDMX_Dimmer00 GroupName: Main Mixer Name: confirmed: 1 +I (503573) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerDMX_RGB00 GroupName: Main Mixer Name: confirmed: 1 +I (503583) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerDMX_RGB10 GroupName: Main Mixer Name: confirmed: 1 +I (503603) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerDMX_RGB20 GroupName: Main Mixer Name: confirmed: 1 +I (503613) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerDMX_RGB30 GroupName: Main Mixer Name: confirmed: 1 +I (503633) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerDMX_RGB40 GroupName: Main Mixer Name: confirmed: 1 +I (503653) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerDMX_RGB50 GroupName: Main Mixer Name: confirmed: 1 +I (503663) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerMedia_SoundVolume00 GroupName: Main Mixer Name: Media confirmed: 1 +I (503683) Watch: SPIT-REMOTE-Type CHANGED ID: mainmixerMedia_Transparency00 GroupName: Main Mixer Name: Media confirmed: 1 +I (503693) Watch: SPIT-REMOTE-Type CHANGED ID: selectedJingles GroupName: Playcontrol Name: selected Jingles confirmed: 1 +I (503713) Watch: SPIT-REMOTE-Type CHANGED ID: selectedJingleGroups GroupName: Playcontrol Name: selected Jinglegroups confirmed: 1 +I (503723) Watch: SPIT-REMOTE-Type CHANGED ID: 00000m8uedyyt0000000000000000lo0va8bom GroupName: MainScene Name: ChangingPositionScene confirmed: 1 +I (503743) Watch: SPIT-REMOTE-Type CHANGED ID: 00000m8uedyyt0000000000000000m70va8bom GroupName: MainScene Name: InPosition1Scene confirmed: 1 +I (503753) Watch: SPIT-REMOTE-Type CHANGED ID: 00000m8uedyyt0000000000000000mh0va8bom GroupName: MainScene Name: InPosition2Scene confirmed: 1 +I (503773) Watch: SPIT-REMOTE-Type CHANGED ID: 00000m8uedyyt0000000000000000mr0va8bom GroupName: MainScene Name: InPosition3Scene confirmed: 1 +I (503793) Watch: SPIT-REMOTE-Type CHANGED ID: 00000m8uedyyt0000000000000000nk0va8bom GroupName: MainScene Name: InPosition4Scene confirmed: 1 +I (503803) Watch: SPIT-REMOTE-Type CHANGED ID: 00000m8uedyyt0000000000000000nu0va8bom GroupName: MainScene Name: InPosition5Scene confirmed: 1 +I (503823) Watch: SPIT-REMOTE-Type CHANGED ID: 00000m8uedyyt0000000000000000o40va8bom GroupName: MainScene Name: InPosition6Scene confirmed: 1 +I (503833) Watch: SPIT-REMOTE-Object CHANGED ID: playControlStart Name: start -> SPITType: start +I (503833) Watch: eventPlayRemoteObjectStatus RemoteSPITType: start RemoteSPITObject: start Position: 0 Value: 0 +I (503853) Watch: SPIT-REMOTE-Object CHANGED ID: playControlPause Name: pause -> SPITType: pause +I (503853) Watch: eventPlayRemoteObjectStatus RemoteSPITType: pause RemoteSPITObject: pause Position: 0 Value: 0 +I (503863) Watch: SPIT-REMOTE-Object CHANGED ID: nextSceneBridge Name: next scene -> SPITType: next scene +I (503873) Watch: eventPlayRemoteObjectStatus RemoteSPITType: next scene RemoteSPITObject: next scene Position: 0 Value: 0 +I (503883) Watch: SPIT-REMOTE-Object CHANGED ID: nextMainSceneBridge Name: next main scene -> SPITType: next main scene +I (503903) Watch: eventPlayRemoteObjectStatus RemoteSPITType: next main scene RemoteSPITObject: next main scene Position: 0 Value: 0 +I (503913) Watch: SPIT-REMOTE-Object CHANGED ID: previuosSceneBridge Name: previous scene -> SPITType: previous scene +I (503923) Watch: eventPlayRemoteObjectStatus RemoteSPITType: previous scene RemoteSPITObject: previous scene Position: 0 Value: 0 +I (503933) Watch: SPIT-REMOTE-Object CHANGED ID: previousMainSceneBridge Name: previous main scene -> SPITType: previous main scene +I (503953) Watch: eventPlayRemoteObjectStatus RemoteSPITType: previous main scene RemoteSPITObject: previous main scene Position: 0 Value: 0 +I (503963) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerSound_Volume00 Name: Sound Volume -> SPITType: Sound +I (503973) Watch: eventPlayRemoteObjectStatus RemoteSPITType: Sound RemoteSPITObject: Sound Volume Position: 0 Value: 500000 +I (503983) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerDMX_Dimmer00 Name: Dimmer -> SPITType: +I (503993) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Dimmer Position: 0 Value: 1000000 +I (504003) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerDMX_RGB00 Name: Red -> SPITType: +I (504013) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Red Position: 0 Value: 1000000 +I (504023) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerDMX_RGB10 Name: Green -> SPITType: +I (504033) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Green Position: 0 Value: 1000000 +I (504043) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerDMX_RGB20 Name: Blue -> SPITType: +I (504053) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerDMX_RGB30 Name: Cyan -> SPITType: +I (504063) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Cyan Position: 0 Value: 0 +I (504073) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerDMX_RGB40 Name: Magenta -> SPITType: +I (504083) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerDMX_RGB50 Name: Yellow -> SPITType: +I (504093) Watch: eventPlayRemoteObjectStatus RemoteSPITType: RemoteSPITObject: Yellow Position: 0 Value: 0 +I (504103) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerMedia_SoundVolume00 Name: Sound Volume -> SPITType: Media +I (504113) Watch: eventPlayRemoteObjectStatus RemoteSPITType: Media RemoteSPITObject: Sound Volume Position: 0 Value: 500000 +I (504123) Watch: SPIT-REMOTE-Object CHANGED ID: mainmixerMedia_Transparency00 Name: Media Transparency -> SPITType: Media +I (504133) Watch: SPIT-REMOTE-Object CHANGED ID: selectedJinglesps Name: Play / Stop -> SPITType: selected Jingles +I (504143) Watch: eventPlayRemoteObjectStatus RemoteSPITType: selected Jingles RemoteSPITObject: Play / Stop Position: 0 Value: 0 +I (504163) Watch: SPIT-REMOTE-Object CHANGED ID: selectedJinglespf Name: Play / Fade Out -> SPITType: selected Jingles +I (504173) Watch: SPIT-REMOTE-Object CHANGED ID: selectedJingleGroupsps Name: Play / Stop -> SPITType: selected Jinglegroups +I (504183) Watch: eventPlayRemoteObjectStatus RemoteSPITType: selected Jinglegroups RemoteSPITObject: Play / Stop Position: 0 Value: 0 +I (504193) Watch: SPIT-REMOTE-Object CHANGED ID: selectedJingleGroupspf Name: Play / Fade Out -> SPITType: selected Jinglegroups +I (504213) Watch: SPIT-REMOTE-Object CHANGED ID: 00000m8uedyyt0000000000000000lo0va8bom Name: play -> SPITType: ChangingPositionScene +I (504223) Watch: eventPlayRemoteObjectStatus RemoteSPITType: ChangingPositionScene RemoteSPITObject: play Position: 0 Value: 0 +I (504233) Watch: SPIT-REMOTE-Object CHANGED ID: 00000m8uedyyt0000000000000000m70va8bom Name: play -> SPITType: InPosition1Scene +I (504243) Watch: SPIT-REMOTE-Object CHANGED ID: 00000m8uedyyt0000000000000000mh0va8bom Name: play -> SPITType: InPosition2Scene +I (504253) Watch: SPIT-REMOTE-Object CHANGED ID: 00000m8uedyyt0000000000000000mr0va8bom Name: play -> SPITType: InPosition3Scene +I (504273) Watch: SPIT-REMOTE-Object CHANGED ID: 00000m8uedyyt0000000000000000nk0va8bom Name: play -> SPITType: InPosition4Scene +I (504283) Watch: SPIT-REMOTE-Object CHANGED ID: 00000m8uedyyt0000000000000000nu0va8bom Name: play -> SPITType: InPosition5Scene +I (504293) Watch: SPIT-REMOTE-Object CHANGED ID: 00000m8uedyyt0000000000000000o40va8bom Name: play -> SPITType: InPosition6Scene +I (504303) Watch: eventEndProjectTransfer +I (504433) Watch: SPIT-Type CHANGED ID: ActionMoveTo5 GroupName: CatasWatchMovement Name: ActionMoveTo5 confirmed: 1 +I (504433) Watch: SPIT-Type CHANGED ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 1 +I (504443) Watch: SPIT-Type CHANGED ID: ActionMoveTo3 GroupName: CatasWatchMovement Name: ActionMoveTo3 confirmed: 1 +I (504453) Watch: SPIT-Type CHANGED ID: ActionMoveTo6 GroupName: CatasWatchMovement Name: ActionMoveTo6 confirmed: 1 +I (504463) Watch: SPIT-Type CHANGED ID: ActionMoveTo2 GroupName: CatasWatchMovement Name: ActionMoveTo2 confirmed: 1 +I (504473) Watch: SPIT-Type CHANGED ID: ActionMoveTo1 GroupName: CatasWatchMovement Name: ActionMoveTo1 confirmed: 1 diff --git a/doc/LSS-Icon.afdesign b/doc/LSS-Icon.afdesign index 90a4b2dd9ed30b55d22fff668a79b2f9f55497be..732dad7447eba8bb6d5ba68175d8614ec1c5bf4d 100644 GIT binary patch literal 89027 zcmZ^~bzD@>_c**XOLup7w{&-RNSCxIC9rgNgCN}?9TG0x9Rh;VY0w?_S>K=U@6YGF z_D-C+Q>W(a%pDM*CW8(_1-W~_)uvZ*clgc+`VW-({};#oU;ckN5J)5U$njqq9rnP( z9__at?{Hx;y`r-#OB?qyNEtH&ZsPQNi6#!{jR6uU4fS_ zC$s?cKrl<$vu{8JGO36a9aM>rus zS2C$Fu%B?#Hti5tt;GA}kSqsqtS_ccbf(}u7l)k_Eiw{-~*SfOgHLa&XteD)D!WqLx>Ez9FkEA0H| z=}_jE^Bse2CDpgci#f?U?`R{@F36GDWfW1FvYCC`gU`kq(j>77cn=)ZkiGYC7WafP z+ygLiW#jWj-p9FKkY8H!>hJa;p^#kbOwdAcK?bW~gGd%d1Y6{?Qw@j=1hmHe8rc%W zG|g@I_B)@Y4+gbKXG1;pBEPJ=(@f2ds3;~XxF-=qO zqND|&I#GAhbaMW1NzQ!=3c-aqa}FRuEQ8IaU8pqEDde`5-{AJFFbck z4YAV0RAv;V9b#(rQ=X2@x5&YS;Dd|)NFFiYlneGl5NTXiKDcN}W`djnDymECpy+B1s=s3BZ4A$ThLfnUfZbXvHQd%%Gem3)O)}_)( zlsj%v?$`2J3yvKDIA_uW;b;-YDpL59LoQAzOjwlDZv!YD>{}-m&!@( zX+gKb5c)zgsi(aaO~P&bhRNX!(HVQ>`?k{7N@NEjbbfke2DG$I3iC5B`6%TOswKvD zn$%5-DCsHBL4pKqkixlKW~`-xRoc~=K?q3MW#o=eM`Z}}6)K-@A1<}LmEVLsBQ}nD zYI-GzP`3_OlZh>sr*#00AOU2j!760GW2A$thvo;eJxS(gPK~wXbwA>ROTBvLQQXeL z;M0kfp93om9eZcP@eOQD9jC>ra_GFu;F+7X;AP9PM$uu#&$Mw8us+`|=(Z`7*%I+& z!q0RcyUQ0>DeSh1sGloQj8fOn8kcy|zxFmtpbe2#?qkN!v?wER@*a5QOX?|b$?-*9 zUkt9_DJ2>E460b+aqMjbXW`n6r89m?NhZRpU&XrkP$>$RT}A!#%dZdt zlLcYdiw`K6bXfX+u)Z*)brhqB`0slc%V@xLno_=mbLDagR`E|ii?`*K<1>8!23Uu+ zRP87R|C!4Tl|{j$-jYgG-~4&}c)IbvkCx>f8gg#c6`UgiLH@$wXG9uL8f+wo+?=KD z<3!_z!fqnJ76lNQQf>~zhx)LmGtJzjMtFtX*l{LM6>W(&;Ktlr5NyP>pum7Ap_Xtq zB~ORX(&jF(H95px&WU;?a-~TOf_Gq0VTxLlK8PSKlGOQqgi1Y23hRm@MS0-cfHu?H zCIu^Ih40J<(#*+t9DROyw08+D|KN%=j9V{aE7Tx6_-}KIG_L78?bJ;k3OmApxBiu$ z5je7Tp-%%mN=cN0><_0K1`b0Bn5q#M=;5@4oW?0?h22b`Z5#qR^|6KmVFjrzm6F2l zn7*RWM0%`G6|)wivw*KnRDIHzR|S&3(|rj2 zSXA~G@s;81Bt@|&Q15IvxKep@rafY<92N^%3>X7ki6T@&Cv=0)%iz*NK>AnS#EArm za+6~B!mkK0UclIT^@^+O1`XPQX9Su!I5LuMa!aIA;bAFD<`JZ5qrC@9{Yc5 z!XMNP#TYV>i=N>{5t1UXNvn)Wa1fSHW(XzLH<+{+{N-q^I1XV z*i#ewiC|`BZz;lCH}_rV=7eOEW}RMQ&%&9U&eyuu;&V8(*J%Qr9~sE%l2q(VbMo@v zikZ*c4h>2OHfeOeCcuxkeRy7at;Lr8y{3ZXOjM zjS@IqhgAeQc)t8#O?HpvCN0fc0!_EDv;hg3Y7G%qmMrjXnd)(1FAFuiyfVo}7)ctI z>-VQB6P>qJ22J=G2S`jZTm);+o-wL495JheIW@ZE#r zPPPM~EKC)J1dH)k%rqLdd%M~2R##y8Xh- z=E{|XGoWXAsg#~&W{l+WmC3OAM$?D|uMYPGq5+?*W-M7eulQ)i^5GFO>61Qcft05{Gi=f)kS{=09hC8pL-YIjYh<^kq~>8K~R1e*L~|JB*iE>0w@uY zKRN)^hz~^yfUhm^ciMJ6@%fcGDZgBTrk@7z`E7U)AT=+^jA5_{{Kks{gu5et0F{E> zbS8q&A1z8p0HqV)hpox#Z{R~6wrPeI%eo!%MuX$*$RhA}1^*uUqv7xrNdEpDK(`Fs zisl-tu5`Vn0xJKmTuwL*_x22wya7%*s0p>EfS1jCw{vKa{wPas{=`kmTV2gwCT3>y zjPJYKhRki?!w)tEo*Fvhudz?YkEIX{)wa5pfLHO=cEgPh&(M~-3~^pJB!dfir`M+| zJ(Rylm6q8Lan~T-T1V$V`~&3i>sBdgJj`hAq}sO}0YUxy+Rn9yt-Kp=Z5dZq#gnXy z=l!PqHFj%)IY$)Q>VunB>LH`6zixov7ufccs4Sy%v!X6P?~aLxT?;B~=BEui(` zJy~Q=rC}?~ygAbrpLmN_V<2|B1>T1wMmrFNdI z^B^|EMf_nbx;%sVwf71}oxB`(`P0r9*|O&1fmcW%a;mz#`{D3VJO>cNk?-HU`JYb| z_WQ)MgmqFTX=ZNut^jagEl-AXp(dw-Gf78OM#9n*igvH@W`1YNqQ45^HFoI}Qz&av zbz-@>yFB&9M}fX{p|RLc5B)jmmSlK)F(vtzYzl~HX_o7S7{P&`G~xIc8KHviJjjZc zQr?NQm~iECiBI3QSnpFQ`d*b|jw@G9cwp`z3oZ}`v6Pu5a>HMk4I&v)ZsX&g5=0T^ zk=O*28xP9Y#?%*L%|j}AM|iBo(=ExJ6BxMzkCO?Do-A-vHRf}InD6hPt?lJoSP#dah@ zC3i`4_os9EOO7t8*H+5@ts*+{J1gU)AIe*Uprj|Uz9C#jT2)(NZDoNhxnRn%QUn4z z_(ah&*#xS*y_Hasz$1S?2h|BhgRR6alp6~aKz{jKe+Gu@TCSS#&s%F|p zR#^BRkwiImV+{-Qwf$i6ioBkCmD{*R6Dd1+$_9Ju z@^auNBxO1eplIhm@wrJH7b`_Iu_)*hnv8j1v0w{QA&}^4ZZV?j1$*fi%k3IhDsqC% zTla(&8fbS^a~PSdjCUqIG(ak1L?j=xM0P%;Z<3{Q5U{|R?pz|EV%*o~wn??%zPTd8 z345wgcEi$N3jt-}^Rw>>N4kU;e=U=elLiW2D~vm(PjbgGOUv_%KN|Qrk>u_Z59ivT zu_Y`i{(>WDc@mpvY1z>PKTjzf$kFwo+6EUo74_}PAe~Mr7`A$c70cd7mNaFQsO4YX zqM&06UOX}=(8uynJmki^g2Nd}V)j?6mrLl;f-4d3ib=Pbpc)fIqm#>8#lv@UJWve* z?LIbX@ObVXmPW7^hd(a}jBYnYhDy4h{cSLp<5j!9HMudKe6X`|1j$=`MTdOcKTit* z%0tYZ+Pm5j??TX zJ(kjF@j!H#q$qryF(wB_HO|sIk-3EYf{3^*P#ra&&MGF=y(&*a+2G;~l6cepabNHt%XYu&)Mi zs-McQLMoA1nwa8ZpNO125wSc69u&BoOmtYB_*;h(IH2Nv3^iThvISjmVCmowIA{7| zy0g_;F%eHUG#|wlKn7uieq$3J*d!SG;IM_p`%qmPsQ3U5e0s>ja6C;4^ZkB50v9}3 z<2$61Y3`zkg%0Z9VL%_95R5OV5!Yz9FASv|QW#PxrDz(+w+cRW(7>}rz2-Mc7qd7) z^|0GnLqk5b%f&22knjlX31fQW+sBu@8JNb_y!d7I77j@)tM#l=KoBY^ z>V>9$7s7xp!^{M&g*%x?HYM9Dk_&%&uqz5x&_L1;9y(IqU+LKMZp5Jxv@0ItgG!pC zaH^uJZ9*Kmn0XMUm_7N<=g0{}Z9>Ym81>+J$A{z`QV?^a9&#sD%)?RL^q8o2b}Glv zZBO-oA0Q_dsf)`WXr_8CNzvkCU*pKYqxTG@$vS{wISo&QY$BgN@vfJmu^~BbZBeiR z=>_5#A}$~9JXmCcNA+_`N(eE^MK^rh7UD;Yc81Utc~&TtP%BA3byp!Wn>BN@5MMWo z&9Gfu@NAzRRw9z0f;^fj$O)%^Zvhv?y9>{ZHt7g*zUc1q|0ph{{CKLbMn~l5NrR8c z*^i-zUje+7cWkdfDrvNl&hhB*F+;ZoV)qiirgM9x;P8g13%rv}`*BXsNE=3Vn_{XpK zynHZ*ut1?z$QI2>nio~Dm5v4{oB9?noTiIr=tJdP)p8=Fo6B5dl{Vj@Db-A5o3JKn5) zdBrJKq?(L$Up^sovvXGtX(}b68sjF!los$Lt$6ljD<8a3oAAg?A_&#bIOe7$RDCNO zT#anfSAq5}`xQ;h{aD z9Vba6O`F9kGfoFJ6tei}NT5oDJu@;lc1pNVglEI29m7u%^=B|S|Ii$yNv7=)-C+>}wrYt|njdk~xBpdH*$#MRh{ zr~;FUsgt_+tXR1roevJJ$I!wuCCOvxB1TRODxw?{nvSwIB4yRFQn3vSlIVy!1syX7 zo~+EoNEkBx(5w0_B`H;MHbZgr3-+bAdRyT_abU6tTs$VIEaTiv0)0sYs~+MvCg=dA zLZjar-Y_~kj__<3@HN*$vr4A9Z+DoQ{Dl0P~HwStBNFdk}$&kjP;={#R z&7|TKXAvo-k`1<}!+ERix7d$Pu!VY8!ZDPfIu{vYC`MpmW!W1|tEJ zR&-r2+x3e+oO?>T{sca$9#$789p$R0w<;k66f`8-pg|O?v9hPHR=U(85-JUH-s7k9 zW79dZQ9oHV6@h{;bpl>*?NyVWsJuH_z3pg%4w~U3!(zg@?j^{+klI#N6@IDn)3F+g z5P&LDZX{TRe)2tNrYkFv!%(=#r&!AZB;>+%(Rv0uh zADCVbg^fA9L+UbyTCTPjG2Yk(8GofUbxVFvR-a`~GNyVDp<;ihaMq+2#&j(rlqyIq z=C>5sSlf6Yhk{Kh{_f0pKyRF0A0@eB5q0Q``<#+4MmS;m7(Ew9b#${yM5UEOjvIKC z2OB&(={MoGXWg>)u1Zv&a=tUxj?TIaYgZ>4?_>&2uK&|W>9j-3T3TAbkd)}pTqG85lZF8`Pxew}B}hGZ?aPsx=$sItbCL%wt=J+4XjRcJ72!>T&*1AM2mnh|$PMT$`jbJ=MGDHdV zPC6z76@f~f1O5Pq-_$nm25M7kMt=d*e_4wquYuEnk*eG|lF>VEjMbiJ5BO+QyETqm z;=TI~CeOUSdz16e!ID;UZt#Z?csJe`(=I|1ij|j54L$-rRp5&FfD9;HgYv9Y`QW~6 ze#TAubZ;h-^z+m5K+|^*YhjfK>gvd78&yE7)tW=^Sc1eK)`NA%y?&PgZ_@G$Z~cxL zkkfbLQ#89$bBwc{0sz)+axb^owQes`8&ICQ%Dk6n^h;h~QyK8cB2}7RfX03;y8z+^ z=Ck!{jyJhnT>;1%EL^^|A~Ni?+M8DdfVYwJodCO;al*mUEjP!@k3cJJmOo-2>)Yuw z^emY^*5CYkD`e)TbR@s5XxF^<<{1m#Q2gbT2%PxIzeBl7w`0CimkWKp(b%*-Zw@@z zRwqdGPAKzV#4$4Y-83Oy|AqKI-!tO|s(d7mSKeD6=Vj~xF7WzmGR>_23=o}Auss)U zx5SYZKPO*GX?l<%*d{#xFdG>l5$0oKQ`M`ruC+7lGn{^b{^+bqgG;uqSv!-l;#Ya} zuxkr6WxbAz@b6&z4v0t`c*oyR$42tmmK)TKs{445@<+~-Jh+fW0_&iT_bKs^+)ZHUZA>&rQXu)ZG6~wF*-Vz(g9p=L=}{n)^{dyzNkf{oGj6v-iET( z)cU7~t%}Frm?^m9_P29#N??0jl^gh<$49+kn|f6=@)LHsaEQg$@j}t>?U9h+u-&R2 zAZHyF&PnzUG72i^Ir&9_B228W3AoVMRw6!}D4cuNYSv`C#KA8RsrvHofzu(PS>K3r z7G3~)jpY~Y-+;kjW6lat{cu0BhLbovhwdMP_uovuRfLLg<#|$_kC}_Yzjr%3oSK{@ zb=Ykf5QFc1Hc|y{GcQR5)c~rfrZb>rdO(xGc${pJI~&=^P8;*{bjCw~rpxK*hXql= z^G}{#f^29g*JVQ6MTQm3`RR+ZvF|6E939>MdJoK10m`x>K5X_Bvn5RjBXgZM9BfDD zSua0I!>9o0it(&S&EKrK<9A{OpOp;kzWtQwWc^LW!Ew->EXh1ml;>H*j`trSLnf$} z>q95Dzx}y)o@;vp%!ZGMmj@!ei5amuid2^e|0fd_q1^wQlI#`Y$@i^UQgr(p*D^@U z9Ni`4vWVjf@Rz`duU&$Oas>Q%0pu!EZ-Fns4etloMji1@KJOn08v&c`cYtnt?!N3< zE3)5C-G$1Q9C%+Q=hRgFRYAz24FzAFq~^k;SK3E1&my&M;^v5oV9Effb@p6)w+wW! zDJIT6^wK5%nJt4fD3@LW{#U1;J?mbe9}Micg5pNFMj@qjBBX5u@=Uw=2CG@gqZd2C z<~(4jA89_)3go>$<9z-Q`S1ylS}xrB{aZaI0ofUdj~F}BK2}Plf7U{ZmjHZul#u|a zKH$M-%<<-%2iuAp(6P+-+wTA^;rJkl4rKe`h5WkDO4xU+@yOs2pt(R*e*}tG@vAdl zD9si90qSK)chluP;Ql-ClL|mZ)Vl#h%RVG-kaSVBsD({T#WMud_(X)Uu)|=I=GLlC zlZTt_7%0V_lWZGqAM@_sANKkStkLPY9s`lC{4>vr&UqEpxVmvykZCmz#kAgao5eM^ zrsJt+sqdy#P$!fTg}WQ!EY32%3d$yhiq(ZVG%l{<9-#FbX=3)zx)##g38CE$DA8_7 z-irki`SvqZ4|ql3E*xg1bN@m=tZfK`EE$~K1eeoqDYu(dnpB*yDH6j?@U^2%u2OA4 z$Ot)Z%ui_eNLM`fSjg8G?Ol@*$P@mY^R+V{L(tibe}7r>sAJapC6#6fGv6w}NWg_3 zu(<@W#WcAEEbKPK(_az^FL!{I>jwJgLP@Ek5u0bJ71*w;e)yYzJE@NzK444UwxpSP zz{U8rLWu*EFk1XYithn?FtK=&*MIl~@v`KtPZa!WLaFY8RQb;EIj~DcLZ5pA5Uh$v z%|B=$T}A+AsNWJk`RnzIcU1d%HBfLOy zYC-C~ZPhBk-A3Mh&cku=3{6X3*;SE{Y0}b=AR6W4J@@2TY5?C}?N)bY8ocjisRC{( z*G$>$QJWWolu9JXfmaG8s^i)pEeo)-r*PlEw${KCB@yRO2O-LNs)+rsyc5qwiy|p0 z_JoaO;-vbCs&V)jG;k+8xKcCGYH=TOT@t|JE|O>ImXsLRxaOP3{KUEQ2xN$Sv`{fB zyTItbz6WG#0`{_m^-m`}Alt$|<-%@MR9WyV{hI2A=ZZ3@ z?PFIxi>Q7|mQ#G^E|oj-bVv^!>QB0tEILXG50LI=iEFp!$YsDIU9NlqQrb=#$NCJh zy$>CzEt&_A(aZ`Lj7rVkcjJ&IdPx2|&f>SaBvI_f#yF_~PKDyNT2Km%wXUH%Zj>Ik z3O^3&L#JzYVS2Rc-Si?HPt~Q(ajp6QO`qxTPa=oZIL&nt?_RQZoHrW2D_i!##XZB6ABi8&zRnCim7`@rqe+ul2mk_ z?qbKAFFxWkeG1@%09qt?uf#4B^$1UZUb^in6Tq=#IBBMsJpLMBd;lPk81dQ0%oyC9 z&r;|{POmA}4UfE^0s033(eXE)M@nt+K~zVfV%1z7v^AR6Pf_9PWoN6KHo4(C`w3k)cSlOrQCNe zv6#}lbi|z8n&IkZ<_%ROFiRJIo=XUZIbeg%VsHoxA4`c7%;$9W6gA9_fR)r5V;8_< z5h$cLX!-^?E&>1@(ZgRfwZ9JlTfXrk05L^VX1SW3nVCsiA}MDTqg7ZG*!m7=IFWfi z19*rci-18+IgT`J=!yei{#HI^yQC44L~RBp%te44Ro4|YF|OnDGqt+ZCd+_T8-Nl< zKrU;R>bU{YJO6eKC>#OVA(6>CWWQWTzQD%#Tv^vm2S`P{B)9!z+XF;l;2gLSHQEEh z=h*R*mb)!A89IPt?ccHbvWoG&fTE(DFwrA`{Q!W4iNdEBq$suFf5Lwp*0*gi2R;tAHYU8ZNaVax?l#1(=nArb z*fMj$99%VX(UD2+_;%7iYUW}>Slscg1m5hYX*|kc2TFBcR>$8q$%8)-gpXc&)n+We zx_cuZ0y}Q*jSuP}O0UmufM0BOnMuug=Z&+9E^eW1b?r#s7N9Myfz!Zg5iHWU2KK)< zteaKo`M*LAwQYK_21j3QO4U)%0*6ILH__#9V4|6Y9n<#Cf~(g51MKMY8{kpQc{SB- zv37G4m8f#`2f|#eShWB|Nfs-92jmiG82&)e-qXb{yi_VOPnEIu?{sFp^qNwp15lZU zDZ%QmE18jy1Asq~2D6!`PKc+A$;0Fh04~3@E*FhDB>)OQ{DwUqLjpipMpyDt`yM75$W5+9T;ajK}RVLT`HyQtuXC zgt6W6oIP&im|bsc2oJjKgMR-3bS5wIR3Q&p*O>7a;G$-w_Xup!W*v29(RFi5`=T|~ zeLI|NCgZ2x17`X^CEGdMJ;vIEFw`(jyc#70&70#RMb5|)2XRx@JziIZtRqQg%VW4y%i{K4LYgRQsu zca5fVJ8_xr$FSEQWNN6oYXA>=dn1P0X5D~4<;p8rl+7-P$6|Kt?_pwSv7+(TyS^@8 zsr=L0KbQlXJNx>}(JUEsosr(UzmgqhG_REQA?T-!%+ti$wL&3~5U&~=f&lwB@g`?Ez)FJucxU6t)-giEZf^|6M z@qY4>hKngEI7F+AY{lVZhA|5c^hKGaJjU8k8W!{_FrL#2^Y~ws&*UndP10jCn)RcX z2(Q{K3Wyh$0>q^nOKnhO@g(#eUURHTsFXy*oD{}x8SjIsTz!5r^yrvB$TjS_Y<%QI>pe;G)^Lo(0G!VV;7vH_c)KH^v0cfx>RUqhYf)KjA zDZcwKXHaLd8q46D-ErL=gnsY6>_NM``G>2)aXGv`UsV!|WwI}bXb~8oBKQqKkCZq9 zq>iWbGb&y&<-bdZamwf!P+u$Rt`Tg09sakb0@A?FC;IKz#J~x0pa42uvix+^(`+1D zs@ThBHj??rpMTCy?g0GOx#NUo;Mjo3lT#INj~=)Ka<3)^8oT)Elu^N1R}kW3i0Q-W zNPty;nu1E&iwFHPgu%{wb&Ak7AorPDHAsfHDuDPek`Ba5ud@e+2v^{(df2q@nq9Xj zOz!=$f4{m8_yj4i{DE}$RHSCTz!snlKtew13&8yiSVy{iJN<&K($o_-^yZ-hJs}sM z{sxef@RvHk{;%RGzDT9rd{H)jw#;}*8Zdqa8q|e_y8pGr;5AMf=`X~v@C+GvpW4F+ zOIYr8Det9mjsi=67-QAkxrw+8NY@wbT(Oe?fevDXY}a<6dQuH5`vv_2o`=S@Yh(wq z(2p83W8*YHq2EUD%br;A`2t`o6Rp((P)jE2v|M?>JOiJy&}rM8hf!;VzZ} zz#&?m*0^Pmr}*KU?80YLHwuYC+1#cDz>+X`tQ-j1AC`4?#}FqfhcsxGlHUTaEz0H- zst|v1rIS2EbwMhfhJ%ckLqNCHYlWMFD0*MsBH|*m2J;S1>xVjduh}I{;k7zF4fiMim9V^yrU3ej=*8_hvYq~ z^Wj#M$PZQgi~6D|Wg;=wBvFpC@(vE30{mps1WEG(PQ}fy@Il}aP>nbS*j6R3&U1{! z3Iq1-BS;>^LnFXbx&|6~`i=D4$Z{sZNvy`Y_b!Ac_v|MD?bEzSJ%X^TQ2wj0Y{UB! z%49vrn#NLoKT91>ZW4G!qiNx1XP8^G72)&NUo?7dmn8PYO%4#wV7=RLvB)iwZ29pfA~9=ib)h8Cw{N zQ@{V(k3=NM)xOsaIZFE8a6i`Q^x0ZfO z{J8%*;5JNcmI+H*>90Je>1&QDjzQmQPuJ)m+Oq?C?qCRsf#M;m3#|!L^76<;Q!8(a z*ktQY>%E`t3-ueyB%Z3<1PT`Uy7P^Vr3*wS?E3hIgGE+SL+#$cUZ(sBo@}+jPav9M zZzfu(*G}PONC*RJpz!F!Onh&z6pT?zK|~zM-=3KH1Eu2IJ(ndfv)WEG(VUz<8(k8xB>gk)_gsqsudL z4I?0A(@;QzyHc{a)%rj?x!=ke&y#I}%qh&Xr6FgVxVw^Iu)I1)XN~7UA;7eMarm>S z`!wZ1pt;`8Uo8qEgaejv_m*$B^5eQ!#Yf6@&G9BcL zevWg;yqE^Jp%LP}Dd~0}7^nDFyrp*>`S*ffG@Jb1{peTTj=t<@O$bfS)~DzqqC1b* z*+`?tVeP>y$cw>5k2=j#wC!On@SkZIvc<3zmBJVJ^6|PD6N`dKG;ymItfT#)c3QvK zpW1iWn#4=g7amUI%9{`j{8aS`jm$Vp+8%?O{Ma21Ix+?4Qkf33yxB9!Iw=Mw!TIMYW zbmg{hoA_GGX-LM$qO5`oIB+g@Hi9@1M-ID28_I{c=>NW{qt412IuZ6QT)wn$yEsQ; zKW?DdsEB+jV2mL)569{+cXR$48XutoZt3b&?D5+nOFrkWGV%$_(|IjyTkmJAMFT(=mE#@zdb%E*RL#e$BNoT0TW81wr(>KgYw;$7@RS@O zuViYLvh%nzwu=N_?2XH1v8SJl@6 zEvyvWk4stI+ozugLn|mXU7CZT>y^>yh6qy1B*}{FU+|YiT*m#gKxiI;z1VJ9dp< zBw4n&yQ{R^Lr5w(5&zMtAgx8elWD2@#^w^zdI)*nBJN7%yRg&HKr^vBZWzyJi}EWT z1Q)ZZr5_x$00GOm%`&K>3sIgB03XmlZ97q^di5<8e|VdhouApwDtwQT6lO$?EX#)U zso7lw((4wA!ic;^XjgUS^XW*JYoyQibDcx5O2Q~MR2tW}JMo+bj2q^^VcF_*hOB$% zAB^yJ20<_jrN3gy{WNNsq1sY69JD0!O1uB@<1@6?>Nkdpjh%4l)vMSHz1jzUIKVz3jMt|L z>B7l$9I>{CI3&MdSWX!zZk1^}8w-u9{9Q@-%FbifA!J7K#E7SxFB%Ak`%8J0Hd#I_ zS*>;7jH&F)2Hf%%>qZ?#KO<`45jsIKyY?iIb##Goh%!cn-M_$CpgnuCil-(a!H9==!7D^efExe=eISL+;t>h6ch2T=oHc2Ovk5`Kvog@ zK&wH`D011$B!+uKn?uR>qvG%7j&lzS>Q^;h(~?D{GWXy03RXF{`UIt4`Q=jHOI`#OEJ_T z6q5MN%@!0WTsOz7VMor?e>h?dnFH3?5QO%0Pgu2WD1?Vv8w;Gc8$5B}e+mH)q6EpY#P4fMZDFYy0m zmH!W?k^8^I|GNpZ@-N5pAxLPZbl9MbRvO}W+&^Z$C!KVNA8J6*>g7Y!`l*G!D2G3M^5 zAH?MIYVj&vDS&WTO|m$3=yEq23OOV2Y4AcZtQvZ6OgEYL{Xfy;pd!MDZWYJ||KOIU z`IqT$NJa(0aMCn>D7bJT{~=Fl=s^E_ky0KJ^sfx3Cp-r9Us;$h4ld|lBhqJBbnu{m zWvD-8mR6qOVQq1b${w<-q@5-X2c_~=6d-DHl*i&x&GEg*(#)>buM_@q! zNm_@1V$|PxwY@k0NdbojXG2{c1PiS$#F;1g0yiCbNap_deEIsdV(~bI0Sv0CS#T0? z68gxX5>~>JQxVHCX>&o0>dupP29Ja4PGn7j7e)L060*3+ucYD1}V6q#d}!;+A&3a$Aoa7Csbo3mdg9^`J&cox)CyMTytnV)YjpoO*d9C#yxxZ^1e87=BbI2>Cvl8nmi1sb zT|y|+)xgU50us`~iX!_|H9OWMLMmyEU%teC{>2gpoA6k(6Ad2fPoMut1WIGD7W&AW ztL}HUMQa&&&WKH&?;Xg(Pa3F9VK|0<+GHxmq~xKx{psg+}wK$ znBeqdO8*PZrb?oGMJUeq#`&ov1E&U2EIxC;K};voy^+*?ki`3?ycB|`0BXGBPJw)& z(P5so9b??FQm4@B{2JqbR}}v1g>6^IfFuhMsS(R}>(0-Y5 z6ines@lW>uGks&^N9#j|% z)q+Y{@!fzCluP*R%*I^l^|n149w4aTTr}O_c<~<$i53Gij(j)Aw&DL?#|ikYeGb{I=C6vYY#7-Hy05DnI1VD zF0RCC{iaru6Q-c-v@iwT!nA8@o@sVvJ$(GJE|LU0?#nMI@baIx7FSil#};L$-xtDT zl5)F-O3TSI&bnPp(W;4$lqO8ZV^vmG+L=Vv)Hvm}XJEd#bkM{hA%zL!{!@Ps7Id$| z$Pb%4eqQ8Jw16x7t-KHsdx(`Z~$9A^Ue0X8NJ@Z4AnpPj}CeQZmM3!4FgN?I0P ze|$g)u?KNdn5=*@jo*KU;SBw}gnSb_kz?}f?W)br>{xS#NYWuatxDW3gG$V9MBlBb zq~!M2R?6Zc*RGdhmZA0q-d@95X+dpD_Sgbism{dlF`*BuLKdOE!f-2xfQE$wg1&*= zV%#p>tD+*73qJNnlD^yE8#y@`F$4Z-&=Y)5=UdC1%Rpbme)J9*WgKLA9eIMt2y3s8 z6~}ykpj91a6wE3E*UN%NMn>l5Ll`Jx{thYjYwQhwr<)V<^S7tZ7+YzU$KYyGA90VwMKdI-akEk=*I<$~}m13NgN!z=(tC=xcWQ(h#Q^AwL z*?N>*jGcLBPCreiOpqI4)aE{OnQuO!(vq<4sho#>bPdn(i)2wC{&E^`L4bC0;oeR0 zlcO@8u^}z>ZxMTnO7%4_PYL1`&fPBiiG2?bON!6G(hfzVtp5$_4haWlrO)U&7A{P( zrj3qptx0A)O8r&8Dlb+#H=S6DbH&jGO3|RoKIJB#qTB`dO<|uo(zclNxgPA!>NPjm9rNAW3IrE{Zx2WbsyrsyNWJI^bI1Bp29kzN&CHylH)Ydv))C#zR z+bR84JRZH|bEmhY$;|3ZdQ9oyuTu1=fh8<-DhoD@T!i=?4AsL;Wkd=AX>k$Z_J)m| znPP0s<{R9TWX*M78&9|qeeF~f^Rztocyh6FHI>ZG&Ch-x8KQ||mg6MGSjSpO1V{Y%#SRJHg*dGm{>W~` zxs&Ql2nTmC)-ZJP5>X*l#|}wjrICYtvDGUdFG;V&+^5R0R=<{zEz`#DQ}kC<68Ud1 zZhid6v#oWy9;gq+DDT%(d_*`SqZM=WeDC1kCW;^K$?hFW&=p4kDqb>7l{7?_g zy;P6UK@3bO!zqpgWFRR))Ui;EG7^5BYJe9M`H`9prO{{94r)?0(QE#yR+)v{~n2dv();$$)bvQg0j z)IcYRw&F}mKHL~H%L%GMb|VLV<(>|k0nfWjkFV_tKfEdNR6}Pj6dT>O6u(4 zD@uC70{#*fnz*2nIp+Li0rqx68YKgJeFGT-LIDdpHG-~!kmE9q?x0v}@jf1X*Y%O+ zIQ3As^$gW=;;2M7V%zy*n__YaxB*$4;n#07UvKWvQ z3=eA`Js_{eH5Jnc?Nshlmun)5&0wXw`Uh|zhP509_w?j|A{GSCq%9CoN$_wBc zKE-8wj>!Qp@qAq*gJg`^mbeI7;?rp7%<*O$7n+YAxOOJ0d5nAa9a37vQd)Xx z0(7x*B_ecjK|7v`IGU(oyfQo$>!e$c2v1gHQ`EbUa<1L0bZ6qphP5g!Yh`P$^KS%U zPTtb5Yx{~Vg(kYtEeknBP#F27O_*itj)IOlLFAB^PAhTLWmwNzLci6R6;Ig;OsO%C zuA{CV5CVF^iz><_74oT3H91yYPNtOW?mL;}8Tn)|mR9TcH&bv-%B)QJgNmMQjvZ9e zv@>kt`&j)2PHJ82PI-=0Fk0{j^y%o8Cftf5BH)~)F6wwiX?Ymalg7)Ub4I|g4N7#^ zi|37pz1WVrVi}(Q$aX87(b0#OJRfEudkx%zz@58p|n5T%HI2C`cI%-&mcs8vOC{uiK>=MuYOPG;i zsy(H`Hys0n#nvWul)=WsQvI^CYr3|EYO$J%(lNHUr(YubDrpJ3`l~-*LIl+OUVewM zhz($Wrb&iF617CiyL9ct?ybnrCly_>TR_Tvmu&umHVIzcFx|Z=z+U^=6|Z-ZQf3*f zo5289FqB?SwIfyFYR7k7AHK{RCXy9l#BfC1PN2!bLF7+kV9=0T;DBeP)xZ;5f&1|n z>4dsg(-tICyMd}Ns5Fq~Nz?fN?HbHgfq!)im=?^~7ON|m3+gga%2dEx0e zL|Bkpha#9g;_{81A0&U+#giiW&mZiw9xEb1ZBa^m6W+L@+A=w>eZ)&W} zo9|QF`0d#KEH7nt{U7Z6KaK#(ri}Bp}kf-J!Mjzb|Sy6@{m9O(y3iGv9z=e3QGL*$IZvbos*DEV==Hg zN1LWo1!lR=zBT9U5gR;2cFx4iI}Leuif~2vFztqn4>4oBQ@4#=&SbkbRm>~fQx@@w zTB`JW|U zd3hcKVMP9OdBvk&kl3V8!hnt*iKBzZ(C|6zWX|#B)qzvb7iuZl+FuABujs4KY@TxC zWZ>f-hDNaEklDtPKDpgAU9OU7Yq$QW`unrCmcx(qPv_#p?E^hKyaiz*)p?sQ8HK!X z0xyLWvZuDcfA|nGyJC%8HM7;E8=$ zPe@%6WmAb;_A-K0rCp*^rCi(YVF^7}jnyt5;R+Nt#u{~GjeaM^Zj4LJk@*m`5yX3v zSY&+REGhuKlcACv!O$f5?|>jAPpKBHEOn353ECf($GERziZ3%JF9zw@;mgYl%Kd!S zI_8<_RNj}=k#9MqPL+-te6>bJ@Qo0B|NHo!Om6rRyZTf2t+H8N+ySQn-!)(!GQ&my zyK=tQh3K(%Ip!-(luW;GX(NpyqCOpDy%D3N-3NwMG`BR zN->TazL(B0jaoWIqD-Z~L6@;2$~2j6FWCE`E%zBhXZ^?(Mv+U0gdgpxqxas)!(+^Z z&x|{B^AXk%Mko%CPspDt&?3N4dOjuGCYA1^shZZ(k6#TAD~mce5YKknn~0%3%V0%p zMr1@Ezo^sL^l@?75})FiIJ&IOH_8|MqKa79Tw=;Xs!p;py-vD1lLZUbzrXz{gB<;_ z_#z(E4gq*v6SkNB2= zg;psJLqvpjl@hZ$eX3QzJwvHwO)Zl%^6Ki}A@mwV1YCme{Wd8@R2DtooX5ZY$%6=P zJv_u!9Er57aA%*qb$Iu+Ql)gx^6$xs{oVvgYisLrOa1uG4R_2IqZI-|01u9X3(_in z02vty08|Sy6CR0DibFj3QTw+NS6;?&`rVvr-?#}?+K6YIBSxMNk!BYO>qiK4mKY0N z_vl~Tf+nV zH`yq=iIngRipuPl8Cltxg1{T_3y|M#FS!=Yk*$+~@m6Z^66bN`T5;hkG@r zimG1$GKn8*1X^MkFIsrMKUvnhkeQ;nFB{rlOEF$=gt7j`8ZfTqB$M}MzyZ*r|L~AO zTRYR*#%9{G{vViTNOrsP#BP)NcZv01=lhFCvHh^cbaZu{TwJ7DeFk1$FyB0eX65SJ zdw2}H^A{-T=BY8MJ%h*jVO;yq(b1nHB8?Od{p;0boFj#;LF6rjHHnPs7q0QHhR#`e zx&|aAZ$IHiFX=|Fft_pe#NjC0y@;3f1YhX8M(euT=?%-uL3jQSfB$>#LF1E3C^FvY ziT%Qhhotug)RDW{;mfS4(tXIOGauj>j=sJ^)exYDv6740A> zBE3+?6spTWd=)|RoY|Z1~z!vkCRP3-xm-8a+xUmYgm?AqT z<>2pbdhI`!s^znX)7?Mys<&F0tBxY9)Xyp?*Hd5Vq91~5klr??_lJ0S1MZ7!< z8e7dGmGZ9@cG%jC4x;!Ih?KeA>j`?$DBIhh%Nh78zDEYd>v_!P|uf5eCZfol&Yg^kfrl?F|OO3Ng3h)xt z#dG#91rDt>xA72QQ&ZJ}xN^BaW!%wx>;DFwB)&MV_+!qJ(cawaib`}1-G#i_#cmg( zHMS*8#8q!S>rNHbY^7oNj#(o77(N|c9QJXE!CT&sz9Zk9gUd(gki4&^xL(F+<&11UU22(S+m9+9~?}ZD^FZz?MUwbCv<2 zDN1ji4s(>&;VkNiEo!6AV3y281Pfoc+<$l8+jlQP=Y@mc{uDt3i*`xTJeN6}7-0Gl{$QuT)iB*3#SFOe5%_jL54@MFI~WB_g4vzfO3ThrhfYFW>^ z!zQ?6{KemFQimJ;o<>JJQO+}N} zNm{nArKp0^n;#^TBeGCtj882)Dwbff$x9wXoj_&qce1Gs-;mHIfwurc3WE7%Dhw<* z$jl9I5d!?MK`VZu0>Tgk0@2aecXDtK92w$SV(U z@YQK%it_wfIiJx5bcY`M*gL>}z!@yV_Yh%XTNy6x6v5}Mmn2}(VtyCwN2igc(G@QsNwkPPFQmhloo3S%5K5t79PRq$ zJO_cyFMaTSgWDg_VAFY$h}jnWud0$7#h;+}#@RNGZfyKdqt5kvc?DkNH?6lKEHyPR z05p%=^2_;@}eKRhFg7uXtxema>x&7C>Y#}F6T z4wmoOn{!y<%YkGmJjo?c<$QwAC}qh1uw_o3SN2+K;Xj?KDNEZ)L2VAc73G$8<(Qa` zjrB7b`N^Dj;>w%uBde>-K&d|+zC_VXanQw^;S>`WKSTdl^+-((2Z_Wm@$gbX#T~Ol ze%0w~H)4Q+aYsPisufo7XU^hJW7#akK^g~8UpWrF+p;!g?8KL#u3UQ$pT7Qn*z6Pf zM5ztLrZE@Deb!`95^fNUr(gTzmYZfk(DV{Vk?`I{!v+3+tR{L+Fw(3B=gDW`??(% z2@fEpmU;&~687}7t6{8;mj@E?Xo372(#w|9DpXJ-;d6_NQysonX`qePa(>+RAKl`S zK(t$w(X3$l)xj;x{2DZZRza}D=O&0X4KoCgHJb5`N?6I6yCOpW1?Q&aMz!7kbe!to zJuXe%g`JyKyLf7X>S>*Zj<>!75&4R>pHWtN=v6`OG2B(aM`IyCsXn-g+1EL}e7eWt zua+&^tZi%@HP7{lFiq!;p?rFU;D-metaq%KVCU&0f>4(|Z{f^=z0bW_Rc3Cqmquln<+7aR zV$j3t{Tb|iU`1`tc`|*R_h2Hqb^%;*na>jwIp^Nc4>|mgSPHp5^4P)K9!S{Sjpdf>DOP}H;pQOMyByYYsf?3l z-d4Er(K@%-Ff*fvCx&h8XYis)CB)Good>>6RhJk_5N>afud4~Bl5*+{fjsLiGnxPo zX(Y{zJg2_KH(XXGa){5B@7>2tIAQ zbM(+P(G(_@=#v_ny=DuQxaH;VkZAN0$A6IV^ICG$v^f54xspFMU#PhDpO$WRqotan zO0qZejt;YW8HA@)6=FZ?GE&44IK@@4!DYCO6~a-=STtiZBj6Kcnry+J^KM^UM3_(JIG(QhkbL%(&9O2`4=|lu(C~}(JjS(c2FnN3CX_l(7S4Bx z(4*r0KWS{25<0r?9qip>3kn{`o-jRf0457j%-7P~m^fZLp9+OaS2l!fsnpoG<+QNe zoTWE<&K+5aDt3VflmqE;A|fVPqm6+Nu$LwdEwm7BbelLI76DX1QN^-e_4gR$Ib~Uc zN{V7qND-UAao)AU9aT-;b$;m?;JYwAXj*TtGN4%Tg=y#lO`|2bzGK;+PHSqXdpPBQ zeIyEVR#mgVHCY?Qit@HM?%Z7%n4{akq^MFvnSnJJ(rb0WPZ@(1QeXvEa9%mz^&+7nu~7!KsKMQ64J%3QF?)mV z022hfS;PW@$472o3?S0sqj;f6q;59{6d!JX1OjY^S<)zgc?S3cj$U7$+EBb=2G$=d(FEI|EI(r(2|XXQ36xzxuNTg9>;WK!&@siE#W zuYKz7-a8Ou++nq}b2#@Jv9?hl7HbsOS(9TwT@2Mm@v(I1Xf6oNIA>hTJp>|yj|$i3 z*;#;m$>_+TKt%;pLqmj7cYXb=DH$1@zZ>%Tf%hPQ*|dpoB_t%C4is{oPFH!Zynw1o zp3@43LhPC!SM4IgJ3C@*T7z+)l%UTpxxwqLqK03p-MTFv-#&L!D{gl>ckXd5tlTHH zo5MSWjZe%Hjv48VKd`;>39U{)XF>qey{Z@32x!QDD-& zM1TvYAt;TQkhTi-^a)(}wLiCiJITxcf*cyE&qkcBSmB{!g(L8Mg>}JSqQkt*!zG7s zdrC+F<1UdlZYEoz{5p^vOf6?+=Quih4=h;3@=n(rb1^zadfG&eU!!YiE)@O6Zh3BD zzHwTUjYt{iluMKK($Ob%a(2wsJB^~dn&QM7q*uY`;W?>oaLqI`MlMkiQvB2DRo{ql zuZWFPJ#FOTk_ylhAo2F|u#P60c{)}33}79-8#FYepz1L6rH<&*NuV-mF5UZTf-^Mb z5=a$3RF`F29YRIhr#J#Gsrr}Q{;lT^JL{hv9r8t+iVVp?ja{Dt?%X>lWofV`CMSV3 zvANoA*97R7AzeWkFzZk)ljXny;%^jdUhc|1eT=|9$&|^#^MWdFa}c^TxAASC-3h!{ z%i`bThsafUL`Fy7&NpAPeW-lTUmadd1pO_okPv}mmLubC8yJ0kD>)M+zlWg9liC88 zJc5*>o3peMLSgScP8T6vw#~F8U{&uD()+J>z+JAyYox#b<-)g7r(|mW-&W`5K2fT+Tjx#AJX;{X^sE6gj!h~7=Qp-p=%05uQc09v$@1A6lrSX)6pd6<4B= zd)|-dx4YdW_jr}X>ffHdc786=S)#X8sAQqY4Ee3{UUfD&=22TT2Q+k-y&&6Llr>VY z8_O-7G8dQt#CSnk#y?JoG}KVBswk8)r0Q$)kxeoAbMK-;H~E(BKb~NUK+1w6-0KIv zoTdNtv<}c6DM&p@H6c))VMQU5o9&O#IeS-LZoFVh zrDHL{sDD-DX>_JPBFw5ISW%Ns zAUgztOGnp06vG5Do0mQQh-zhq*@e~R?e-<;*zWEdI+m*|b)cyov>TjS z{3cXK59RkPUt@!MsTz0b>>R*1imsV-Bl+dGE}fp;lhl(=2~?nqAmk||48VNL_+FKs zB&~`v!we_T{4;*M*4cs(TLM;*7()!!ke4z`P(q-3oy84g~9|d9) z0plXSP_Ij-wVh9Ztp;G?D6dQCEJx}}YzDTVV<#tQK;4uX_m?iB2=H&j$AoF?2kvI4 z;QHNNSSUK_`A(|-`87mexneb6ZN<>XC$&C#=||57#Cs{m%%b z_qa4hhuHi_$538QDfMxaujMUv2V4ZjRx>KfO8)HP=F`*1J-o^0L*lcid(2$F^HcAe z1#?iG!PibUI_Rn+z}T^Yo)f8of6sXH@FtM_@$r%0&$sJxFH}cA`Yk-Fh~4kf)7l!> zR5dHmM2IxiL`R?@@q3p{{tNifU?vzj4!Y!j=DTiV9CbP!5@G;7z%||L|7619Lf~c_ z@e#59PhA$BqCk#QWbl}GJ?94&zKUZR1R2?I(h9&9#+h_|?R=jr8?%~9WBlNS)Gd`^ zjyS4h{?s%%T7(w@^;F87&!4H}oIq|v>Ky|P`k=#4Mj3phcGEDJbtXgdzlp{4+47<0 zlQ#=%YkNR&nVNbl6sPRU4Op_EDX4#S9+6ru0F4Gv1@YTbdE{V<3Ct|`FIdYGhcf

9gsgsAx(84_jz*PWw_BlvmzY>iX)PJTm@p$coY^cledpG8Liy4>} z8$CQ^uBd#krsk?)am=_vPA!E^u!=w>C7b{PDtvbDIUR^&#f>BB4ySDOXO3N(TH5kg z1WfJhVu6#Rp|3BIVoFYYg-Z_S-x$U?nquR7d%Cu#;P-&Fx2FySTcz`cyK&mwi%bP5 z%g7Gljw9;KPfYs7%wY;5Y%y36C0wu;O$d^F_pL>!Y#W#Tr_*`vdDG~^f^yEO-*DZY z{)IJECct21RLoCs0?<%yo)h+t*;i5nms&#+5sZ-?(99sl;mgx_hGfe~Gp9&ElKma6DzRi=Ey^d7~4?IM!TCmZF z7kRNHc0uqiBQa3|FvD$+7*pI=J|Tuoue@=CgB{)hE+5cbx3=jfUkuM&9RvDoV%StE z2%^}`skxTT&h@!=2};J#MoJ~5amq-}AV?+bKHmqk?;VK=t8y~V2nic`9Z_EJ7YKd> zQy||-e|E0XOhSh&9+R{iZENb=#mZDb!i}8lDufcwpC^k`4q)DHgD#%i(@VjZLFo2F zxdOJ-cKXD_0}0U)DQM$gT@RB+xv<5=Qu=dmiW7D|T4cnH(L#A+cEvQsV8HeZF%&{u zIUz_K2JIU2jl^wJ8y{6nr0jRoRsd8Sn?p?b(o#fHiV(W7*K%2j_2AbZJ@W1(^7zyG zFv0!?x7Ob;K)U>l=R97hQ#GkQDjIvYCX-Sk>M#|IIo=8k3}zi(D0AzsK8dCp+xWW- zv!C_X?B!ZbauG1=&;MV#emVK!b}jO%y%Ow zw;Wc_Z*%^WX;SRi)|0H?r~061HtZ->+k8FGP^qX;X#>1upjKy^vHO-52y%MREWOh# zuo$hm&30oY6T%Lx!$@V*?u~&OX1!Fjuw1MLGCQBGwJ{+ZYeG4DeTrQM_HusqLfqAz z8o%^$2jr^#;FxZ%BT*FPX3v*Fyfc|9JY81&>J5-J)PXoec#T`Hg}QcY!AYo6G26`e zYY3@5JWSz$NHWC~&>9Q`e!q^%cCWRw?O|ol6@rG@LPfiu(~AHH$y7GT54$Rw;7I*# zZ^zp95KkBYJ3NDCG}+HVf5Lrw>uK}jbN4H$cPz?xDXPUvn)DHOYB&EJ`5nTde}dU> zl|X)$2Hbo)1AaTyzpe_+P5kSdj(#t7Bmg!C3wY!Jb;H5+CMn^#W_ppH7)}i4j7Rg2 zy=)1kygbRp-}_XJl)x=_;5hIWF=*y=!p=ZPC6zV^HEKW4LDqUXWq_$@?@>Q#?K*yb zPMvtrdH(WvdVWxnYkzz42m%Kd85BfkuPFqI?8rdAjFYgYvvaZ&`slY;QGGIF{ddax zZ*9#BTkEIXpUvkR{4F3wF|`D(irW!;4OFCBPI9O``I^ZzEsBqc6pd6QqfljwbV1GV zz@k^%?Tg^~ix*Vo$J01_h#_7DN4STafqaTN!VAJ$uDx%~WMT~Zf*_jB@tE5{KZ9??<<)- zJ&a=wpJnU%4o8lKiG;a6TCDBe-NmuIv`t=LQx_$SgP0jiOI0MyIx0wO+hHhTV}dBO zZ|?Im$grZh-&|q%(I{7+{A{=oAUbl>)LrR!(%x^OpSC=u7-h;2VpQlqk zNzCyk6}f=oTr#^TuEhuc;tijl2@DLNQx1sxiJO-+)z)<0&2FgB8NJ(pFY3TB<2kp-k-7a3K41X&FwPk9Jk41IIRc@* zfkfI#_lxb1=p_6lY6}2+GXHxAE<4;66^(n(&jD^3#JeY-*E&B;4qf)3&C{!vLU=Uv zJI8P4B&=FoN#@)C81dsaJPhe+{DD2O$=&U7~ zavNA(!uJflaSSP#sD&q=WbYYbp$d6sYdG$Rm}zIDvXI3eOS`9Ju15PP&OX$syRg_?BEEkEOFh! z|3^nywe+6~2*|h^a_E#hIA7qPllTH1j$AWktAzvvB{fp0;rt;{X>xk-9yuJD<7Ym( zqoXo8pS>pP%qMw2HV1*Gu~IbK*8A|_#kmV77-HLglFH;RLiaSU$|(oUg!Rw21UlA4{4mOp&%3&fK)O&F@2VXU>xQ_&MKDh8o&-_$7>Fm( z2tMAfAVg$DMV&VdPMyP__*||5k)#XVOyvX9;k65RucGxW5f-aa4lLSS0-JW9?qCO^+|o zfr%TN8&^M>`ssWnO-y>f?puwpns4PX<=-xiK6}tJE8n%UP<^)n5w01=JUT%^nBOWs zWrU>`12T_)0I2SV6wX`tO{(MQeGw)R3zbX=GO>uT@%m$B^`m-? zo}b?~EULDc01z{qX21rw{>%%qHr?%}NhpvQ;^Tt2Y&jq_n=Q;4#o;|&`UGsPPZ2;8 zYgqxQ9SFbo9r!OvoE%pBe-k~OG(vf_Gf8VZT+L7FPugI`$pU!djTAZ%;hb0cK!B%C z78|&(VHBf75iL*eUR*2I_w*Gmp4<*wG!d{_Ol&UsX=6m-{Az#U`a+~;g7lyP@_R|W z1&=^x1qW1=Z7Wt();6?+?%{seQNQN#OpK!imqLzsV=i0tZ$1Sg!uX1rapca-DCY?H3_$ePwpje`krhj88Xw;Xv^~B#tVgx1 zug}-g)+~K|i@>5>xDqL~%KC!>=4Y1h01sNc=_}RQy^9XMjPgn3QQw#A!ZCPcT^>ah zoQ_1;uq_P1G>j0AcvzTP#ym*t`uZ7(gv9NEt2|;4Tm2$K@Y(IT45b@MwqB&sAZOoSq#)kTUZGFF+ z`9?<{J)Tba97z{Ce%+dsh18&0TK5*g4;k1W)C6)IHI?ke2N?aZcgW%XQT(Gw-T!e? zk1AtJZKw{3$&5mMpgF;|U2;0(FO-bSgtRlTkZfZhZP~l(VZWGaMr^5Q=r0-jJfl@D zX)MyM@kh9R5mR)?VyMkG$dKP)n`$LP1l~XDzw6lc=)iu=qS9r zJgI|+OP4dZXbO%_WB0&-m-UaeZkHn-+Z`z6Yf_JzMhZ?tgMctZjxU=sWXl*d%wKIe z`EHT6uK+8De_`(ydf;>83he@&Fc`1( zpbbkOE|S;XY|LhlT#daF|Mt~iHo!@y`K^E)Fb6sL3G~MmcOI>ETu5%-QfVe%^aITxE&AQ& zs1^A7HyVqtk6PsG7DQDekFIsy{XmKbJYpb5M~PDc;($&nuz6H{>frOa@Y5o!k_ ztH?)xns-~ioW%kuzr_qp2uL@yS~qLOnbI5Xb7Z6Kl3Whll3d0n6u(teF~Los@|B9w z0MEC#Sf|Qpi8FTnFHD$?APAI8jT6JAD*+yDgF4Fp$ zEQS=+o?;87idi~rB#pVHDU$o*cqD()aI3`J!r9Z0;4z3AIN6=*gMM#5Qbdz{!Lab- z`nAHdG{~{ZOTTW`3C~h}%7p8>eQ$QjR;=2^ehl%Qq(ie)LY`_A$NWHn33KoLYLubP zi5`Z&T7nA%Qq+mx3vN$sK@IpxHa#$l74wz!fCO8prQ3>Wb83{PJ(F-VD{YG7uT(ZX zHKotX`(U?ttc=pz)nL=ZDmwE^1?EYz5N;heeCuvtd2?~&^!^g>m$r|$LW#Ys76>V&ur?Bj1+0Ypwr!-`B6r-0JRL z0&@yuQh&Ly1*Wgj3g*g92Byzp$XmdSn{?_VYuYk<>O=?QHMt_TF}{c8Y;@msbxVxJ z_S!;5?vapkisqNfvU%6wgI|MUM{(!#MJtDw+rz0rhGA7l_#xk`j`mw#jD$C4I(Bba!VssBbozSZl3StHl1s$pUcNsZ3Ps(~=iC^5myMEyAJ;zD8 z-X_vV7s*|4{sIh60rg@fJu&HftpgfJIvf7419WCh#^N;$mb}!4V;Lg=m+SE5`Y?HVnHA=^`+6Io}Xn)v4WcF-V02 z)98Qt*igo(i13kIbXhj${jFL5~KXw7lJkE3t>plNhSZ{cFe>{zB6A8-DqALOPG`Is%WF_tBY~4?(V&lmp+{;XUd1?-qyn z#d7tv;(1?tYyY}&-$HMjs?3M?WK=#JS=;#b8L@Q_SrU`zVIXwwZN>W4{2-zOlTy*< zUq&ht!7J&yY}=7slOYk57k{8&Do=j=YrSG@b1jg3VVQ91DdFTx-#B@F#U)0Ejm!nw zgKL8yh)7CexHIA^hxBqIn+KRKY+stz5(IksJQkBaK4OTG$9ystAa$CR8<@|@7VLE~ z?{kPU-2Qnww{M z5y(f?wAm#$zUV#HNWSX&@NST;>Ik5`&`^n|9TvZh`%Cy;j^Ud*K}G%M$;CsjBpH_| zx28p&of7gyuCgTca~@*wruGJ$RK%!L*w|B|26bZ;NVYtXz3qgEgRvuB9Mv#KYllr_ z+0*;tXktWqSWRm1IrL@sZzgy@d5s(_qynMLoSVpZtKFt`WNtTfx%1Y_au(H@>2Z!_ zNQox#GgdVe_f4q&nIjZ4`zENXf_&>E;v3b>ugq)4UXMO=kW=NK9|UiUI?n-UHC?0= z{@L(A67y;B1UF4y_~k4VS}eGKnYo6r?f4PYXV%qh=NX&C6X|M6Y%#FuOxQQ}_rnBV z&SSmrcVGdnG_>1m{88CHXlWd)RQ4T1ns1(VM}j(&txQF2>KX;;_H5Do5&7g>7-0ko zEn~YP;=O1N*c3tkDX!%yX;Q~zZacEqAmawGqMZ4p4*!}o_`SRR_pL(i^Y@a;7yqLP zhn0Jt)z+`2waxeBx2Mk`j?MS-zo68ZU2$Y*piF+`eabSQ6zFw3LeP6(h-MU$&qSAe zX>HR!Iq>kTZPD+&Bqi%_jY0`T__yCJwm$;vTA%+ZYNHg`W@cVq$m?cN_9N)DI52{7 zbkZReD4`<%OP2DRKzG zxio*?m^ko9lJJnZkb-es8wJhkn~nxHtu<>uz5 z$;~d-u{o-|ybR;+dtvJgIu(it|6~E===^Mh(ii#&?bD<)xnlS70+jchykcDUuXnQb z;%?#vRvsN;dQ^D%p|vgl7ges2WK{rp9h{$lYCohiQkc-`7PB=rWG3glLYBzJmNK9M zq4Wvt(&l^d;GIZXu$IJs7|>s+6zy=5$p`-uvuLh47fA5t=sLzGZTSa4q~*ApFeNyME>h(Z)Y#iK7G2KUwxpi z823_PurlE|*v-9|iN_Y9)`Lbra5w9`{R9qX{l3QpD*0FJ&sZ<27K__^AZEZTHydYxHm2 zCyGCcDbK(1{XGl3)bw6>+-%>s;@AIim%E<<6&m zmY+7Cj#2Jl3qQ@?evy{K77H>QS~#Ewu}{DAi~hGMngwc0hCauEqA;ANc`H3bvq?!1 zAxK?mc}$h*u;#0|xf3VXn<%3^@sqYMjczetSVb@f*$nY91~(wwzW33P(f!vuN&x+& zf(!*nU*&?Iq?@Ih+ajt=SJS7{Z|aPPI_s} zUtbLd=0GqJOyWumnmbpAG*y9ZXJ~UwnKAwuY~rXtOP_X7$=)t}K%{=Vl36T=kAR4f zqH17jnz&&fdv7$>lfK#Pl+Sx`{{{mQW7Eta(k8VG(g1=m`HE}BdTYf>wnm!4g=c3> zllS@(VnzfU#0?)m`;1JTb9k<>RVC71$rU1y3tvTj88xXvel@ZK0u5ZU95(R2y6%sZh17Cv4U^A?-Z-B=4#2iw@$;kB^}s zVHmWvh3u{W_2&`iq1WGIZ`qo!oym$7^z@D4Ul>t6ut$pc2tLcyx5OMx*e>4dxWyce zpZmO-bc&P2j!%Qr-P2>Luup^=(iHol1525yO}N%%BwhYMp*ABo>* zlLu|%b>1QNvMRxzeFn|e%|82fbe{>set^Y~C7^_#SZ4+^CMcV=%xg={f+|Hw2m z$jlSqpa~|FUIQPWY|DC2W%Rgu*18y*?4?QA;cMvkUt<>s>HzBSQ- z)f62fMno@@{auGvzev;Cstx2P+FX|B<g^Yr8-4kb>s;2#+i~yUS8e-7wV!-nw{y_vxj^;jz;qFT2IBxs#VGe|0O(>cw^C< zD&cLkqP%8W%vPS5yiJecaIbpB{)Rn}>Wd=0%IASv&XFSa=mFehNBCYzr{97!5efK8 zrtCDA_i>IEfl3ZogW+IgL`V@dQLqz24F9vxB7A#?3z`QmILv_;4XEb85Egj+>(rvI z{P&43_vykIRQa9>bwwQ1Ji0byv9I*>r-TsYmylkx${Wmfy~wF=VSAim0q^==QLzCQ ztAoN3XtPI;T@Fg(4;@ThuSau=r?xPnM24lRn)Yj%ps#7;Ec1fArhG&RlS|gt)?XQM zYZyPgCx2p6`gp|zkRF(&$4B`$3m3`KvA(|_C0pD>O9~|gmyvIvo_Kbkz50@ra8X5J zI%dtiS?-m9=|TBp!gyLveH@4vhe-kCASpqwdN5UAU}vGu+8a8-rK?GwB4dv>|le38XCX(Tq%*P#sVUzhhu3$zpCI zwSKFs>FA%B;7&edC@+RClWt{;sB)oDhKf#?p8l+RX3JSCnISoEU3-oJQ#5BAq3Enp zg~lJ`UQrc(BGA`-7FQIlUfP=Km3RVwjMKkLl`geWv+M*Y0rDZ)rJh=MsRaK!!w zWXq!glKVyJ&dt|hVl)**SsEst|HjpoC&?WB;67z4slbuqf&P0BCNJI2+?(51GH7UE z4A&ui%Y>X8vlda~i@!+>Me#RJ*#TC-Jd+~0r2F|o;$?bA1wRDnREdHzn}j)I5&O^L z{?HxmQuYK6?I10vVjP*` z*hp5^RsYgEhJ@S^2`$e>g>97}f)5y<0O^b+DS#*71d*mlb_WgNA@<<|eSiBeC_{uC zmi6zVcL~RLx$kw@*yN=l;koa{=p@Aq2w!Dfd)?*qx_eGIFK%vcM~z1-$IL-2I1jfk zJs6Kx-f!N>Bm3Wb%U8^9?(e5hG;lY%pRRTq;i<7k={$TbDQxQ(RU9&z zE}8kbdvOsb)H&+iKz5}bR$xg1V=_HW8w78e`-7lXX>I+b9bLobglX_k@lju900vy| z(3JIwp(Z!WEi_Z_HsHLe_xzkb+ANSa281|eUUe;XU9acRMcBT4s^OLs_8Rub!V$Zd zE&?eWd3kyFo4+5`vtg?!Yn;RwlI6I$N&YMM)cTzWHUmYG=m`Fr8v)89pod!*7ik;z z0Z027=@>X)cE95zVnhVy%d??GTh@=w&A}gj0Qs<&y%%2kHHt*G(xgmmWYyQbxDO8T z=Y>Ft-dd>JLxfF9E>K}u`So2w(YY>E=M)P9AN+2~`q+%rgUH>=wUHGieR6MX&q)W; z@1h$()^s1Nl_DmPJIFas#Aff{&|M%A3vze#5lSX@dpw+kr^=N-3d$cYQnSh*z|xJU zLpp{=v_-y!4V%AJNgHSCI!64 zSOgzB@B1Y>O>M3}1Cg}6JQ1-=1*WjDEjmasY;Pi6{>`sXAgSsj)QI)&RqN2VPw7_@ zxKh8cVT`e7#US0Ba!A1pU^Fg8^^4Spku}~bb6vzdrLrHCK@k=U{P!1Y9v4^S0b$3- z@40z+Y|&!Dh#x4t_PnAH7xr|N6jMb;TzYIIPC`_aUb4*b4jlU2PxLT7tbMmWfWEDf zPM@N8+?a>eg=sJf^Yc)kBnrA3eyMSmXD%tQ0KU`DPQM}hbpt|bYp-BwkL=CbGEBdjG|c*l0-u=NWx8B2z@vn+FvUxYZ@A)%6&BNwL(vzGVb7~d9GmgG-YaT2p`z$paaZfO;AfTpU<%)$rGhYRU_ zYnVofo zg#X0R{VL9UQm|l_aI^VU&@aqd7<|MkWq$!Wtf0kWjYR_|r_Ai*Te?(23zqx$LXcWS znXin0N>%1G%4}=WS_*i6kY_<1X4Pl-n!prOIxIg3v0owrQ%T1#!$2#cvJ$7~tAXZg zLws-~pq$n^^D(KLI1t9Yv2FwbYrdQ$z1ZJSjzRO*GB-6V;LFqg^7axjLD0Zo1%pnq zSaP7$NS5)j&(WVJmyMYB+ahND;_GNnWHCjyv8U-99%||x8w$jK17f{~p^>8^AqC`B zSXi%jYxk?O+@C4q@BBkCoUmslW~uIVax6_<(jQrh%X&Tq?2V_h(CD}*>^sX_)GOel zlH0FIBvL1RdqrM>s43d_s&I^Q6VW6pOgAWvBK=)Bn=NPl(v8QJSnU0ioA-qR=|zRU zPe9d?Nu6fxLaS3)8wcDM>F_-d;An!XdA~&p?dyb|bZW|;)TOP`Ufp1vqe-_#V-Wra zkEBF{UP>m6L6J_uD`X$h=srT`8AYo152Q3KO8?+j1)zbR-i{ntLHNHue)byK*}*K> zz<`8@QNnL7vOoFxlq*>KRlo8t7GlmV(XvshsLHcQ|8spBv)%%RCehT@OMWet{L(5J zqdAg@rC^DbKa zy}#`4NnzY+6bvX-Y84<)MITH0-r=X<-o>);>kk+wPHzSB6FPeQgg&mvl=@H%Pa1 zcXxLq9n#&B0@5lC(k0y>@B;*-TLgrmYu@eudY`X&IdkTmv-e)>UUwuNzEcwv^9OP* zOQAGr3xaKU`HbC7sxZH!dw#kMAI8iJ{PY+LGui$}sXkW&a6)Vfg z^fY0##jo6zRAE|($jrg!X3hreAoP6Kqv%=&i{uec@ey_OB~CSM{d*^w=T-{k_Y%m= zaVV)c9;~t5%xlRnL?jg{h0Q>L#^LfpS;1ck0T+cCz}-E99&=3jEyY-jH1dc6&iI7J?&DZ4N(sJ^8Bz)3C%xD<<`6%+kbCSIZV5(e^%ih}?A~8K*2$Mm_y$pt&iK?2JyPqFQA3gUi5q^7u)CvQfg5`0@EL|AcD+7pjxxP6gI2}7V6v7R0w(?)oI>wu z6@dwg@~318s!}wMoIVeD`V4BIiQ3bAVKUQG0*TGG7!d@Q2cXzm{?PK{$KvY$_zVn| zrNAhP_=tBP(>L9zE|kgYJ_1x~;ycUGm_(%TA9cZ1duJW4j0hswJlF}+5NjR9a%QKg zK8T834Xb7!c(zH;OQB4rijaC$rh-q7!;Y|{uq`2+ ztIYTze%G^I8`8zza|R5gfUIA+Qmm&EFGeu4EmA6~j^dY|q!}}erhye(4iVnWM$9)y zIe=I;S;{!DTrYVWd&4(pMh@(mU@3#4R?yJ#BOHn(eiZ*Ky3WE6GXrqe|1$XpnJRk_ zYSq?G+c(d&{WjhTWEq@AQ#T-d4(>K*LEu8PiM3GlyrcP`SYX)@?UJp5&qgrs8_9^~ z@sR{L)!g;J{@XPAQ+l*t&tT=1 zrD~74i80zbesdL}#vY?MhK-%zAEHXYIlQmNjlwBp0Gs@6j}p0D-Q`ye;>|Xm;dzRh zYq*D)A}&&swf?IRekqj3Wpb8gz*XI6F$+~3HyMGFcdU7>oY1nfr{pHu-S)`h?`LRz z`UVpUU=&dw{%n}7DJa+EpE8wn!$jc3p9TiWzc4LHc97YVc?NE_cW)@jsMyLL-^KiV zxmOihgMufG7)6>8^=XMr{RnFr8M3@Lgr`b`H})O2o-17t+uhvc33!68wy&Q_phSIGp})C)j^n({UgA*bB+*=d zBeGGvD!Q||>BY{GlB>Lr(1WDmx_n{tS8pcjFU~lMOmB&H!1w)qQNG2EO8w8>wvz7S zYAWP%w>>dC%I6{q`1@%daFz*m9Ydxu$GTp4I@*%D9{WFzF+VR&{O4FlDEiFgzk?VC zz{8-ruV~n~)Z0eEFXJRisLEx@(MuS6mPO2(1H|LO<@N<}4c`+YH6;^ z1Z@o6yh4f~JelUIJeWDW68R`2Huf+5X z3vnA7?1%Oi-ek+ee}5Z~D8;IdPb6FfXapsu8^gR8Wg6c)qol#SO#>fSj>`i>e$PqP zqxD8rY7hmd^eecStcQjCGhBZL1PS_#KF-F^dD19EaWPa~L%wP9I8;#y>hRhNQuEvs z;YE56uj!e>1fh4tGrqAqImbOgGC2CSI1|jDjwj%|jXEf!)IaMka-&W>lAl|5m~KX|hfzoc^zGG>iuD*B+k zyHaJ{XWEcPd0*jp7(l24)xf9J4@1Gt2wRe6hw&pE(L^THMp)26A*bPFn`9giZD%#I99bO&( zeTn^HKy*#bOF-u!*z@G!V(lq+Ps0ZDoUnUEPsiD-&K;$K^oy^?t&c+<(sjPm3E83h zn|}qns{}pTkj}^F4xR#_uzP5h2u#zP%S&wG1Htbk6~|^Di~%W)%>SS;tdg&wjrpYM zI@c`9EsI<{g>#NjvXnH+Zh{miDKvNmsr zOv8hoiSZM94q;1cBDC0Ak#mwWdAm>&#d4%99X}g5Y+1Nu9xFbwEr0ZF0a+A47aO(4 z_=i@R!S-M_UeEzLX7>biV8og}l{3L8YuJ`~!TwjLt#wuS;BG?Pt3DK<``E}%R85pih8wiJ&*OqO|I|?z7mE@k+6?k=M?FbmN$#zfpa{nL{2cT5M3WS`n zdUDe-(qv&Ze53-(2kBktKjxl;+vD~9K6;ok{o7*oPlh$>tovgJJjzL7KTq(Y?D!WG zyTVCQ2N4P7g{Y7|O@i4=yK%DTmt>n2`#MHQ_;)aH2P!9zUnCynB@ROE#%bXuz<)=J z^*_d+3r22in)sMH8uMTGGJTPj3V29;0nz!Jpn(f)QJ7Pgx6c328H?*yO&R4r`^%mWz-j(4FOOTV93 zTxlR089~nwQ9SBQRPNt+^HNlB=;vr55M0VJ>@f)2JVQo=V!8Ym<1%gLw3&l>lTy_rea2%qg||x_iM_UXK3hYtJ}` z1}*|c(_QRrTf~lXTnUQFO!~|R&{zQiM|7GRA@TW=7rI%DH=)FMXY|gbeRHyaSaAQ| z9#d1U8gb6(s4CKvIV^p&zx6IvDlThm)GP;2kUe{J&lA+Ld_R0%smz1Jx4K$e->8ZwU)p;>Ea8p^0hb9H z))@31HY?ZRdKZ_9k-Cka`IdV)vf4(SHM9O?uJJ_far4*4)h4C5J3s=;VvZ+ccTh|w zQYSuuN3-iyZjbAB2mU@$FkX+@Z zI!}0)iw092Kq94enlJAj(_(i9OO|~OFrwKEYhGLf#?0(aXr*}Dr`ez7U~tOotebyh zdL*i?^E$tI)LI!W3U|m7XLWj;joxn-j++qWOM2|vq+NI*E9(Se`P!_z#qG z_J+xX?7f+u;VY_E~GBK!_;A7^?m;MCu|n)t>< z=$Nx#MMMnn1v<-B4?BSbrtWn_uvY?YyfTAeP#uB?PTACk$;-$XY+CJL`37rs)-wQv zS*`-|jae<61H#F*0!>-Z+5czT9&kJl-VJ%}Luc7~QY2W9tEv`s)fpTADseVMph zu0%M+cGs|u{gfz$>bfuWc=d+C00yV&ow|)sEGnx(Ij_%lem+9>IA7QL^OrG0M!Rs- zlCLfDxGfLx9sBe(Tp)US0f*z75-$dqng^RfRxA#38#wK&&|7CMJ^8x9Pqz9I^-Z9( z)m7;EgxO=>)YQ!v?YugCpd#&^d}pd1p>WoX*AVsS&-Y=L4a4{MNK^Y1EhgOx zPvuPCR^`UaWXC-!fDZvVrTG4A#s+Zcb^mx&Q=72#<%grqhnMRx%nAp*=-x`7E2f?e z+GL$nBs5$F*IdQt>u2hA5*)Vs!9Nif_{E}QyHh^tasJEOg*x%g=O>rEDZp+#RlS6n zdD$U^l`!&05!{?H2o@XGOjE+#zdLu#IG^J)jSpsG|A*ZutGUILt(!DowxFi0@gGS% zUuk2yotIO_R1MNStW?Xwa zANtuhOn*31BkWAjyEfVX{6g&?z4G_(OIv96#XFbvI)#qT`2V(Zy4O->zhMAv#I$Ol z_qH19iwH*ER1eo>gDf@Hh;oT>L@rUwfVKU`x+_olp`-BCr$h-1 za3ccfWoHI?b;WnryI+B}G*Z##gXb3odg$*VvZYGgkz8<;moVNAFX`ye=1-+fd>DN! zK>5xe{FtGx9Y6~3u6STMBNB7uE#2ug-nV7N&LJE5j5J6lkyh6D;8rkLTl$_|%0pc{ zMVYTepY?~cvsRUB*}g&Rq>qL7W}v`n;$6^340++l#GQGDN!u6wKVTYm<@Sb1Digq? z6s7)zTlN~qg7^Cs$KNi<3}&nqI<*p2f;>~YAeU!+SrWbrFfq!a&gvd}x?z4??R{cN zk}Z%b4zn>3U%7(m|003=>+_FvrO#QQ3WlKb-|Tr8KkKx9)@?l}$6T6?qj~MIfrs|h zRAOmq)S5cGY4pIWy1IH6TqQey!zBE;Q?zSs6)fXO3%%bB6(X|$C^D>7@_bg0A0YC~ zR;7Cz3OQOD+S)ow^N37LO8ZbQP>g41BY!i@{zvjzrb0(iL`mE`g1Ooyk>ruz817su2VFSHO6~N)fAE6}ID|#JgQT5rBrg)CRI6 zms9}uy&SXks;*nJ6D#5>Qacw_Aa(?H%!#iXGCw;;R5vK`0U~F?+;M@Wb<=InjJp6; zb`z%xwDJzpI$1yfN#5bke|_Rp;ZR~X-qm`83XWVG5mIi7m**lxIty70XROf{sT0fE z%$VbQNENwYXgqc(dl5W-{3K9I3qiMwKc0dKA%6O7%|qXA{9bwZu_|g`=o`rpwFf!Q z2u|KtjsxT}f-xp02q+?;P$H4gJEod2={5XFlek@hdO)TN31$BH$OPSQk1R#Pz%~dO=AkqtP%avaIZh z?ZgLo1A@SO5y($0xdyI8L}oe-B9f{l8}y6y8KIW26p=s*noLB=O&($lCPF-DQRip@ zJ|tl%{9WhJ))r1Jo(3}?S0X7H*;zyL9YqFk%lMXZApAK#x`dw0jnC<|i{B7I{1Cx^ zd;0-KgWSV6uLu)>2`2*vs1llKiz<#l?Qg=5B2@&2E97#1g%M}M6I>PSl80;3FTB^j zkLFotE%pGSQ3jXmz0n&LIh`}zb*9&QF*G)blzs^BN6ddzEC}vD1{G~Vf;e)a?AC?7 zXD9(CV<#L_<^egn1p(b-`@;{~S+${G4q(R~I}zKRZR;P0EERi0RqH~hhxU|I)p~b< zh#ttr!C#5*#gDFD@9br~;mP0{9i#E!qRVDcuUF!~G6I|I1VA--2oXCKi`8vTF>;hU zSwCVW$b8@G!vXAJ$8xmhqRY}>Xuhftc_uJHYfH6 z+|m+8Y1Zz)Iy!P%Z+Jx$8YX);-Z`2K19=H|Q3?PTEDkv~jAS&v)m^B61!@g2OazvU zz#|bu4&1%5soPCDM5-}cHf5d^o0VP9I7y8!`n_KaKu0$5O(T=nE%)LYcL*opE)q}% zb#4-?s(3oq2v18?iT|T!f6;#C7d3dz-{4+AO=4;2Lz?uarB%E{)3vM}wj@2iClW0H z1pPmb3%nLY_kddV;9n=qL7dW=$k1&wYxXzA>{5=ND^M#V_vP1k8-i?8cDQtFOkJHM z=V6-sH(&~}{L4=w)SN3{#sBs%SF}TYb8}SY#q@&H8WWs*H(=r;^yToGR1$PWA(=<-}T_B+WQD(6jXobC97xd@+d!iTaEc?z?8?FI?!WT1 zA@ncE(+Ry>+qSLI#J}3#cs8a(+!w^y=|r%WDsPk}jzTGR54s1ku^D?_-JHh&Ppv_} z?8Qw0oiBE$+YAQTtvTLvj5{=J9?#nU%lsv zw_0m?Fu~6h)9FoHQTE7I3#~`DQ>+Re{ny3<8UL)hL|0O56`gJ^?31i)+jn9eN~=B0 z$wy#KiF6l~o9Md!-%8n|JFcF1_K>A=D_9i1st3PwbRSYx4**3joXS1J;qyevJ~+jI zLV@Y^n(2jGh$_zCV8C1jc;Qm+564yMG;5*!`IC1J&4yr7d~x?!a1P(51rPF*fHmZy z=~d43zH}O0{*)F|od)}xA0hkLrsN}F6$1N+ATfHBuKYSwgbanEr|i&TpZ1x4h5o10 zInKisUdCjYA;iyA)A&$GOLm8)V~vNK1Q^CIuRTQ`eVf@IexaMs1+)k{3NFf8>u9xs zBd@?O_ZgkH3oV<^<0>MgT7h>&arm1e^6NEwEcI8uVRq{;HO@fqWpx0ky0Suo&^IXX zfOw`H>OR)DbwExYBwHES@BY(Pq^BQB9{wHJ&uO!bb@P*U0t(SWBLw^YDWRwuZ_}rZ z9p7h-M3zsEcu={Lr?$4^+p5d&E1?Ppz=Uf7P6HvmGkty3C)WfTWtxotHJmtFR$J}5 ziB`gb6{N&H+tsIt|FL~(!@qam-CrH8dDzCTUq~S`O0_Rf>d2@Fy@-?;*1**?nkGbf zE6!A%I}^7f&E#Z=B%_h4vrfkI!H=jG<~uRBR>FfsLiyhSaTCN^PdXzEr3ytrDji7D7Ydt5rXt~BxOHhj~#$IOs!H;8AQ4p@Me#JD!rhM>M0emT*9o`N`^}A6t886!H8DUh55gg+`Vnq-+@)(`TqgqKMXk+un6`O zP;ui*7#Y7R0{Tc{=W>2ty62Sj9N4f>X9}O9OlSIhF|CcIM&ZLnHlBV>?Cn!h8$f7z zMJqI!8k(M{!9+640me(Y%Qg&sMZW`nJtClGkF^1KHSMAb&K}S{r;?C^ZZ|{E`yOBs zA9V)D2~ssJ4K}zM&Xc55$8rEm_>Xh2^22YzY@(T?EB2pjYeP3r!t*$P0nWMP<3S!% zRmBeG*JIYQvQ_D=RlH=K_-G47-2wdZQb8MiSNotN>iQGaEvtbasXlrzp*^l}uGG|^ zRNC{l{TDcE)0^V0n-r?zNyct3T zRtTw6`(SnrbPp!{Kd$~1w2^3OQhf;oCnyj+Ei5ptt-p@2C>j!xBd?*;tqG!>rKGP7 zog5{lHmH)Xan$_B5>G#1!-VyUX)4lj0eqbVY^Q%=O*iXmo^%E+>j%X$jvBeIA^2g0 zJi<-kN-Ke~bN0iqkHBGgF6*p&t)RexYfU|B?t>7mjQzn&9D_sCYvs3@(V;F5Y?EQJ z(t44Uy&-3U3x>0)#x*TR@2(HO-TXWix3YUknCMCHP0GGGTeBvnZ+48S&TcTq6cnA$ znITFXv0`UO0{zBuhrslR(ZmLV?{lSiJPpVJA|e821zK4X1h&Bmj^!$D$EYnQA5KkL z<$!MRJkO_%QM6{mr^$6+*=G$%2)6H3OdBQ@|ghw~$cZjWTc3icco^Uy#f69zDtC9l^{{Ib+KZVcrk=+&6!-{_4| zKKBP&KdAYjpLhS=kWusi9=I$AZMK=`W2%jjfH#QnWyG5TOi8jCuAOhY*N42E^!H&K z$wuerC@Lc!EdM#aV*WrcygGAqQ#9*xHhc6(qt5sI38~gdX8tPB#nhIVaKRCM!n2*Y zOKLxS$a2ijxLT+7*m!^Gm(6JxM4w#`*xtH(drM(gWA_jH{JsszH>?R{7+#~3$taT8 zY}Z+-F;O1q!MNs9MxU?$xptRcsRk>o>wTW#B@-pRs=3J%MO4Tez72`6ZAz&)V$Igt zZ-SdxNZj)b5mdlt9X7_mYHJhtWO_`vm~DEpNJ>W#e`CY*l0t@Mct>lUB4p&~$OwdA zENDvXQ(Yj9qV+Cby~Jfo@4wc=aPKBvn@Ob&rivVQ;e_S>(g&i{^mg$*vI z(E$Mm81QT_RJ|xcY3WcqdUx~X*0<85%st*S;dHSw^d$=61jtZKJs_#rGtb3Zo2I1@ ze%?jmkH-NE)Qtra<2sR9ui5if$f?!EY0dNn80EG3#3t?h2k%a4ng zpUhq*YZWj2rsYjCbt|GnJ?|Dul1(wJi8#>ZQaOIVmy5sg7UlD;PsduYCkc++-`@*l z&Z{NM&Ty-(f%(1t1)*qs@S9gv{D+1aHPc!FMrwb%hSzW)dGBr7|8sg(cmjKMa?QRK zAc-fiD4Oe|*>v$_y@o%}X@C^931DCp)%98Xzv?iPo8LvoZkY6%wj=XvZs zu|n8??4PwmCr(eTu8STq7aWaH!&m_G!*J@PUwh26UP*5#>EPLRDO7KLNpGkkv=2&p z*-}Ua%@HWPxL<(#5bw)T0e8BqRp0P91^oz~o3QZCi zp_7#Xy9aK11$ZKaa1zl;C%1mC1SYVYxl)OFgil-kZ-fd&=U9OZ3$s>>np62ggyRvZ zUuKI}K+LAOkk;m%TZbk=5l7Qjlqqn9l$uL;<1t$0cG* zsYM6o?<>Nje;(jTE`cvgFoN|sm8(AU8M0^XnHyqtR5X$Jha9%KM!j>&=EW2gF7onx zH?CVZWZ6KaGOr0)n-Wg|oT^Xm&r0)|Lo}PfXCDgn>R9V7U-$)l+=tuW!b_lFssJlE zkEmoDp=`p6_RMS~@eWtxvB7W`fLH}bV)K$cl?>Ycq;oJXLyuOng~By0hg}7DkhC)G zJzad!4HA=Q%2l5B19UIH^9v*P>5(#pR~Lk%q?^>7e!aM!4)<0Fw>=8Y4JyEox_qwR zhefXt{=VJnkiMT#KDX3ma#Ac~h!QPu6F8UAp$dxK6(&H@0b35C?<1YUKZaXdzS2oS zSCz<2TuJOzz*G2u|{Q&u3%#L z)1k2hu{bTXU=O+7zRSK0eDG@}C#>+x!6y?(U-dkHqMsTjjNalbKmyj7|C%-nVns+7 z2N|5Z``@fF@8}9)u!Ayx7*-qh727Cq*6;wnaPH*2_>idy;w_OG^uSG(5Q%StjUOAC z4zk=#i*G?p2v=?)(U=F3TW(?uYs4FW$G7Wm!eakOOVY+FVl#Me`pcmx$t(U~;o+VY~ zc1eqhH%|CU`hQuaz)n4g&x)I3{>0mT4e8_>tI&+&KHzw=V^;ij@q#6)e zA2UFo&x9}ZdemhwETbz5wA@6t&v)biUzK1=R&VN&#TCJ1{`^S@oGSCnObY2d6e+o? zmEe*Bx`%mHl%c2EB|xYJY$O&OWv~$@_r2)nnUXpNp`_ndJNIbbRl2s9`F+{*H;ufp z{^ti(fyzA-YAIr=S>2~c3wW;>@P;_DPIH$BU{};YfsC-QAo!|@Fo|)Lv07Fmms*9~ zZuJ6*Z%Se`4)?0mDB+pxvl!j$+WIGg74l1T(xd~Ckjq4dlu)J8hVsa|ZCMa6wNVAU zjVkTL(+9!qH3#snu@S0uSwv>E;5RuMOzVJb7$_9_eZq@{1ym7dYPLE)%()+&zJb*& zp@XuZYA;cTxZacl__MJpVN3mRJ(+bl+xCB>Jl|1ryDjBCc%HZCIPNIQpg_C1W?bta zq_2Cvji~ZbjxL_t32^082T@#-T}IPELQE{MiolW#ExMub<_8@32A~9e2FgaDo=SgdZ2vH&B&k>6bzQcuYvsSB9*sqZaIGt-V9BIZvskh4hpV9QNx51+w+V|#xsr&NEGp-{npT(x zd86@Ej`B2mFRWg`bF>Kq`_{BT)h@f{6z|`Hr)P9cN)q)+mri7`Bd3G`v$7&3V)DPzyyn6lgOxT$s1d651nOrFk;h!yPRn1dEAJfXMl9N?EOcD-e ziq@`co)U$dYO*xB^AUl7%`?bbD(|c)KMzl!VzZKyq+1S{w;&@J5U$i1WIQ`hf zEGACATDg4KwBRq5b+k8p9lOlhrd1l&+QSX3dC5nrmz=`Qr>#XSgfOxDD?n*vdS-6m zJ0o>o3GQ$6O2zUafk*F3r)MBL4=6yP3H;z%LAay`dAbeiMa0Lub-@R=Y#yYDw;%(= zPDJc=qV6vDTXpXeU1l~=6Cb*qXno;bSnl0k9EE055qkwZ=j~+h1MwRV>9hetIPVt% z3-OD$GeUZHcP15z?+w0h~&ax_DP-($n~| zrlZS`FEqSk`A9{U-WnBwST@li z|28BlpvH@Yz;ri?5x+IUVdXZYfG*DcPf46;qUAmmkn7~jHGy8h+(3^D=lUE#Gn~X2 zIWsS|8R5QIEQ>W863tX?+#yajl7rx-qyVC&8p6AuQdUh)Mana|$h6AywssGKeU{+} z%JcB+XEM$HxzStcW4nn1rDu2NL!oxfd3Z9%+^>FoZzTWS%>MN3)$%Y?|4K~wWkpoS5(ew0NBq$_eMdB9)`GnahHG2iKnDMoE=tSU>;m37e9fW?hp`32{?XU4m zDB5D{m|k=LXG_ZDn-WftCcPRtWQErvivnpNN(**l{3flIs7xfb7O$0j>Cx=5sGZx5((h)z zyo#zJGmm5E3OJ0l!JFUTj5^y~hiOm*1^f~!9R71`Ho8G*^MO;RgC+SJnt6u2uDM|tH&;k1(DPs1~Mhqq|<5tDq zo5X{e=l2B#9G`WKa#VXnri*I>#tHPjA{w~pb9wMRyqG+&Pb0d&=fX(>V+Vyg7K> zegnPx%gsQAk!rF^_Y#QAKAr|S>uI$I3Ve>1Zq5%^{%@tV0G)rB#-y9kvZJ( zjz!FQpVE_xB@cFqSkYWI`*(RQc=-BS3smz9p-fTRcz};KQ#I>)(qLHBU>pthUyzC8 z%YX~-W&)v87|5IQs$|xc&%GJgxKGcUOw6 zJYYUNgicIPXKPonu|i$dR2eBKH1|OP!f41v{>m%pB0QpXgQrNJP6PQu*8dd7)p^-} zi7dt2(9g-ux>{yfGwdZs%h*RXg841>E zc|(P+pN>sAWX~~pRVq!78#|#k4O*?iLA}#{p5tJNw0|T(59*?yn42(jBPOhHppB$b zu$<#%evx`PA^Ud1ar*(&ae)xvHXMadv?-J@%Zq&{-S2MoRIw~kEn|;ge-m)z<~W7Bn%9UuYMeH=&;Q@#4YIP%m%4Y45zZJw}s{N-y8{ z$pxmwVHC4ruRwaYo4UJ4<|`k(I|G02HGmpr30um1l>+6xmEPD~;_|0(jTVC+HcRjo3I~%|=@J){%3+Zz$ouz*9 zt@|A7>p0r|K49p<4|ahw3}jS~pYOYndEsJGPVPCzVW?89IQIy>+p}jbO|ab?fOq+> zGijgS(L}x@895aY!<8hKtzJ5wXrA#P$Jlw7wQbb?H8Xv|aR^v(2^CP6%XY69Z@=MG z=`?<%j4mOP!WV`rW`wv=4%FMX`hpUr&r+F~9T+CEs*GM-Hqw|A(??ratWqSO>9!~Bvg^i;j~SxL;UuO2nv?K^1fIp?kE}ka{;wp_-^bjVxAtP9 zrW5Oba-i-g-0I+)vdvy!!~>71!}Ce&mqjEtc;y{dw7UR=NK^)vtd#&c2*9j&dC*<# zG9rM0mjB2bNfVS|TMs_U^TFz>rc(AlZRqNDwC$VU$)|rNh9)cxYUtm>4IcMjGQ_3I zldq1v6Cv*m-?{zSVr2M4N*wKT*M9Z^cj$>hKM^2BY1wtK!68soJ8V-yNlDqzsy0&a zAnEvHXw-x#Y*IYj#!JP^e;OA8!;3)z`_~YrQ+6^v{dsTDK!S4ON3LoG@XRA0DW0_t z5`%}Bw;Ka#I&n&6m}KetzztbW#g#cB43n$~GEndS7fvCo92osdmk$GO2O;buVNE7l1%mx!T=hbE0*Y8N65Dpqs6wjyFcmxL%M$B~=3M5pm8w^eNA_l;dFG4=l8 zaH8W>nJysEuNCV$?Ffne&Qz5N13`mAI55we^(nozj}rbAFvE0;=3m%o zip;9VgET-3)H5EQp5FtO=@SA|`6UB_9JRh;Q`_Sy2TE0~0oz}NEpG#dl0wv>;Qk*j zLA~Io%k9%=oC6yKYGL8dRzjShDtL3wHgl0eYMZozKM$A~P%mrDv3?CiKu7HsN{G_9J2!<$0vmHEk;Hi>#l#svgc}kM!gGiv7 z6?RJ3H}kdXzjP{^fI;)d-;0G-jOe%NKWQeIQ4HkVb#|1Qq!2z8X?<}88~4O>Mx6tQ z@cX8Gm8||t9P}MNS97~l^zpd5RhM%(?oGGi`f$J+r)fD6JTZ%$%?=-owLXuoiMg1s zf0*!n6L?i(OI}-iv*Z-m{__~txB1b=JiT%?)mI|Kd3&h@@ZH?p0f?;b=w%*%@7Sza!Edh#V zL-Yx>xRT7KCa*@;(gjD0JpLP=kR5n)p#sl$?-cQ01N{FZX|0wdiphs-{CHvcykP*o zfo#TzJ^$BB`iML8t_#dZTd$&-3@&Dx#=i1;t}N7OelpAX)(FH44ehjzi9srh7F${ z$`(~H#slp)2zCQ>F5}8%hn5BxHMVE8p;vDe#L^O4s~;#3C4 zQ>BJAa{!pQbam~5=giH7r&9JT)ii4;#;`@SB_fcq~Kj;4DiEq%uiMYo*K06Y> z)Fmo62t9mK7514_b=nH?JeGZH)wj;x@{PdoGyWewPm(r~jACYy*dT!3uzA90V1RG;@q@EKLhPg-ry4pyvzDplPh&lw=M`r$U@m5Nq*=+Hp%XNY$iH;plyfMD+5 z!&wTA%P>Sx6Cm`3&)O%RwQF}Vhm=Rzw12+nmGbZfChSL-;h_8j16ErB@+MP<-MEBF zM~Q-xOW2oJcetbRDf;hGIHwYAoBGz*^}IV%K!sfy@+xW@i@KhbXv3{B*%q{JSxsD$ z^N!_+2H3G1cE}t80V4+i(_7kya&`+lu zOIn{u(uJhc*#M#^iQ3^eEpVRRfGD(xuMp6Ws}&yX`YRIG5QBUWf!nNs0shGfF8@Vl zj8JRDw)h5dM(0pkY$b2n{(8C|w|RSBfbV}^SaG~mJO7TYUlDPz;PDYnA)Sjv4a{@P z9Nv}sdX~adO`t86`g1ZUc`2`s_^{+eU%>PjPvJd)tFhcOJ5r1>MslvQUG);CbdOHt zlkwPeuQVMB7cy6wCJt|&@Si`*%P6W%{~O;9025mK=NT({FzROK~NYDDd z&IIE8?pYx{Ga=Mtn40&+z&9>sGLzgu@R*`Aht7@j=mDq)m`xM>8;^KRaguFciFja* z!wYQB5R!C!{TFcQs6B3TXX2Kit#`ai=6=!;(dS+JE^U5DC}lr1>XL;!1SDk^28&5_ zFV=G)C(b-s+OaFQ%CB$cfnSYd;!XT6sIU4eH*8Q!$=| zpE&i#kP$$D;NL+gq&(WCQ*jIY9$@oBm(<=SunX{97Pprmq*-^@AD#MG0`vXIf?>2X z!grJjEC;@-%llxV6Vaf$WQ(6N+@Cce@yN*)M?YKS$~EPdFc**CNMf6>@@bAc^*&GO zLUf%XInkh$t2%Ztv>~>1IvkBITcKC(puO7N1->|u3v;r&qN$h&Sb8^ksm>o^bS&6- z%0@pNPtJGGy*dg+MOwov);^1a{>15Ur4tQu7|O|QXP^h2PxDW;5PY2cIc_i zh~Ene_gvK(!CqjACjbJ;>h;U$H1ICO;3;EyGhD)d|AI_I~Kp275ua*J_E ze8?`c;ux&XGXgnC)ddPwd`S!wgx6xT{SE7c#=likLybCsSbC1iPzh3W!D5tUC8VH% z;xxY0%e=UmcT(hz|G7aBE7)Q+>(II!dLb-QCqSyrC`QDqGSc{q`%J3$51gMnyt&v* z{hGH3^o2{`TSOw&;U$XO6v{F|ctuuu;)q?B;B6L2J$P|&;I-{T)JQtYd`1YX!iRWR z+|%0L_I$6oJbdT-WkCo;b6DWhYM>1rgkwhmoE-^1;!4O`EYuvH3WHx1f`js6rpC(9 z)d5nb&ghC}Ap1Cco_D^R$q%ZD1Ip(Q?hEu-ovE#<+T%!FEUx`{sIesWFGS2r=Z~5e zf|a`$hdeSN>Omp)dC3m#ey*>mJr}D|!Tbe(h@S>h`{XbIeKbKdC!pc{+a=UeUID?6 z&!<j6-^n`af`I#Lt66S!A(jpp=8*-yab>Ap!TsqC3h;U z%P8@2ObTLruERtV%0ox3IVsVF2MG)`+iHK4d7QHCCC$PD=`mx7k73oL-WLfr7lmlZ z*X!3CqObf$0gu%~w@MJ;cTG@!o58c31fX03)nWGpe)hn>FUE((L$oO_w{S{jWN~% z1y&Q_NM*A0KwIr952ZnbH~)?+Q``1cS#`2PlcL zWUI5V<*=-EQhjPec3<-Ch3eA`p{z#hRt=r1#=LVPo2juNUL-KnDsB@$ydOrbkFFq* z){xI*i`zMr&4bjbK%D} zq&1YY_Og!;eO{%RI3ZHac>N2HrCmIJ-LYTn5QX=tmdt(}MZUO=5Byz0YVjCxV2cY> z))&98Zh*(k#V*M%Cf)O!s8i=4m=YY7tU#e$-O^6NL8w~I%5Y1!Q(LW+N9fN>$YDoZ zMeb04ksC9F#J|wYiEp?WHB4k?tT7S5X8?AU#3Su+1vo)o#g}2qsO>yPjJ7NQ-)w=` zDkjD)N0oMaRBo4Gvrp*4^8L z1Lpb(HA!14%LYu3vutFz_k*hdvmQhOfUkp+Yp_4(RhW^6FoLyVEGo0C-e}4pAatMR z*7L-WoPx}{Pr7TgH`yEW9lo{_jUn#6U@U6#i-mxE*;2Wh#o?RZ*=O)k+g=s=FW&H~ z7}q9Ijjy-ouulBoJz4n*Su%uUM39Kj#8sIGD3i&O&aX--k0h{5ieeG!8;Y_ot#hn~RT34n1i-RxU0({c=o5r6K zL^_Zs(kIVam)Go4a)1sX32>|zYn=bpniaR%hMP~09Vvk>)m%Wxt{o$eHbTUS%9^Nb z=1TP523mw7nO~A`mB&`}1e)R22Z9C1hrC+w`EGpq)++O9jrAw0^OuGraNvdOs)EoB zMU7uXSM-bF$2+}MG(ZW<$R?+F`tII_1EJ>zAB)`QgAPHZk&0#N;Hp@-_!)XZ09LnV zRdel82ink6g#bN2cpEq#4r;x~{~88D_>wR*$4mYnP1hYy<^R6VF^^HGW6RD;MkFLF zdt`*nh=lAt5+^I0?Cg;pLiQ#rNs=V8g(Q2A^Sgb%uivZw>(x2Wd7kHekL$kf>pIl9 zMGnIpO=B_d%vYA&HgrOCS?6=xmoNDt7qe?cNR;0Fhol;_YD&YUh$A;K&6}8cVEkv7 zV{K0)>WC`(&&dNWKMHje>D^v|PgOXvNf&m;9w6&;7!hA?=GmQSoo9rn;7}Qv^mdGd zkHAsP>-f4O8JPir`_>M{f_nR+&z*fCc2&65X|@tW1rJv>OWlDN$yxQVNN|NKf- zMA-bH1qXzB^JtLC`*<&OwDTOK<6`wwFZbNXe%?_GMf&A;e*O%`_s4FxoAiIXN00^2 z`E5JsOi8QseI?XHD#axjf6Q&xqGRL&09!V0DX!bRvtwfYU`*rD7jOO|>+2{nQJ0yk zoW!($GZA->vRHn8O8L$ZA12~1etw`eE2#B@CG55|{o`Qs&9=`Ujl$VwLMa<5@?MK2 zhTko0k#E}%Qppd_F)dtz(iO`s(oc|D9-pj;*l&b~b~Vztbrq>;fq_p3`eFPEzSUBN z_p<}syv99Ll; z1V`I|+&J{qEKNRq{1c!$ZO~<6^d>8%JVY!T-j`(zn@IbSuM4D84pE^qs(1*v%ChW8H9Qs zu!!d-ek}3q=(dMvTeh~%!;zbm;V)lu2)`dhBPQ1wFhmFMao}dGdY49wi}y(!xKERGoyPhi*dIruNU@zY=*Pn#kxKe zK{i_Nd|77uk+3LL!y3zCz-ExUVymV)(;!*%G(xZRJm^=YYcz+*ZXRY6T~NPPg>ZqO zyO5)gR1La;qs>(w#APg)neObfmkLEuk^u_fiD-6qD?BxFeT-=c_5+Fs^~ZS7Svur# z@Z<1;GC}nhtKKk6HXO7s8BOx}P8m)njVdD@6pB5(eQoBM2^@eo5;y`Mi|+1fYjQ~j z3m6O1Wk7O|TXB=88ykKT%q-6)e~C2=L!%Unw~&s&=}+mT`oUj{%VbND&iWql0Y5SI zvz}v&V$3nPVyF%1`N8{6SXGHLC5m)NMXcN7&zM}E=~-xB@VTIj4u2Vy5a(Y1SXBJ? z@&SIwC$^|GR6|rOl^M(Hq$~uv@aM~ynLvCD-YZy3-*J6f15R&@ z+kaQa-cL-Vgg_qVl0?gJBZ8toO-CW8CWzac_?aVk5hjWw-_Y7wnh0TSvUD)Zw%#sud=m%!n*uS|l z<5IBfTuqhC)1I(uY8%LFsj&W5r;<|vHwiB%Y~WKmgEw{_!ykiK`0d*zjnX|Yw_!e< z>!pt7GvEWy*>HB{{u@``C~AG2=56K+cyhQ-iFfL<2`d3Of?`&|&zP(hz73SL>y2}o z;kGeMTnl?~Q&*oQql- zz8{JVGeKBL!wfG6?DB99m4y0U-aWow%@pNnjv#i#T%;4kAyLLWe&|=Q*p?M99lt7UL@3qhY@ zWi3HSD(8KH<$HF_yI-LWo-wDVCbh>Jo6V^(Iu3sZWfFqrLlYSeyJf#tj;1eHGS19j z%C1?lRm#3*-307nMe=0Cm6l$OD<^p3abf`mhtoYuH`uweSp-z35gDB_U!<*FgG4$! zgvEbx93Qt?leyA1ywyN&a!l`pY5VDz^Na1-w@)q^ONc^w%wK; z=lv^5@7ZqtS&FX^$;vDn$7+BOE70w#_*Oics&gVO>)uih6lBkh8yw4NLX}H&ZK2F!MnJ{|M`zUS3oDx7d&IPMrno5&d%)2!f!$`K=K-K z*k5t;@HaooJAW7Mzw(ClU^GiO8wP?Z@SjI`KMOoI_^Ek*P>+G&K}w(qsEN6_!6ik? z#}DznPp$sRzClquGQ{b%pRMQ9V8mWG_1ld3D|L7WPJUy#nm^Pd*&u9BjLd#vBZ(o# zJW4@z(g z{|sP1KcA(fn_=Wa2=+LBDVJQ`YP@JpVR5?gg|hnc;Z(%PbO;cvLkj$C$*$1?%cr9Bl!WbEJ$Z~7$Ctw@yA<0>~(eHur z(d%*}b&x}Y(Z7HF?6-gJ$oMrA?6)~6bFX@@;KnZ53@2`r_aM|qczY1lk-Qp-^x3kT z*X;15QZAIJ@A{pQZG2O_B4zqYcUi0iUyz!?H|Rfj-moS!Bhf{^xezu0Gk{LEVb>+;IPEe%0>?F2o~HdoW|bv z+i${tI*XtF`gCs~1G{@14`mOVHkE?3K_-g|(rNt~qQEA=%d_D1(nn&LQro_<>9i98 zA2P~$DE!dO^vovVihCtgX3CYvF|W*{ABWoW7kyKsE8~0iOv7vI;MQL|sowW?LG`WF zuVgnH;*&36ypwWl=FavJXq@b~hy??KDa|{8Hkq<1TfqDW6cuSm3*IKt-MEH_iG9$3 zDzrp>x%7dYCAxU@&R&)zsP{kL+xLfRy+hdEP5tW2Yv{4Cgenv+tkkt1KSXjxBUG3W zmQZOmQ`=ku$1+iIpAIKPsU_~~o85AT8_)7(#+ey zVs((338yTC6d0OpdJ8)B2%l}+%sZ#y85veE@2_{rM{hhm|IoB3N+-i3C|S8No_g)_ z_}QAb&L32pTq;Ms{jRxM-0dPTnmm-iArO!t#_eeGs zCFhX1=-*Lz3-Lrrmi(HVMYO~9qVMKMry`~j*gMb#LjO9~n0W0#fjD^Xd4E2;y3kkQ z!*O(b3mUP`gW!;+b%`w&guKlE&UlcPG)DBc6uZ9Mf_KZi(?qJQ)&s|r)A_k()7!nJ z?7~L&wY8b=>h>v5r|zdlF-Fgu4pM7#q1V-iaWx+!C!eupn-b%G)V9Qbt9f!&FCQT) zCH0s>uJ3Jh{rl6?Zzj^*h)`+zfHS&^ui0b%o$hYZf7oHlXrjU?le#-EL4Rz1H#ye(=l zxw8CE$=i>gN`9aX8ytV!n*O!!>lB+48u>P|FIGvjF@{!+M0q9vanig$={i*nrLf=T zX&1vcRUHet{=p5No8qez5kW2(QNwr) zr|4ui8gt9=?3-Bl_bvfW(5v|VUEB_grW+1JqyDiSiX|xh! zT*nEL#RG#R8$;21wD|E78k>RKNxGfdSH9I*+p)fyyj8`^g8Gd&3kEB)mkL9TO{vbr zqj74cK(? zW%(UV+wcwgv0v){#Vn@~7lhXlB%x8sds&^I+W+bLS?EbdlP}tema2S}f`Fhw$>89= zTUV!t#N&fx-@c&X0I-g{7}GlU_b>i-cY*|AP&lhFvy1@iQsg=wCWcwovhow&$vaH} z`B?Nl|34`CHLcMF`?bddEZ>l4lplnEXB}?6VZu@E0EU z@3hIeJOI;lG$HQ^Q2@HPlB)^y-ljhePnMw&6IGkW)UPb1!`C%Jn?uluI5IjGyjH2% zCoOc&PEv@g7f9j{*G|@7B5rDs32_Oo;Av?mk{5!#; zsdK)!?e_zXGkVxWOO2j9Rb}`5c8bXAvf42rAZkchAU07r%} zSe)2B=mugjQd=yyx>C9D_!{G#quZ%b7t}@+Mi#*G@iAq6KZ2KIfi>T_s#u4Ccfdyq z4}q~a0to1Z>8INdc{x5fGYi3Qy~KhC-x}iD>2xoy2YuU*B$$WzrhfFZ&#J#=C{DpyiJomDo$$(`XU8 z>dq?iZ{M#?Y%bI%vPuu|WPY=w6H2=tgLs38^=<#39b;=s9J^S!wyai3QEr&Z<=|Xw z8x77vwmE+w7S-Xzjbk1j&_D7{qy;J5|HhpApC{yEJCWRq;F? zAjPa}a5af7#zieP{HQ%WLnD9I1}}Mw=8ILY;7Fy!e?S^!wywTRR?;Jvp*d75cwR6f zsQfmk)ZWGY$`)U^zES3izb8^tKyw_=4e!Cg_jaVbI)=+*7vAPUYvD9IJIUFOz&j$h zq;d`I=S3M)?HUr5^ui^El;#jpDVjVJqE};7^0zWa5xhc(t5!i~k?S#G=1eS)38c4X zS@7hB=WZioi>#m0%Nr2p9*#OBJ2X z=;d)+!N{*dJ^Q?pb&sM@Io88NlokW>;EYCwq_?tIr+L4SU^ctbt%#K328QM*zq6JtC5%&0a3EF9i%cC%cl_ifY)ne6!YVUmr`kqdV}#@ zt?9CiBKY`;`f?;HfL62D*-m2p4i!T7&B0lM=qnR=Ig(iqsP)FXAAe%N@6e!4GO0)W zL2PMda&G2qj5S{1E=d_4|=NtoF65YnjTv`rgKPu)T!7k+boQD;#;3w@IaG^pXF% zE4Um0*>$FIcfwotQrLnc>p(>Yf>SzVO@F-t@yR8x1&gkPT3fC!Ct`^76Kov&QiG?e$U?U97`>!?CJKVmP`ERrBJ z->NMxH#WEAuBN%$uL7<0FV=1c%ftRT)vYfr#kDn6*{|J8vRW`uh*NlM5KbO!;+%eovLc|MlzljWImN=D z%G_YWYt?YUFy28lOS-%u8-J>2&e@Mqzjrx7VAx*UP$1? z`hKAakuQFeO%MAt!`5!faiQ#C{qnF54Mq(1$`us`KMSZ|X!_Q^J!$#kWX-wMh;RVZTvy$iuGlGZqI%VyJkPauP8*0-Vu%0q zIg~Z4|Ggr4bfqc*J-rEN)FfF>{SkN2bx0{tZh4qDvGy({iyY75s}5VZZ%`~PB213; zRr5581(hc@Vi3cA#bSc-m%~e+mJpk%azy4QQ^dzX6fiV-c`K^uB)^d!!iX1PJPf1pXwPKclah|W4WNuO^?m_9+G z$1nWvD~VacciQ?~JHJ?oU(xos&#PKEV$i$Yynl?E`FZh2t-VVArNycUn?G-CKDdc6 zqkca&a7j~z({X+;p>>lHfd3a;K#^pr$&<*Pr~)3kk7$bitkv#JJtdIV)deignZa%% z$C!_TfWm-LDD9#qno@micy~fq=F)$+N%fpQ_5`qmD&C$dwU3r0y@%50s)^RA9u_E_ zGCiU$F>gkp%$+Y6E>G}vt$mkyE9{*aA3^%cYN0_owD}+ahxn=Bu}SH9^&^6HRdxN;tGp-N^P7~fL%9=GzdZ%{Oi-T1S(%ilRbTy>} z!-V`;J_6p6QdzAH4!L`&9B*vYs!powufDOtK?x5^kGPR`efUyFf0x(fmV;dTvA}O} zbyjeV&KnjZCW=x>tf}ExbUFN-Ih}z*U|bs1ntpL?;2We0&}Gf*rn1|(Jy11N{>sY| zNp)}*DPTw*B8g}$u%MwLCQh=!b-9!-$7*n)oMZ|}&&uXd;)g%aEvoN!hO~#EDF}Xq zrW&i&?X3E!AG+9Qx7dO@(^NwkA6O{Ny9(dQ*QywHsN+grcZl52utX3e-}U%X4X+1B z_D~C_8NE^VrB*fM4kx<@17lKx!t{(gOC_Fiyc>PEcew6-_(ub;Ba%4x zyIzfm|Cu?{hq7C^IRVXk!{QeH*;lQ zvE8;OUKND-lrOOb)h83L+rwm6MgWwWUA+%eySn(j&*n^l{qsnmcRLlYgA~thNQxt| zEFO;1J&2fc41@=uX?rHvG9}o{sR4W00r4Y_u%pTJihcUZ`a{BJz!FF@&#sqJ7vd5F z1VAw3A_OzxD55c{P>DR_@<)aj3m#3Uu>u)UISxc;UaRqGC0wA}NDj+nCxhlQ4S_u;M0-K3?$N>(SszdE)%LBAeG1H-MgkS?*qX z5DG8(0U^81CnvAZM@M`ayC&bq_LtwT4?EcBaeb`PbaIz(cQ0U5#-WNJnpY<4D;l*G zP8%fS$91}n(9zA;E6wE+139w>DGp^;2w4Te|IFPzduwo_=VBjXL#g?(umF8OByT(4 zWUIy~7lPpA)iK?(fX#*QK)BO~TV(0!cb0bk(#i<1okNx_HppfLt#;unlP+Z_UlNcs zkgz&zF&N%Wkdu3*;qUZuv;UUc*na)rzo0gVH{fP1(m3FQ8J*(tdq7GnxX&5cdq?xe z(;A*KJ(7u9DPANZd-W)aE!%$LM{RHbGbuIi$sB$yuhpXIWSuhl5SsRf>mWG!fFa8d z#CapvHT<))ufl`=r!=xqP``dMM|u8;CB0Sry+E2!E|dXQ92m&zjJw=d_4SBMZV8gc zyA-Q57|Uy+Ps|i%hQi{($v2$l9oRHSLK7z%2FBGijj$5&!{hbS{NUB^j{hbE^hP8U zLeoVrhRtCFjI){F*^~4-JD6vcPaDv*-bQMsjB$xZN3AwO?ILW#MrsARrcSVA0nA@y zfLV{3*XP4SRWNLF^4Lp&b8&Aq3DWNs$a2T>}aVW9_c=w{)@H&wnp? zfA$qL2e*{fE3-fN5UB<6mfV{zgjeu{c$<9VwFF2b4DDNrIQ2UW5iBm9)*Ws?`M*0n z6{b^%>#q9eu}|j7g(w#!4Fp%J9tG-&8$?}@Y_8^O11q}$*YktX)qyH{eBaUAbBn7| zAPT{>LZ;F0V({zyl3((w!iZ_bt$k%hsMY&OBR#9_u^gsb82?9~nFme$MgY-V) z#+6v|wqkAbAkTkhMB}XYYx!iCz^Am_mRl41;U-P>F(6fzz+E}w#SPN~rh=(B;g8(Yr%1T<8ph6Y(1mrtHY*dgK8$;o=3mzUG zqPMTONYY*=pv~C5vvqPxi5M$>&t)h;lL?Q{)#EI{4;yr79$B9Dt;81UYX*GCsjfQb zg^#C9T+cyA!uZz}#~W*aNFaDea`Z_K}X-{Svw#-BQ{wBrFQ|wK;yqL2#}skAw4{ETMUpw(@OwCNRx?heY#6bpLT^V zN<74Q|Gwh`X#~yr6?-xXWZ)fiAYsSUT+pZD+H?h>CFIHfDbo_(OD>>=`eT#syp~?k zO8&Iez0S6DN+}POO^xzgED&0JC0U~bSEnoyZe4GHj{}ZBcJ>m`G3HE*?w_Vtd*ef& z=eAf7DnR-i)}Tbin_jap2QlB1_4N;6`oxvUsQW3prZeyPWUcGBIpU)Lnql`ROmF1xKoWpm>xGgNLw{Cn}HN<98?MRiR#YKACq zmOK2(ypISO9UFVU!MoBhuL)w5`k)&XRu_X7cTUzh5tk$N~;~Oi^ zzFXHJOs$aJBMJ~pExFG}y<{4*hjkby{!u6;IxngJPz9>(WKo!6!J78n+&=8ot2enN zw+N)7=g-tTurJ}++b44;^3a4t<@$MEKpR^jU^C$@O=2r6lz4#ba6o_XBKNm`tujbi zk3OAk{FmX0XeTB@Ow<aHH=F5`-qSd{IJy5M9y@#GLrEuY6zfPBmQgj9t0ED>OcIZ;mls@xSZuBuoAYXkgIJ+1dHZ zSv}A4c=ob%N^6*r4Yv)Rsf8P`kQt0CJ{vxJDSDCk*nm9C4@Z{LENi=hX z2b8Q>r?&1~I5=|`7!rc&bwGQI@(*3aeC*2mUMDXCIUQTZs3*8Xr8A`F9Spx2MK3c-{tTL3$kyKFq8t;+~zmHs7Q?IS9Ez)aAG+g?KLLi2= z!Oq~rKHJfqtf^7t)j}1k=j-LkdwNRMcv2}h7)_o1Hsc;tU^5`kIDWOR`AOH*l(l^T zpvm}TXYDUb%C%?zLfBs^{li~$xu8A@ZLgg|OxQdIGIcz;u9l6+t<6dCf=6wMt4ZWy z<5gzjLqdK(@XCsKQcH5q5=FWuIKrt&UoP$V5WXM#==QzQ&e2h;_^lqtvu-@;V3*$S zA^*<>7#vgw!K&e9vC|Gg%8I)*eE-~UNoQIuc=ykFz-Dlt(msUm2@E zfB)SJaay~g;=aq|?cLBM=s}rsZ3zl=WpzQ}hUI*fl4al$S{}URf4x6ziL!NvsCl;Y zgt0wsN+3Mfj7}t9J27s)OwRPweb=AnGi?;#GFkMBgYT#BzX^BMb-C zMH*w0aAwY};6d>`AvY2FPW6#WG-a0nh4;gQg9wIKB%1AC)ZKo0b*-%@zv56uI+?f~ zgxreE<)SH2FE;Mx*3|=EE3abh5?;=bwXcl7Q$V@@hn^?NaI1JIxe;fq(et3UN)y%d zBU&akIB1qZD&-QMD`{7!fSt~+BoQW^IenhLVCN`!VtRP<7W_Ml%cM(S%^ogzQ4c~U z*j@ba_L$uT;JueGN}djUJ8P<`ypB`MjIxqvUSoo4t$*v*+AyVBSFUjhnig^DfG?d% zZ341h6nK|&t?#80{D|)VX_%&0DqpPAICAqWHt`Z7>>Ipjf7(-sKEDZ9aPXm><)}7hsXRc8wLl zGuA^*3RcelhW60^`0NFAqFWA8AdjRa{rp9^Mbx5kHTdi?o*upaTnnp|@M$Z_~r~=QTR5EP8B^Jqm2b(leyMv|Tm8 zOyMYGe8~NRbc0TZGtaW8FJ9~-ZA5oa#|&DE#)5_?N`VCdwUu-FZIkJkO6|&>M(Yn% zYCqSgo;_;{dZ9q0-thOzOoB1p;NWeOd5x>evYmZa;%n4R*m=kLdarIfNx9H;m72l5 z@0THB6pl_kB=A?&J5gniBa2%_+JJNzgNXng6uoBwvm3eZj?`s?`nbgyALh%KR(3$& z0;ORUgWH-z;i{#sL(Rd)iS-|gspp@YBVrY zQL&KrAChw?0EG5fv;43r@T7n`-{a-m@E6fXF008m_T%S4C?T1oMfEWSWkr~!xM!>P z$FD)-c72PBwxmMl_GO*F^#VPb+?RSU`-dg+3h{H`iHuK7QR+U3TxCYL|0171(_8 zm3%WM#j0%ejh^w@vuDC-pb_R!4Od4w2o(|Cg(}|plfQ8iB(zcduZMb}6Z>!Cn)_C- zvDxb~`~SMf+1X?X|IG^Hhm7QkfaMK8b@=MA{to(cur8}J?iF6E`+9>7YP$Wf)fw&} zGvQWnv52kSUTXH;U5BhT=;U>e=95-pu63hM$vc4M0TLFu#dN>4?3ed0)_vFkvH!s3fJx_bHXtYG9`O<48ni&4dx0f;}ysnKDOi_(>_)D}t z77#t}*8ol!SwUdp<|zaH;Nt;ahu{!B-$L1Dcb+gcjMq={`mAoO0j#t`R{u0s4J(d>&t5EF1&`mJBOfM{0SGz*r1W=haVM90wy4cC{TXGyxV#$^ z!6Mab3b*kxC(ELCA~-cdX%Q6_17fBWfioVI?XqKXL=iDZ&4` zYa5EX%Bl_~JspH`TTw~LoHt{}JutZ-R|g74^aBT3vsMPZSwf+5AH`dwHOhCQ4SGY`5%kvQ;rzK*66v2!O_01A+=J2VhD`;XsA%=Y9y-i)M_s)hV z3`_2n)kZg(=UqET8BFf~J&Fiuc!*6YEoD1z+jl$KpdA9Kctr-nqLOfssVlf!Sl#>m zw?%DTCM;yq);y&j;LH2vJmkOW8~&+cJ*J^qe4zxJ8WlxHpGF4NPv^GYz&^IO9@;}v zwva%I2d59X!u!q7Y=g+JQ78pE0o$x|Wn2jG0~f!|@Izlb5dX0Jxn|FJ=j1jBhUYw7 zo&0<9;L+MSqCk%h9M+Cw&mEKceK_C`K89dTpLw2}*u#`YXmm&4m0bd4!C{|5BlE-) zKHv&iT#x?w>GEyEWc@5+hCj%xHRa3dl`pGpPdwK>|E{mAAUA5cl2zZ9mBFf`20$*E zib2DW(H@JhJuI zCD5Yj#>RPS2w5fa_5)~pP3ZLwvF%P5znIvw9w)Epb&X+goqNxnT=E`#ifTO1+wrwB zPPgy-@7`{y(43vGt)dU*wA#%DnMpZO6!YFtgqnQ+{+%oNf$hdnOyw3%dlfGX5M;=| zT7Pr?bt9HCDdNG)Z%=IjXsqKyK!+8M)9KW)ILcB%b{2S!a#_1Ut1A5G3fR>>v056* zHLYn3v1qzB+Hl^+uE%wbNwE#xFNkM^-0SMLb5jvgjPKF)zz#qj3GoV6H2EIb+^qAe z#~SVJ`>EC)#{%3Dy_UPu^U*F7Iz$nAzEc|lu99~50bx3KxKJ2^=zlkf;XGS?+YF;m z`hhB?kp!QXd--#h6vej3F%bh}Kv^*=w=k$P(#l$-ee~W;gvkl;m(@T(-Tr9Y8ZCoo z2PYVYhSMW!5+MBuz>0S!cA=Mo_2r_$$RPGQiA@msf-LjaiQ;hn$m*5(UxT;c2dPez65-j>xAk3QX>Yi!!WK_uPJQj2$}>$1vv4!+7k?O9G{?ts*WejDXt!yaaKcqLx7Q{n>Oc;-G)WYufjdT z_QrJzWwoCJGc>%nHvK`6{ecdT`p5i_gOLfNvyD-LZ=^(LXEsPYJPdu`ABJ+a9fdm7 zRace!OZBu+AR5bI6zF~6l-2L`v2G|+Fyo%_OlLSPknEuH1I;?(=`3@a?>82wb4R?D;FJIc z^$UHn5)zzKF?CN|+2SiZut^0?NmJDMhj&20jE;=yA6))})_tt{zd;oeqnXZ=oEDFO zrKDl^M6OgwXpbh&Yey$XMMS7E`fO-8K$IvskEcO-M5EwNbadMj;ntbt^e&CU=TEkW z_s{qTE(JK957xbV+(cl~yi|s$ouB)`_v;@UU6jM4!oz{ga!7kepq@LWb)k zXV5UYI3K32yw^YL zB&A*s313PyFtQz4adR@ER&SDeF!78NJhP2{@-|x2$@QntE;IC&n=Nx>PShvvqPfdM zxptJ}mYcQ@Ej2UMeAEh`qraKD@oZY;#f%8EsNU~%`fT_8<@P!W>5x4LgKSAGb$sRw z&C+t?f(YeLB8vhLAl&yT@czT*6WnQuQ_he)@GXz9OnP6W#gka_-q7f;-JRJ@MQl4~ z)(IJJY0xA6#LaJWJdRvmUUIItl_TlJ z@h`mT)!x$_QAFRC8@Jq|y%{S$9C?sC8V!e4Q*p;4SGoqXN_S#t2HX!mGbDrAg#*R164u1su6<^_`-1uDTL!3Yq0O}E#o{bzwP_n_r2 z$9$Q<%!EqnZQ874UH@+7T4xs6AZ-NNRKAGB-FmzH z_?;U4knNneI$s6Qde6eS=-xGrJ#t*XzqjX6%!l9pe13`ufzd9Ot7`%&tR0`b9PuFI zFP1rxyYLOx*J0Z#m#dk!(ZYbL*8VGD?y72NNIPS*t&G z*Ul>9R|_G~0MfsnrvLTf#|Hq->*1qDGdd0}^bNYGzOU1+-tNi_;Bj^@=_$Z=C0y1% z;pLnuNwN)pwfLUBH==j@?rB{k;-o^U61^XP1^-H~<$gyYn8J{QmuIYS)bx?-9m&Ix z^VGhw;_C7$u#cqalS@?im>FQBQBjHssx`O#q`D~-%W4%opZi~ZD+Ke^<3MsTG5jDsUBXhhxqZKoT{*H~#n+d6bOFFu755Ns_TOP zTCejz-9>ELLo-08IsJLyRTu zkJ^r@f1Gkm*gK6mfw^V|QqK!8^Ij4^4kI0wW~*?e(Mwy7ucc0AvFEA{&YQ$H`Vtsi z#V$5f*A5hBojCfQjbmlSn*^ z?c1=IxoH=jlGaYA7k_FHVgnK zYPmGdIWsArL!jRs0GtZM@?5+N1nJk}tQft2vj!372Cz=bB2f5X4^Ab!!bbBdg5vDc z%9?h5?PROM~gijc3c{_|1gC|2ep3d9E`k-Rj)Py_;(D$skf=zXm665kS zU8H8Sx313ak@|^)9Hs;g4)LuQ&0Z3ghe&WLwl`SX==qamd-87`+Jh|-^4xcwYr7g= zP)@@9v?+c0R#R~%f78uc5ytA4)1cFq>34Ot=(r=z9g6xv%DYUeR@RF zdUTXUvv=ipynWTOYu}ir9KC!!CM=+m^o%%`Sq`D1^qDAJ^pRl8LMcC(0b%)1&%lMy z;(oEt7k3k4Or3g?B`8LhmzR5;onWNSX1TEkF&h2z8WjB&I-A#oGqb~EWQx%IlWFTW zUf`gp7RCi>d)49~GKqC+uwg*Zp?t9l_#4wf^hnG zNkZD-XVXST!j8y}jdWP6V_gU`!8m!9b9}@Tc z;-M9n1Y#J^kN2SZq)xg+I_E_=POj6&KrR)vRRI64|5a207nAL`)zv;_pYx}6$vcot1?d9exEuadhfNcDyj?L@iv?HorAxPLVsSukXMo` za29{a^yCFKf2Ol{d91vDOsbR|B~xBin5^Y%!86s>rf4QgbS1ubbnb@*?j1hf)}uL6 z^+4Xs@4>4^keKFQA|g~wQgYGMAFG(@ciG8(_Eoo$^_;8DCN1!6TQOLJKk`UY9Xb>b zmn@-ORnh0}!v~QZScRlP>$=);fJmpu_f`MnT>*^q+8Fu`S8wn3@k0_{f0d+sh}XqB zIa;e<92_Wdvcbn8<*|)Q?DeTXhEt?xjSiDEty7XAZZewsyycLQjVJ^V$?C zV>G)NiRrnlPj;P(vNh%NgUGLLk;*;!+9WYMz<)1njs#{iSusU;{xa$YW|rr7Sb zUZJtZE_^xKF;hWcZM^OFs;hwXnrK$DMX`GKMcsSi*nE_qW({fg!u$Bqwf&pc7Ig+=P`j~WEVhkZ%xutFz97X?NMJIA{THrUTe?eDl_5qFYEiv6GgexGwjQB}|t}6`5@#ezn)gF9ynP-%#G(li%Fn?-@Um z8|BbS6Cc5Z!Z_U{|NL6*S$d}Av%=D^?tz0*y>|AJFw9DoqIs5S$=xbt0U(@YR{RH^ z1^KKtS;F8WelNGnK&QXC^1a{DWIbpLE@TeB71AgE;Zfo^?-S8Rvr35x;NQiOB}xn_ClyGwN&)40{`hhnyYb2+ z3xgzh_F!;E6_LVT&b;ML&gjUwV?v!~RHQ;FuM@_acsR+4!ujg9Ytj4B3h`C=T$(Ix zFpLdf*CxC8ramzyz%=#YSMpr2U=y~GjG&3;gBL})dVzYX?i>R)J(oTqMv~*fu9hH) zzt23T5vCfLb3R=JP^X`THb;{GtI|D5)<$7iZRF z#n-SmptpV&+2>j%(JgGxlPI$Geb0oSNPWzv21a!g2`ZFo^T#!2vJ0?#k=pb4we$i9 zs;T~a+h{7@1^mk_yj5tZ`IIkJ-TK3(mzWsC04&0Sl`U!>@&=Vk3;(o2>alGc7aiSf z8=giz8l0Ahxx}o%RgoV*eL=2dz_p%qf^R-)Rp;9ElEghz_v;Dp2uwdzEtWrAf7iBe z%QM9fitM+GN)&3o!Z?1!+RfQ+|C#9nP0i%mmDGaVA{_aC&A#a>XWLogYe6bWL|=v3 z)bGQgOe5R6r|*r_jC3?UlNHj!JEJdbt9uzBt>uDF%tr_~Jl7tLne}$Bt!1<@xEk(R zCOtx`*41+kh+KEOOAN<`|& zyh*7$sFgtaVb?dMt~M^M0cpblunw=$+Wae9y@v?>Bp{@MsNzflnaoOj7)SVqR{x>% zSX-9r#gdrZi^Dsp5f>*0>aO=BOlP-0I7=7~UbibXR-;D;Z;jrB{>r(9pt1I683!Ee zvs_rC($aZ9Rtm&9Wi-BLa|vtvYGYVVnrQS(3;$^nh4ay3j!uc0frapMf)X-wEmFPX z?#+h!K;r|{u%gy+y+bnaBBK=MAG#qYuOT&gh=RUy4y0M*`C=(gCgcI^(8SSHwDyU% zDFeP=!J`}=PhNx_byxU>e;yS?k zRM?XDw^iMbkPduu9umC zwaoVN9FE;H|w;c$^wv5vstDAuH`88{Ca(1QJ^)~{KnlahcJHqEA<6}X)J)!?Vl8TRil z8&|fmnxd6kOL&)rq)FL3Uh`HF^jEptjsHPmYqkrIx}u_&C4V{3Gfwo@{!SGmOIhN6 zW#O+xp5z;2U#yeQleBkPMweR?S0CY0Vf<{Z#xI3DEtcgAqBxM9Odyi->k4UiqWYz2 z3*L9ksDO=sTDlhoK7!g{u}+e{+Fh+Ho!P20Cae@Vhiy?&Sfnh2Y_W{e1$Eo(-sf?! zlCBf(CLU#Ju}Nm~`HNtCoCK{LB0%!NbXFtl^4I^P=_`P$ z?7purNXtuiBi#sBKqMqCB_XMFUAp1YsdP6I(hUj%(k0z_ML-0kOIk|mJN*9h%{UH> z4xIZu=j^lhT5GS(RusqVp0LgsmSKzrp&r53e9wT@y;#6bm6pm%rz8ZLC)^vH8kU*G^ z_-~jvp|j}q`CMn?P;j_+LxT{Qd9BKQ=PZv3f%HtyFD=O?y`1edh2AAak7#zo+!#1; z$=tGuZ%$Y7_viM?}#hTle(2s7u#hT8u5nUItgigfu3ujBxq6ucSZ=}4?~}T zODTck^gD9Ibs)=MQ8cO9u6UIHuLZ!$f3J+rPwr-Mcb7@e+bR7I&45UWPwI|H@%sJA zPod6#m*h7K)%0JQo8OuK%63?LK@1uK<%%_)Bt{5kt2VU+49(1h%$E%z5buTY6Q#+e zbNRI*JDz#Z53==Q7T`?segxGW_iNAZ;z`WCE z6hpFUejNZcvv7CMY7nxT>ogHPAW~ApDi$+MmwQ6%fUSVSh?2BU5W*zgPq9g{NRu?u zYJZqEzx4TJJD5pGSQspjBFv@Kk?v3#!Z0EbW}3Grnw3Sp-2!sQ^+4U+r&RZ;8Avms zRA=dg?k6FzZU*dpsu?VH9(b`7dp*`IW5=w#pdj3>QfoLXWh9Fvni@V0gI~?`KYk4M z+aaBd@RU|I!x0BrC3vy~Xl$d4uUI|8UkYHcJjxI=eJhO>UWBT@Fru__||mhnIt0#PS`nCO!At>RQv@Mr%lvmHEh4+cY? zP5ArViM*=fw&Z$3P$gdqKO22ZrXrlcjH&2))Ru5X!-}Ls?nGSqMQuGVtLV6C1=}yA zmB*It&}4#~DR#i&Q%LXBlxU_73oc9d>uz`RCb!2{yoKxnwFL$2M70%p71*`&B=h!B z^=CNvbTqZ??TSKKfW0KyI9L=}Du?|3;oz3H9g(M6-=bPMlfQT{ZR?({>c?u1zi@us z2AMrmD4s47#E2}4Gi9d;8$KSkI+*=DefGS#WS#~CE_Y!D@&ss7mkkO0XbU-$ z^w1qdHD#RM+lo$1-OyGRVCc}FsK`z*`Xs4>$k+& z@<_tYuChp@d_xpu*9xr3B+)Pu82DYF$A%wQ8QCUCd)HBY@dOfN4Tf2bB`LFFzXu~W z$((|=U#X|`*;`vYW!12BcTbg%rz>FRoXE{S`8#h+87p5T$n~ju@lnC^=_ilD8FZcv zL6ZtPY(=yPw~5?6-XDK;u(+_fw1P=PyJ+s<5DOQeVxkFa?3BR4D3Ft$c5QDmlw2zP z_vL~W(&YaxKmn09W;yrk7c&+r#x1aTE^RspQr&t#QdwH0!BwP*jw?g+7=+3uU}0>@ zZ!bvGu#Mn#Swtzp-f(@_)8lLJ=$JHAv|Rb(AN_7SHpD2@LRX8E6s}vM?&Rw4*5kE~ z+&4b@tNTsvj4_N(X4c${`XvF{N*q=X!9vdK>Re}+t7pMeq?XDhuMI5h?1I4zcBSG~ z-?|U?6#+j`UW(DN(Zv%Bnj07|JA1qLZNOr?euv4eVJt?dbL%KF*N!wJAFj1lF04o0 z3?`QN<-+macPDDSW<)z*yZS9dW5@n$XlzhmCU&|m?{JsggZxe_u>ag#d zp?mWP2qbL)XhI9VX#AeSjGsire&DMD6U3}UDU%h7balc}p2Lb;c-6XPF(q@d){ zmwoJWd*w>^{;R$>quF?^t=i}KbS_?A3LOc?bdShki-d#_?q6~tq0;Zbmek-(rHH*# zyW5+%Pj2>?$$wqk5ZI~MJa*T=Vus1Jf>#ye;itjW zdm4kLzKrzE0M`&YK~GWpL;Kg}2a?%kWT>zR0#4&QZ= zEiCB6>vWZovf6#F7Z<&qgUg8)l!mkFB%w1i+6J?XSa}Qklk^7Dd&W~c2IhTrZ;wfi zy{L4_P{85sR^z~u25ejM4md-ZM)y%mzmtM}Sv)Qpz~o#rclWdLxZPWh2*_{x1m;L( zRuu|IvjsQc^fEg;8?q9!m&N8))w8?X@qhc~@%wLu$o9?6P4w8!r=}w24xg3X&9i~7 zMo6fl2x+5!bfNaYpJV|%#br2CyHCXc+*Ym?HCIO|EUZQmAC_JMYyKKt5VESm3a)Bm z>>h&UiyaRjn7N8s*{15jE!P^hxBmoe>&N>0`(5Q?j+Tj0zDc@VZw|qy|NQv_+=AKI z-h9jfn2s^hIwwhqRG~DAnTS$Z^J^N(lJ=AVV)-I{f^F`UBTlf##hzxM|CGjHg7HZF z{WmsT83a>9dZ=lE4Qr-lUirThl9&gyGK|^QBqTS%A)Ye+8W%%_YE09o-A-%Kw7q3~ zd|dR!ix+SKo0_eA@rc0uL&ih}aOD7+aeXElh@{stN_i6U7 zDk}F#t7{R=^R2K!v*WCx6HVpqMN=Y{B90oorSm^4P8OB}r1KNl5(#Ek4`t9G%QD<# z<{%QA)qsUOo5-=)xd>M-<>9UFkV-3pNtxhiPrW8lvB$=8GNh2xo(78&aij67mYV4e~+&G^@gqf7CTD>|(oaYLRBv(#$sW(sYN;qmXMr-Sv$8WFY%PKgd?mE~A zA%6Ic1E|{C7H)3I%eM!OBquOlUMd5FkNKQbEp$w{jM;jOshoKgtE1&d9_a7l_vAS4 zJg%cG_ugAxzXxCF>?IAszm3wFE&%gjO7KcgX>P!aM7{ZDE=oIjU|^m}7DhM#U8Ruw zs9d7pew(oSk8$Ta&JaBAE%#MJr^Sl+#x-5AY1T^K*vyz_mEDAO)oGaBWjDh+>InH-#Uq;D72*N@_fa(?gd^d~t)o|@` zD)Y#?TV;&AI9!nx%MY>0O!kVw#|+Eq{h=>zI4uamRn@s}n!a+SzWsa>KR1(?@2D>h zXu*j1wClSkkjnsB$dUMBM?Uw6w6?Zo9VI5_^;fCOdMrgL3xRG#ynWXkqLeVzf zFuot^GB_+CMhN=GtijNOO$opqhz3*77?*20pqX&vH&-;XG$X`)+#SEx;s&~q3)MgP ztfkkTR%iTF(a}lL5~g!@cFK*7EZ9~zJC;{wu4_(VGD&?KNb8|yDH{=^WLe$ zTk3NFt)bQ!TEOo_RdN`F;b#5)w}CU7utGfY4{BcLH}T)8OQBgH{riuGt>v_lJKCT@ zT1cN2?2>F=6ABj+n2h@O4UTtRUsPJ%6)XLR5JF}`kH2hbI@$tjRZQiQU>M|gZLJ1u zHl~m6QxnBw$vE*`{_RHV2HvJNztNqmt##L@bYgRB+jkP+V3XjWD$KkJ2Ic zW|~_9hLKi)v2+s1`I|mb${rO~l~tt4m7=7tHQY*qvqy5W*Sl7}ot|4DP{%fRE>eNQ z&n<1jZw*G1fZSX4B2x#{Ii7_VP0WStRABQ~_+%*(SbYhl=VZnz;3?mME3~@7+5?p9 z+~ukRr7YY(wBPbb-2U|}(%?uMVs7EhtZBy~gtR?@sq?E42LYvhz-iWU!WbDvy!1Gq zq?KhnBQB`u-JVLnErNv#^TGM8)tx@NdfYub`^V8^O1(h0=F8jSs4-Zr$^J=`w&7ZbC7oS(XU`yprQ2qR+rDb4dMzE?XM{Yi7Ct(ONXgvo`zvA~7 zFXI!((ja8|CY$le2S&o61R&^B2A4W=jTG@T1vmJ z?iI{nKCoJD^Gw#3s=B(m*ebjAQ}nyb0m;+LpT%vE=jce4!&HVT2idR{qDqz?5wK1|#KJkYf?AsX) zXR6_!s}L;#dU3K#$S4`p+x@GQd3$9cO*4mmh)g^qR|OU%gnslw9N_Q4QqfsIftXC9 za6xh-Sxo|*M!(U!F1o$FJ@CkWsYrIGvupP2lfq>ciCFt z!*oE%WRK!RMOmqT+>^j?bo?m3>r3C**egdzqsc?iXYZ??WtKRmQVLlSx#b#7pRjHFcJ7fH?0c)U;{$mzza6>0DBQj9;IS*t0AWjl<;#kUD8Qsb?Z;xqK^a$IsH=dyHsPi0aGH;T? z`qJMBKW*@%ay7 zXdHn4PK`5lQ!Vfxv6U5{*S{N%W3MRb{3sjN1PgST_~s1rwtAr74_79$KKmV!KoA0Te_RHTA zbE%Ra|J)Yor0sSVT3K2 zg9R~Sf~kXgNsH6s{QP{|!xuPxmt%r46&X`yGW9<6?uPQ(P%UlZea+C>?h8;?qkwHR zgoxN`UiKEVWF55N`t(VwhD=|b;r6%CT}6d?CiZHyE~LeA)yEBWc>v#!H5n!Q;J@Zy zoTsaQ&isSBeL02=U_1eKXXapKNc(KFepHFOOQwV6&Vi*R(AXZS#mRzmXCw$tzFbs6 zf>LorpV{b^o53s#UA)`P$$N6XJLOV+V;$2hIln0jmA3p)`iWBmRwQG)Q7~}g+X@th z@Q<-S`l3+=&iP=}KP6pu?U~3v=G7XK5*y&Z9wiWKOK?->?p*3C<1*Ln0Ct$yWD6CeA~5cdYT}0bMIA;vSx!>>oy~Gg(oCW|h$()rs6ApgYNw0+>)4 z%)+#_S(CB1$Oq;;vOKOoMvn}@1ua~gagOI4SSr2DA4|R`*++6!$ceUh>sipN%sf<` ze?d~E!ReSd@!3qb{IKXCaMGA*gdMmG-Y@17hA~!cnJf^0Y>qwjtp@nkl8n@EVl))w ze1c=6T(xoOq6C;RPEn%PoU{cto4tbrC=GfMox-wc5GMt0vO+D+e0H3km4x}xk{K#~ z3d5rh6MBCf?@=Med3iRhExf3Zm6@GPMN#dS+U{`0Cs`bV6b)pg|AdNH$to+a;Q}x- z%aa-EzaflL6tZl1Vwkg8YuCJ{1VNmzv7q&`_@FX3!aKqVHy6V!$HxAh`7OY8#}$m0 zecI%xvUfuu2A7t2LCNAJcGr-5;QQ)fQU5C|!Nj7P{j#&&S!2n~ET^24n=5QchB7GI z!kM|O^S8};+C)_Z6^h>|us((hvNSYGd~0AE{R09mE7>bEUCPxO=1j|ullh$m!k&QN zD^~}#=tn$?8fmd1vg9vUI*G#=a}LcWO8@?Ik5iM}s?NQ|$HVjR`g;T#4-OwzH9n44 z^Y)K}vIId~e)^CQI)&UG6l*Hc@b?X9?ujt+27{YBDlYF6ys zLjq&WoiNX=vFNnbO#`EpXmal&_kLo_$HkIPBq+cW%%eace?#`HOe4|4h7i(=g&L^q z?Bi>7S3#~bn<38=#C8jV5b)9`lcsu!sqi)`acX~?gzf5FQZIXg8*5Dw^nMPAd7tNk zjXG?bBaa{dunZ77>uPEuE&53<_i$s;-n zEHI3h5UgW=z@|~eUjx(x(J~9wFU7_90QRtpMHYBJb)B69{r#+9+O~t_PVRr8unghm z0^RqbEmce-0yXK1?LSO~9FAuv?l7rmuI(Mg3bcN*(!C;zW+B%^Ltoj)Mx~#vclq@^ zwx45wE!WNU9DRTMS;ryMD*)!1QMeH4gnT26Q>k89DNmRm7S0DliMc z>sXQ^xxwZOIPd0v>k zZ0$DioFN2?Kw6`+kKTSqI+OxXzVKh2f$No4DuEK+S-pFxo*&B9a{%sDlqz-TtWo4qyunBAVYV3%xP z9Fc+jp5djs7Ig7tVxfBX6Adz>c;~688B?e|^1wha1J9Y}MN1HV!Bj_V|ML%T)SB9S zlqlXazq8TnHCL={#+f-|!aJ9=^xb>($t%-KjD_qzH=iGuoXKBYu8?=^2m0B+r(-`} zwcKjztf5!T2mrLd8n_3gj95&q9P$w7PB$teq0>9iTJF>BsYh^KF#9QK<=fi&AHJ9Y z!_D*bD?cSpU53=*!is+j0YAHa88{EzGE^}?8cVFqpGrQZfPU!F{WG7QA#MpOZYp;G zEa>Vy@TJ3F8XlfnxV_e4okp2i9}?W$f1^~w0M1QCxM<36uUSd&=6;rLxfg@bd&u`J zeOrfvF)wrtKXVJ_buX}>20g4yAOm*@PNb_dxZz3?&38F*f5T+#cl8G2Rw&^2J2X=) z7cQQM*NOEWGU1l49A;o3u~|29&!@M~g%u1#R+JgH9{PH9Jd$20g-6BgRa$x-=Ge4Jxc*;%~w5gfFXfO8lv+gn0v@N^Bs3I zlIt)Rj3mY;JIwCN191cN z?Dz}DMc+m!!I6KpXuYkr^uF#4dzBg= zp8lswN-w&Sn`A+$GNTSpeakK7SYs9Vg2#EDWip%Z@SIc^rtXf*6jzm@PM9xlA(6Y< z;s#gjcd<9KOp-RuPVE+LAtaA|cK{gmw4J+^vL5U2CCKKIc`-|o4yh@c;SDHPA2;TO zN3-W)kaRu}B9CB~b+;;#pe&(GO>vHs4MS%W&!)N;h6lB7kmsf2|~zuW#Nu)|42l%X7%K%k8T5Q91e`wi25 zi;^S`suoN}8>-Cx$t%j$CfuOv{n{MJIsKN+50o?J%>mp9%zqF*p_Y3eSCv3t3MiO^ zMDE-#LcBU!?XlcluF|VJ?(qKwzv8U4(0TLf&mXO;zeqI^QBiFM{V9v zVUu6_ci@78jVc54J5XXOw?vrsF0Iy)1w=4_5ygd!uZ8Q)$N4%|`$q1~EQM=`h_b*S z9Y3#Je2JSN-wQm@X{hf3B^{7F#7jhJVq#X*3utn@m<0`1V6<8OTW(h$*YV?H^wQEm z6T4HwENXSN3k{cK@C(_a@r#evV2AnETJA0u#MqHL2!+o9C)vhU3&bspRN%Mbgu07O zc)w74d)d{^&x~6D$(s^e`?vXgi~OOvpLF2`^`8T+`Ng}R=cWH&3$S2jWd(YA9RxC< zk+P^T_1@LM0RX|{HQzcf;t>sRodP`uw^C?ln3 zRSLdWT_)gEKlw>E2@OV61QnEloUaG^3AV!UGGc9X8(+WoCwBiDUCv?0J{#{1v3i$P zlRe(EtpCb|fysEhjk{{b3)<0i`I>Z-dz0v%9wtBr*xTFZRhUsWSN3vwh7Z*$3uWmd z2)+YW9nhD^vI`rikAVRmW!%rNq90PCTT@0}tk-V9Sf!-CV`5b+rIF$?sVXRNTjtwh z)PCX~j|^|B>H&Qd{Ps_?Vvqgf`El=c-mz6Fa6hk_pD;Krd7XK zE8uI>-ZG#z+%rzd4|u`8H?8GP9)c^BB1v$(D`wp3B>V;gZw3OL-Tk}!V6n2-QBA2m z850o$$wivpFJ+QQWQksSX`j^AO4_m(mH%5Mky4f*6HdpofNO(J0pMA;5#d?Z5{UiP~-G@uHniG-*qI ztKm`ZxA=oU!18j|yxJvceZS8brs1{mEQw`I@uWzMVLz9G@0L4%OC7h)5A zXPePJv1OIU)t-GO2o-KJ4bJLhrNf%$n(>ttMj#hRvxp41I|L+J8=ICkfDS-chrE3F zClVY31Eb@=LvA?|{^QnKg^Mk6FMLPumIelEl|&7h>C~bizr_i{)a%G5+{mMk{F*6R zmp+E1GG?S0FHB7?n7xE0sz0NZiHGTIDPY2SqD$8oC1)1mc^Vd$u2=8X&=uP{6#<5mvAJK2aLFb4Y*PY`|(f zNF0Weyb}=}&4m$+0WL%k0K{^D7Bg{(M3L3C448WFMz@N(gm!@GR~8_x&cMr10j4WV zf3DB~$I&Fj70UTP-^(QC&M;PW)4$97K8*@VA>14zs~U<)g=yUtai7=~R>jZou(01l zX5Eeq!U4$RG+BgfE|~ICZ9OGIhNMnYWl@vH#hqUP#E6-G z1cmGBu?YDV`NwR-*T4*POQys7=00gii=DKQeO-9aa%8=h1tH#GkIwar7N8b;Ss#A= zYRj8-0uq7@)o@T1AGZEEyv2b<`rO$8cRfl;+m~u7tMNa3ex6bSply_HrNs?oCj7YE zT(5ZbyP~XKlLzK{8Mo6mI%IE+#~4+sb{dz?w-il@6)sns_M-y+y~Kd`OLKh}upACZCt~^*{ zph|UMY!zUT()dT8;L|T{ZEw?MWo3ceGij)IA>d!P+DkvqK%kmLtE{Z-T_f8;gzbOk z8Rv6s66ws>X*J_7bMg6y-uwqNKl}gCIZRaAe4PY9=mUt#4A2k&&H#V__xknszcK_U z8g|a8DSTqID!#?fPoMdN(u_{}2NP-d>{}@_S)Ajw(RmT8Az(i!% z)&DeRWMly0`#~Wo{?kA8mO!@;W3k#gvp?P%8nPrSn(O{p2-xjblQozRWCdIG*z2Rc z(8#dTJ5Vsz8V3e%joEls?RZ=xS|7<3;w5qCbBb2k$#>2w6>?HV75IB9eLNa}tsNYa z%93l$->D%eQ2-LU=onkM$M(_Kuge4>!}|dc>R%et zw#YlZ27AKs!8HOHdi9liK_;X9TuR-vr?`)Tfa?p878vlVR|}WVW-0gMoq9(PsNG4{ z&f@@9)4oJnqEktNoQJBSAoBK?XH10+pp9LdwE^A$L?AjO-F<{@Q%ya9-hk_}kiANn zsD8(sU*3-|im`jmTeZbc(a>Dg{(I+C(#8K4G~0L5aBz>{fb7AbO1k_jkn+fA_o^d> zIj~U0misOYL>Koqx|a`Uch2m}Dtdl+P;%8sH5(Ke@M?UP`|L*?i56xWQ6eEJ0|1l^ zkjMa+QYdJw<^-y)o*o%MnK!kytJ^VR@-`&6R4R)E5kMppw+ zf^q8Fv?Id=VT_ToWQM}(aCG`__!O}%UPcJ3^oi}@35imGbeK%S z`R$z#m*_Ar;+j00)avyt{Qa}x0(zHDIsve{t z2+=KND-}dfv6iZaZmgSE(?EL<7?<+UQ~-`LR0VDkZ~&lhS@B0?4k6}GlL6Zfuz}`| z3O6@o5t7nb^E#|_;!X*`G0k6JxmZL?oBpSwFRxw5;rs;4%NMRIHCuq*ru7RRc=%zk zcJ!)GIHrGb8*d6A7hwj5l8>Z)+C^v1WDK0bLsGklhy;3L-VZ&s+*9A>A>iW?%%C$TD*`sL z&n&UMUEF?Q^K_!~_Xr=DghUNYZHDWt)F^SOMlGkD$+fi=-ckaW2=2wK?(#J^-DE~bR|EcawB0v6WjOrLpHHViu=6_@U-BDNMN6CXUHTC%&}4M1 zdH8}lU*`=MsBcBH3-k=vew*Z88T7jwP<`GSwG;;nO&HPv91YO_Qpgz;`7Lusf^?m+ zlWu%1U8s*adTplO$^h4(Y=vTHgj~nhemZ+r&`0EC6F&(O^a$S7x&}V1WUTeKh4H~wM z1i-n={hc^YC~By54$z6)WN!bDTj^v0U|FCWHQKM7|A5#LtZjIM$dmvepb05KQh^Gc zl5iorN&8M_EQ9GD(y$$(!v&fxX6eTld{FjC#FnBTwm0C-VtufE9U(iN+fZ zz8Tth5C<}U8Z{daI?~LTu)>w!FEdr!`zW`T^1!;TeY8CN*!5-1YuZYPnkP_A>s4L> z`>@$ud?&>kwPGm_$Z6JHNu#**Q=%T!#3XNohPK`)zSSj)9IdrUIqGRX5aVp2x!Cq_ zvaaXbK6fmziBFcWRDP2DbZC}|%!EA0HqzIFe$Th~LNE+I3{q^hn7c0EF`Hu{f8OlyxcV@B$X-pY|i3;nA z#Rc@{mZ*Z3`Q@Tdv~O5%KR>HZ9ej=D2bl9(fxp-P0nN#pOW<>%Is6+~s&`O@tQ!Lf zO#h}VX((k79tG4oB+*$w`D9kYa&T#^7_lb`?j`^(iyiROcu>Z^h#APX?td?7R-B&q z*5@U66>&7>rz#yF{j+p)3-*)XYq`X(R<=jMs_wn;w_oUQaOhuq+OrZ7(5d!Wr_@6e zMD?)KQ|jF_fb7d?n?++h!_?xuh6@(MioK*q$u6;f@g7yZ0OE}rD|5?eJ&3PFSH^@h z4K*lWe1IUhfchz}IMA7F`}}q5iQrT70kXPL|44@W=ctzG)YrU`EWc%J{ zrb}F6{95YT^T7pq$+M(mXK~MY=^q&r1;;f9jgNvv`WpjMEG*`EUSBd6^oy&z;xk^D6Je*yN;73gg6KPFi6n{U0@`VuP%&`7Aw=8lSGbHGtqc$~>UD!Tos84a zSU(9hp{!!P&%BM;yu3hu)V4a0-10k{5&oDf*>@o$Cd`n^SyO+70*ovHNttNb(A&4q z=Ikq69l~jip-w}N?#9SSMAY~U?dDreS9c?f_NHLm|39i&&2e5ZM(Ku2t_P!nwUC|Y z;*h?!{Wbxx1NQb>*BFMpzA3-3cD#r&!fv4)+k4I>;{p9`?{_M8X4&lIEr> z)Y3DBg3;6}NB)$$+0)h%<^m2tXJFFj24sm|Vlv!m43?~EJ62DuYs3$8$U7`WXawoh z5}30YJ`!W#+KHZ~ACKOgxAx^NHoxEs<8fFlFkfSWq1TwGoIcZQzN3O~z?W$l>?v2TzCnyBK} z#ah2~zvdb;f!dDl6@y}wLI%#mn+wUGKnOkH*x=8UXyKGd@k~eFveV?Aup$djRPhtL zO40_;hoN1-u28z>ZNXausabcZij4M*#bOM@&3BM$wh@D-q2)v5-kG&fmVuFxi?=td za4K)gdh!r|@;gNomCPGr3OS4(1>$&%hyi4;nT?qx4N}>Jf(?rpmAk58N(?4Gaf zd-LWTa!=&@=G6T;=2JYW?U2^Kzdt{?X^ve}`hD5BCBgsg_o|Az2GKy0Vfmu{KC9$< z?(!|mkY%7kt?F|R`&Xfpy@29Wv5rz#sFgMJ3 zZDj=oe1m8O9a4T@I^S$~sG|hAf=Q5I<^uPJr_p`y`^=YD4M4T}ZT2b22;lY9Hq|9S2pFfNTSC-%f9Q{P!u>nY7E8w|Y{(IpsgOMK2pZ@f64BEq}#ED()+SK{(-mbfvJ64shIzgc}PNBvNz8I>-LQX$biRHJS z+N<9=2fZP9rWBKom}pYI$P7L#RB$ggIM57SSp|y0P_&5hT%$jYWO|6wnvk2+!3bc4 z0|Nsz^tnf?eUFn6!&iMQV3gVrJjS#M_a7#Afy^{QPQ56_LQWn2UBhg<|4qf*XQ!;* z%4<@ZPZ#Bt6$R{W!%xf!Rdl)gE1#NnP&oaB?6pX}*d|0Xe4i&z07uhq))k*RyY{}( z82;Bk)$Ze_KTB$%&7Wl`Xl(F|_NvOr)%z?741L|3;;_h=+&|ww^J&T%xRZ)!Q_DHp zo??`jm%r@j)Lng(vY_-C!rrK7IGg3sI|i2oF%CG$kDZ-G>>!5yB-m73hcybh(Y1>; z$wZ~+n&RRut}h)imk%BP&9yo{9yqUYz#nlv&}IM=f^~BQa^sttL^fAXz_eT`8a~C< z7-%xwrcM-+XM?&xDAMrl%wBAwbOY1gNz%-BFT$g>aR<|x{uA4sn3L*nrGUB45IoN^tTU=)r>M=(Piw@2?*p69Sn+cC!q4B_PEi@!Q$>s(ulzt0j;9jr}i zn@rRWZ`nQCoamHAT4DKzS?J8gy*u<4^F2RQabc6eWITXDzDR`W%|6r3`4Z7Tx;2}% z-v00&DmCTS-Y{_Hl@Mdl(EM>}Y8<$`qr1Lt#SIT0o9=MX2YnnC8R?dS-+QZnp>slB zJJz3tw2h~9GzW4P15b}tk&=b~Z0g1Qmb=_}4Bl7?@+=A6#Z{HZJncCB znE6}HBbtE$sDm=nA)gG%+ZW70rKyWI zpHbWT`a1APd0!VT*uO?tH=hC>!|Gu)wNfapQ<Kb#O`L!7?Nk(~TjWqnY)muHC6AEL4uPll^uN0bmnk1zW1Ybk*0`-va;6gG zE7oK;R-_;+(ygS<&9d%sNgY=Sl8a`b1c|+K_7AvoP46AnHg@(Tv&BCb_31U?H{qu! ztMuDg(g5L_@3R}G-sh6~FC{i;Qs26|x=Jj709{sHHi?dn?CGSGncCYW6phbxZ_pv}l$tTQ4-MWW)5G-@@U?$?Lb@V!qiW$YK6I__xI zVzdpP@kCX+x)m_;0n2`eB-*+ro6@YlqM;;cG{;Cx#c&z?UEWJ!r7)TJ&-*eVbB{O) zNUQdyZR@S;^$?=8;O?E>6QF<&`F+-T^=wW3;2GGl7e7QHfCTqw9XmLn13_jB9i|S( z*x6(f4gjCTm>u}Amw>rIjsTSkrCLeMfZ(cya@q!fwptep7Z0Xv@U1arME6%JWL-S9 z6UsvO8oqFo6Tdsh7m;AIP$5wP9%+Jsmpy?`X`K>f<0p5SpiA;=;%IcJS%*d$1XyAw zn1&7SqFRI$3d~j2cy(oSfk}B!7fSom_zTHrjKxJpv=*bM@YHg8!U5nZ*6sS-RH)Oe zqsdID(^7&S(1BnQ%0k1DK3%(!LN)dDVK~CK^=}Jpx1$1u#}Tl(uBmarL_*&v`i))a zrG=VO>{8^qR+k4Z4!0NEP^Hb>SRHsT2^;Z^B-L^&B2$3Id*-;Ci3-NCP-#k%9WBpw) zBtLe@k*v%{E<5xpE^a(B4Vb#LCsJJPA65@FRVUPP+#1Xp)6VSb49~dDWNlTrY7gWM zv!BGYDGZ*bLt`^5?|_x4D#tK~G&lbkNvHP8wP?p7K^Pb;oXOwPc|p0P{iW5hAiH&hJCY)aodq^eP0d!%-m)*g72$3s>%uP9V)SsxYfYf zR)?}EYMju(DH+yLMB@n%m!?-(s8SKED9w4ik}MM}ib+H;!GaBv35S)Ie&gFK;b_7Q z@7mq%^n{I}3e~Qx1v7Wa31VQvWARis?X~uXZB}7FKNMlu1I@zmODjgww}_|)t%-HH zaN94uwb=3n;Lnci&b36&)|Bm4C0C%8TN^+wIKeK*Pb;y>V))kJ(9MswWYAo7NDh}#hD{wJWiQK2T6YL{VdOxu8SFUOGK985U1d8)F5p}=7*_F zw1#%5!D4DzQ66qX@K5S*#GyNnSe>@m3n0qy#ey_{xx(l5H{x65KP$w()cqXc;~0sm z;LL2lI}7OiB&_J&un)xXaeJ%2cvV)_j*kpxyWDBTX1iP*fWy5zEihj*+Hlzpn<8Nn z_^XnA>)xH?u#n{!@BXETeb`eIC8)p;pRu=uDBmXYvg5ve8TnCQaIn^1v+8ow8i!;| zmmAEML*HzJ=gaU20$_DCP3tU412sb1@XC@RtXU6x5&-cciV;lFVtem!QK;ATKSGKz zx-sUTOjPOevVDhpRYe>A{9bEQq?y*2wcb%t!0{QEh<@>?hW6cZEjDVf$ATg0yv>wj z_2UCSH!$hXVWDC>uAuD^xcyT+P5e>wbsNa%8dSgw$jhU=;%xjqw#NNx=yWq6$EtGl z%6(Q;sB!Y6*#pe6dy;f|`myefkYW+z?uR6x^s^h8I}vnA7suzs0VEH)~e_O{mW#+8Ya(tTn{gv|pV{jl`>E8i(&fU6W&e(bbX{4l?Q~ zjcVwSsFS!G@#NX8mwCFX#|W3|3*P?5k}DwW*#2JhLIf8sz2&}w9nrC%2S zU+;8$d5jWIN9*eRCEj5Hc#+Su>gIknmNZg3i7NQT`|vFFZN*(Wbd?$%frjmQ&fD2% z$u7gC`)~3LnZ9CGyk|wd^kp-`Cc$!e_q_`1=Zio4{{hK0Q22x!RX09&Yz(O0(|>l% z1*!vZs+&U{b9C<;#E&W}Ko*L{C?ZKu{M8*{j&X)68^dgy#p4D2yMJv@*7 z3?(lgd5a=xs38c8;*)v-6DAj_3R`v+3iZ?~6@&f1?Ys?&)$%L5>>8J40(;KDg=LSP z+y9?%SwGirzfEG?n$_-;bFWcySfd6+!gz5jo6`uXz8e}90ZO~CB|=2QQR0E6#J{H8^B zm|rshZ{VC~U+=bCcEjGklKX#tb@y3TpCsv-k`^c?cS7&PKQ#u25D!BpL$?`*%VIBZ zvDnvsQ{4aKDZ5Smzhpi>KH#Yovme<3(`GFw9;+Xuoqn`-t>U)ag|Dq5#e&0(pKYG; zbd!Q_)+wdsC&c3;84cFT9G+sa&KY!=$HyPj>uV34ulr`_?%w~R#LA-Yv;V&-U5obk zg3SUBd0Wlp1NO@$+D-!38eM+b1RQi?VG2B&6c`lhE6)^ror8&a|I*9vDoU($4{bR6 z@1Nf9-_^i2YR>Q9e*79;Mb|krpWa?2u}P~ZO*qQJbdJg@9du}pgKp5xzZfBm%!y}E_xO6lCN z)xb&L$16_82g)&QWdg>{oGFu5tukBNay|L)a{ZPYB_E=-(>(==@3shd>e6 zK)D6`w>oz$(&$OqT*M839F3F)smT fRiHVQ4gdHLe|;1^@0hR^0}yz+`njxgN@xNAe`_kI literal 88310 zcmZ^KbzD?Y)9}&_OE)at4T6Mpceix6A}K80-67o}B_aZ{bVzqehkziG()U}R=XwA9 z=C}9G-nl1d=A1KU<{l8BDvbp~2f4p}qs5@?Ztuzu`VXxB4^#aQ|Cb5^Nz}b_`1cDPqj@iu*AQ(Bc%Qa4RxpjyjPv9m-=dGLI_l`B8i z_Tn9lKBgCz8-{fGA#CpFM@~NLda+as+Z^KH0i)tgf2?@0h5AR@i+HtJrfHd~Ctvo+ zo~&Yn;Pg-2;&w?_o3iCBxHHfyr4K|TIeWt757l1UrJMd7@tRSnw?v~JZxD$2DgK0p z;SNxFU5uZlsbC=>V;J!E;Yj{MzLVcU*2a*>Ypqu%Xz4}0b94X9RqChROU567x_%K~ zjzKFU600*EO3Kcsac8bGiZ6>}nuUi*ynUb^oXG>J4nv7j{lHqkCw@tZwT;|{a-7y1 z578@zz$}^w?Gh{lVyzWbN0J};SLUP$tlT;*AuN-;>cOxr=4^b1_JL5@s&-~rGngyF znXG9GR4Sn?wnrL9i)HTJv=yI$7@!b!mlzUJip14=S2`TV>g*O=(9RWuLN3@Q5ORpB z99$rdaDZ%`$`kOR4lnFc)T@9h5dkLm(yA^oeG`4MzIn&yPF^vSk3k7u%wolWGA?!q z*;X|w#~rb0IJ5sCBCjO*v{Z^raM{4tjE!oE@5byF3cCd;=D;^D6{5Ds!V7D{?y4X0 zAR==`_e3JW4xY9eqe0v=bX7-^^FGZ%7G%QY4S7`Qkyp6>tyJ`7wkae-gg$dqfMXy= zbouZn7sT>5&t{kv=7n2qRjs@NQlY8tlDp`X)kDzL5LYhx65_}}B1=YpLHRR8LVbYb z-k&3pXOfKk^JAg0c0QBDpGi{+Fs96Oy=HJ#b+H1SbWgtTJ#rL14&{aCC~6#@q=}>i z&XX@D3&^Y$oEoi4P)KHtU$U7i0wOQM85Q<#my=G0KrA$R0EF+YTtUojA#*4F@;RH- zTN%X)%T-0OJX%`1QZ!bIsN)f>w0 z^@pg5K2E56RF;V#+{n^DjSf`LE?+5rLZKqVj(}&YbnbP)e9`2hfNQ}hlGe>LM0OG; zO~an~C~Xxh62wd)wOg0?fycjk9&tZB7V$~#gS0fxt0-mvYO1&4%2?ntwGXKT{{5gl zalJOSxo`reAm+(i>t1;r9RF&;^iXW+g{c8@#m9sgsTgs+;8>Lq9LzH{!7aZ7Q&0cu z2t-8uVhGEY$sy_Fl=SYa1)mDCNL`f9O${K%h>wFhMj8t!)kE90{2i>Z2|o-H zi(Z&IBqb6_8LOl%KKqh5mkf z08c2t>M-Ir@e`F}#1NVYXY6yC7DhanC+l0eMF(_)R=E@hoFf4*H0HeOuVfj~ubsj3 z+Nn3uV&lEL5m@|%tE?PwP%Waq)saW1(F;0qur8ob_T09T4<2+4VLCk8PsEo`njdMz zezP;L-M>>1Yoj!|l|sY{cup^i&98XeaI!(hV%3EAQPF^v{q4vZbqgxD7Sd<0VFX&q@x8yeXvW+k2*(An zpDE-b+tlFi`E+9x$drp>KVuG5TgtP+d}pzxEkPXjxqb{NR?}%3!DsC?R?1+$v#Y?1 zK(uIySCEu>4+v*a-sj~<;NeWIYa0crgimhI>J1tWmCQ-XD?+#Ol)ewC40!1l3Zl#H zvr}@&;(l-FBJ0G}W@EMWqQ=As5sKF^1;UcW^$w(pk+4J&01vqE0H?!mB)dDaou^F3 zooMO=gDc+1y%((5dq$Q_L}9eTAj@~qd7|DpIu%x2UNaBgb@%H zzqApS!z55kxhBzM5+}#cX23mgnh|IWAVj_aJf9C!6&o!1two)Mq>5We7A73uk zI3;$}sA*~oSFvOskz5aOuYZ`YHcLiZKY#9B09d~?!AVZ@ax|gzNX)|J?r9ZRBS$EAsRAjq4c!}Z3$X? z_irx_{TLVnn%{A+ur%H=-gN_L^rbc7gd|gc9 z;yP-yG}XSC={6n>$?U&Z6|dfCEcDU~YFr6-12$b+##ey9dEb7XKv!KbohDo2*&!d7 zx>RO2jxhD#2=xJtqnp}CwWNXvhcwuBZa}<`x{cv16f1y_h~}OrZ*cYbS6`TJ*E)bV zEy04Vzru8K0}xL%C>hu-RW}25mR2pof4=-`K`{IxBIYUI){bPjCeGdgq$CtWzU=9S&^g9 zMZ-76vUf_O%p6-j68pM5(EM}Siwi6FpY-hGL%<{3IQ+NBbZm3et9`L46jK#p^A z@S0fv0cvwy>0|T!7np2}2iEgN6~?yovd|*qop<UV15LcT#8&o`R8mTdfMKS#X67?&7Bp$I>zhRL%^XslWHJlQuHF=pl^1K!#lMG1C z1D#7Kw4){&nVH1tocXfACK7j~vWd6@Zb=p;%h#cURBWuoA=_>j3d3s`KJHrc{rIo0 zr(#29ZGb~|H)AgMi9=)I5K%`HaBM7Cd021f?bO*+eNw~0@2uzS|MIttzr{=Lh!*2E ztP-e2!NaUg7j zabg9^utD%@@_DW{Oa1T!YDi2QGC2$LovJ^4_*X1Y<@ZI&@v26w`~*RcQh1(fCUf+R znw_WoQTf=xI*}>FD$aiIuf{SK(^k`VL9Ecm`1D7vi$DkET+u+}3ib>UbodJHTiO*9 zhFllSyxPvrxTo^{tbnt>hKjRm4pe_$Qk%OeM#^i22?+~!C{0{^A%|}ed}jM~=Mz)S zU}en>a7L?Ajz9+!&LL`kUmSLY$RcP-2UFrU%lOI#_G&_s$*?HrmFI75nvZuwmkUls zkC`QS>C9Gy{qpV`K0-2^%1hWq56JSubT>RyGp0(vYx4al4=&~V(B`EnQ!52U@$(P{ zn23*B1S7^D4F?%Mg6fNSn`(q4K?PuRB&rNcA=s;Hxs=dbW~bnL4?m^A_!%OH$Y?j$nRG-$Yv;nn`HH< zg&dIJJ>h7)@UABEZe2>}oE%H#;J3WZ(qwo!PskyxUOhRF2fVTe1F^ZS8k>a?Op&0U ziAKTi+Wq(xqwI1Lk?Dw*Q!P-7mD2PW+0+y0vJ#_qn6DxN&p2tb@}N-oHk#`SZ|H5&l!SMirB4#CY}dpFRSdJ9YK| z0jcfi`E-bm?Pw#{VtSqN{*C21`+?yw4Y#ft~I>mvZvaz6SiHLkhfI#CT`)FwB zVup5WIzoy< z!P%{)pix=b#|LOWj9|Fiw zYqB-Pg4i7=_!uHVLH6Y9j3OV7!wq9AeJrisUa6{m8y>?6W1A+@*Rm^rX@Xatvj62M zik!qp1#Y1?7vf_xCEUI1NZm<7BkH=$GHS-f3`gGodlZ!x$K$C(OUw0QYot+kK9RZG z8=ju80xQo9l(kuzrHaRTTR^}&pceb$&Q7OIY~y2h4kq^yB;?MnBehQ-L0M&*@g2+F zUnPtL1Qj!|%?3Dz750gC+Vy;9AG1>`o&G{>PRCX&pNFq3(ebD6jVv9V9%sqkcuuaw zorI2Py6bM)S1CMBy^%9~BT)HmkCn9pB7@S%SvsMsR8Q{!;!i9CE|`{jl2k~Hpf%<6 zAAbAX&FZ$$STb9q$sbw~MUOH_TitvOfz zs;=W{_!5GnjoM_yQEEB?6N%*NH+xHtF)>uNJ^t{{QirkjTaS6n;D4!$m&Z>Oi9Srr zq2#3Gm>%^=#TC6R|1t3WFoa+)`jNtkZyS|1bO2GRtd<~ib0vk|Z;L<{(M1I!dUqW< zSOyYG8u;GSWJJgWd-WqDg+7j-+ZlfgpAIIOm({Kvg4@i`&b(ZH@vC2*M9S(hhHfSR zB$sPJYow^pOWO0K$z;+oYA;VocCbdN`YpATK0R z-V^@S>iMU523mSBnnF_lc#s_~f+3<=$vG27Wf{C_AIUs|93b-(tDrbZoYQ8z2R$H7 z%N1QFfSv&li-_4X}pShu@kik4<3zrL?S83pv*|( z=$UhfNx8HEs@T;C1SUb@?x-!>I}f&eTY9nP^5&(9r5uL2pJndmMj{d^)BB1u*d+;( z5rTb&u)orXIwp-k*X&O&R!wI8N0Cuk8HWr|Zn$W-bVL>#9)>^pPAFO5hCdc&&c_K1 z=tW9Oj%lO@Y99Fr2QP4!JX&gu=~a~7NKx zQSe9W+7J;djr*lqKqDHr_`9xjaFt)opoq`3q|po(&YthF0xe}1`rNZv;<5H6-F|j$ zG^QlS_*G^CGM6+ROgDtx=q*Z8Y2`413ix|tibGQrGIGp?4CyR6?;Y{QJ_h835gZxC zjOlG~N8Exso(SR7e(i|w-K!8B>Bn|q6%x+slqV%CqaPe85~QT)4GFD|l-xHQ(aT|A zo&V|;`hg_$0xN-{+!_yEC(2$$t8K(XpKJJlJhNpmoS$F#!o?1`I-)%x!wN^9cKO0o zzrPm;XFZX}PEG3qD zm&&cerfp(6m|F&+U&z*9)xGce$ba_OL?}(>$M?P@_LX1t$$rOwEsjl|w#mWFkbJAXa)3pBm^|) zd)<0$9l9hwyyPB~=s2~MhMMAjGU?D1HrIN+Q}z*$lz6UCyj3=4TS#S0&Le6jO!P%o z4*k%03Tgf$YLIv_idr_CrI}|jqSzfyTRZ(8$SlA-=~?Uv3`QkxFQz^^qr>`yszigx z-iMAdL@gu1v`m*~u}wzx=4!b#Eb7P_2k&kW(OVWPuo7LWB$?1U__GhF*CB?O-O2p|`7``cjj1POAT>hE~52twl{{SwNM1?=iL z60v^r8u1?tNO(>J2DLE~TLaj>7oK>5-VsqXVP;auOx@x?kSePqUV`=RW=6JAO=x~= zmk!b9q3FA-4axP;<3;Cu-;R*6sIBioie}zo@dY%o*&a)`qS3gO6~P*MUmSfk-Q zn!5Jv<@D=|Kt^X-h3R6-MBk0R3uKincJYhAy_unL?a(WKEG#`0BFgupXQ|aVxze&v zU6GM4h>XnTcS0A__7RvDU6&+T#l$rBeh}CYLM!I3#~|;ivad$uT6~5R zU*%fpSV%fbdn*mIGNdsnlq?XCVwlT(K9RX8)K}G4H&K#G8l#xaBTkV*oHb)lHTz5! zJ7Dxa_$c_XV4$hiJaZOiXtQt+%)AcNue+~bPINcFTF<4oMP2?ELx!I}U0erC{ThQBEoHwE3$C&4LxN81ok(ggTo`B0a}aE-RNDjFe{wWG z!ne32-xJaecxePyy6ncW6>O>-ov@$JYApqyH{E$D0Lhl{!Roq=AeqRvE;AYbmkA=h z{UdzNOK-n7|4K41$#K`{WUZ#uO}6XUUuLPI)OC-v&V8df#K9E9II@MpL1U&d$e?g< zthkbTv%?o1`$-#wS+#^v#j>zuV-nVPXH=R09U0|aphm776x|L^WMLz%qP_KI9jv`ySRR@ zrD-zEIrF~q3dCrxCmW+d~a$n6tL;UidROV@xn;X>m4y*h`U`@4?Q;^lQWCycnG zA(y_F>p20P%te}!^lt{nNhsxz2|66#8p7AG`(;0A|A_efV?b&%uTsQk^e-~;XH(~Z zdJDkaSp2!cQ0g9IXId2Xa)(O9wac7U6SH`KW z=A#LRPlSido8h+ntUfs!Mg3aBr<~yl9@HGoZ@JcFn{Sa2LkJ)_1$?LdvNPU^Q_q;7 z4yGhC`k&|Y53F!b_x`s>^#1?h^^i<%7uC@wXY0u0rWh;M6JU-7vu3}xz>J6cdtlQ} zKc1k!VS#EJ*{49bxP$mZ5o-8%zZ)nktM@AhU=G4dK9x5tG7QkvfK6O$JyO*TQ4mpx z!m9)H&%ov>_J)jgEmC=C*KZa8XH2sf=GQ=7oHpa9;6^2zK*6I;j@iRUfcB}AgQ^ZV zGa=4Z$?hoGJugD%(2!w6NF60JyslVSYwo-Sg028OZMy99lWt~GS5@G3$+w??>NOMG z-Ht_H)&n1Z5Po*Gd)+@ufM&1d6o7-Q(F@Qn0D+jO@oCqA-`}kP=AR!$OPepOJKC$j zQaOcyoH)<&;1dhyo0(_Y7&XMHXAATjIpzu|QufR`AbY*(e)9eqMk!Y02p6wB_g|nW zA(&n`ihJ}hFGrNnMwy1)yqJFIAMlQdlh@6~kEz_l4v||m+?u(5|8V#9N_c>_jUemZ z1CX@@FG=mZN+%WDa{4FDUBviQ>$A3HZy!@vQ7<6AHEXzG1?q+0_ViI6t0uug-Zd4Y zlCeH4UiI)dQ2$QBrb76a>(IBB39`S9gYDIoP~Bc7A7FDH#*LDXOK+(A4NwqBNQ8qG zNRHWNwT|h>6H94$v?{!dvO#STM>7PKKX0HfP{JiLDPq)yTB*f{`mWw%%=L$$S_Sk( z97*4wS!1FGvR^+Oe;vE`$k2}{gLk>HuyY*{xZX6BS$u+$k_*q2LoEj3a(MgnR|%+^ zLhIl&0)~Y=~?FFc>oE2uesId1XF7Gm7_Hzy81U1>gFI_hQ#=EzU`3*H^$dMw7Af6Djuq9_5VeU1*h>788#1Wj@wUma)v~ z&yP)#rWyQ&7F763I+0Xvo!BlJj3Q% z3IGNpjYhHW`kK;afiITXf4tgkeEA5)czm7!rh8y)nd$w9kJB5vu^WS4ZjrB+0L@ZB zRcnZQd-ud>%3{uEDc+^3vd7MQ2|yC!r8v_gZ8rsIV`=41@ijl<^MQJAWkZTc<=YSE z!tk)@QOQaTPmTcg2uG8;sz$7g(up~)!r+6?(pR67NMdfH7o*#vv!ZV_EJ&+AUy{Bv zJDDzB2$hFB)B!X{uR}o7uvNI6-2{Z2z5xaG zr7PgC(n8&5pmQ3SV$g3~1UyOrK$i1rojBviHJ~q|0)G?`QgFJrgM&OPxPaGI#zbZ+ z*ac9W`?Prv*dk#U1C0>r!Q5_c@Wi-wE;)G_e%uf^mK-xZZW;(gCm0`bb^g-uBpDIB zs2%am5s*a2u(xfa-);vAS3mv&!lwaR1T5MzfyI>sFL)atG>v`bp8>Qdz*)XeyX6Xq zi`WI$-!_Z@q*9GaA_iwZFEf{)t7Mv3_%X=2E}jYTG1kdW0Et6D(H$E#y#mVaZSxlp zb1b0@uQ_8Aj(UbYJhIJPL2*s2cz*+w-dI65^OMKw{wp15otmZ&Up1F+pmyf?PY(Wn zGCXfMX~gXwzMu5AO%en*w@v1S(YO^1h9|d8*0RgE6$tHrZhg0i8|8+k;m_qZ;S#8} z20RPx+UtDLYI6w0I=yyX|JAH!`j8}6dq2(27ViPF=U9+NYHb7)e~~5h8g!?qy2@HfT^iLaH1vqL0~fpYlECxGGUjNyqV^Ep~Y z7tw^{Tbr0c5TR~Ebl&q>YNcqUkJk^N?n?Bt%>tltwE8=t8t^z0{VY)0GA^Prgo_Xl z-%d1g1`0_xa(340%@@vc;E4>{7+wQ!%TMBL^$k=S#fgtrTV#A9A?A^;oedAI zpMQ0zy1MIUUgiui{0saOib8*#{MNV)?@-2jWmBk5THPMuq&KpYy6BEAZ!Jsj?F7uR zGxpV%8_K7mFDyo4WKYpd#~+c{z(Y|FZ7!U+b3kV$L3cylE%Nu8&{}kf7V(tg5yKhx zX(9WhhLb3gN^rF5o&_I95U3=oK?{TG$8=xD3&N)+qS&ti_kdDONmLB&dLdH>q|IA! zrZSAaLsSqlg?Bvd?QN|ji*)f=Jc&t-u6m(X5IZABYNuRSBfyt;2pUagP)wqF+3{a{ zX2@HPF@4mQzlM-Ldu;#BOX@-~k-axx&61R}`bzX{!+B{O`AJas2(oo~{f zp(tbQmD7<=97X~hgHz!RmJ@v%OzoXwTt%lQN=0?AvB)1>eSN#wY0UQ3FyHi$q5l4q z^Ne><{2CA=+mi+W<)0NLf(z1gi&oz*LK^OY+!iTceJ6q|Om9P>r$F;mWtMLZob^7v ziu@3M<&5zWXni%o$}SLS1j{^H$NZQC&`P5fOd35EnOHq7mRy|~kR<>xIrrEG?cS74KoJBYnKNSVMdC50V)-A(mR#+~W+T&oFyWCpZBy z9!>zDd;%(2&!_ZOdjQ8#VSK~_AX{@rmaqT--@R>GmY%b>#z(mGPfDP*w<@Odoy+I3r{SNEj3Zmv`9y}9((@mGxl zW$Sh0k&3W zVSdUd#tjF~7V7_SRCj;MX#E8^eD)%m0E!~{cguk6twV{y7>BIB(@f?HP~qXx)$e1vJOs>n8qhKlCU>()T#(};tXKryMFY);+NFZqMf=5y*LUwNG--&J z(@)K>5hK;A8FuwvrVNP0SdpPt@yprUyE`&aND)nJ^E#Hah!aX-41sH5`C z$SkqppD}`BK$cRDmI?=`AlQ9|lia3u!IgDbn62wM6FMEonJSm%DUQO<|m znaieQnot&DQzC!GJ#(YGtunQZzR0$BF%TeG6{{oi#g((+9cC|O=r_)!2gTU?CZ0;g zh<*NhfN0kF+lOcI3fm*n3{!(t6`qC}MY5WgFWi5G33$d@X0h)5{2sW#b%Ny|0rY)C zKU1BW0WZcRUIuO7xz&?ruXX*1|McyF>SfGKu$$M0W_@TF&8Z^I(s0W8=VmXVvC$w3 zo{6|TW8fVXtA&MgE)3ne9{9ia?z?`OlJ9dYUq(46ci*IAmos>Mq4T}sSrt`24Qs1> zS1S0|@75is7`-%qaDYOiappI#BRv3h`szDEEIJC^<+Rhu3KE>~Wil_Dz1@<5{AT7( z=NA(9N*g2=>rl_v;atWX>vfj13d{DyA;vbrrapMTA?NR!t|slYhoEtGZ)lqM^Nfqd z?U?FH3`YH9GBH-Zyx72iMGU|7(C}_k93MT!j$Ew=qTb?#jxlWG=;N{ zb_t0(LJxN^QJ|a=fq>+r*dY5+M|iW$7$UJ`+l6DK-&`Vl`XfZCM`&(AM#EHGO0o4? z-u|0j(Y4B`jR@>g*IVaESJAs^$)=_p{X>2NW4g@!h*$wRhId6~T=O}eMsAZG_=(BZ z0&hJ8oVVDvuT%JSOvUQ$M;|4OM4`32M8I~qJZgyw68H|2T8G8rm4iS4LPMI?eXB@b zN!a|LEB|(riST*k7_H3}rCumxvfe3?x^Rhv+m7>Q>y#~;j&IM&4>H!^-790{;iiVD zmqlA$tXHlzd!@^Y&b4V(S;T&0i|djImH^*bJdm*d?Id5+8VdW7Eb(SU8ya7MMgPQc z_}r-|+Q|AuoOi3WwmQ|k7u9npJT7HOL0k4}#`&WGyQaGCxm^}_%vD2^%hD@3Sn1)% z-;k2EWxV{OM5$!rd(Al2#*vN%49#$qwx-^g7i6@0@%E*foanF_7Bo6g^b$SeHXn-U z*c1|VvkRLP$=m$Bl_}3sHXpiPo0A}&zak{#)L@sZbK!)jI%j{HfR8Ue)(l>I=v_r; z$eC0RGQ?{{f~%i-5wg_H7!nQ(>FG5Jk)|GGkUQ2R+TU}(ifYSnjV8##C#uU2Pybe} zoZau-ZT45(J#*I17WQzzU8m$~=<}tHV#A40l8AFV`wa^&rPiHim44F`R*8Lkg*^ph zRBoE^_{yD%vNhCw4koLKAtQt_?7q<w?D&k~dk9w3)=*;ld})HB-3p9|A9CDBm1KXHsG1(>IB^ou z&BkKZ+^vk|4k`v6NG-PwBcb=1gjHH{Y#?pAtIq)e2=Cm&wDi^fF2?nv3=<8Ep307- z$_4gdtlkHefKGVa4?+}K3*%S{>U23GFzJaXjgpC8NkyGB0aKTB9AzH8SsgMYkq()+ zqrr>0SHPgYH`B&_y zgUu;SkCix~Pk-5o`U72_tI-8tT%Dq0hK7y}7a`7v`LA#(uWovT)I$Z2F@so%%>u#^ z(HK3q9~~N8-UQ&A7+qk-9HrWORLCy!#Mide^mO%Iqj2%_%^wS#k1Qd1gs7LJha$XT z@H^0dufQeJ*f6Zl0&N&@$?AZMZ(bj>#B>{A%GM>Rf9B~d>03i@_k6{>lq>QL z_hUkGT7h*@c$l%<7B~Ec_U!Ts~X-oElsL!4Y@Ji2Y#b8x0u0fl#vnju{`#}U@b1C zM;=GY!DkCP!Y_@^o{NjB=|#7a5cVS|?+1LrtE4w{;=mF%l*5Yj1lZPL&m(Kw)8e z$T^V&Q4$D#1l5fAhyJWt+4L z{kwWKpvbQHf(z37N&jm_u-Ja3kdSozBKLH_FUPgxqvg$wrTCpwnRBfju*4*u)yR>% z9uc2C!ql-D^CC^GxVL;DyZY6Xf8qHApT5%%jBI+$mH6Nf*n;>IAD9W=JpGlunYo?H zu@(Fs(TTw)R-RPcL2y~6DCTu%HW+pg<6PR|b@)S3>?|=;72}!WG+eGojhLh64Pu{= zwFIzGoPG0RXd*83@oi@844%mK552hFwGunK5`(;w?}%IZqGQs@$thzQp&^*VxqJ<7 zg4G-^5bJLaozjspWDHqM%0PdqGwJ7(B^$dace>=JE58~QyT8XH$0TR3`V_X^gnZ)C zFYe7#y(>6qPyH;Q0DFIn2Ec(qK~M0Xjr9-y?;Oeh@0Dh2m}Es%Sr3`eK=V+ zPNy`?+PZ_C{SN7GMrszISBfQIs%YW=R2R@OZ13tieor{13Y+)VG_*6Yk6Ud=vB3j1 zTU)FnY##K6f;019s3hz^kDG;zfcMc6y{5kX{qeS3B*_L@8jLL6Zn)!4ZK<$e@2|J@H~eQvWEw>F`1Svh+!mcmJY< zXZiW5`jQyA*TOu0Go2AbUmrL&c`SsW`=-N-+)j$yy}iE>Po8nS`pAJT3nG&5Z9DZa zuhBaW_(Lik0{Nj1uO~u`Gs&iuweOvIz&DyxpM3jI%5@9$=!hUa{R%yHZSHK0Fp#`9 zuR5V|*5DQox^E6+00Mg7I)8yiu11x2r-X*)l!$~x)e`0GSuzy0Q9(hLkZoK5V3Z-i>n(LgZ~X0uE4^=dfSluqAJ?LEZUJ zN$8|QQP60yq?P#1xfur3es^ki;M}@MQfhA4@g99HPPs~`<*Oj{Ba-|K-Kwx(0T_w zB~(RFVh~)H6-Hgo#jQ;n=x8Wo#f&S3jO~C@AwPWn!yyPdB6B)M*-T6} zkHz`b5ouR|zs9MN{rm$Mn#Y2vGNO&UqxZ(V2r((897Bn4r#+gsjVzM-H7swtL-T8w z`0f`NJoYfgSfG)vQZfDR$-LW48oYrB7iAwc7#RUxu21L0Sa#zrEwBsh?q9yzzFLZy zOHM6~9ub$T#8e6yr+;7>y^IgZnTA19l5#p8PP*^I!uzMbwvSsGGw0`1f(|>l5kb=J zNdHvo%QAiRmrdHH&d#Yi!$$w>7WK>05aC*g{24>!8AEfJ9D-6hGAJI3crL8T7&p+2 z*Bo(%bN+-sfmLM4V=6KU{j(jNe76-oY?PJxNWPN+R}_WGW3z-1YRE$;*d(UtfnPwe%d9^+(HTD`BYU^ z_3DWEZn65fSpGG(Vn>7-TQ&?*ymsp4t+yM`^O~3X3Du)Dlt@C_nlM*i>aGx48yXQB zAxk!q!bt8>t}S`@q3-7G3t{0SpTKc@0X=o9e*Yk65#^^G*}EP7^bAv!VU8w}gy1fr2SwMA3Q%;wlfhNK;TQe)81%kVCIk40 z$udC(eS4kk{$kp@>ouOrx?^*0koo+nUS(3%IRO%T11h0 z?AL7;SrBv>_@6j&T62sQwY|+J|MJiVZB{Kfd-?bb?aRk+Lm07JMzm4cH0Z1@cI^Qy z3IcYo5A;c{a6R(`d->1oTwP_b#%bvjtIsuzp#mQj!J}beo`nB~y?eF1SCRbR?!n8! zU2oC-$HxyQABR?q4s^zFwE^~o3GH)g+h9rJ)COIzSrP&CIw|> zHX531*wOgfIkK^HVAx=?Prb|sX3V$PsB~3ThUK$#E%n9h?3H#UPRG~IA+^qqCKuwy z)LL3ZcLDmAUI@@@7w8!Q^7bhqd_H@`-uUp9C-3rcf8XCjJV3XrX4v(G&5L~g0_J2Z zve!HhJQt@VQ{j+e|AoEd>XUU$?S-c!;d8 zpUSx5NIQOg0V`!a>{ z5AaFGQ{=JEh4=Qris zB)?BM@)m`Dn8@Bsx4Y+6vww?#060@N2t+hH$CBKrL5IoSBf+mw?}k zN!*YD+m+Fq=w&1)6B3*kthE8(P8wL*(-_OxX*v$*@VBRkQWU_N(s3KrfBq6G*Ok3U7x*Z;|ZB^qUAmd%>A@6kqyEPea%kK3D8sa}%# z6Ni5vt^&T@&2-YNyJv5E4mb+h3sP)%5Q;PHX_|Yf!xo*fpQ5s_WW2JsIcGe3#95>F;%+q~TnG@=S5G^9Hee1SioAMI zzYiy=nHLZ(z>OX@XH)>+ffX5rK*6qHFcQAft2A*1oem;Q+Vel#EM0#O38|{&7TM^= zpc2!}9L#jmTkx}L?db@+qao+zQ?|1X;u;O3OHe7RRS?MTe&2xVT$=d5?DB1tJJ zTKXu%qiLhIqoi+$;!)xT5y!?T3ove*X@+!ZjW<#DPeujA#!DpfNFB{_a z!ntZWYRn14ghRXM*O{%$)Vu!h!x_j^m$@22;!DGqh^0Nu1ufGH#43X!yfNru;FJ_w zVtoTXY^?sKX&fx`Pt)%RWi?BVNTS?JevO`S6;gJ@R+?U}0Gk%yvlubfo8XM%_wnhr z<;I^v1uw>q&`&hdzQ$&yuhdk-+Y^lwm0Dop92?MZP_BAQ)^Ue-=9c=!l8nt(S!My7 zbId-EjW@qz+@5?j-ZLJ&nMo-HUg*la0J8ZNv}-eLFpUX??h)=`o2`xsuPT zrOUixt-1zy^>k{8vNG$5%5~UgkFF>Uf4^2u*^!)-E84|#1lFtT5vV%1#9 zy8E2#3%GeP0Z#D|0{P>hmszmnY;)(YowswXqj@%_z z7%L`5S%}EF$#2*aPM@kerj&A}p#Ka~vP9x*?0oW2CKyW=hW67Y&{cQ4Xo zU!fnd|D?xm_kEv#|4pPyh1^%ON+ZtKjYM6>^-AF1l<;NEchNe;f@&~-;=TPRw(cUv zQ}wFLh_2Cy*NvKuOI346GpARF-uK=e5~2n8yE7R_g0?T_w1^4S(9}87R5C~HRmx8h zeMA*S3;J7JImZ;1#{EIXPp)GVX^bVTqa>jPlRE6&%^fYujSMr%$7-^%F=T8S2u_UH zQV&Uz3oQ1S39;oAsaKeD)#($edzkqdDyqvqxaPvC<Q)_GK;r1lwzwR4=krNac6w2^VeI5cDyEo6~&i<0) zM#E|1Qw&LVF~m|#NrF2fiRq)M6V)RvN%X&}YeStXo75=#l_na!TOt}+R3Gwc%bZ2y z>PtspYE|OOY0alpl$5k!1q8GQ(s6s1_6_2JSH+NFRVn{&ia&pUvoYJtsHH1)K++2F z$1JSjF|%J|;_t8MD1Rk4&lxiw{iG#gQkF?2)_TWitdN?18lm@{E}x6V6n&0w?g-gK zwD(fMZzBSdLlC9g=ZLB!MTXp(2eCbFo)kvs_;U7MN;rk~F(f zuC>j)dvbt&4Ew_kx24L_0iB-)x36Nc#cd@Ow#=dV* z;WlN;Hl;86_hT-yV9w@B_lgtA-FdJ1%#(eY)(8yZ5h{UmSy z37A~jr;Y7|8;DUNC^`vLRj{{W5PKQM0>WlRMoES&$^KUAMd4R_OGVGLwx8@=#UA3B zX1Lnq1--3zFz8z&9Y97UG(i zrwLIsWvOHHb9{;Hste+SGIC@Q14_#^R7d`A)^=Lv{9VNq*)s?E-2^B6Y_?#=NMWUp z<@MMEP0i0aqve_}-YPeKoOU|{qfqZ0#;~%3m@UsITw)MN|498VW;Jv?CcZ0GY52oN zNvZ#0kv4rStGOOK?n0LIax+Rkb;6xp|UIQ6}VbEKpKRvn&LQW7t+d6@Mw-E-VfxHfIXC2pu_q2X!ak zQk?;2v$1lLuaS7}KFTePqIM9sigsS=dcs3C!;hP( z%lW%bQCuew%IAz$oR69*8nX;Y1h2(2&d;5urr&GnDwL}f@s3h|2jJtcw&9c4^{y?Bn`yoQN6~CsH*o zF+qzdL7y&H*-+Ev5h-Ho=Ef>(%e(J#$I|w;iu+r!VDU}e<$mnGZ*K9b>$n-riihaO z_IXSh!ss)*-dD5agt=UHWHHu}w)0W_#sjWHe#Akl< zn%%1}(jtkp`b^(zYWj1e=d7%)kC)m}Kn?j*>y=JRg~}iA>VnQ6u<0gWpxU$AUnjU3 zE+tE&U%~%vj{Mg?=CRI`i9!|j_&yUO`3Xht%Tx6ee-rculPX04<{BaWl{Su;Z&D2h zWJJBP>SDU@OfQq=BmU;XD!wOLQPM3IU?!|bRmC(1H4%}uFr!&Qpbu5nuc4BCF@E{P zptIyBCz&RMwY*_(3gIWuvA`|PUur-%E6~-M-n`q3Nl%}KjWnMwlg>Yz*#6yoUwO^0 zS59?@|1W+}?Z`$+_Z%A<8?*Inlq&e^>+6>Q=hCZ)%-3S7@-H{zJflkzui0y{#G?ZxptPc*vb9wzPlY;j zG`F+{$a+dXHq@3q~tA0IL~vecQ8TWjk`NvfKmfG(HcDC z#YK|O3GD~f2C}%Z5%{nCz@rldRAd6>7N<0s9S3(1?FW6O{(U zPhW?u7Zau5?Ovm#yStknKz&ESe_B~*yWckEUC|q&0pu)S8jIY0;o5XYBf|0uHNov~ ziD_eP9=E?chO7FBkM1qTXKeqP!FD*wYKbER!=zq;j4{~DVWAGe%_8Osc<$Vjt<)Dg zx>+GaL=Y-T*4u7JcD#V^Z3n8^mE?=!+Gl|h?Ck6?7;LROlu#J{5CaI6Eleum8B3lu z%leCfNhkDceESBLfX@a*MY+EZ?t~j@So^9%*cO{tggfS|`$B*5;xXpLC~h)A-^acn zfcH2G8VEXUpR;d+xUbty%cQWI6r>Bu|Km*3TX}u88hHgiu2;6CS_!}$G7WE~x>Eu5 z^{zCVDTTwUF|60<=H7T?@gESjvbP&sJINlkD$XjBJZV7BUshsf^fv=HgzgUl-l8?E zY<|0ocbP9L$^=bos_h(!HzFq&qRiRJsbZcIoS!Tc6F|4^sz;d{G{d`cQWcqh02n{h zdlEI4_-nb>D08)33V4H6T?q+C)wmxZ9iyho#V%tSmuElP$HusNr5VGdi~@4F45)HS z1bAOb_prw(5>`$;8Fx-_WMLLDO5qDIn4eiS@0dT@I3C>o-F><-kHPp#YE@*_E_JN1 z)BLw7!P)UwiV)nG$_Zm`J}f@Ue@Q<(yVLA%rxiy+;H?2x!S&M$EF&`~qCEBvaK4k1 z5Fo*fjC{%v_2?f=6!N3?GmxJu`hNW}K5yVDn>s(>c6Mpw`n+>EeyNAUtBJ+Mv5ID2 zY<8ZVJ$+GL9>YD%SY!74lLscs`@-U|?4PlW3V(y&5(T_bcJwl~jizH7486f$aiDG{ z{}%xL1UA%*m)qy=XSZG{!&B!&ZFBo$Ad)e40y>FT4SXz&IWbe^87zLQ3{}L~p~I4C zHk#K;uf!PtKIz}2?QxRElqN^{%9nls!k@X*fYe6NP>|Gcj>K82(@q}!TDZY8K`u`| zPbEu@C1%*Pf8E|(dpu0mQ^YS*4jIz%u2yCbT>ba1)6O|cQ&ZF4Uh~G$5$a+j>er+= z^=!4-Tusl{)NS(AZNAoi&M&@Xk(JAb%&h zi{QD)krDS*g%|%Z-b1X_?WzrhC9mDJTFl6j>ZwbEjT;Mw_yrTMHutO|t53Ze=ifHA zV6aV?8m*#XO=T{@=*bHFEbl% z_}j}nP9-bLD2W4UeuA4~`OO5AI~g(lr01^sW!9uf-n_v2+M0lLufDB&ZLcF=&te>;(Y?p7EFkH?Kl-wtuRnUlR%R{{9)cJlsXK0&DzR};X{(z(XMmPnnSAR*)qzu znh0}*ie{GD-)~Bq)afJHOe?Sn1^fV!uLh~@--c!P>BD=T7nt3i-MmMBIMZER0FLN> z4KcxVdWHZPL%Or3mUrZFeXr|y_YdRQGA{VTDIqV(=H9_U^$#@@3ya{qJeJ0C{W@9# zKlmFE%r5A@kZC94aH+lhgOf?H*+N)28wk0FSp9+}adLCeI*O>lgnrYKTsG2q8KbQ! zCkNtXh7hz)AMdvQnHiCqS&W@<@{y6tENm$>z{x3kY!1?Y?zczA@q6TL?s-a7KvTN(fjb+{7+p@t=g01Nfw6 zjXB?k=GhrD_@Q5QHGu&WP5?oIdY+1V*X)i_npJSAs+4-S4}8Mk;5GIT(K~mYm!HTo zg$p#`-RjjnAAh+|*SXmASA~_Qo?Z;g(q>Z~*`?uX75LM90+kwQN%t9}=6`4~O&mMl z!~mjya$eca&x#&`4_oE{+Rjx1OfiD>x^?vWS|GfKIb7;%Y%Ctg_UfXrLsB)?!`Obc z?-TU)*Cy!KCiXMj0nxbYZ*79Ntvbwq=go`cXn1r#w5yJcU=d-?9o|g&wNVXnCs@$F z<(9!Ma!i<92f6iUwhKeYg|g&}%j}+kDy7RH3DR8}yVk^Lyn*QcVq(=7;-_din3u6L;`~W$L=E zcE%6u>YD}g_2B&r51XLIyiq5Z(7L*-y?CRN4>gtwEca@%@XY1_lFBHwR zR(G}4&ocOSj!m6XxlEWU^Fs%(wVFEpwh)JR{a>BqX8x~{yU&yBL9>oD=XEZec7Zj) zKCV1R>s-=ZEIe{y^WCLWRuYSW+BeYqQh{pE#wx-0p}U``9uEdH=REgReD_XEyI7@6 zgBgmRJ7F=t{X??|5A%)vp{i_1&bi@hg8LKVSA;Y=#uhiFPz50%-3fA+`O zrg1w91{&mV21^+pwQUph@_WJMD&UeO^GjD(0#5_=ZS7BdAHMZlZM5#rL0bX63^D@q zi_%!Dru8cNgyK{y8!x#gFY$s8t5;WX+GPQB*Pci1Mk3d1v=p!0BQ0xuEmFX%c>}Rs zWJB>~3Q1Bd0N^*E69>eLd&|gf`YXMbS+mP?oEfWlE9YR9tbvp9Kyb~Ftb$)oZ|Sb* z5f>c`LX(Dd@_7JKAD+1uF*Ca*BZm)<9Z&Nrx&(JbapG1#&KZumGQ|%>$(h)41Kz8i zUyT+R$gE=nINP`B!(Ws-xV`8p#dy6-ZWIPY(fxmj0=^g!P0u0GM78OITN`ByxdL}J zGRgrs1?XAq?B(^%^@hABT<6^HM0C;XS7)j>9fg2O zCZc8LKRgWfVYKMeBf;(b)ds}Wd7+Z2qqqy_CD^TzlKMA5xV`R1@VI>^P}K5mrg*|? zGFg!kS?o2`KPY6WE|qQ2JmyRBmKtj+G_*v%2Wd8)r*WPq;*-9E=N?rCO% zDXkCJK9)|QVd=m3r=3o97h8{z6fXw(`6PGIjm zyZm-vU|umWeo|dSL!)oK3WWUFhouZ`@ZPvc!eOGKn`>)+W}_LWE8Q6Rs>BMzQT?SV zePz+36;Vzs#@zI2^4v$E$!Q$%YfTdN28l+gH z$=m6D%$Mi;V905%YO@Dc=ecGabcz>A{UsArW9zbF>r8Rmnbc8m?@}}K|GfaO%2V`@ z&Zjd^$D}Eb`xz-um)emM5)&mMw(o*64_tnyZeHIfkFKxdOH23ugGDpd?>&#Z9n$3E z&(CQ^js({{jeH-Bmfq6X6`YJ>IflnDQiD}w$V+}C&9!=~Y%4^PP3(3h=cX0hgy^24nOgA!|r!f$_DazrZ$6t(4!)f;m* z(}cuaN`e7Wwgf>+xvmXH&|jY>S!9Td5|lo9v9mp@$KtEhYTT@B_-ZW4`$TeMfx+H) z5AW<7Op4G|yu;trw2eNU;!%{syLx)?2J)PwRw;6n6H82= zsZTC0-(!dd(z(5tntl<|jbEi0Y-o@yXAguH^e{pCa z^|T9CGq)$}tQlVSVX?E!ovni(Iq6e%*V}JU{5u4@J9e7GY)I5`s#}`mCZ3&K)5~?M zgXfm>R}aZkXUTguu+YI8v_yOg~J_%mU$$_mmsT zp3#nteLb@zhp+C;rlv$*yRFK%*RXOWP>*!^SeNN|2`C-AkW8TPjNRLf5c;aLx zR*7rd6bxA+0C%ES;o?>MxV04oM%3&a?pv18Pf68J8r0GK@r&cFxfO{ewT#bOcbf>k zDRAGu{or}C{Wv`JO*Ze&M{d2nx!5QkfHjeK7f@t~tf5HMCzxV#_<7{mvrxs&Fug;d zT+J+g;v{UKT1d=%OpCh&R{oYqNU#*04T(%0eNI4hQC~0@HkSC={;c1OM~jU;)>L32eK#h-}7tn zo@nizU%Goe$HEeT!B&=*k~SuziV6(2z}mmiNTgIPvQlEVrWy>ReJmrsbf{I1@OsPc9Snj-qos*knj@`h; z1z#kEb#+yhFWX?Y?XMR!h&~_aLb7*_yaD!G8ihabY;L{>tS@G;{In!eboqVeoxU;m z6F^1sqs7_I7e&EPCAj*o;~mx8leglr^Cz5d0gh*B} zyJO!}DpKphY5yRF4B^)y3IKK=SK)lU5(j(xjxoFR)m2sD_xVwa*_y86B6U4IH+Z0F zcsIY3z+lR_{cqLLlI^L$W{nTk`we>V6dI_i%mT%1hW(c{_5pKga& z&#_3mjwuDK(@sFUnBt$3Etn`QW$zNVPi_L~_p+VJS#n`8g>sVDqTYqSae ze!lGE-@k zq5xA>2;Id3^0J0z+7@x-)8D%le?+ekK@jh=HR#|Ar89=Cl5*a`=dx3c1>;Rj)?dl< z46je(B)$hqw1Q>LTd7s}`u*kNYV13ajpNlzARbNdc3b{@Mu+G_YK{ZJL_q@SbA1Va z?5v^>Km{R?5nnYpzcvlp{Hx@U;lcZl5gI${_j#9p}C)YwaY|zh_+^XBixv zD-7u={eD-*pvd2yt)&UZK)e%x3#`ECp_91_u3}}*LldJ|7JMAC1*&Wu90=cb8^QV8 zR5*~oRMj)U;UQNyw|;a4iWlw0WrQ6gclRB`;3QB!+=j--3A75hE4CO=yu|7iR$!*Q zJKRLI7HJ3LR#RJ-sc|8!03dX)uoS5|FJvw=#QdkFDaR$1sv4MFQ&+{&VFnoZ2}Qe| z+hZ*Prax;4D5s|gFxX^A{(J_~iqx2E*M^rw*y|=v^x-&iD4(P;!OY>5`cp}y)`xpY zFLP|w8#_X=`tTK4zNq;)Y<@NOBF6Lk}XG&tLcVdxig8CFSi%BqUIbj9y~++NRR=w*V8v#J-+N#i6Zx^dTBFqMz zcu#Kui$Tw~_U`f%J-pVyO#wrZR2C2k7HEUz&6UKCCNdGcm5J#(IT<*2{z)UC4)Qzt(I?AAaBC0kW zUF5cIPV!|BzNXay#oJb;qFFk#RPpvPM$Iu{j)V5@YLc|Oaaw02%FuYz>LGKY)85Cc zFd$Nk+-#vKLxG>dmh34oH=bKBelp~B>-AhLSUhy__HM5>W-NJxyag4+$f!~R^sd1Ti@eeWGwQi5k$lZY8e4w~vm>vOL76G02s)U>SzT_aIQ zNcJ*}eterOKU!`Uvj8LQciY-}$!OtZWN#;w zb8yToihhK{Gu`iTSD^lP1o0=d8X5~Zyc|bB;&6Fv2ZmFa9T^hWs$FJvH4;fd1t=u| zLDN!44=1>NKlTH2unGCa*}oM3CX%3S_Zg%68Thab0+DLj7S&Fs#k)WA;fxWm#4eye zX_v*w<&~47p|ye8c{AF%yu-<3?RTwVF4r|asqdJb2c2?={Y zidHuqN9~vC$BwG^trr{igYT{c&H+Tq#mw=2U6qo<@25AB$n9}Vn6i0QP>jLSQeioF z*T2yWiYcbwEKryS#nfL~HT_(UZtp%N5o!`53h+14Dl85uE`~*X&9|W8IwE9{O4R=a zn#+G)5w~;8KrociNvq>J!)?1hhZ}kAOK2oeg15`1aEro=h=aUbfZFM!c`)xOWQ#+ln`{i1LaG&?smV1?D>%wtfXKb8-8=l)b;uUh z<)jPdD&2-SbG3^g_(*9WS5Fie*b52@_V)Krfz)+%vs;m@@UphfyEiZrE?xOuF6(<( z`p78hP0%YYvHIa`rf(AsOIugOjEo%Sbvv#T)czf~@h5=rP{a%;j5#?_K>n7EHnY8* z4)=pDO=M}Q7!E<)G1bPnr zuqkCQW`mW=G~9Zf%R)$c!2Z`iepyR}Dk?^Vg4`Z9Rxe$x4)mn{8Ml}#LP_e{bR!eD z)cAO5m?D~%#=+k`(P*-#YEb;S5n5LCdEUqh^Bl@4Yfa;j(1C(~`d9+t4C4 zIjg64L!bcgV01<~H!0+deROe&G#k}B+L>h6G7Ar!dz5eZAzM?W(8H`ZiU?fU^Pcbl z*YSc0fz6YXpquUIAo#)rTM{E2%Zkhgz za?17CFpx>kof16$)YKH`KX;!f57+FSd`ymLzrbTj3F|-7bG(9Ip|@Yv>RcXh?A|e?8S-cP`+u?B!}%zz>ujg~9G(PEUB(a5;QS1^ttjGrlj(BwosKKzg1YS zip#3&ngUQ6GW)ap-r4^?e5nt=e~C*>@%fQw?n4`G=7;Pk{T@yg{`%cS;1qmMCIOZ9 zGk9I$(hWo)VUGu!vs*A_#~vI~?yLB&rdyz?L!EB_>&I=wP+2ia6@V3NNKu0?>>SVH zzUGM9*(rDODgYOY81}c~VpNDX11No=*-VY>pDTgk@#dVJaMRjUHC(6mO~a3V@U}5& z{S9)J@b~`gZ(PUIBDxkiwU@qOEdXQ6FM5d&##coe-ak z5VQU*4hm3Nr$Ok%sl<&}Waud$K&W)6h`b8m9(WZbCVqGjbKdJ5Y&IR5;RaBHs^{G{ z`rxgye7HV1o#Y<8U$*!^ki$snsgB137ps@>giBRx71%YtEvtQ7!B2(hxWXh((@`Z~ zJn2+h2bV1R5kTGOPBSR0=tsw@Rx;-aJFT~*SZ-9v5V^;lb{gY-*2xK+TWj_Lpv+4C zdvt&;VPy88**rXm=zCw|k7n#2rRqQOi`*@_l$HrItU@I_0Im~j70sI|t*(0%sF?-p z9`$QFIQa|IAdihD{$*{gx4+5ER(2OZaQN<`Yg>J9K8tc>k!Da`JLPx~%7kA(nJ5CM zrROLy0hJdBEDCrf`8J`bkOg0$bZ@$W$*5k7dpGEIh0`2d;kcB|kC`(79)of-JCe1V zPjvTW`FZlNjrQPMu6lntk0$Z{{BXCFAz6*pgajk-PvTWr5g10cR@ zqvv0hRqo?pyw$yQ9DRpaj@K>b&%us0=EYb$z^?`V3u8D z@A~AEmV=~zS1B@9^I|cESfe8CJQcUs465}9QH-8*srX1GlP}~a7*O-mGRViaYhi-L zs%3j1T|a&Ll$0OLHaJ~_#QsH}k({pRh=q zS@LmV)kc0y`TF#*y72~;QPp+2 z&U=+PL~dY!>Mbr1K$hK&xD^7Isg|(dS9tr1sf%|#jOmI-DGd1**-VBn*L$&Z#v`Et z)ES#xM3^u^!Ien(9W94G#rK+P(tmhoV8DazeO>>0u}lmb$t~FW5K{_4xq1k5-VFQN z$uTo??VJ3*JyU~f>NN><37)-MYIyji)(5XQJtJ+qAKH#%XkHV`^C)0nQORoN4=*39 zw%*)eG`0|2duBYv;)9gWp<;-pfhzEg6BDg7>T}&-dpmVtU?5<&JgJsYdr|=T*j~KK zRg-7&3QlgL0_Tt?OE)4-aZv@jN@aB9L zzw%~s_UDdk0fhxTDeum&!@49z^^42MG2Za~eQOGlzYLk9Ibi1rvNsi%;QebcY!HnW zHQJu{=RDqzxA5NdzAfzxfO!9hISGiHf~X^|Q9IIk(;Ibk$SUDSPikgyI={Sw&U96Z zhehTO8gpxfJfZDJklW-8|B-}!_Zsls0S#qi{83Vz01>>p{)1gGp`m@)h2Jmso078) zc5q_iK<-|z%wN5Fk#Y;BK8^GLoct~GUjJAQ;2Ei@SRfp@2H#>aLp3-Z|Lwxi#ghbj zz);D3`giyd{`*7;sm>(W5N@x}njsO&wP&U3P|Ryd{tPdSH;AcCP~%_doT z+Qc@6D!cm3AI;t>Hv5LZ=lzgq=+!;I`yQ@5tB-5BJ)wjgf979(n@9$FM75e%WX)vn zKb~YP$5eGyi{7ET)+hlgZ{mAK-qdH>Wex#I`0xaUi~DV#-wf98we++NJZ`!2##vGr zz_B>u%4$`LXhCQanaPJ)eYk)#K3;WZ0=vBD-I%m7H?bY}(o<~O$xG~BE(0Q5WQ23= zaM8PE(LZyqs7>OT;`so*N<)Uc#Zums)&i~G0}Sb$H`4|O@ya(4eE5s7uZe@Wsa(W% zq7)Og^z@cNZ|mDk{N-eKc37YU#qVW~krR?piTR3y3>0?00yB92WGju)T=V0V7ubIi zLx%(L#4^miq0pHIw0g|41}0cO(Y&+b#+7H793Rif_QHAw z(kb?m^8Vt3m{n1I$IVUPntgn3QoMVcTqOgm54AGc*uI`pNz2NXYoJDTXUZd|Ag8%%3U)vZw2QWhD+Fc8J~edELo|U ztHu(oSnv-Mx~}M6zXG1si%TqkMxONc77Urc9+l^NQ6NuNOyb3-5|2r3~fvslL5!y>wd+?)9gx zN=35Uz5&dMIN2Gusu|n})vkxf8IMCofe0Sm%YJ)Zb?aiUNJ^M?u#QEIS;Y*g-Rj-8 z$AMN(yax0cszez7zI6?A=4IfHg-V=E6qU@->+?7Am}0o|llk0>cSE=M1Li4T`g9)k zNNaU-Cz}J4tAmX)XRKtfk<-$2sQlL6x7}b*@bVxWA@w2uytIwI%#_b3qoh0y6um>R z$)m#iD(9A{aVp}`L}~o+K*1+k-X>BvENtxKywROLs zH!Cpf+d|-8kRE{eg=Uw3w~DvS6U+OXtyyX?m&fmQZ9|@~1r$P6wyC5BB$ThLrUxL4 zbOSp1@-3>Gn%70(zO&{=I3mv_ee^qa?KnQ>A|y=wG54xC{&sIq_}ipR$-TPz zFyCWXSY6Wk`1;PxllRm5c5ZGxhU`(Y__<%B+^|JdlCw57e(&D?ZG-yddd?K zp$HRd`Zj-{QsUirF!Gda?=huWSG=F)frooRJ2#H)J^TCjqt|!GkNFcB-_tPaaUg4A zVXudNh11vERJhtczTZ1AMqJvIQs%Xs)RnLH$=?p^nf_5B1QfdQS-~FOi4lxmyM?3p z1-+{I-4ArK;{Tdb@A>)5cNxO#TU*f4*tm2rmi1SbHGr)APNS*58t!wwjZ(oyX1)7q z#A`XRo#Ehijp$;zJtAU}Ei8(a}8`B6&}v(vDW zNR|0e+4(}N3^yWjL<#!KDcrp!!Xm{yB|#FgRT4bABvC-A1}m^^FfuZFp7dvKU+RST z>xw*_OOx%vWh#{<)Or1~A<2-wKG(VW zxf#@Do9O;58yrcT)9bV`^P&EJ=1lJ!W=2LrBB}UD(VNVFw^5`iq5cvY-Qq<|Y(uNU zFtmy1eqXHy!JL!N$4ht{l*8S}A|uv8q<&htN7ii^uTmMZ%G)=m$air`_*z*7L5XDw z_UAF`-_^iHCt@)~?$3C@#F03>hm8QEgVS>&(POud2J$I}PE4-}-FT4!YIVnjgjfroJOl}0EDcWYpjNfZMrWmf$+N9K6By#sRF$A^j{^}4a&@{qf6 zCOH-e?>xBD+R;aGxT|=D(8|e95+|w!9|`cMi^^ZU1ZR&8%asV(&18j zs!d9mQ*;|fm^uXR?>|jF``E+rcJ|Qbn}y)y0D;(daa34alAZU$hSg)pY3N(aa}ve= zEKL^ESfqYrNEE??uAVM%pm4ZeoIN>klw2rRWgyn+7 z0MRr#Cy@?!I-A?cxt?#Na216Kq7Qg>Y!vGE@2Bs!-(}j`Ewnp%om`Vl?y%3z zMVkM{n!_CgFHxapd2@}&q2FtO)qP>5sDVt9p}6m*Z!^3QLyuahDRKexMWB7lT;`-0uJAQ219Hg)uBxWZAM-ac(UJ<4QG0Q(0; znu@@yH(Y@k@{x}3XV`mrf!VSdmp<;3XEF5&=#b>vGqg%XCz+8Db8tA!+0m=oI*QWX z-=@1=)?%n%EH-9l-F>VHuXnoPTwD5F>CPa33Th^4WDT92ok1Vqv*oF0j948OWt2tC z&3dJ-uB?tPd99uIjsX~GMqF>sh+7U&ZRnXd$crbztaL$I{k-%WBkk%7Nx9%SG_fTv z5~uol&w=xE=G9|NaFT?Tm=2;A1efX!6DxGGoA;$<4f@lkhZ9zNM#=vC_x9Ya{su{E ztRG-`Bsq4Z_rDDUcPF+n|9y?PkM$;V;$SM@5iEk=qivG8Op0Lw?}J(WHWpK z#$Dh|bsK)!1RG|6xRZ+YyVe@rA2Gqiy6flUBz`9R;R*O4OWL{G9#UG=EaYj-ORArr z2c{L>fMymAdyXbf=^~On_iB0Til@B%W+bo+*|^4+b* z5s*fal%gB4?^>6pDIePIb~+a;tM8x3pAZ0#Ci+i#h_P{VIM@q$_`-HxH~P8A|9b&& zfPE6!DaH?_x|Y3+J(Cn~Xani=FnpLpcCvOqY7ykAgu7c4&ar112j(=&hy7$+%iZ#_~wS6zioIf;M`W6X)Xlk>YZX|Ekqyxb3M!1d@7 z2V3x&GliHT*-T&;zUQJDjEsjYqV<@^v?ff8oz|0sA!Iz$(85o(l`eC7j2B;B-Sv1S z>DV01>X`|EU8@PUtC3N++&SFWcQq%&oZMtIn{LF;o;mT^#nx=;mXC&+${2?e@`PIW zBTBY(7E|G*%b%H<0-etvi3qee?p#7~P!aNz3-)-A@94Y5!_$@G60W?% z4yA|Yefs}&rav)n49REKObAG~iRA#BNnY-p@7%bAYnN5wAg4HA)=o6Jbmtb_Uwe+Y z3WGU}nXvbr-);%}>T%eys}yuSxKr59Dyl1r4!yDRCnw?74LUWQxJ|EeMDAb{lwPVPJppG6qF4g+%!9?%*ca(N-KKkJSX_`aCs6yhqx z7N$g+4vmEiL>R5Y_?nttc;Al&dY+9vRVz{V!%l`=H8e2))?_0%yF~&X?CZN~v%6ln zXU~j9;LK2O`V&-3rtD~fLz!pHFLQ0dsqaKId697pPYD7)ubZ;{QJ=E)b|E=g`ld{tZlx@g+F?lcfw`RPg(hhvtt%250XmQrgt4>$J$ zLkH(a;cadTmxe|WQ(@xOGTiK6+JyJ&Div_L7|0Qh;g@Wb!j#-74yBUM6%LPz2`tUD zR}a43_EHsasX7lupa2UnzC&R~b1Ot=Dv1eaO+SsLM2V!QD`fj9-Vy zo)6nT-7EUnSCk@4{B74ny3@d=yk_sRiS1^F>=TE(cxk7bSY7P^xVGp~+rxRA<_JZl zBPGr?7Iy!uxHW8Q-q%l|x$-tjVqsL`D>N_(+lV&L4yFfRs>b}u=H3x!p_&u5$^UZS z|Bdob^WV#ND`?ZxjPgB3&Fb>FsZqbDmmgDAy)17%Xd%4MPW%yTW(m$`pQo4_m&09< zM?Y{UJ8qwkY&(uv)Qu*OI!CvA6!!Nr_4A2aeHo%v!coyB{PLC#4Ld6+2-ZqpfE_@+?;JQW;m~?@=a)l>QO;p){KsbtfyV8r z|10RlYxMEI=~o)h+K`2znBQLGc6S92iht1?-8|c4^}{Zd6Vw+3QMOMNLAwGo7Rmf| znCakt@nqkb)P*59hlGwkieS544AMV)ZW9*$L79b+Ng(id@f;K#-+s6KqZaa#bL^DI z&mnRKR-~3Wz&qI;fi5LBn`0( zxL2+nA28RZZ!WYT$xk%%)KI%fL9V=ij*T%tKG;0=uW|%9mY?(;Q7Xkmih28dBoxD` zS6+kf_CQe`zompgh-2w|yDG*G%YAxfh?UsXW){4oY7k6~o9W*u`)m#;D|$EzGNxsC zw|}FoPD+fj`?P=IQhkji(dG%tR1@c$KVvdDe5&3Q(#j9!&J>?+EsOrLqWGBXZ*|&+B-1}T z$zdwI?cn{8wz_JBdKta^_&WMh*_^uY;iohdH3T(8#sWwZbSz&-RD}nR zr45+-7lIG_$_W28$yRDWpGLDq8R#X(-yjnv`A4y^={8IY)=6+&W zA9CDyH7bF_>bDZha~d}YhE$X)&MC>ei{#WHhyTgjvRGp%%OUC0C-vGO}tTGKFCxbHgbp#9hL5KilU*M5m(fFao`JzH^WN&4d_ zVhSoUcX`YkloItmFh_$m=Bt36=nd0M5IQ?D97%-JYp{hga5qAey?`x&N5{nv{L02q z+AP3o6JdhSL{JPpG1+UDSa2@XsI%aE4*Va?FQD`<`369*O(Cs-Gvfv1JlAiz@+%k> zG2+I3BXBMh#Gt=so_iu9yMYO>|KE+CF(g8qVj4M@};Zmn*%;DRY1DQEhHo!m3Bf(VmD zPDdW0bYtVv;MJ)00h1a~^4QH?*teWKkiEaseTGarEidw8)Y4$HGa1Rhjp2Z)l_-!E zC{}8UDgO|{nH`qF5Pe@FFkz9|Jx+^h-`6GHH$H8>QW4fzPWoL2H;`@w?}{YUtM1RdM@ch*MW^v zCgzIqRbyNX=Ly;!{(U=rVj?(r$Gyk=uYvHvcTIU99&&yo<%uCG-1Q&al6q-1WJ+5BLBXUTn*q5Ln*10dc5^ zZQi9!{p!iUioP_KKh^+LeOI-74dDL1hlQrN^xtQUWljAD6-}>c@O*z6)uiBE$=)_|nX}cy zP!a1BrYVYk!-^n&c^DM>yv4xdCs`HC}a>hFGEAQcJs{@en=7PsoTEG~vnytbq92uO+j#})x*-UR#&z&j_v~A5(o?v#q z!2zc+;R55;R-Q7%1*9#VEKN33*Ja|FyIEm~9Fe~YDIM=%pr`OePuSE`{_U~OVlS6!% zfd2qFIp~Mi;Y-R0zbF};uQEz%;AEM?Vt2-_6;L@tvVoT>B|nSFu;seqRii$midgn% zhta@!TV9xuD`%^OQ>VtLsY2>^E{p8W;hctn3vT4$coru@mozpI7`lZ{j)E zFk-j3zkP#jiBn|RhL`0eps&^;-7G1lrB8fP(Sz-tN-77fGKEu>g2~?(At@OW?2nC!$v4Bpb-~ETZu*5FdET*Ln0zo&&pO;+U->R1I4e!8qP==61vD#l&Ax z9-zj3S3_4sD@a?&%ro3qWZNKy2V)~DO#V72D<=5Hgzz01XJJhnPV;G$fF_DU+;vMZ z$y5+)iM<|S!5vt#1Z%BTnf?$p5OpEy4#wc^k)1$>pU z2&oIU`s74;(E!1HcBFwb&Mac|5Y>Z4jV@`T7;Y46jIlUP@0OH!rRLAt{SS+Xs4lM| z<|zRtT2OSp1|450K=+c}tGm2E-@RJyq0;dimmCFuLRq)Rm}9>$96mKYeHQ~{Bs;h3 zuuc8@FWXi>4F%{!By!^li>0dF`YJ@O2q}cGo}JIK*X%qGDbBV+5C2S7NMDM9mKrYc z97`lusgTp97fuf;FVEm1sR7~tPwUKSjm*dRUCP9{TDG}sYXi6KudaCL8w;gvHi@VE zi=c&s{+;XY8ifX-@^zsX+g$d{-_3^>36h$5N0=tx$)#d;5s6zZ1#e5ObpSixB?Q~-JFK#PyQWc@#8~V%Yrw;MYW9#D))UY*BRS?-d`%mgf?$KPA-eIAwoyBRR#qK}~UgeQkY zUI!%$8MhJ@eEw3LfzN5uJPDdk|Bq4Ezj^bm9|bd3%aE1Lk!sFKjuk54A6tCBK4tSE z&bLsh;D`P3$dog|pyj!DqX$Pzp}w~e%g?Ok4~%a6Z1Wr~=f}C0Ttl$)PRf^ZQi~ha zmr5_mdCZJb-0T}Fa5S-Td5wai z11%@BbnKWC2chWxY=}pKee3qH2#J;h<#M3wW%P5J;-90zqznkxoe2Hkf z5a$b{IiSoHx)AmAKzNWWZnfq}Qdm=%lr_VI$mzAQs*<^uWUV&VpE-}nulHEyFR|>> zP#QBlwiC5c{dGp9)SW|dZ2Y(_S;ikOLD1&L!26HbVUChdxSTwLq9aCu^g(9zAC`umf@#pPl_6i0>E zOKxvWi{0u(lGKJAr)39A*9|uejRnJf?-U9h#}|R+q<=J05Nk?l@{@ac0nB_+9REU2 zJXeG%oBujw44R*2^JR9Q-Z&S6=@ z5-*qRDUvA((R&IG3$!3vuad}7HZd#c_avBz3}7RCha;2A1{t_PfzP~cw73qA4vShL zi!;J>kQ(8$lQRkFK55*SzAOBzPbNLIY2<$IfYQnOcLsa(LunI{qg=P+z*6VaHWQak za$spcsXhHl@!{`Zhw;UeM{#_Fp!ji@_XeEJX5i<)!QNrV7&IJPP9c0`wsS1qtZXh{McZX_6s2}D ze!sCP`Owy$GA4`6f9@9EdQ^&T_D5#Arnop^cmY2|yhydrkvO84_{k}RjEn;Na~wkv z&x~XT6^r)C3u+2wR1qEWUhKnP-{z7>yF|X2)reGSj1<7M%LifLhjgv22|_or{bj}) zw_kpgrLmRtNx%={7tU$UI=u8nVH0H+XMck^F4<#l(L_~W|H|ze8ZUvq3J}P+N#!R zI_NSd?fOHtMPs^mFQfX-)-$U~47K~$gq#bNM3HW{V;blZYSXTNTahX=H_+jgY+jfK zoP^sIOe+TmXxXN_uRf9#Yi*t{ZJe(w1g+qoDw+g+4-_Tfa;9jP)4EJy6^&q4&Y-Ae zQJi71uuZw$%@cT9YXBPm6C-^0!pA##BuIeH*x$bf=$~+@kzKrL`Tft}rKmBd0;u1e zOTl-#O z!-f#pv+aF5g$ENs*J%QngAe|(Nu7rAEQ!&`!L1rczx7e<`+0}dUsTi5(myx%BBJ*X z%~eYNnBJJ&26mg}2MKn-gqyLb`On25trnB6Zd_O?A zZT<2AcvuCIG~O;p|8&SeFf9}*Ql&ND9+YPzu*c@6*kQc{of$75G+}yr2NluzVfOuD z_NLTMu+Q`vI@e2HEDeg(oSz)hTVns*$f{?XC2|zUxSmodrRK7`UAVrl3KcH%ZXZ4X z0w{LxdYmBo4|q3#`2T>{hU)G1@D`Kmr$tmXY4Ok05wN**)JST30kyMH?+qYDfw1RCBi^!i6b7>Z@c6fI!WGd#AWafN}TEvKggT#OABuI zV5CTcj8L6Cg?c?INCnvVGJT_$AFppm?N>J@^Tg`wwKgwq`6i+M-I?Cv{E+~8AYf1HF zCa<1=2MzATqBo=4hwZ1gffE*lcJDhqWyM>kgXl$q=tW`@XezKN0OWA@pM2_gKbXLu zB?$^uid~L`szchKL^*wY-=wOfx=y_^^R`Tld3rCv?gVaJKY?25y^JaER`X*ZXfT>G zKw4#Su~NyAo$PdbY;DVMP8KzPBNQ{u%)xPTYu!hf`xaZt0!xC1eXxRW7^TRx5=XL$ z+EADhk=%^j3}=|8<7wCT=>)p-V#RYu@cIN0G7LEfcbV+b%_^{+oN}_$ACz!x7IW1~ zrcSPJ*3aG;&4_%mbrC=xL}Oo&FZ5j=K~tn5@1xr%UY4AQ4x0Oi$nWD3D}gRlptW3} zyyBJb*lf64qa&L-b_dG5SAko*zle{s+`<*sm@zhET+>*qqp6RE$boCEMyl z%U3grkJBmR*$j8VO#yNY`Efx70fhqJf*L`ogzt0=pzhPp7R|Z=i{l1@dX3WDxWy^58hS49E)ib?gvL+<*e?}TQG!uI41G^>7;up- zttnt5dQr@dopU{cUhAygQ?$QMpym=y7I`m8KgG*7B|aq*f#ygYH-OaAIG*QT42%&E z9Ds-fGFjWjj?==^=_U>k#|;!aPEA0%oj~1HZKG92vS0VYs!r@7DWqX4+!$UQlTK7* zR%Z7O?IYT`XSyhbLS9w3+5zxJzg%RsnJm$|V;gr!lb8%8>+lsSzycdE^Iv@NU#ta-{Qip*lZR0G= zXQi)Nuk8E1oU=K6r_~l)_W1nc6<)K_S|;MNGxy}1e4lKgvCry#pCxaoW!mP2c=0S= zlJv`A1^^G>76Md+q2iz0Qii13N+2sr`#TZE??pv9y>iEl05P9UWuej06Wm!)_s?Cn ztbiAW!9s)&%o{{0#x3#5m z_vl+oG#4bB6_3H(Z$29KhP8# zMT{r##AtvK`5*>Vc^i8H>TDLOpmSvy@UYf@A~)CgUEe)7C(t?@2&OO4nKfl>+zPgz z*q8T@r1Hq)7OJk@My_65Y6dAL2N`x+aP~PWUu3roWG+P~55LKjPv6+U2K>ds!Y|H) z!=twDt|z{c3``K(g|7B9BBXjOa>t3Q{!@=5A&>lvPqX?me*E&ewQarnnEo=5ADECw zBFuoxx2vjsG)nKw*-^sR9WMC7jn}EQ6vSqfaBZo~YVCQB?0fi&TxP2-%$PnbdWYhvPQ#u$`KS>#SbwS6pO1nKnAZ3QG^Vyx-W| zOavrZ6vmtVt9w<(d(f0QNWYS;5nhlgTt^mP@Yzi(&e`J~sVmz&D2|qS#p)C2AWkgd zGwmVaKm}n!?Os9(;E6%X3+U7@Xd5ZHEzozXOS8W-aTQ2uHrhJ3c4ta&)h$qz9F0)+ zmVH}uH|kLm{`K3IQQrs&c>N|0bb-?JELkqM5?KmRs0-2)a)YevF*Ca{nQ%ZF}&Sc^MY+Y zIm$uO%;q_C45NK8=*Rw17=d|t3J&ICzXtTjeUUVo3c)}JG$q4#j?3Deef*=G7j(rD zwtUu(n3VD93vYR;qW{hnw;Z0djXRidWViVITX_8~d9bUi>-`(Y2E28?HxRp!BVdP+ zR~WlFA1++tdyqI@Zs|Y%=gql~m?+)RiYk-9b5)PlI@+22O7y#59)hsarvz$SL+Q6{ zv?FGgJx1>jI5J;3EK@{^@1NOkp96vlsNU|}gQc5-KjiN5x{L}>_r#tLj14qeQ#+1; zLeAQ%WB;U%iXb4lAJ&LcJ$BvF_$GZ_sE0U5w(0_w;x{=^U;FD)54AcewI6y#p0 zIRhvQfR2?~O%VL%aMRaCiQ2VdD&wYXSb; za%R5bX}Q5_lFj3FB(Bnt1;rewEL0iF)V<^^KYMz0dJzEHS&5h;=-1wDHV>b-bjhs2 zzr_W!19NTPErvONn znz3#HLj&r@mN@Hwh$!}s)7I26@x?R3y!2fyy$JF{5|+_EUa z3|mgl%OY3Nf6(a9zPM~Z!$hc$**E)oF{XGw6SX}`2#)0Ad6FA1;6a87aO31CepjSh zB47ys&xu(L0YLfu>;w4pG5Qm9$}26ardJe^SftkL+O{I-(4gxD2AO`WsMwzks${#r zjq5*rrd4?QVt3+V9DvzxNa!a`nZToa6O@}$uDR7nM6wcW$I{%OEaxYb3ZYe z|Ipx`IjY3`0e^cn{Uvq;tmqHFC&#dp!r2OL-1_MSKo51ga7j9A0PeJi`ycmsNwNEI z98gl&uX#pZ`8ormF0dsVvg1)Jy)gO8c>?uKx<6PKsuGQ0D{lX;vtnxR9&5G{;M1Pr zy8VE(eq~4-L+K&_KuxiEITNg}EQyZNuKz=LKaSlE=1R}HIQ{CYm)>-mE0DYB6JSLZ zz_Xt3q(jl0E_txKy!yFrlp~s>n5SWdDS?vd77NV#V7Y`^$#SYE#C_5(%rQHL_ z@WtncmiU$m)E33(N3XV_W;mVEjHxFq;d8o>W;3ArMCnBdk0MZLM$MIpi4j`c-BbbH z%68;n^V|F|)0E1QUw_udf8*qqsxgDxur>4s)%Vu~RfG@TuqGh|1b|eJUGTA_k03m_ zvJ|WS(+8z$3*o+HKyx{{{d+@Os6VymhTKZbUXL060%smuxI<>QpuQvF+su`HpxKRT z3EK6s@4&w~-*dOU*WPdK;Sb(3$xSjAH|RZi2kZ zY@N=Zg9-x6AGk=}E=chWc3n@mm`D_pu3x=uW4%Mka;yNJ?)AY@xJqO5>G8g!)3ufK zI0*7AitYLcfomUAyLh41a-vjrXtaxGU;T<%iZZaX`y#~>PI$SS)ycWW9e{c?(F2mG7Yap#K7>Ka)Q@ zmk(@tlkd{v^Ym85MAgva&eTBD$1C6s0>q%B29=bjvL?zO2e1NRSN&IqueQmkG-0th z1#-0BI-i_^VX7^qKHBu*O@fPn+Pg2+(?A!hi#JS=#jPNb#P=37%x28l&Bu=)a46y; zA_}Z_o8$4U_j$2WOZkc(YTbs?p_G^bIG+tQR7?1l_-?}FPYA#UbbQqEMt`WF2*y%s zOn^2Egn!()PHXbuiXgUs#LOAB>|>6GF*t^li~jYMxaZNmn)cQ!4%)gK-a}*rqQ&`n z{k7Ydt+N@oK7ppV^n7wdK&5CJY4!X=w8(6vnePfmUWN<^PcYO1f@ZRD)M7^dC}bJP z-2hE8RTOZ6d35lapXKQ@KrjL2DJO&!f5m0KL_ak!pRqNRKhIYv)M&;@TCKAwwf@m+ zb_gBwQEC6KKO=)6zJ_G~-OK)>uj721PHuQl(D+T%uSQiU0ac{@cyNq?tnYNKxzK*j zyA8Y^s@Q^H^`Du&z54R$k0mZVwNy1JwtfDx(k*+)(}wMmK1ju)$35sN`_}6u+>*zd zJ_=IHF1>t#->jNR_9CUFKz(h_|K4}ioS$_1z?C4DmI+VBrBJF$F>jWiI;BScJ<|FP zO^le2{h-x5{g(l?;=R{+dn4zw8S*DMpUI_+KsSJRPv&rPN(I<U^{t%9K5O3FQ)Y_qSpv^pjO(8ZKK&2?uTcwm+R|7RsS+SL;`{iI3*l* z=g_E-c^B^;RD^lpJ)!Jq9DC#=_Yb?Wf@_qV?B}E!+Cque6385|OafQ5=J7Eeuv-zu zhMMq0TQrNGB@%vINpXMi2g6wTj^1z=)0M{AX=^RV5V{%>%=coeKe(StmFQHtGu1la z(#(FiqJ@Z8_(#dYUEBsv(k+)T4KIyUG>tBK!BlE6ft*AgJ-v-)nV*-dq5XR2u#Bs&ess0B z`pePo+GG&C9Xj({>+1;{8yr4lY0>wbgx7SNG7V-bEo`tTqOl&!2p-t*l1F~V!U^Lk zyg()HPWl*=ndxrv?nH@Uj@9{}d)8Di*xSJxH4`kY;)($#qp)=gUF``uYgjera9Qv! z?z$*c9%3aqMMl`Iq+K&mZL~Df`^e?#vUr>yc39|xz7e74p1cIyZFT=&(MJ_H96xqd zm_Gep5cu8rWSRqQ`Mkpdq&Sy|Dd~wj2o$WS&k*v8o8MX*t)nwC&N*6ip8(b#_Kky& z4`@n3M91eN{nIo*{)Q)JU_hYlFZ?MTY$iZLYq_|kT~pL6C5r=uCn?*T@dxiA;TUIs z@Pw5$UIzHz-1x62?k7sS%5p&4^q#oYl0poXOO6zoxs_CHGqEo)L|OG^kpgi`W>Hu5 zS@HFzj{wkekH z(BpyBK$eGBFi)}a1+J6S z#DrO^tg)@Ee?{u0J|P?dH-WxXy@>de%UU2ONRo9DJ=3}6uK261i>QH$o=W; zR1j#FNC?W#u>KyjR^#=+IEad6s z+}n`>qF2@|gX8Ja%u&u~n^wjE>#oSa;11R!|T zC{->wR&-1I)|BFX3nkVt`)uW!&U)F{4D!Mk^X9GpHgo)9{V>hRdE{nS*Kl48Fq>;% zwGvzqrftG*y3MQx z9E^vFQ@i~;L}OK7sVb96o4KE#8t8Et><<&aojKXfRj^)aj?jXt*0w@0e?(Qj$ih`N z*_0tCcmiGm&=n^Rm&u7grITmsX!KvF(21IFGvmjCaSL=xu+yCL#>@8l{exvVKp@6W z7!B69$o6r#jOHp^#*eEHloh%y7yKgue6xsv8H_H+)4B^qP+)2e=mR5yQJUuC3YBqi zyTOU;$|A zR+|Lgv?lHN=P34YmSw9#f+i|oiZdk5<%4C|X)%_6G-tc$*YHYkQ1T5zARmaYX)OI8>luvxTJ!&NfW9(z4>6 z$NBDc?V>KRdehUgSpqc;DnHFvQt$imn}Ztv&C5eMzkk`9Q0dfnD(>9b=U4O4&h0++ z#Np^Av?sGHdr=GgkM+n*NmesfB&gknoN1LE{sD&gGgfuld&mxq@WS{XL0Ha8t7o?b zPe0dit@hiYe1yIZZ3Fukn%D-P1CNXz?tvkKO`(ffxpG;is$WMAVb_ZbQJZ1TVOctP zW@|L;LO*4gUgWQC6jgB#N3X46k_T^gERTTq@UXi7Cdl?%kfn;*k4tv0$wq(oRjRs2 z2o{y{k% zef-eI#NrX6jSW9Yc46GFL#y9fvN&C^BJ5;klFmmsntLHjWx$znwmnKzJd3h?{4aWW zb#+4xC4dfP?;5ey=az7Fy6T7~`p!$R-T8imPYt%SdbzY~_c8OIw_|64WuE@}WH5%7 zS+HiQk_)59FxW*(OriPL6C4K|RP57maxIyeKOevv*h>I<)v` zo{`mV#xK}^z0>39!uB|0VN=<37IbwbQCdf4k|Wm8GaUpci;)>|23GAVk zc$Md^``6Gw(DEHu%!oJa~4N786qAJy8FPYel$L(yyTt@f|ud5g0via(sDOi`!jaY~9?llq>4&m*aC_ z!6vB)*pC~|Xt92qr@OrNt53lfD?m~i#CjgDyp9tAI+6V=S5koofmqU~EW2xKh9ta& zb^qy#O_JsU6(%)Ht_FMs`LNu?H3uMhG~-HN^CT^>G)im8GlFT5h5W}1m~f@Dr2-#c z|4cE~eA%RponhKP+OaYHx6S3oT3q#851|AbpMok*#%mh?^7r3WOD24yLkY{fh6_kt zFiw_vMNG>Wzn6vuiAa|iDm`2zB0hV#?Eo1lFA*LgsihPqU)-tu{TE3t%-b0;C~N6= zcV?_&Ju5+_LR>W&OXc}$@8NC(xtAyVe=Kx=nlVYe-2_&4#LbT4SA_)>PQ)P zX->j)8(Y8LywHxFg9_+pGh^)eHUYI$M$XZJx8W}{GTO;eu)&fwu(tw;R{x_r-awx4 zvUVm|Uod?p@tE%{c1O zj%z30?hCUIjz~y0i}}iy+iKnU*Lcvy>lzgwULY;RU;@}>MmCv)Q?*3Je7CkLh3*SY ziGfdhP_a1SAnFemq|F35+6mHivMp^=Ep_5&c+BATTc(NM_emvkKaf;*KuNssR~uHZap4*>L797yPw}fq&uzfp8 zA`rPj$XjJtLOT5cm-`>?Pxd8cdhXL0CM|v!h7&=8KGft7({Lk4r_WmC2J7*Oi zO}MTEJ!qWXNdO3I0?yW~6f6m5Q8!_{+tYIY0kq%z)Eq9pF}Bt?5uX^g-p^X4PX+Tv zd7Z3+m4JQdcpk$9h={8f`&VQ&J^j=3;El{3pq0Zyoz7J|n6R;{zWB?{?|0)30!ZZY z;>+OE%$AguXwS_%I_Vo{tPg6_bk{XDc6Wo62Yc&Za;A@_w@<#bOM-kGEdWTCqlbqq z)=RBX+x;u~rxZW$VUG|)qt`mbg&CuHRzkQCkzF?ZC`~5XpcHb5+A6mk)`LNp3zvZ) zS^N)8Wi>PYnXyB*mv4elV3n6(ef)u7Vqme&JR_3?R*9e&T0^N=1eF#@o-KiS)x;iCurceKh{k zYm{)WX`TIG7LyAZ2LoX?TXt;tufOXfsMR!`%0lDHd^BHqcDTtcX$-^UXLj(A-b_?u}XqO0q;{jv_IXXCWPOh;nmvIptw9Hr&apRqz=4hyW zuC~B{Bfa|bK3Xf3Rf9c=zP$sO>`%kC9lrKD$r6XYruv*s1M%6eq3B+d!hM*@gFOsf++Vjr1)e1D6f zMK=Ey>;>tYruF|`^DjVj?O#TX-=JhF);8|MbPe~z%>#7fp6rQeW03dj8G%S+Yvs+` zqytb$*1G;xcs}f+gYSa~SjZTaF~&~!9l9EW*G2Pl;i9qK8_0;E5hL4Z! z_uM)PYU9bTNFH|XggMM5Vrc8Ke~2kBI0Q{W zqb1AXee*a)q$BNlmXkJyK%CvWIeQ>9bpm#pJ>9#1dA3WG;K*Fb@-J7R$F2*;(YEwb zfW&X0HDYP?yhvCh4{*UYc|k{6d2?D0#brx?2Ma+&Wfy;FfHcTj=GZIFF<`| zrwcSnvBY8E`K*nuzr^jieC${)1nZ0$k}6AMExp=&?4lvNS6;G(9KXn6iwqY)bIw(+ z-S%Rih2saST%?z8CgNg;85fzO&-s2X9N|Zp$0y9>BVesbE13RSro#Mgq88orD^ML# z#83e%ML%eAZtr5FXm^5guD`BYrn)k13Re<3?Bu4?R2xq44spZnTg+@r5E5 zGMU-YKr8~8&dyq(Nk=EJJ^0IEmA2UPZ&kp%JHvgv8FSYD>__SS_VhPy-u`JM`{|*> z*{wb0>P3)XDt#7MFi~3Pe!D;DzrA*B?|F0TUaP(6p1XGPOmc}Ye;C49WTsS!?nF+94A`yim4EL!u?PzQZ3K;Q5&-A%Lj1nfht3SW?cG z9t-k{9;jb7YMAgj1BXzUnscO?Go#EEqgs{vP6}murXF*lEKS=3>QMzTNyp#I%XdJg z!-FO@jX!T$-E{U15xqTs@i9%y_0^)=#O309j*`Z4rWB5`v6X878>*chAOe;7B}^+d zgtRaw1I<3aiATaDuVZUoD4e`WTV5`-vGjCWA`N7rD?=NJq^ z+F;ou5m7p~uXlq81P&EJ4D1y^_5sNC+WUh>yDj;nCm7DRk)^ezu+e=82bsDE-9Ta| z7MGCE-Ho2i)J9N$1e*Z(0~;=bstiSXZu%4=9F*S3zhU{@#%yF9#F?jeqaA1avt)bd zG2cc*Z=Q&|D=UvEK@Bb|EA+YA6soCu3Uey*JMgB(xqeB{kqzaP1OE@SirYtvC*ZXN zs#P8*3VN!aoBrz?W=|CG38l9R*~VHgt?DSXwPSz(_K+-6ZFzW|eb9NAL11-JYJKPg9f_S zNfZYjDd+ikyF(+jfu6gw*{5DoR3k%bpWs4AE}Kp&4uIA5Mcdf`&ZrjrmEj zLsHUTUeGVW!eHnk1zgEz)~N++F++~E;2|rSk2A%#HYLKKkKI+P*+8WTJEv*yHHz9X zjqJ$cZpAOigeOIg<_VWv4^u6;EoXQmMY+y1BpRiOkz)2V5iofe_K_!I~EQwiI~9K{TSGW1sMemL>*Q4 zeIPh*qQ`jz{RS^yLw{vM&;8l6GC&lO6k(oqUogZ29D+Xgqfptx8X0q25I!7JPUP-T zb8QGr4;zU;XWug=i;azo$&bl{T*?oVubDvkA0@*V1i`#(4#G9@>p0bRD}hHVd)$EX zzhw*Q+TK>ztj$*`P<>4 zd@@Eg9FNZ(6)k)fWU}9pim;5vnk2={_(eZGG!#d^cQ)a+A*jbuvZ7)9puvCpDqYCY z@N{W?d={T6(6>w(B+=-Ht4)7>F-?euTd8BeeaWBP3hGwch&cPYS-WE(T#g(D-* z#nsI3(0Bh8Feu3DCW;iO7Kwq^=CSQ3fS86lbzcA#cC z!)N2(u?9k|D!_Ox4q~Tto}5I}s)uZ0x+|-$_b^`Hsz!5i)Gd#Rjp^FjEe~P1~izfe*l(VG66pv zj(*bR1z^QTe)T2_t4ZxDmXra4$hp7t{^CM;>Fst6X4?~mgaiw(kWlZ1azbN(YzYz} zl1`6A%VSwsTu>*m+{NS-Tz^&3{G!X88(j*~?$E*d9}SXg&_!IVJY$jo;2Lz|eH=Vt zOd)h>(Z2vA7-(8$N)|@T22b1vp*t9&-z^CXELEIJW~^-E-fx@*fi3HKlfb=1DY6*)cy`UD+3S@j ztZ>WU8fGwyZVt;RpYoF{GK;OeKE{aD9(AH#E)&c%gb-Wq;t+KiPZ_F_uGb}+{7 zT}z+9bZw1=K7D+gdl=zvT9*HJm*azx()HuGg4DBNBi@{OA%OqB>+kpWh@_GF{kaxx zYRh@GQ1s?|H0u#&wAoiX_fSx_6J=aiZtdvGBSB-q|9%UU_?AD|qB}Q&hFCu4=fgJMjg#~&_ zTkZ5lR|U*y(=_)R0ZZ= z1GPS1jkLImMwZCOz3=Cp^bayaaUwr~f~-G$B?#YLONVy=PHxF26IOf`hD9d4NER6g zqzSUiMjTy~2s#g<#0Xc}jbUpnCAwo2MwQ|%r=hhqXTA12DsON5RQV{M%?h-svGgZF z*9h8!yOa+|Rd8#0MD$zI!B=DQc%`{IP`jX8qmhMMZFzZ+M)WG4z3IkZSvrA-5{~Ap zpt6}J?fmCN`sL&Kd8aakUQVV6yZSk~9dA?#qzh}rYMR2!K7tR_D-8iNG8fUN-x~sD>2+#qsT!LAfVb`Hj|YMAa-N1u5VyPb z*)DrPB)bhF2(XzLADtK=%4Q)H0Q}8n0ri_{8z#+6sifXqU z^x`WgePAi&Pgt((hMO0ZA1ydA%oB&+XI{xQFCK6b5q&EtqcJE?wb@9H8-fEgb^5Ds zV+e2nT-syte*q5(Fg#aPg)qH&0mvtxWRy2B@nwsfkdfO zh#D+?Y+Ny7ixaUZNgO)z+88|cZ7VS5=H8cHJ0G67*jHdR5pHkgJQvnaUJM_~FgfY~ z-YIi5nwCdis!4AJB5FeACu+sN`xF5Tmph~2O85mHBo}?+j5`HyRZ0c`1&;} z0?_hxfP*lu%V5YSnQ{tnjAEa`zM)5YiZI?Zwtj|yqej&dKqPR@S`o=jcStfWq|<6Q z24Tz`9DpBgUom%l$9N2lvf41CSF6u|C|`$p+ODDE%C5W(mX&Y|wlmf-gRp$jPXR&) zu7PM8%@508E?g$|Q1ABp<7^&*%<6AVacbmcFf_2y!x$%`9+I|UmS7d~Fz4cG<;nu6 zTU&Oi*KesloV}q8`fiZ&GjWlr?NSs{yJ-81wRO(BX&Xg&z=Crf2&Flh*Kn*-@KGYV(zYUHoYez*CbCh{6hjg;PY_tRFp$|B3qC%+fBHuV>Je-qtd?^0}p_bbA;>?tjTF04YUgybY5>(Dn zT;eg@tQnAa8uLcXxQ@Y(ruEQ!6<=;@D3nrtF^-8TDl2kHp9EKT2jYXR0ZlAh5>P-; ze5T-d!YWGyHX3O%OC^BllG9drM;`@72sq6_do55fjqI3Vkct+g@{9GYD;)SnumC`0 z-vjtnzvoGS-bvUQ9eMN|`B7kPqbiIroDs?&f_$gwu{#>=baa5$R*r~r`InQTMR*5c zXtICbNUW3%<kGOU8ArI5PgSWz!NB7Qd20u7!nhoS^1OL7z!Q~pCP zT${T$@D-~MNngKmY;%02VNG4?G7RgZ2rQ~=0*B0-h zUj3X#sdb)p&{9oK%IJ06ex4iuk_7-cu%YtFAbdg* zb{wDN1b=`&sd%>;L=ys&fz9GaY0s_sjun*7DKR7}4rmpL>%R)cC34`W3?kidj0Lo8 ze}Bc^)kmh+T$D!vr4)1yp0UV-L$?amaBRP7;iEsMWFp2|HZ(WNBg?g@`LhSF_f6Ef z<3c9R+HA_0QiiV;A)6AAa_ug5l3MFsCsjHep;&-L#E$dut>(@18S(71W%qv&A(?W8 z6OT*LxuX@qqRKRr?a!(vh>gQt({|ildK_R&JaMA7SSPS2+?32_$dKh84y} zc%Dm8_K}2h8ri7Z!RkW(?VC;9wiS>pA8@-QPAwj!6DlKp>kUmy2x9u@j%*a6TWRqw z9n|Z{12c&)D7`6x1$!FFUw3qOUkgC4~XdJog9fF4G#YK@ITt7q%Iz>|=Ux<{c@WA8gx#|B(wTU(tsi zDIOUzUq-=t%AdV=nS~6bN>>m#a#Wqd2ut23m^jg#MrISzGoldE?nz|(>#Vbl3!!zE z^dLW?DTD;&l>qlaIS)!$Hkh(d?HP-@IZbP!?^>2BbaXJ^Z_YtF)U=aBCWGh?4;hf? zEsYU0PYEf1m`*O(YXP@Y!r*W7CmR_#81NP3h$UnTeL)-R?9_q=2U*Ite zH$Mm;P*wl|h!^!i{~0f@XLrrXQ~2~W+gIec`kHv5ROA4eb_UH&`@kNF2;?w#*zb$J z5eKS@m95>oCmf!H6dx3E?vhAFl^}Q$t{6=f@ri^M0Ssa{W*Bd4SFUsnNrsJ~E^?rT-o`VDfk8HNV;W z`MDPkZ(+$%#kMa9+Rbwc-};_&}V5S^Z*a+lmyC zKI}~bOvsiJ^J~jm9jiLDUZd#1qvD-_^~kMU*tlzmhn_IQi@?qfGFWmsPyq}Cvq2se zCpcjkf2+ah^7_%^sD~tC(O-O9-3!?Gs(whuU${zCsUwV!Lr(vt)ajPWzmfsk4NH&k zn~Rh1RXvwBXp9@>;kzrDZ_`kEmqq5)paz84)?y zX#Dg(^IaDI6UmXAIyj-*J%T1cs7;K@D7(ZzqwW&lCxQC3p`-JaS#239#9T;%cj14*eiyOivv%nnXyhPL~=Tj8suPy zQA@>PapvS4Ab^kp%QUM8CA#vkkpSziy#+AatvEQGCZF+;qeg_)!dVi0c7~_&XQZT- z3F7LmRv8hE*Q%4R`;)6>t5T`!qD%0ZzTGAW10aV`tMACs8lnl*J&v*o)SB$ux+M@v z`tXf!bPJ#6t`-~HL|Q!LV)JpRyv#Prvy z*dYPqTOhs?op95iA8H4HfTnMrjWqu(diLgP*=NEu8s@o=7@j9Ok_prnX>O*U0vO96 zCa~lmrNav>cbj9%4;YSBavH%0p^OounTDaIwf8tXU;P&4njDEGs#e2-(rHTb_~;GZ z@b7zKOGcl~tTO=%Bi$sDquBcE`RYZ^nrTdP*7`(`a7}393U`QhWH4%n*G$9%Nq-!c z%d#*xYTW^N7`_4h;n^S~8hZ9LSw@w{P0(kNv>6QWk`K)KUS4bqt$pG8$Q?REB<|+k z4(fHHQ!bOVNa$9>)O#k6&GD=)}aWV2^QFAcCcG@C-at z`Is9wJS??f^Ks6iA`>r|64FLrSg+yK?>(N`fu_iA+I0X)c>%msi2eHP(( zT&8{fDo9yGIVIOAZlHgr`-2=$65*SfaM9+}&(}q2+KEH2hznhM=hf+snMJ3W8MfHl zHY6Y=D4pWi-@&G>=gO5bXtilCNCuYG2mqBs@Z+Oc@&zn_Q$OOJSv%FWK-~+3L@()* zrEToo7M7QRHs=?6g_aK;xVY|l=LpK8SgT*2`|KaeW?Ruqr@}dkI(P}3Nh3Q{|NeFC z#QNU};iDV!Hegy}i@YVf9o~+t*e9*->%i|pt#yttO^J?{153h5%I5G2^5FtR&#nPP zxwoLy1ee>2_;*YVq9z|OFtR0?>JL8Xe*%ywK#DCafbkMBBa0aG=51~zJf}$V03NiY zw6#}~GDstrh$1ajnE}`0-Mq%hA;=SAy)3yTR-`)?T%cJHo_3vjK>91M4q0yviXU

yD@T|G(GDwJ&Z~veT8l_jX10 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 diff --git a/doc/LSS-Icon.jpg b/doc/LSS-Icon.jpg index fdc11a8a8638c6fea4c67db5c5b4926d82f744fd..7c24febbcb50dc933fe4685877891de335fed828 100644 GIT binary patch delta 20833 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 PEp*`J|5~3r|2^}6*G~5a delta 20445 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

K=VSGR=OgOHx2CRl{EJo6 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 literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.ldv b/doc/LiveShowProject/CatasWatchProject.ldv new file mode 100644 index 0000000000000000000000000000000000000000..7e827f5710cda9d4c527f5c20e022607c362087a GIT binary patch literal 9955 zcmeI1zi-n(6vyvEToqBI3@t2lh1G#1jRaB!NJuQGD1U)l@~ia^)pn|eiIIhcg^3My zf`Na8fth~+gjisMch7#|l3wFFVAX|plKs7R=e+pNcb~hbd;3{fPlc!oNNehno3GlB zz8zT~z_!R0*=jvVSIXpQxDJOD%lj`w4 zHAy`y#4NO~N|jU&HsgeG0>dB!f#+j)@*4sKtdeX|)VwPTPC^4tZkcg%>BdL( z=947v{J=aZRcJQjgmD7H;tX+u5XgvV7mokR5%H*bR}!4~dj^~|%s9FHeV>SdO4uN! zO3h}RFiv1tJBi1h5;unGfq~QUK24;WovaxsglaUW}K8CCn*Hf z#D|ozk>KMUZ3Zz;w9Zi3x-;3GtaM^0j5~u-ujd{=B)Qc&Jk_c9c4=o~J?Q#7#~HGIQ`K literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lms b/doc/LiveShowProject/CatasWatchProject.lms new file mode 100644 index 0000000000000000000000000000000000000000..fbb39bc256cc8947c2976528f763502298441fa3 GIT binary patch literal 14 TcmZ4UmVvdLgMop85r`Q88mR&w literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lmv b/doc/LiveShowProject/CatasWatchProject.lmv new file mode 100644 index 0000000000000000000000000000000000000000..7d346ae5a566e2871ae833d2b8816f232eefd9de GIT binary patch literal 2334 zcmZ4UmVvd3fq{hq2$(>a5lAotF((kS0x=7NngIypT9l@yR92RNIY>lKzCl@{MN)n) zgQ#;xVqSV?UV1=&ab`(oeqL~LYF;YP2r(dL_zwgint{<;7EHqkri}t%CX7ZG2lDM3 zfZ7;AE<*s8ywaQ;u&Hp95q2Py!CCenAWRqymw+-rc3=g>1VXMkED!`d^I+aL#O{Aq zQ&ejh(*nQ(Fd8O{#K-M_m|_Tx2nkei5D(^W7>%xiGXG~_@xKvv|8vOPL9v@La0!?X zqhXRr{K4=4A}szl#_oS^^-C}>Li}y>1BHf3GD5|He0umFTnJE<2=cPA1cC|nK;Zpe z2=gb3=aD>(B2K43pv?cJSp08_-Twj~CJj6P=bK>hzZrJ_i?Gc_^}m@2B)*|EOp+17 zr$;8BB>oK(;qlKCT#{H+5}Z+*mX?EA0gCr7gLx0)=S)z23#{RwG?;_Rrg#aTr z%zhM_h+5DvEenP(~+6T?nILl1O~qJ_l8HAOO*XV8IMQ(6A~G NMk8b(ES#~<00300LAC$@ literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lsb b/doc/LiveShowProject/CatasWatchProject.lsb new file mode 100644 index 0000000000000000000000000000000000000000..7323c019428be2c957f1558726f4a550a8709f67 GIT binary patch literal 10011 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 literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lse b/doc/LiveShowProject/CatasWatchProject.lse new file mode 100644 index 0000000000000000000000000000000000000000..817353f8fedd33a188319f37beef1f8f799a0710 GIT binary patch literal 96 zcmZ4UmVvcAih+TF35XfNw3-13c`K5U&Hu^von3tTImzq?RnUbDb3>UP7u=K$?AiCgk z{z)LWBGl^QQR|hNm!5-UE*7;ez7cSvg9q3xzNsmhiPUqAIb|W^lbV-ak^y&)fuWV5 tft8V&0aOGSE&9-i)dxp216P2vZ+x()yPvCzyN(MmkueBBQyUAI4*>t5&r|>a literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lss b/doc/LiveShowProject/CatasWatchProject.lss new file mode 100644 index 0000000000000000000000000000000000000000..7f842f9433ba6eb0c60cc2eb9c6fddd3683506a9 GIT binary patch literal 147 zcmZ4UmVvdrmw|zS5suXiKp@wmG&QBNvINXQ5QgO$24#sBN%^@9oQ}CknTdJHsYXDp V2m_cH@EcH42r~eo2c{ov5CH1A8+HHy literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lsu b/doc/LiveShowProject/CatasWatchProject.lsu new file mode 100644 index 0000000000000000000000000000000000000000..a8a763e40f579e4ccfbd257f4dc4fab86b8cb01d GIT binary patch literal 1104 zcmZ4UmVvd3fq{hq2$V>)ElN{UDl1FC90Xxlo@r2)Xpxkk%fJzySdyF(nwQDI zYm-run`39A52hIK8&FaOGXP{Qdud*FUVeEVhz$gcK+HtQfI^r7T+WFliN)n0XMi*^ zFz`Aj7MB#|7i55)1~bPzF}I}Hpc3H;2&>4%z$B|UyP_DVkpqaK&c>zM458Y24KU!! zZGn0iLH05-u;patr6v}^X-IGar4YdW1B4Bu30ap!U+dE8Yh4a~t;?mab!Bw5uGoNL X>&jihi4&eSAsG>#B?uM;&}0q(t83e} literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lsv b/doc/LiveShowProject/CatasWatchProject.lsv new file mode 100644 index 0000000000000000000000000000000000000000..435b4ddf92857daa3d5cb25ace7c950b62ee4bc5 GIT binary patch literal 1714 zcmZ4UmVvd3fq{hq2$(>ak%23~**8Ae)7{V2#a+h*Bq0EmWP$P-n1KSEK+M9RW&i@Y z7Nw~vm6au64ib@*Z%~$Kk(8gyAnKfvn3tZJmmZK`oLQ2YpBJ2*nwJVSm*GDU0ND%- zjMlPX8b&Z}1lbLA7L-O82lDM3fZ7-tVKQKvC9gCm2So(TK~qG)@ww(O#|wDo!JKV~ z-QBFFsJ1bt1wd?s(lA+=IFL^}cV}R6w-I)CbI9C*ISu08z$GX&Op*~Q4&>9$-9=d3 zZH(RB-0GKLPJ_7D<_8K5lVpU71Nk&_cV0FYcbi~$H}CgCnA1?)i{wreahkfj6xrRt zLV#%rG;f+>cf7!dNrT4m`6kGYhq~JgySqi$=AydWOav0hP#Px5h~U#Iu^1-81Dz+h zB(bO@IHNQzEeEq86z^RIa~8y{nV>QkSkgghFb9=SGdHJY!NQu=Ej2G0)3LH*?_ll$ T(~M4#;t)o|B$4=JJC*?eYXSA4 literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.lsx b/doc/LiveShowProject/CatasWatchProject.lsx new file mode 100644 index 0000000000000000000000000000000000000000..de1b114198d497651d6d755e56dbcfa876be8384 GIT binary patch literal 14 TcmZ4UmVvdLgMop835Xd08mEtn3-3cUz(RvmY-9an`#JBh6+F;Ap9Q* zBddb385yL21{Eczdb)&U=BDOk=B4_jR+I!Mr{<*^!xSNm28n<$A!C^sjCOa4a0ya?T literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.rtf b/doc/LiveShowProject/CatasWatchProject.rtf new file mode 100644 index 0000000..1740ec3 --- /dev/null +++ b/doc/LiveShowProject/CatasWatchProject.rtf @@ -0,0 +1,5 @@ +{\rtf1\ansi +{\fonttbl\f0\fnil Monospaced;} + +\par +} diff --git a/doc/LiveShowProject/CatasWatchProject.spi b/doc/LiveShowProject/CatasWatchProject.spi new file mode 100644 index 0000000000000000000000000000000000000000..a184f1b99a26337ce8f60aa29144414c8938b44a GIT binary patch literal 2024 zcmZ4UmVvd3fq{hq2$-Ol9Y`}W2stK~Waj4umn0UI1ZR|{rRAhDGB5}^Czd1@hbNXK zXZYrqrRJvQm0(i|G7b$eGVnr71nCROH^gBWsvf$HGDO7Nd|FSOsmoRgA-1ARif{`UsTyK#|YDpqd*2reOr* ztxqr}F5159#|Bu^V|c6zRz?#a8Rg>fkqN4g5XFE-;zksgGj8BT;bY+-#}UH^4%+$1 z*cgwGOi_IVDv%(lPW$L&6h||z^h4oe;h^~F*n6-Fn#7TbIUXOGq523^bwE;`-h)aM WM>8&xK;dKIp!jHY6j%jmJ^}#tI(|z4 literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.ssj b/doc/LiveShowProject/CatasWatchProject.ssj new file mode 100644 index 0000000000000000000000000000000000000000..e9143e6dfd1e873bd21025a6b49afa3224a39f63 GIT binary patch literal 22 UcmZ4UmVvcgfPsO535ekU04z2FC;$Ke literal 0 HcmV?d00001 diff --git a/doc/LiveShowProject/CatasWatchProject.uip b/doc/LiveShowProject/CatasWatchProject.uip new file mode 100644 index 0000000000000000000000000000000000000000..efec254dc4421d6b965b24d8b4cf82627f657637 GIT binary patch literal 150 zcmZ4UmVvc=0s{jB6A&{ps2PAju0?5TN@ZmUn1dh;%QFqi5-pPQbHVC~RZFZoprJ4T E0H>)U;s5{u literal 0 HcmV?d00001 diff --git a/main/watchMain.cpp b/main/watchMain.cpp index 059b10a..5c1bb8c 100644 --- a/main/watchMain.cpp +++ b/main/watchMain.cpp @@ -6,15 +6,18 @@ * @copyright Copyright (c) 2024 */ -// Conig-Key: -// -// -// +/* Watchface + 6/ + 5 / 1 + 4 2 + 3 +*/ struct { const char *syslogDest = "syslogDst"; // example: "172.16.16.10" - const char *mqttBroker = "mqttBroker"; // example: "172.16.17.62" + const char *mqttBroker = "mqttBroker"; // example: "172.16.16.10" const char *mqttPrefix = "mqttPrefix"; // example: "SomeTag" + const char *spitServer = "spitServer"; // example: "172.16.16.10" } ConfigKeys; // MQTT Topics @@ -27,6 +30,33 @@ struct { const char *changingPosition = /* / */ "watch/changingPosition"; } MqttTopics; +struct { + const char *expectedServer = ""; + struct { + const char *group = "CatasWatchMovement"; + const char *startShuffle = "ActionStartShuffle"; + const char *moveToX[6] = { + "ActionMoveTo1", + "ActionMoveTo2", + "ActionMoveTo3", + "ActionMoveTo4", + "ActionMoveTo5", + "ActionMoveTo6", + }; + } Provided; + struct { + const char *changingPos = "ChangingPositionScene"; + const char *inPosX[6] = { + "InPosition1Scene", + "InPosition2Scene", + "InPosition3Scene", + "InPosition4Scene", + "InPosition5Scene", + "InPosition6Scene", + }; + } Expected; +} SpitTypes; + // ToDo: // - MQTT Integration // - OTA @@ -36,8 +66,8 @@ struct { #include "watchMain.hpp" -string MyApp::s_ClientName = "CatasWatchDev"; -string MyApp::s_ProjectName = "CatastrphicProj"; +string ClientName = "CatasWatchDev"; +string ProjectName = "CatastrphicProj"; extern "C" { // This switch allows the ROS C-implementation to find this main void app_main(void); @@ -47,20 +77,29 @@ struct DeviceState { uint8_t minJumps{6}; uint8_t maxJumps{32}; uint8_t profile{}; - uint8_t restTime{}; + uint8_t shuffleRate{}; float speed = 1.0; // Rad/sec float accel = 1.0; // Rad/sec^2 Color color{0x80, 0x80, 0x80}; - uint8_t pictogram{}; // 0..5 active Pictogramm }; enum class MoveType { StepTo, + Demo, Shuffle, - Demo +}; +enum class ResponseType { + StepAt, + StartMoving, }; struct MoveCommand { MoveType type; + // 1..6 + uint8_t pos; +}; +struct WatchIndex { + ResponseType type; + // 1..6 uint8_t pos; }; struct PictoIllumCommand { @@ -68,6 +107,7 @@ struct PictoIllumCommand { }; static fos::Queue commandQueue(8); +static fos::Queue responseQueue(8); static fos::Queue pictoIllumQue(2); DeviceState activeState; @@ -245,7 +285,7 @@ static void UniverseCallback(const uint8_t *data, const uint16_t size) { Syslog::logv(Syslog::Severity::Debug, "Got DMX: r%0x g%0x b%0x i%0x m%i M%i p%i a%i w%i r%i", /* RGB*/ data[0], data[1], data[2], /*Intens*/ data[3], /* MinMaxJumps */ data[4], data[5], /*profile*/ data[6], /*accel/speed*/ data[7], data[8], - /*RestTime*/ data[9]); + /*shuffleRate*/ data[9]); float intens = (float)data[3] / UINT8_MAX; activeState.color = Color{ @@ -263,7 +303,7 @@ static void UniverseCallback(const uint8_t *data, const uint16_t size) { activeState.accel = (float)accel / 100 + 0.5; // min .5 / max 3 activeState.speed = (float)velo / 100 + 0.5; // min .5 / max 3 - activeState.restTime = data[9]; + activeState.shuffleRate = data[9]; } void moveToSubs(std::string data) { @@ -346,6 +386,7 @@ static void dmxSocketTask(int addrFamily) { } fos::Semaphore etherActive; +fos::Semaphore spitProjectFinish; /** Event handler for IP_EVENT_ETH_GOT_IP */ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, @@ -437,7 +478,7 @@ namespace Effect { }; const Macro macDemoFlicker = { - {64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF}, + {16, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF}, {32, 1, StateMachine::UpdateFlicker, 0xFF}, }; } @@ -472,14 +513,23 @@ void LightingTask() { processors[5].setEffect(Effect::macDark, &colorSource, 0); const std::array PictoEffects{ + Effect::macDemoPulse, // 1 Effect::macDemoPulse, Effect::macDemoPulse, Effect::macDemoPulse, - Effect::macDemoPulse, - Effect::macDemoPulse, - Effect::macStartFlicker}; + Effect::macStartFlicker, + Effect::macDemoPulse}; // 6 - uint8_t lastPicto = 0; + uint8_t lastPicto = 1; + + std::array startPoints{ + &(values[0][4]), // 1 + &(values[1][12]), + &(values[1][8]), + &(values[1][4]), + &(values[0][12]), + &(values[0][8]), // 6 + }; while (true) { auto onPos = pictoIllumQue.dequeue(0); @@ -504,14 +554,6 @@ void LightingTask() { } } - std::array startPoints{ - &(values[0][4]), - &(values[0][8]), - &(values[0][12]), - &(values[1][4]), - &(values[1][8]), - &(values[1][12]), - }; for (size_t i = 0; i < processors.size(); i++) { auto col = processors[i].tick(); auto sp = startPoints[i]; @@ -533,7 +575,7 @@ void MovementTask() { StepperDriverDrv8833::Pins stepperPins{ LEDC_TIMER_0, {LEDC_CHANNEL_0, LEDC_CHANNEL_1, LEDC_CHANNEL_2, LEDC_CHANNEL_3}, - {GPIO_NUM_23, GPIO_NUM_22, GPIO_NUM_21, GPIO_NUM_20}, + {GPIO_NUM_21, GPIO_NUM_20, GPIO_NUM_23, GPIO_NUM_22}, }; StepperDriverDrv8833 stepperDriver(stepperPins, MicroSteps, 0.25F); stepperDriver.setPos(0); @@ -549,25 +591,34 @@ void MovementTask() { StepperMotor stepper(stepperCfg, stepperDriver, initSens); + WatchMotor watch(stepper, motorSleep); + ESP_LOGI("Stepper", "Find Home"); stepper.findRef(); - // Illum 1 - pictoIllumQue.enqueue(std::make_unique(1)); + // Todo Set by User-Interface + for (size_t i = 0; i < 7; i++) { + stepper.fullStep(1); + fos::Task::delayMs(40); + } + (void)stepper.zeroPosition(); + while (!stepper.isIdle()) { + fos::Task::delayMs(40); + } + // watch.moveTo(1, ProfileGenerator::Unitform); + ESP_LOGI("Stepper", "Got to 1"); + // Illum 6 + pictoIllumQue.enqueue(std::make_unique(0)); - ESP_LOGI(TAG, "Fist Position is %f.2", stepper.getScaledPos() * 6); + ESP_LOGI(TAG, "Fist Position is %.2f", watch.getScaled()); fos::Task::delayMs(1000); - activeState.pictogram = 0; - while (true) { ESP_LOGD(TAG, "Waiting for command"); auto cmd = commandQueue.dequeue(); if (cmd->type == MoveType::StepTo) { if (stepper.isIdle()) { - pictoIllumQue.enqueue(std::make_unique(0)); int newPos = cmd->pos; if ((newPos >= 1) && (newPos <= 6)) { - auto idx = newPos - 1; Syslog::logv(Syslog::Severity::Informational, "Triggered movement to picto pos:%i ", newPos); } else { @@ -575,61 +626,368 @@ void MovementTask() { "Got invalid index for illuminated pictogram =%i ", newPos); continue; } - int delta = newPos - activeState.pictogram; - if (delta <= 0) { - delta += 6; + + int jumps = newPos - watch.getIndex(); + if (jumps <= 0) { + jumps += 6; } - delta = delta + (activeState.minJumps % 6) * 6; - if (delta < activeState.minJumps) { - delta += 6; + jumps = jumps + (activeState.minJumps % 6) * 6; + if (jumps < activeState.minJumps) { + jumps += 6; } Syslog::logv(Syslog::Severity::Notice, "Running Stepper by %i steps with prof=%i a=%.2f w=%.2f", - delta, activeState.profile, activeState.accel, activeState.speed); + jumps, activeState.profile, activeState.accel, activeState.speed); pictoIllumQue.enqueue(std::make_unique(0)); - stepper.moveBy(delta * std::numbers::pi / 3, - activeState.profile, activeState.accel, activeState.speed); + responseQueue.enqueue(std::make_unique(ResponseType::StartMoving, 0)); + watch.moveTo(newPos, activeState.profile); + pictoIllumQue.enqueue(std::make_unique(newPos)); - activeState.pictogram = newPos; + responseQueue.enqueue(std::make_unique(ResponseType::StepAt, newPos)); } } else if (cmd->type == MoveType::Demo) { - int i = 0; - while (i++ < 80) { - stepperDriver.step(1); - stepperDriver.getSubPos(); - fos::Task::delayMs(100); - } - ESP_LOGI("Stepper", "Find Home"); - stepper.findRef(); - activeState.pictogram = -1; - stepper.findRef(); - fos::Task::delayMs(1000); - for (size_t i = 0; i < 6; i++) { - stepper.moveBy(std::numbers::pi / 3); - while (!stepper.isIdle()) { - fos::Task::delayMs(100); + ESP_LOGI(TAG, "Running Demo"); + for (size_t i = ProfileGenerator::Smooth; i < ProfileGenerator::NumProfiles; i++) { + ESP_LOGI(TAG, "Running Profile %d ", i); + fos::Task::delayMs(1000); + int steps[3]{4, 2, 0}; + for (size_t j = 0; j < 3; j++) { + watch.moveTo(steps[j], i); + fos::Task::delayMs(1000); } - ESP_LOGI(TAG, "Position is %f.2", stepper.getScaledPos() * 6); } } else { fos::Task::delayMs(100); } } } +struct LocalSpitObj { + string iD; + string groupName; + string name; +}; +std::map ProvidedSpitActions; +std::map ExpectedObjects; + +void onServerEvent(SPIT_Client::ServerEvent event, const SAD_DetectedServer &p_DetectedServer) { + switch (event) { + case SPIT_Client::ServerEvent::Detect: + ESP_LOGI(TAG, "SERVER DETECTED"); + ESP_LOGI(TAG, " Name: %s", p_DetectedServer.getName().data()); + ESP_LOGI(TAG, " ID: %s", p_DetectedServer.getID().data()); + ESP_LOGI(TAG, " Computer: %s", p_DetectedServer.getComputerName().data()); + ESP_LOGI(TAG, " IP: %s", p_DetectedServer.getIP().data()); + ESP_LOGI(TAG, " Port: %s", p_DetectedServer.getPort().data()); + ESP_LOGI(TAG, " Addition: %s", p_DetectedServer.getAdditions().data()); + ESP_LOGI(TAG, " ClientIP: %s", p_DetectedServer.getClientIP().data()); + break; + case SPIT_Client::ServerEvent::Lost: + ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data()); + + break; + case SPIT_Client::ServerEvent::Changed: + ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data()); + break; + + default: + break; + } +} + +void onConnectionStatus(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, int p_ConnectionStatus, int p_OldConnectionStatus) { + ESP_LOGI(TAG, "MySPITApp: eventConnectionStatus %d ", p_ConnectionStatus); +} + +// The transfer of the server's SPITTypes and SPITObjects is finished. +void onProjectUpdate(SPIT_Client::ProjUpdate state, string projectId) { + + switch (state) { + case SPIT_Client::ProjUpdate::ServerLoaded: + ESP_LOGI(TAG, "eventProjectReport ID: %s ", projectId.data()); + break; + case SPIT_Client::ProjUpdate::StartTransfer: + ESP_LOGI(TAG, "eventStartProjectTransfer"); + break; + case SPIT_Client::ProjUpdate::EndTransfer: + ESP_LOGI(TAG, "eventEndProjectTransfer"); + spitProjectFinish.give(); + break; + case SPIT_Client::ProjUpdate::ServerClosed: + ESP_LOGI(TAG, "eventProjectClosed ID: %s", projectId.data()); + // If we don't save SPITServer's project specific information + // perhaps close all SPITObjects and RemoteSPITObjects to avoid conflicts, when the SPITServer loads a new project + // SPITObject::clearSPITObjects(); + // SPITObject::clearSPITObjectsRemote(); + break; + + default: + break; + } +} + +/** + * The SPITCLientInterface (implemented by this) will be asked to veto the SPITType while SPIT_Client.parseReportSPITType.
+ * @param p_ReportSPITType + * @return false = the SPITType is denied, true = the SPITType is accepted + */ +bool onCheckSpitTypeVeto(SPIT_Message::ReportSPITType *p_ReportSPITType) { + return true; // Bypass veto + + if (p_ReportSPITType == NULL) + return true; + SPITType *ptrSPITType; + ptrSPITType = SPITType::getSPITType(p_ReportSPITType->getID()); + + // Don't allow foreign SPITTypes + if (ptrSPITType == NULL) { + // ESP_LOGW(TAG, "ObjectVeto NoSpitType"); + return false; + } + if (ptrSPITType->getCreatedByClient() == false) { + // ESP_LOGW(TAG, "getCreatedByClient"); + return false; + } + return true; +} + +bool onCheckSpitObjectVeto(SPIT_Message::ReportSPITObject *p_ReportSPITObject) { + return true; // Bypass veto + + if (p_ReportSPITObject == NULL) + return true; + SPITType *ptrSPITType = SPITType::getSPITType(p_ReportSPITObject->getSPITTypeID()); + if (ptrSPITType == NULL) { + // ESP_LOGW(TAG, "ObjectVeto NoSpitObj"); + return false; + } + + // Don't allow SPITObjects which refers to a SPITType which is not created by this client - other SPITTypes cannot be handled here + if (ptrSPITType->getCreatedByClient() == false) { + // ESP_LOGW(TAG, "getCreatedByClient"); + return false; + } + SPITObject *ptrSPITObject = SPITObject::getSPITObject(p_ReportSPITObject->getID()); + // Don't allow foreign SPITTypes + if (ptrSPITObject == NULL) { + // ESP_LOGE(TAG, "Unknown ID"); + return false; + } + + return true; +} + +// Called when the server has created, loaded, changed or deleted a SPITType. +// May also occur when the server confirms a SPITType created or changed by the client. +void onSpitType(SPIT_Client::ObjectEvent event, const SPITType &p_SPITType) { + if (event == SPIT_Client::ObjectEvent::Created) { + // Whenever you provide an action for this SPITType take this over in your code. + // call _SpitClient.setActionSPITType(p_SPITType.getID(), true); + ESP_LOGI(TAG, "NEW SPIT-Type ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed()); + } else if (event == SPIT_Client::ObjectEvent::Changed) { + ESP_LOGI(TAG, "SPIT-Type CHANGED ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed()); + } else if (event == SPIT_Client::ObjectEvent::Deleted) { + ESP_LOGI(TAG, "SPIT-Type Removed ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data()); + } +} + +/** + * Called when the server has created or changed a Remote SPITType. + * Remote SPITType are used in Remote SPITObjects. A Remote SPITObject is used to remote control the SPITServer. + * @param p_New true = server created a new SPITType / false = server changed a existing SPITType + */ +void onSpitTypeRemote(SPIT_Client::ObjectEvent event, const SPITType &p_SPITType) { + if (event == SPIT_Client::ObjectEvent::Created) { + ESP_LOGI(TAG, "NEW SPIT-REMOTE-Type ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed()); + auto typeName = p_SPITType.getName(); + if (ExpectedObjects.contains(typeName)) { + ExpectedObjects[typeName] = p_SPITType.getID(); + } + } else if (event == SPIT_Client::ObjectEvent::Changed) { + // we had to inform all Remote SPITObjects using the p_SPITType + // perhaps the SPITObject uses information from the SPITType + SPITObject *ptrSPITObject; + int intSPITObjectCount; + intSPITObjectCount = SPITObject::getSPITObjectRemoteCount(); + for (int intObject = 0; intObject < intSPITObjectCount; intObject++) { + ptrSPITObject = SPITObject::getSPITObjectRemote(intObject); + if (ptrSPITObject == NULL) + continue; + if (ptrSPITObject->getSPITTypeID() == p_SPITType.getID()) { + // call ecentSPITObjectRemote + // onSpitObjectRemote(SPIT_Client::ObjectEvent::Changed, p_SPITType, *ptrSPITObject); + } + } + ESP_LOGI(TAG, "SPIT-REMOTE-Type CHANGED ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed()); + } else if (event == SPIT_Client::ObjectEvent::Deleted) { + ESP_LOGD(TAG, "SPIT-REMOTE-Type Removed ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data()); + } +} + +/** + * Called when the server has created, loaded or changed a SPITObject. + * May also occur when the server confirms a SPITObject created by the client, what the client should never do!!. + * false = server changed a existing SPITObject + * @param p_SPITType a reference to a copy of the associated SPITType instance. + * @param p_SPITObject a reference to a copy of the SPITObject instance. + */ +void onSpitObject(SPIT_Client::ObjectEvent event, const SPITType &p_SPITType, const SPITObject &p_SPITObject) { + if (event == SPIT_Client::ObjectEvent::Created) { + ESP_LOGI(TAG, "NEW SPIT-Object ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data()); + // check your actions + // Whenever you provide an action for this SPITObject take this over in your code. + // call _SpitClient.setActionSPITObject(p_SPITObject.getID(), true); + + // for our little excample as described in loadClientProject: + // We have only actions for SPITTypes - means every SPITObject with the associated "Actionx"-SPITTypes will trigger the action when it is played + //-> no need to do something here, because setActionSPITType has been set prior and the SPITObject will automatically inherits this + // SPITObjects with other SPITTypes asscciated will trigger no actions + + } else if (event == SPIT_Client::ObjectEvent::Changed) { + ESP_LOGI(TAG, "SPIT-Object CHANGED ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data()); + } else if (event == SPIT_Client::ObjectEvent::Deleted) { + ESP_LOGD(TAG, "SPIT-Object Removed ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data()); + // Check your actions + // take the removal of the SPITObject over in your code + + // CAUTION: Deleted SPITObjects can be added later again (perhaps per UNDO on the SPITServer) + //-> don't remove your assigned action immediately - keep it to reassign it later + } +} +/** + * Called when the server has created or changed a Remote SPITObject. + * A Remote SPITObject is used to remote control the SPITServer. + * @param p_New true = server created a new remote SPITObject + * false = server changed a existing remote SPITObject + * @param p_SPITType a reference to a copy of the associated SPITType instance. + * @param p_SPITObject a reference to a copy of the SPITObject instance. + */ +void onSpitObjectRemote(SPIT_Client::ObjectEvent event, const SPITType &p_SPITType, const SPITObject &p_SPITObject) { + if (event == SPIT_Client::ObjectEvent::Created) { + ESP_LOGI(TAG, "NEW SPIT-REMOTE-Object ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data()); + // This is a remote SPITObject which can be used to remote control the server. + // If you want you can list this for later use + } else if (event == SPIT_Client::ObjectEvent::Changed) { + ESP_LOGI(TAG, "SPIT-REMOTE-Object CHANGED ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data()); + } else if (event == SPIT_Client::ObjectEvent::Deleted) { + ESP_LOGD(TAG, "SPIT-REMOTE-Object Removed ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data()); + // This is a remote SPITObject + // If you have listet this prior you should remove it from the list + } +} + +// SPITServer may use several methods for playing SPITObjects. +// e.g. liveSHOWsoftware has the timeline and jingles which plays objects, where the timeline the main player is. +// SPIT distinguishes between the different players. All eventPlay... functions contain the information which player plays the SPIT object. +void onPlay(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames) { + ESP_LOGD(TAG, "eventPlay Player: %s Runs: %d Time: %lld", p_PlayerName.data(), p_PlayerIsRunning, p_TimeFrames); + + switch (p_PlayerType) { + case SPIT_Client::PLAYERTYPE_MAIN: + // p_FrameTimes contains the position inside the server's project, we can use it like a timecode + // int intMilliseconds = (int)(((double)p_TimeFrames / (double)m_ServerFramesPerSecond) * 1000); + break; + case SPIT_Client::PLAYERTYPE_CONTINOUS: + // The olayer is playing only single Object sequences sometime during the project + break; + case SPIT_Client::PLAYERTYPE_DISCRETE: + // Only discrete values where submitted, e.g the fader position of remote faders. + break; + } +} + +/** + * Called when the SPITServer plays a SPITObject. For every played SPITObject one eventPlayObject is called. + * You can decide here which action should be done or not. + */ +void onPlaySpitType(string p_PlayerID, string spitTypeId, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value) { + // double doubleValue = ((double)p_PlayObject.getValue() / 1000000) * ((double)p_PlayObject.getValueFactor() / 1000000); + + ESP_LOGD(TAG, "eventPlayObject Player: %s is running: %d Object Started: %d Stopped: %d", p_PlayerID.data(), p_PlayerIsRunning, p_Started, p_Ended); + // ESP_LOGD(TAG, " SPITType: %s SPITObject: %s Position: %lld Value: %f\n", spitTypeId.data(), p_SPITObject.getName().data(), p_PlayObject.getFrameInside(), doubleValue); + ESP_LOGD(TAG, " SPITType: %s Value: %f\n", spitTypeId.data(), p_Value); + + if (!ProvidedSpitActions.contains(spitTypeId)) { + ESP_LOGE(TAG, "SPIT ID %s is not accepted", spitTypeId.c_str()); + return; + } + if (p_Started == true) { + auto command = ProvidedSpitActions[spitTypeId]; + ESP_LOGI(TAG, "Player: %s is running: %s Object", p_PlayerID.data(), spitTypeId.c_str()); + commandQueue.enqueue(std::make_unique(command)); + Syslog::logv(Syslog::Severity::Informational, "Got SPIT command for move ot : r%d", command.pos); + } +} + +/** + * Called when a remote SpitObject which value function is changed by the server. + * This allows the Client to adjust its display for the remote command. + * @param p_SPITType the assigned remote SPITType of p_SPITObject + * @param p_SPITObject the remote SPITObject which is changed + * @param p_FrameInsideObject can be discarded + * @param p_Value the new value + */ +void onPlayRemoteObjectStatus(const SPITType &p_SPITType, const SPITObject &p_SPITObject, long long p_FrameInsideObject, int p_Value) { + ESP_EARLY_LOGI(TAG, "eventPlayRemoteObjectStatus RemoteSPITType: %s RemoteSPITObject: %s Position: %lld Value: %d", p_SPITType.getName().data(), p_SPITObject.getName().data(), p_FrameInsideObject, p_Value); +} void SpitClientApp() { - ESP_LOGI(TAG, "Starting SPIT task"); - auto ptrMyApp = std::make_unique(); + ESP_LOGI(TAG, "Starting SPIT task"); + auto &provided = SpitTypes.Provided; + auto &expected = SpitTypes.Expected; + std::vector ProvidedObj; + ProvidedSpitActions[provided.startShuffle] = MoveCommand{.type = MoveType::Shuffle, .pos = 0}; + ProvidedObj.push_back(LocalSpitObj{.iD = provided.startShuffle, .groupName = provided.group, .name = provided.startShuffle}); + ExpectedObjects[expected.changingPos] = ""; + for (size_t i = 0; i < 6; i++) { + ProvidedObj.push_back(LocalSpitObj{.iD = provided.moveToX[i], .groupName = provided.group, .name = provided.moveToX[i]}); + ProvidedSpitActions[provided.moveToX[i]] = MoveCommand{.type = MoveType::StepTo, .pos = (uint8_t)(i + 1)}; + ExpectedObjects[expected.inPosX[i]] = ""; + } - // load a client project and start auto detection of SPITServers - ptrMyApp->init(); - - while (true) { - fos::Task::delayMs(10000); - ESP_LOGI(TAG, "Test LiveShow"); - ptrMyApp->testLiveShowRemote(); //This is an excample how to remote control the liveSHOWsoftware - } + SPIT_Client spitClient(ClientName, ProjectName, + { + .onServerEvent = onServerEvent, + .onConnectionStatus = onConnectionStatus, + .onProjectUpdate = onProjectUpdate, + .onSpitType = onSpitType, + .onSpitTypeRemote = onSpitTypeRemote, + .onSpitObject = onSpitObject, + .onSpitObjectRemote = onSpitObjectRemote, + .onPlay = onPlay, + .onPlaySpitType = onPlaySpitType, + .onPlayRemoteObjectStatus = onPlayRemoteObjectStatus, + .onCheckSpitTypeVeto = onCheckSpitTypeVeto, + .onCheckSpitObjectVeto = onCheckSpitObjectVeto, + }); + + for (auto &obj : ProvidedObj) { + SPITType *ptrSPITType1Fix = spitClient.createSPITTypeFixed(obj.iD, obj.groupName, obj.name, 0, 0); + spitClient.setActionSPITType(ptrSPITType1Fix->getID(), true); // should be executed whenever a SPITObject with this SPITType is played + } + spitClient.clientProjectLoaded(); + spitClient.startServerAutoDetect(); + + spitProjectFinish.take(); + string serverProjectID = spitClient.getServerProjectID(); + string serverProjectName = spitClient.getClientProjectName(); + int serverFramesPerSecond = spitClient.getServerFramesPerSecond(); // set when the server reports his project, see eventProjectReport + ESP_LOGI(TAG, "eventProjectReport ID: %s Name: %s FramesPerSecond: %d", serverProjectID.data(), serverProjectName.data(), serverFramesPerSecond); + + for (auto &&obj : ExpectedObjects) { + if (obj.second == "") { + ESP_LOGE(TAG, "No matching Remote ID for %s", obj.first.c_str()); + } + } + + while (true) { + auto res = responseQueue.dequeue(); + if (res->type == ResponseType::StartMoving) { + spitClient.sendRemoteObject(ExpectedObjects[expected.changingPos]); + } else if (res->type == ResponseType::StepAt) { + spitClient.sendRemoteObject(ExpectedObjects[expected.inPosX[res->pos - 1]]); + } + } } void app_main(void) { @@ -641,17 +999,18 @@ void app_main(void) { ESP_ERROR_CHECK(ret); initialize_ethernet(); NvsApi::init(); - static fos::Task lightingTask(LightingTask, "Lights", 0x4000uL); - static fos::Task movementTask(MovementTask, "Motor", 0x4000uL); + static fos::Task lightingTask(LightingTask, "Lights", 0x8000uL); + static fos::Task movementTask(MovementTask, "Motor", 0x8000uL); etherActive.take(); + fos::Task::delayMs(10000); ESP_LOGI(TAG, "Start net services"); static int ipVersion = AF_INET; static fos::TaskT telnetSocket(telnetSocketTask, ipVersion, "tcpServer", 4096); static fos::TaskT dmxNode(dmxSocketTask, ipVersion, "dmxNode", 4096); // static Task otaUpdate(SystemFunctions::OtaTaskEntry, "otaTask", 8192); - static fos::Task spit(SpitClientApp,"SpitClient"); + static fos::Task spit(SpitClientApp, "SpitClient"); auto &store = NvsApi::getInstance(); auto logger = store.getValue(ConfigKeys.syslogDest); diff --git a/main/watchMain.hpp b/main/watchMain.hpp index 09aee55..dba95a0 100644 --- a/main/watchMain.hpp +++ b/main/watchMain.hpp @@ -7,8 +7,9 @@ #pragma once -#include -#include +#include +#include +#include #include "sdkconfig.h" #include "esp_event.h" #include "esp_log.h" @@ -36,7 +37,7 @@ #include "Processor.hpp" #include "nvsFunctions.hpp" #include "mqttClient.hpp" -#include "MyApp.h" +#include "watchFace.hpp" // #include "esp_chip_info.h" // #include "esp_flash.h" @@ -51,4 +52,13 @@ // #include "systemFunctions.hpp" // #include // #include -// #include \ No newline at end of file +// #include + +#include "SAD_DetectedServer.hpp" +#include "SPITObject.h" +#include "SPITPlayer.h" +#include "SPITType.h" +#include "SPIT_Client.h" +#include +#include +#include diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt new file mode 100644 index 0000000..1cd72f3 --- /dev/null +++ b/test/integration/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS + "../../core/components" + "../../core/managed_components" + "../../components" + # "../../managed_components" +) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(INTEGRATION_TESTS_FW) + diff --git a/test/dependencies.lock b/test/integration/dependencies.lock similarity index 100% rename from test/dependencies.lock rename to test/integration/dependencies.lock diff --git a/test/integration/main/CMakeLists.txt b/test/integration/main/CMakeLists.txt new file mode 100644 index 0000000..39a435f --- /dev/null +++ b/test/integration/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "movementTests.cpp" + INCLUDE_DIRS ".") diff --git a/test/integration/main/movementTests.cpp b/test/integration/main/movementTests.cpp new file mode 100644 index 0000000..9fc745e --- /dev/null +++ b/test/integration/main/movementTests.cpp @@ -0,0 +1,322 @@ +/** + * @file watchMain.cpp + * @author Gustice + * @brief ChaosWatch Application + * + * @copyright Copyright (c) 2024 + */ + +/// NOTE: Create IDF shell navigate to directory ("test/integration") +// and run "idf.py -p COM9 flash monitor" + +#include "Processor.hpp" +#include "PwmExpanderPca9685.hpp" +#include "StepperDrv8833.hpp" +#include "Task.hpp" +#include "esp_event.h" +#include "esp_log.h" +#include "sdkconfig.h" +#include "stepperMotor.hpp" +#include "watchFace.hpp" +#include +#include +#include +#include + +/* Watchface Indicies + 6/ 5/ + 5 / 1 4 / 0 + 4 2 3 1 + 3 2 +*/ + +extern "C" { // This switch allows the ROS C-implementation to find this main +void app_main(void); +} + +static const char *TAG = "IT"; + +struct DeviceState { + uint8_t minJumps{6}; + uint8_t maxJumps{32}; + uint8_t profile{}; + uint8_t restTime{}; + float speed = 1.0; // Rad/sec + float accel = 1.0; // Rad/sec^2 + Color color{0x80, 0x80, 0x80}; + uint8_t pictogram{}; // 0..5 active Pictogramm +}; + +class IndexIllumination { + public: + IndexIllumination() + : master(I2C_NUM_0, /*sda=*/GPIO_NUM_10, /*scl=*/GPIO_NUM_11), + ledDriver1(master, /*iverted=*/false), + ledDriver2(master, /*iverted=*/false, 0x41), + pwmEnable(GPIO_NUM_1, GpioPort::Logic::Inverted), + RED{CRed.getColor()}, + GREEN{CGreen.getColor()}, + BLUE{CBlue.getColor()} { + pwmEnable.write(true); + clearColorData(); + syncToDevice(); + } + + void clearColorData() { + for (size_t i = 0; i < 2; i++) { + for (size_t j = 0; j < PmwExpanderPca9685::PwmChannels; j++) { + Values[i][j] = 0; + } + } + } + + void setColorOfIndexTo(uint8_t idx, Color::Rgbw color) { + if (idx >= 6) { + return; + } + auto sp = LedStartPoints[idx]; + sp[0] = (uint16_t)(color.white) << 5; + sp[1] = (uint16_t)(color.blue) << 5; + sp[2] = (uint16_t)(color.green) << 5; + sp[3] = (uint16_t)(color.red) << 5; + } + + void syncToDevice() { + ledDriver1.sendImage(Values[0]); + ledDriver2.sendImage(Values[1]); + } + + void flashAll(Color::Rgbw color, int duration = 200) { + clearColorData(); + for (size_t i = 0; i < 6; i++) { + setColorOfIndexTo(i, color); + } + syncToDevice(); + fos::Task::delayMs(duration); + clearColorData(); + syncToDevice(); + } + + private: + PmwExpanderPca9685::GrayValues Values[2]{}; + std::array LedStartPoints{ + &(Values[0][4]), // 1 + &(Values[1][12]), + &(Values[1][8]), + &(Values[1][4]), + &(Values[0][12]), + &(Values[0][8]), // 6 + }; + + I2cMaster master; + PmwExpanderPca9685 ledDriver1; + PmwExpanderPca9685 ledDriver2; + OutputPort pwmEnable; + const Color::Rgbw RED; + const Color::Rgbw GREEN; + const Color::Rgbw BLUE; +}; + +DeviceState activeState; + +void IndexColorSweep(IndexIllumination &illum) { + const auto RED = CRed.getColor(); + const auto GREEN = CGreen.getColor(); + const auto BLUE = CBlue.getColor(); + + illum.flashAll(RED); + fos::Task::delayMs(200); + illum.flashAll(GREEN); + fos::Task::delayMs(200); + illum.flashAll(BLUE); + fos::Task::delayMs(200); + + illum.clearColorData(); + illum.setColorOfIndexTo(0, GREEN); + illum.syncToDevice(); + fos::Task::delayMs(500); + + illum.clearColorData(); + illum.setColorOfIndexTo(0, RED); + illum.setColorOfIndexTo(1, GREEN); + illum.syncToDevice(); + fos::Task::delayMs(500); + + illum.clearColorData(); + illum.setColorOfIndexTo(1, RED); + illum.setColorOfIndexTo(2, GREEN); + illum.syncToDevice(); + fos::Task::delayMs(500); + + illum.clearColorData(); + illum.setColorOfIndexTo(2, RED); + illum.setColorOfIndexTo(3, GREEN); + illum.syncToDevice(); + fos::Task::delayMs(500); + + illum.clearColorData(); + illum.setColorOfIndexTo(3, RED); + illum.setColorOfIndexTo(4, GREEN); + illum.syncToDevice(); + fos::Task::delayMs(500); + + illum.clearColorData(); + illum.setColorOfIndexTo(4, RED); + illum.setColorOfIndexTo(5, GREEN); + illum.syncToDevice(); + fos::Task::delayMs(500); + + illum.clearColorData(); + illum.setColorOfIndexTo(5, RED); + illum.syncToDevice(); + fos::Task::delayMs(500); + + illum.clearColorData(); + illum.setColorOfIndexTo(0, GREEN); + illum.syncToDevice(); +} + +constexpr bool DoFlushAtBeginning = false; +constexpr bool DoFullTurns = false; +constexpr bool DoTurnSteps = false; +constexpr bool DoTurnProfiles = true; + +void testMovementTask() { + esp_log_level_set(TAG, ESP_LOG_DEBUG); + esp_log_level_set("STP", ESP_LOG_DEBUG); + ESP_LOGD(TAG, "Init Lights for signaling"); + + IndexIllumination illum; + + if constexpr (DoFlushAtBeginning) { + IndexColorSweep(illum); + } + const auto BLUE = CBlue.getColor(); + + ESP_LOGD(TAG, "Init Stepper"); + + constexpr int MicroSteps = 32; + constexpr float Intensity = 0.25; + constexpr float StepWidth = 1.8; + StepperDriverDrv8833::Pins stepperPins({LEDC_TIMER_0, + {LEDC_CHANNEL_0, LEDC_CHANNEL_1, LEDC_CHANNEL_2, LEDC_CHANNEL_3}, + {GPIO_NUM_21, GPIO_NUM_20, GPIO_NUM_23, GPIO_NUM_22}}); + StepperDriverDrv8833 stepperDriver(stepperPins, MicroSteps, Intensity); + StepperConfig stepperCfg(StepWidth, MicroSteps); + InputPort initSens(GPIO_NUM_18); + OutputPort motorSleep(GPIO_NUM_15, GpioPort::Logic::Inverted); + StepperMotor stepper(stepperCfg, stepperDriver, initSens); + + WatchMotor watch(stepper, motorSleep); + + /// + /// Full Turns with full steps + /// + if constexpr (DoFullTurns) { + ESP_LOGD(TAG, "Find Home"); + stepper.findRef(); + ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos()); + fos::Task::delayMs(2000); + + ESP_LOGD(TAG, "Make one turns with full steps"); + // stepper.setPos(0); + illum.flashAll(BLUE); + int i = 0; + + ESP_LOGD(TAG, "Position at begin is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6); + while (i++ < 200) { + stepper.fullStep(1); + fos::Task::delayMs(100); + ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6); + } + fos::Task::delayMs(2000); + + int spB = stepper.getSubPos(); + stepper.demoFullTurn(); + int spE = stepper.getSubPos(); + ESP_LOGD(TAG, "Fullsteps SubPos begin %d / end %d", spB, spE); + fos::Task::delayMs(2000); + + ESP_LOGD(TAG, "Position at begin is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6); + i = 0; + while (i++ < 64) { + stepper.step(1); + fos::Task::delayMs(100); + ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6); + } + } + + /// + /// Homing + /// + ESP_LOGD(TAG, "Find Home"); + stepper.findRef(); + ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos()); + for (size_t i = 0; i < 7; i++) { + stepper.fullStep(1); + fos::Task::delayMs(40); + } + illum.flashAll(BLUE); + fos::Task::delayMs(1000); + + auto ref = stepper.zeroPosition(); + ESP_LOGD(TAG, "Reference saved at %.2f ", ref); + ESP_LOGD(TAG, "Correct Home"); + + /// + /// Multiple Turns continuous + /// + if constexpr (DoTurnSteps) { + + ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos()); + fos::Task::delayMs(1000); + ESP_LOGI(TAG, "Move to each index multiple times"); + illum.flashAll(BLUE); + for (size_t i = 1; i <= 2 * 3; i++) { + watch.moveTo(3 * i); + ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6); + } + + ESP_LOGI(TAG, "Move to each index multiple times"); + illum.flashAll(BLUE); + for (size_t i = 1; i <= 6 * 3; i++) { + watch.moveTo(i); + ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6); + } + } + + /// + /// All other Profiles + /// + if constexpr (DoTurnProfiles) { + for (size_t i = ProfileGenerator::Smooth; i < ProfileGenerator::NumProfiles; i++) { + // for (size_t i = ProfileGenerator::JumpIn; i < ProfileGenerator::NumProfiles; i++) { // If only part is needed + ESP_LOGI(TAG, "Running Profile %d ", i); + ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos()); + fos::Task::delayMs(1000); + illum.flashAll(BLUE); + int steps[3]{4, 2, 0}; + for (size_t j = 0; j < 3; j++) { + watch.moveTo(steps[j], i); + ESP_LOGI(TAG, "Last position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6); + fos::Task::delayMs(1000); + } + } + } + + while (true) { + ESP_LOGI(TAG, "Finish"); + fos::Task::delayMs(60000); + } +} + +void app_main(void) { + ESP_LOGI(TAG, "Start Movement Integration Tests"); + + static fos::Task movementTest(testMovementTask, "Move", fos::Task::DefaultStackSize * 8); + + while (true) { + fos::Task::delayMs(5000); + // ESP_LOGI(TAG, "Finish"); + } +} diff --git a/test/integration/sdkconfig b/test/integration/sdkconfig new file mode 100644 index 0000000..7a210c2 --- /dev/null +++ b/test/integration/sdkconfig @@ -0,0 +1,2159 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) 5.3.0 Project Configuration +# +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_DEDICATED_GPIO_SUPPORTED=y +CONFIG_SOC_UART_SUPPORTED=y +CONFIG_SOC_GDMA_SUPPORTED=y +CONFIG_SOC_AHB_GDMA_SUPPORTED=y +CONFIG_SOC_GPTIMER_SUPPORTED=y +CONFIG_SOC_PCNT_SUPPORTED=y +CONFIG_SOC_MCPWM_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_ETM_SUPPORTED=y +CONFIG_SOC_PARLIO_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_IEEE802154_SUPPORTED=y +CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED=y +CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y +CONFIG_SOC_TEMP_SENSOR_SUPPORTED=y +CONFIG_SOC_PHY_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_SUPPORTS_SECURE_DL_MODE=y +CONFIG_SOC_ULP_SUPPORTED=y +CONFIG_SOC_LP_CORE_SUPPORTED=y +CONFIG_SOC_EFUSE_KEY_PURPOSE_FIELD=y +CONFIG_SOC_EFUSE_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_GPSPI_SUPPORTED=y +CONFIG_SOC_LEDC_SUPPORTED=y +CONFIG_SOC_I2C_SUPPORTED=y +CONFIG_SOC_SYSTIMER_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_HMAC_SUPPORTED=y +CONFIG_SOC_DIG_SIGN_SUPPORTED=y +CONFIG_SOC_ECC_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y +CONFIG_SOC_BOD_SUPPORTED=y +CONFIG_SOC_APM_SUPPORTED=y +CONFIG_SOC_PMU_SUPPORTED=y +CONFIG_SOC_PAU_SUPPORTED=y +CONFIG_SOC_LP_TIMER_SUPPORTED=y +CONFIG_SOC_LP_AON_SUPPORTED=y +CONFIG_SOC_LP_PERIPHERALS_SUPPORTED=y +CONFIG_SOC_LP_I2C_SUPPORTED=y +CONFIG_SOC_ULP_LP_UART_SUPPORTED=y +CONFIG_SOC_CLK_TREE_SUPPORTED=y +CONFIG_SOC_ASSIST_DEBUG_SUPPORTED=y +CONFIG_SOC_WDT_SUPPORTED=y +CONFIG_SOC_SPI_FLASH_SUPPORTED=y +CONFIG_SOC_RNG_SUPPORTED=y +CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y +CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y +CONFIG_SOC_MODEM_CLOCK_SUPPORTED=y +CONFIG_SOC_PM_SUPPORTED=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_AES_SUPPORT_DMA=y +CONFIG_SOC_AES_GDMA=y +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED=y +CONFIG_SOC_ADC_MONITOR_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=1 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=7 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=1 +CONFIG_SOC_ADC_PATT_LEN_MAX=8 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_IIR_FILTER_NUM=2 +CONFIG_SOC_ADC_DIGI_MONITOR_NUM=2 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=4 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=83333 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=611 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_CALIBRATION_V1_SUPPORTED=y +CONFIG_SOC_ADC_SELF_HW_CALI_SUPPORTED=y +CONFIG_SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED=y +CONFIG_SOC_ADC_TEMPERATURE_SHARE_INTR=y +CONFIG_SOC_ADC_SHARED_POWER=y +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED=y +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +CONFIG_SOC_CACHE_FREEZE_SUPPORTED=y +CONFIG_SOC_CPU_CORES_NUM=1 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FLEXIBLE_INTC=y +CONFIG_SOC_INT_PLIC_SUPPORTED=y +CONFIG_SOC_CPU_HAS_CSR_PC=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=4 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=4 +CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=0x80000000 +CONFIG_SOC_CPU_HAS_PMA=y +CONFIG_SOC_CPU_IDRAM_SPLIT_USING_PMP=y +CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=3072 +CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16 +CONFIG_SOC_DS_KEY_CHECK_MAX_WAIT_US=1100 +CONFIG_SOC_AHB_GDMA_VERSION=1 +CONFIG_SOC_GDMA_NUM_GROUPS_MAX=1 +CONFIG_SOC_GDMA_PAIRS_PER_GROUP_MAX=3 +CONFIG_SOC_GDMA_SUPPORT_ETM=y +CONFIG_SOC_GDMA_SUPPORT_SLEEP_RETENTION=y +CONFIG_SOC_ETM_GROUPS=1 +CONFIG_SOC_ETM_CHANNELS_PER_GROUP=50 +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=31 +CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER=y +CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM=8 +CONFIG_SOC_GPIO_SUPPORT_ETM=y +CONFIG_SOC_GPIO_SUPPORT_RTC_INDEPENDENT=y +CONFIG_SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP=y +CONFIG_SOC_LP_IO_CLOCK_IS_INDEPENDENT=y +CONFIG_SOC_GPIO_IN_RANGE_MAX=30 +CONFIG_SOC_GPIO_OUT_RANGE_MAX=30 +CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK=0 +CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT=8 +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x000000007FFFFF00 +CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y +CONFIG_SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP=y +CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y +CONFIG_SOC_CLOCKOUT_HAS_SOURCE_GATE=y +CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 +CONFIG_SOC_RTCIO_PIN_COUNT=8 +CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y +CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y +CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y +CONFIG_SOC_RTCIO_VALID_RTCIO_MASK=0xFF +CONFIG_SOC_DEDIC_GPIO_OUT_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_GPIO_IN_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_PERIPH_ALWAYS_ENABLE=y +CONFIG_SOC_I2C_NUM=2 +CONFIG_SOC_HP_I2C_NUM=1 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_CMD_REG_NUM=8 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_HW_FSM_RST=y +CONFIG_SOC_I2C_SUPPORT_HW_CLR_BUS=y +CONFIG_SOC_I2C_SUPPORT_XTAL=y +CONFIG_SOC_I2C_SUPPORT_RTC=y +CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST=y +CONFIG_SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH=y +CONFIG_SOC_LP_I2C_NUM=1 +CONFIG_SOC_LP_I2C_FIFO_LEN=16 +CONFIG_SOC_I2S_NUM=1 +CONFIG_SOC_I2S_HW_VERSION_2=y +CONFIG_SOC_I2S_SUPPORTS_XTAL=y +CONFIG_SOC_I2S_SUPPORTS_PLL_F160M=y +CONFIG_SOC_I2S_SUPPORTS_PCM=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_PDM_MAX_TX_LINES=2 +CONFIG_SOC_I2S_SUPPORTS_TDM=y +CONFIG_SOC_LEDC_SUPPORT_PLL_DIV_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_XTAL_CLOCK=y +CONFIG_SOC_LEDC_CHANNEL_NUM=6 +CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=20 +CONFIG_SOC_LEDC_SUPPORT_FADE_STOP=y +CONFIG_SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED=y +CONFIG_SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX=16 +CONFIG_SOC_LEDC_FADE_PARAMS_BIT_WIDTH=10 +CONFIG_SOC_MMU_PAGE_SIZE_CONFIGURABLE=y +CONFIG_SOC_MMU_PERIPH_NUM=1 +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=1 +CONFIG_SOC_MMU_DI_VADDR_SHARED=y +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_PCNT_GROUPS=1 +CONFIG_SOC_PCNT_UNITS_PER_GROUP=4 +CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 +CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 +CONFIG_SOC_PCNT_SUPPORT_RUNTIME_THRES_UPDATE=y +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=2 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=2 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=4 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=48 +CONFIG_SOC_RMT_SUPPORT_RX_PINGPONG=y +CONFIG_SOC_RMT_SUPPORT_RX_DEMODULATION=y +CONFIG_SOC_RMT_SUPPORT_TX_ASYNC_STOP=y +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_COUNT=y +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP=y +CONFIG_SOC_RMT_SUPPORT_TX_SYNCHRO=y +CONFIG_SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY=y +CONFIG_SOC_RMT_SUPPORT_XTAL=y +CONFIG_SOC_RMT_SUPPORT_RC_FAST=y +CONFIG_SOC_MCPWM_GROUPS=1 +CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 +CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 +CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 +CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y +CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 +CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 +CONFIG_SOC_MCPWM_SWSYNC_CAN_PROPAGATE=y +CONFIG_SOC_MCPWM_SUPPORT_ETM=y +CONFIG_SOC_MCPWM_CAPTURE_CLK_FROM_GROUP=y +CONFIG_SOC_PARLIO_GROUPS=1 +CONFIG_SOC_PARLIO_TX_UNITS_PER_GROUP=1 +CONFIG_SOC_PARLIO_RX_UNITS_PER_GROUP=1 +CONFIG_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH=16 +CONFIG_SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH=16 +CONFIG_SOC_PARLIO_TX_RX_SHARE_INTERRUPT=y +CONFIG_SOC_MPI_MEM_BLOCKS_NUM=4 +CONFIG_SOC_MPI_OPERATIONS_NUM=3 +CONFIG_SOC_RSA_MAX_BIT_LEN=3072 +CONFIG_SOC_SHA_DMA_MAX_BUFFER_SIZE=3968 +CONFIG_SOC_SHA_SUPPORT_DMA=y +CONFIG_SOC_SHA_SUPPORT_RESUME=y +CONFIG_SOC_SHA_GDMA=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA224=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SDM_GROUPS=1 +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=4 +CONFIG_SOC_SDM_CLK_SUPPORT_PLL_F80M=y +CONFIG_SOC_SDM_CLK_SUPPORT_XTAL=y +CONFIG_SOC_SPI_PERIPH_NUM=2 +CONFIG_SOC_SPI_MAX_CS_NUM=6 +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_SUPPORT_DDRCLK=y +CONFIG_SOC_SPI_SLAVE_SUPPORT_SEG_TRANS=y +CONFIG_SOC_SPI_SUPPORT_CD_SIG=y +CONFIG_SOC_SPI_SUPPORT_CONTINUOUS_TRANS=y +CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2=y +CONFIG_SOC_SPI_SUPPORT_CLK_XTAL=y +CONFIG_SOC_SPI_SUPPORT_CLK_PLL_F80M=y +CONFIG_SOC_SPI_SUPPORT_CLK_RC_FAST=y +CONFIG_SOC_SPI_SCT_SUPPORTED=y +CONFIG_SOC_SPI_SCT_REG_NUM=14 +CONFIG_SOC_SPI_SCT_BUFFER_NUM_MAX=y +CONFIG_SOC_SPI_SCT_CONF_BITLEN_MAX=0x3FFFA +CONFIG_SOC_MEMSPI_IS_INDEPENDENT=y +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=16 +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_RESUME=y +CONFIG_SOC_SPI_MEM_SUPPORT_IDLE_INTR=y +CONFIG_SOC_SPI_MEM_SUPPORT_SW_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_CHECK_SUS=y +CONFIG_SOC_SPI_MEM_SUPPORT_WRAP=y +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_SYSTIMER_COUNTER_NUM=2 +CONFIG_SOC_SYSTIMER_ALARM_NUM=3 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_LO=32 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_HI=20 +CONFIG_SOC_SYSTIMER_FIXED_DIVIDER=y +CONFIG_SOC_SYSTIMER_SUPPORT_RC_FAST=y +CONFIG_SOC_SYSTIMER_INT_LEVEL=y +CONFIG_SOC_SYSTIMER_ALARM_MISS_COMPENSATE=y +CONFIG_SOC_SYSTIMER_SUPPORT_ETM=y +CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32 +CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16 +CONFIG_SOC_TIMER_GROUPS=2 +CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=1 +CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=54 +CONFIG_SOC_TIMER_GROUP_SUPPORT_XTAL=y +CONFIG_SOC_TIMER_GROUP_SUPPORT_RC_FAST=y +CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=2 +CONFIG_SOC_TIMER_SUPPORT_ETM=y +CONFIG_SOC_TIMER_SUPPORT_SLEEP_RETENTION=y +CONFIG_SOC_MWDT_SUPPORT_XTAL=y +CONFIG_SOC_TWAI_CONTROLLER_NUM=2 +CONFIG_SOC_TWAI_CLK_SUPPORT_XTAL=y +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_BRP_MAX=32768 +CONFIG_SOC_TWAI_SUPPORTS_RX_STATUS=y +CONFIG_SOC_EFUSE_DIS_DOWNLOAD_ICACHE=y +CONFIG_SOC_EFUSE_DIS_PAD_JTAG=y +CONFIG_SOC_EFUSE_DIS_USB_JTAG=y +CONFIG_SOC_EFUSE_DIS_DIRECT_BOOT=y +CONFIG_SOC_EFUSE_SOFT_DIS_JTAG=y +CONFIG_SOC_EFUSE_DIS_ICACHE=y +CONFIG_SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK=y +CONFIG_SOC_SECURE_BOOT_V2_RSA=y +CONFIG_SOC_SECURE_BOOT_V2_ECC=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=3 +CONFIG_SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=64 +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES=y +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128=y +CONFIG_SOC_CRYPTO_DPA_PROTECTION_SUPPORTED=y +CONFIG_SOC_UART_NUM=3 +CONFIG_SOC_UART_HP_NUM=2 +CONFIG_SOC_UART_LP_NUM=1 +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_LP_UART_FIFO_LEN=16 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_UART_SUPPORT_PLL_F80M_CLK=y +CONFIG_SOC_UART_SUPPORT_RTC_CLK=y +CONFIG_SOC_UART_SUPPORT_XTAL_CLK=y +CONFIG_SOC_UART_SUPPORT_WAKEUP_INT=y +CONFIG_SOC_UART_HAS_LP_UART=y +CONFIG_SOC_UART_SUPPORT_FSM_TX_WAIT_SEND=y +CONFIG_SOC_COEX_HW_PTI=y +CONFIG_SOC_EXTERNAL_COEX_ADVANCE=y +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12 +CONFIG_SOC_PM_SUPPORT_WIFI_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_BEACON_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_BT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT1_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN=y +CONFIG_SOC_PM_SUPPORT_CPU_PD=y +CONFIG_SOC_PM_SUPPORT_MODEM_PD=y +CONFIG_SOC_PM_SUPPORT_XTAL32K_PD=y +CONFIG_SOC_PM_SUPPORT_RC32K_PD=y +CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y +CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y +CONFIG_SOC_PM_SUPPORT_TOP_PD=y +CONFIG_SOC_PM_SUPPORT_HP_AON_PD=y +CONFIG_SOC_PM_SUPPORT_MAC_BB_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y +CONFIG_SOC_PM_SUPPORT_PMU_MODEM_STATE=y +CONFIG_SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY=y +CONFIG_SOC_PM_CPU_RETENTION_BY_SW=y +CONFIG_SOC_PM_MODEM_RETENTION_BY_REGDMA=y +CONFIG_SOC_PM_RETENTION_HAS_CLOCK_BUG=y +CONFIG_SOC_PM_PAU_LINK_NUM=4 +CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y +CONFIG_SOC_MODEM_CLOCK_IS_INDEPENDENT=y +CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y +CONFIG_SOC_CLK_OSC_SLOW_SUPPORTED=y +CONFIG_SOC_CLK_RC32K_SUPPORTED=y +CONFIG_SOC_RCC_IS_INDEPENDENT=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL=y +CONFIG_SOC_TEMPERATURE_SENSOR_INTR_SUPPORT=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_ETM=y +CONFIG_SOC_RNG_CLOCK_IS_INDEPENDENT=y +CONFIG_SOC_WIFI_HW_TSF=y +CONFIG_SOC_WIFI_FTM_SUPPORT=y +CONFIG_SOC_WIFI_GCMP_SUPPORT=y +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_WIFI_HE_SUPPORT=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_ESP_NIMBLE_CONTROLLER=y +CONFIG_SOC_BLE_50_SUPPORTED=y +CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y +CONFIG_SOC_BLE_POWER_CONTROL_SUPPORTED=y +CONFIG_SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED=y +CONFIG_SOC_BLUFI_SUPPORTED=y +CONFIG_SOC_BLE_MULTI_CONN_OPTIMIZATION=y +CONFIG_SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND=y +CONFIG_SOC_PHY_COMBO_MODULE=y +CONFIG_SOC_CAPS_NO_RESET_BY_ANA_BOD=y +CONFIG_SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TOOLCHAIN="gcc" +CONFIG_IDF_TARGET_ARCH_RISCV=y +CONFIG_IDF_TARGET_ARCH="riscv" +CONFIG_IDF_TARGET="esp32c6" +CONFIG_IDF_INIT_VERSION="5.3.0" +CONFIG_IDF_TARGET_ESP32C6=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x000D + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# end of Build type + +# +# Bootloader config +# + +# +# Bootloader manager +# +CONFIG_BOOTLOADER_COMPILE_TIME_DATE=y +CONFIG_BOOTLOADER_PROJECT_VER=1 +# end of Bootloader manager + +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 + +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V2_RSA_SUPPORTED=y +CONFIG_SECURE_BOOT_V2_ECC_SUPPORTED=y +CONFIG_SECURE_BOOT_V2_PREFERRED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +CONFIG_SECURE_ROM_DL_MODE_ENABLED=y +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=9 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_UART_CLK_IS_XTAL=y +CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=3 +CONFIG_ESP_ROM_HAS_RETARGETABLE_LOCKING=y +CONFIG_ESP_ROM_GET_CLK_FREQ=y +CONFIG_ESP_ROM_HAS_RVFPLIB=y +CONFIG_ESP_ROM_HAS_HAL_WDT=y +CONFIG_ESP_ROM_HAS_HAL_SYSTIMER=y +CONFIG_ESP_ROM_HAS_HEAP_TLSF=y +CONFIG_ESP_ROM_TLSF_CHECK_PATCH=y +CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH=y +CONFIG_ESP_ROM_HAS_LAYOUT_TABLE=y +CONFIG_ESP_ROM_HAS_SPI_FLASH=y +CONFIG_ESP_ROM_HAS_REGI2C_BUG=y +CONFIG_ESP_ROM_HAS_NEWLIB=y +CONFIG_ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT=y +CONFIG_ESP_ROM_REV0_HAS_NO_ECDSA_INTERFACE=y +CONFIG_ESP_ROM_WDT_INIT_PATCH=y +CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE=y +CONFIG_ESP_ROM_RAM_APP_NEEDS_MMU_INIT=y +CONFIG_ESP_ROM_HAS_SW_FLOAT=y +CONFIG_ESP_ROM_USB_OTG_NUM=-1 +CONFIG_ESP_ROM_HAS_VERSION=y +CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y + +# +# Boot ROM Behavior +# +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT=y +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="8MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEBUG=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +# CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB is not set +CONFIG_COMPILER_FLOAT_LIB_FROM_RVFPLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set +# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set +# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +CONFIG_COMPILER_RT_LIB_GCCLIB=y +CONFIG_COMPILER_RT_LIB_NAME="gcc" +# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set +CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART1 is not set +# CONFIG_APPTRACE_DEST_UART2 is not set +CONFIG_APPTRACE_DEST_UART_NONE=y +CONFIG_APPTRACE_UART_TASK_PRIO=1 +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +CONFIG_BT_ALARM_MAX_NUM=50 +# end of Bluetooth + +# +# Console Library +# +# CONFIG_CONSOLE_SORTED_HELP is not set +# end of Console Library + +# +# Driver Configurations +# + +# +# TWAI Configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +# end of TWAI Configuration + +# +# Legacy ADC Driver Configuration +# +# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set + +# +# Legacy ADC Calibration Configuration +# +# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy ADC Calibration Configuration +# end of Legacy ADC Driver Configuration + +# +# Legacy MCPWM Driver Configurations +# +# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy MCPWM Driver Configurations + +# +# Legacy Timer Group Driver Configurations +# +# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy Timer Group Driver Configurations + +# +# Legacy RMT Driver Configurations +# +# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy RMT Driver Configurations + +# +# Legacy I2S Driver Configurations +# +# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy I2S Driver Configurations + +# +# Legacy PCNT Driver Configurations +# +# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy PCNT Driver Configurations + +# +# Legacy SDM Driver Configurations +# +# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy SDM Driver Configurations + +# +# Legacy Temperature Sensor Driver Configurations +# +# CONFIG_TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy Temperature Sensor Driver Configurations +# end of Driver Configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK is not set +# CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set +# CONFIG_ADC_ENABLE_DEBUG_LOG is not set +# end of ADC and ADC Calibration + +# +# Wireless Coexistence +# +CONFIG_ESP_COEX_ENABLED=y +CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y +# CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE is not set +# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set +# end of Wireless Coexistence + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# ESP-Driver:GPIO Configurations +# +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:GPIO Configurations + +# +# ESP-Driver:GPTimer Configurations +# +CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:GPTimer Configurations + +# +# ESP-Driver:I2C Configurations +# +# CONFIG_I2C_ISR_IRAM_SAFE is not set +# CONFIG_I2C_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:I2C Configurations + +# +# ESP-Driver:I2S Configurations +# +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:I2S Configurations + +# +# ESP-Driver:LEDC Configurations +# +# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:LEDC Configurations + +# +# ESP-Driver:MCPWM Configurations +# +# CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:MCPWM Configurations + +# +# ESP-Driver:Parallel IO Configurations +# +# CONFIG_PARLIO_ENABLE_DEBUG_LOG is not set +# CONFIG_PARLIO_ISR_IRAM_SAFE is not set +# end of ESP-Driver:Parallel IO Configurations + +# +# ESP-Driver:PCNT Configurations +# +# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_PCNT_ISR_IRAM_SAFE is not set +# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:PCNT Configurations + +# +# ESP-Driver:RMT Configurations +# +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:RMT Configurations + +# +# ESP-Driver:Sigma Delta Modulator Configurations +# +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:Sigma Delta Modulator Configurations + +# +# ESP-Driver:SPI Configurations +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of ESP-Driver:SPI Configurations + +# +# ESP-Driver:Temperature Sensor Configurations +# +# CONFIG_TEMP_SENSOR_ENABLE_DEBUG_LOG is not set +# CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE is not set +# end of ESP-Driver:Temperature Sensor Configurations + +# +# ESP-Driver:UART Configurations +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of ESP-Driver:UART Configurations + +# +# ESP-Driver:USB Serial/JTAG Configuration +# +CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y +# end of ESP-Driver:USB Serial/JTAG Configuration + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +CONFIG_ESP_GDBSTUB_ENABLED=y +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y +CONFIG_ESP_GDBSTUB_MAX_TASKS=32 +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# Chip revision +# +CONFIG_ESP32C6_REV_MIN_0=y +# CONFIG_ESP32C6_REV_MIN_1 is not set +CONFIG_ESP32C6_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 + +# +# Maximum Supported ESP32-C6 Revision (Rev v0.99) +# +CONFIG_ESP32C6_REV_MAX_FULL=99 +CONFIG_ESP_REV_MAX_FULL=99 +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_IEEE802154=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP32C6_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32C6_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32C6_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC is not set +# end of MAC Config + +# +# Sleep Config +# +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=0 +# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set +# CONFIG_ESP_SLEEP_DEBUG is not set +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_RC32K is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y +# end of Peripheral Control + +# +# ETM Configuration +# +# CONFIG_ETM_ENABLE_DEBUG_LOG is not set +# end of ETM Configuration + +# +# GDMA Configurations +# +CONFIG_GDMA_CTRL_FUNC_IN_IRAM=y +# CONFIG_GDMA_ISR_IRAM_SAFE is not set +# CONFIG_GDMA_ENABLE_DEBUG_LOG is not set +# end of GDMA Configurations + +# +# Main XTAL Config +# +CONFIG_XTAL_FREQ_40=y +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config + +# +# Crypto DPA Protection +# +CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP=y +CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL_LOW=y +# CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL_MEDIUM is not set +# CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL_HIGH is not set +CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL=1 +# end of Crypto DPA Protection + +CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y +# end of Hardware Settings + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y +# CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS is not set +# CONFIG_ESP_NETIF_L2_TAP is not set +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# end of ESP NETIF Adapter + +# +# Partition API Configuration +# +# end of Partition API Configuration + +# +# PHY +# +CONFIG_ESP_PHY_ENABLED=y +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# CONFIG_ESP_PHY_PLL_TRACK_DEBUG is not set +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +CONFIG_PM_SLP_DEFAULT_PARAMS_OPT=y +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +# CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP is not set +# end of Power Management + +# +# ESP PSRAM +# + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_120 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0 +CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y +# CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set + +# +# Memory protection +# +CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=y +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=7 +# end of Brownout Detector + +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +CONFIG_ESP_SYSTEM_HW_STACK_GUARD=y +CONFIG_ESP_SYSTEM_BBPLL_RECALIB=y +CONFIG_ESP_SYSTEM_HW_PC_RECORD=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +# end of IPC (Inter-Processor Call) + +# +# ESP Timer (High Resolution Timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set +CONFIG_ESP_TIMER_TASK_AFFINITY=0x0 +CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y +CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of ESP Timer (High Resolution Timer) + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_ENABLED=y +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# CONFIG_ESP_WIFI_CSI_ENABLED is not set +CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP_WIFI_TX_BA_WIN=6 +CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP_WIFI_RX_BA_WIN=6 +CONFIG_ESP_WIFI_NVS_ENABLED=y +CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP_WIFI_IRAM_OPT=y +CONFIG_ESP_WIFI_EXTRA_IRAM_OPT=y +CONFIG_ESP_WIFI_RX_IRAM_OPT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP_WIFI_ENABLE_SAE_PK=y +CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y +CONFIG_ESP_WIFI_SLP_IRAM_OPT=y +CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME=50 +CONFIG_ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME=10 +CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME=15 +# CONFIG_ESP_WIFI_FTM_ENABLE is not set +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set +CONFIG_ESP_WIFI_GMAC_SUPPORT=y +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y +CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT=y +# CONFIG_ESP_WIFI_WAPI_PSK is not set +# CONFIG_ESP_WIFI_SUITE_B_192 is not set +# CONFIG_ESP_WIFI_11KV_SUPPORT is not set +# CONFIG_ESP_WIFI_MBO_SUPPORT is not set +# CONFIG_ESP_WIFI_DPP_SUPPORT is not set +# CONFIG_ESP_WIFI_11R_SUPPORT is not set +# CONFIG_ESP_WIFI_WPS_SOFTAP_REGISTRAR is not set +# CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS is not set +# CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS is not set +CONFIG_ESP_WIFI_TX_HETB_QUEUE_NUM=3 + +# +# WPS Configuration Options +# +# CONFIG_ESP_WIFI_WPS_STRICT is not set +# CONFIG_ESP_WIFI_WPS_PASSPHRASE is not set +# end of WPS Configuration Options + +# CONFIG_ESP_WIFI_DEBUG_PRINT is not set +# CONFIG_ESP_WIFI_TESTING_OPTIONS is not set +CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT=y +# CONFIG_ESP_WIFI_ENT_FREE_DYNAMIC_BUFFER is not set +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +CONFIG_FATFS_VOLUME_COUNT=2 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +# CONFIG_FATFS_SECTOR_512 is not set +CONFIG_FATFS_SECTOR_4096=y +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +# CONFIG_FATFS_USE_FASTSEEK is not set +CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0 +# CONFIG_FATFS_IMMEDIATE_FSYNC is not set +# CONFIG_FATFS_USE_LABEL is not set +CONFIG_FATFS_LINK_LOCK=y +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +CONFIG_FREERTOS_UNICORE=y +CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" +# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set +CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y +CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y +# CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# end of Port + +CONFIG_FREERTOS_PORT=y +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y +CONFIG_FREERTOS_NUMBER_OF_CORES=1 +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +CONFIG_HAL_SYSTIMER_USE_ROM_IMPL=y +CONFIG_HAL_WDT_USE_ROM_IMPL=y +CONFIG_HAL_SPI_MASTER_FUNC_IN_IRAM=y +CONFIG_HAL_SPI_SLAVE_FUNC_IN_IRAM=y +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_USE_HOOKS is not set +# CONFIG_HEAP_TASK_TRACKING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +CONFIG_HEAP_TLSF_USE_ROM_IMPL=y +# end of Heap memory debugging + +# +# IEEE 802.15.4 +# +CONFIG_IEEE802154_ENABLED=y +CONFIG_IEEE802154_RX_BUFFER_SIZE=20 +# CONFIG_IEEE802154_CCA_CARRIER is not set +CONFIG_IEEE802154_CCA_ED=y +# CONFIG_IEEE802154_CCA_CARRIER_OR_ED is not set +# CONFIG_IEEE802154_CCA_CARRIER_AND_ED is not set +CONFIG_IEEE802154_CCA_MODE=1 +CONFIG_IEEE802154_CCA_THRESHOLD=-60 +CONFIG_IEEE802154_PENDING_TABLE_SIZE=20 +# CONFIG_IEEE802154_MULTI_PAN_ENABLE is not set +# CONFIG_IEEE802154_TIMING_OPTIMIZATION is not set +# CONFIG_IEEE802154_DEBUG is not set +# end of IEEE 802.15.4 + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +# CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT is not set +CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=4 +# CONFIG_LOG_MASTER_LEVEL is not set +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_ENABLE=y +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# CONFIG_LWIP_NETIF_API is not set +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +# CONFIG_LWIP_EXTRA_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_ND6=y +# CONFIG_LWIP_FORCE_ROUTER_FORWARDING is not set +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# CONFIG_LWIP_SO_RCVBUF is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP_DEFAULT_TTL=64 +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +CONFIG_LWIP_IP_REASS_MAX_PBUFS=10 +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +CONFIG_LWIP_DHCPS_STATIC_ENTRIES=y +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV4=y +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760 +CONFIG_LWIP_TCP_WND_DEFAULT=5760 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 +CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4 +# CONFIG_LWIP_TCP_SACK_OUT is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +CONFIG_LWIP_SNTP_STARTUP_DELAY=y +CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY=5000 +# end of SNTP + +# +# DNS +# +CONFIG_LWIP_DNS_MAX_SERVERS=3 +# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set +# end of DNS + +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE=y +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y +# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v3.x related +# +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +CONFIG_MBEDTLS_PKCS7_C=y +# end of mbedTLS v3.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +CONFIG_MBEDTLS_CMAC_C=y +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +CONFIG_MBEDTLS_AES_INTERRUPT_LEVEL=0 +CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI=y +CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y +CONFIG_MBEDTLS_MPI_INTERRUPT_LEVEL=0 +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_HARDWARE_ECC=y +CONFIG_MBEDTLS_ECC_OTHER_CURVES_SOFT_FALLBACK=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +# CONFIG_MBEDTLS_DHM_C is not set +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +CONFIG_MBEDTLS_ERROR_STRINGS=y +# end of mbedTLS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +# CONFIG_MQTT_PROTOCOL_5 is not set +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ENCRYPTION is not set +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY is not set +# end of NVS + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set + +# +# Thread Operational Dataset +# +CONFIG_OPENTHREAD_NETWORK_NAME="OpenThread-ESP" +CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX="fd00:db8:a0:0::/64" +CONFIG_OPENTHREAD_NETWORK_CHANNEL=15 +CONFIG_OPENTHREAD_NETWORK_PANID=0x1234 +CONFIG_OPENTHREAD_NETWORK_EXTPANID="dead00beef00cafe" +CONFIG_OPENTHREAD_NETWORK_MASTERKEY="00112233445566778899aabbccddeeff" +CONFIG_OPENTHREAD_NETWORK_PSKC="104810e2315100afd6bc9215a6bfac53" +# end of Thread Operational Dataset + +CONFIG_OPENTHREAD_XTAL_ACCURACY=130 +# CONFIG_OPENTHREAD_SPINEL_ONLY is not set +# CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE is not set + +# +# Thread Address Query Config +# +# end of Thread Address Query Config +# end of OpenThread + +# +# Protocomm +# +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# end of Protocomm + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# Main Flash configuration +# + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50 +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# CONFIG_SPI_FLASH_ROM_IMPL is not set +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_VENDOR_XMC_SUPPORTED=y +# CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_GD_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Ultra Low Power (ULP) Co-processor +# +# CONFIG_ULP_COPROC_ENABLED is not set + +# +# ULP Debugging Options +# +# end of ULP Debugging Options +# end of Ultra Low Power (ULP) Co-processor + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_VFS_SELECT_IN_RAM is not set +CONFIG_VFS_SUPPORT_TERMIOS=y +CONFIG_VFS_MAX_COUNT=8 + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set +# end of Wi-Fi Provisioning Manager + +# +# mDNS +# +CONFIG_MDNS_MAX_INTERFACES=3 +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_ACTION_QUEUE_LEN=16 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +# CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES is not set +# CONFIG_MDNS_ENABLE_DEBUG_PRINTS is not set +CONFIG_MDNS_ENABLE_CONSOLE_CLI=y +# CONFIG_MDNS_RESPOND_REVERSE_QUERIES is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y + +# +# MDNS Predefined interfaces +# +CONFIG_MDNS_PREDEF_NETIF_STA=y +CONFIG_MDNS_PREDEF_NETIF_AP=y +CONFIG_MDNS_PREDEF_NETIF_ETH=y +# end of MDNS Predefined interfaces +# end of mDNS + +# +# LittleFS +# +# CONFIG_LITTLEFS_SDMMC_SUPPORT is not set +CONFIG_LITTLEFS_MAX_PARTITIONS=3 +CONFIG_LITTLEFS_PAGE_SIZE=256 +CONFIG_LITTLEFS_OBJ_NAME_LEN=64 +CONFIG_LITTLEFS_READ_SIZE=128 +CONFIG_LITTLEFS_WRITE_SIZE=128 +CONFIG_LITTLEFS_LOOKAHEAD_SIZE=128 +CONFIG_LITTLEFS_CACHE_SIZE=512 +CONFIG_LITTLEFS_BLOCK_CYCLES=512 +CONFIG_LITTLEFS_USE_MTIME=y +# CONFIG_LITTLEFS_USE_ONLY_HASH is not set +# CONFIG_LITTLEFS_HUMAN_READABLE is not set +CONFIG_LITTLEFS_MTIME_USE_SECONDS=y +# CONFIG_LITTLEFS_MTIME_USE_NONCE is not set +# CONFIG_LITTLEFS_SPIFFS_COMPAT is not set +# CONFIG_LITTLEFS_FLUSH_FILE_EVERY_WRITE is not set +# CONFIG_LITTLEFS_FCNTL_GET_PATH is not set +# CONFIG_LITTLEFS_MULTIVERSION is not set +# CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE is not set +CONFIG_LITTLEFS_MALLOC_STRATEGY_DEFAULT=y +# CONFIG_LITTLEFS_MALLOC_STRATEGY_INTERNAL is not set +CONFIG_LITTLEFS_ASSERTS=y +# end of LittleFS +# end of Component config + +# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set + +# Deprecated options for backward compatibility +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +# CONFIG_NO_BLOBS is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +CONFIG_CXX_EXCEPTIONS=y +CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP_WIFI_SW_COEXIST_ENABLE=y +# CONFIG_EXTERNAL_COEX_ENABLE is not set +# CONFIG_ESP_WIFI_EXTERNAL_COEXIST_ENABLE is not set +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +CONFIG_GDBSTUB_SUPPORT_TASKS=y +CONFIG_GDBSTUB_MAX_TASKS=32 +# CONFIG_OTA_ALLOW_HTTP is not set +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_REDUCE_PHY_TX_POWER is not set +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +CONFIG_BROWNOUT_DET_LVL=7 +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +CONFIG_WPA_MBEDTLS_CRYPTO=y +CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5760 +CONFIG_TCP_WND_DEFAULT=5760 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options diff --git a/test/integration/sdkconfig.defaults b/test/integration/sdkconfig.defaults new file mode 100644 index 0000000..6ebada1 --- /dev/null +++ b/test/integration/sdkconfig.defaults @@ -0,0 +1,18 @@ +# +# Compiler options +# +CONFIG_COMPILER_CXX_EXCEPTIONS=y + +# +# Serial flasher config +# +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="8MB" + +# +# Log output +# +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y +CONFIG_LOG_MAXIMUM_LEVEL=4 diff --git a/test/unitOnHost/.vscode/settings.json b/test/unitOnHost/.vscode/settings.json new file mode 100644 index 0000000..7536b3f --- /dev/null +++ b/test/unitOnHost/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.cmakePath": "C:/msys64/usr/bin/cmake.exe" +} \ No newline at end of file diff --git a/utest/CMakeLists.txt b/test/unitOnHost/CMakeLists.txt similarity index 88% rename from utest/CMakeLists.txt rename to test/unitOnHost/CMakeLists.txt index 5fa8d11..197f034 100644 --- a/utest/CMakeLists.txt +++ b/test/unitOnHost/CMakeLists.txt @@ -20,7 +20,7 @@ project(UnitTests) find_package(doctest REQUIRED PATHS "/mingw64/lib/cmake") # target_link_libraries(${PROJECT_NAME} PRIVATE doctest::doctest) -addSubDirs_ofRoot("${CMAKE_CURRENT_LIST_DIR}/../components") +addSubDirs_ofRoot("${CMAKE_CURRENT_LIST_DIR}/../../components") diff --git a/utest/ReadMe.md b/test/unitOnHost/ReadMe.md similarity index 100% rename from utest/ReadMe.md rename to test/unitOnHost/ReadMe.md diff --git a/utest/test_core.cmake b/test/unitOnHost/test_core.cmake similarity index 100% rename from utest/test_core.cmake rename to test/unitOnHost/test_core.cmake diff --git a/test/CMakeLists.txt b/test/unitOnTarget/CMakeLists.txt similarity index 86% rename from test/CMakeLists.txt rename to test/unitOnTarget/CMakeLists.txt index ca1bb93..0f78a91 100644 --- a/test/CMakeLists.txt +++ b/test/unitOnTarget/CMakeLists.txt @@ -3,7 +3,10 @@ cmake_minimum_required(VERSION 3.16) # Include the components directory of the main application: # -set(EXTRA_COMPONENT_DIRS "../components ../managed_components") +set(EXTRA_COMPONENT_DIRS + "../../components" + # "../../managed_components" +) # Set the components to include the tests for. # This can be overriden from CMake cache: diff --git a/test/ReadMe.md b/test/unitOnTarget/ReadMe.md similarity index 100% rename from test/ReadMe.md rename to test/unitOnTarget/ReadMe.md diff --git a/test/unitOnTarget/dependencies.lock b/test/unitOnTarget/dependencies.lock new file mode 100644 index 0000000..68be0f1 --- /dev/null +++ b/test/unitOnTarget/dependencies.lock @@ -0,0 +1,9 @@ +dependencies: + idf: + component_hash: null + source: + type: idf + version: 5.3.0 +manifest_hash: c4f4ec05313d427eb56c633f78ce213e553379725bf2af3c511665f930571beb +target: esp32c6 +version: 1.0.0 diff --git a/test/main/CMakeLists.txt b/test/unitOnTarget/main/CMakeLists.txt similarity index 100% rename from test/main/CMakeLists.txt rename to test/unitOnTarget/main/CMakeLists.txt diff --git a/test/main/unitTest.cpp b/test/unitOnTarget/main/unitTest.cpp similarity index 100% rename from test/main/unitTest.cpp rename to test/unitOnTarget/main/unitTest.cpp diff --git a/test/sdkconfig b/test/unitOnTarget/sdkconfig similarity index 100% rename from test/sdkconfig rename to test/unitOnTarget/sdkconfig diff --git a/test/sdkconfig.defaults b/test/unitOnTarget/sdkconfig.defaults similarity index 100% rename from test/sdkconfig.defaults rename to test/unitOnTarget/sdkconfig.defaults