19 Commits

Author SHA1 Message Date
gustice 348a1a1e14 tests: Make more tests run 2026-01-06 17:01:31 +01:00
gustice 118291f8ab refactor: Tidy up SPIT 2 2026-01-05 19:53:30 +01:00
gustice 4a97988227 refactor: Tidy up SPIT 2025-11-15 20:57:26 +01:00
gustice 7aec14cbb9 feat: shuffle mode 2025-11-15 18:19:06 +01:00
gustice 331258692b temp 2025-11-15 00:48:13 +01:00
gustice 0ecd846183 fix: Spit working again also with linux 2025-11-14 23:29:44 +01:00
gustice 66140ea823 refactor: Working on SPIT yet again 2025-11-14 21:31:10 +01:00
gustice c01439dc05 proj: cleaning project files 2025-11-13 21:07:37 +01:00
gustice 20d1ca79b8 cli improvement 2025-11-13 00:39:48 +01:00
gustice bd4a593963 feat: Full featured Telnet implementation (not integrated) 2025-11-13 00:24:43 +01:00
gustice 3afaf3848f refactor: Heavy refactoring of SPIT 2025-11-11 14:24:34 +01:00
gustice a18ddf2cb1 feat: Switching to mqtt 2025-11-10 20:52:14 +01:00
gustice de9ff6f807 refactor repo 2025-11-10 15:34:07 +01:00
gustice f064794499 refactoring message 2025-11-10 10:43:13 +01:00
gustice 598f1262d7 proj: refinement 2025-11-09 19:04:54 +01:00
gustice 889523f0c8 temp 2025-10-30 17:38:36 +01:00
gustice 8f0dbd4cbd proj: switching to Linux 2025-07-06 11:00:34 +02:00
gustice 9ebbedb04a refactor: Heavy refactoring to modern code style 2025-04-08 23:50:09 +02:00
gustice 04a8904cbe refactor/bringup: Bringup full project
moving SPIT-App parts to main app
LiveShowDemoProject added
Debugging motor movements
2025-04-08 23:49:05 +02:00
125 changed files with 11810 additions and 10754 deletions
+2
View File
@@ -0,0 +1,2 @@
CompileFlags:
Remove: [-f*, -m*]
+2 -1
View File
@@ -1 +1,2 @@
build*
build*
.build*
+22 -23
View File
@@ -1,25 +1,24 @@
{
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "${config:idf.toolsPathWin}\\tools\\riscv32-esp-elf\\esp-13.2.0_20240530\\riscv32-esp-elf\\bin\\riscv32-esp-elf-gcc.exe",
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
"includePath": [
"${config:idf.espIdfPath}/components/**",
"${config:idf.espIdfPathWin}/components/**",
"${workspaceFolder}/**",
"${workspaceFolder}/core/**"
],
"browse": {
"path": [
"${config:idf.espIdfPath}/components",
"${config:idf.espIdfPathWin}/components",
"${workspaceFolder}",
"${workspaceFolder}/core"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
"configurations": [
{
"name": "ESP-IDF",
"compileCommands": "/home/gustice/jobs/projects/Proj_Zwickau_waitingRoom/FW_X_WatchController/build/compile_commands.json",
"includePath": [
"${config:idf.espIdfPath}/components/**",
"${config:idf.espIdfPathWin}/components/**",
"${workspaceFolder}/**",
"${workspaceFolder}/core/**"
],
"browse": {
"path": [
"${config:idf.espIdfPath}/components",
"${config:idf.espIdfPathWin}/components",
"${workspaceFolder}",
"${workspaceFolder}/core"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
}
+30
View File
@@ -0,0 +1,30 @@
[
{
"name": "GCC 14.3.0 x86_64-linux-gnu",
"compilers": {
"C": "/usr/bin/gcc-14",
"CXX": "/usr/bin/g++-14"
},
"isTrusted": true
},
{
"name": "Host GCC",
"description": "GCC 15.2.0 x86_64-linux-gnu",
"compilers": {
"C": "/usr/bin/gcc",
"CXX": "/usr/bin/g++"
},
"cmakeSettings": {
"TgtEnv": "Host"
},
"isTrusted": true
},
{
"name": "Esp32 Tests",
"environmentSetupScript": "/home/gustice/esp/v5.4.1/esp-idf/export.sh",
"cmakeSettings": {
"TgtEnv": "Target"
},
"isTrusted": true
}
]
+56 -17
View File
@@ -1,19 +1,58 @@
{
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -2, NamespaceIndentation: All, FixNamespaceComments: false }",
"C_Cpp.intelliSenseEngine": "default",
"idf.customExtraVars": {
"OPENOCD_SCRIPTS": "C:\\Tools\\ESP\\tools\\openocd-esp32\\v0.12.0-esp32-20240318/openocd-esp32/share/openocd/scripts",
"IDF_CCACHE_ENABLE": "1",
"ESP_ROM_ELF_DIR": "C:\\Tools\\ESP\\tools\\esp-rom-elfs\\20240305/"
},
"idf.espIdfPathWin": "C:\\Tools\\ESP-IDF\\v5.3\\esp-idf",
"idf.openOcdConfigs": [
"board/esp32c6-builtin.cfg"
],
"idf.portWin": "COM9",
"idf.toolsPathWin": "C:\\Tools\\ESP",
"idf.flashType": "UART",
"C_Cpp.autoAddFileAssociations": false,
"project.deviceIp": "172.16.17.56"
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -2}",
"C_Cpp.intelliSenseEngine": "default",
"idf.customExtraVars": {
"OPENOCD_SCRIPTS": "/home/gustice/tools/.espressif/tools/openocd-esp32/v0.12.0-esp32-20241016/openocd-esp32/share/openocd/scripts/",
"IDF_CCACHE_ENABLE": "1",
"ESP_ROM_ELF_DIR": "/home/gustice/tools/.espressif/tools/esp-rom-elfs/20241011/"
},
"idf.openOcdConfigs": [
"board/esp32c6-builtin.cfg"
],
"idf.flashType": "UART",
"C_Cpp.autoAddFileAssociations": false,
"project.deviceIp": "172.16.17.56",
"sonarlint.pathToCompileCommands": "${workspaceFolder}\\build\\compile_commands.json",
"idf.port": "/dev/ttyACM0",
"cmake.showSystemKits": false,
"cmake.defaultVariants": {
"buildType": {
"default": "debug",
"description": "The build type.",
"choices": {
"debug": {
"short": "Debug",
"long": "Disable optimizations - include debug information.",
"buildType": "Debug"
},
"release": {
"short": "Release",
"long": "Optimize for speed - exclude debug information.",
"buildType": "Release"
}
}
}
},
"clangd.path": "/home/gustice/.espressif/tools/esp-clang/esp-18.1.2_20240912/esp-clang/bin/clangd",
"clangd.arguments": [
"--background-index",
"--query-driver=/home/gustice/.espressif/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
"--compile-commands-dir=/home/gustice/jobs/projects/Proj_Zwickau_waitingRoom/FW_X_WatchController/build"
],
"cmake.debugConfig": {
"setupCommands": [
{
"description": "Skip standard library code",
"text": "skip file /usr/include/*"
},
{
"description": "Skip GCC internal code",
"text": "skip file /usr/lib/gcc/*"
},
{
"description": "Skip std namespace",
"text": "skip namespace std"
}
]
}
}
+1 -265
View File
@@ -1,271 +1,7 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build - Build project",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py build",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py build",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"autoDetect",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Set ESP-IDF Target",
"type": "shell",
"command": "${command:espIdf.setTarget}",
"problemMatcher": {
"owner": "cpp",
"fileLocation": [
"autoDetect",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "Clean - Clean the project",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py fullclean",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py fullclean",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"autoDetect",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
]
},
{
"label": "Flash - Flash the device",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} -b ${config:idf.flashBaudRate} flash",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py flash -p ${config:idf.portWin} -b ${config:idf.flashBaudRate}",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"autoDetect",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
]
},
{
"label": "Monitor: Start the monitor",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} monitor",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py -p ${config:idf.portWin} monitor",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"autoDetect",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
],
"dependsOn": "Flash - Flash the device"
},
{
"label": "OpenOCD: Start openOCD",
"type": "shell",
"presentation": {
"echo": true,
"reveal": "never",
"focus": false,
"panel": "new"
},
"command": "openocd -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}",
"windows": {
"command": "openocd.exe -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": [
"autoDetect",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "adapter",
"type": "shell",
"command": "${config:idf.pythonBinPath}",
"isBackground": true,
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}",
"PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter"
}
},
"problemMatcher": {
"background": {
"beginsPattern": "\bDEBUG_ADAPTER_STARTED\b",
"endsPattern": "DEBUG_ADAPTER_READY2CONNECT",
"activeOnStart": true
},
"pattern": {
"regexp": "(\\d+)-(\\d+)-(\\d+)\\s(\\d+):(\\d+):(\\d+),(\\d+)\\s-(.+)\\s(ERROR)",
"file": 8,
"line": 2,
"column": 3,
"severity": 4,
"message": 9
}
},
"args": [
"${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter_main.py",
"-e",
"${workspaceFolder}/build/${command:espIdf.getProjectName}.elf",
"-s",
"$OPENOCD_SCRIPTS",
"-dn",
"esp32",
"-om",
"connect_to_instance",
"-t",
"xtensa-esp32-elf-"
],
"windows": {
"command": "${config:idf.pythonBinPathWin}",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}",
"PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter"
}
}
}
},
{
"label": "Start TeraTerm Telnet",
"type": "shell",
"command": "C:/Program Files (x86)/teraterm5/ttermpro.exe",
"args": [
"telnet://${config:project.deviceIp}:23",
"/W=\"Device-Platform\"",
"/T=1",
"/F=\"${workspaceFolder}/core/.configs/TelnetTeraTerm.INI\""
],
"problemMatcher": []
}
]
}
+22 -7
View File
@@ -1,9 +1,24 @@
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS
"core/components"
"core/managed_components"
)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(X_WatchController_FW)
if(TgtEnv STREQUAL "Host")
message("Using Host-Branch")
enable_testing()
add_subdirectory("test/unitOnHost")
elseif(TgtEnv STREQUAL "Target")
# add_subdirectory("test/unitOnTarget")
add_subdirectory("core/test/unitOnTarget")
else()
message("Using ESP-Branch")
if(DEFINED ENV{UNIT_TESTS})
message("Using UnitTestFrame")
add_subdirectory("test/unitOnTarget" ${CMAKE_BINARY_DIR}/main)
else()
set(EXTRA_COMPONENT_DIRS
"core/components"
"core/managed_components"
)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
message("Using Main App")
project(WatchController)
endif()
endif()
+1 -1
View File
@@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "src" "src/esp"
INCLUDE_DIRS "include"
REQUIRES esp_system esp_netif freeRtosApi
REQUIRES esp_system esp_netif freeRtosApi sockets
)
+11
View File
@@ -0,0 +1,11 @@
# SPIT
Original implementation from Hag seem to be not suited for Embedded devices.
- Supports IPv4 only
- Reduced Threads to a minimum
- Then reduced usage of Mutexes to a minimum
- Reduced Sockets to a minimum
- Introduced containers and removed plain new and delete
- Removed UUID-Generation because SPIT-Types never change on embedded devices
- Callbacks instead of interfaces where suitable
Binary file not shown.
-37
View File
@@ -1,37 +0,0 @@
#pragma once
#include <string>
using namespace std;
class I_SAD_Client {
public:
/**
* If a new server was found by the ServerAutoDetect mechanism, this function is called.<br>
* To do so the SAD_Client ServerAutoDetect has to be startet - see SAD_Client::startServerAutoDetect.<br>
* If a server can be reached via several IP addresses, the IP address is selected according to the following preference:<br>
* 1.) If a loopback address is available, it is used.<br>
* 2.) If an IP4 address is available, it is used.<br>
* 3.) In the other cases the IP6 address is used.<br>
* @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.<br>
* @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;
};
-85
View File
@@ -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 <chrono>
#include <string>
#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 */
@@ -1,138 +0,0 @@
#pragma once
#include "I_SAD_Client.hpp"
#include <string>
#include <unordered_map>
#include <list>
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);
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; }
//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<string, SAD_DetectedServer*> 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<br>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);
/**
* Returns a reference of the DetectedServer with the id p_ServerID.<br>
* 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;
}
throw new exception();
}
}
};
-176
View File
@@ -1,176 +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: SPITObject.h
* Author: Hagi
*
* Created on 9. April 2019, 12:11
*/
#ifndef SPITOBJECT_H
#define SPITOBJECT_H
#include "SPIT_Message.h"
#include "SPITType.h"
#include <string>
#include <unordered_map>
using namespace std;
class SPITObjectListener;
class SPITObject {
private:
static unordered_map<string, SPITObject*> s_SPITObjects;
static unordered_map<string, SPITObject*> 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();
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<br>
* 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.<br>
* This is used when an action is associated with a SPITType. <br>
* 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.<br>
* @return true = the user has asscociated an action with this SPITObject or <br>
* 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 */
-96
View File
@@ -1,96 +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: SPITPLayer.h
* Author: Hagi
*
* Created on 30. April 2019, 11:44
*/
#ifndef SPITPLAYER_H
#define SPITPLAYER_H
#include "SPITObject.h"
#include <unordered_map>
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<string, SPITPlayer*> 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<string, PlaySPITType*>* 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<string, PlaySPITType*> m_PlaySPITTypes;
bool m_IsRunning;
long long m_TimeFrames;
};
#endif /* SPITPLAYER_H */
-167
View File
@@ -1,167 +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.
*/
/*
* SPITSocket is the base class for WindowsSocket, UnixSocket,.
* Used by SPIT_Client and SAD_Client.
* File: SPITSocket.h
* Author: Hagi
*
* Created on 12. April 2019, 15:40
*/
#ifndef SPITSOCKET_H
#define SPITSOCKET_H
#include <string>
#include "esp_netif.h"
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "Task.hpp"
#include "esp_log.h"
using namespace std;
/** Returns an guid */
string createGUID();
/** Returns the name of the client's host computer*/
string getClientHostName();
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;
/**
* 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;
return inet_ntoa(broadcast);
}
};
const IPAddress mOwnIp;
static IPAddress getAdaptersInfo();
bool createSocket_UDP();
static const int INVALID_SOCKET = -1;
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();
}
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_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;
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 */
-142
View File
@@ -1,142 +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: SPITType.h
* Author: Hagi
*
* Created on 8. April 2019, 08:40
*/
#ifndef SPITTYPE_H
#define SPITTYPE_H
#include "SPITSocket.h"
#include "SPIT_Message.h"
#include <string>
#include <unordered_map>
using namespace std;
class SPITTypeListener;
class SPITType {
private:
static unordered_map<string, SPITType*> s_SPITTypes;
static unordered_map<string, SPITType*> 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();
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<br>
* 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.<br>
* This can used to setActionAssigned to all SPITObjects with this SPITType.<br>
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.<br>
* @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.<br>
* This can used to setActionAssigned to all SPITObjects with this SPITType.<br>
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.<br>
* @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 */
-342
View File
@@ -1,342 +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: SPIT_Client.h
* Author: Hagi
*
* Created on 7. April 2019, 08:50
*/
#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 <memory>
#include <vector>
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,
};
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);
};
//----- Connection Status -----
public:
/** No Connection established.<br>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<br>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.<br>The time value is the position in server's project.<br>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;
//------ 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.<br>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.<br>This is usefull e.g. when instead of a fader a endless wheel is used*/
static const char VALUEFLAG_DECREASE = 0x02;
//----- SPIT_Client -----
public:
SPIT_Client(string name, string projName, Callbacks calls);
virtual ~SPIT_Client();
static int s_MAX_OVERTAKING_SPIT_MESSAGES;
private:
Callbacks mCallbacks;
fos::TaskT<SPIT_Client&> * 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<SPIT_Message*> 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.<br>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.<br>
* When the server plays objects, it will do so at discrete time steps.<br>
* Play events will take place in these time steps..
*/
int getServerStepTime() { return 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);
//--------------- 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.<br>
* 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<SPIT_Message> p_SPITMessage);
void checkParseSPIT_Message(unique_ptr<SPIT_Message> 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.<br>
* Fixed SPIT types cannot be changed or deleted by the server.<br>
* These SPITTypes will be automatically added to the SPITType-List and sended to the server.
* @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
* @param p_GroupName a name which groups the actions/SPITTypes
* @param p_Name the name of the Action/SPITType
* @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
* @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
* @return the pointer to the new SPITType.
*/
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.<br>
* These SPITTypes will be automatically added to the SPITType-List and sended to the server.
* @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
* @param p_GroupName a name which groups the actions/SPITTypes
* @param p_Name the name of the Action/SPITType
* @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
* @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
* @param p_Fixed true = the server is not allowed to change this SPITType, false = the server may change or delete this SPITType
* @param p_ProjectIndepended true = the SPITType belongs to a specific project, false = the SpitType always exists for every project
* @return the pointer to the new SPITType.
*/
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.<br>
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the change.<br>
* @param 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.<br>
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the deletion.<br>
* @param 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.<br>
* The SPITServer may discard the changes and an eventSPITObject occurs.<br>
* @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.<br>
* The SPITServer may discard the deletion and an eventSPITObject occurs.<br>
* @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<SPIT_Client &>* sThread{};
bool abortSearch{};
bool sAnswered{};
static fos::Semaphore sStartSad;
SPITSocket * mSPITSocket;
void answerWatchdog() {
sAnswered = true;
}
};
#endif /* SPIT_CLIENT_H */
-950
View File
@@ -1,950 +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: SPIT_Message.h
* Author: Hagi
*
* Created on 3. April 2019, 08:51
*/
#ifndef SPIT_MESSAGE_H
#define SPIT_MESSAGE_H
#include <cstdlib>
#include <string>
using namespace std;
static const string SPITID = "#spit#";
//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;
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);
};
//----------- 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;
};
//----------- SPIT_Message -----------
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;
//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;
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).<br>
* The length of the string will be p_Length -1.
* @return the String char*
* @throws Exception if p_Bytes == null<br>
* p_Offset less than 0<br>
* p_Bytes.length less than p_Offset + p_Length<br>
* 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.<br>
* 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.<br>
* @throws Exception if p_String == NULL, p_Bytes == NULL<br>
* p_Offset less than 0<br>
* 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<br>
* 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 */
@@ -0,0 +1,155 @@
#pragma once
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
using namespace std;
namespace spit {
class SadDetectedServer;
class ISadClient {
public:
virtual void eventServerDetected(SadDetectedServer &server) = 0;
virtual void eventServerChanged(SadDetectedServer &server) = 0;
virtual void eventServerLost(SadDetectedServer &server) = 0;
};
class SadDetectedServer {
public:
SadDetectedServer(string name, string iD, string computerName,
string iP, string port, string clientIP,
string additions, string projName)
: mName(name),
mID(iD),
mComputerName(computerName),
mIP(iP),
mPort(port),
mClientIP(clientIP),
mAdditions(additions),
mServerProjectName(projName) {
}
private:
string mName{};
string mID{};
string mComputerName{};
string mIP{};
string mPort{};
string mClientIP{};
string mAdditions{};
string mServerProjectName{};
bool mNew{true};
bool mChanged{};
bool mFoundAgain{};
public:
string getID() const { return mID; }
string getName() const { return mName; }
string getComputerName() const { return mComputerName; }
string getIP() const { return mIP; }
string getPort() const { return mPort; }
string getClientIP() const { return mClientIP; }
string getAdditions() const { return mAdditions; }
string getProjectName() const { return mServerProjectName; }
bool getNew() const { return mNew; }
bool getChanged() const { return mChanged; }
bool getFoundAgain() const { return mFoundAgain; }
void setChanged() { mChanged = true; }
void setKnown() { mNew = false; }
void setFoundAgain() { mFoundAgain = true; }
void updateProjectName(string newProjectName) {
mServerProjectName = newProjectName;
if (mServerProjectName != newProjectName) {
mChanged = true;
}
}
// SAD_Client mThreadSend will send to Multicast addresses
void resetFlags() {
mChanged = false;
mFoundAgain = false;
mNew = false;
}
private:
static unordered_map<string, unique_ptr<SadDetectedServer>> sKnownServers;
public:
enum ParamIndex {
PARAM_PRECODE = 0,
PARAM_SPITTASKID = 1,
PARAM_NAME = 2,
PARAM_ID = 3,
PARAM_COMPUTERNAME = 4,
PARAM_PORT = 5,
PARAM_CLIENTIP = 6,
PARAM_ADDITIONS = 7,
PARAM_SERVERPROJECTNAME = 8,
PARAM_IP = 9,
};
/**
* Used by SAD_Client to add a found SPITServer - don't use this manually
* @param id the id of the server, every instance of a SPITServer has an own id
* @param p_ServerParams the server's parameter
*/
static void addDetectedServer(unique_ptr<SadDetectedServer> detected) {
if (auto i = sKnownServers.find(detected->getID()); i != sKnownServers.end()) {
auto &known = *(i->second.get());
known.setFoundAgain();
if (detected->getProjectName() != known.getProjectName()) {
known.updateProjectName(detected->getProjectName());
}
return;
}
sKnownServers[detected->getID()] = move(detected);
}
static void removeDetectedServer(SadDetectedServer &server) {
auto i = sKnownServers.find(server.getID());
if (i != sKnownServers.end()) {
sKnownServers.erase(i);
}
}
static void clearDetectedServers() {
sKnownServers.clear();
}
static void resetServerFlags() {
for (auto &srv : sKnownServers) {
srv.second->resetFlags();
}
}
/**
* Used by SAD_Client internally -don't use this manually
*/
static void evaluateDetectedServers(ISadClient &sadClient) {
for (auto &srv : sKnownServers) {
SadDetectedServer &known = *srv.second;
if (known.getNew()) {
known.setKnown();
sadClient.eventServerDetected(known);
} else if (known.getChanged()) {
sadClient.eventServerChanged(known);
} else if (known.getFoundAgain() == false) {
sadClient.eventServerLost(known);
removeDetectedServer(known);
}
}
}
/**
* Returns a reference of the DetectedServer with the id p_ServerID.<br>
* If no DetectedServer is found an eyception is thrown.
* @param id the id of the SPITServer
* @return the reference of the SadDetectedServer instance with getID() == p_ServerID
*/
static const SadDetectedServer &getRefDetectedServer(const string &id) {
return *sKnownServers.at(id);
}
};
}
+203
View File
@@ -0,0 +1,203 @@
#pragma once
#include "sad_DetectedServer.hpp"
#include "spit_message.hpp"
#include "spit_object.hpp"
#include "spit_player.hpp"
#include "spit_processor.hpp"
#include "spit_repo.hpp"
#include "spit_socket.hpp"
#include "spit_type.hpp"
#include <functional>
#include <memory>
#include <vector>
using namespace std;
namespace spit {
class SClient : ISadClient {
public:
using Callbacks = SProcessor::Callbacks;
using ProjUpdate = SProcessor::ProjUpdate;
using ServerEvent = SProcessor::ServerEvent;
using ObjectEvent = SProcessor::ObjectEvent;
using Connection = SProcessor::Connection;
using PlayerType = SPlayer::PTypes;
using ValueFlags = SPlayer::VFlags;
SClient(string name, string projName, ISocket &socket, Callbacks calls);
virtual ~SClient();
private:
Callbacks mCallbacks;
fos::TaskT<SClient &> *mThreadReceive{};
fos::TaskT<SClient &> *mThreadProcess{};
bool mStopReceiveMessages{};
Connection mConnectionStatus{Connection::None};
bool mDisconnectedByServer{}; // flag true = when server disconnects
SProcessor mProcessor;
string mClientProjectName;
uint8_t mMessageNumberSend{1};
int mMessageNumberReceived{-1}; // set to -1 because the first received message will set the number (1..255)
// Server's info filled by parseConnectAnswer
string mServerID{};
string mServerName{};
string mServerComputerName{};
int mServerStepTime{-1};
public:
/** The ID of the client.<br>Every client instance should set an unique id*/
string getID() { return mProcessor.getID(); }
/** The name of the client, should be set by the user app*/
string getName() { return mProcessor.getName(); }
/** The name of the client's host computer*/
string getComputerName() { return mProcessor.getComputerName(); }
void setClientProjectName(string clientProjectName) { mClientProjectName = clientProjectName; }
string getClientProjectName() { return mClientProjectName; }
// connected Server Infos
/** The ID of the connected SPITServer*/
string getServerID() { return mServerID; }
/** The host computername of the connected SPITServer*/
string getServerComputerName() { return mServerComputerName; }
/** The name of the connected SPITServer*/
string getServerName() { return mServerName; }
/** Expected Refreah Rate of the connectd SPITServer.<br>
* When the server plays objects, it will do so at discrete time steps.<br>
* Play events will take place in these time steps..
*/
int getServerStepTime() { return mServerStepTime; }
/** Should be called when the client wants to close his project*/
void clientProjectClose();
/**
* Should be called whenever the client has a project loaded
*/
void clientProjectLoaded();
void setActionType(string spitypeID, bool actionAssigned) {
mProcessor.setActionType(spitypeID, actionAssigned);
}
void setActionObject(string objectID, bool actionAssigned) {
mProcessor.setActionObject(objectID, actionAssigned);
}
//--------------- SPITMessage ---------------
private:
bool startReceiveSPITMessages();
void stopReceiveSPITMessages();
static void receiveSpitMessage(SClient &rM);
static void processSpitMessage(SClient &rM);
// Reconnect to the server when connection is lost see eventConnectionStatus and eventServerDetected
bool _doReconnect{}; // true = on eventServerDetected connect to the server identified by mServerID
public:
int sendMessage(Message::OPPart &spitMessageOPPart);
//--------------- ServerAutoDetection SAD ---------------
public:
/** Starts the autodetection of SPITServers in the local network. If a connection is tried, the autodetection should be stopped before.*/
void startServerAutoDetect();
/** Stops the autodetection of SPITServers in the local network*/
void stopServerAutoDetect();
/** Called every time a new SPITServer is detetced in the local network */
void eventServerDetected(SadDetectedServer &server);
/** Called every time a prior detected SPITServer is is no longer found.*/
void eventServerLost(SadDetectedServer &server);
void eventServerChanged(SadDetectedServer &server);
//--------------- Connection ---------------
public:
/**
* Tries a connection to the SPITServer
* @param p_ServerIP ip address of the SPITServer
* @param p_ServerPort port of the SPITServer
* @param p_ClientIP IP of the client
* @param p_ClientPort if "0" any free port will be used
* @param p_LoginName maybe some SPITServer need a login - liveSHOWsoftware will not.
* @param p_LoginPassword maybe some SPITServer need a login - liveSHOWsoftware will not
* @return true = the connection try is ok, SPITServer will answer with COnnectAnswer and an eventConnectionStatus will occur.<br>
* false = something is going wrong. (client could not bind)
*/
bool connect(string serverIP, string serverPort, string clientIP, string clientPort, string loginName = "", string loginPassword = "");
/**
* Terminates the connection to the SPITServer.
*/
void disconnect();
private:
void disconnectInternal(Connection cause);
void resetMessageNumberReceived();
void parseMessage(Message& message);
void checkParseMessage(unique_ptr<Message> message);
void addOvertakingMessage(unique_ptr<Message> message);
void parseConnectAnswer(Message::ConnectAnswer &message);
void parseDisconnect(Message::Disconnect &message);
void parseWatchdog(Message::Watchdog &message);
void parseWatchdogAnswer(Message::WatchdogAnswer &message);
public:
/** Used internally*/
void sendWatchdog();
/** Used internally. When the connection to the SPITServer is lost an eventConnectionStatus will occur*/
void eventWatchdogLost();
//--------------- SPIT Project ---------------
/** Returns the SPITServer's project ID - may be the same as the project's name*/
string getServerProjectID() { return mProcessor.getServerProjectID(); }
/** Returns the SPITServer's project name*/
string getServerProjectName() { return mProcessor.getServerProjectName(); }
/** Returns frame rate per second. This is the time resolution in which the server transmits time data. The unit of time data is always frames.*/
int getServerFramesPerSecond() { return mProcessor.getServerFramesPerSecond(); }
public:
static void sendProject(SClient *p_PtrSClient);
// --------------- SPIT Types ---------------
public:
/**
* Creates a fixed SPITType for application actions that are always present and project independent.<br>
* Fixed SPIT types cannot be changed or deleted by the server.<br>
* These SPITTypes will be automatically added to the SPITType-List and sended to the server.
* @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
* @param p_GroupName a name which groups the actions/SPITTypes
* @param p_Name the name of the Action/SPITType
* @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
* @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
* @return the pointer to the new SPITType.
*/
SType *createTypeFixed(string iD, string groupName, string name, uint64_t defaultDelay, uint64_t defaultDuration);
public:
bool changeType(SType *spitType) { return mProcessor.changeType(spitType); }
int removeType(string spitypeID) { return mProcessor.removeType(spitypeID); }
public:
public:
bool changeObject(SObject *sObject) { return mProcessor.changeObject(sObject); }
void sendRemoteObject(string objectID, int valuePpm = 0, char valueFlag = 0x00) {
mProcessor.sendRemoteObject(objectID, valuePpm, valueFlag);
}
private:
static void processSocketTask(SClient &instance);
fos::TaskT<SClient &> *sThread{};
bool mAbortSearch{};
bool sAnswered{};
static fos::Semaphore sStartSad;
ISocket &mSocket;
void answerWatchdog() {
sAnswered = true;
}
};
} // namespace spit
+720
View File
@@ -0,0 +1,720 @@
#pragma once
#include <cstdlib>
#include <memory>
#include <optional>
#include <string>
#include <vector>
using namespace std;
static const string SPITID = "#spit#";
namespace spit {
class Message {
//----------- Header -----------
public:
/** Maximal length of a SPITMessage*/
static const int MAX_MESSAGE_SIZE = 512;
class Header {
public:
static constexpr int BYTESLENGTH = 99;
Header(const Header &orig);
Header();
private:
string mID;
int mVersion{SPITVERSION};
unsigned char mMessageNumber{};
int mBytesCount{BYTESLENGTH};
string mServerId{};
string mClientId{};
int mOpFlag{-1};
int mParseOffset{};
public:
string getSPITID() const { return mID; }
int getSPITVersion() const { return mVersion; }
unsigned char getMessageNumber() const { return mMessageNumber; }
int getBytesCount() const { return mBytesCount; }
string getServerID() const { return mServerId; }
string getClientID() const { return mClientId; }
int getType() const { return mOpFlag; }
// Receive
bool parse(const std::vector<char> &message);
// Send
Header(int p_SPITVersion, int pOpFlag);
void setMessageNumber(unsigned char messageNumber) { mMessageNumber = messageNumber; }
void setServerID(string iD) { mServerId = iD; }
void setClientID(string iD) { mClientId = iD; }
void setOPFlag(int pOpFlag) { mOpFlag = pOpFlag; }
bool fillBytes(std::vector<char> &message);
};
//----------- OPPart -----------
public:
class OPPart {
// Members
protected:
unique_ptr<Header> mHeader{};
int mParseOffset{};
int mBytesCount;
public:
virtual ~OPPart();
Header *getHeader() const { return mHeader.get(); }
int getBytesCount() const { return mBytesCount; }
void setServerInfoInHeader(string clientId, string serverId) {
if (!mHeader) {
return;
}
mHeader->setClientID(clientId);
mHeader->setServerID(serverId);
}
void setMessageNumber(uint8_t no) {
if (!mHeader) {
return;
}
mHeader->setMessageNumber(no);
}
const string getServerID() const {
if (!mHeader) {
return "";
}
return mHeader->getServerID();
}
const string getClientID() const {
if (!mHeader) {
return "";
}
return mHeader->getClientID();
}
int getType() const {
if (!mHeader) {
return -1;
}
return mHeader->getType();
}
// Receive
OPPart(unique_ptr<Header> header, int pOpFlag, int size);
void setHeader(int opFlag);
virtual bool parse(const std::vector<char> &message) = 0;
// Send
OPPart(int size);
virtual bool fillBytes(std::vector<char> &message) = 0;
};
//----------- Message -----------
public:
static constexpr int SPITVERSION = 1;
// SPIT_Object value usage
static constexpr char VALUEUSE_DISCARD = 0x00; // value of SPITObejct is not used
static constexpr char VALUEUSE_INRANGE = 0x01; // value of SPITOBject in range 0 - 1000000ppm
static constexpr char VALUEUSE_OVERRIDE = 0x02; // value can be overridden
// SPIT Player type
static constexpr char PLAYERTYPE_MAIN = 0x02;
static constexpr char PLAYERTYPE_CONTINIOUS = 0x01;
static constexpr char PLAYERTYPE_DISCRETE = 0x00;
// PlayObject value usage
static constexpr char VALUEFLAG_DIRECT = 0x00; // use the vlue direct
static constexpr char VALUEFLAG_INCREASE = 0x01; // increase the value
static constexpr char VALUEFLAG_DECREASE = 0x02; // decrease the value
Message() = default;
// Members
private:
unique_ptr<OPPart> oPPart{};
// Receive
public:
Message(std::vector<char> message);
const Header *getHeader() const { return oPPart->getHeader(); }
int getType() const {
if (!oPPart || !oPPart->getHeader()) {
return -1;
}
return oPPart->getHeader()->getType();
}
const OPPart *getOPPart() const { return oPPart.get(); }
template<typename T>
T &getAs() const { return *reinterpret_cast<T *>(oPPart.get()); }
private:
bool parse(std::vector<char> message);
// Send
public:
static std::vector<char> createMessage(OPPart & p_OPPart);
//------------------------------ Connection ----------------------------------
//----------- Connect -----------
public:
class Connect : public OPPart {
public:
static constexpr int OPFLAG = 1;
static constexpr int BYTESLENGTH = 304;
private:
string mClientComputerName{};
string mClientName{};
string mLoginName{};
string mLoginPassword{};
string mServerIp{};
int mServerPort{};
public:
// Receive
Connect(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
string getClientComputerName() const { return mClientComputerName; }
string getClientName() const { return mClientName; }
string getLoginName() const { return mLoginName; }
string getLoginPassword() const { return mLoginPassword; }
string getServerIP() const { return mServerIp; }
int getServerPort() const { return mServerPort; }
// Send
Connect(string p_ComputerName, string p_ClientName);
void setLoginName(string p_LoginName) { mLoginName = p_LoginName; }
void setLoginPassword(string p_LoginPassword) { mLoginPassword = p_LoginPassword; }
void setServerIP(string p_ServerIP) { mServerIp = p_ServerIP; }
void setServerPort(int p_ServerPort);
bool fillBytes(std::vector<char> &message);
};
//----------- ConnectAnswer -----------
class ConnectAnswer : public OPPart {
public:
static constexpr int OPFLAG = 2;
static constexpr int BYTESLENGTH = 137;
private:
string mServerComputerName{};
string mServerName{};
bool mConnected{};
int mStepTime{40}; // ms step size the Server will send play sequences
public:
ConnectAnswer(const ConnectAnswer &orig);
// Receive
ConnectAnswer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getServerComputerName() const { return mServerComputerName; }
const string getServerName() const { return mServerName; }
bool getConnected() const { return mConnected; }
int getStepTime() const { return mStepTime; }
// Send
ConnectAnswer();
void setServerComputerName(string p_ServerComputerName) { mServerComputerName = p_ServerComputerName; }
void setServerName(string p_ServerName) { mServerName = p_ServerName; }
void setConnected(bool p_Connected) { mConnected = p_Connected; }
void setStepTime(int p_StepTime_ms);
bool fillBytes(std::vector<char> &message);
};
//----------- Disconnect -----------
class Disconnect : public OPPart {
public:
static constexpr int OPFLAG = 3;
static constexpr int BYTESLENGTH = 4;
Disconnect(const Disconnect &orig);
// Receive
Disconnect(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
Disconnect();
bool fillBytes(std::vector<char> &message);
};
//----------- Watchdog -----------
class Watchdog : public OPPart {
public:
static constexpr int OPFLAG = 8;
static constexpr int BYTESLENGTH = 4;
Watchdog(const Watchdog &orig);
// Receive
Watchdog(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
Watchdog();
bool fillBytes(std::vector<char> &message);
};
//----------- WatchdogAnswer -----------
class WatchdogAnswer : public OPPart {
public:
static constexpr int OPFLAG = 9;
static constexpr int BYTESLENGTH = 4;
// Receive
WatchdogAnswer(const WatchdogAnswer &orig);
WatchdogAnswer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
WatchdogAnswer();
bool fillBytes(std::vector<char> &message);
};
//------------------------------ SPITProject ----------------------------------
//----------- ReportProject -----------
class ReportProject : public OPPart {
public:
static constexpr int OPFLAG = 11;
static constexpr int BYTESLENGTH = 113;
private:
string mProjectID{};
string mProjectName{};
int mFramesPerSecond{1000}; // Frames per second
// Receive
public:
ReportProject(const ReportProject &orig);
ReportProject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getProjectID() const { return mProjectID; }
const string getProjectName() const { return mProjectName; }
int getFramesPerSecond() const { return mFramesPerSecond; }
// Send
ReportProject(string p_ProjectID, string p_ProjectName);
void setFramesPerSecond(const int p_FramesPerSecond) { mFramesPerSecond = p_FramesPerSecond; }
bool fillBytes(std::vector<char> &message);
};
//----------- CloseProject -----------
class CloseProject : public OPPart {
public:
static constexpr int OPFLAG = 13;
static constexpr int BYTESLENGTH = 45;
private:
string mProjectID{};
public:
CloseProject(const CloseProject &orig);
// Receive
CloseProject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getProjectID() const {
return mProjectID;
}
// Send
CloseProject(string projectID);
bool fillBytes(std::vector<char> &message);
};
//----------- StartProjectTransfer -----------
class RequestProjectTransfer : public OPPart {
public:
static constexpr int OPFLAG = 15;
static constexpr int BYTESLENGTH = 4;
RequestProjectTransfer(const RequestProjectTransfer &orig);
// Receive
RequestProjectTransfer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
RequestProjectTransfer();
bool fillBytes(std::vector<char> &message);
};
//----------- StartProjectTransfer -----------
class StartProjectTransfer : public OPPart {
public:
static constexpr int OPFLAG = 16;
static constexpr int BYTESLENGTH = 4;
StartProjectTransfer(const StartProjectTransfer &orig);
// Receive
StartProjectTransfer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
StartProjectTransfer();
bool fillBytes(std::vector<char> &message);
};
//----------- EndProjectTransfer -----------
class EndProjectTransfer : public OPPart {
public:
static constexpr int OPFLAG = 17;
static constexpr int BYTESLENGTH = 4;
EndProjectTransfer(const EndProjectTransfer &orig);
// Receive
EndProjectTransfer(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
// Send
EndProjectTransfer();
bool fillBytes(std::vector<char> &message);
};
//---------------------------- SPIT_Types ----------------------------------
//----------- ReportType -----------
class ReportType : public OPPart {
public:
static constexpr int OPFLAG = 21;
static constexpr int BYTESLENGTH = 168;
private:
bool mConfirmed{};
string mTypeID{};
bool mFixed{};
bool mServerRemote{};
bool mServerProjectIndepended{};
string mTypeGroupName{};
string mSPITTypeName{};
uint64_t mDelay{};
uint64_t mDuration{};
public:
ReportType(const ReportType &orig);
// Receive
ReportType(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
bool getConfirmed() const { return mConfirmed; }
const string getID() const { return mTypeID; }
bool getFixed() const { return mFixed; }
bool getServerRemote() const { return mServerRemote; }
bool getServerProjectIndepended() const { return mServerProjectIndepended; }
const string getGroupName() const { return mTypeGroupName; }
const string getName() const { return mSPITTypeName; }
uint64_t getDelay() const { return mDelay; }
uint64_t getDuration() const { return mDuration; }
// Send
ReportType();
void setConfirmed(bool p_Confirmed) { mConfirmed = p_Confirmed; }
void setID(string iD) { mTypeID = iD; }
void setFixed(bool p_Fixed) { mFixed = p_Fixed; }
void setServerRemote(bool p_IsServerRemote) { mServerRemote = p_IsServerRemote; }
void setServerProjectIndepended(bool p_ProjectIndpended) { mServerProjectIndepended = p_ProjectIndpended; }
void setGroupName(string p_GroupName) { mTypeGroupName = p_GroupName; }
void setName(string p_Name) { mSPITTypeName = p_Name; }
void setDelay(uint64_t p_Delay) { mDelay = p_Delay; }
void setDuration(uint64_t p_Duration) { mDuration = p_Duration; }
bool fillBytes(std::vector<char> &message);
};
//----------- RemoveType -----------
class RemoveType : public OPPart {
public:
static constexpr int OPFLAG = 23;
static constexpr int BYTESLENGTH = 45;
private:
string mTypeID{};
public:
RemoveType(const RemoveType &orig);
// Receive
RemoveType(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getID() const { return mTypeID; }
// Send
RemoveType();
void setID(string iD) { mTypeID = iD; }
bool fillBytes(std::vector<char> &message);
};
//---------------------------- SPITObjects ----------------------------------
//----------- ReportObject -----------
class ReportObject : public OPPart {
public:
static constexpr int OPFLAG = 31;
static constexpr int BYTESLENGTH = 339;
private:
bool mConfirmed{};
string mSPITObjectID{};
bool mFixed{};
bool mServerRemote{};
string mSPITObjectName{};
string mTypeID{};
string mServerParams{};
uint64_t mFrameStart{};
uint64_t mFrameLength{};
uint64_t mFrameFadeInLength{};
uint64_t mFrameFadeOutLength{};
int mValueFactor{};
char mValueUse{VALUEUSE_DISCARD};
int mTrack{};
string mRemark{};
uint64_t mDelay{};
uint64_t mDuration{};
bool mActionAssigned{};
public:
ReportObject(const ReportObject &orig);
// Receive
ReportObject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
bool getConfirmed() const { return mConfirmed; }
const string getID() const { return mSPITObjectID; }
bool getFixed() const { return mFixed; }
bool getServerRemote() const { return mServerRemote; }
const string getName() const { return mSPITObjectName; }
const string getSPITTypeID() const { return mTypeID; }
const string getServerParams() const { return mServerParams; }
uint64_t getFrameStart() const { return mFrameStart; }
uint64_t getFrameLength() const { return mFrameLength; }
uint64_t getFrameFadeInLength() const { return mFrameFadeInLength; }
uint64_t getFrameFadeOutLength() const { return mFrameFadeOutLength; }
int getValueFactor() const { return mValueFactor; }
char getValueUse() const { return mValueUse; }
int getTrack() const { return mTrack; }
const string getRemark() const { return mRemark; }
uint64_t getDelay() const { return mDelay; }
uint64_t getDuration() const { return mDuration; }
bool getActionAssigned() const { return mActionAssigned; }
// Send
public:
ReportObject();
void setConfirmed(bool p_Confirmed) { mConfirmed = p_Confirmed; };
void setID(string iD) { mSPITObjectID = iD; };
void setFixed(bool p_Fixed) { mFixed = p_Fixed; };
void setServerRemote(bool p_IsRemote) { mServerRemote = p_IsRemote; };
void setName(string p_Name) { mSPITObjectName = p_Name; };
void setSPITTypeID(string iD) { mTypeID = iD; };
void setServerParams(string p_Parameters) { mServerParams = p_Parameters; };
void setFrameStart(uint64_t p_StartTime) { mFrameStart = p_StartTime; };
void setFrameLength(uint64_t p_Length) { mFrameLength = p_Length; };
void setFrameFadeInLength(uint64_t p_FadeInTime) { mFrameFadeInLength = p_FadeInTime; };
void setFrameFadeOutLength(uint64_t p_FadeOutTime) { mFrameFadeOutLength = p_FadeOutTime; };
void setValueFactor(int p_Volume) { mValueFactor = p_Volume; };
void setValueUse(char p_ValueUse) { mValueUse = p_ValueUse; };
void setTrack(int p_Track) { mTrack = p_Track; };
void setRemark(string p_Description) { mRemark = p_Description; };
void setDelay(uint64_t p_Delay);
void setDuration(uint64_t p_Duration);
void setActionAssigned(bool p_ActionAssigned) { mActionAssigned = p_ActionAssigned; }
bool fillBytes(std::vector<char> &message);
};
//----------- RemoveObject -----------
class RemoveObject : public OPPart {
public:
static constexpr int OPFLAG = 33;
static constexpr int BYTESLENGTH = 45;
private:
string mSPITObjectID{};
public:
RemoveObject(const RemoveObject &orig);
// Receive
RemoveObject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getID() const { return mSPITObjectID; }
// Send
public:
RemoveObject();
void setID(string iD) { mSPITObjectID = iD; }
bool fillBytes(std::vector<char> &message);
};
//---------------------------- SPITPlayer ----------------------------------
//----------- PlayStart -----------
class PlayStart : public OPPart {
public:
static constexpr int OPFLAG = 37;
static constexpr int BYTESLENGTH = 119;
private:
string mPlayerID{};
string mPlayerName{};
char mPlayerType{};
bool mPlayerIsRunning{};
uint64_t mTime; // Frames
public:
PlayStart(const PlayStart &orig);
// Receive
PlayStart(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getPlayerID() const { return mPlayerID; }
const string getPlayerName() const { return mPlayerName; }
char getPlayerType() const { return mPlayerType; }
bool getPlayerIsRunning() const { return mPlayerIsRunning; }
uint64_t getTime() const { return mTime; }
// Send
PlayStart(string p_PlayerID, string p_PlayerName, char p_PlayerType);
void setPlayerIsRunning(bool p_IsPlaying) { mPlayerIsRunning = p_IsPlaying; }
void setTime(uint64_t p_Time) { mTime = p_Time; }
bool fillBytes(std::vector<char> &message);
};
//----------- PlayObject -----------
class PlayObject : public OPPart {
public:
static constexpr int OPFLAG = 38;
static constexpr int BYTESLENGTH = 100;
private:
string mPlayerID{};
string mSPITObjectID{};
uint64_t mFrameInsideObject{}; // Frames
bool mPlayPrePosition{};
int mValue{};
char mValueFlag{VALUEFLAG_DIRECT};
public:
PlayObject(const PlayObject &orig);
// Receive
PlayObject(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getPlayerID() const { return mPlayerID; }
const string getSPITObjectID() const { return mSPITObjectID; }
uint64_t getFrameInsideObject() const { return mFrameInsideObject; }
bool getPlayPrePosition() const { return mPlayPrePosition; }
int getValue() const { return mValue; }
char getValueFlag() const { return mValueFlag; }
// Send
PlayObject();
void setPlayerID(string p_PlayerID) { mPlayerID = p_PlayerID; }
void setID(string iD) { mSPITObjectID = iD; }
void setFrameInsideObject(uint64_t p_TimeInside) { mFrameInsideObject = p_TimeInside; }
void setPlayPrePosition(bool p_PlayOldPosition) { mPlayPrePosition = p_PlayOldPosition; }
void setValue(int p_Value) { mValue = p_Value; }
void setValueFlag(char p_ValueFlag) { mValueFlag = p_ValueFlag; }
bool fillBytes(std::vector<char> &message);
};
//----------- PlayEnd -----------
class PlayEnd : public OPPart {
public:
static constexpr int OPFLAG = 39;
static constexpr int BYTESLENGTH = 45;
private:
string mPlayerID{};
public:
PlayEnd(const PlayEnd &orig);
// Receive
PlayEnd(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getPlayerID() const { return mPlayerID; }
// Send
PlayEnd(string p_PlayerID);
bool fillBytes(std::vector<char> &message);
};
//----------- ReportPlayStatus -----------
class ReportPlayStatus : public OPPart {
public:
static constexpr int OPFLAG = 40;
static constexpr int BYTESLENGTH = 57;
private:
string mSPITObjectID{};
uint64_t mFrameInsideObject{};
int mValue{};
public:
ReportPlayStatus(const ReportPlayStatus &orig);
// Receive
ReportPlayStatus(unique_ptr<Header> header);
bool parse(const std::vector<char> &message);
const string getID() const { return mSPITObjectID; }
uint64_t getFrameInsideObject() const { return mFrameInsideObject; }
int getValue() const { return mValue; }
// Send
ReportPlayStatus();
void setID(string iD);
void setFrameInsideObject(uint64_t p_TimeInside);
void setValue(int p_Value);
bool fillBytes(std::vector<char> &message);
};
//----------------------- static helper functions ----------------------------
public:
static bool isSystemLittleEndian();
static optional<int> getInt(const std::vector<char> &message, int &offset);
static optional<uint64_t> getLong(const std::vector<char> &message, int &offset);
static optional<bool> getBoolean(const std::vector<char> &message, int &offset);
static optional<char> getByte(const std::vector<char> &message, int &offset);
static int setInt(int value, std::vector<char> &message, int offset);
static int setLong(uint64_t value, std::vector<char> &message, int offset);
static int setBoolean(bool value, std::vector<char> &message, int offset);
static int setByte(int value, std::vector<char> &message, int offset);
/**
* Returns the string char* of the part of the byte sequence (0x00 null terminated).
* @param p_Bytes the byte array
* @param offset the startposition of strings bytes
* @param p_Length the length of the string included the null terminate byte (0x00).
* The length of the string will be p_Length -1.
*/
static optional<string> getString(const std::vector<char> &message, int &offset, int maxLength);
/**
* Fill the p_String in the byte array.
* If p_String length is greater than p_Length -1, the p_String will be truncated.
* CAUTION the return value should be freed after use.
* @param p_String the string
* @param p_Length the maximal length of the string included the null character.
* @throws Exception if p_String == nullptr, p_Bytes == nullptr
* p_Offset less than 0
* p_ByteCount less than p_Offset + p_Length
* @return p_Length
*/
static int setString(string p_String, std::vector<char> &message, int p_Offset, int p_Length);
};
}
+122
View File
@@ -0,0 +1,122 @@
#pragma once
#include "spit_type.hpp"
#include "spit_message.hpp"
#include "spit_repo.hpp"
using namespace std;
namespace spit {
class SObjectListener;
class SObject {
public:
template <typename T>
struct Property {
friend SObject;
Property(bool &confirmed)
: rConfirmed(confirmed) {
}
bool set(const T& val) {
if (mValue == val)
return false;
mValue = val;
rConfirmed = false;
return true;
}
T get () const {
return mValue;
}
private:
bool & rConfirmed;
T mValue{};
};
Property<string> Name{mConfirmed};
Property<string> Remark{mConfirmed};
Property<string> ServerParams{mConfirmed};
Property<string> SPITTypeID{mConfirmed};
// Returns if the SPITType triggers an action on the Server or on the client.
// @return false = the action is triggered on the client The client waits for the server to play objects of this SPITType
// true = the action is triggered on the server. The server waits for the client to play objects of this SPITType.
Property<bool> ServerRemote{mConfirmed};
Property<bool> Fixed{mConfirmed};
Property<uint64_t> FrameStart{mConfirmed};
Property<uint64_t> FrameLength{mConfirmed};
Property<uint64_t> FrameFadeInLength{mConfirmed};
Property<uint64_t> FrameFadeOutLength{mConfirmed};
Property<char> ValueUse{mConfirmed};
Property<int> ValueFactor{mConfirmed};
Property<int> Track{mConfirmed};
Property<uint64_t> Delay{mConfirmed};
Property<uint64_t> Duration{mConfirmed};
static void clearUnconfirmedObjects(SpitRepo<SObject> &repo);
static void setConfirmedFalse(SpitRepo<SObject> &repo);
static void eventProjectClosed(SpitRepo<SObject> &repo, SpitRepo<SObject> &remoteRepo);
SObject(string iD) {
mID = iD;
}
private:
string mID;
bool mConfirmed{};
bool mCreatedByClient{};
bool mActionAssigned{};
bool mActionAssignedType{}; // Virtual construct
char mValueUse{0x01};
int mValueFactor{1000000}; // Values are given in ppm -> 1000000 = 1/1;
bool mPlayPrePosition;
uint64_t mPlayTimeInsideFrames;
int mPlayValue;
char mPlayValueFlag;
public:
string getID() const { return mID; }
/**
* This is used by the server and client to tell if the other side has registered the changes.
* @return true = other side has registered the changes.
*/
bool getConfirmed() const { return mConfirmed; }
bool getCreatedByClient() const { return mCreatedByClient; }
/**
* This is a virtual construct - ActionAssignedType is not implemented in the SPITProtocol.
* This is used when an action is associated with a SPITType.
* Then this action is done for every SObject with the SPITType.
* @return true = an action is assigned for the SPITType.
*/
bool getActionAssignedType() const { return mActionAssignedType; }
/** Returns if this SObject has an associated action or not.
* @return true = the user has asscociated an action with this SObject or
* the user has asscociated an action with the SPITType of this SObject
*/
bool getActionAssigned() const { return mActionAssigned || mActionAssignedType; }
bool getProjectIndepended(SpitRepo<SType> &repo, SpitRepo<SType> &remoteRepo) const {
SType *ptrSPITType;
if (ServerRemote.get() == false) {
ptrSPITType = repo.getEntry(SPITTypeID.get());
if (ptrSPITType == nullptr)
return true;
return ptrSPITType->ProjectIndepended.get();
} else {
ptrSPITType = remoteRepo.getEntry(SPITTypeID.get());
if (ptrSPITType == nullptr)
return true;
return ptrSPITType->ProjectIndepended.get();
}
};
bool setConfirmed(bool confirmed);
void setCreatedByClient(bool createdByClient) { mCreatedByClient = createdByClient; }
bool setActionAssignedType(bool actionAssigned);
bool setActionAssigned(bool actionAssigned);
bool setMessageOP(Message::ReportObject *message);
void fillMessageOP(Message::ReportObject &message);
void fillMessageOP(Message::RemoveObject &message);
};
}
+98
View File
@@ -0,0 +1,98 @@
#pragma once
#include "spit_object.hpp"
#include <unordered_map>
namespace spit {
class SPlayer {
//----- PlayObject used in PlaySequences: PlaySPITStart, PlaySPITObject,..., PlaySPITEnd ------
public:
enum PTypes {
// diescrete player: This player is used to transmit single discrete values.
PTYPE_DISCRETE = 0x00,
// continous player: This player plays SPIT objects sometime during the project.
PTYPE_CONTINOUS = 0x01,
// continous main player: time value can be used like a timecode.<br>The time value is the position in server's project.<br>A server should use only one main player.
PTYPE_MAIN = 0x02,
};
enum VFlags {
// Set the given value directly
VFLAG_DIRECT = 0x00,
// Increase the existing value by the given value.<br>This is usefull e.g. when instead of a fader a endless wheel is used*/
VFLAG_INCREASE = 0x01,
// Decrease the existing value by the given value.<br>This is usefull e.g. when instead of a fader a endless wheel is used*/
VFLAG_DECREASE = 0x02,
};
class PlayType {
public:
PlayType(SPlayer *spitPlayer, string spitObjectID);
PlayType(const PlayType &orig);
string getSPITTypeID() const { return mSpitTypeID; }
void startPlaySequence();
bool getIsNew() const { return mIsNew; }
void setIsNew(bool isNew) { mIsNew = isNew; }
bool getIsPlayed() const { return mIsPlayed; }
void setIsPlayed(bool p_IsFound) { mIsPlayed = p_IsFound; }
string getPlayerID() const { return mPlayerID; }
string getPlayerName() const { return mPlayerName; }
bool getPlayerIsRunning() const { return mPlayerRuns; }
void setPlayerIsRunning(bool playerRuns) { mPlayerRuns = playerRuns; }
void setValue(double value) { mValue = value; }
void addValue(double value, double valueFactor) { mValue += (value * valueFactor); }
double getValue() const { return mValue; }
private:
string mPlayerID;
string mPlayerName;
bool mPlayerRuns;
string mSpitTypeID;
bool mIsPlayed;
bool mIsNew;
double mValue;
};
//----- SPlayer ------
public:
// list the SPITPlayers
static unordered_map<string, unique_ptr<SPlayer>> sSpitPlayers; // all actual played objects
static SPlayer &getSPITPlayer(string pPlayerID); // if a player does not exist creates a new one
static void clearPlayers() { sSpitPlayers.clear(); }
SPlayer(string pPlayerID);
virtual ~SPlayer();
void startPlaySequence(); // called by SPIT_Client::parsePlaySPITStart
PlayType *addTypePlaying(string spitTypeID); // called by SPIT_Client::parsePlaySPITStart
void endPlaySequence(); // called by SPIT_Client::parsePlaySPITEnd
string getID() {
return mId;
}
unordered_map<string, unique_ptr<PlayType>> &getPlaySPITTypes() { return mPlaySPITTypes; }
void setIsRunning(bool isRunning) { mIsRunning = isRunning; }
void setName(string name) { mName = name; }
void setType(char type) { mType = type; }
void setTime(uint64_t frames) { mTimeFrames = frames; }
bool getIsRunning() const { return mIsRunning; }
string getName() const { return mName; }
char getType() const { return mType; }
uint64_t getTime() const { return mTimeFrames; }
private:
string mId;
string mName;
char mType;
unordered_map<string, unique_ptr<PlayType>> mPlaySPITTypes;
bool mIsRunning;
uint64_t mTimeFrames;
};
} // namespace spit
+169
View File
@@ -0,0 +1,169 @@
#pragma once
#include "sad_DetectedServer.hpp"
#include "spit_message.hpp"
#include "spit_object.hpp"
#include "spit_player.hpp"
#include "spit_repo.hpp"
#include "spit_type.hpp"
#include <functional>
#include <memory>
#include <vector>
using namespace std;
namespace spit {
class SProcessor {
public:
enum class ProjUpdate {
ServerLoaded,
StartTransfer,
EndTransfer,
ServerClosed,
};
enum class ServerEvent {
Detect,
Lost,
Changed,
};
enum class ObjectEvent {
Created,
Changed,
Deleted
};
enum class Connection {
None = 0, // No Connection established.<br>Either no connect tried or disconnected
NoneServer = 1, // Server has disconnected
Lost = 2, // The connection is lost<br>Either because of a network crash or because the server no longer responds.
Ok = 3, // Connection to the serv er is established.
TryConnection = 4, // A connection to the server is tried.
};
struct Callbacks {
function<void(ServerEvent event, const SadDetectedServer &detectedServer)> onServerEvent;
function<void(string serverID, string serverComputerName, string serverName, int serverStepTime, Connection connectionStatus, Connection oldConnectionStatus)> onConnectionStatus;
function<void(ProjUpdate state, string projectId)> onProjectUpdate;
function<void(ObjectEvent event, bool isRemote, const SType &sType)> onSpitType;
function<void(ObjectEvent event, bool isRemote, const SType &sType, const SObject &sObject)> onSpitObject;
function<void(string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames)> onPlay;
function<void(string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value)> onPlaySpitType;
function<void(const SType &sType, const SObject &sObject, uint64_t p_FrameInsideObject, int value)> onPlayRemoteObjectStatus;
function<bool(bool knownType, bool createdByClient)> onCheckSpitTypeVeto;
function<bool(bool knownType)> onCheckSpitObjectVeto;
};
struct InternalCallbacks {
function<void(int ms)> delay;
function<int(Message::OPPart &msg)> sendMessage;
function<void(Message &msg)> parseMessage;
};
static constexpr int MAX_OVERTAKING_SPIT_MESSAGES = 10;
//----- SProcessor -----
public:
SProcessor(string name, string projName, string hostName, string guid,
Callbacks calls, InternalCallbacks intern);
virtual ~SProcessor();
private:
Callbacks mCallbacks;
InternalCallbacks mInternCallbacks;
string mName;
string mGuid;
string mProjName;
string mComputerName;
uint8_t mMessageNumberSend{1};
int mMessageNumberReceived{-1}; // set to -1 because the first received message will set the number (1..255)
vector<unique_ptr<Message>> mOvertakingMessages;
string mServerID{};
string mServerProjectID;
string mServerProjectName;
int mServerFramesPerSecond;
public:
string getID() { return mGuid; }
string getName() { return mName; }
string getProjName() { return mProjName; }
string getComputerName() { return mComputerName; }
void setActionType(string spitypeID, bool actionAssigned);
void setActionObject(string objectID, bool actionAssigned);
void checkParseMessageData(vector<char> data);
unique_ptr<Message::Connect> createConnectMessage(string serverIP, string serverPort, string loginName, string loginPassword);
std::vector<char> createMessage(Message::OPPart &spitMessageOPPart);
void parseMessage(Message &message);
void addOvertakingMessage(unique_ptr<Message> message);
int sendOvertakingMessage(int msgNumRec);
void resetMessageNumberReceived();
string getServerProjectID() { return mServerProjectID; }
string getServerProjectName() { return mServerProjectName; }
int getServerFramesPerSecond() { return mServerFramesPerSecond; }
// /**
// * Creates a SPITType for application actions.<br>
// * These SPITTypes will be automatically added to the SPITType-List and sended to the server.
// * @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
// * @param p_GroupName a name which groups the actions/SPITTypes
// * @param p_Name the name of the Action/SPITType
// * @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
// * @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
// * @param p_Fixed true = the server is not allowed to change this SPITType, false = the server may change or delete this SPITType
// * @param p_ProjectIndepended true = the SPITType belongs to a specific project, false = the SpitType always exists for every project
// * @return the pointer to the new SPITType.
// */
SType *createType(string iD, string groupName, string name, uint64_t defaultDelay, uint64_t defaultDuration, bool fixed, bool projectIndepended);
int sendTypeInternal(SType &sType);
/**
* If a client wants to change a SPITType, he should send it to the server.<br>
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the change.<br>
* @param spitypeID the id of the SPITType to remove.
* @return 0 = is sended, -1 = is not sended
*/
bool changeType(SType *spitType);
/**
* If a client wants to remove a SPITType, he should send it to the server.<br>
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the deletion.<br>
* @param spitypeID the id of the SPITType to remove.
* @return 0 = is sended, -1 = is not sended
*/
int removeType(string spitypeID);
int removeObject(string objectID);
bool changeObject(SObject *sObject);
void sendRemoteObject(string objectID, int valuePpm = 0, char valueFlag = 0x00);
void resetConfirmedFlags() {
SType::setConfirmedFalse(mSpitTypes);
SObject::setConfirmedFalse(mSpitObjects);
}
private:
void parseReportProject(Message::ReportProject &message);
void parseCloseProject(Message::CloseProject &message);
void parseRequestProjectTransfer(Message::RequestProjectTransfer &message);
void parseStartProjectTransfer(Message::StartProjectTransfer &message);
void parseEndProjectTransfer(Message::EndProjectTransfer &message);
void parseReportType(Message::ReportType &message);
void parseRemoveType(Message::RemoveType &message);
void parseReportObject(Message::ReportObject &message);
void parseRemoveObject(Message::RemoveObject &message);
void parsePlayStart(Message::PlayStart &message);
void parsePlayObject(Message::PlayObject &message);
void parsePlayEnd(Message::PlayEnd &message);
void parseReportPlayStatus(Message::ReportPlayStatus &message);
int sendObjectInternal(SObject *sObject);
SpitRepo<SObject> mSpitObjects;
SpitRepo<SType> mSpitTypes;
SpitRepo<SObject> mRemoteSpitObjects;
SpitRepo<SType> mRemoteSpitTypes;
};
} // namespace spit
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
using namespace std;
namespace spit {
template <typename T>
class SpitRepo {
public:
bool hasEntry(const string &id) {
return mEntries.contains(id);
}
T *getEntry(const string &id) {
auto i = mEntries.find(id);
if (i == mEntries.end()) {
return nullptr;
}
return i->second.get();
}
const T &getEntryRef(const string &id) {
return *mEntries.at(id);
}
void addEntry(unique_ptr<T> entry) {
mEntries[entry->getID()] = move(entry);
}
bool removeEntry(const T &entry) {
return removeEntry(entry.getID());
}
bool removeEntry(const string &id) {
auto i = mEntries.find(id);
if (i == mEntries.end()) {
return false;
}
mEntries.erase(i);
return true;
}
int getSize() {
return mEntries.size();
}
unordered_map<string, unique_ptr<T>> &getRepo() {
return mEntries;
}
void clearEntries() {
mEntries.clear();
}
private:
unordered_map<string, unique_ptr<T>> mEntries;
};
}
+149
View File
@@ -0,0 +1,149 @@
#pragma once
#include "Task.hpp"
#include "esp_log.h"
#include "esp_netif.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
using namespace std;
namespace spit {
/** Returns an guid */
string createGUID();
/** Returns the name of the client's host computer*/
string getClientHostName();
class ISocket {
public:
/**
* IpAddress class is used to fetch all available IP addresses of the computer
* This is for internal usage
*/
struct IpAddress {
public:
IpAddress(const string &iPAddress, const string &subnetMask)
: mIpAddress(iPAddress), mSubnetMask(subnetMask) {}
const string mIpAddress;
const string mSubnetMask;
/**
* Calculates the broadcast address from a ip4 address
* @param iPAddress the ip4 address
* @return returns the broadcast address
*/
string getBroadcastIP4() const {
struct in_addr broadcast;
unsigned long ipAddress;
unsigned long subnetMask;
ipAddress = inet_addr(mIpAddress.data());
subnetMask = inet_addr(mSubnetMask.data());
broadcast.s_addr = ipAddress | ~subnetMask;
return inet_ntoa(broadcast);
}
};
const IpAddress mOwnIp;
ISocket(IpAddress ip)
: mOwnIp(ip) {}
virtual int sendMessage(const char *message, int length) = 0;
virtual int receiveMessage(char *bu1ffer, int bufferLength, string *serverIp) const =0;
virtual void setConnectionParams(const string &serverIp, const string &serverPort, const string &clientIp, const string &clientPort) =0;
virtual int bindSocket(string clientIp, string clientPort) =0;
virtual int setBroadcast(bool broadcast) const =0;
virtual int sendMessageTo(const string &ip, const string &port, const char *message, int msgLength) =0;
bool getIsBound() const { return mIsBound; }
protected:
bool mIsBound{};
};
class Socket : public ISocket {
public:
static const int FAMILY_IP4 = AF_INET;
static IpAddress getAdaptersInfo();
bool createSocketUdp();
static const int INVALID_SOCKET = -1;
private:
int mUdpSocketIp4;
public:
//-------- class --------------
Socket(IpAddress ip) : ISocket(ip) {
mUdpSocketIp4 = INVALID_SOCKET;
createSocketUdp();
}
virtual ~Socket() {
ESP_LOGD("UDP", "Shutting down ...");
if (mUdpSocketIp4 != INVALID_SOCKET) {
shutdown(mUdpSocketIp4, 2);
close(mUdpSocketIp4);
mUdpSocketIp4 = INVALID_SOCKET;
}
fos::Task::delayMs(100);
mIsBound = false;
}
private:
string mServerIP{};
string mServerPort{};
string mClientIp{};
string mClientPort{}; // port given by the user maybe "0"
string mBoundClientPort{}; // port set after bind
public:
// Sets the ip address and port for server and client.
void setConnectionParams(const string &serverIp, const string &serverPort, const string &clientIp, const string &clientPort) override {
mServerIP = serverIp;
mServerPort = serverPort;
mClientIp = clientIp;
mClientPort = clientPort;
}
/**
* Send a message to the server as set by setConnectionParams
* @param message byte buffer containing the message
* @param length length of the message
* @return
*/
int sendMessage(const char *message, int length) override {
if (mServerPort.length() <= 0) {
return -1;
}
if (mIsBound == false) {
return -1;
}
int intResult = sendMessageTo(mServerIP, mServerPort, message, length);
return intResult;
}
int receiveMessage(char *bu1ffer, int bufferLength, string *serverIp) const override;
int setBroadcast(bool broadcast) const override;
int bindSocket(string clientIp, string clientPort) override;
int sendMessageTo(const string &ip, const string &port, const char *message, int msgLength) override;
string getServerIP() const { return mServerIP; }
string getServerPort() const { return mServerPort; }
string getClientIP() const { return mClientIp; }
string getClientPort() const { return mClientPort; }
string getBoundClientPort() const { return mBoundClientPort; }
void setBoundClientPort(const string &port) { mBoundClientPort = port; }
void setIsBound(bool isBound) { mIsBound = isBound; }
private:
};
}
+189
View File
@@ -0,0 +1,189 @@
#pragma once
#include "spit_message.hpp"
#include "spit_repo.hpp"
using namespace std;
namespace spit {
class STypeListener;
class SType {
public:
template <typename T>
struct Property {
friend SType;
Property(bool &confirmed)
: rConfirmed(confirmed) {
}
bool set(const T& val) {
if (mValue == val)
return false;
mValue = val;
rConfirmed = false;
return true;
}
T get () const {
return mValue;
}
private:
bool & rConfirmed;
T mValue{};
};
Property<string> GroupName{mConfirmed};
Property<string> Name{mConfirmed};
Property<bool> Fixed{mConfirmed};
Property<bool> ProjectIndepended{mConfirmed};
// Returns if the SType triggers an action on the Server or on the client.
// @return false = the action is triggered on the client The client waits for the server to play objects of this SType
// true = the action is triggered on the server. The server waits for the client to play objects of this SType.
Property<bool> ServerRemote{mConfirmed};
Property<uint64_t> DefaultDelay{mConfirmed};
Property<uint64_t> DefaultDuration{mConfirmed};
// Virtual construct - means ActionAssigned for STypes is is not implemented in SPITProtocol.
// This can used to setActionAssigned to all SPITObjects with this SType.
// This may be used in the case when the same action should be done for every SPITObject with this SType associated.
// @return true = the user has associated an action with this SType.
Property<bool> ActionAssigned{mConfirmed};
// Sets confirmed = false for all STypes.
// This should be called when the client has loaded a project.
static void setConfirmedFalse(SpitRepo<SType> &repo) {
auto &entries = repo.getRepo();
for (auto i = entries.begin(); i != entries.end(); i++) {
i->second->setConfirmed(false);
}
}
static void eventProjectClosed(SpitRepo<SType> &repo, SpitRepo<SType> &remoteRepo) {
auto &entries = repo.getRepo();
for (auto i = entries.begin(); i != entries.end();) {
SType *ptrSType = i->second.get();
if (ptrSType->getCreatedByClient() == true) {
i++;
continue;
}
i = entries.erase(i);
}
// Remote
remoteRepo.clearEntries();
}
SType(string iD) {
mID = iD;
}
SType(string iD, string grpName, string name, bool fixed, bool projectIndependent, uint64_t delay, uint64_t duration) {
mConfirmed = false;
mID = iD;
ActionAssigned.set(false);
GroupName.set(grpName);
Name.set(name);
Fixed.set(fixed);
ProjectIndepended.set(projectIndependent);
DefaultDelay.set(delay);
DefaultDuration.set(duration);
}
private:
bool mConfirmed{};
string mID;
bool mCreatedByClient{}; // flag true = the SPITTyype is created by the client
// false = the SType is received from the server
public:
string getID() const { return mID; }
// This is used by the server and client to tell if the other side has registered the changes.
// @return true = other side has registered the changes.
bool getConfirmed() const { return mConfirmed; }
bool getCreatedByClient() const { return mCreatedByClient; }
void setCreatedByClient(bool createdByClient) { mCreatedByClient = createdByClient; }
// Set the content of the SType as received from the server
// @param p_ReportSType
// @return true = the SType is changed
// false = the SType is NOT changed, because it is not allowed to change.
bool setMessageOP(Message::ReportType &message) {
bool changeAllowed;
if ((mCreatedByClient == true) && (Fixed.get() == true)) {
changeAllowed = false;
} else {
changeAllowed = true;
}
// Confirmation should be changeable
if (mCreatedByClient) {
// Server reports a client created SType -> the type is confirmed
mConfirmed = true;
} else {
// type is NOT client created -> the client has to confirm the SPITtype
mConfirmed = message.getConfirmed();
}
if (changeAllowed == false) {
return false;
}
bool changed = false;
if (DefaultDelay.mValue != message.getDelay()) {
DefaultDelay.mValue = message.getDelay();
changed = true;
}
if (DefaultDuration.mValue != message.getDuration()) {
DefaultDuration.mValue = message.getDuration();
changed = true;
}
if (Fixed.mValue != message.getFixed()) {
Fixed.mValue = message.getFixed();
changed = true;
}
if (GroupName.mValue != message.getGroupName()) {
GroupName.mValue = message.getGroupName();
changed = true;
}
if (mID != message.getID()) {
mID = message.getID();
changed = true;
}
if (Name.mValue != message.getName()) {
Name.mValue = message.getName();
changed = true;
}
if (ProjectIndepended.mValue != message.getServerProjectIndepended()) {
ProjectIndepended.mValue = message.getServerProjectIndepended();
changed = true;
}
if (ServerRemote.mValue != message.getServerRemote()) {
ServerRemote.mValue = message.getServerRemote();
changed = true;
}
return changed;
}
void fillMessageOP(Message::ReportType &message) const {
message.setConfirmed(mConfirmed);
message.setDelay(DefaultDelay.mValue);
message.setDuration(DefaultDuration.mValue);
message.setFixed(Fixed.mValue);
message.setGroupName(GroupName.mValue);
message.setID(mID);
message.setName(Name.mValue);
message.setServerProjectIndepended(ProjectIndepended.mValue);
message.setServerRemote(ServerRemote.mValue);
}
void fillMessageOP(Message::RemoveType &message) const {
message.setID(mID);
}
// This is used by the server and client to tell if the other side has registered the changes.
// @param confirmed
// @return if mConfirmed has changed
bool setConfirmed(bool confirmed) {
if (mConfirmed == confirmed)
return false;
mConfirmed = confirmed;
return true;
}
};
}
-452
View File
@@ -1,452 +0,0 @@
#include "MyApp.h"
#include "Task.hpp"
#include "esp_log.h"
#include "Semaphore.hpp"
#include "Queue.hpp"
#include <list>
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.<br>
* @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");
}
-177
View File
@@ -1,177 +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.
*/
/*
* 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";
unordered_map<string, SAD_DetectedServer*> 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;
}
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;
}
void SAD_DetectedServer::cycleStart() {
for (auto i = s_DetectedServers.begin(); i != s_DetectedServers.end(); i++) {
i->second->startCycleSAD();
}
}
void SAD_DetectedServer::cycleEnd(I_SAD_Client& sadClient) {
list<SAD_DetectedServer*> o_LostServers;
list<SAD_DetectedServer*> o_NewServers;
list<SAD_DetectedServer*> 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();
}
/**
* 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<br>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]);
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
*/
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;
}
}
}
}
-554
View File
@@ -1,554 +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.
*/
/*
* 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<string, SPITObject*> SPITObject::s_SPITObjects;
unordered_map<string, SPITObject*> 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.<br>
* Throws an exception if no SPITObject is not found.<br>
* @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.<br>
* Throws an exception if no SPITObject is not found.<br>
* @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);
}
}
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;
}
}
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<string, SPITObject*>::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.<br>
* Throws an exception if p_Index is out of range.<br>
* @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<string, SPITObject*>::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<string, SPITObject*>::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.<br>
* Throws an exception if p_Index is out of range.<br>
* @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<string, SPITObject*>::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.<br>
* This should be called when the client has loaded a project.<br>
*/
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();
}
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;
}
SPITObject::~SPITObject() { }
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;
}
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::setID(string p_ID) {
m_ID = p_ID;
}
void SPITObject::setCreatedByClient(bool p_CreatedByClient) {
m_CreatedByClient = p_CreatedByClient;
}
/**
* 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 SPITObject::setConfirmed(bool p_Confirmed) {
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;
}
bool SPITObject::setRemark(string p_Remark) {
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;
}
bool SPITObject::setSPITTypeID(string p_SPITTypeID) {
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;
}
/**
* This is a virtual construct - ActionAssignedType is not implemented in the SPITProtocol.<br>
* This is used when an action is associated with a SPITType. <br>
* 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;
}
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;
}
bool SPITObject::setFixed(bool p_Fixed) {
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;
}
bool SPITObject::setFrameLength(long long p_FrameLength) {
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::setFrameFadeOutLength(long long p_FrameFadeOutLength) {
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;
}
bool SPITObject::setValueFactor(int p_ValueFactor) {
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;
}
bool SPITObject::setDelay(long long p_Delay) {
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;
}
-153
View File
@@ -1,153 +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.
*/
/*
* SPITPlayer describes a virtual SPIT Player.
* File: SPITPLayer.cpp
* Author: Hagi
*
* Created on 30. April 2019, 11:44
*/
#include "SPITPlayer.h"
#include <vector>
unordered_map<string, SPITPlayer*> 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;
}
}
void SPITPlayer::clearPlayers() {
;
vector<SPITPlayer*> 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;
}
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;
}
}
}
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<string, SPITPlayer::PlaySPITType*>* SPITPlayer::getPlaySPITTypes() {
return &m_PlaySPITTypes;
}
/**
*
* @param p_SPITObjectID
* @return true = new PlayObject added<br>
* 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;
}
void SPITPlayer::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;
}
}
}
}
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(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_Value = orig.getValue();
}
void SPITPlayer::PlaySPITType::startPlaySequence() {
m_IsPlayed = false;
m_IsNew = false;
m_Value = 0;
}
-288
View File
@@ -1,288 +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.
*/
/*
* Unix implementation of a SPITSocket.
*
* File: UnixSocket.cpp
* Author: Hagi
*
* Created on 12. April 2019, 15:58
*/
#include "SPITSocket.h"
#include "Task.hpp"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp/uuid.h"
#include <unistd.h>
#include <string>
using namespace std;
/**
* Creates socket. If there exist some, they will be closed.
* @return
*/
bool SPITSocket::createSocket_UDP() {
bool boolSuccess = true;
int intResult = -1;
int intOptionValue4 = 1;
// ip4
if (m_UDPSocketIP4 != INVALID_SOCKET) {
close(m_UDPSocketIP4);
m_UDPSocketIP4 = INVALID_SOCKET;
}
m_UDPSocketIP4 = socket(AF_INET, SOCK_DGRAM, 0);
if (m_UDPSocketIP4 == INVALID_SOCKET) {
boolSuccess = false;
} else {
intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_REUSEADDR, (void *)&intOptionValue4, sizeof(intOptionValue4));
}
if (intResult < 0) {
boolSuccess = false;
}
if (boolSuccess == true) {
struct timeval tv;
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));
// set the m_UDPSocketIP4 in NON BLOCKING mode because
// if the UDPSockets are in blocking mode the receiveMessage does not return in every constellation
// int intFlags;
// intFlags = fcntl(m_UDPSocketIP4, F_GETFL);
// 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));
}
return boolSuccess;
}
/**
* Binds the socket to the client's ip address and port. The socket option SO_REUSEADDR is set to true.
* @param p_ClientIP ip address of the client
* @param p_ClientPort port of the client.
* if p_Port == "0" any free port will be used
* @return -1 id bind fails, o if bind is ok
*
*/
int SPITSocket::bindSocket(string p_ServerIP, string p_ClientIP, string p_ClientPort) {
addrinfo *clientAI;
struct sockaddr_in *ptrIP4SocketAddress;
struct sockaddr_in o_IP4SocketAddress;
int intSocklen;
string stringClientPort;
if (p_ClientPort.length() <= 0)
stringClientPort = "0";
else
stringClientPort = p_ClientPort;
// int intResult = SOCKET_ERROR;
int intResult = 0;
if (getaddrinfo(p_ClientIP.data(), p_ClientPort.data(), NULL, &clientAI) != 0) {
return -1;
}
switch (clientAI->ai_family) {
case AF_INET:
if (m_UDPSocketIP4 == INVALID_SOCKET) {
break;
}
ptrIP4SocketAddress = reinterpret_cast<sockaddr_in *>(clientAI->ai_addr);
intSocklen = sizeof(*ptrIP4SocketAddress);
// copy the ptrIP4SocketAddress, may be not filled correct by getaddrinfo
memset(&o_IP4SocketAddress, 0, intSocklen);
o_IP4SocketAddress.sin_addr = ptrIP4SocketAddress->sin_addr;
o_IP4SocketAddress.sin_family = ptrIP4SocketAddress->sin_family;
// o_IP4SocketAddress.sin_zero = ptrIP4SocketAddress->sin_zero;
o_IP4SocketAddress.sin_port = ptrIP4SocketAddress->sin_port;
intResult = bind(m_UDPSocketIP4, (const sockaddr *)(ptrIP4SocketAddress), (socklen_t)intSocklen);
if (intResult < 0) {
break;
}
setBoundClientFamily(AF_INET);
if (intResult == 0) {
if (getsockname(m_UDPSocketIP4, (sockaddr *)ptrIP4SocketAddress, (socklen_t *)&intSocklen) != -1) {
setBoundClientPort(to_string((int)ptrIP4SocketAddress->sin_port));
}
}
break;
default:
setBoundClientFamily(0);
intResult = -1;
break;
}
freeaddrinfo(clientAI);
if (intResult == -1) {
setIsBound(false);
} else {
setIsBound(true);
}
return intResult;
}
/**
* Set whether the sockat are brodcast sockets or not. Set the sockopt SO_BROADCAST to 0 or 1
* @param p_Broadcast true SO_BROADCAST is set
* false = SO_BROADCAST is not set
* @return 0 = ok, -1 = error
*/
int SPITSocket::setBroadcast(bool p_Broadcast) {
int intResult;
int intOptionValue = 1;
u_char charOptionValue = 0x01;
// IP4
if (p_Broadcast) {
intOptionValue = 1;
} else {
intOptionValue = 0;
}
intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_BROADCAST, &intOptionValue, sizeof(int));
// intResult = setsockopt(m_UDPSocketIP4, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&charOptionValue, sizeof(charOptionValue));
return intResult;
}
/**
*
* @param p_InetFamily AF_INET or AF_INET6
* @param p_ServerIP the ip address of the server
* @param p_ServerPort the port of the server
* @param p_MessageBytes buffer containing the message
* @param p_MessageLength the length of the message
* @return -1 send fails
* 0 send is done
*/
int SPITSocket::sendMessageTo(int p_InetFamily, string p_ServerIP, string p_ServerPort, const char *p_MessageBytes, int p_MessageLength) {
if (m_UDPSocketIP4 == INVALID_SOCKET)
return -1;
struct addrinfo *ptrAddressInfo;
struct sockaddr_in *ptrIP4SocketAddress;
struct sockaddr_in o_IP4SocketAddress;
int intSocklen;
int intResult = -1;
// prepare AddressInfo
if (getaddrinfo(p_ServerIP.data(), p_ServerPort.data(), NULL, &ptrAddressInfo) != 0) {
return -1;
}
switch (ptrAddressInfo->ai_family) {
case AF_INET:
ptrIP4SocketAddress = reinterpret_cast<sockaddr_in *>(ptrAddressInfo->ai_addr);
intSocklen = sizeof(*ptrIP4SocketAddress);
if (m_UDPSocketIP4 != INVALID_SOCKET) {
// copy the ptrIP4SocketAddress, may be not filled correct by getaddrinfo
memset(&o_IP4SocketAddress, 0, intSocklen);
o_IP4SocketAddress.sin_addr = ptrIP4SocketAddress->sin_addr;
o_IP4SocketAddress.sin_family = ptrIP4SocketAddress->sin_family;
o_IP4SocketAddress.sin_port = ptrIP4SocketAddress->sin_port;
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);
}
freeaddrinfo(ptrAddressInfo);
}
break;
default:
intResult = -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<br>
* 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;
struct sockaddr_in o_IP4SocketAddress;
int intSocklen;
switch (p_InetFamily) {
case AF_INET:
if (m_UDPSocketIP4 == INVALID_SOCKET) {
break;
}
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);
if (intResult >= 0) {
if (p_ServerIP != NULL) {
char bufferIP4[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(o_IP4SocketAddress.sin_addr), bufferIP4, intSocklen);
*p_ServerIP = bufferIP4;
}
}
break;
}
return intResult;
}
SPITSocket::IPAddress SPITSocket::getAdaptersInfo() {
// iterate over active interfaces, and print out IPs
esp_netif_t *netif = NULL;
while ((netif = esp_netif_next_unsafe(netif)) != NULL) {
ESP_LOGI("SPIT", "Connected to %s", esp_netif_get_desc(netif));
esp_netif_ip_info_t ip;
ESP_ERROR_CHECK(esp_netif_get_ip_info(netif, &ip));
ESP_LOGI("SPIT", "- IPv4 address: " IPSTR ",", IP2STR(&ip.ip));
ESP_LOGI("SPIT", "- IPv4 netmask: " IPSTR ",", IP2STR(&ip.netmask));
char buffer[64];
sprintf(buffer, IPSTR, IP2STR(&ip.ip));
string stringIP4 = buffer;
sprintf(buffer, IPSTR, IP2STR(&ip.netmask));
string stringSubnet = buffer;
return {stringIP4, stringSubnet};
}
return {"0.0.0.0", "0.0.0.0"};
}
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 uu;
char uu_str[UUID_STR_LEN];
uuid_generate(uu);
uuid_unparse(uu, uu_str);
string stringGUID = uu_str;
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;;
}
-450
View File
@@ -1,450 +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.
*/
/*
* 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";
unordered_map<string, SPITType*> SPITType::s_SPITTypes;
unordered_map<string, SPITType*> 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.<br>
* Throws an exception if no SPITType is not found.<br>
* @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);
}
}
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.<br>
* Throws an exception if no SPITType is not found.<br>
* @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);
}
}
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<string, SPITType*>::iterator i = next(s_SPITTypes.begin(), p_Index);
ptrSPITType = i->second;
}
return ptrSPITType;
}
}
/**
* Returns a reference to the SPITType at position p_Index.<br>
* Throws an exception if p_Index is out of range.<br>
* @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<string, SPITType*>::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<string, SPITType*>::iterator i = next(s_SPITTypesRemote.begin(), p_Index);
ptrSPITType = i->second;
}
return ptrSPITType;
}
}
/**
* Returns a reference to the remote SPITType at position p_Index.<br>
* Throws an exception if p_Index is out of range.<br>
* @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<string, SPITType*>::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.<br>
* This should be called when the client has loaded a project.<br>
*/
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();
}
/*
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();
}
*/
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;
}
void SPITType::setCreatedByClient(bool p_CreatedByClient) {
m_CreatedByClient = p_CreatedByClient;
}
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.<br>
* This can used to setActionAssigned to all SPITObjects with this SPITType.<br>
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.<br>
* @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<br>
* 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);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+650
View File
@@ -0,0 +1,650 @@
#include "spit_client.hpp"
#include "esp_log.h"
#include "Queue.hpp"
namespace spit {
static const char *TAG = "SPIT";
static fos::Queue<vector<char>> incommingSpit(128);
/**
* 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.
*/
SClient::SClient(string name, string projName, ISocket &socket, Callbacks calls)
: ISadClient(),
mCallbacks(calls),
mProcessor(name, projName, getClientHostName(), createGUID(), calls,
{
.delay = [&](int ms){ return fos::Task::delayMs(ms); },
.sendMessage = [&](Message::OPPart &msg){ return sendMessage(msg); },
.parseMessage = [&](Message& msg) { parseMessage(msg); }
}
),
mSocket(socket) {
}
SClient::~SClient() {
stopServerAutoDetect();
disconnectInternal(Connection::None);
}
void SClient::clientProjectClose() {
if (mConnectionStatus == Connection::Ok) {
ESP_LOGI(TAG, " ... tidy up ressources");
Message::CloseProject closeSPITProject(mProcessor.getProjName());
if (sendMessage(closeSPITProject) < 0) {
ESP_LOGD(TAG, "Client could not send Client's ReportProject");
}
}
}
void SClient::clientProjectLoaded() {
// set confirmed = false for all SPITTypes and SPITObjects
mProcessor.resetConfirmedFlags();
if (mConnectionStatus == Connection::Ok) {
// send ReportProject to the server
Message::ReportProject reportSPITProject(mProcessor.getProjName(), mProcessor.getProjName());
reportSPITProject.setFramesPerSecond(0);
if (sendMessage(reportSPITProject) < 0) {
ESP_LOGD(TAG, "SPIT_CLient::clientProjectLoaded could not send Client's ReportProject");
}
// send RequestProjectTransfer
Message::RequestProjectTransfer sMRequestProjectTransfer;
if (sendMessage(sMRequestProjectTransfer) < 0) {
ESP_LOGD(TAG, "SPIT_CLient::clientProjectLoaded could not send RequestProjectTransfer");
}
}
}
//---------- ServerAutoDetection SAD -----------
/** Starts the autodetection of SPITServers in the local network. If a connection is tried, the autodetection should be stopped before.
* If a SPITServer is detected in the locale network an eventServerDetected occurs.
*/
void SClient::startServerAutoDetect() {
if (mDisconnectedByServer == true) {
// Server has previously disconnected -> do not start ServerAutodetect directly
fos::Task::delayMs(1000); // sleep a little to give the SPITServer time to clean up its stuff
}
SadDetectedServer::clearDetectedServers();
if (!sThread) {
sThread = new fos::TaskT<SClient &>(SClient::processSocketTask, *this, "spitSock", fos::Task::DefaultStackSize * 2);
}
mAbortSearch = false;
sStartSad.give();
}
/** Stops the auto detection of SPIT servers. */
void SClient::stopServerAutoDetect() {
mAbortSearch = true;
}
/**
* If a new server was found by the ServerAutoDetect mechanism, this function is called.
* To do so the SAD_Client ServerAutoDetect has to be startet - see SAD_Client::startServerAutoDetect.
* If a server can be reached via several IP addresses, the IP address is selected according to the following preference:
*/
void SClient::eventServerDetected(SadDetectedServer &server) {
mCallbacks.onServerEvent(ServerEvent::Detect, server);
// If a connection has been established and the connection is lost -> reconnect
if (_doReconnect) {
if (mServerID == server.getID()) {
stopServerAutoDetect();
ESP_LOGI(TAG, "reconnect to %s / %s", server.getIP().data(), server.getPort().data());
if (connect(server.getIP(), server.getPort(), server.getClientIP(), "0")) {
return;
}
}
}
// Stop auto detection because a suitable server was found
stopServerAutoDetect();
ESP_LOGI(TAG, "connect to %s / %s", server.getIP().data(), server.getPort().data());
if (!connect(server.getIP(), server.getPort(), server.getClientIP(), "0" /*= any port*/)) {
// connection message could not be sent -> better to restart AutoDetection
startServerAutoDetect();
}
}
/**
* If a SPITServer is not more found, this function is called.
* To do so the SAD_Client ServerAutoDetect has to be startet - see SAD_Client::startServerAutoDetect.
*/
void SClient::eventServerLost(SadDetectedServer &server) {
mCallbacks.onServerEvent(ServerEvent::Lost, server);
}
void SClient::eventServerChanged(SadDetectedServer &server) {
mCallbacks.onServerEvent(ServerEvent::Changed, server);
// tryConnection(detectedServer);
}
// void MyApp::tryConnection(const SadDetectedServer &detected) {
// // fetch the infoemations from the detected
// bool boolSuccess = false;
// bool boolPossibleConnect = checkPossibleConnection(detected);
// if (boolPossibleConnect == false)
// return;
// // --------------------------------------
// // You have three Options to use the detected server
// // OPTION 1 Use the first server found
// // OPTION 2 Use the first server found that fulfills specific conditions
// // OPTION 3 take a copy of the detected and do connection later
// // SadDetectedServer o_DetectedServer = detected; //this will call the copy constructor
// // ---------------------------------------
// // Excample use the first detected LOOPBACK server, means the server runs on the same computer as this client
// // if (detected.getIpIsLoopback() == true) { //omit the if condition if you want to use the first server found
// boolSuccess = false;
// // Stop auto detection because a suitable server was found
// stopServerAutoDetect();
// if (mSPIT_Client != nullptr) {
// mServerProjectName = detected.getProjectName();
// mServerIP = detected.getIP();
// #if defined(DEBUGOUTPUT)
// ESP_LOGD(TAG, "MySPITApp: connect to %s ", detected.getIP().data());
// #endif
// // Use the mBoardNumber as login name
// string stringLoginName = "";
// string stringLoginPassword = "";
// boolSuccess = mSPIT_Client->connect(detected.getIP(), detected.getPort(), detected.getClientIP(), stringLoginName, stringLoginPassword); // ClientPort = "0" meeans use any port
// }
// if (boolSuccess == false) {
// // connection message could not be sent
// // perhaps restart AutoDetection
// startServerAutoDetect();
// } else {
// // WAITING FOR CONNECTION ANSWER
// // If the Server is closed in the meantime no answer will return
// //-> connect(..) has started the watchdog
// }
// // } //Excample
// }
int SClient::sendMessage(Message::OPPart &opPart) {
if (mMessageNumberSend == 255)
mMessageNumberSend = 1;
else
mMessageNumberSend++;
opPart.setMessageNumber(mMessageNumberSend);
opPart.setServerInfoInHeader(mProcessor.getID(), mServerID);
int opFlag = opPart.getHeader()->getType();
try {
auto spitMessage = Message::createMessage(opPart);
if (spitMessage.empty()) {
return -1;
}
int intResult = mSocket.sendMessage(spitMessage.data(), spitMessage.size());
if (intResult < 0) {
ESP_LOGD(TAG, "client could not send message OPFlage: %d", opFlag);
}
return intResult;
} catch (...) {
ESP_LOGD(TAG, "Exception client OPFlag: %d", opFlag);
}
return -1;
}
bool SClient::startReceiveSPITMessages() {
if (!mSocket.getIsBound())
return false;
mStopReceiveMessages = false;
mThreadReceive = new fos::TaskT<SClient &>(receiveSpitMessage, *this, "receiveTask", fos::Task::DefaultStackSize, fos::Task::MAX_PRIORITY-3);
mThreadProcess = new fos::TaskT<SClient &>(processSpitMessage, *this, "processTask", fos::Task::DefaultStackSize);
return true;
}
void SClient::stopReceiveSPITMessages() {
mStopReceiveMessages = true;
}
void SClient::receiveSpitMessage(SClient &rM) {
char buffer[Message::MAX_MESSAGE_SIZE];
int rdLen;
while (rM.mStopReceiveMessages == false) {
rdLen = rM.mSocket.receiveMessage(buffer, Message::MAX_MESSAGE_SIZE, nullptr);
if (rdLen < 0) {
if (rM.mStopReceiveMessages) {
return;
}
continue;
}
auto vec = make_unique<vector<char>>(buffer, buffer + rdLen);
incommingSpit.enqueue(std::move(vec));
}
}
void SClient::processSpitMessage(SClient &rM) {
while (true) {
auto data = *incommingSpit.dequeue();
auto spitMsg = make_unique<Message>(data);
rM.checkParseMessage(move(spitMsg));
}
}
void SClient::resetMessageNumberReceived() {
mMessageNumberReceived = -1;
mProcessor.resetMessageNumberReceived();
}
void SClient::checkParseMessage(unique_ptr<Message> p_SPITMessage) {
answerWatchdog();
if (!p_SPITMessage || !p_SPITMessage->getHeader() || !p_SPITMessage->getOPPart()) {
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
return;
}
int msgNum = (int)(p_SPITMessage->getHeader()->getMessageNumber() & 0xFF);
if (msgNum == 0) {
parseMessage(*p_SPITMessage);
return;
}
if (mMessageNumberReceived < 0) {
mMessageNumberReceived = msgNum;
parseMessage(*p_SPITMessage);
return;
}
int intNextMessageNumber = mMessageNumberReceived + 1;
if (intNextMessageNumber > 255 || intNextMessageNumber < 1)
intNextMessageNumber = 1;
if (msgNum == intNextMessageNumber) {
mMessageNumberReceived = msgNum;
parseMessage(*p_SPITMessage);
mMessageNumberReceived = mProcessor.sendOvertakingMessage(mMessageNumberReceived);
} else {
// p_SPITMessage has overtaken another message
mProcessor.addOvertakingMessage(move(p_SPITMessage));
}
}
void SClient::parseMessage(Message& message) {
answerWatchdog();
if (!message.getHeader() || !message.getOPPart()) {
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
return;
}
switch (message.getType()) {
//----- Connection -----
case Message::ConnectAnswer::OPFLAG:
parseConnectAnswer(message.getAs<Message::ConnectAnswer>());
break;
case Message::Disconnect::OPFLAG:
parseDisconnect(message.getAs<Message::Disconnect>());
break;
case Message::Watchdog::OPFLAG:
parseWatchdog(message.getAs<Message::Watchdog>());
break;
case Message::WatchdogAnswer::OPFLAG:
parseWatchdogAnswer(message.getAs<Message::WatchdogAnswer>());
break;
default:
// pass object to SubProcessor
mProcessor.parseMessage(message);
}
}
//----- Connection ------
/**
* Tries to connect to a SPITServer.
* @param serverIP the ip address of the SPIT server
* @param serverPort the port number of the SPIT server
* @param clientIP the local IP address of the client
* @param clientPort the port number of the Client, if "0" the OS uses any possible port number
* @param loginName login user name (liveSHOW does not use this -> mayby ""
* @param loginPassword login user password (liveSHOW does not use this -> mayby ""
* @return false = an error has occured, true = the connect was sent to the server
*/
bool SClient::connect(string serverIP, string serverPort, string clientIP, string clientPort, string loginName, string loginPassword) {
disconnect();
mSocket.setConnectionParams(serverIP, serverPort, clientIP, clientPort);
if (mSocket.bindSocket(clientIP, clientPort) < 0) {
mStopReceiveMessages = true;
return false;
}
auto connMsg = mProcessor.createConnectMessage(serverIP, serverPort, loginName, loginPassword);
if (startReceiveSPITMessages() == false) {
mStopReceiveMessages = true;
return false;
}
resetMessageNumberReceived();
Connection intOldConnectionStatus = mConnectionStatus;
mConnectionStatus = Connection::TryConnection;
mCallbacks.onConnectionStatus(mServerID, mServerComputerName, mServerName, mServerStepTime,
mConnectionStatus, intOldConnectionStatus);
// sleep a little to make sure that the reception of the messages is started
fos::Task::delayMs(500);
if (sendMessage(*connMsg) < 0) {
mConnectionStatus = Connection::None;
mStopReceiveMessages = true;
return false;
}
return true;
}
/**
* Terminates the connection to the SPITServer.
*/
void SClient::disconnect() {
disconnectInternal(Connection::None);
}
void SClient::disconnectInternal(Connection cause) {
Connection intOldConnectionStatus = mConnectionStatus;
mConnectionStatus = cause;
switch (mConnectionStatus) {
case Connection::Lost:
break;
case Connection::None: {
Message::Disconnect sMDisconnect;
sendMessage(sMDisconnect);
} break;
case Connection::NoneServer:
break;
default:
break;
}
stopReceiveSPITMessages();
mCallbacks.onConnectionStatus(mServerID, mServerComputerName, mServerName, mServerStepTime,
mConnectionStatus, intOldConnectionStatus);
if (intOldConnectionStatus != Connection::None && intOldConnectionStatus != Connection::NoneServer) {
ESP_LOGI(TAG, "eventConnectionStatus %d ", (int)mConnectionStatus);
switch (mConnectionStatus) {
case SClient::Connection::None:
ESP_LOGD(TAG, "not connected");
break;
case SClient::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, mProcessor.getServerProjectID());
// Server has terminated the connection -> start a new game
// _doReconnect = false;
startServerAutoDetect();
break;
case SClient::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;
default:
break;
}
}
}
void SClient::parseConnectAnswer(Message::ConnectAnswer &message) {
if (message.getClientID() != mProcessor.getID())
return;
mServerID = message.getServerID();
mServerComputerName = message.getServerComputerName();
mServerName = message.getServerName();
mServerStepTime = message.getStepTime();
if (message.getConnected() == false) {
disconnectInternal(Connection::NoneServer);
} else {
mConnectionStatus = Connection::Ok;
mDisconnectedByServer = false;
ESP_LOGD(TAG, "connection established");
stopServerAutoDetect(); // normally you should stop the autodetection before you try a connection
// This is redundand
mStopReceiveMessages = false;
// Maybe you want to reconnect, see eventServerDetected(...)
// Here the connection is established -> don't reconnect at eventServerDetected(...)
// _doReconnect = false;
}
}
/**
* The SPIT server was closed
* @param message
*/
void SClient::parseDisconnect(Message::Disconnect &message) {
Connection intCauseDisconnect = Connection::NoneServer;
mDisconnectedByServer = true;
SClient::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.
* @param message
*/
void SClient::parseWatchdog(Message::Watchdog &message) {
Message::WatchdogAnswer o_WatchdogAnswer;
sendMessage(o_WatchdogAnswer);
}
/**
* The SPIT server sends a watchdog message at regular intervals. The client responds immediately with WatchdogAnswer
* Conversely, the client also sends a watchdog message at regular intervals and waits for a WatchdogAnswer message.
* This is used to check if the other side is still present.
* @param message
*/
void SClient::parseWatchdogAnswer(Message::WatchdogAnswer &message) {
answerWatchdog(); // is also done by parseMessage
}
void SClient::sendWatchdog() {
int intResult;
Message::Watchdog message;
intResult = sendMessage(message);
if (intResult < 0) {
ESP_LOGW("WDT", "Failed to send Watchdog msg");
}
}
void SClient::eventWatchdogLost() {
if (mConnectionStatus == Connection::TryConnection) {
disconnectInternal(Connection::NoneServer);
} else {
disconnectInternal(Connection::Lost);
}
}
void SClient::sendProject(SClient *p_PtrSPIT_Client) {
// int intResult;
// Message::StartProjectTransfer* ptrSMStartProjectTransfer;
// Message::EndProjectTransfer* ptrSMEndProjectTransfer;
// int intCount;
// SPITType* ptrSPITType;
// SObject* ptrSPITObject;
// //StartProjectTransfer
// NotifyStartProjectTransfer_Client* o_RunnableStart = new NotifyStartProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface());
// SPIT_Handler::addRunnable(o_RunnableStart);
// ptrSMStartProjectTransfer = new Message::StartProjectTransfer();
// intResult = p_PtrSPIT_Client->sendMessage(ptrSMStartProjectTransfer);
// if (intResult < 0) {
// return;
// }
// // mWatchdog->answerWatchdog();
// // {
// //send all listes SPITTypes
// // unique_lock<recursive_mutex> o_LockType(*SPITType::getMutex());
// intCount = SPITType::getSPITTypeCount();
// for (int i = 0; i < intCount; i++) {
// ptrSPITType = mSpitTypes.getEntry(i);
// if (ptrSPITType == nullptr) continue;
// if (ptrSPITType->getCreatedByClient() == false) continue;
// intResult = p_PtrSPIT_Client->sendTypeInternal(ptrSPITType);
// if (intResult < 0) return;
// // mWatchdog->answerWatchdog();
// this_thread::sleep_for(chrono::milliseconds(7));
// }
// // }
// // {
// // unique_lock<recursive_mutex> o_LockObject(*SObject::getMutex());
// intCount = mSpitObjects.getEntryCount();
// for (int i = 0; i < intCount; i++) {
// ptrSPITObject = mSpitObjects.getEntry(i);
// if (ptrSPITObject == nullptr) continue;
// if (ptrSPITObject->getCreatedByClient() == false) continue;
// intResult = p_PtrSPIT_Client->sendObjectInternal(ptrSPITObject);
// if (intResult < 0) return;
// // mWatchdog->answerWatchdog();
// this_thread::sleep_for(chrono::milliseconds(7));
// }
// // }
// //EndProjectTransfer
// ptrSMEndProjectTransfer = new Message::EndProjectTransfer();
// intResult = p_PtrSPIT_Client->sendMessage(ptrSMEndProjectTransfer);
// if (intResult < 0) {
// return;
// }
// // mWatchdog->answerWatchdog();
// NotifyEndProjectTransfer_Client* o_RunnableEnd = new NotifyEndProjectTransfer_Client(p_PtrSPIT_Client->getSPITClientInterface());
// SPIT_Handler::addRunnable(o_RunnableEnd);
// //Send act
}
SType *SClient::createTypeFixed(string iD, string group, string name, uint64_t delay, uint64_t duration) {
return mProcessor.createType(iD, group, name, delay, duration, true, true);
}
fos::Semaphore SClient::sStartSad;
unordered_map<string, unique_ptr<SadDetectedServer>> SadDetectedServer::sKnownServers;
void SClient::processSocketTask(SClient &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;
while (true) {
sStartSad.take();
bool searching = true;
instance.mSocket.setBroadcast(true);
string stringDatagram = SERVERAUTODETECT_PRECODE + SERVERAUTODETECT_SEPERATOR + SERVERAUTODETECT_TASKID;
int intDatagramLength = stringDatagram.length();
while (searching) {
if (instance.mAbortSearch)
break;
SadDetectedServer::resetServerFlags();
string stringBroadcastIP4 = instance.mSocket.mOwnIp.getBroadcastIP4();
instance.mSocket.sendMessageTo(stringBroadcastIP4, SERVERAUTODETECT_PORT, stringDatagram.data(), intDatagramLength);
{
// wait for 3000 milliseconds or
fos::Task::delayMs(3000);
}
bool receiving = true;
while (receiving) {
if (instance.mAbortSearch) {
break;
}
constexpr int SIZE = 512;
char buffer[SIZE + 1];
string stringServerIP;
int intReceivedByteCount = instance.mSocket.receiveMessage(buffer, SIZE, &stringServerIP);
if (intReceivedByteCount <= 0) {
break;
}
buffer[intReceivedByteCount] = '\0';
string stringMessage = buffer;
// Check if precode is ok
if (stringMessage.find(SERVERAUTODETECT_PRECODE.data(), 0) != 0) {
break;
}
int intIndex = 0;
int intOldPos = 0;
string stringPart;
string strParts[10];
while (intIndex < SadDetectedServer::PARAM_IP) {
int intPos = stringMessage.find(SERVERAUTODETECT_SEPERATOR.data(), intOldPos);
if (intPos == string::npos) {
stringPart = "";
} else {
stringPart = stringMessage.substr(intOldPos, intPos - intOldPos);
intOldPos = intPos + SERVERAUTODETECT_SEPERATOR.length();
}
strParts[intIndex] = stringPart;
intIndex++;
}
auto server = make_unique<SadDetectedServer>(
strParts[SadDetectedServer::PARAM_NAME],
strParts[SadDetectedServer::PARAM_ID],
strParts[SadDetectedServer::PARAM_COMPUTERNAME],
stringServerIP,
strParts[SadDetectedServer::PARAM_PORT],
strParts[SadDetectedServer::PARAM_CLIENTIP],
strParts[SadDetectedServer::PARAM_ADDITIONS],
strParts[SadDetectedServer::PARAM_SERVERPROJECTNAME]);
SadDetectedServer::addDetectedServer(move(server));
}
fos::Task::delayMs(100);
SadDetectedServer::evaluateDetectedServers(instance);
instance.mAbortSearch = false;
// if(instance.mConnectionStatus == Connection::Ok) break;
fos::Task::delayMs(1000);
}
instance.mSocket.setBroadcast(false);
ESP_LOGW(TAG, "Finished searching");
ESP_LOGW(TAG, "Start working");
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;
// }
// if (time > nextWdCheck) {
// if (!instance.sAnswered) {
// ESP_LOGW(TAG, "TimeOut");
// instance.eventWatchdogLost();
// break;
// }
// nextWdCheck = nextWdTrigger + WATCHDOGTIME;
// }
fos::Task::delayMs(25);
// if (instance.mStopReceiveMessages)
// break;
}
}
}
}
File diff suppressed because it is too large Load Diff
+202
View File
@@ -0,0 +1,202 @@
#include "spit_object.hpp"
#include "spit_socket.hpp"
#include "esp_log.h"
namespace spit {
/**
* clears all unconfirmed SObjects not created by this SPIT_Client.
*/
void SObject::clearUnconfirmedObjects(SpitRepo<SObject> &repo) {
auto &entries = repo.getRepo();
for (auto i = entries.begin(); i != entries.end();) {
SObject *ptrSObject = i->second.get();
if (ptrSObject->getCreatedByClient() == false && ptrSObject->getConfirmed() == false) {
i = entries.erase(i);
} else {
i++;
}
}
}
void SObject::eventProjectClosed(SpitRepo<SObject> &repo, SpitRepo<SObject> &remoteRepo) {
auto &entries = repo.getRepo();
for (auto i = entries.begin(); i != entries.end(); ) {
SObject *ptrSObject = i->second.get();
if (ptrSObject->getCreatedByClient() == true) {
i++;
continue;
}
i = entries.erase(i);
}
// Remote
remoteRepo.clearEntries();
}
/**
* sets confirmed = false for all SObjects.
* This should be called when the client has loaded a project.
*/
void SObject::setConfirmedFalse(SpitRepo<SObject> &repo) {
auto &entries = repo.getRepo();
for (auto i = entries.begin(); i != entries.end(); i++) {
i->second->setConfirmed(false);
}
}
bool SObject::setMessageOP(Message::ReportObject *message) {
bool changeAllowed;
if ((mCreatedByClient == true) && (Fixed.mValue == true)) {
changeAllowed = false;
} else {
changeAllowed = true;
}
// Confirmation should be changable
if (mCreatedByClient) {
// Server reports a client created SPITType -> the type is confirmed
mConfirmed = true;
} else {
// type is NOT client created -> the client has to confirm the SPITtype
mConfirmed = message->getConfirmed();
}
if (changeAllowed == false) {
return false;
}
bool changed = false;
if (Delay.mValue != message->getDelay()) {
Delay.mValue = message->getDelay();
changed = true;
}
if (Duration.mValue != message->getDuration()) {
Duration.mValue = message->getDuration();
changed = true;
}
if (Fixed.mValue != message->getFixed()) {
Fixed.mValue = message->getFixed();
changed = true;
}
if (FrameFadeInLength.mValue != message->getFrameFadeInLength()) {
FrameFadeInLength.mValue = message->getFrameFadeInLength();
changed = true;
}
if (FrameFadeOutLength.mValue != message->getFrameFadeOutLength()) {
FrameFadeOutLength.mValue = message->getFrameFadeOutLength();
changed = true;
}
if (FrameLength.mValue != message->getFrameLength()) {
FrameLength.mValue = message->getFrameLength();
changed = true;
}
if (FrameStart.mValue != message->getFrameStart()) {
FrameStart.mValue = message->getFrameStart();
changed = true;
}
if (Remark.mValue != message->getRemark()) {
Remark.mValue = message->getRemark();
changed = true;
}
if (mID != message->getID()) {
mID = message->getID();
changed = true;
}
if (Name.mValue != message->getName()) {
Name.mValue = message->getName();
changed = true;
}
if (SPITTypeID.mValue != message->getSPITTypeID()) {
SPITTypeID.mValue = message->getSPITTypeID();
changed = true;
}
if (ServerParams.mValue != message->getServerParams()) {
ServerParams.mValue = message->getServerParams();
changed = true;
}
if (ServerRemote.mValue != message->getServerRemote()) {
ServerRemote.mValue = message->getServerRemote();
changed = true;
}
if (Track.mValue != message->getTrack()) {
Track.mValue = message->getTrack();
changed = true;
}
if (mValueFactor != message->getValueFactor()) {
mValueFactor = message->getValueFactor();
changed = true;
}
if (mValueUse != message->getValueUse()) {
mValueUse = message->getValueUse();
changed = true;
}
return changed;
}
void SObject::fillMessageOP(Message::ReportObject &message) {
message.setActionAssigned(getActionAssigned()); // Action can be assigned to type or to this object
message.setConfirmed(mConfirmed);
message.setDelay(Delay.mValue);
message.setDuration(Duration.mValue);
message.setFixed(Fixed.mValue);
message.setFrameFadeInLength(FrameFadeInLength.mValue);
message.setFrameFadeOutLength(FrameFadeOutLength.mValue);
message.setFrameLength(FrameLength.mValue);
message.setFrameStart(FrameStart.mValue);
message.setID(mID);
message.setName(Name.mValue);
message.setRemark(Remark.mValue);
message.setSPITTypeID(SPITTypeID.mValue);
message.setServerParams(ServerParams.mValue);
message.setServerRemote(ServerRemote.mValue);
message.setTrack(Track.mValue);
message.setValueFactor(mValueFactor);
message.setValueUse(mValueUse);
}
void SObject::fillMessageOP(Message::RemoveObject &message) {
message.setID(mID);
}
/**
* This is used by the server and client to tell if the other side has registered the changes.
* @param p_Confirmed
* @return if mConfirmed has changed
*/
bool SObject::setConfirmed(bool p_Confirmed) {
if (mConfirmed == p_Confirmed)
return false;
mConfirmed = p_Confirmed;
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 SObject with the SPITType.
* @return true = an action is assigned for the SPITType.
*/
bool SObject::setActionAssignedType(bool p_ActionAssigned) {
if (mActionAssignedType == p_ActionAssigned)
return false;
bool oldActionAssigend = getActionAssigned();
mActionAssignedType = p_ActionAssigned;
if (getActionAssigned() == oldActionAssigend)
return false;
mConfirmed = false;
return true;
}
bool SObject::setActionAssigned(bool p_ActionAssigned) {
if (mActionAssigned == p_ActionAssigned)
return false;
bool oldActionAssigend = getActionAssigned();
mActionAssigned = p_ActionAssigned;
if (getActionAssigned() == oldActionAssigend)
return false;
mConfirmed = false;
return true;
}
}
+93
View File
@@ -0,0 +1,93 @@
#include "spit_player.hpp"
#include "esp_log.h"
#include <memory>
#include <vector>
using namespace std;
namespace spit {
unordered_map<string, unique_ptr<SPlayer>> SPlayer::sSpitPlayers;
SPlayer &SPlayer::getSPITPlayer(string playerID) {
auto i = sSpitPlayers.find(playerID);
if (i == sSpitPlayers.end()) {
sSpitPlayers[playerID] = make_unique<SPlayer>(playerID);
}
return *sSpitPlayers.at(playerID);
}
SPlayer::SPlayer(string playerID) {
mId = playerID;
}
SPlayer::~SPlayer() {
mPlaySPITTypes.clear();
}
/**
*
* @param p_SPITObjectID
* @return true = new PlayObject added<br>
* false = PlayObject exists
*/
SPlayer::PlayType *SPlayer::addTypePlaying(string spitTypeID) {
PlayType *ptrPlaySPITType;
auto i = mPlaySPITTypes.find(spitTypeID);
if (i == mPlaySPITTypes.end()) {
auto playSpitType = make_unique<PlayType>(this, spitTypeID);
ptrPlaySPITType = playSpitType.get();
mPlaySPITTypes[spitTypeID] = move(playSpitType);
} else {
ptrPlaySPITType = i->second.get();
}
ptrPlaySPITType->setIsPlayed(true);
return ptrPlaySPITType;
}
void SPlayer::startPlaySequence() {
for (auto i = mPlaySPITTypes.begin(); i != mPlaySPITTypes.end(); i++) {
PlayType *ptrPlaySPITType = i->second.get();
ptrPlaySPITType->startPlaySequence();
}
}
void SPlayer::endPlaySequence() {
for (auto i = mPlaySPITTypes.begin(); i != mPlaySPITTypes.end();) {
if (i->second.get()->getIsPlayed() == false) {
i = mPlaySPITTypes.erase(i);
} else {
++i;
}
}
}
SPlayer::PlayType::PlayType(SPlayer *p_SPITPlayer, string spitTypeID) {
mIsNew = true;
mSpitTypeID = spitTypeID;
mPlayerID = p_SPITPlayer->getID();
mPlayerName = p_SPITPlayer->getName();
startPlaySequence();
mIsNew = true;
}
SPlayer::PlayType::PlayType(const PlayType &orig) {
mSpitTypeID = orig.getSPITTypeID();
mIsPlayed = orig.getIsPlayed();
mIsNew = orig.getIsNew();
mPlayerID = orig.getPlayerID();
mPlayerName = orig.getPlayerName();
mPlayerRuns = orig.getPlayerIsRunning();
mValue = orig.getValue();
}
void SPlayer::PlayType::startPlaySequence() {
mIsPlayed = false;
mIsNew = false;
mValue = 0;
}
}
+745
View File
@@ -0,0 +1,745 @@
#include "spit_processor.hpp"
#include "esp_log.h"
namespace spit {
static const char *TAG = "SPIT";
/**
* Create a new SPIT_client instance, should be done once by the user app.
* @param p_SPITClientInterface the user app should implement the SPIT_ClientInterface.
*/
SProcessor::SProcessor(string name, string projName, string hostName, string guid, Callbacks calls, InternalCallbacks intern)
: mCallbacks(calls),
mInternCallbacks(intern),
mName(name),
mGuid(guid),
mProjName(projName),
mComputerName(hostName) {
}
SProcessor::~SProcessor() {
}
unique_ptr<Message::Connect> SProcessor::createConnectMessage(string serverIP, string serverPort, string loginName, string loginPassword) {
auto msg = make_unique<Message::Connect>(getComputerName(), mName);
msg->setLoginName(loginName);
msg->setLoginPassword(loginPassword);
msg->setServerIP(serverIP);
if (serverPort.length() <= 0) {
serverPort = "0";
}
int intServerPort = stoi(serverPort);
msg->setServerPort(intServerPort);
return msg;
}
/**
* Virtual construct - means actionAssigned for SPITTypes is is not implemented in SPITProtocol.
* This can used to setActionAssigned to all SPITObjects with this SPITType.
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.
* This tells the server not what action is done, but it tells the server that there is an action.
* @param typeId the id of the SPITType
* @param actionAssigned
*/
void SProcessor::setActionType(string typeId, bool actionAssigned) {
SType *spitType = mSpitTypes.getEntry(typeId);
if (spitType == nullptr)
return;
if (spitType->ActionAssigned.set(actionAssigned)) {
sendTypeInternal(*spitType);
for (auto &[key, value] : mSpitObjects.getRepo()) {
if (value->SPITTypeID.get() == spitType->getID()) {
if (value->setActionAssignedType(actionAssigned) == true) {
sendObjectInternal(value.get());
}
}
}
}
}
/** This should be called if the user wants to associate/remove an action with a SPITObject. */
void SProcessor::setActionObject(string spitObjId, bool actionAssigned) {
SObject *spitObject = mSpitObjects.getEntry(spitObjId);
if (spitObject == nullptr)
return;
if (spitObject->setActionAssigned(actionAssigned) == true) {
sendObjectInternal(spitObject);
}
}
std::vector<char> SProcessor::createMessage(Message::OPPart &opPart) {
if (mMessageNumberSend == 255)
mMessageNumberSend = 1;
else
mMessageNumberSend++;
opPart.setMessageNumber(mMessageNumberSend);
opPart.setServerInfoInHeader(mGuid, mServerID);
int opFlag = opPart.getHeader()->getType();
try {
return Message::createMessage(opPart);
} catch (...) {
ESP_LOGD(TAG, "Exception client OPFlag: %d", opFlag);
}
return {};
}
void SProcessor::resetMessageNumberReceived() {
mMessageNumberReceived = -1;
mOvertakingMessages.clear();
}
void SProcessor::checkParseMessageData(vector<char> data) {
auto message = make_unique<Message>(data);
// answerWatchdog();
if (!message->getHeader() || !message->getOPPart()) {
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
return;
}
int msgNum = (int)(message->getHeader()->getMessageNumber() & 0xFF);
if (msgNum == 0) {
parseMessage(*message);
return;
}
if (mMessageNumberReceived < 0) {
mMessageNumberReceived = msgNum;
parseMessage(*message);
return;
}
int msgNumNext = mMessageNumberReceived + 1;
if (msgNumNext > 255 || msgNumNext < 1)
msgNumNext = 1;
if (msgNum == msgNumNext) {
mMessageNumberReceived = msgNum;
parseMessage(*message);
mMessageNumberReceived = sendOvertakingMessage(mMessageNumberReceived);
} else {
// message has overtaken another message
addOvertakingMessage(move(message));
}
}
void SProcessor::addOvertakingMessage(unique_ptr<Message> message) {
if (!message) {
return;
}
if (mOvertakingMessages.size() > MAX_OVERTAKING_SPIT_MESSAGES) {
ESP_LOGD(TAG, "Client receiveing: perhaps message lost !!!!!");
}
int intMessageNumber = (int)(message->getHeader()->getMessageNumber() & 0xFF);
for (auto it = mOvertakingMessages.begin(); it != mOvertakingMessages.end(); ++it) {
const auto &overtaking = *it;
int intOvertakingMessageNumber = (int)(overtaking->getHeader()->getMessageNumber() & 0xFF);
if (intMessageNumber < intOvertakingMessageNumber) {
mOvertakingMessages.insert(it, move(message));
return;
}
}
mOvertakingMessages.push_back(move(message));
}
int SProcessor::sendOvertakingMessage(int msgNumRec) {
// check overtaking messages
auto it = mOvertakingMessages.begin();
while (mOvertakingMessages.size() > 0) {
int msgNumNext = msgNumRec + 1;
if (msgNumNext > 255 || msgNumNext < 1)
msgNumNext = 1;
auto &overtakingMessage = *it;
int msgNum = (int)(overtakingMessage->getHeader()->getMessageNumber() & 0xFF);
if (msgNum == msgNumNext) {
msgNumRec = msgNum;
mInternCallbacks.parseMessage(*overtakingMessage);
mOvertakingMessages.erase(it);
it = mOvertakingMessages.begin();
} else {
break;
}
}
return msgNumRec;
}
void SProcessor::parseMessage(Message &message) {
// answerWatchdog();
if (!message.getHeader() || !message.getOPPart()) {
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
return;
}
switch (message.getType()) {
//----- Connection -----
case Message::ReportProject::OPFLAG:
parseReportProject(message.getAs<Message::ReportProject>());
break;
//----- SPIT Project -----
case Message::StartProjectTransfer::OPFLAG:
parseStartProjectTransfer(message.getAs<Message::StartProjectTransfer>());
break;
case Message::CloseProject::OPFLAG:
parseCloseProject(message.getAs<Message::CloseProject>());
break;
case Message::RequestProjectTransfer::OPFLAG:
parseRequestProjectTransfer(message.getAs<Message::RequestProjectTransfer>());
break;
case Message::EndProjectTransfer::OPFLAG:
parseEndProjectTransfer(message.getAs<Message::EndProjectTransfer>());
break;
//----- SPIT Types ------
case Message::ReportType::OPFLAG:
parseReportType(message.getAs<Message::ReportType>());
break;
case Message::RemoveType::OPFLAG:
parseRemoveType(message.getAs<Message::RemoveType>());
//----- SPIT Objects ------
break;
case Message::ReportObject::OPFLAG:
parseReportObject(message.getAs<Message::ReportObject>());
break;
case Message::RemoveObject::OPFLAG:
parseRemoveObject(message.getAs<Message::RemoveObject>());
break;
//----- Play SPIT Objects ------
case Message::PlayStart::OPFLAG:
parsePlayStart(message.getAs<Message::PlayStart>());
break;
case Message::PlayObject::OPFLAG:
parsePlayObject(message.getAs<Message::PlayObject>());
break;
case Message::PlayEnd::OPFLAG:
parsePlayEnd(message.getAs<Message::PlayEnd>());
break;
case Message::ReportPlayStatus::OPFLAG:
parseReportPlayStatus(message.getAs<Message::ReportPlayStatus>());
break;
default:
ESP_LOGD(TAG, "Client::parseMessage: Unknown Message");
}
}
//----- SPIT Project ------
void SProcessor::parseReportProject(Message::ReportProject &message) {
ESP_LOGD(TAG, "parse ReportProject");
mServerProjectID = message.getProjectID();
mServerProjectName = message.getProjectName();
mServerFramesPerSecond = message.getFramesPerSecond();
mCallbacks.onProjectUpdate(ProjUpdate::ServerLoaded, mServerProjectID);
// Set all SPITTypes and SPITObjects confirmed = false
SType::setConfirmedFalse(mSpitTypes);
SObject::setConfirmedFalse(mSpitObjects);
// Send RequestProjectTransfer
Message::RequestProjectTransfer sMRequestProjectTransfer;
if (mInternCallbacks.sendMessage(sMRequestProjectTransfer) < 0) {
ESP_LOGD(TAG, "Client::parseReportProject could not send RequestProjectTransfer");
}
// todo Don't send the ReportProject here it should be sended after parseEndProjectTransfer
// Send client's ReportProject
Message::ReportProject reportProject(mProjName, mProjName);
reportProject.setFramesPerSecond(0);
if (mInternCallbacks.sendMessage(reportProject) < 0) {
ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
}
}
void SProcessor::parseCloseProject(Message::CloseProject &p_CloseSPITProject) {
ESP_LOGD(TAG, "parse CloseProject");
string stringProjectID;
mCallbacks.onProjectUpdate(ProjUpdate::ServerClosed, p_CloseSPITProject.getProjectID());
SPlayer::clearPlayers();
}
void SProcessor::parseRequestProjectTransfer(Message::RequestProjectTransfer &message) {
ESP_LOGD(TAG, "parse RequestProjectTransfer");
// StartProjectTransfer
Message::StartProjectTransfer sMStartProjectTransfer;
if (mInternCallbacks.sendMessage(sMStartProjectTransfer) < 0) {
return;
}
// send all listes SPITTypes
for (const auto &[key, value] : mSpitTypes.getRepo()) {
sendTypeInternal(*value);
mInternCallbacks.delay(10);
}
for (auto &[key, value] : mSpitObjects.getRepo()) {
sendObjectInternal(value.get());
mInternCallbacks.delay(10);
}
// EndProjectTransfer
Message::EndProjectTransfer sMEndProjectTransfer;
mInternCallbacks.sendMessage(sMEndProjectTransfer);
}
void SProcessor::parseStartProjectTransfer(Message::StartProjectTransfer &message) {
mCallbacks.onProjectUpdate(ProjUpdate::StartTransfer, mServerProjectID);
}
void SProcessor::parseEndProjectTransfer(Message::EndProjectTransfer &message) {
SObject::clearUnconfirmedObjects(mSpitObjects);
mCallbacks.onProjectUpdate(ProjUpdate::EndTransfer, mServerProjectID);
// Send Message::ReportProject after the mSPITClientInterface is notfied of EndProjectTransfer
Message::ReportProject reportSPITProject(mProjName, mProjName);
reportSPITProject.setFramesPerSecond(0);
if (mInternCallbacks.sendMessage(reportSPITProject) < 0) {
ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
}
}
void SProcessor::parseReportType(Message::ReportType &message) {
ESP_LOGD(TAG, "parse ReportType ID %s Name %s", message.getID().c_str(), message.getName().c_str());
SType *sType;
bool isNew = false;
bool isChanged = false;
if (message.getServerRemote() == false) {
sType = mSpitTypes.getEntry(message.getID());
if (sType == nullptr) {
// The user's app may veto the SPITType
bool createdByClient = false;
if (sType) {
createdByClient = sType->getCreatedByClient();
}
if (mCallbacks.onCheckSpitTypeVeto(false, createdByClient) == false) {
ESP_LOGW(TAG, "TypeVeto %s / %s", message.getID().c_str(), message.getName().c_str());
return;
}
auto spitType = make_unique<SType>(message.getID());
sType = spitType.get();
mSpitTypes.addEntry(move(spitType));
isNew = true;
}
} else {
sType = mRemoteSpitTypes.getEntry(message.getID());
if (sType == nullptr) {
auto spitType = make_unique<SType>(message.getID());
sType = spitType.get();
mRemoteSpitTypes.addEntry(move(spitType));
isNew = true;
}
}
if (!sType->setMessageOP(message)) {
// SPITType is not changable -> send back to the server
sendTypeInternal(*sType);
return;
}
auto eventType = isNew ? ObjectEvent::Created : ObjectEvent::Changed;
// add or change SPITType
mCallbacks.onSpitType(eventType, sType->ServerRemote.get(), *sType);
if (sType != nullptr) {
if (sType->setConfirmed(true) == true || isChanged == true) {
sendTypeInternal(*sType);
}
}
}
void SProcessor::parseRemoveType(Message::RemoveType &message) {
ESP_LOGD(TAG, "parse RemoveType %s", message.getID().c_str());
bool isRemote = false;
string sTypeID = message.getID();
SType *sType = mRemoteSpitTypes.getEntry(sTypeID);
if (!sType) {
isRemote = true;
} else {
sType = mSpitTypes.getEntry(sTypeID);
if (!sType) {
isRemote = false;
} else {
// No SType with sTypeID is listet
return;
}
}
if (sType->getCreatedByClient() && sType->Fixed.get()) {
// the SPITyte is created by client himself and it is fixed -> don't remove the SType!!
// Send the SPITTyp back to the server
sendTypeInternal(*sType);
return;
}
mCallbacks.onSpitType(ObjectEvent::Deleted, isRemote, *sType);
if (isRemote == false) {
mSpitTypes.removeEntry(*sType);
} else {
mRemoteSpitTypes.removeEntry(*sType);
}
}
/**
* Change an existing SPIT_Type.
* @param p_SPITType the SPITType vont
* @return true = changed, false = not changed maybe p_SPITType is NULL or the SPITType doesn't exists
*/
bool SProcessor::changeType(SType *sType) {
if (sType == nullptr)
return false;
SType *mod = mSpitTypes.getEntry(sType->getID());
if (mod == nullptr)
return false;
mod->DefaultDelay.set(sType->DefaultDelay.get());
mod->DefaultDuration.set(sType->DefaultDuration.get());
mod->Fixed.set(sType->Fixed.get());
mod->GroupName.set(sType->GroupName.get());
mod->Name.set(sType->Name.get());
mod->ProjectIndepended.set(sType->ProjectIndepended.get());
mCallbacks.onSpitType(ObjectEvent::Changed, false, *mod);
sendTypeInternal(*mod);
return true;
}
/**
* If a client has removed a SPITType where id == p_SPITTypeID, it should send it to the server.
* The corresponding SPITType if listet in SPITType will be deleted.
* An eventRemoveSPITType will occur.
* If a connection to a SPITServer is established, the SPITServer may dicard the deletion an an eventSPITType will occur
* -> the SPITType will be listet again.
* @param p_SPITType the id of the SPITType ro remove
* @return 0 = is sended, -1 = is not sended
*/
int SProcessor::removeType(string sType) {
if (sType.length() <= 0)
return -1;
SType *mod = mSpitTypes.getEntry(sType);
if (mod == nullptr)
return -1;
Message::RemoveType sMRemoveSPITType;
mod->fillMessageOP(sMRemoveSPITType);
mCallbacks.onSpitType(ObjectEvent::Deleted, false, *mod);
mSpitTypes.removeEntry(*mod);
return mInternCallbacks.sendMessage(sMRemoveSPITType);
}
SType *SProcessor::createType(string id, string groupName, string name, uint64_t delay, uint64_t duration, bool fixed, bool projIndipendent) {
bool boolNew;
SType *sType = mSpitTypes.getEntry(id);
if (sType == nullptr) {
auto spitType = make_unique<SType>(id, groupName, name, fixed, projIndipendent, delay, duration);
sType = spitType.get();
mSpitTypes.addEntry(move(spitType));
sType->setCreatedByClient(true);
boolNew = true;
} else {
sType->GroupName.set(groupName);
sType->Name.set(name);
sType->Fixed.set(fixed);
sType->ProjectIndepended.set(projIndipendent);
sType->DefaultDelay.set(delay);
sType->DefaultDuration.set(duration);
boolNew = false;
}
auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed;
mCallbacks.onSpitType(eventType, false, *sType);
sendTypeInternal(*sType);
return sType;
}
/**
* If a client has changed a SPITType, it should send it to the server to transmit the changes.
* If the SPITType is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the changes.
* @param sType the pointer to the changed SPITType
* @return 0 = is sended, -1 = is not sended
*/
int SProcessor::sendTypeInternal(SType &sType) {
Message::ReportType reportType;
sType.fillMessageOP(reportType);
return mInternCallbacks.sendMessage(reportType);
}
//----- SPIT Objects ------
void SProcessor::parseReportObject(Message::ReportObject &message) {
ESP_LOGD(TAG, "parse ReportObject %s", message.getID().c_str());
SObject *sObject;
SType *sType;
bool isNew = false;
bool isRemote = false;
bool isChanged = false;
{
ESP_LOGD(TAG, "parse ReportObject %s / %s", message.getID().c_str(), message.getName().c_str());
if (message.getServerRemote() == false) {
isRemote = false;
sObject = mSpitObjects.getEntry(message.getID());
sType = mSpitTypes.getEntry(message.getSPITTypeID());
if (sType == nullptr) {
// No associated SPITType found
if (sObject != nullptr) {
// SpitObject exists but has no corresponding SPITType -> remove the SPITObject without sending a message
// Maybe the SPITObject has changed the SPITTypeID to a SPITTypeID of another board
mSpitObjects.removeEntry(*sObject);
}
return;
}
bool isKnownType = sType != nullptr;
if (sObject == nullptr) {
// The user's app my veto the SPITType
if (mCallbacks.onCheckSpitObjectVeto(isKnownType) == false) {
ESP_LOGW(TAG, "ObjectVeto %s / %s", message.getID().c_str(), message.getName().c_str());
return;
}
auto spitObj = make_unique<SObject>(message.getID());
sObject = spitObj.get();
mSpitObjects.addEntry(move(spitObj));
isNew = true;
} else {
// The user's app my veto the SPITType
if (mCallbacks.onCheckSpitObjectVeto(isKnownType) == false) {
// SpitObject exists and User APp denied the SPITObject -> remove the SPITObject without sending a message
mSpitObjects.removeEntry(*sObject);
ESP_LOGW(TAG, "TypeVeto %s / %s", message.getID().c_str(), message.getName().c_str());
return;
}
}
} else {
isRemote = true;
sObject = mRemoteSpitObjects.getEntry(message.getID());
sType = mRemoteSpitTypes.getEntry(message.getSPITTypeID());
if (sType == nullptr) {
// No associated SPITType found
return;
}
if (sObject == nullptr) {
auto spitObj = make_unique<SObject>(message.getID());
sObject = spitObj.get();
mRemoteSpitObjects.addEntry(move(spitObj));
isNew = true;
}
}
if (!sObject->setMessageOP(&message)) {
ESP_LOGE(TAG, "Change not allowed %s", sObject->getID().c_str());
// setMessageOP error - the SPITObject can't be changed, it may be fixed and crated by this client
sendObjectInternal(sObject);
return;
}
if (isRemote == false) {
// set the virtual action assignment
sObject->setActionAssignedType(sType->ActionAssigned.get());
}
auto eventType = isNew ? ObjectEvent::Created : ObjectEvent::Changed;
mCallbacks.onSpitObject(eventType, isRemote, *sType, *sObject);
if (sObject->setConfirmed(true) == true || isChanged == true) {
// Confirmation has changed
sendObjectInternal(sObject);
}
}
}
void SProcessor::parseRemoveObject(Message::RemoveObject &message) {
ESP_LOGD(TAG, "parse RemoveObject %s", message.getID().c_str());
SObject *sObject = mRemoteSpitObjects.getEntry(message.getID());
if (sObject != nullptr) {
SType *sType = mRemoteSpitTypes.getEntry(sObject->SPITTypeID.get());
if (sType != nullptr) {
mCallbacks.onSpitObject(ObjectEvent::Deleted, true, *sType, *sObject);
}
mRemoteSpitObjects.removeEntry(*sObject);
} else {
// call removeObject, this will notify the server that the object is removed
removeObject(message.getID());
}
}
int SProcessor::sendObjectInternal(SObject *sObject) {
if (sObject == nullptr)
return -1;
Message::ReportObject reportObject;
sObject->fillMessageOP(reportObject);
return mInternCallbacks.sendMessage(reportObject);
}
/**
* When the client changes an existing SPITObject (normally the client should not do this), then he should send the changes to the SPITServer.
* An eventSPITObject occurs.
* The SPITServer may discard the changes and a second eventSPITObject occurs to correct the changes.
* @param obj the pointer to the changed SPITObject.
* @return 0 = sended, -1 = not sended
*/
bool SProcessor::changeObject(SObject *sObject) {
if (sObject == nullptr)
return false;
SObject *mod = mSpitObjects.getEntry(sObject->getID());
if (mod == nullptr)
return false;
SType *sType = mSpitTypes.getEntry(sObject->getID());
if (mod == nullptr)
return false;
mod->setActionAssigned(sObject->getActionAssigned());
mod->Delay.set(sObject->Delay.get());
mod->Duration.set(sObject->Delay.get());
mod->Fixed.set(sObject->Fixed.get());
mod->FrameFadeInLength.set(sObject->FrameFadeInLength.get());
mod->FrameFadeOutLength.set(sObject->FrameFadeOutLength.get());
mod->FrameLength.set(sObject->FrameLength.get());
mod->FrameStart.set(sObject->FrameStart.get());
mod->Name.set(sObject->Name.get());
mod->Remark.set(sObject->Remark.get());
mod->SPITTypeID.set(sObject->SPITTypeID.get());
mod->ServerParams.set(sObject->ServerParams.get());
mod->Track.set(sObject->Track.get());
mod->ValueFactor.set(sObject->ValueFactor.get());
mod->ValueUse.set(sObject->ValueUse.get());
mCallbacks.onSpitObject(ObjectEvent::Changed, false, *sType, *mod);
sendObjectInternal(mod);
return true;
}
/**
* When the client wants to remove a SPITObject with id == p_SPITObjectID (normally the client should not do this), then he should send it to the SPITServer.
* The corresponding SPITObject if listet in SPITObject will be deleted.
* An eventRemoveSPITType will occur.
* If an connection to a SPITServer is established, the SPITServer may discard the deletion and an eventSPITObject occurs
* -> the SPITObject is listet again.
* @param objId the id of the SPITObject to remove.
* @return 0 = sended to the SPITServer, -1 = not sended to the SPITServer or nos SPITObject with id == objId exists.
*/
int SProcessor::removeObject(string objId) {
if (objId.length() <= 0)
return -1;
Message::RemoveObject remObj;
SObject *sObject = mSpitObjects.getEntry(objId);
if (sObject == nullptr)
return -1;
SType *sType = mSpitTypes.getEntry(sObject->SPITTypeID.get());
if (sType == nullptr)
return -1;
sObject->fillMessageOP(remObj);
mCallbacks.onSpitObject(ObjectEvent::Deleted, false, *sType, *sObject);
mSpitObjects.removeEntry(*sObject);
return mInternCallbacks.sendMessage(remObj);
}
// //----- Play SPIT Objects ------
void SProcessor::parsePlayStart(Message::PlayStart &message) {
ESP_LOGD(TAG, "parse PlayStart ID: %s Name: %s Running: %d", message.getPlayerID().c_str(), message.getPlayerName().c_str(), (int)message.getPlayerIsRunning());
SPlayer &player = SPlayer::getSPITPlayer(message.getPlayerID());
player.setIsRunning(message.getPlayerIsRunning());
player.setName(message.getPlayerName());
player.setType(message.getPlayerType());
player.setTime(message.getTime());
player.startPlaySequence();
mCallbacks.onPlay(player.getID(), player.getName(), player.getType(), player.getIsRunning(), player.getTime());
}
void SProcessor::parsePlayObject(Message::PlayObject &message) {
SPlayer &player = SPlayer::getSPITPlayer(message.getPlayerID());
SObject *sObject = mSpitObjects.getEntry(message.getSPITObjectID());
if (sObject == nullptr) {
return;
}
SPlayer::PlayType *playType = player.addTypePlaying(sObject->SPITTypeID.get());
if (playType == nullptr) {
return;
}
playType->setPlayerIsRunning(player.getIsRunning());
playType->addValue(((double)message.getValue() / 1000000), ((double)sObject->ValueFactor.get() / 1000000));
}
void SProcessor::parsePlayEnd(Message::PlayEnd &message) {
SPlayer &sPlayer = SPlayer::getSPITPlayer(message.getPlayerID());
auto &playTypes = sPlayer.getPlaySPITTypes();
for (auto i = playTypes.begin(); i != playTypes.end(); i++) {
SPlayer::PlayType *playType = i->second.get();
bool isStarted = playType->getIsNew();
bool iStopped = (playType->getIsPlayed() == false);
SType *ptrSPITType = mSpitTypes.getEntry(playType->getSPITTypeID());
if (ptrSPITType == nullptr) {
// set isplayed to false, the ptrPlayObject will be removed by sPlayer.endPlaySequence()
playType->setIsPlayed(false);
continue;
}
mCallbacks.onPlaySpitType(playType->getPlayerID(), playType->getSPITTypeID(), playType->getPlayerIsRunning(), isStarted, iStopped, playType->getValue());
}
sPlayer.endPlaySequence();
}
void SProcessor::parseReportPlayStatus(Message::ReportPlayStatus &message) {
SType *sType = NULL;
SObject *sObject = mRemoteSpitObjects.getEntry(message.getID());
if (sObject == nullptr) {
sObject = mSpitObjects.getEntry(message.getID());
if (sObject == nullptr) {
return;
}
}
if (sObject->ServerRemote.get() == false) {
sType = mSpitTypes.getEntry(sObject->SPITTypeID.get());
} else {
sType = mRemoteSpitTypes.getEntry(sObject->SPITTypeID.get());
}
if (sType == nullptr) {
return;
}
mCallbacks.onPlayRemoteObjectStatus(*sType, *sObject, message.getFrameInsideObject(), message.getValue());
}
// //--------- Remote ----------
/**
* Send a remote control command to the SPITServer.
* There may be different command types:
* a) Some don't use value e.g. go to next scene, olay a jingle
* b) Some use values e.g. the main sound fader
* @param sObjectId the id of the remote SPITObject (this represents the remote control command)
* @param valuePpm the value in ppm
* in case a) the value is ignored
* in case b) the value is used
* @param valueFlag indicates how the server should use valuePpm:
* VALUEFLAG_DIRECT (0x00) The server overwrites its existing value with p_Value
* VALUEFLAG_INCREASE (0x01) The server increases his existing value by valuePpm
* VALUEFLAG_DECREASE (0x01) The server decreases his existing value by valuePpm
*/
void SProcessor::sendRemoteObject(string sObjectId, int valuePpm, char valueFlag) {
SObject *remoteObject = mRemoteSpitObjects.getEntry(sObjectId);
if (remoteObject == nullptr)
return;
Message::PlayStart playSPITStart(mGuid, mProjName, SPlayer::PTYPE_DISCRETE);
playSPITStart.setPlayerIsRunning(false);
playSPITStart.setTime(0);
mInternCallbacks.sendMessage(playSPITStart);
Message::PlayObject playSPITObject;
playSPITObject.setID(remoteObject->getID());
playSPITObject.setPlayPrePosition(false);
playSPITObject.setPlayerID(mGuid);
playSPITObject.setValue(valuePpm);
playSPITObject.setValueFlag(valueFlag);
mInternCallbacks.sendMessage(playSPITObject);
Message::PlayEnd playSPITEnd(mGuid);
mInternCallbacks.sendMessage(playSPITEnd);
}
} // namespace spit
+213
View File
@@ -0,0 +1,213 @@
#include "spit_socket.hpp"
#include "Task.hpp"
#include "esp/uuid.h"
#include "esp_log.h"
#include "esp_netif.h"
#include <string>
#include <unistd.h>
using namespace std;
namespace spit {
/**
* Creates socket. If there exist some, they will be closed.
* @return
*/
bool Socket::createSocketUdp() {
if (mUdpSocketIp4 != INVALID_SOCKET) {
close(mUdpSocketIp4);
mUdpSocketIp4 = INVALID_SOCKET;
}
mUdpSocketIp4 = socket(AF_INET, SOCK_DGRAM, 0);
int intResult = -1;
bool success = true;
if (mUdpSocketIp4 == INVALID_SOCKET) {
success = false;
} else {
int intOptionValue4 = 1;
intResult = setsockopt(mUdpSocketIp4, SOL_SOCKET, SO_REUSEADDR, (void *)&intOptionValue4, sizeof(intOptionValue4));
}
if (intResult < 0) {
success = false;
}
if (success == true) {
struct timeval tv;
tv.tv_sec = 1; // seconds
tv.tv_usec = 0; // microseconds (0.0 sec)
// This sets the receive timeout
setsockopt(mUdpSocketIp4, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
// set the mUdpSocketIp4 in NON BLOCKING mode because
// if the UDPSockets are in blocking mode the receiveMessage does not return in every constellation
// int intFlags;
// intFlags = fcntl(mUdpSocketIp4, F_GETFL);
// fcntl(mUdpSocketIp4, F_SETFL, intFlags | O_NONBLOCK);
// int intBufferSize = 2046 * 512;
// intResult = setsockopt(mUdpSocketIp4, SOL_SOCKET, SO_RCVBUF, (void*)&intBufferSize, sizeof(intBufferSize));
// intResult = setsockopt(mUdpSocketIp4, SOL_SOCKET, SO_SNDBUF, (void*)&intBufferSize, sizeof(intBufferSize));
}
return success;
}
/**
* Binds the socket to the client's ip address and port. The socket option SO_REUSEADDR is set to true.
* @param clientIp ip address of the client
* @param clientPort port of the client.
* if p_Port == "0" any free port will be used
* @return -1 id bind fails, o if bind is ok
*
*/
int Socket::bindSocket(string clientIp, string clientPort) {
string stringClientPort;
if (clientPort.length() <= 0)
stringClientPort = "0";
else
stringClientPort = clientPort;
addrinfo *clientAI;
if (getaddrinfo(clientIp.data(), clientPort.data(), nullptr, &clientAI) != 0) {
return -1;
}
if (mUdpSocketIp4 == INVALID_SOCKET) {
return -1;
}
auto *socketAdr = (sockaddr_in *)(clientAI->ai_addr);
int intSocklen = sizeof(*socketAdr);
// copy the socketAdr, may be not filled correct by getaddrinfo
sockaddr_in o_IP4SocketAddress;
memset(&o_IP4SocketAddress, 0, intSocklen);
o_IP4SocketAddress.sin_addr = socketAdr->sin_addr;
o_IP4SocketAddress.sin_family = socketAdr->sin_family;
o_IP4SocketAddress.sin_port = socketAdr->sin_port;
int intResult = bind(mUdpSocketIp4, (const sockaddr *)(socketAdr), (socklen_t)intSocklen);
if (intResult < 0) {
return intResult;
}
if ((intResult == 0) &&
(getsockname(mUdpSocketIp4, (sockaddr *)socketAdr, (socklen_t *)&intSocklen) != -1)) {
setBoundClientPort(to_string((int)socketAdr->sin_port));
}
freeaddrinfo(clientAI);
setIsBound(intResult != -1);
return intResult;
}
/**
* Set whether the socket are broadcast sockets or not. Set the sockopt SO_BROADCAST to 0 or 1
* @param p_Broadcast true SO_BROADCAST is set
* false = SO_BROADCAST is not set
* @return 0 = ok, -1 = error
*/
int Socket::setBroadcast(bool broadcast) const {
int intOptionValue = broadcast ? 1 : 0;
int intResult = setsockopt(mUdpSocketIp4, SOL_SOCKET, SO_BROADCAST, &intOptionValue, sizeof(int));
return intResult;
}
/**
* @param ip the ip address of the server
* @param port the port of the server
* @param msg buffer containing the message
* @param msgLength the length of the message
* @return -1 send fails
* 0 send is done
*/
int Socket::sendMessageTo(const string &ip, const string &port, const char *message, int msgLength) {
if (mUdpSocketIp4 == INVALID_SOCKET) {
return -1;
}
// prepare AddressInfo
int intResult = -1;
addrinfo *ptrAddressInfo;
if (getaddrinfo(ip.data(), port.data(), nullptr, &ptrAddressInfo) != 0) {
return intResult;
}
auto *ptrIP4SocketAddress = (sockaddr_in *)(ptrAddressInfo->ai_addr);
int intSocklen = sizeof(*ptrIP4SocketAddress);
if (mUdpSocketIp4 != INVALID_SOCKET) {
// copy the ptrIP4SocketAddress, may be not filled correct by getaddrinfo
sockaddr_in o_IP4SocketAddress;
memset(&o_IP4SocketAddress, 0, intSocklen);
o_IP4SocketAddress.sin_addr = ptrIP4SocketAddress->sin_addr;
o_IP4SocketAddress.sin_family = ptrIP4SocketAddress->sin_family;
o_IP4SocketAddress.sin_port = ptrIP4SocketAddress->sin_port;
intResult = sendto(mUdpSocketIp4, message, msgLength, 0, (const sockaddr *)&o_IP4SocketAddress, (socklen_t)intSocklen);
if (intResult < 0) {
ESP_LOGE("SPIT", "sendMessageTo IP4 sendto %s FAILED %s\n", ip.data(), strerror(errno));
ESP_LOGE("SPIT", "sendMessageTo ret=%d %s / %s / %d\n", intResult, port.data(), message, msgLength);
}
freeaddrinfo(ptrAddressInfo);
}
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_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 Socket::receiveMessage(char *p_Buffer, int p_BufferLength, string *serverIp) const {
int intResult = -1;
if (mUdpSocketIp4 == INVALID_SOCKET) {
return intResult;
}
sockaddr_in o_IP4SocketAddress;
int intSocklen = sizeof(o_IP4SocketAddress);
memset(&o_IP4SocketAddress, 0, intSocklen);
intResult = recvfrom(mUdpSocketIp4, (void *)p_Buffer, p_BufferLength, 0, (sockaddr *)&o_IP4SocketAddress, (socklen_t *)&intSocklen);
if (intResult >= 0 && serverIp != nullptr) {
char bufferIP4[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(o_IP4SocketAddress.sin_addr), bufferIP4, intSocklen);
*serverIp = bufferIP4;
}
return intResult;
}
ISocket::IpAddress Socket::getAdaptersInfo() {
// iterate over active interfaces, and print out IPs
esp_netif_t *netif = nullptr;
if ((netif = esp_netif_next_unsafe(netif)) != nullptr) {
ESP_LOGI("SPIT", "Connected to %s", esp_netif_get_desc(netif));
esp_netif_ip_info_t ip;
ESP_ERROR_CHECK(esp_netif_get_ip_info(netif, &ip));
ESP_LOGI("SPIT", "- IPv4 address: " IPSTR ",", IP2STR(&ip.ip));
ESP_LOGI("SPIT", "- IPv4 netmask: " IPSTR ",", IP2STR(&ip.netmask));
char buffer[64];
sprintf(buffer, IPSTR, IP2STR(&ip.ip));
string stringIP4 = buffer;
sprintf(buffer, IPSTR, IP2STR(&ip.netmask));
string stringSubnet = buffer;
return {stringIP4, stringSubnet};
}
return {"0.0.0.0", "0.0.0.0"};
}
string createGUID() {
uuid_t uu;
uuid_generate(uu);
char uu_str[UUID_STR_LEN];
uuid_unparse(uu, uu_str);
return {uu_str};
}
string getClientHostName() {
const char *hostname;
esp_netif_get_hostname(esp_netif_get_default_netif(), &hostname);
if (hostname != nullptr) {
return {hostname};
}
return "";
}
}
+5
View File
@@ -0,0 +1,5 @@
idf_component_register(
SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES cmock spit
)
+123
View File
@@ -0,0 +1,123 @@
/**
* @file test_mean.cpp
* @author Gustice
* @brief Hardware bound unit-Test example device
*/
#include "spit_client.hpp"
#include "unity.h"
#include <limits.h>
#include <queue>
#include
using namespace spit;
using namespace std;
queue<string> callbackEvents;
class ClientMock {
public:
void onServerEvent(SClient::ServerEvent event, const SadDetectedServer &detectedServer) {
}
void onConnectionStatus(string serverID, string serverComputerName, string serverName, int serverStepTime, SClient::Connection connectionStatus, SClient::Connection oldConnectionStatus) {
}
void onProjectUpdate(SClient::ProjUpdate state, string projectId) {
}
void onSpitType(SClient::ObjectEvent event, bool isRemote, const SType &spitType) {
}
void onSpitObject(SClient::ObjectEvent event, bool isRemote, const SType &spitType, const SObject &spitObject) {
}
void onPlay(string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames) {
}
void onPlaySpitType(string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value) {
}
void onPlayRemoteObjectStatus(const SType &spitType, const SObject &spitObject, uint64_t p_FrameInsideObject, int value) {
}
bool onCheckSpitTypeVeto(bool knownType, bool createdByClient) {
return true;
}
bool onCheckSpitObjectVeto(bool knownType) {
return true;
}
};
class SocketMock : public ISocket {
public:
SocketMock(IpAddress ip) : ISocket(ip) {}
int sendMessage(const char *message, int length) override {
return 0;
}
int receiveMessage(char *bu1ffer, int bufferLength, string *serverIp) const override {
return 0;
}
void setConnectionParams(const string &serverIp, const string &serverPort, const string &clientIp, const string &clientPort) override {
}
int bindSocket(string clientIp, string clientPort) override {
return 0;
}
int setBroadcast(bool broadcast) const override {
return 0;
}
int sendMessageTo(const string &ip, const string &port, const char *message, int msgLength) override {
return 0;
}
};
// class SpitClientFix {
// protected:
// static ClientMock client;
// ISocket::IpAddress ip{"10.10.0.1", "255.255.255.0"};
// SocketMock socket{ip};
// SClient::Callbacks callbacks{
// .onServerEvent = [&](SClient::ServerEvent event, const SadDetectedServer &detectedServer){client.onServerEvent(event, detectedServer);} ,
// .onConnectionStatus = [&](string serverID, string serverComputerName, string serverName, int serverStepTime, SClient::Connection connectionStatus, SClient::Connection oldConnectionStatus){client.onConnectionStatus(serverID, serverComputerName, serverName, serverStepTime, connectionStatus, oldConnectionStatus);} ,
// .onProjectUpdate = [&](SClient::ProjUpdate state, string projectId){client.onProjectUpdate(state, projectId);} ,
// .onSpitType = [&](SClient::ObjectEvent event, bool isRemote, const SType &spitType){client.onSpitType(event, isRemote, spitType);} ,
// .onSpitObject = [&](SClient::ObjectEvent event, bool isRemote, const SType &spitType, const SObject &spitObject){client.onSpitObject(event, isRemote, spitType, spitObject);} ,
// .onPlay = [&](string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames){client.onPlay(playerID, playerName, playerType, playerIsRunning, timeFrames);} ,
// .onPlaySpitType = [&](string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value){client.onPlaySpitType(playerID, spitTypeID, playerIsRunning, started, ended, value);} ,
// .onPlayRemoteObjectStatus = [&](const SType &spitType, const SObject &spitObject, uint64_t p_FrameInsideObject, int value){client.onPlayRemoteObjectStatus( spitType, spitObject, p_FrameInsideObject, value);} ,
// .onCheckSpitTypeVeto = [&](bool knownType, bool createdByClient){return client.onCheckSpitTypeVeto(knownType, createdByClient);} ,
// .onCheckSpitObjectVeto = [&](bool knownType){return client.onCheckSpitObjectVeto(knownType);}
// };
// SClient sut{"sut", "sutProj", socket, callbacks};
// };
TEST_CASE("Full Connect precedure", "[spit][init]") {
static ClientMock client;
ISocket::IpAddress ip{"10.10.0.1", "255.255.255.0"};
SocketMock socket{ip};
SClient::Callbacks callbacks{
.onServerEvent = [&](SClient::ServerEvent event, const SadDetectedServer &detectedServer) { client.onServerEvent(event, detectedServer); },
.onConnectionStatus = [&](string serverID, string serverComputerName, string serverName, int serverStepTime, SClient::Connection connectionStatus, SClient::Connection oldConnectionStatus) { client.onConnectionStatus(serverID, serverComputerName, serverName, serverStepTime, connectionStatus, oldConnectionStatus); },
.onProjectUpdate = [&](SClient::ProjUpdate state, string projectId) { client.onProjectUpdate(state, projectId); },
.onSpitType = [&](SClient::ObjectEvent event, bool isRemote, const SType &spitType) { client.onSpitType(event, isRemote, spitType); },
.onSpitObject = [&](SClient::ObjectEvent event, bool isRemote, const SType &spitType, const SObject &spitObject) { client.onSpitObject(event, isRemote, spitType, spitObject); },
.onPlay = [&](string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames) { client.onPlay(playerID, playerName, playerType, playerIsRunning, timeFrames); },
.onPlaySpitType = [&](string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value) { client.onPlaySpitType(playerID, spitTypeID, playerIsRunning, started, ended, value); },
.onPlayRemoteObjectStatus = [&](const SType &spitType, const SObject &spitObject, uint64_t p_FrameInsideObject, int value) { client.onPlayRemoteObjectStatus(spitType, spitObject, p_FrameInsideObject, value); },
.onCheckSpitTypeVeto = [&](bool knownType, bool createdByClient) { return client.onCheckSpitTypeVeto(knownType, createdByClient); },
.onCheckSpitObjectVeto = [&](bool knownType) { return client.onCheckSpitObjectVeto(knownType); }};
SClient sut{"sut", "sutProj", socket, callbacks};
// tood connect - Response - Request project
// Transfer items liveSHOW -> Device
{
Message::ReportType t1;
t1.setConfirmed(false);
t1.setID("type1Id#");
t1.setFixed(true);
t1.setServerRemote("serverId");
t1.setServerProjectIndepended(true);
t1.setGroupName("sGroup");
t1.setName("type1Name");
t1.setDelay(100);
t1.setDuration(200);
socket.
}
}
+361
View File
@@ -0,0 +1,361 @@
-- COPY to: /usr/lib/x86_64-linux-gnu/wireshark/plugins/spit.lua
-- LiveShowSoftware SPIT-Protocol
spit_proto = Proto("spit", "LiveShowSoftware SPIT")
spit_sad_proto = Proto("spit_sad", "LiveShowSoftware SPIT SAD")
-- Define fields (add more as needed)
local f_hVer = ProtoField.uint32("spit.version", "Version")
local f_hNum = ProtoField.uint8("spit.msgCount", "MsgCount")
local f_hLen = ProtoField.uint32("spit.len", "Length")
local f_hSerId = ProtoField.string("spit.serverId", "ServerID")
local f_hCliId = ProtoField.string("spit.clientId", "ClientID")
local f_hType = ProtoField.uint8("spit.msgType", "MsgType")
local f_pLen = ProtoField.uint32("spit.paylen", "Payload Length")
local f_pSession = ProtoField.string("spit.key", "Spit Session")
local f_pKey = ProtoField.string("spit.key", "Spit Key")
local f_pSadKey = ProtoField.string("spit.sadKey", "Spit SAD Key")
local f_pServerDevName = ProtoField.string("spit.serverDevName", "Server Device Name")
local f_pClientDevName = ProtoField.string("spit.clientDevName", "Client Device Name")
local f_pClientName = ProtoField.string("spit.clientName", "Client Name")
local f_pLoginName = ProtoField.string("spit.loginName", "Login Name")
local f_pLoginPassword = ProtoField.string("spit.loginPassword", "Login Password")
local f_pServerName = ProtoField.string("spit.serverName", "Server Name")
local f_pServerIp = ProtoField.string("spit.serverIp", "Server IP")
local f_pServerPort = ProtoField.uint16("spit.serverIp", "Server Port")
local f_pSrvParam = ProtoField.string("spit.serverParam", "Server Paramter")
local f_pStepTime = ProtoField.string("spit.stepTime", "Step Time")
local f_pConnected = ProtoField.string("spit.connected", "Connected")
local f_pProjectId = ProtoField.string("spit.projectId", "Project ID")
local f_pProjectName = ProtoField.string("spit.projectName", "Project Name")
local f_pObjectId = ProtoField.string("spit.ObjectId", "Object ID")
local f_pObjectName = ProtoField.string("spit.ObjectName", "Object Name")
local f_pTypeId = ProtoField.string("spit.TypeId", "Type ID")
local f_pTypeName = ProtoField.string("spit.TypeName", "Type Name")
local f_pTypeGroupName = ProtoField.string("spit.TypeGroupName", "Type Group Name")
local f_pObjectsFrames = ProtoField.uint64("spit.ObjectFrames", "Object Frames")
local f_pValue = ProtoField.uint64("spit.Value", "Value")
local f_pValueFlag = ProtoField.uint8("spit.ValueFlag", "ValueFlag")
local f_pConfirm = ProtoField.uint8("spit.confirmed", "Confirmation")
local f_pFixed = ProtoField.uint8("spit.fixed", "Fixed")
local f_pAssigned = ProtoField.uint8("spit.assigned", "Action assigned")
local f_pSrvRemote = ProtoField.uint8("spit.serverRemote", "Server Remote")
local f_pProjIndep = ProtoField.uint8("spit.projectIndipendent", "Project Indipendent")
local f_pValueUse = ProtoField.uint8("spit.valueUse", "Value Use")
local f_pFrameStart = ProtoField.uint64("spit.frameStart", "Frame Start")
local f_pFrameLength = ProtoField.uint64("spit.frameLength", "Frame Length")
local f_pFrameFadeIn = ProtoField.uint64("spit.fadeInLength", "Fade In Length")
local f_pFrameFadeOut = ProtoField.uint64("spit.fadeOutLength", "Fade Out Length")
local f_pValueFactor = ProtoField.uint32("spit.valueFactor", "Value Factor")
local f_pFramesPerSec = ProtoField.uint32("spit.framesPerSec", "Frames per second")
local f_pTrack = ProtoField.uint32("spit.track", "Track")
local f_pRemark = ProtoField.string("spit.remark", "Remack")
local f_pDelay = ProtoField.uint64("spit.delay", "Delay")
local f_pDuration = ProtoField.uint64("spit.duration", "Duration")
local f_pPlayerId = ProtoField.string("spit.PlayerId", "Player ID")
local f_pPlayerName = ProtoField.string("spit.PlayerName", "Player Name")
local f_pPlayerType = ProtoField.uint8("spit.PlayerType", "Player Type")
local f_pPlayerRunning = ProtoField.uint8("spit.PlayerRunning", "Player Running")
local f_pPlayerFrames = ProtoField.uint64("spit.PlayerFrame", "Player Frames")
local f_pPlayerPrePos = ProtoField.uint8("spit.PlayerPrePos", "Player Preposition")
local sessionInfos = {}
spit_proto.fields = {
f_pSession, f_pKey, f_pSadKey, f_pServerDevName,
f_hVer, f_hNum, f_hLen, f_hSerId, f_hCliId, f_hType, f_pLen,
f_pClientDevName, f_pClientName, f_pLoginName, f_pLoginPassword, f_pServerName, f_pServerIp, f_pServerPort, f_pSrvParam, f_pStepTime, f_pConnected, f_pProjectId, f_pProjectName,
f_pObjectId, f_pObjectName, f_pTypeId, f_pTypeName, f_pTypeGroupName, f_pObjectsFrames, f_pValue, f_pValueFlag,
f_pConfirm, f_pFixed, f_pAssigned, f_pSrvRemote, f_pProjIndep, f_pValueUse,
f_pFrameStart, f_pFrameLength, f_pFrameFadeIn, f_pFrameFadeOut, f_pValueFactor, f_pFramesPerSec, f_pTrack, f_pRemark, f_pDelay, f_pDuration,
f_pPlayerId, f_pPlayerName, f_pPlayerType, f_pPlayerRunning, f_pPlayerFrames, f_pPlayerPrePos
}
function extractSession(buffer, pinfo)
local serverHash = buffer(16,41):string()
local clientHash = buffer(57,41):string()
return string.format("%s - %s", sessionInfos[serverHash], sessionInfos[clientHash])
end
function extractVersionString(buffer)
local vBytes = buffer(7,4):bytes()
local vStr = ""
for i = 0, 3 do
local byte = vBytes:get_index(i)
local high_nibble = bit.rshift(byte, 4)
local low_nibble = bit.band(byte, 0x0F)
vStr = vStr .. tostring(high_nibble) .. tostring(low_nibble)
end
return vStr
end
function addBigEndianValue(tree, proto, buffer)
local val = -1;
-- local val = buffer(99,4):le_uint()
if proto.type == ftypes.UINT32 then
val = buffer:le_uint()
elseif proto.type == ftypes.UINT64 then
val = buffer:le_uint64()
end
tree:add(proto, buffer):set_text(proto.name .. ": " .. val)
end
-- Heuristic dissector function
function spit_proto.dissector(buffer, pinfo, tree)
if buffer:len() < 6 then return false end
if buffer(0,6):string() ~= "#spit#" then return false end
pinfo.cols.protocol = "SPIT"
local subtree = tree:add(spit_proto, buffer(), "SPIT Protocol Data")
local hTree = subtree:add("Header")
hTree:add(f_hVer, buffer(7,4)):set_text("Version: " .. extractVersionString(buffer))
hTree:add(f_hNum, buffer(11,1))
local hLen = buffer(12,4):le_uint()
subtree:add(f_hLen, buffer(12,4)):set_text("Length: " .. hLen)
hTree:add(f_hSerId, buffer(16,41))
hTree:add(f_hCliId, buffer(57,41))
local type = buffer(98,1):uint()
hTree:add(f_hType, buffer(98,1))
local pTree = subtree:add("Payload")
-- local pLen = buffer(99,4):le_uint()
-- pTree:add(f_pLen, buffer(99,4)):set_text("Pyload Length: " .. pLen)
addBigEndianValue(pTree, f_pLen, buffer(99,4))
local info_text = "Type: " .. type
if type == 1 then -- Connect
pTree:add(f_pClientDevName, buffer(103,64))
pTree:add(f_pClientName, buffer(167,64))
pTree:add(f_pLoginName, buffer(231,64))
pTree:add(f_pLoginPassword, buffer(295,64))
pTree:add(f_pServerIp, buffer(359,40))
pTree:add(f_pServerPort, buffer(399,2))
local clientName = buffer(167,64):string()
local clientHash = buffer(57,41):string()
sessionInfos[clientName] = clientHash -- e.g. 70866c9b-af1c-4765-a17e-8b45c93f3aca
sessionInfos[clientHash] = clientName --
sessionInfos[tostring(pinfo.src)] = clientName
info_text = string.format("Connect Req | Client: %s (%s) | ADDR: %s:%s",
clientName, clientHash, buffer(359,40):string(), buffer(399,2):uint())
elseif type == 2 then -- Connect Response
pTree:add(f_pServerDevName, buffer(103,64))
pTree:add(f_pServerName, buffer(167,64))
pTree:add(f_pStepTime, buffer(231,4))
pTree:add(f_pConnected, buffer(235,1))
local serverName = buffer(167,64):string()
local serverHash = buffer(16,41):string()
sessionInfos[serverName] = serverHash -- e.g. 405c7100-64e8-435d-8a7b-00c5629f9ccf
sessionInfos[serverHash] = serverName
sessionInfos[tostring(pinfo.src)] = serverName
info_text = string.format("Connect Res | Server: %s (%s) ",
serverName, serverHash)
elseif type == 3 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
info_text = string.format("Disconnect")
elseif type == 8 then
info_text = string.format("Watchdog")
elseif type == 9 then
info_text = string.format("Watchdog Ans")
elseif type == 11 then -- Report Porject
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pProjectId, buffer(103,41))
pTree:add(f_pProjectName, buffer(144,64))
addBigEndianValue(pTree, f_pFramesPerSec, buffer(208,4))
info_text = string.format("%s -> %s | Report Project | Project: %s / %s",
sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], buffer(103,41):string(), buffer(144,64):string())
elseif type == 13 then -- Close Porject
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pProjectId, buffer(103,41))
info_text = string.format("Close Project | Project: %s",
buffer(103,64):string())
elseif type == 15 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
info_text = string.format("Request Project Transfer")
elseif type == 16 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
info_text = string.format("Start Project Transfer")
elseif type == 17 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
info_text = string.format("End Project Transfer")
elseif type == 21 then -- Report Type
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pConfirm, buffer(103,1))
pTree:add(f_pTypeId, buffer(104,41))
pTree:add(f_pFixed, buffer(145,1))
pTree:add(f_pSrvRemote, buffer(146,1))
pTree:add(f_pProjIndep, buffer(147,1))
pTree:add(f_pTypeGroupName, buffer(148,39))
pTree:add(f_pTypeName, buffer(187,64))
addBigEndianValue(pTree, f_pDelay, buffer(251,8))
addBigEndianValue(pTree, f_pDuration, buffer(259,8))
local group = buffer(148,39):string()
local name = buffer(187,64):string()
local id = buffer(104,41):string()
info_text = string.format("%s -> %s | Report SPIT Type: %s.%s (%s)", sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], group, name, id)
elseif type == 23 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pTypeId, buffer(103,41))
info_text = string.format("Remove SPIT Type")
elseif type == 31 then -- Report Object
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pConfirm, buffer(103,1))
pTree:add(f_pObjectId, buffer(104,41))
pTree:add(f_pFixed, buffer(145,1))
pTree:add(f_pSrvRemote, buffer(146,1))
pTree:add(f_pObjectName, buffer(147,64))
pTree:add(f_pTypeId, buffer(211,41))
pTree:add(f_pSrvParam, buffer(252,64))
addBigEndianValue(pTree, f_pFrameStart, buffer(316,8))
addBigEndianValue(pTree, f_pFrameLength, buffer(324,8))
addBigEndianValue(pTree, f_pFrameFadeIn, buffer(332,8))
addBigEndianValue(pTree, f_pFrameFadeOut, buffer(340,8))
addBigEndianValue(pTree, f_pValueFactor, buffer(348,4))
pTree:add(f_pValueUse, buffer(349,1))
addBigEndianValue(pTree, f_pTrack, buffer(350,4))
pTree:add(f_pRemark, buffer(354,64))
addBigEndianValue(pTree, f_pDelay, buffer(418,8))
addBigEndianValue(pTree, f_pDuration, buffer(426,8))
pTree:add(f_pAssigned, buffer(435,1))
local name = buffer(147,64):string()
local tId = buffer(211,41):string()
local oId = buffer(104,41):string()
info_text = string.format("%s -> %s | Report SPIT Object: %s (%s / %s)", sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], name, oId, tId)
elseif type == 33 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pObjectId, buffer(103,41))
info_text = string.format("Remove SPIT Object")
elseif type == 37 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pPlayerId, buffer(103,41))
pTree:add(f_pPlayerName, buffer(144,64))
pTree:add(f_pPlayerType, buffer(208,1))
pTree:add(f_pPlayerRunning, buffer(209,1))
addBigEndianValue(pTree, f_pPlayerFrames, buffer(210,8))
info_text = string.format("Play SPIT Start")
elseif type == 38 then -- Play Spit object
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pPlayerId, buffer(103,41))
pTree:add(f_pObjectId, buffer(144,41))
addBigEndianValue(pTree, f_pObjectsFrames, buffer(185,8))
pTree:add(f_pPlayerPrePos, buffer(193,1))
addBigEndianValue(pTree, f_pValue, buffer(194,4))
pTree:add(f_pValueFlag, buffer(198,1))
local oId = buffer(144,41):string()
info_text = string.format("%s -> %s | Play SPIT Object: %s", sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], oId)
elseif type == 39 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pPlayerId, buffer(103,41))
info_text = string.format("Play SPIT End")
elseif type == 40 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pObjectId, buffer(103,41))
addBigEndianValue(pTree, f_pObjectsFrames, buffer(144,8))
addBigEndianValue(pTree, f_pValue, buffer(152,4))
info_text = string.format("Report Play Status")
else
info_text = string.format("ERROR Unknown")
end
pinfo.cols['info'] = info_text
return true -- We handled this packet
end
function split(str, delim)
local result = {}
local delim_len = delim
local s = 1
while true do
local e, next_e = string.find(str, delim, s)
if not e then
table.insert(result, string.sub(str, s))
break
end
table.insert(result, string.sub(str, s, e - 1))
s = next_e + 1
end
return result
end
-- Heuristic dissector function
function spit_sad_proto.dissector(buffer, pinfo, tree)
if buffer:len() < 14 then return false end
if buffer(0,14):string() ~= "#SAD##,##spit#" then return false end
pinfo.cols.protocol = "SPIT-SAD"
local info_text = "SAD"
if buffer:len() > 16 then
local payload = buffer(0,buffer:len()):string()
local parts = split(payload, "#,#")
local subtree = tree:add(spit_sad_proto, buffer(), "Discovery Data")
subtree:add(f_pSadKey, parts[1]) -- 1 #SAD#
subtree:add(f_pKey, parts[2]) -- 2 #spit#
subtree:add(f_pServerName, parts[3]) -- 3 liveShowSPIT
subtree:add(f_hSerId , parts[4]) -- 4 405c7100-64e8-435d-8a7b-00c5629f9ccf
subtree:add(f_pServerDevName, parts[5]) -- 5 P17gen1
subtree:add(f_pServerPort, parts[6]) -- 6 15120
subtree:add(f_pServerIp, parts[7]) -- 7 172.16.17.56
subtree:add(f_pProjectName, parts[9]) -- 9 CatasWatchProject
info_text = string.format("SPIT-SAD Discover Data | Client: %s Porject: %s ",
parts[4], parts[9])
else
info_text = string.format("SPIT-SAD Discover")
end
pinfo.cols['info'] = info_text
return true -- We handled this packet
end
-- Register as a heuristic UDP dissector
spit_proto:register_heuristic("udp", spit_proto.dissector)
spit_sad_proto:register_heuristic("udp", spit_sad_proto.dissector)
+5
View File
@@ -0,0 +1,5 @@
UnitTestsFrame()
target_link_libraries(${moduleName} PUBLIC
fmt
hwMock
)
+320
View File
@@ -0,0 +1,320 @@
/**
* @file TestableUTest.cpp
* @author Gustice
* @brief
*/
#include "doctest/doctest.h"
#include <fmt/core.h>
#include <iostream>
#include "spit_message.hpp"
using namespace spit;
class SpitMessageFix {
protected:
};
void checkData(std::vector<char> a, std::vector<char> b) {
CHECK(a.size() == b.size());
for (size_t i = 0; i < b.size(); ++i) {
CHECK_MESSAGE(a[i] == b[i],
fmt::format("Mismatch at index, {} : a = 0x{:02x} , b = 0x{:02x}",
i, (int)a[i], (int)b[i]));
}
}
TEST_CASE_FIXTURE(SpitMessageFix, "Connect Request") {
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0020*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0030*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x62, 0x33, 0x63, 0x66, 0x32, 0x34, // .........db3cf24
/*0040*/ 0x34, 0x2d, 0x36, 0x30, 0x35, 0x39, 0x2d, 0x34, 0x30, 0x65, 0x36, 0x2d, 0x61, 0x33, 0x35, 0x35, // 4-6059-40e6-a355
/*0050*/ 0x2d, 0x32, 0x62, 0x66, 0x34, 0x34, 0x36, 0x37, 0x33, 0x32, 0x62, 0x30, 0x36, 0x00, 0x00, 0x00, // -2bf446732b06...
/*0060*/ 0x00, 0x00, 0x01, 0x30, 0x01, 0x00, 0x00, 0x64, 0x65, 0x76, 0x70, 0x69, 0x00, 0x00, 0x00, 0x00, // ...0...devpi....
/*0070*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0080*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0090*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x71, 0x74, 0x74, 0x53, 0x70, 0x69, 0x74, 0x42, // .......MqttSpitB
/*00b0*/ 0x72, 0x69, 0x64, 0x67, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ridge...........
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x37, 0x32, 0x2e, 0x31, 0x36, 0x2e, 0x31, 0x36, // .......172.16.16
/*0170*/ 0x2e, 0x31, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .10.............
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // ................
/*0190*/ 0x3b, 0x00, 0x00 // ;..
};
std::vector<char> msgC(msg.begin(), msg.end());
{
Message sut = Message(msgC);
CHECK_EQ(sut.getType(), Message::Connect::OPFLAG);
auto &pM = sut.getAs<Message::Connect>();
CHECK_EQ(pM.getClientComputerName(), "devpi");
CHECK_EQ(pM.getClientName(), "MqttSpitBridge");
CHECK_EQ(pM.getLoginName(), "");
CHECK_EQ(pM.getLoginPassword(), "");
CHECK_EQ(pM.getServerIP(), "172.16.16.10");
CHECK_EQ(pM.getServerPort(), 15120);
}
{
Message::Connect sut("devpi", "MqttSpitBridge");
sut.setLoginName("");
sut.setLoginPassword("");
sut.setServerIP("172.16.16.10");
sut.setServerPort(15120);
sut.setMessageNumber(2);
sut.setServerInfoInHeader("db3cf244-6059-40e6-a355-2bf446732b06", "");
auto data = Message::createMessage(sut);
CHECK(data.size() == msg.size());
for (size_t i = 0; i < msg.size(); ++i) {
CHECK_MESSAGE(data[i] == msgC[i],
fmt::format("Mismatch at index, {} : a = 0x{:02x} , b = 0x{:02x}",
i, (int)data[i], (int)msg[i]));
}
}
}
TEST_CASE_FIXTURE(SpitMessageFix, "Connect Response") {
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x62, 0x33, 0x63, 0x66, 0x32, 0x34, // 9ccf.....db3cf24
/*0040*/ 0x34, 0x2d, 0x36, 0x30, 0x35, 0x39, 0x2d, 0x34, 0x30, 0x65, 0x36, 0x2d, 0x61, 0x33, 0x35, 0x35, // 4-6059-40e6-a355
/*0050*/ 0x2d, 0x32, 0x62, 0x66, 0x34, 0x34, 0x36, 0x37, 0x33, 0x32, 0x62, 0x30, 0x36, 0x00, 0x00, 0x00, // -2bf446732b06...
/*0060*/ 0x00, 0x00, 0x02, 0x89, 0x00, 0x00, 0x00, 0x50, 0x31, 0x37, 0x67, 0x65, 0x6e, 0x31, 0x00, 0x00, // .......P17gen1..
/*0070*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0080*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0090*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x69, 0x76, 0x65, 0x53, 0x48, 0x4f, 0x57, 0x00, // .......liveSHOW.
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01 // .......(....
};
std::vector<char> msgC(msg.begin(), msg.end());
{
Message sut = Message(msgC);
CHECK_EQ(sut.getType(), Message::ConnectAnswer::OPFLAG);
auto &pM = sut.getAs<Message::ConnectAnswer>();
CHECK_EQ(pM.getServerComputerName(), "P17gen1");
CHECK_EQ(pM.getServerName(), "liveSHOW");
CHECK_EQ(pM.getConnected(), true);
CHECK_EQ(pM.getStepTime(), 40);
}
{
Message::ConnectAnswer sut;
sut.setServerComputerName("P17gen1");
sut.setServerName("liveSHOW");
sut.setConnected(true);
sut.setStepTime(40);
sut.setMessageNumber(1);
sut.setServerInfoInHeader("db3cf244-6059-40e6-a355-2bf446732b06", "405c7100-64e8-435d-8a7b-00c5629f9ccf");
auto data = Message::createMessage(sut);
checkData(data, msgC);
}
}
TEST_CASE_FIXTURE(SpitMessageFix, "Report Spit Type") {
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x62, 0x33, 0x63, 0x66, 0x32, 0x34, // 9ccf.....db3cf24
/*0040*/ 0x34, 0x2d, 0x36, 0x30, 0x35, 0x39, 0x2d, 0x34, 0x30, 0x65, 0x36, 0x2d, 0x61, 0x33, 0x35, 0x35, // 4-6059-40e6-a355
/*0050*/ 0x2d, 0x32, 0x62, 0x66, 0x34, 0x34, 0x36, 0x37, 0x33, 0x32, 0x62, 0x30, 0x36, 0x00, 0x00, 0x00, // -2bf446732b06...
/*0060*/ 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, // ........ActionMo
/*0070*/ 0x76, 0x65, 0x54, 0x6f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // veTo1...........
/*0080*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0090*/ 0x00, 0x01, 0x00, 0x01, 0x43, 0x61, 0x74, 0x61, 0x73, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4d, 0x6f, // ....CatasWatchMo
/*00a0*/ 0x76, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // vement..........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x74, 0x69, 0x6f, // ...........Actio
/*00c0*/ 0x6e, 0x4d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // nMoveTo1........
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ...........
};
std::vector<char> msgC(msg.begin(), msg.end());
{
Message sut = Message(msgC);
CHECK_EQ(sut.getType(), Message::ReportType::OPFLAG);
auto &pM = sut.getAs<Message::ReportType>();
CHECK_EQ(pM.getConfirmed(), true);
CHECK_EQ(pM.getID(), "ActionMoveTo1");
CHECK_EQ(pM.getFixed(), true);
CHECK_EQ(pM.getServerRemote(), false);
CHECK_EQ(pM.getServerProjectIndepended(), true);
CHECK_EQ(pM.getGroupName(), "CatasWatchMovement");
CHECK_EQ(pM.getName(), "ActionMoveTo1");
CHECK_EQ(pM.getDelay(), 0);
CHECK_EQ(pM.getDuration(), 0);
}
{
Message::ReportType sut;
sut.setConfirmed(true);
sut.setID("ActionMoveTo1");
sut.setFixed(true);
sut.setServerRemote(false);
sut.setServerProjectIndepended(true);
sut.setGroupName("CatasWatchMovement");
sut.setName("ActionMoveTo1");
sut.setDelay(0);
sut.setDuration(0);
sut.setMessageNumber(6);
sut.setServerInfoInHeader("db3cf244-6059-40e6-a355-2bf446732b06", "405c7100-64e8-435d-8a7b-00c5629f9ccf");
auto data = Message::createMessage(sut);
checkData(data, msgC);
}
}
TEST_CASE_FIXTURE(SpitMessageFix, "Report Spit Object") {
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x62, 0x33, 0x63, 0x66, 0x32, 0x34, // 9ccf.....db3cf24
/*0040*/ 0x34, 0x2d, 0x36, 0x30, 0x35, 0x39, 0x2d, 0x34, 0x30, 0x65, 0x36, 0x2d, 0x61, 0x33, 0x35, 0x35, // 4-6059-40e6-a355
/*0050*/ 0x2d, 0x32, 0x62, 0x66, 0x34, 0x34, 0x36, 0x37, 0x33, 0x32, 0x62, 0x30, 0x36, 0x00, 0x00, 0x00, // -2bf446732b06...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x68, 0x63, // ...S....00000mhc
/*0070*/ 0x67, 0x65, 0x64, 0x30, 0x69, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // ged0i00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x7a, 0x34, 0x30, 0x74, 0x63, 0x79, 0x6b, 0x63, 0x33, 0x00, 0x00, // 00000z40tcykc3..
/*0090*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x31, // ...ActionMoveTo1
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x70, 0x00, // ............vip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0xfc, 0x12, 0x00, // ............m...
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x4b, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....K...........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ......
};
std::vector<char> msgC(msg.begin(), msg.end());
{
Message sut = Message(msgC);
CHECK_EQ(sut.getType(), Message::ReportObject::OPFLAG);
auto &pM = sut.getAs<Message::ReportObject>();
CHECK_EQ(pM.getConfirmed(), true);
CHECK_EQ(pM.getID(), "00000mhcged0i0000000000000000z40tcykc3");
CHECK_EQ(pM.getFixed(), false);
CHECK_EQ(pM.getServerRemote(), false);
CHECK_EQ(pM.getName(), "");
CHECK_EQ(pM.getSPITTypeID(), "ActionMoveTo1");
CHECK_EQ(pM.getServerParams(), "vip");
CHECK_EQ(pM.getFrameStart(), 1244269);
CHECK_EQ(pM.getFrameLength(), 53323);
CHECK_EQ(pM.getFrameFadeInLength(), 0);
CHECK_EQ(pM.getFrameFadeOutLength(), 0);
CHECK_EQ(pM.getValueFactor(), 1000000);
CHECK_EQ(pM.getValueUse(), 0);
CHECK_EQ(pM.getTrack(), 1);
CHECK_EQ(pM.getRemark(), "");
CHECK_EQ(pM.getDelay(), 0);
CHECK_EQ(pM.getDuration(), 0);
CHECK_EQ(pM.getActionAssigned(), false);
}
{
Message::ReportObject sut;
sut.setConfirmed(true);
sut.setID("00000mhcged0i0000000000000000z40tcykc3");
sut.setFixed(false);
sut.setServerRemote(false);
sut.setName("");
sut.setSPITTypeID("ActionMoveTo1");
sut.setServerParams("vip");
sut.setFrameStart(1244269);
sut.setFrameLength(53323);
sut.setFrameFadeInLength(0);
sut.setFrameFadeOutLength(0);
sut.setValueFactor(1000000);
sut.setValueUse(0);
sut.setTrack(1);
sut.setRemark("");
sut.setDelay(0);
sut.setDuration(0);
sut.setActionAssigned(false);
sut.setMessageNumber(21);
sut.setServerInfoInHeader("db3cf244-6059-40e6-a355-2bf446732b06", "405c7100-64e8-435d-8a7b-00c5629f9ccf");
auto data = Message::createMessage(sut);
checkData(data, msgC);
}
}
TEST_CASE_FIXTURE(SpitMessageFix, "Report Play Object") {
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x83, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x62, 0x33, 0x63, 0x66, 0x32, 0x34, // 9ccf.....db3cf24
/*0040*/ 0x34, 0x2d, 0x36, 0x30, 0x35, 0x39, 0x2d, 0x34, 0x30, 0x65, 0x36, 0x2d, 0x61, 0x33, 0x35, 0x35, // 4-6059-40e6-a355
/*0050*/ 0x2d, 0x32, 0x62, 0x66, 0x34, 0x34, 0x36, 0x37, 0x33, 0x32, 0x62, 0x30, 0x36, 0x00, 0x00, 0x00, // -2bf446732b06...
/*0060*/ 0x00, 0x00, 0x28, 0x39, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, // ..(9...00000m8ue
/*0070*/ 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // dyyt000000000000
/*0080*/ 0x30, 0x30, 0x30, 0x31, 0x66, 0x6a, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, // 0001fj0va8bom...
/*0090*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ............
};
std::vector<char> msgC(msg.begin(), msg.end());
{
Message sut = Message(msgC);
CHECK_EQ(sut.getType(), Message::ReportPlayStatus::OPFLAG);
auto &pM = sut.getAs<Message::ReportPlayStatus>();
CHECK_EQ(pM.getID(), "00000m8uedyyt0000000000000001fj0va8bom");
CHECK_EQ(pM.getFrameInsideObject(), 0);
CHECK_EQ(pM.getValue(), 0);
}
{
Message::ReportPlayStatus sut;
sut.setID("00000m8uedyyt0000000000000001fj0va8bom");
sut.setFrameInsideObject(0);
sut.setValue(0);
sut.setMessageNumber(131);
sut.setServerInfoInHeader("db3cf244-6059-40e6-a355-2bf446732b06", "405c7100-64e8-435d-8a7b-00c5629f9ccf");
auto data = Message::createMessage(sut);
checkData(data, msgC);
}
}
+92
View File
@@ -0,0 +1,92 @@
/**
* @file spitRepoTest.cpp
* @author Gustice
* @brief
*/
#include "doctest/doctest.h"
#include <fmt/core.h>
#include <iostream>
#include "spit_object.hpp"
using namespace spit;
using namespace std;
class SpitObjectFix {
protected:
};
TEST_CASE_FIXTURE(SpitObjectFix, "Typical use case") {
{
SObject sut("#Id#123");
CHECK(sut.getID() == "#Id#123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Name.set("G123") == true);
CHECK(sut.Name.get() == "G123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Name.set("G123") == false);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Name.set("G321") == true);
CHECK(sut.Name.get() == "G321");
CHECK(sut.getConfirmed() == false);
}
{
SObject sut("#Id#123");
CHECK(sut.getID() == "#Id#123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Fixed.set(true) == true);
CHECK(sut.Fixed.get() == true);
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Fixed.set(true) == false);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Fixed.set(false) == true);
CHECK(sut.Fixed.get() == false);
CHECK(sut.getConfirmed() == false);
}
{
SObject sut("#Id#123");
CHECK(sut.getID() == "#Id#123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.FrameLength.set(123) == true);
CHECK(sut.FrameLength.get() == 123);
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.FrameLength.set(123) == false);
CHECK(sut.getConfirmed() == true);
CHECK(sut.FrameLength.set(321) == true);
CHECK(sut.FrameLength.get() == 321);
CHECK(sut.getConfirmed() == false);
}
// ...
// {
// SObject sut("#Id#123", "grp123", "name123", true, false, 1234, 4321);
// CHECK(sut.getID() == "#Id#123");
// CHECK(sut.GroupName.get() == "grp123");
// CHECK(sut.Name.get() == "name123");
// CHECK(sut.Fixed.get() == true);
// CHECK(sut.ProjectIndepended.get() == false);
// CHECK(sut.DefaultDelay.get() == 1234);
// CHECK(sut.DefaultDuration.get() == 4321);
// }
}
+350
View File
@@ -0,0 +1,350 @@
/**
* @file spitRepoTest.cpp
* @author Gustice
* @brief
*/
#include "doctest/doctest.h"
#include <fmt/core.h>
#include <iostream>
#include <queue>
#include "spit_processor.hpp"
using namespace spit;
using namespace std;
static queue<string> cbEvents;
class ClientMock {
public:
void onServerEvent(SProcessor::ServerEvent event, const SadDetectedServer &detectedServer) {
}
void onConnectionStatus(string serverID, string serverComputerName, string serverName, int serverStepTime, SProcessor::Connection connectionStatus, SProcessor::Connection oldConnectionStatus) {
}
void onProjectUpdate(SProcessor::ProjUpdate state, string projectId) {
}
void onSpitType(SProcessor::ObjectEvent event, bool isRemote, const SType &sType) {
cbEvents.push(fmt::format("{}: {} {} {} {}", (int)event, isRemote, sType.getID(), sType.Name.get(), sType.GroupName.get()));
}
void onSpitObject(SProcessor::ObjectEvent event, bool isRemote, const SType &sType, const SObject &sObject) {
cbEvents.push(fmt::format("{}: {} {} {} {} {}", (int)event, isRemote, sType.getID(), sType.Name.get(), sObject.Name.get(), sObject.getID()));
}
void onPlay(string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames) {
}
void onPlaySpitType(string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value) {
}
void onPlayRemoteObjectStatus(const SType &sType, const SObject &sObject, uint64_t p_FrameInsideObject, int value) {
}
bool onCheckSpitTypeVeto(bool knownType, bool createdByClient) {
cbEvents.push(fmt::format("veto check {}/{}", knownType, createdByClient));
return true;
}
bool onCheckSpitObjectVeto(bool knownType) {
return true;
}
};
class SpitClientFix {
protected:
std::vector<string> messages;
ClientMock client;
SProcessor::Callbacks callbacks{
.onServerEvent = [&](SProcessor::ServerEvent event, const SadDetectedServer &detectedServer) { client.onServerEvent(event, detectedServer); },
.onConnectionStatus = [&](string serverID, string serverComputerName, string serverName, int serverStepTime, SProcessor::Connection connectionStatus, SProcessor::Connection oldConnectionStatus) { client.onConnectionStatus(serverID, serverComputerName, serverName, serverStepTime, connectionStatus, oldConnectionStatus); },
.onProjectUpdate = [&](SProcessor::ProjUpdate state, string projectId) { client.onProjectUpdate(state, projectId); },
.onSpitType = [&](SProcessor::ObjectEvent event, bool isRemote, const SType &t) { client.onSpitType(event, isRemote, t); },
.onSpitObject = [&](SProcessor::ObjectEvent event, bool isRemote, const SType &t, const SObject &o) { client.onSpitObject(event, isRemote, t, o); },
.onPlay = [&](string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames) { client.onPlay(playerID, playerName, playerType, playerIsRunning, timeFrames); },
.onPlaySpitType = [&](string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value) { client.onPlaySpitType(playerID, spitTypeID, playerIsRunning, started, ended, value); },
.onPlayRemoteObjectStatus = [&](const SType &t, const SObject &o, uint64_t p_FrameInsideObject, int value) { client.onPlayRemoteObjectStatus(t, o, p_FrameInsideObject, value); },
.onCheckSpitTypeVeto = [&](bool knownType, bool createdByClient) { return client.onCheckSpitTypeVeto(knownType, createdByClient); },
.onCheckSpitObjectVeto = [&](bool knownType) { return client.onCheckSpitObjectVeto(knownType); }};
SProcessor::InternalCallbacks intCallbacks{
.delay = [&](int ms) { return; },
.sendMessage = [&](Message::OPPart &msg) { return 0; },
.parseMessage = [&](Message &msg) {
// auto o = fmt::format("msg-{}", msg.getHeader()->getMessageNumber());
// messages.push_back(o);
},
};
SProcessor sut{"sut", "sutProj", "dev", "##GUID##", callbacks, intCallbacks};
};
TEST_CASE_FIXTURE(SpitClientFix, "Spit types") {
{
Message::ReportType t;
t.setConfirmed(false);
t.setID("type1Id#Rem");
t.setFixed(true);
t.setServerRemote(true);
t.setServerProjectIndepended(true);
t.setGroupName("sGroup");
t.setName("type1Name");
t.setDelay(100);
t.setDuration(200);
sut.checkParseMessageData(sut.createMessage(t));
}
CHECK_MESSAGE(cbEvents.front() == "0: true type1Id#Rem type1Name sGroup", cbEvents.front());
cbEvents.pop();
{
Message::ReportType t;
t.setConfirmed(false);
t.setID("type2Id#Rem");
t.setFixed(true);
t.setServerRemote(true);
t.setServerProjectIndepended(true);
t.setGroupName("sGroup");
t.setName("type2Name");
t.setDelay(100);
t.setDuration(200);
sut.checkParseMessageData(sut.createMessage(t));
}
CHECK_MESSAGE(cbEvents.front() == "0: true type2Id#Rem type2Name sGroup", cbEvents.front());
cbEvents.pop();
{
Message::ReportType t;
t.setConfirmed(false);
t.setID("type1Id#Rem");
t.setFixed(true);
t.setServerRemote(true);
t.setServerProjectIndepended(true);
t.setGroupName("sGroup");
t.setName("type1Name");
t.setDelay(200);
t.setDuration(300);
sut.checkParseMessageData(sut.createMessage(t));
}
CHECK_MESSAGE(cbEvents.front() == "1: true type1Id#Rem type1Name sGroup", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
// Local Objects
{
Message::ReportType t;
t.setConfirmed(false);
t.setID("type1Id#Loc");
t.setFixed(true);
t.setServerRemote(false);
t.setServerProjectIndepended(true);
t.setGroupName("sGroup");
t.setName("type1Name");
t.setDelay(100);
t.setDuration(200);
sut.checkParseMessageData(sut.createMessage(t));
}
CHECK_MESSAGE(cbEvents.front() == "veto check false/false", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: false type1Id#Loc type1Name sGroup", cbEvents.front());
cbEvents.pop();
{
Message::ReportType t;
t.setConfirmed(false);
t.setID("type2Id#Loc");
t.setFixed(true);
t.setServerRemote(false);
t.setServerProjectIndepended(true);
t.setGroupName("sGroup");
t.setName("type2Name");
t.setDelay(100);
t.setDuration(200);
sut.checkParseMessageData(sut.createMessage(t));
}
CHECK_MESSAGE(cbEvents.front() == "veto check false/false", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: false type2Id#Loc type2Name sGroup", cbEvents.front());
cbEvents.pop();
{
Message::ReportType t;
t.setConfirmed(false);
t.setID("type1Id#Loc");
t.setFixed(true);
t.setServerRemote(false);
t.setServerProjectIndepended(true);
t.setGroupName("sGroup");
t.setName("type1Name");
t.setDelay(200);
t.setDuration(300);
sut.checkParseMessageData(sut.createMessage(t));
}
CHECK_MESSAGE(cbEvents.front() == "1: false type1Id#Loc type1Name sGroup", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
}
TEST_CASE_FIXTURE(SpitClientFix, "Message Counter") {
Message::ReportType t1;
t1.setID("type#1");
t1.setServerRemote(true);
auto m1 = sut.createMessage(t1);
Message::ReportType t2;
t2.setID("type#2");
t2.setServerRemote(true);
auto m2 = sut.createMessage(t2);
Message::ReportType t3;
t3.setID("type#3");
t3.setServerRemote(true);
auto m3 = sut.createMessage(t3);
Message::ReportType t4;
t4.setID("type#4");
t4.setServerRemote(true);
auto m4 = sut.createMessage(t4);
Message::ReportType t5;
t5.setID("type#5");
t5.setServerRemote(true);
auto m5 = sut.createMessage(t5);
Message::ReportType t6;
t6.setID("type#6");
t6.setServerRemote(true);
auto m6 = sut.createMessage(t6);
CHECK(cbEvents.empty());
SUBCASE("Normal order") {
REQUIRE(cbEvents.size() == 0);
sut.checkParseMessageData(m1);
CHECK_MESSAGE(cbEvents.front() == "0: true type#1 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m2);
CHECK_MESSAGE(cbEvents.front() == "0: true type#2 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m3);
CHECK_MESSAGE(cbEvents.front() == "0: true type#3 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m4);
CHECK_MESSAGE(cbEvents.front() == "0: true type#4 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
}
CHECK(cbEvents.empty());
SUBCASE("overtakes one") {
REQUIRE(cbEvents.size() == 0);
sut.checkParseMessageData(m1);
CHECK_MESSAGE(cbEvents.front() == "0: true type#1 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m3);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m2);
CHECK_MESSAGE(cbEvents.front() == "0: true type#2 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#3 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m4);
CHECK_MESSAGE(cbEvents.front() == "0: true type#4 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
}
CHECK(cbEvents.empty());
SUBCASE("overtakes two") {
REQUIRE(cbEvents.size() == 0);
sut.checkParseMessageData(m1);
CHECK_MESSAGE(cbEvents.front() == "0: true type#1 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m4);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m2);
CHECK_MESSAGE(cbEvents.front() == "0: true type#2 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m3);
CHECK_MESSAGE(cbEvents.front() == "0: true type#3 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#4 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m5);
CHECK_MESSAGE(cbEvents.front() == "0: true type#5 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
}
CHECK(cbEvents.empty());
SUBCASE("many overtakes") {
REQUIRE(cbEvents.size() == 0);
sut.checkParseMessageData(m1);
CHECK_MESSAGE(cbEvents.front() == "0: true type#1 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m5);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m6);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m4);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m3);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m2);
CHECK_MESSAGE(cbEvents.front() == "0: true type#2 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#3 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#4 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#5 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#6 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
}
CHECK(cbEvents.empty());
SUBCASE("reverse order") {
REQUIRE(cbEvents.size() == 0);
sut.checkParseMessageData(m1);
CHECK_MESSAGE(cbEvents.front() == "0: true type#1 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
sut.checkParseMessageData(m6);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m5);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m4);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m3);
CHECK(cbEvents.empty());
sut.checkParseMessageData(m2);
CHECK_MESSAGE(cbEvents.front() == "0: true type#2 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#3 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#4 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#5 ", cbEvents.front());
cbEvents.pop();
CHECK_MESSAGE(cbEvents.front() == "0: true type#6 ", cbEvents.front());
cbEvents.pop();
CHECK(cbEvents.empty());
}
}
@@ -0,0 +1,516 @@
/**
* @file spitRepoTest.cpp
* @author Gustice
* @brief
*/
#include "doctest/doctest.h"
#include <fmt/core.h>
#include <iostream>
#include <queue>
#include "spit_processor.hpp"
using namespace spit;
using namespace std;
static queue<string> cbEvents;
class ClientMockCmplx {
public:
void onServerEvent(SProcessor::ServerEvent event, const SadDetectedServer &detectedServer) {
}
void onConnectionStatus(string serverID, string serverComputerName, string serverName, int serverStepTime, SProcessor::Connection connectionStatus, SProcessor::Connection oldConnectionStatus) {
}
void onProjectUpdate(SProcessor::ProjUpdate state, string projectId) {
}
void onSpitType(SProcessor::ObjectEvent event, bool isRemote, const SType &sType) {
cbEvents.push(fmt::format("{}: {} {} {} {}", (int)event, isRemote, sType.getID(), sType.Name.get(), sType.GroupName.get()));
}
void onSpitObject(SProcessor::ObjectEvent event, bool isRemote, const SType &sType, const SObject &sObject) {
cbEvents.push(fmt::format("{}: {} {} {} {} {}", (int)event, isRemote, sType.getID(), sType.Name.get(), sObject.Name.get(), sObject.getID()));
}
void onPlay(string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames) {
}
void onPlaySpitType(string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value) {
}
void onPlayRemoteObjectStatus(const SType &sType, const SObject &sObject, uint64_t p_FrameInsideObject, int value) {
}
bool onCheckSpitTypeVeto(bool knownType, bool createdByClient) {
cbEvents.push(fmt::format("veto check {}/{}", knownType, createdByClient));
return true;
}
bool onCheckSpitObjectVeto(bool knownType) {
return true;
}
};
class SpitClientCmplsFix {
protected:
ClientMockCmplx client;
SProcessor::Callbacks callbacks{
.onServerEvent = [&](SProcessor::ServerEvent event, const SadDetectedServer &detectedServer) { client.onServerEvent(event, detectedServer); },
.onConnectionStatus = [&](string serverID, string serverComputerName, string serverName, int serverStepTime, SProcessor::Connection connectionStatus, SProcessor::Connection oldConnectionStatus) { client.onConnectionStatus(serverID, serverComputerName, serverName, serverStepTime, connectionStatus, oldConnectionStatus); },
.onProjectUpdate = [&](SProcessor::ProjUpdate state, string projectId) { client.onProjectUpdate(state, projectId); },
.onSpitType = [&](SProcessor::ObjectEvent event, bool isRemote, const SType &t) { client.onSpitType(event, isRemote, t); },
.onSpitObject = [&](SProcessor::ObjectEvent event, bool isRemote, const SType &t, const SObject &o) { client.onSpitObject(event, isRemote, t, o); },
.onPlay = [&](string playerID, string playerName, char playerType, bool playerIsRunning, uint64_t timeFrames) { client.onPlay(playerID, playerName, playerType, playerIsRunning, timeFrames); },
.onPlaySpitType = [&](string playerID, string spitTypeID, bool playerIsRunning, bool started, bool ended, double value) { client.onPlaySpitType(playerID, spitTypeID, playerIsRunning, started, ended, value); },
.onPlayRemoteObjectStatus = [&](const SType &t, const SObject &o, uint64_t p_FrameInsideObject, int value) { client.onPlayRemoteObjectStatus(t, o, p_FrameInsideObject, value); },
.onCheckSpitTypeVeto = [&](bool knownType, bool createdByClient) { return client.onCheckSpitTypeVeto(knownType, createdByClient); },
.onCheckSpitObjectVeto = [&](bool knownType) { return client.onCheckSpitObjectVeto(knownType); }};
SProcessor::InternalCallbacks intCallbacks {
.delay = [&](int ms){ return ; },
.sendMessage = [&](Message::OPPart &msg){ return 0; },
.parseMessage = [&](Message &msg) { },
};
SProcessor sut{"sut", "sutProj", "dev", "##GUID##", callbacks, intCallbacks};
};
static void spoofMsgCounter(std::vector<uint8_t> &msg, uint8_t cnt) {
msg.at(11) = cnt;
}
TEST_CASE_FIXTURE(SpitClientCmplsFix, "Spit types Raw") {
int cnt = 1;
{
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x41, 0x63, 0x00, 0x00, 0x00, // #spit#.....Ac...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ........00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x37, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000m70va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x00, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x6c, 0x00, // ....MainScene.l.
/*00a0*/ 0x00, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ement..........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x50, 0x6f, 0x73, // ...........InPos
/*00c0*/ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x63, 0x65, 0x6e, 0x65, // ition1Scene.cene
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ...........
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000m70va8bom InPosition1Scene MainScene", cbEvents.front());
cbEvents.pop();
}
{
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x63, 0x00, 0x00, 0x00, // #spit#.....Bc...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ........00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x68, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000mh0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x00, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x6c, 0x00, // ....MainScene.l.
/*00a0*/ 0x00, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ement..........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x50, 0x6f, 0x73, // ...........InPos
/*00c0*/ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x63, 0x65, 0x6e, 0x65, // ition2Scene.cene
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ...........
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000mh0va8bom InPosition2Scene MainScene", cbEvents.front());
cbEvents.pop();
}
{
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x63, 0x00, 0x00, 0x00, // #spit#.....Cc...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ........00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x72, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000mr0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x00, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x6c, 0x00, // ....MainScene.l.
/*00a0*/ 0x00, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ement..........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x50, 0x6f, 0x73, // ...........InPos
/*00c0*/ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x33, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x63, 0x65, 0x6e, 0x65, // ition3Scene.cene
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ...........
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000mr0va8bom InPosition3Scene MainScene", cbEvents.front());
cbEvents.pop();
}
{
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x44, 0x63, 0x00, 0x00, 0x00, // #spit#.....Dc...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ........00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6e, 0x6b, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000nk0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x00, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x6c, 0x00, // ....MainScene.l.
/*00a0*/ 0x00, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ement..........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x50, 0x6f, 0x73, // ...........InPos
/*00c0*/ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x34, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x63, 0x65, 0x6e, 0x65, // ition4Scene.cene
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ...........
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000nk0va8bom InPosition4Scene MainScene", cbEvents.front());
cbEvents.pop();
}
{
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x63, 0x00, 0x00, 0x00, // #spit#.....Ec...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ........00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6e, 0x75, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000nu0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x00, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x6c, 0x00, // ....MainScene.l.
/*00a0*/ 0x00, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ement..........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x50, 0x6f, 0x73, // ...........InPos
/*00c0*/ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x35, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x63, 0x65, 0x6e, 0x65, // ition5Scene.cene
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ...........
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000nu0va8bom InPosition5Scene MainScene", cbEvents.front());
cbEvents.pop();
}
{
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x63, 0x00, 0x00, 0x00, // #spit#.....Fc...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x15, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ........00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6f, 0x34, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000o40va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x00, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x6c, 0x00, // ....MainScene.l.
/*00a0*/ 0x00, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ement..........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x50, 0x6f, 0x73, // ...........InPos
/*00c0*/ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x36, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x63, 0x65, 0x6e, 0x65, // ition6Scene.cene
/*00d0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00e0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00f0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ...........
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000o40va8bom InPosition6Scene MainScene", cbEvents.front());
cbEvents.pop();
}
CHECK(cbEvents.empty());
{ // In InPosition1Scene
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7b, 0x63, 0x00, 0x00, 0x00, // #spit#.....{c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x37, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000m70va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 0000000000000000
/*00f0*/ 0x6d, 0x37, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // m70va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb9, 0x04, 0x00, // ................
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0xed, 0x35, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....5..........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000m70va8bom InPosition1Scene play 00000m8uedyyt0000000000000000m70va8bom", cbEvents.front());
cbEvents.pop();
}
{ // In InPosition2Scene
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7d, 0x63, 0x00, 0x00, 0x00, // #spit#.....}c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x68, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000mh0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 0000000000000000
/*00f0*/ 0x6d, 0x68, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // mh0va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0xef, 0x06, 0x00, // ............r...
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x26, 0x2d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....&-..........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000mh0va8bom InPosition2Scene play 00000m8uedyyt0000000000000000mh0va8bom", cbEvents.front());
cbEvents.pop();
}
{ // In InPosition3Scene
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x72, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000mr0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 0000000000000000
/*00f0*/ 0x6d, 0x72, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // mr0va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xfc, 0x08, 0x00, // ................
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x52, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....R...........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000mr0va8bom InPosition3Scene play 00000m8uedyyt0000000000000000mr0va8bom", cbEvents.front());
cbEvents.pop();
}
{ // In InPosition4Scene
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x81, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6e, 0x6b, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000nk0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 0000000000000000
/*00f0*/ 0x6e, 0x6b, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // nk0va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0x0a, 0x00, // ................
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x36, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....63..........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000nk0va8bom InPosition4Scene play 00000m8uedyyt0000000000000000nk0va8bom", cbEvents.front());
cbEvents.pop();
}
{ // In InPosition5Scene
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x83, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6e, 0x75, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000nu0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 0000000000000000
/*00f0*/ 0x6e, 0x75, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // nu0va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x01, 0x0d, 0x00, // ................
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x75, 0x29, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....u)..........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000nu0va8bom InPosition5Scene play 00000m8uedyyt0000000000000000nu0va8bom", cbEvents.front());
cbEvents.pop();
}
{ // In InPosition6Scene
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x85, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x6f, 0x34, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00000o40va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 0000000000000000
/*00f0*/ 0x6f, 0x34, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // o40va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x05, 0x0f, 0x00, // ................
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x13, 0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....6..........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK_MESSAGE(cbEvents.front() == "0: true 00000m8uedyyt0000000000000000o40va8bom InPosition6Scene play 00000m8uedyyt0000000000000000o40va8bom", cbEvents.front());
cbEvents.pop();
}
{ // unknown
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x87, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x31, 0x61, 0x75, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00001au0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, // 0000000000000001
/*00f0*/ 0x61, 0x75, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // au0va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x06, 0x11, 0x00, // ............2...
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0x33, 0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....3S..........
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK(cbEvents.empty());
}
{ // unknown
std::vector<uint8_t> msg = {
/*0000*/ 0x23, 0x73, 0x70, 0x69, 0x74, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x89, 0x63, 0x00, 0x00, 0x00, // #spit#......c...
/*0010*/ 0x34, 0x30, 0x35, 0x63, 0x37, 0x31, 0x30, 0x30, 0x2d, 0x36, 0x34, 0x65, 0x38, 0x2d, 0x34, 0x33, // 405c7100-64e8-43
/*0020*/ 0x35, 0x64, 0x2d, 0x38, 0x61, 0x37, 0x62, 0x2d, 0x30, 0x30, 0x63, 0x35, 0x36, 0x32, 0x39, 0x66, // 5d-8a7b-00c5629f
/*0030*/ 0x39, 0x63, 0x63, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x38, 0x36, 0x36, 0x63, 0x39, // 9ccf.....70866c9
/*0040*/ 0x62, 0x2d, 0x61, 0x66, 0x31, 0x63, 0x2d, 0x34, 0x37, 0x36, 0x35, 0x2d, 0x61, 0x31, 0x37, 0x65, // b-af1c-4765-a17e
/*0050*/ 0x2d, 0x38, 0x62, 0x34, 0x35, 0x63, 0x39, 0x33, 0x66, 0x33, 0x61, 0x63, 0x61, 0x00, 0x00, 0x00, // -8b45c93f3aca...
/*0060*/ 0x00, 0x00, 0x1f, 0x53, 0x01, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, // ...S....00000m8u
/*0070*/ 0x65, 0x64, 0x79, 0x79, 0x74, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // edyyt00000000000
/*0080*/ 0x30, 0x30, 0x30, 0x30, 0x31, 0x66, 0x6a, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, // 00001fj0va8bom..
/*0090*/ 0x00, 0x01, 0x01, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x2f, 0x20, 0x46, 0x61, 0x64, 0x65, 0x20, 0x4f, // ...play./ Fade O
/*00a0*/ 0x75, 0x74, 0x00, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ut.cy...........
/*00b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00c0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*00d0*/ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x6d, 0x38, 0x75, 0x65, 0x64, 0x79, 0x79, 0x74, // ...00000m8uedyyt
/*00e0*/ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, // 0000000000000001
/*00f0*/ 0x66, 0x6a, 0x30, 0x76, 0x61, 0x38, 0x62, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x69, 0x70, 0x00, // fj0va8bom....ip.
/*0100*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0110*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0120*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0130*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x3a, 0x14, 0x00, // .............:..
/*0140*/ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0150*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, // ............@B..
/*0160*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0170*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0180*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*0190*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01a0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
/*01b0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ......
};
spoofMsgCounter(msg, cnt++);
sut.checkParseMessageData(std::vector<char>(msg.begin(), msg.end()));
CHECK(cbEvents.empty());
}
}
+128
View File
@@ -0,0 +1,128 @@
/**
* @file spitRepoTest.cpp
* @author Gustice
* @brief
*/
#include "doctest/doctest.h"
#include <fmt/core.h>
#include <iostream>
#include "spit_repo.hpp"
using namespace spit;
using namespace std;
struct SomeType {
string id;
int val{};
int tst{};
string getID() { return id; }
};
class SpitRepoFix {
protected:
SpitRepo<SomeType> sut;
};
TEST_CASE_FIXTURE(SpitRepoFix, "Typical use case") {
CHECK_EQ(sut.getSize(), 0);
CHECK_EQ(sut.hasEntry("obj1"), false);
CHECK_EQ(sut.getEntry("obj1"), nullptr);
CHECK_THROWS(sut.getEntryRef("obj1"));
CHECK_EQ(sut.removeEntry("obj1"), false);
// CHECK_EQ(sut.removeEntry(1), false);
auto obj1 = make_unique<SomeType>("obj1", 1, 0);
sut.addEntry(move(obj1));
{
CHECK_EQ(sut.getSize(), 1);
CHECK_EQ(sut.hasEntry("obj1"), true);
CHECK_EQ(sut.getEntry("obj1")->val, 1);
CHECK_EQ(sut.getEntryRef("obj1").val, 1);
}
auto obj2 = make_unique<SomeType>("obj2", 2, 0);
sut.addEntry(move(obj2));
{
CHECK_EQ(sut.getSize(), 2);
CHECK_EQ(sut.hasEntry("obj2"), true);
CHECK_EQ(sut.getEntry("obj2")->val, 2);
CHECK_EQ(sut.getEntryRef("obj2").val, 2);
}
auto obj3 = make_unique<SomeType>("obj3", 3, 0);
sut.addEntry(move(obj3));
{
CHECK_EQ(sut.getSize(), 3);
CHECK_EQ(sut.hasEntry("obj3"), true);
CHECK_EQ(sut.getEntry("obj3")->val, 3);
CHECK_EQ(sut.getEntryRef("obj3").val, 3);
}
auto obj4 = make_unique<SomeType>("obj4", 4, 0);
sut.addEntry(move(obj4));
{
CHECK_EQ(sut.getSize(), 4);
CHECK_EQ(sut.hasEntry("obj4"), true);
CHECK_EQ(sut.getEntry("obj4")->val, 4);
CHECK_EQ(sut.getEntryRef("obj4").val, 4);
}
{
auto *p = const_cast<SomeType *>(sut.getEntry("obj3"));
auto &r = sut.getEntryRef("obj3");
CHECK_EQ(p->val, 3);
CHECK_EQ(r.val, 3);
CHECK_EQ(r.tst, 0);
p->tst = 20;
CHECK_EQ(r.tst, 20);
}
{
const auto & repo = sut.getRepo();
CHECK_EQ(repo.size(), 4);
CHECK_EQ(repo.at("obj1")->val, 1);
CHECK_EQ(repo.at("obj2")->val, 2);
CHECK_EQ(repo.at("obj3")->val, 3);
CHECK_EQ(repo.at("obj4")->val, 4);
}
{
CHECK_EQ(sut.removeEntry("obj1"), true);
CHECK_EQ(sut.removeEntry("obj3"), true);
const auto & repo = sut.getRepo();
CHECK_EQ(sut.getSize(), 2);
CHECK_EQ(repo.size(), 2);
CHECK_EQ(repo.at("obj2")->val, 2);
CHECK_EQ(repo.at("obj4")->val, 4);
}
auto obj5 = make_unique<SomeType>("obj5", 5, 0);
sut.addEntry(move(obj5));
{
const auto & repo = sut.getRepo();
CHECK_EQ(sut.getSize(), 3);
CHECK_EQ(repo.size(), 3);
CHECK_EQ(repo.at("obj2")->val, 2);
CHECK_EQ(repo.at("obj4")->val, 4);
CHECK_EQ(repo.at("obj5")->val, 5);
}
{
sut.clearEntries();
CHECK_EQ(sut.getSize(), 0);
}
auto obj6 = make_unique<SomeType>("obj6", 6, 0);
sut.addEntry(move(obj6));
{ // Still works after clear
CHECK_EQ(sut.getSize(), 1);
CHECK_EQ(sut.hasEntry("obj6"), true);
CHECK_EQ(sut.getEntry("obj6")->val, 6);
CHECK_EQ(sut.getEntryRef("obj6").val, 6);
}
}
+11
View File
@@ -0,0 +1,11 @@
/**
* @file uTestMain.cpp
* @author Gustice
* @brief
*/
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"
TEST_CASE("TestTest") {
CHECK(true == true);
}
+88
View File
@@ -0,0 +1,88 @@
/**
* @file spitRepoTest.cpp
* @author Gustice
* @brief
*/
#include "doctest/doctest.h"
#include <fmt/core.h>
#include <iostream>
#include "spit_type.hpp"
using namespace spit;
using namespace std;
class SpitTypetFix {
protected:
};
TEST_CASE_FIXTURE(SpitTypetFix, "check confirmend behaviour") {
{
SType sut("#Id#123");
CHECK(sut.getID() == "#Id#123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.GroupName.set("G123") == true);
CHECK(sut.GroupName.get() == "G123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.GroupName.set("G123") == false);
CHECK(sut.getConfirmed() == true);
CHECK(sut.GroupName.set("G321") == true);
CHECK(sut.GroupName.get() == "G321");
CHECK(sut.getConfirmed() == false);
}
{
SType sut("#Id#123");
CHECK(sut.getID() == "#Id#123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Fixed.set(true) == true);
CHECK(sut.Fixed.get() == true);
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Fixed.set(true) == false);
CHECK(sut.getConfirmed() == true);
CHECK(sut.Fixed.set(false) == true);
CHECK(sut.Fixed.get() == false);
CHECK(sut.getConfirmed() == false);
}
{
SType sut("#Id#123");
CHECK(sut.getID() == "#Id#123");
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.DefaultDelay.set(123) == true);
CHECK(sut.DefaultDelay.get() == 123);
CHECK(sut.getConfirmed() == false);
sut.setConfirmed(true);
CHECK(sut.getConfirmed() == true);
CHECK(sut.DefaultDelay.set(123) == false);
CHECK(sut.getConfirmed() == true);
CHECK(sut.DefaultDelay.set(321) == true);
CHECK(sut.DefaultDelay.get() == 321);
CHECK(sut.getConfirmed() == false);
}
// ...
{
SType sut("#Id#123", "grp123", "name123", true, false, 1234, 4321);
CHECK(sut.getID() == "#Id#123");
CHECK(sut.GroupName.get() == "grp123");
CHECK(sut.Name.get() == "name123");
CHECK(sut.Fixed.get() == true);
CHECK(sut.ProjectIndepended.get() == false);
CHECK(sut.DefaultDelay.get() == 1234);
CHECK(sut.DefaultDuration.get() == 4321);
}
}
+4
View File
@@ -0,0 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
REQUIRES devHal
)
@@ -0,0 +1,70 @@
#pragma once
#include "stepperDrv.hpp"
#include "stepperMotor.hpp"
#include <cmath>
#include "logging.hpp"
class WatchMotor {
static constexpr uint8_t Positions = 6;
public:
using AlmostFinishedCb = void (*)(uint8_t newIdx);
WatchMotor(IStepperMotor &stepper, AlmostFinishedCb onDone, ILogging &logger)
: _stepper(stepper),
_onFinCb(onDone),
_logger(logger) {
}
void moveTo(uint8_t position, uint8_t profile, int minJumps, float accel, float speed) {
auto sign = position % 6;
int minTurns = minJumps / 6;
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;
}
int steps = 0;
if (_currentIndex < sign) {
steps = (sign - _currentIndex);
} else if (_currentIndex >= sign) {
steps = (sign + 6 - _currentIndex);
}
steps += minTurns * 6;
if (steps < minJumps) {
steps += 6;
}
float delta = 2.0F * std::numbers::pi / 6 * steps;
ESP_LOGD("MV", "Moving to %d by %.2f + %.2f", sign, delta, corr);
_stepper.moveBy(delta + corr, profile, accel, speed, [&](int diff) {
_logger.logv(ILogging::Severity::Debug,"Almost done with head=%i",diff);
if (diff < 6) {
_logger.logv(ILogging::Severity::Warning,"Low headroom in Profile pipeline=%i",diff);
}
if (_onFinCb) {
_onFinCb(position);
}
});
_currentIndex = sign;
}
float getScaled() { return _stepper.getScaledPos() * 6; }
uint8_t getIndex() { return _currentIndex; }
private:
IStepperMotor &_stepper;
uint8_t _currentIndex{};
AlmostFinishedCb _onFinCb{};
ILogging &_logger;
};
+1
View File
@@ -0,0 +1 @@
// Dummy file
@@ -0,0 +1,5 @@
UnitTestsFrame()
target_link_libraries(${moduleName} PUBLIC
devHal
bases
)
@@ -0,0 +1,112 @@
/**
* @file TestableUTest.cpp
* @author Gustice
* @brief
*
* @copyright Copyright (c) 2024
*/
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"
#include <iostream>
#include <numbers>
#include "watchFace.hpp"
class StepperMotorMock : public IStepperMotor {
public:
void moveBy(float angle, uint8_t profile = 0) override {
lastAngle = angle;
lastProfile = profile;
}
void moveBy(float angle, uint8_t profile, float accel, float speed, std::function<void(int diff)> profileDone = nullptr) override {
lastAngle = angle;
lastProfile = profile;
}
float getScaledPos() const override {
return nextPos;
}
uint16_t getQuanted() const override {
return 0;
}
float lastAngle{};
uint8_t lastProfile{};
float lastAccel{};
float lastSpeed{};
float nextPos{};
};
class LoggerMock : public ILogging {
void output(Severity severity, std::string message) override {
// do nothing
}
};
void onFin(uint8_t idx) {
}
class WatchFaceFixture {
using PositionStore = StepperMotor::Position<50, 5>;
public:
protected:
static constexpr int MicroSteps = 32;
StepperMotorMock motor;
LoggerMock logger;
WatchMotor sut{motor, onFin, logger};
private:
};
TEST_CASE_FIXTURE(WatchFaceFixture, "Moving simple steps") {
auto next = 0*std::numbers::pi/3;
motor.nextPos = next;
sut.moveTo(1, 0, 0, 1, 1);
auto delta = 1*std::numbers::pi/3;
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(2, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 2.0F/6;
sut.moveTo(3, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 3.0F/6;
sut.moveTo(4, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 4.0F/6;
sut.moveTo(5, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 5.0F/6;
sut.moveTo(6, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 6.0F/6;
sut.moveTo(1, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(2, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
}
TEST_CASE_FIXTURE(WatchFaceFixture, "Moving multiple turns") {
auto next = 0*std::numbers::pi/3;
motor.nextPos = next;
sut.moveTo(1, 0, 0, 1, 1);
auto delta = 1*std::numbers::pi/3;
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(1, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(6*delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(1, 0, 7, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(12*delta).epsilon(0.000625)); // MicroStep tolerance
}
+1 -1
Submodule core updated: 3041a17851...37e288c012
+15 -9
View File
@@ -1,15 +1,21 @@
dependencies:
ethernet_init:
component_hash: null
frozen-eye/esp_telnet:
component_hash: e00a16d6372fa31df46b32e330847d6e09af2ec184d8c7cac4d183b3daac02e5
dependencies:
- name: idf
require: private
version: '>=4.0'
source:
path: C:\Tools\ESP-IDF\v5.3\esp-idf\examples\ethernet\basic\components\ethernet_init
type: local
version: '*'
registry_url: https://components.espressif.com/
type: service
version: 0.0.2
idf:
component_hash: null
source:
type: idf
version: 5.3.0
manifest_hash: 736e193f01d8a1ca4afaed91b473283f46d56db468270aee2f055b9425257e7f
version: 5.4.1
direct_dependencies:
- frozen-eye/esp_telnet
- idf
manifest_hash: 8e2a908d16408b9cafcd4c4b109b841acfca6e660d2500fc6d1362f0f143376c
target: esp32c6
version: 1.0.0
version: 2.0.0
Binary file not shown.
+188
View File
@@ -0,0 +1,188 @@
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=2b2e0h (176864) map
I (128) esp_image: segment 1: paddr=0003b308 vaddr=40800000 size=04d10h ( 19728) load
I (134) esp_image: segment 2: paddr=00040020 vaddr=42000020 size=6bfe0h (442336) map
I (226) esp_image: segment 3: paddr=000ac008 vaddr=40804d10 size=094b0h ( 38064) load
I (235) esp_image: segment 4: paddr=000b54c0 vaddr=4080e1c0 size=01bd0h ( 7120) load
I (241) boot: Loaded app from partition at offset 0x10000
I (242) boot: Disabling RNG early entropy source...
I (256) cpu_start: Unicore app
I (265) cpu_start: Pro cpu start user code
I (265) cpu_start: cpu freq: 160000000 Hz
I (265) app_init: Application information:
I (268) app_init: Project name: X_WatchController_FW
I (274) app_init: App version: 858b7d8-dirty
I (279) app_init: Compile time: Apr 8 2025 22:42:59
I (285) app_init: ELF file SHA256: ab11b461f...
I (290) app_init: ESP-IDF: v5.3
I (295) efuse_init: Min chip rev: v0.0
I (300) efuse_init: Max chip rev: v0.99
I (305) efuse_init: Chip rev: v0.0
I (309) heap_init: Initializing. RAM available for dynamic allocation:
I (317) heap_init: At 40812120 len 0006A4F0 (425 KiB): RAM
I (323) heap_init: At 4087C610 len 00002F54 (11 KiB): RAM
I (329) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM
I (336) spi_flash: detected chip: generic
I (340) spi_flash: flash io: dio
I (345) sleep: Configure to isolate all GPIO pins in sleep state
I (351) sleep: Enable automatic switching of GPIO sleep configuration
I (358) coexist: coex firmware version: dab85ae96
I (385) coexist: coexist rom version 5b8dcfa
I (386) main_task: Started on CPU0
I (386) main_task: Calling app_main()
I (396) esp_eth.netif.netif_glue: 42:4c:ca:ff:fe:4e
I (396) esp_eth.netif.netif_glue: ethernet attached to netif
I (406) Watch: Ethernet Started
I (406) Watch: Start Lighting
I (406) gpio: GPIO[10]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (416) gpio: GPIO[11]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (426) Watch: Start Stepper
I (426) gpio: GPIO[18]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (436) gpio: GPIO[8]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (446) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (456) TMR: Create timer handle
I (456) TMR: Setup timer
I (456) Stepper: Find Home
I (466) Stepper: Homing ...
I (466) Stepper: Fast find right side of home sensor
I (486) gpio: GPIO[1]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (2206) Stepper: Find right side of home sensor
I (2376) Stepper: Find end of sensor
I (2406) Watch: Ethernet Link Up
I (2406) Watch: Ethernet Link Up
I (2406) Watch: Ethernet HW Addr 00:00:00:00:00:00
I (3406) esp_netif_handlers: eth ip: 172.16.17.56, mask: 255.255.0.0, gw: 172.16.0.1
I (3406) Watch: Ethernet Got IP Address
I (3406) Watch: ~~~~~~~~~~~
I (3406) Watch: ETHIP:172.16.17.56
I (3416) Watch: ETHMASK:255.255.0.0
I (3416) Watch: ETHGW:172.16.0.1
I (3416) Watch: ~~~~~~~~~~~
I (5186) Stepper: Find left side of home sensor
I (5646) Stepper: Move back to mid position 116
I (6806) Stepper: Reset position
I (7086) Stepper: Got to 1
I (7086) Watch: Fist Position is 0.03
I (7106) Watch: Changing picto-Illum to pos = 0
I (7106) Watch: Current color set r128 g128 b128
I (13426) Watch: Start net services
I (13426) Watch: Starting Telnet task
I (13426) TCP: Socket created
I (13426) Watch: Starting ArtNet task
I (13426) TCP: Socket bound, port 23
I (13426) Watch: Starting SPIT task
I (13426) UDP: Starting syslog session to 172.16.16.10
I (13426) UDP: Socket bound, port 6454
I (13436) Telnet: Socket waiting for connect
I (13436) SPIT: Connected to eth
I (13456) SPIT: - IPv4 address: 172.16.17.56,
I (13456) SPIT: - IPv4 netmask: 255.255.0.0,
I (13446) SysLog: Starting Syslog Task
I (13466) Watch: NEW SPIT-Type ID: ActionStartShuffle GroupName: CatasWatchMovement Name: ActionStartShuffle confirmed: 0
I (13466) UDP: Socket bound, port 514
I (13486) Watch: NEW SPIT-Type ID: ActionMoveTo1 GroupName: CatasWatchMovement Name: ActionMoveTo1 confirmed: 0
I (13496) Watch: NEW SPIT-Type ID: ActionMoveTo2 GroupName: CatasWatchMovement Name: ActionMoveTo2 confirmed: 0
I (13506) Watch: NEW SPIT-Type ID: ActionMoveTo3 GroupName: CatasWatchMovement Name: ActionMoveTo3 confirmed: 0
I (13516) Watch: NEW SPIT-Type ID: ActionMoveTo4 GroupName: CatasWatchMovement Name: ActionMoveTo4 confirmed: 0
I (13526) Watch: NEW SPIT-Type ID: ActionMoveTo5 GroupName: CatasWatchMovement Name: ActionMoveTo5 confirmed: 0
I (13536) Watch: NEW SPIT-Type ID: ActionMoveTo6 GroupName: CatasWatchMovement Name: ActionMoveTo6 confirmed: 0
I (13546) SPIT: Starting Socket managing
I (17656) Watch: SERVER DETECTED
I (17656) Watch: Name: liveShowSPIT
I (17656) Watch: ID: 698a3e4f-1ae9-4dd8-9015-29332d29629e
I (17656) Watch: Computer: GgP17
I (17656) Watch: IP: 172.16.16.10
I (17666) Watch: Port: 15120
I (17666) Watch: Addition:
I (17666) Watch: ClientIP: 172.16.17.56
I (17676) SPIT: connect to 172.16.16.10 / 15120
I (17676) Watch: MySPITApp: eventConnectionStatus 0->0
I (17686) Watch: MySPITApp: eventConnectionStatus 0->4
I (18196) Watch: eventProjectReport ID: CatasWatchProject
I (18196) Watch: eventStartProjectTransfer
W (18306) SPIT: TypeVeto e019646a-4e24-4608-954e-da4ca6761bb6 / ToIgnore 43
I (18326) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000002sb0va8bom Name: -> SPITType: ActionStartShuffle
I (18336) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000002rd0va8bom Name: -> SPITType: ActionMoveTo1
I (18356) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000002vl0va8bom Name: -> SPITType: ActionMoveTo2
I (18366) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000002wh0va8bom Name: -> SPITType: ActionMoveTo3
I (18386) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000002yl0va8bom Name: -> SPITType: ActionMoveTo4
I (18396) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000002tc0va8bom Name: -> SPITType: ActionMoveTo5
I (18416) Watch: NEW SPIT-Object ID: 00000m8uedyyt0000000000000002zi0va8bom Name: -> SPITType: ActionMoveTo6
I (18446) Watch: Min heap size: 297568 / FreeHeap 299880
I (18446) Watch: NEW SPIT-REMOTE-Type ID: playControlStart GroupName: Playcontrol Name: start confirmed: 1
I (18466) Watch: NEW SPIT-REMOTE-Type ID: playControlPause GroupName: Playcontrol Name: pause confirmed: 1
I (18476) Watch: NEW SPIT-REMOTE-Type ID: nextSceneBridge GroupName: Playcontrol Name: next scene confirmed: 1
I (18496) Watch: NEW SPIT-REMOTE-Type ID: nextMainSceneBridge GroupName: Playcontrol Name: next main scene confirmed: 1
I (18506) Watch: NEW SPIT-REMOTE-Type ID: previuosSceneBridge GroupName: Playcontrol Name: previous scene confirmed: 1
I (18526) Watch: NEW SPIT-REMOTE-Type ID: previousMainSceneBridge GroupName: Playcontrol Name: previous main scene confirmed: 1
I (18546) Watch: NEW SPIT-REMOTE-Type ID: mainmixerSound_Volume00 GroupName: Main Mixer Name: Sound confirmed: 1
I (18556) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_Dimmer00 GroupName: Main Mixer Name: confirmed: 1
I (18566) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB00 GroupName: Main Mixer Name: confirmed: 1
I (18586) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB10 GroupName: Main Mixer Name: confirmed: 1
I (18606) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB20 GroupName: Main Mixer Name: confirmed: 1
I (18616) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB30 GroupName: Main Mixer Name: confirmed: 1
I (18636) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB40 GroupName: Main Mixer Name: confirmed: 1
I (18646) Watch: NEW SPIT-REMOTE-Type ID: mainmixerDMX_RGB50 GroupName: Main Mixer Name: confirmed: 1
I (18666) Watch: NEW SPIT-REMOTE-Type ID: mainmixerMedia_SoundVolume00 GroupName: Main Mixer Name: Media confirmed: 1
I (18686) Watch: NEW SPIT-REMOTE-Type ID: mainmixerMedia_Transparency00 GroupName: Main Mixer Name: Media confirmed: 1
I (18696) Watch: NEW SPIT-REMOTE-Type ID: selectedJingles GroupName: Playcontrol Name: selected Jingles confirmed: 1
I (18716) Watch: NEW SPIT-REMOTE-Type ID: selectedJingleGroups GroupName: Playcontrol Name: selected Jinglegroups confirmed: 1
I (18726) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000lo0va8bom GroupName: MainScene Name: ChangingPositionScene confirmed: 1
I (18746) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000m70va8bom GroupName: MainScene Name: InPosition1Scene confirmed: 1
I (18756) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000mh0va8bom GroupName: MainScene Name: InPosition2Scene confirmed: 1
I (18776) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000mr0va8bom GroupName: MainScene Name: InPosition3Scene confirmed: 1
I (18786) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000nk0va8bom GroupName: MainScene Name: InPosition4Scene confirmed: 1
I (18806) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000nu0va8bom GroupName: MainScene Name: InPosition5Scene confirmed: 1
I (18826) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000000o40va8bom GroupName: MainScene Name: InPosition6Scene confirmed: 1
I (18836) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000001au0va8bom GroupName: MainScene Name: StartShuffle confirmed: 1
I (18856) Watch: NEW SPIT-REMOTE-Type ID: 00000m8uedyyt0000000000000001fj0va8bom GroupName: MainScene Name: Fence confirmed: 1
I (18866) Watch: NEW SPIT-REMOTE-Object ID: playControlStart Name: start -> SPITType: start
I (18886) Watch: NEW SPIT-REMOTE-Object ID: playControlPause Name: pause -> SPITType: pause
I (18906) Watch: NEW SPIT-REMOTE-Object ID: nextSceneBridge Name: next scene -> SPITType: next scene
I (18916) Watch: NEW SPIT-REMOTE-Object ID: nextMainSceneBridge Name: next main scene -> SPITType: next main scene
I (18936) Watch: NEW SPIT-REMOTE-Object ID: previuosSceneBridge Name: previous scene -> SPITType: previous scene
I (18946) Watch: NEW SPIT-REMOTE-Object ID: previousMainSceneBridge Name: previous main scene -> SPITType: previous main scene
I (18966) Watch: NEW SPIT-REMOTE-Object ID: mainmixerSound_Volume00 Name: Sound Volume -> SPITType: Sound
I (18976) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_Dimmer00 Name: Dimmer -> SPITType:
I (18996) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB00 Name: Red -> SPITType:
I (19006) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB10 Name: Green -> SPITType:
I (19026) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB20 Name: Blue -> SPITType:
I (19036) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB30 Name: Cyan -> SPITType:
I (19056) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB40 Name: Magenta -> SPITType:
I (19076) Watch: NEW SPIT-REMOTE-Object ID: mainmixerDMX_RGB50 Name: Yellow -> SPITType:
I (19086) Watch: NEW SPIT-REMOTE-Object ID: mainmixerMedia_SoundVolume00 Name: Sound Volume -> SPITType: Media
I (19106) Watch: NEW SPIT-REMOTE-Object ID: mainmixerMedia_Transparency00 Name: Media Transparency -> SPITType: Media
I (19116) Watch: NEW SPIT-REMOTE-Object ID: selectedJinglesps Name: Play / Stop -> SPITType: selected Jingles
I (19136) Watch: NEW SPIT-REMOTE-Object ID: selectedJinglespf Name: Play / Fade Out -> SPITType: selected Jingles
I (19146) Watch: NEW SPIT-REMOTE-Object ID: selectedJingleGroupsps Name: Play / Stop -> SPITType: selected Jinglegroups
I (19166) Watch: NEW SPIT-REMOTE-Object ID: selectedJingleGroupspf Name: Play / Fade Out -> SPITType: selected Jinglegroups
I (19176) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000lo0va8bom Name: play -> SPITType: ChangingPositionScene
W (19196) SPIT: Finished searching
W (19196) SPIT: Start working
I (19196) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000m70va8bom Name: play -> SPITType: InPosition1Scene
I (19216) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000mh0va8bom Name: play -> SPITType: InPosition2Scene
I (19226) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000mr0va8bom Name: play -> SPITType: InPosition3Scene
I (19246) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000nk0va8bom Name: play -> SPITType: InPosition4Scene
I (19256) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000nu0va8bom Name: play -> SPITType: InPosition5Scene
I (19276) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000000o40va8bom Name: play -> SPITType: InPosition6Scene
I (19286) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000001au0va8bom Name: play -> SPITType: StartShuffle
I (19306) Watch: NEW SPIT-REMOTE-Object ID: 00000m8uedyyt0000000000000001fj0va8bom Name: play -> SPITType: Fence
I (19316) Watch: eventEndProjectTransfer
I (19316) Watch: eventProjectReport ID: CatasWatchProject Name: FramesPerSecond: 44100
I (23446) Watch: Min heap size: 278024 / FreeHeap 282460
I (28446) Watch: Min heap size: 278024 / FreeHeap 282460
I (33446) Watch: Min heap size: 278024 / FreeHeap 282460
I (38446) Watch: Min heap size: 278024 / FreeHeap 282460
I (43446) Watch: Min heap size: 278024 / FreeHeap 282460
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
{\rtf1\ansi
{\fonttbl\f0\fnil Monospaced;}
\par
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+54
View File
@@ -0,0 +1,54 @@
{
"App": {
"build": {
"compileArgs": [],
"ninjaArgs": [],
"buildDirectoryPath": "",
"sdkconfigDefaults": [],
"sdkconfigFilePath": ""
},
"env": {},
"idfTarget": "",
"flashBaudRate": "",
"monitorBaudRate": "",
"openOCD": {
"debugLevel": -1,
"configs": [],
"args": []
},
"tasks": {
"preBuild": "",
"preFlash": "",
"postBuild": "",
"postFlash": ""
}
},
"UnitTest": {
"build": {
"compileArgs": [],
"ninjaArgs": [],
"buildDirectoryPath": "build_uTest",
"sdkconfigDefaults": [
"test/unitOnTarget/sdkconfig.defaults"
],
"sdkconfigFilePath": ""
},
"env": {
"UNIT_TESTS": "All"
},
"idfTarget": "",
"flashBaudRate": "",
"monitorBaudRate": "",
"openOCD": {
"debugLevel": -1,
"configs": [],
"args": []
},
"tasks": {
"preBuild": "",
"preFlash": "",
"postBuild": "",
"postFlash": ""
}
}
}
+4 -4
View File
@@ -1,25 +1,25 @@
menu "Example Configuration"
config EXAMPLE_WIFI_SSID
config DEVICE_WIFI_SSID
string "Wi-Fi SSID"
default "eth2ap"
help
Set the SSID of Wi-Fi ap interface.
config EXAMPLE_WIFI_PASSWORD
config DEVICE_WIFI_PASSWORD
string "Wi-Fi Password"
default "12345678"
help
Set the password of Wi-Fi ap interface.
config EXAMPLE_WIFI_CHANNEL
config DEVICE_WIFI_CHANNEL
int "WiFi channel"
range 1 13
default 1
help
Set the channel of Wi-Fi ap.
config EXAMPLE_MAX_STA_CONN
config DEVICE_MAX_STA_CONN
int "Maximum STA connections"
default 4
help
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <cstdint>
struct {
const char *syslogDest = "syslogDst"; // example: "172.16.16.10"
const char *mqttBroker = "mqttBroker"; // example: "172.16.16.10"
const char *mqttPrefix = "mqttPrefix"; // example: "SomeTag"
const char *spitServer = "spitServer"; // example: "172.16.16.10"
const char *motorPower = "motorPower"; // example: "50"
} ConfigKeys;
// MQTT Topics
struct {
// Subscriptions:
const char *moveTo = /* <mqttPrefix>/ */ "watch/moveTo";
const char *startShuffle = /* <mqttPrefix>/ */ "watch/startShuffle";
// Publishes:
const char *inPosition = /* <mqttPrefix>/ */ "watch/inPosition";
const char *changingPosition = /* <mqttPrefix>/ */ "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;
+5 -2
View File
@@ -1,3 +1,6 @@
## IDF Component Manager Manifest File
# https://docs.espressif.com/projects/idf-component-manager/en/latest/reference/manifest_file.html
# https://components.espressif.com
dependencies:
ethernet_init:
path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init
frozen-eye/esp_telnet: "^0.0.2"
-119
View File
@@ -1,119 +0,0 @@
/* Ethernet Basic Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "ethernet_init.h"
#include "sdkconfig.h"
static const char *TAG = "eth_example";
/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
uint8_t mac_addr[6] = {0};
/* we can get the ethernet driver handle from event data */
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "Ethernet Link Up");
ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started");
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
}
/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
ESP_LOGI(TAG, "Ethernet Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
}
void app_main(void)
{
// Initialize Ethernet driver
uint8_t eth_port_cnt = 0;
esp_eth_handle_t *eth_handles;
ESP_ERROR_CHECK(example_eth_init(&eth_handles, &eth_port_cnt));
// Initialize TCP/IP network interface aka the esp-netif (should be called only once in application)
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Create instance(s) of esp-netif for Ethernet(s)
if (eth_port_cnt == 1) {
// Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and you don't need to modify
// default esp-netif configuration parameters.
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&cfg);
// Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0])));
} else {
// Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify
// esp-netif configuration parameters for each interface (name, priority, etc.).
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
esp_netif_config_t cfg_spi = {
.base = &esp_netif_config,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
};
char if_key_str[10];
char if_desc_str[10];
char num_str[3];
for (int i = 0; i < eth_port_cnt; i++) {
itoa(i, num_str, 10);
strcat(strcpy(if_key_str, "ETH_"), num_str);
strcat(strcpy(if_desc_str, "eth"), num_str);
esp_netif_config.if_key = if_key_str;
esp_netif_config.if_desc = if_desc_str;
esp_netif_config.route_prio -= i*5;
esp_netif_t *eth_netif = esp_netif_new(&cfg_spi);
// Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[i])));
}
}
// Register user defined event handers
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
// Start Ethernet driver state machine
for (int i = 0; i < eth_port_cnt; i++) {
ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
}
}
+549 -201
View File
File diff suppressed because it is too large Load Diff
+17 -20
View File
@@ -7,8 +7,9 @@
#pragma once
#include <string.h>
#include <stdlib.h>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include "sdkconfig.h"
#include "esp_event.h"
#include "esp_log.h"
@@ -22,12 +23,14 @@
// Component header
#include "Task.hpp"
#include "PwmExpanderPca9685.hpp"
#include "StepperDrv8833.hpp"
#include "pwmExpanderPca9685.hpp"
#include "stepperDrv.hpp"
#include "stepperMotor.hpp"
#include "cliWrapper.hpp"
#include "udpSockets.hpp"
#include "tcpSockets.hpp"
#include "syslog.hpp"
#include "telnetServer.hpp"
#include "Mutex.hpp"
#include "Queue.hpp"
#include "Semaphore.hpp"
@@ -36,19 +39,13 @@
#include "Processor.hpp"
#include "nvsFunctions.hpp"
#include "mqttClient.hpp"
#include "MyApp.h"
// #include "esp_chip_info.h"
// #include "esp_flash.h"
// #include "esp_ota_ops.h"
// #include "esp_partition.h"
// #include "esp_random.h"
// #include "esp_system.h"
// #include "fileSystem.hpp"
// #include "lwip/apps/netbiosns.h"
// #include "mdns.h"
// #include "soc/soc_caps.h"
// #include "systemFunctions.hpp"
// #include <inttypes.h>
// #include <sys/param.h>
// #include <unistd.h>
#include "watchFace.hpp"
#include "random.hpp"
#include "sad_DetectedServer.hpp"
#include "spit_object.hpp"
#include "spit_player.hpp"
#include "spit_type.hpp"
#include "spit_client.hpp"
#include <chrono>
#include <string>
#include <map>
+20
View File
@@ -0,0 +1,20 @@
.PHONY: start test clean
start:
./startCode
# testConfig: buildTestOnTarget
test:
cmake -DTgtEnv:STRING=Target -S . -B buildTestOnTarget
cmake --build buildTestOnTarget --parallel
idf.py -B buildTestOnTarget -p /dev/ttyACM0 flash monitor
uTest:
cmake -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ -DTgtEnv:STRING=Host -S . -B buildUTest
cmake --build buildUTest --parallel
ctest --test-dir buildUTest
clean:
rm -rf build buildTestOnTarget
@@ -0,0 +1 @@
e00a16d6372fa31df46b32e330847d6e09af2ec184d8c7cac4d183b3daac02e5
@@ -0,0 +1,12 @@
Original Telnet Server code is based on the version created and written by the following people:
- Sean Middleditch <sean@sourcemud.org>
- Jack Kelly <endgame.dos@gmail.com>
- Katherine Flavel <kate@elide.org>
- Daniel Loffgren (https://github.com/RyuKojiro)
and taken from here: [https://github.com/seanmiddleditch/libtelnet](https://github.com/seanmiddleditch/libtelnet)
Midificatons are performed by:
- FrozenEye (https://github.com/frozen-eye)
@@ -0,0 +1 @@
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-05-21T14:59:16.171166+00:00", "files": [{"path": "CMakeLists.txt", "size": 303, "hash": "70671f714f52ac79607119703f1ddab4a0b325f25e8981afe7c93baf7af7cd34"}, {"path": "LICENSE", "size": 1063, "hash": "068129b238141ba0ebcb2158402d73408c798f4d8c5a42f4dafaa41a002b9ea2"}, {"path": "AUTHORS", "size": 452, "hash": "277d45436ae96f30f6ee4b2dcde2661e679f2ded4f790cbee0c726d5f13c8dba"}, {"path": "idf_component.yml", "size": 179, "hash": "39f2a2bd0c96ab90610389356a2cf39842364514e2a69c1241e6ecd84b269d72"}, {"path": "Kconfig", "size": 1114, "hash": "ccc9fc290f957c953bdb3bbc8d1079efe7c5fdb82f10d6c7a2dc9973b4046bd7"}, {"path": ".gitignore", "size": 0, "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}, {"path": "src/libtelnet.h", "size": 21611, "hash": "0798f3706642fdd4520923914ddfa59fb9ded670b7716877c80fa852153b8521"}, {"path": "src/server.c", "size": 9226, "hash": "bf90b0df126da4a16d79c626724ce715fdfb8015dd7ea0030b8a6cbf072c947f"}, {"path": "src/libtelnet.c", "size": 44236, "hash": "de15620edc5492aaf6c273ce4c9181cb99490a2153e56db7d7c3f96f3ea7e2b4"}, {"path": "include/telnet/server.h", "size": 1493, "hash": "ebe6d17a86a1c56c97e263bd4d468cffc5d95a3ca810e79388b2a9598f89f8ba"}]}
@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.10)
idf_component_register(
INCLUDE_DIRS
include
src
.
SRCS
src/libtelnet.c
src/server.c
REQUIRES
PRIV_REQUIRES
)
# target_compile_options(${COMPONENT_LIB} PRIVATE -Wall -Wextra -Werror)
# target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17)
@@ -0,0 +1,41 @@
menu "Telnet Server"
config TELNET_SERVER_DEFAULT_PORT
int "Default Telnet Server Port"
default 23
help
Default Telnet Server Port Number
config TELNET_SERVER_MAX_CONNECTIONS
int "Maximum Telnet Server Connections"
default 5
help
Maximum Number of Telnet Server Connections
config TELNET_SERVER_STACK_SIZE
int "Telnet Server Stack Size"
default 4096
help
Telnet Server Stack Size
config TELNET_SERVER_TASK_PRIORITY
int "Telnet Server Task Priority"
range 1 25
default 24
help
Telnet Server Task Priority. In case of high events rate, this parameter could be changed up to (configMAX_PRIORITIES-1).
config TELNET_SERVER_TASK_CORE
int "Telnet Server Task Core"
range 0 1
default 0
help
Telnet Server Task Core
config TELNET_SERVER_REDIRECT_LOGS
int "Redirect Logs to Telnet Server"
range 0 1
default 0
help
Redirect Logs to Telnet Server
endmenu
@@ -0,0 +1,21 @@
Copyright 2024 Frozen Eye
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Some files were not shown because too many files have changed in this diff Show More