Compare commits
32 Commits
master
..
598f1262d7
| Author | SHA1 | Date | |
|---|---|---|---|
| 598f1262d7 | |||
| 889523f0c8 | |||
| 8f0dbd4cbd | |||
| 9ebbedb04a | |||
| 04a8904cbe | |||
| 810264aa71 | |||
| 171a48eb71 | |||
| c13310d540 | |||
| 4e94d7ad78 | |||
| 500641a6e2 | |||
| a5805aceb2 | |||
| c7e1b4805b | |||
| b667f9c255 | |||
| 199007c0c5 | |||
| c872f1a9ae | |||
| 5fcc0dda1e | |||
| 968d078c07 | |||
| dd9f59e418 | |||
| eb0eb436ed | |||
| 6db9bd85a5 | |||
| e4621f8ad8 | |||
| 1cf86768c0 | |||
| bd923e4fdc | |||
| 2dc06e8d79 | |||
| de2c0c167c | |||
| 0181c72a9d | |||
| f6608075ff | |||
| deccb3186c | |||
| 49b3b46ffe | |||
| 33c875c6bd | |||
| 3f627f08f7 | |||
| bc651eff27 |
+1
-2
@@ -1,2 +1 @@
|
||||
build*
|
||||
.build*
|
||||
build*
|
||||
Vendored
+23
-20
@@ -1,22 +1,25 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "C:\\Espressif\\tools\\xtensa-esp-elf\\esp-14.2.0_20250730\\xtensa-esp-elf\\bin\\xtensa-esp32-elf-gcc.exe",
|
||||
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
|
||||
"intelliSenseMode": "gcc-x86",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/core/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceFolder}",
|
||||
"${workspaceFolder}/core"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
"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
|
||||
}
|
||||
|
||||
Vendored
+38
@@ -5,6 +5,44 @@
|
||||
"type": "gdbtarget",
|
||||
"request": "attach",
|
||||
"name": "Eclipse CDT GDB Adapter"
|
||||
},
|
||||
{
|
||||
"type": "espidf",
|
||||
"name": "Launch",
|
||||
"request": "launch"
|
||||
},
|
||||
{
|
||||
"name": "C/C++: g++.exe debug selected file",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
// "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
|
||||
"program": "${workspaceFolder}/test/unitOnHost/build/watchFace/watchFaceTest.exe",
|
||||
// "program": "${workspaceFolder}/core/test/unitOnHost/build/devHal/devHalTest.exe",
|
||||
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "C:\\msys64\\ucrt64\\bin\\gdb.exe",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"existing": false,
|
||||
// "preLaunchTask": "C/C++: g++.exe build active file",
|
||||
"detail": "preLaunchTask: C/C++: g++.exe build active file",
|
||||
"taskDetail": "compiler: C:\\msys64\\ucrt64\\bin\\g++.exe",
|
||||
"taskStatus": "Detected Task"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+37
-79
@@ -1,82 +1,40 @@
|
||||
{
|
||||
"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_TARGET": "esp32"
|
||||
},
|
||||
"idf.openOcdConfigs": [
|
||||
"interface/ftdi/esp_ftdi.cfg",
|
||||
"target/esp32.cfg"
|
||||
// "board/esp32-wrover-kit-3.3v.cfg"
|
||||
],
|
||||
"idf.flashType": "UART",
|
||||
"C_Cpp.autoAddFileAssociations": false,
|
||||
"project.deviceIp": "172.16.17.56",
|
||||
"sonarlint.pathToCompileCommands": "${workspaceFolder}\\build\\compile_commands.json",
|
||||
"idf.portWin": "COM4",
|
||||
"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": "C:\\Espressif\\tools\\esp-clang\\esp-18.1.2_20240912\\esp-clang\\bin\\clangd.exe",
|
||||
"clangd.arguments": [
|
||||
"--background-index",
|
||||
"--query-driver=**",
|
||||
"--compile-commands-dir=c:\\Users\\Jakob\\hello_world\\build"
|
||||
],
|
||||
"cmake.configureOnOpen": false,
|
||||
"cmake.configureOnEdit": false,
|
||||
"cmake.automaticReconfigure": false,
|
||||
"cmake.autoSelectActiveFolder": false,
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cmake.options.advanced": {
|
||||
"build": {
|
||||
"statusBarVisibility": "inherit",
|
||||
"inheritDefault": "hidden"
|
||||
},
|
||||
"launch": {
|
||||
"statusBarVisibility": "inherit",
|
||||
"inheritDefault": "hidden"
|
||||
},
|
||||
"debug": {
|
||||
"statusBarVisibility": "inherit",
|
||||
"inheritDefault": "hidden"
|
||||
}
|
||||
},
|
||||
"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 }",
|
||||
|
||||
"idf.currentSetup": "C:\\esp\\v5.4.3\\esp-idf",
|
||||
"idf.port": "COM16"
|
||||
"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",
|
||||
"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"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+265
-1
@@ -1,7 +1,271 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
]
|
||||
}
|
||||
+6
-14
@@ -2,24 +2,16 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
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/components_extern"
|
||||
"core/managed_components"
|
||||
)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
message("Using Main App")
|
||||
project(LeoLightShow)
|
||||
endif()
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
"core/components"
|
||||
"core/managed_components"
|
||||
)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(X_WatchController_FW)
|
||||
endif()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
idf_component_register(
|
||||
SRC_DIRS "src" "src/esp"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES esp_system esp_netif freeRtosApi sockets
|
||||
REQUIRES esp_system esp_netif freeRtosApi
|
||||
)
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class SAD_DetectedServer;
|
||||
class I_SAD_Client {
|
||||
public:
|
||||
virtual void eventServerDetected(SAD_DetectedServer &server) = 0;
|
||||
virtual void eventServerChanged(SAD_DetectedServer &server) = 0;
|
||||
virtual void eventServerLost(SAD_DetectedServer &server) = 0;
|
||||
};
|
||||
|
||||
class SAD_DetectedServer {
|
||||
public:
|
||||
SAD_DetectedServer(string p_Name, string p_ID, string p_ComputerName,
|
||||
string p_IP, string p_Port, string p_ClientIP,
|
||||
string p_Additions, string projName)
|
||||
: m_Name(p_Name),
|
||||
m_ID(p_ID),
|
||||
m_ComputerName(p_ComputerName),
|
||||
m_IP(p_IP),
|
||||
m_Port(p_Port),
|
||||
m_ClientIP(p_ClientIP),
|
||||
m_Additions(p_Additions),
|
||||
m_ServerProjectName(projName) {
|
||||
}
|
||||
|
||||
private:
|
||||
string m_Name{};
|
||||
string m_ID{};
|
||||
string m_ComputerName{};
|
||||
string m_IP{};
|
||||
string m_Port{};
|
||||
string m_ClientIP{};
|
||||
string m_Additions{};
|
||||
string m_ServerProjectName{};
|
||||
bool m_New{true};
|
||||
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; }
|
||||
string getPort() const { return m_Port; }
|
||||
string getClientIP() const { return m_ClientIP; }
|
||||
string getAdditions() const { return m_Additions; }
|
||||
string getProjectName() const { return m_ServerProjectName; }
|
||||
bool getNew() const { return m_New; }
|
||||
bool getChanged() const { return m_Changed; }
|
||||
bool getFoundAgain() const { return m_FoundAgain; }
|
||||
|
||||
void setChanged() { m_Changed = true; }
|
||||
void setKnown() { m_New = false; }
|
||||
void setFoundAgain() { m_FoundAgain = true; }
|
||||
void updateProjectName(string newProjectName) {
|
||||
m_ServerProjectName = newProjectName;
|
||||
if (m_ServerProjectName != newProjectName) {
|
||||
m_Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// SAD_Client m_ThreadSend will send to Multicast addresses
|
||||
void resetFlags() {
|
||||
m_Changed = false;
|
||||
m_FoundAgain = false;
|
||||
m_New = false;
|
||||
}
|
||||
|
||||
private:
|
||||
static unordered_map<string, unique_ptr<SAD_DetectedServer>> sKnownServers;
|
||||
|
||||
public:
|
||||
static constexpr int PARAMINDEX_PRECODE = 0;
|
||||
static constexpr int PARAMINDEX_SPITTASKID = 1;
|
||||
static constexpr int PARAMINDEX_NAME = 2;
|
||||
static constexpr int PARAMINDEX_ID = 3;
|
||||
static constexpr int PARAMINDEX_COMPUTERNAME = 4;
|
||||
static constexpr int PARAMINDEX_PORT = 5;
|
||||
static constexpr int PARAMINDEX_CLIENTIP = 6;
|
||||
static constexpr int PARAMINDEX_ADDITIONS = 7;
|
||||
static constexpr int PARAMINDEX_SERVERPROJECTNAME = 8;
|
||||
static constexpr int PARAMINDEX_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<SAD_DetectedServer> 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(SAD_DetectedServer &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
|
||||
* @param p_SADClientInterface
|
||||
*/
|
||||
static void evaluateDetectedServers(I_SAD_Client &sadClient) {
|
||||
for (auto &srv : sKnownServers) {
|
||||
SAD_DetectedServer &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 p_ServerID the id of the SPITServer
|
||||
* @return the reference of the SAD_DetectedServer instance with getID() == p_ServerID
|
||||
*/
|
||||
static const SAD_DetectedServer &getRefDetectedServer(const string &id) {
|
||||
return *sKnownServers.at(id);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 "SPITType.h"
|
||||
#include "SPIT_Message.h"
|
||||
#include "SpitRepo.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class SPITObjectListener;
|
||||
|
||||
class SPITObject {
|
||||
public:
|
||||
static void clearUnconfirmedSPITObjects(SpitRepo<SPITObject> &repo);
|
||||
static void setConfirmedFalse(SpitRepo<SPITObject> &repo);
|
||||
static void eventProjectClosed(SpitRepo<SPITObject> &repo, SpitRepo<SPITObject> &remoteRepo);
|
||||
|
||||
SPITObject(string p_ID);
|
||||
|
||||
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{0x01};
|
||||
int m_ValueFactor{1000000}; // Values are given in ppm -> 1000000 = 1/1;
|
||||
int m_Track{};
|
||||
long long m_Delay{};
|
||||
long long m_Duration{};
|
||||
|
||||
bool m_PlayPrePosition;
|
||||
long long m_PlayTimeInsideFrames;
|
||||
int m_PlayValue;
|
||||
char m_PlayValueFlag;
|
||||
|
||||
public:
|
||||
string getID() const { return m_ID; }
|
||||
string getName() const { return m_Name; }
|
||||
string getRemark() const { return m_Remark; }
|
||||
string getSPITTypeID() const { return m_SPITTypeID; }
|
||||
string getServerParams() const { return m_ServerParams; }
|
||||
|
||||
/**
|
||||
* Returns if the SPITType triggers an action on the Server or on the client.
|
||||
* @return false = the action is triggered on the client The client waits for the server to play objects of this SPITType
|
||||
* true = the action is triggered on the server. The server waits for the client to play objects of this SPITType.
|
||||
*/
|
||||
bool getServerRemote() const { return m_ServerRemote; }
|
||||
|
||||
/**
|
||||
* This is used by the server and client to tell if the other side has registered the changes.
|
||||
* @return true = other side has registered the changes.
|
||||
*/
|
||||
bool getConfirmed() const { return m_Confirmed; }
|
||||
bool getFixed() const { return m_Fixed; }
|
||||
bool getCreatedByClient() const { return m_CreatedByClient; }
|
||||
/**
|
||||
* This is a virtual construct - ActionAssignedType is not implemented in the SPITProtocol.
|
||||
* This is used when an action is associated with a SPITType.
|
||||
* Then this action is done for every SPITObject with the SPITType.
|
||||
* @return true = an action is assigned for the SPITType.
|
||||
*/
|
||||
bool getActionAssignedType() const { return m_ActionAssignedType; }
|
||||
/** Returns if this SPITObject has an associated action or not.
|
||||
* @return true = the user has asscociated an action with this SPITObject or
|
||||
* the user has asscociated an action with the SPITType of this SPITObject
|
||||
*/
|
||||
bool getActionAssigned() const { return m_ActionAssigned || m_ActionAssignedType; }
|
||||
|
||||
long long getFrameStart() const { return m_FrameStart; }
|
||||
// contains the length of the SPITObject
|
||||
long long getFrameLength() const { return m_FrameLength; }
|
||||
long long getFrameFadeInLength() const { return m_FrameFadeInLength; }
|
||||
long long getFrameFadeOutLength() const { return m_FrameFadeOutLength; }
|
||||
char getValueUse() const { return m_ValueUse; }
|
||||
int getValueFactor() const { return m_ValueFactor; }
|
||||
int getTrack() const { return m_Track; }
|
||||
|
||||
long long getDelay() const { return m_Delay; }
|
||||
long long getDuration() const { return m_Duration; }
|
||||
|
||||
bool getProjectIndepended(SpitRepo<SPITType> &repo, SpitRepo<SPITType> &remoteRepo) const {
|
||||
SPITType *ptrSPITType;
|
||||
if (m_ServerRemote == false) {
|
||||
ptrSPITType = repo.getEntry(m_SPITTypeID);
|
||||
if (ptrSPITType == nullptr)
|
||||
return true;
|
||||
return ptrSPITType->getProjectIndepended();
|
||||
} else {
|
||||
ptrSPITType = remoteRepo.getEntry(m_SPITTypeID);
|
||||
if (ptrSPITType == nullptr)
|
||||
return true;
|
||||
return ptrSPITType->getProjectIndepended();
|
||||
}
|
||||
};
|
||||
|
||||
bool setConfirmed(bool p_Confirmed);
|
||||
void setCreatedByClient(bool p_CreatedByClient) { m_CreatedByClient = 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 */
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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(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, unique_ptr<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() { s_SPITPlayers.clear(); }
|
||||
|
||||
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, unique_ptr<PlaySPITType>> &getPlaySPITTypes() { return m_PlaySPITTypes; }
|
||||
void setIsRunning(bool p_IsRunning) { m_IsRunning = p_IsRunning; }
|
||||
void setName(string p_Name) { m_Name = p_Name; }
|
||||
void setType(char p_Type) { m_Type = p_Type; }
|
||||
void setTime(long long p_Frames) { m_TimeFrames = p_Frames; }
|
||||
bool getIsRunning() const { return m_IsRunning; }
|
||||
string getName() const { return m_Name; }
|
||||
char getType() const { return m_Type; }
|
||||
long long getTime() const { return m_TimeFrames; }
|
||||
|
||||
private:
|
||||
string m_ID;
|
||||
string m_Name;
|
||||
char m_Type;
|
||||
unordered_map<string, unique_ptr<PlaySPITType>> m_PlaySPITTypes;
|
||||
|
||||
bool m_IsRunning;
|
||||
long long m_TimeFrames;
|
||||
};
|
||||
|
||||
#endif /* SPITPLAYER_H */
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 "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;
|
||||
|
||||
/** 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;
|
||||
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
|
||||
bool m_IsBound{};
|
||||
|
||||
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) {
|
||||
m_ServerIP = serverIp;
|
||||
m_ServerPort = serverPort;
|
||||
m_ClientIP = clientIp;
|
||||
m_ClientPort = 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) {
|
||||
if (m_ServerPort.length() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (m_IsBound == false) {
|
||||
return -1;
|
||||
}
|
||||
int intResult = sendMessageTo(m_ServerIP, m_ServerPort, message, length);
|
||||
return intResult;
|
||||
}
|
||||
|
||||
int receiveMessage(char *p_Buffer, int p_BufferLength, string *serverIp) const;
|
||||
int setBroadcast(bool p_Broadcast) const;
|
||||
int bindSocket(string clientIp, string clientPort);
|
||||
|
||||
int sendMessageTo(const string &ip, const string &port, const char *message, int msgLength);
|
||||
|
||||
string getServerIP() const { return m_ServerIP; }
|
||||
string getServerPort() const { return m_ServerPort; }
|
||||
string getClientIP() const { return m_ClientIP; }
|
||||
string getClientPort() const { return m_ClientPort; }
|
||||
string getBoundClientPort() const { return m_BoundClientPort; }
|
||||
void setBoundClientPort(const string &p_Port) { m_BoundClientPort = p_Port; }
|
||||
void setIsBound(bool p_IsBound) { m_IsBound = p_IsBound; }
|
||||
bool getIsBound() const { return m_IsBound; }
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif /* SPITSOCKET_H */
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 "SpitRepo.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class SPITTypeListener;
|
||||
|
||||
class SPITType {
|
||||
public:
|
||||
static void setConfirmedFalse(SpitRepo<SPITType> &repo);
|
||||
static void eventProjectClosed(SpitRepo<SPITType> &repo, SpitRepo<SPITType> &remoteRepo);
|
||||
|
||||
SPITType(string p_ID);
|
||||
SPITType(string p_ID, string p_GroupName, string p_Name, bool p_Fixed, bool p_ProjectIndepended, long long p_DefaultDelay, long long p_DefaultDuration);
|
||||
|
||||
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
|
||||
|
||||
public:
|
||||
string getID() const { return m_ID; }
|
||||
string getGroupName() const { return m_GroupName; }
|
||||
string getName() const { return m_Name; }
|
||||
/**
|
||||
* Returns if the SPITType triggers an action on the Server or on the client.
|
||||
* @return false = the action is triggered on the client The client waits for the server to play objects of this SPITType
|
||||
* true = the action is triggered on the server. The server waits for the client to play objects of this SPITType.
|
||||
*/
|
||||
bool getServerRemote() const { return m_ServerRemote; }
|
||||
bool getProjectIndepended() const { return m_ServerProjectIndepended; }
|
||||
/**
|
||||
* This is used by the server and client to tell if the other side has registered the changes.
|
||||
* @return true = other side has registered the changes.
|
||||
*/
|
||||
bool getConfirmed() const { return m_Confirmed; }
|
||||
bool getFixed() const { return m_Fixed; }
|
||||
long long getDefaultDelay() const { return m_DefaultDelay; }
|
||||
long long getDefaultDuration() const { return m_DefaultDuration; }
|
||||
bool getCreatedByClient() const { return m_CreatedByClient; }
|
||||
|
||||
/**
|
||||
* Virtual construct - means ActionAssigned for SPITTypes is is not implemented in SPITProtocol.
|
||||
* This can used to setActionAssigned to all SPITObjects with this SPITType.
|
||||
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.
|
||||
* @return true = the user has associated an action with this SPITType.
|
||||
*/
|
||||
bool getActionAssigned() const {
|
||||
return m_ActionAssigned;
|
||||
}
|
||||
|
||||
bool setGroupName(const string &p_GroupName);
|
||||
bool setName(const string &p_Name);
|
||||
bool setServerRemote(bool p_BelongstoServer);
|
||||
bool setProjectIndepended(bool p_ProjectIndepeneded);
|
||||
bool setConfirmed(bool p_Confirmed);
|
||||
bool setFixed(bool p_Fixed);
|
||||
bool setDefaultDelay(long long p_Delay);
|
||||
bool setDefaultDuration(long long p_Duration);
|
||||
void setCreatedByClient(bool p_CreatedByClient);
|
||||
|
||||
/**
|
||||
* Virtual construct - means ActionAssigned for SPITTypes is is not implemented in SPITProtocol.
|
||||
* This can used to setActionAssigned to all SPITObjects with this SPITType.
|
||||
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.
|
||||
* @return true = the m_ActionAssigned has changed.
|
||||
*/
|
||||
bool setActionAssigned(bool p_ActionAssigned);
|
||||
|
||||
bool setMessageOP(SPIT_Message::ReportSPITType &reportSpitType);
|
||||
void fillMessageOP(SPIT_Message::ReportSPITType &smReportSpitType) const;
|
||||
void fillMessageOP(SPIT_Message::RemoveSPITType &smRemoveSpitType) const;
|
||||
};
|
||||
|
||||
#endif /* SPITTYPE_H */
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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 "SAD_DetectedServer.hpp"
|
||||
#include "SPITObject.h"
|
||||
#include "SPITPlayer.h"
|
||||
#include "SPITSocket.h"
|
||||
#include "SPITType.h"
|
||||
#include "SPIT_Message.h"
|
||||
#include "SpitRepo.hpp"
|
||||
#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 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 {
|
||||
void (*onServerEvent)(ServerEvent event, const SAD_DetectedServer &p_DetectedServer){};
|
||||
void (*onConnectionStatus)(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, Connection p_ConnectionStatus, Connection p_OldConnectionStatus){};
|
||||
void (*onProjectUpdate)(ProjUpdate state, string projectId){};
|
||||
void (*onSpitType)(ObjectEvent event, bool isRemote, const SPITType &p_SPITType){};
|
||||
void (*onSpitObject)(ObjectEvent event, bool isRemote, 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)(bool knownType, bool createdByClient){};
|
||||
bool (*onCheckSpitObjectVeto)(bool knownType){};
|
||||
};
|
||||
|
||||
//------ 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 constexpr char PLAYERTYPE_MAIN = 0x02;
|
||||
/** continous player. This player plays SPIT objects sometime during the project.*/
|
||||
static constexpr char PLAYERTYPE_CONTINOUS = 0x01;
|
||||
/** diescrete player. This player is used to transmit single discrete values.*/
|
||||
static constexpr char PLAYERTYPE_DISCRETE = 0x00;
|
||||
|
||||
//------ Value Flag ------
|
||||
//------ used by sendRemoteObject
|
||||
public:
|
||||
/**Set the given value directly*/
|
||||
static constexpr 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 constexpr 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 constexpr char VALUEFLAG_DECREASE = 0x02;
|
||||
static constexpr int MAX_OVERTAKING_SPIT_MESSAGES = 10;
|
||||
|
||||
//----- SPIT_Client -----
|
||||
public:
|
||||
SPIT_Client(string name, string projName, Callbacks calls);
|
||||
virtual ~SPIT_Client();
|
||||
|
||||
private:
|
||||
Callbacks mCallbacks;
|
||||
|
||||
fos::TaskT<SPIT_Client &> *m_ThreadReceive{};
|
||||
bool m_StopReceiveSPITMessages{};
|
||||
|
||||
Connection m_ConnectionStatus{Connection::None};
|
||||
bool m_DisconnectedByServer{}; // flag true = when server disconnects
|
||||
string m_ID;
|
||||
string m_Name;
|
||||
string m_ProjName;
|
||||
string m_ComputerName;
|
||||
|
||||
string m_ClientProjectName;
|
||||
|
||||
uint8_t m_MessageNumber_Send{1};
|
||||
int m_MessageNumber_Received{-1}; // set to -1 because the first received message will set the number (1..255)
|
||||
vector<unique_ptr<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:
|
||||
int sendSPITMessage(SPIT_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(SAD_DetectedServer &server);
|
||||
/** Called every time a prior detected SPITServer is is no longer found.*/
|
||||
void eventServerLost(SAD_DetectedServer &server);
|
||||
void eventServerChanged(SAD_DetectedServer &server);
|
||||
|
||||
//--------------- 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(Connection 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(unique_ptr<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 mAbortSearch{};
|
||||
bool sAnswered{};
|
||||
static fos::Semaphore sStartSad;
|
||||
SPITSocket *mSPITSocket;
|
||||
void answerWatchdog() {
|
||||
sAnswered = true;
|
||||
}
|
||||
|
||||
SpitRepo<SPITObject> mSpitObjects;
|
||||
SpitRepo<SPITObject> mRemoteSpitObjects;
|
||||
SpitRepo<SPITType> mSpitTypes;
|
||||
SpitRepo<SPITType> mRemoteSpitTypes;
|
||||
};
|
||||
|
||||
#endif /* SPIT_CLIENT_H */
|
||||
@@ -0,0 +1,728 @@
|
||||
/*
|
||||
* 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 <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
static const string SPITID = "#spit#";
|
||||
|
||||
class SPIT_Message {
|
||||
//----------- Header -----------
|
||||
public:
|
||||
class Header {
|
||||
public:
|
||||
static constexpr int BYTESLENGTH = 99;
|
||||
Header(const Header &orig);
|
||||
Header();
|
||||
|
||||
private:
|
||||
string m_SPITID;
|
||||
int m_SPITVersion{SPITVERSION};
|
||||
unsigned char m_MessageNumber{};
|
||||
int m_BytesCount{BYTESLENGTH};
|
||||
string m_ServerID{};
|
||||
string m_ClientID{};
|
||||
int m_OPFlag{-1};
|
||||
int m_ParseOffset{};
|
||||
|
||||
public:
|
||||
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; }
|
||||
string getServerID() const { return m_ServerID; }
|
||||
string getClientID() const { return m_ClientID; }
|
||||
int getOPFlag() const { return m_OPFlag; }
|
||||
|
||||
// Receive
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
// Send
|
||||
Header(int p_SPITVersion, int p_OPFlag);
|
||||
void setMessageNumber(unsigned char p_MessageNumber) { m_MessageNumber = p_MessageNumber; }
|
||||
void setServerID(string p_ID) { m_ServerID = p_ID; }
|
||||
void setClientID(string p_ID) { m_ClientID = p_ID; }
|
||||
void setOPFlag(int p_OPFlag) { m_OPFlag = p_OPFlag; }
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//----------- OPPart -----------
|
||||
public:
|
||||
class OPPart {
|
||||
|
||||
// Members
|
||||
protected:
|
||||
unique_ptr<Header> m_Header{};
|
||||
int m_ParseOffset{};
|
||||
int m_BytesCount;
|
||||
|
||||
public:
|
||||
virtual ~OPPart();
|
||||
|
||||
Header *getHeader() const { return m_Header.get(); }
|
||||
int getBytesCount() const { return m_BytesCount; }
|
||||
void setServerInfoInHeader(string clientId, string serverId) {
|
||||
if (!m_Header)
|
||||
return;
|
||||
m_Header->setClientID(clientId);
|
||||
m_Header->setServerID(serverId);
|
||||
}
|
||||
void setMessageNumber(uint8_t no) {
|
||||
if (!m_Header)
|
||||
return;
|
||||
m_Header->setMessageNumber(no);
|
||||
}
|
||||
|
||||
const string getServerID() const {
|
||||
if (!m_Header) {
|
||||
return "";
|
||||
}
|
||||
return m_Header->getServerID();
|
||||
}
|
||||
const string getClientID() const {
|
||||
if (!m_Header) {
|
||||
return "";
|
||||
}
|
||||
return m_Header->getClientID();
|
||||
}
|
||||
|
||||
int getOPFlag() const {
|
||||
if (!m_Header) {
|
||||
return -1;
|
||||
}
|
||||
return m_Header->getOPFlag();
|
||||
}
|
||||
|
||||
// Receive
|
||||
OPPart(unique_ptr<Header> p_Header, int p_OPFlag, 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;
|
||||
};
|
||||
|
||||
//----------- SPIT_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
|
||||
|
||||
SPIT_Message() = default;
|
||||
|
||||
// Members
|
||||
private:
|
||||
unique_ptr<OPPart> m_OPPart{};
|
||||
|
||||
// Receive
|
||||
public:
|
||||
SPIT_Message(std::vector<char> message);
|
||||
|
||||
const Header *getHeader() const { return m_OPPart->getHeader(); }
|
||||
int getOPFlag() const {
|
||||
if (!m_OPPart || !m_OPPart->getHeader()) {
|
||||
return -1;
|
||||
}
|
||||
return m_OPPart->getHeader()->getOPFlag();
|
||||
}
|
||||
const OPPart *getOPPart() const { return m_OPPart.get(); }
|
||||
template<typename T>
|
||||
T &getOPPartAs() const { return *reinterpret_cast<T *>(m_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 m_ClientComputerName{};
|
||||
string m_ClientName{};
|
||||
string m_LoginName{};
|
||||
string m_LoginPassword{};
|
||||
string m_ServerIP{};
|
||||
int m_ServerPort{};
|
||||
|
||||
public:
|
||||
// Receive
|
||||
Connect(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
string getClientComputerName() const { return m_ClientComputerName; }
|
||||
string getClientName() const { return m_ClientName; }
|
||||
string getLoginName() const { return m_LoginName; }
|
||||
string getLoginPassword() const { return m_LoginPassword; }
|
||||
string getServerIP() const { return m_ServerIP; }
|
||||
int getServerPort() const { return m_ServerPort; }
|
||||
|
||||
// Send
|
||||
Connect(string p_ComputerName, string p_ClientName);
|
||||
|
||||
void setLoginName(string p_LoginName) { m_LoginName = p_LoginName; }
|
||||
void setLoginPassword(string p_LoginPassword) { m_LoginPassword = p_LoginPassword; }
|
||||
void setServerIP(string p_ServerIP) { m_ServerIP = 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 m_ServerComputerName{};
|
||||
string m_ServerName{};
|
||||
bool m_Connected{};
|
||||
int m_StepTime{40}; // ms step size the Server will send play sequences
|
||||
|
||||
public:
|
||||
ConnectAnswer(const ConnectAnswer &orig);
|
||||
// Receive
|
||||
ConnectAnswer(unique_ptr<Header> p_Header);
|
||||
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
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
|
||||
ConnectAnswer();
|
||||
void setServerComputerName(string p_ServerComputerName) { m_ServerComputerName = p_ServerComputerName; }
|
||||
void setServerName(string p_ServerName) { m_ServerName = p_ServerName; }
|
||||
void setConnected(bool p_Connected) { m_Connected = 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> p_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> p_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> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
// Send
|
||||
WatchdogAnswer();
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//------------------------------ SPITProject ----------------------------------
|
||||
|
||||
//----------- ReportSPITProject -----------
|
||||
|
||||
class ReportSPITProject : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 11;
|
||||
static constexpr int BYTESLENGTH = 113;
|
||||
|
||||
private:
|
||||
string m_ProjectID{};
|
||||
string m_ProjectName{};
|
||||
int m_FramesPerSecond{1000}; // Frames per second
|
||||
|
||||
// Receive
|
||||
public:
|
||||
ReportSPITProject(const ReportSPITProject &orig);
|
||||
ReportSPITProject(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
const string getProjectID() const { return m_ProjectID; }
|
||||
const string getProjectName() const { return m_ProjectName; }
|
||||
int getFramesPerSecond() const { return m_FramesPerSecond; }
|
||||
// Send
|
||||
ReportSPITProject(string p_ProjectID, string p_ProjectName);
|
||||
|
||||
void setFramesPerSecond(const int p_FramesPerSecond) { m_FramesPerSecond = p_FramesPerSecond; }
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//----------- CloseSPITProject -----------
|
||||
|
||||
class CloseSPITProject : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 13;
|
||||
static constexpr int BYTESLENGTH = 45;
|
||||
|
||||
private:
|
||||
string m_ProjectID{};
|
||||
|
||||
public:
|
||||
CloseSPITProject(const CloseSPITProject &orig);
|
||||
// Receive
|
||||
CloseSPITProject(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
const string getProjectID() const {
|
||||
return m_ProjectID;
|
||||
}
|
||||
// Send
|
||||
CloseSPITProject(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> p_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> p_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> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
// Send
|
||||
EndProjectTransfer();
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//---------------------------- SPIT_Types ----------------------------------
|
||||
|
||||
//----------- ReportSPITType -----------
|
||||
class ReportSPITType : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 21;
|
||||
static constexpr 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{};
|
||||
|
||||
public:
|
||||
ReportSPITType(const ReportSPITType &orig);
|
||||
// Receive
|
||||
ReportSPITType(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
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
|
||||
|
||||
ReportSPITType();
|
||||
void setConfirmed(bool p_Confirmed) { m_Confirmed = p_Confirmed; }
|
||||
void setID(string p_ID) { m_SPITTypeID = p_ID; }
|
||||
void setFixed(bool p_Fixed) { m_Fixed = p_Fixed; }
|
||||
void setServerRemote(bool p_IsServerRemote) { m_ServerRemote = p_IsServerRemote; }
|
||||
void setServerProjectIndepended(bool p_ProjectIndpended) { m_ServerProjectIndepended = p_ProjectIndpended; }
|
||||
void setGroupName(string p_GroupName) { m_SPITTypeGroupName = p_GroupName; }
|
||||
void setName(string p_Name) { m_SPITTypeName = p_Name; }
|
||||
void setDelay(long long p_Delay) { m_Delay = p_Delay; }
|
||||
void setDuration(long long p_Duration) { m_Duration = p_Duration; }
|
||||
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//----------- RemoveSPITType -----------
|
||||
|
||||
class RemoveSPITType : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 23;
|
||||
static constexpr int BYTESLENGTH = 45;
|
||||
|
||||
private:
|
||||
string m_SPITTypeID{};
|
||||
|
||||
public:
|
||||
RemoveSPITType(const RemoveSPITType &orig);
|
||||
// Receive
|
||||
RemoveSPITType(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
const string getID() const { return m_SPITTypeID; }
|
||||
|
||||
// Send
|
||||
RemoveSPITType();
|
||||
void setID(string p_ID) { m_SPITTypeID = p_ID; }
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//---------------------------- SPITObjects ----------------------------------
|
||||
|
||||
//----------- ReportSPITObject -----------
|
||||
|
||||
class ReportSPITObject : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 31;
|
||||
static constexpr 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{VALUEUSE_DISCARD};
|
||||
int m_Track{};
|
||||
string m_Remark{};
|
||||
long long m_Delay{};
|
||||
long long m_Duration{};
|
||||
bool m_ActionAssigned{};
|
||||
|
||||
public:
|
||||
ReportSPITObject(const ReportSPITObject &orig);
|
||||
// Receive
|
||||
ReportSPITObject(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
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) { m_Confirmed = p_Confirmed; };
|
||||
void setID(string p_ID) { m_SPITObjectID = p_ID; };
|
||||
void setFixed(bool p_Fixed) { m_Fixed = p_Fixed; };
|
||||
void setServerRemote(bool p_IsRemote) { m_ServerRemote = p_IsRemote; };
|
||||
void setName(string p_Name) { m_SPITObjectName = p_Name; };
|
||||
void setSPITTypeID(string p_ID) { m_SPITTypeID = p_ID; };
|
||||
void setServerParams(string p_Parameters) { m_ServerParams = p_Parameters; };
|
||||
void setFrameStart(long long p_StartTime) { m_FrameStart = p_StartTime; };
|
||||
void setFrameLength(long long p_Length) { m_FrameLength = p_Length; };
|
||||
void setFrameFadeInLength(long long p_FadeInTime) { m_FrameFadeInLength = p_FadeInTime; };
|
||||
void setFrameFadeOutLength(long long p_FadeOutTime) { m_FrameFadeOutLength = p_FadeOutTime; };
|
||||
void setValueFactor(int p_Volume) { m_ValueFactor = p_Volume; };
|
||||
void setValueUse(char p_ValueUse) { m_ValueUse = p_ValueUse; };
|
||||
void setTrack(int p_Track) { m_Track = p_Track; };
|
||||
void setRemark(string p_Description) { m_Remark = p_Description; };
|
||||
void setDelay(long long p_Delay);
|
||||
void setDuration(long long p_Duration);
|
||||
void setActionAssigned(bool p_ActionAssigned) { m_ActionAssigned = p_ActionAssigned; }
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//----------- RemoveSPITObject -----------
|
||||
|
||||
class RemoveSPITObject : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 33;
|
||||
static constexpr int BYTESLENGTH = 45;
|
||||
|
||||
private:
|
||||
string m_SPITObjectID{};
|
||||
|
||||
public:
|
||||
RemoveSPITObject(const RemoveSPITObject &orig);
|
||||
// Receive
|
||||
RemoveSPITObject(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
const string getID() const { return m_SPITObjectID; }
|
||||
// Send
|
||||
public:
|
||||
RemoveSPITObject();
|
||||
void setID(string p_ID) { m_SPITObjectID = p_ID; }
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//---------------------------- SPITPlayer ----------------------------------
|
||||
|
||||
//----------- PlaySPITStart -----------
|
||||
|
||||
class PlaySPITStart : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 37;
|
||||
static constexpr int BYTESLENGTH = 119;
|
||||
|
||||
private:
|
||||
string m_PlayerID{};
|
||||
string m_PlayerName{};
|
||||
char m_PlayerType{};
|
||||
bool m_PlayerIsRunning{};
|
||||
long long m_Time; // Frames
|
||||
|
||||
public:
|
||||
PlaySPITStart(const PlaySPITStart &orig);
|
||||
// Receive
|
||||
PlaySPITStart(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
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
|
||||
PlaySPITStart(string p_PlayerID, string p_PlayerName, char p_PlayerType);
|
||||
void setPlayerIsRunning(bool p_IsPlaying) { m_PlayerIsRunning = p_IsPlaying; }
|
||||
void setTime(long long p_Time) { m_Time = p_Time; }
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//----------- PlaySPITObject -----------
|
||||
|
||||
class PlaySPITObject : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 38;
|
||||
static constexpr int BYTESLENGTH = 100;
|
||||
|
||||
private:
|
||||
string m_PlayerID{};
|
||||
string m_SPITObjectID{};
|
||||
long long m_FrameInsideObject{}; // Frames
|
||||
bool m_PlayPrePosition{};
|
||||
int m_Value{};
|
||||
char m_ValueFlag{VALUEFLAG_DIRECT};
|
||||
|
||||
public:
|
||||
PlaySPITObject(const PlaySPITObject &orig);
|
||||
// Receive
|
||||
PlaySPITObject(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
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) { m_PlayerID = p_PlayerID; }
|
||||
void setID(string p_ID) { m_SPITObjectID = p_ID; }
|
||||
void setFrameInsideObject(long long p_TimeInside) { m_FrameInsideObject = p_TimeInside; }
|
||||
void setPlayPrePosition(bool p_PlayOldPosition) { m_PlayPrePosition = p_PlayOldPosition; }
|
||||
void setValue(int p_Value) { m_Value = p_Value; }
|
||||
void setValueFlag(char p_ValueFlag) { m_ValueFlag = p_ValueFlag; }
|
||||
bool fillBytes(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//----------- PlaySPITEnd -----------
|
||||
class PlaySPITEnd : public OPPart {
|
||||
public:
|
||||
static constexpr int OPFLAG = 39;
|
||||
static constexpr int BYTESLENGTH = 45;
|
||||
|
||||
private:
|
||||
string m_PlayerID{};
|
||||
|
||||
public:
|
||||
PlaySPITEnd(const PlaySPITEnd &orig);
|
||||
// Receive
|
||||
PlaySPITEnd(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
const string getPlayerID() const { return m_PlayerID; }
|
||||
|
||||
// Send
|
||||
PlaySPITEnd(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 m_SPITObjectID{};
|
||||
long long m_FrameInsideObject{}; // Frames
|
||||
int m_Value{};
|
||||
|
||||
public:
|
||||
ReportPlayStatus(const ReportPlayStatus &orig);
|
||||
// Receive
|
||||
ReportPlayStatus(unique_ptr<Header> p_Header);
|
||||
bool parse(const std::vector<char> &message);
|
||||
|
||||
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(std::vector<char> &message);
|
||||
};
|
||||
|
||||
//----------------------- static helper functions ----------------------------
|
||||
public:
|
||||
static bool isSystemLittleEndian();
|
||||
static optional<int> getInt(const std::vector<char> &message, int &offset);
|
||||
static optional<long long> 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(long long 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);
|
||||
};
|
||||
#endif /* SPIT_MESSAGE_H */
|
||||
@@ -1,13 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace spit {
|
||||
|
||||
template <typename T>
|
||||
class SpitRepo {
|
||||
public:
|
||||
@@ -15,17 +10,33 @@ class SpitRepo {
|
||||
return mEntries.contains(id);
|
||||
}
|
||||
|
||||
T *getEntry(const string &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);
|
||||
}
|
||||
|
||||
T *getEntry(int index) {
|
||||
if (index >= 0 && index < mEntries.size()) {
|
||||
return next(mEntries.begin(), index)->second.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const T &getEntryRef(int index) {
|
||||
if (index >= 0 && index < mEntries.size()) {
|
||||
auto i = next(mEntries.begin(), index);
|
||||
return *i->second;
|
||||
} else {
|
||||
throw "SPITObject index out of range";
|
||||
}
|
||||
}
|
||||
|
||||
void addEntry(unique_ptr<T> entry) {
|
||||
mEntries[entry->getID()] = move(entry);
|
||||
}
|
||||
@@ -40,7 +51,7 @@ class SpitRepo {
|
||||
mEntries.erase(i);
|
||||
return true;
|
||||
}
|
||||
int getSize() {
|
||||
int getEntryCount() {
|
||||
return mEntries.size();
|
||||
}
|
||||
|
||||
@@ -55,5 +66,3 @@ class SpitRepo {
|
||||
private:
|
||||
unordered_map<string, unique_ptr<T>> mEntries;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
#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
|
||||
@@ -1,720 +0,0 @@
|
||||
#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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
#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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
#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
|
||||
@@ -1,169 +0,0 @@
|
||||
#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
|
||||
@@ -1,149 +0,0 @@
|
||||
#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:
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "esp_log.h"
|
||||
|
||||
/**
|
||||
* clears all unconfirmed SPITObjects not created by this SPIT_Client.
|
||||
*/
|
||||
void SPITObject::clearUnconfirmedSPITObjects(SpitRepo<SPITObject> &repo) {
|
||||
auto &entries = repo.getRepo();
|
||||
for (auto i = entries.begin(); i != entries.end();) {
|
||||
SPITObject *ptrSPITObject = i->second.get();
|
||||
if (ptrSPITObject->getCreatedByClient() == false && ptrSPITObject->getConfirmed() == false) {
|
||||
i = entries.erase(i);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPITObject::eventProjectClosed(SpitRepo<SPITObject> &repo, SpitRepo<SPITObject> &remoteRepo) {
|
||||
auto &entries = repo.getRepo();
|
||||
for (auto i = entries.begin(); i != entries.end(); ) {
|
||||
SPITObject *ptrSPITObject = i->second.get();
|
||||
if (ptrSPITObject->getCreatedByClient() == true) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i = entries.erase(i);
|
||||
}
|
||||
// Remote
|
||||
remoteRepo.clearEntries();
|
||||
}
|
||||
/**
|
||||
* sets confirmed = false for all SPITObjects.
|
||||
* This should be called when the client has loaded a project.
|
||||
*/
|
||||
void SPITObject::setConfirmedFalse(SpitRepo<SPITObject> &repo) {
|
||||
auto &entries = repo.getRepo();
|
||||
for (auto i = entries.begin(); i != entries.end(); i++) {
|
||||
i->second->setConfirmed(false);
|
||||
}
|
||||
}
|
||||
|
||||
SPITObject::SPITObject(string p_ID) {
|
||||
m_ID = p_ID;
|
||||
}
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
m_Delay = p_ReportSPITObject->getDelay();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_Duration != p_ReportSPITObject->getDuration()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_Duration = p_ReportSPITObject->getDuration();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_Fixed != p_ReportSPITObject->getFixed()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_Fixed = p_ReportSPITObject->getFixed();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_FrameFadeInLength != p_ReportSPITObject->getFrameFadeInLength()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_FrameFadeInLength = p_ReportSPITObject->getFrameFadeInLength();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_FrameFadeOutLength != p_ReportSPITObject->getFrameFadeOutLength()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_FrameFadeOutLength = p_ReportSPITObject->getFrameFadeOutLength();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_FrameLength != p_ReportSPITObject->getFrameLength()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_FrameLength = p_ReportSPITObject->getFrameLength();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_FrameStart != p_ReportSPITObject->getFrameStart()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_FrameStart = p_ReportSPITObject->getFrameStart();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_Remark != p_ReportSPITObject->getRemark()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_Remark = p_ReportSPITObject->getRemark();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ID != p_ReportSPITObject->getID()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_ID = p_ReportSPITObject->getID();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_Name != p_ReportSPITObject->getName()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_Name = p_ReportSPITObject->getName();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_SPITTypeID != p_ReportSPITObject->getSPITTypeID()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_SPITTypeID = p_ReportSPITObject->getSPITTypeID();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ServerParams != p_ReportSPITObject->getServerParams()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_ServerParams = p_ReportSPITObject->getServerParams();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ServerRemote != p_ReportSPITObject->getServerRemote()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_ServerRemote = p_ReportSPITObject->getServerRemote();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_Track != p_ReportSPITObject->getTrack()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_Track = p_ReportSPITObject->getTrack();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ValueFactor != p_ReportSPITObject->getValueFactor()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_ValueFactor = p_ReportSPITObject->getValueFactor();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ValueUse != p_ReportSPITObject->getValueUse()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* This is used when an action is associated with a SPITType.
|
||||
* Then this action is done for every SPITObject with the SPITType.
|
||||
* @return true = an action is assigned for the SPITType.
|
||||
*/
|
||||
bool SPITObject::setActionAssignedType(bool p_ActionAssigned) {
|
||||
if (m_ActionAssignedType == p_ActionAssigned)
|
||||
return false;
|
||||
bool boolOldActionAssigend;
|
||||
boolOldActionAssigend = getActionAssigned();
|
||||
m_ActionAssignedType = p_ActionAssigned;
|
||||
if (getActionAssigned() == boolOldActionAssigend)
|
||||
return false;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 "esp_log.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
unordered_map<string, unique_ptr<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] = make_unique<SPITPlayer>(p_PlayerID);
|
||||
}
|
||||
return *s_SPITPlayers.at(p_PlayerID);
|
||||
}
|
||||
|
||||
SPITPlayer::SPITPlayer(string p_PlayerID) {
|
||||
m_ID = p_PlayerID;
|
||||
}
|
||||
|
||||
SPITPlayer::~SPITPlayer() {
|
||||
m_PlaySPITTypes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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()) {
|
||||
auto playSpitType = make_unique<PlaySPITType>(this, p_SPITTypeID);
|
||||
ptrPlaySPITType = playSpitType.get();
|
||||
m_PlaySPITTypes[p_SPITTypeID] = move(playSpitType);
|
||||
} else {
|
||||
ptrPlaySPITType = i->second.get();
|
||||
}
|
||||
ptrPlaySPITType->setIsPlayed(true);
|
||||
return ptrPlaySPITType;
|
||||
}
|
||||
|
||||
void SPITPlayer::startPlaySequence() {
|
||||
for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end(); i++) {
|
||||
PlaySPITType *ptrPlaySPITType = i->second.get();
|
||||
ptrPlaySPITType->startPlaySequence();
|
||||
}
|
||||
}
|
||||
|
||||
void SPITPlayer::endPlaySequence() {
|
||||
for (auto i = m_PlaySPITTypes.begin(); i != m_PlaySPITTypes.end();) {
|
||||
if (i->second.get()->getIsPlayed() == false) {
|
||||
i = m_PlaySPITTypes.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SPITPlayer::PlaySPITType::PlaySPITType(SPITPlayer *p_SPITPlayer, string p_SPITTypeID) {
|
||||
m_IsNew = true;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,33 +1,45 @@
|
||||
#include "spit_socket.hpp"
|
||||
/*
|
||||
* 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/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;
|
||||
bool SPITSocket::createSocket_UDP() {
|
||||
if (m_UDPSocketIP4 != INVALID_SOCKET) {
|
||||
close(m_UDPSocketIP4);
|
||||
m_UDPSocketIP4 = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
mUdpSocketIp4 = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
m_UDPSocketIP4 = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
int intResult = -1;
|
||||
bool success = true;
|
||||
if (mUdpSocketIp4 == INVALID_SOCKET) {
|
||||
if (m_UDPSocketIP4 == INVALID_SOCKET) {
|
||||
success = false;
|
||||
} else {
|
||||
int intOptionValue4 = 1;
|
||||
intResult = setsockopt(mUdpSocketIp4, SOL_SOCKET, SO_REUSEADDR, (void *)&intOptionValue4, sizeof(intOptionValue4));
|
||||
intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_REUSEADDR, (void *)&intOptionValue4, sizeof(intOptionValue4));
|
||||
}
|
||||
if (intResult < 0) {
|
||||
success = false;
|
||||
@@ -38,17 +50,17 @@ bool Socket::createSocketUdp() {
|
||||
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));
|
||||
setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
|
||||
// set the mUdpSocketIp4 in NON BLOCKING mode because
|
||||
// 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(mUdpSocketIp4, F_GETFL);
|
||||
// fcntl(mUdpSocketIp4, F_SETFL, intFlags | O_NONBLOCK);
|
||||
// intFlags = fcntl(m_UDPSocketIP4, F_GETFL);
|
||||
// fcntl(m_UDPSocketIP4, 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));
|
||||
// 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 success;
|
||||
}
|
||||
@@ -61,7 +73,7 @@ bool Socket::createSocketUdp() {
|
||||
* @return -1 id bind fails, o if bind is ok
|
||||
*
|
||||
*/
|
||||
int Socket::bindSocket(string clientIp, string clientPort) {
|
||||
int SPITSocket::bindSocket(string clientIp, string clientPort) {
|
||||
string stringClientPort;
|
||||
if (clientPort.length() <= 0)
|
||||
stringClientPort = "0";
|
||||
@@ -71,7 +83,7 @@ int Socket::bindSocket(string clientIp, string clientPort) {
|
||||
if (getaddrinfo(clientIp.data(), clientPort.data(), nullptr, &clientAI) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mUdpSocketIp4 == INVALID_SOCKET) {
|
||||
if (m_UDPSocketIP4 == INVALID_SOCKET) {
|
||||
return -1;
|
||||
}
|
||||
auto *socketAdr = (sockaddr_in *)(clientAI->ai_addr);
|
||||
@@ -82,12 +94,12 @@ int Socket::bindSocket(string clientIp, string clientPort) {
|
||||
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);
|
||||
int intResult = bind(m_UDPSocketIP4, (const sockaddr *)(socketAdr), (socklen_t)intSocklen);
|
||||
if (intResult < 0) {
|
||||
return intResult;
|
||||
}
|
||||
if ((intResult == 0) &&
|
||||
(getsockname(mUdpSocketIp4, (sockaddr *)socketAdr, (socklen_t *)&intSocklen) != -1)) {
|
||||
(getsockname(m_UDPSocketIP4, (sockaddr *)socketAdr, (socklen_t *)&intSocklen) != -1)) {
|
||||
setBoundClientPort(to_string((int)socketAdr->sin_port));
|
||||
}
|
||||
freeaddrinfo(clientAI);
|
||||
@@ -102,9 +114,9 @@ int Socket::bindSocket(string clientIp, string clientPort) {
|
||||
* false = SO_BROADCAST is not set
|
||||
* @return 0 = ok, -1 = error
|
||||
*/
|
||||
int Socket::setBroadcast(bool broadcast) const {
|
||||
int SPITSocket::setBroadcast(bool broadcast) const {
|
||||
int intOptionValue = broadcast ? 1 : 0;
|
||||
int intResult = setsockopt(mUdpSocketIp4, SOL_SOCKET, SO_BROADCAST, &intOptionValue, sizeof(int));
|
||||
int intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_BROADCAST, &intOptionValue, sizeof(int));
|
||||
return intResult;
|
||||
}
|
||||
/**
|
||||
@@ -115,8 +127,8 @@ int Socket::setBroadcast(bool broadcast) const {
|
||||
* @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) {
|
||||
int SPITSocket::sendMessageTo(const string &ip, const string &port, const char *message, int msgLength) {
|
||||
if (m_UDPSocketIP4 == INVALID_SOCKET) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -129,14 +141,14 @@ int Socket::sendMessageTo(const string &ip, const string &port, const char *mess
|
||||
|
||||
auto *ptrIP4SocketAddress = (sockaddr_in *)(ptrAddressInfo->ai_addr);
|
||||
int intSocklen = sizeof(*ptrIP4SocketAddress);
|
||||
if (mUdpSocketIp4 != INVALID_SOCKET) {
|
||||
if (m_UDPSocketIP4 != 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);
|
||||
intResult = sendto(m_UDPSocketIP4, 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);
|
||||
@@ -157,15 +169,15 @@ int Socket::sendMessageTo(const string &ip, const string &port, const char *mess
|
||||
* 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 SPITSocket::receiveMessage(char *p_Buffer, int p_BufferLength, string *serverIp) const {
|
||||
int intResult = -1;
|
||||
if (mUdpSocketIp4 == INVALID_SOCKET) {
|
||||
if (m_UDPSocketIP4 == 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);
|
||||
intResult = recvfrom(m_UDPSocketIP4, (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);
|
||||
@@ -174,7 +186,7 @@ int Socket::receiveMessage(char *p_Buffer, int p_BufferLength, string *serverIp)
|
||||
return intResult;
|
||||
}
|
||||
|
||||
ISocket::IpAddress Socket::getAdaptersInfo() {
|
||||
SPITSocket::IPAddress SPITSocket::getAdaptersInfo() {
|
||||
// iterate over active interfaces, and print out IPs
|
||||
esp_netif_t *netif = nullptr;
|
||||
if ((netif = esp_netif_next_unsafe(netif)) != nullptr) {
|
||||
@@ -209,5 +221,3 @@ string getClientHostName() {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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";
|
||||
|
||||
void SPITType::eventProjectClosed(SpitRepo<SPITType> &repo, SpitRepo<SPITType> &remoteRepo) {
|
||||
auto &entries = repo.getRepo();
|
||||
for (auto i = entries.begin(); i != entries.end();) {
|
||||
SPITType *ptrSPITType = i->second.get();
|
||||
if (ptrSPITType->getCreatedByClient() == true) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i = entries.erase(i);
|
||||
}
|
||||
// Remote
|
||||
remoteRepo.clearEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets confirmed = false for all SPITTypes.
|
||||
* This should be called when the client has loaded a project.
|
||||
*/
|
||||
void SPITType::setConfirmedFalse(SpitRepo<SPITType> &repo) {
|
||||
auto &entries = repo.getRepo();
|
||||
for (auto i = entries.begin(); i != entries.end(); i++) {
|
||||
i->second->setConfirmed(false);
|
||||
}
|
||||
}
|
||||
|
||||
SPITType::SPITType(string p_ID) {
|
||||
m_ID = p_ID;
|
||||
}
|
||||
|
||||
SPITType::SPITType(string id, string grpName, string name, bool fixed, bool projectIndependent, long long defaultDelay, long long defaultDuration) {
|
||||
m_ActionAssigned = false;
|
||||
m_Confirmed = false;
|
||||
m_ID = id;
|
||||
m_GroupName = grpName;
|
||||
m_Name = name;
|
||||
m_Fixed = fixed;
|
||||
m_ServerProjectIndepended = projectIndependent;
|
||||
m_DefaultDelay = defaultDelay;
|
||||
m_DefaultDuration = defaultDuration;
|
||||
}
|
||||
|
||||
void SPITType::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 SPITType::setConfirmed(bool p_Confirmed) {
|
||||
if (m_Confirmed == p_Confirmed)
|
||||
return false;
|
||||
m_Confirmed = p_Confirmed;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SPITType::setGroupName(const string &p_GroupName) {
|
||||
if (m_GroupName == p_GroupName)
|
||||
return false;
|
||||
m_GroupName = p_GroupName;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
bool SPITType::setName(const string &p_Name) {
|
||||
if (m_Name == p_Name)
|
||||
return false;
|
||||
m_Name = p_Name;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
bool SPITType::setServerRemote(bool p_BelongstoServer) {
|
||||
if (m_ServerRemote == p_BelongstoServer)
|
||||
return false;
|
||||
m_ServerRemote = p_BelongstoServer;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
bool SPITType::setProjectIndepended(bool p_ProjectIndepended) {
|
||||
if (m_ServerProjectIndepended == p_ProjectIndepended)
|
||||
return false;
|
||||
m_ServerProjectIndepended = p_ProjectIndepended;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
bool SPITType::setFixed(bool p_Fixed) {
|
||||
if (m_Fixed == p_Fixed)
|
||||
return false;
|
||||
m_Fixed = p_Fixed;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
bool SPITType::setDefaultDelay(long long p_Delay) {
|
||||
if (m_DefaultDelay == p_Delay)
|
||||
return false;
|
||||
m_DefaultDelay = p_Delay;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
bool SPITType::setDefaultDuration(long long p_Duration) {
|
||||
if (m_DefaultDuration == p_Duration)
|
||||
return false;
|
||||
m_DefaultDuration = p_Duration;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual construct - means ActionAssigned for SPITTypes is is not implemented in SPITProtocol.
|
||||
* This can used to setActionAssigned to all SPITObjects with this SPITType.
|
||||
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.
|
||||
* @return true = the m_ActionAssigned has changed.
|
||||
*/
|
||||
bool SPITType::setActionAssigned(bool p_ActionAssigned) {
|
||||
if (m_ActionAssigned == p_ActionAssigned)
|
||||
return false;
|
||||
m_ActionAssigned = p_ActionAssigned;
|
||||
m_Confirmed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content of the SPITType as received from the server
|
||||
* @param p_ReportSPITType
|
||||
* @return true = the SPITType is changed
|
||||
* false = the SPITType is NOT changed, because it is not allowed to change.
|
||||
*/
|
||||
bool SPITType::setMessageOP(SPIT_Message::ReportSPITType &reportSpitType) {
|
||||
bool boolChangeAllowed;
|
||||
bool boolChanged = false;
|
||||
|
||||
if (m_CreatedByClient == true && m_Fixed == true) {
|
||||
boolChangeAllowed = false;
|
||||
} else {
|
||||
boolChangeAllowed = true;
|
||||
}
|
||||
|
||||
// Confirmation should be changeable
|
||||
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 = reportSpitType.getConfirmed();
|
||||
}
|
||||
if (m_DefaultDelay != reportSpitType.getDelay()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_DefaultDelay = reportSpitType.getDelay();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_DefaultDuration != reportSpitType.getDuration()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_DefaultDuration = reportSpitType.getDuration();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_Fixed != reportSpitType.getFixed()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_Fixed = reportSpitType.getFixed();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_GroupName != reportSpitType.getGroupName()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_GroupName = reportSpitType.getGroupName();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ID != reportSpitType.getID()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_ID = reportSpitType.getID();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_Name != reportSpitType.getName()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_Name = reportSpitType.getName();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ServerProjectIndepended != reportSpitType.getServerProjectIndepended()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_ServerProjectIndepended = reportSpitType.getServerProjectIndepended();
|
||||
boolChanged = true;
|
||||
}
|
||||
if (m_ServerRemote != reportSpitType.getServerRemote()) {
|
||||
if (boolChangeAllowed == false) {
|
||||
return false;
|
||||
}
|
||||
m_ServerRemote = reportSpitType.getServerRemote();
|
||||
boolChanged = true;
|
||||
}
|
||||
return boolChanged;
|
||||
}
|
||||
|
||||
void SPITType::fillMessageOP(SPIT_Message::ReportSPITType &smReportSpitType) const {
|
||||
smReportSpitType.setConfirmed(m_Confirmed);
|
||||
smReportSpitType.setDelay(m_DefaultDelay);
|
||||
smReportSpitType.setDuration(m_DefaultDuration);
|
||||
smReportSpitType.setFixed(m_Fixed);
|
||||
smReportSpitType.setGroupName(m_GroupName);
|
||||
smReportSpitType.setID(m_ID);
|
||||
smReportSpitType.setName(m_Name);
|
||||
smReportSpitType.setServerProjectIndepended(m_ServerProjectIndepended);
|
||||
smReportSpitType.setServerRemote(m_ServerRemote);
|
||||
}
|
||||
void SPITType::fillMessageOP(SPIT_Message::RemoveSPITType &smRemoveSpitType) const {
|
||||
smRemoveSpitType.setID(m_ID);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,650 +0,0 @@
|
||||
|
||||
#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
@@ -1,202 +0,0 @@
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,745 +0,0 @@
|
||||
|
||||
#include "spit_processor.hpp"
|
||||
#include "esp_log.h"
|
||||
|
||||
namespace spit {
|
||||
static const char *TAG = "SPIT";
|
||||
|
||||
/**
|
||||
* Create a new SPIT_client instance, should be done once by the user app.
|
||||
* @param p_SPITClientInterface the user app should implement the SPIT_ClientInterface.
|
||||
*/
|
||||
SProcessor::SProcessor(string name, string projName, string hostName, string guid, Callbacks calls, InternalCallbacks intern)
|
||||
: mCallbacks(calls),
|
||||
mInternCallbacks(intern),
|
||||
mName(name),
|
||||
mGuid(guid),
|
||||
mProjName(projName),
|
||||
mComputerName(hostName) {
|
||||
}
|
||||
|
||||
SProcessor::~SProcessor() {
|
||||
}
|
||||
|
||||
unique_ptr<Message::Connect> SProcessor::createConnectMessage(string serverIP, string serverPort, string loginName, string loginPassword) {
|
||||
auto msg = make_unique<Message::Connect>(getComputerName(), mName);
|
||||
msg->setLoginName(loginName);
|
||||
msg->setLoginPassword(loginPassword);
|
||||
msg->setServerIP(serverIP);
|
||||
if (serverPort.length() <= 0) {
|
||||
serverPort = "0";
|
||||
}
|
||||
int intServerPort = stoi(serverPort);
|
||||
msg->setServerPort(intServerPort);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual construct - means actionAssigned for SPITTypes is is not implemented in SPITProtocol.
|
||||
* This can used to setActionAssigned to all SPITObjects with this SPITType.
|
||||
* This may be used in the case when the same action should be done for every SPITObject with this SPITType associated.
|
||||
* This tells the server not what action is done, but it tells the server that there is an action.
|
||||
* @param typeId the id of the SPITType
|
||||
* @param actionAssigned
|
||||
*/
|
||||
void SProcessor::setActionType(string typeId, bool actionAssigned) {
|
||||
SType *spitType = mSpitTypes.getEntry(typeId);
|
||||
if (spitType == nullptr)
|
||||
return;
|
||||
if (spitType->ActionAssigned.set(actionAssigned)) {
|
||||
sendTypeInternal(*spitType);
|
||||
for (auto &[key, value] : mSpitObjects.getRepo()) {
|
||||
if (value->SPITTypeID.get() == spitType->getID()) {
|
||||
if (value->setActionAssignedType(actionAssigned) == true) {
|
||||
sendObjectInternal(value.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This should be called if the user wants to associate/remove an action with a SPITObject. */
|
||||
void SProcessor::setActionObject(string spitObjId, bool actionAssigned) {
|
||||
SObject *spitObject = mSpitObjects.getEntry(spitObjId);
|
||||
if (spitObject == nullptr)
|
||||
return;
|
||||
if (spitObject->setActionAssigned(actionAssigned) == true) {
|
||||
sendObjectInternal(spitObject);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> SProcessor::createMessage(Message::OPPart &opPart) {
|
||||
if (mMessageNumberSend == 255)
|
||||
mMessageNumberSend = 1;
|
||||
else
|
||||
mMessageNumberSend++;
|
||||
opPart.setMessageNumber(mMessageNumberSend);
|
||||
opPart.setServerInfoInHeader(mGuid, mServerID);
|
||||
|
||||
int opFlag = opPart.getHeader()->getType();
|
||||
try {
|
||||
return Message::createMessage(opPart);
|
||||
} catch (...) {
|
||||
ESP_LOGD(TAG, "Exception client OPFlag: %d", opFlag);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void SProcessor::resetMessageNumberReceived() {
|
||||
mMessageNumberReceived = -1;
|
||||
mOvertakingMessages.clear();
|
||||
}
|
||||
|
||||
void SProcessor::checkParseMessageData(vector<char> data) {
|
||||
auto message = make_unique<Message>(data);
|
||||
// answerWatchdog();
|
||||
if (!message->getHeader() || !message->getOPPart()) {
|
||||
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
|
||||
return;
|
||||
}
|
||||
|
||||
int msgNum = (int)(message->getHeader()->getMessageNumber() & 0xFF);
|
||||
|
||||
if (msgNum == 0) {
|
||||
parseMessage(*message);
|
||||
return;
|
||||
}
|
||||
if (mMessageNumberReceived < 0) {
|
||||
mMessageNumberReceived = msgNum;
|
||||
parseMessage(*message);
|
||||
return;
|
||||
}
|
||||
|
||||
int msgNumNext = mMessageNumberReceived + 1;
|
||||
if (msgNumNext > 255 || msgNumNext < 1)
|
||||
msgNumNext = 1;
|
||||
|
||||
if (msgNum == msgNumNext) {
|
||||
mMessageNumberReceived = msgNum;
|
||||
parseMessage(*message);
|
||||
|
||||
mMessageNumberReceived = sendOvertakingMessage(mMessageNumberReceived);
|
||||
} else {
|
||||
// message has overtaken another message
|
||||
addOvertakingMessage(move(message));
|
||||
}
|
||||
}
|
||||
|
||||
void SProcessor::addOvertakingMessage(unique_ptr<Message> message) {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
if (mOvertakingMessages.size() > MAX_OVERTAKING_SPIT_MESSAGES) {
|
||||
ESP_LOGD(TAG, "Client receiveing: perhaps message lost !!!!!");
|
||||
}
|
||||
|
||||
int intMessageNumber = (int)(message->getHeader()->getMessageNumber() & 0xFF);
|
||||
for (auto it = mOvertakingMessages.begin(); it != mOvertakingMessages.end(); ++it) {
|
||||
const auto &overtaking = *it;
|
||||
int intOvertakingMessageNumber = (int)(overtaking->getHeader()->getMessageNumber() & 0xFF);
|
||||
if (intMessageNumber < intOvertakingMessageNumber) {
|
||||
mOvertakingMessages.insert(it, move(message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
mOvertakingMessages.push_back(move(message));
|
||||
}
|
||||
|
||||
int SProcessor::sendOvertakingMessage(int msgNumRec) {
|
||||
// check overtaking messages
|
||||
auto it = mOvertakingMessages.begin();
|
||||
while (mOvertakingMessages.size() > 0) {
|
||||
|
||||
int msgNumNext = msgNumRec + 1;
|
||||
if (msgNumNext > 255 || msgNumNext < 1)
|
||||
msgNumNext = 1;
|
||||
|
||||
auto &overtakingMessage = *it;
|
||||
int msgNum = (int)(overtakingMessage->getHeader()->getMessageNumber() & 0xFF);
|
||||
|
||||
if (msgNum == msgNumNext) {
|
||||
msgNumRec = msgNum;
|
||||
parseMessage(*overtakingMessage);
|
||||
mOvertakingMessages.erase(it);
|
||||
it = mOvertakingMessages.begin();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msgNumRec;
|
||||
}
|
||||
|
||||
void SProcessor::parseMessage(Message &message) {
|
||||
// answerWatchdog();
|
||||
if (!message.getHeader() || !message.getOPPart()) {
|
||||
ESP_LOGD(TAG, "Client::parseMessage incomplete message");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.getType()) {
|
||||
//----- Connection -----
|
||||
case Message::ReportProject::OPFLAG:
|
||||
parseReportProject(message.getAs<Message::ReportProject>());
|
||||
break;
|
||||
//----- SPIT Project -----
|
||||
case Message::StartProjectTransfer::OPFLAG:
|
||||
parseStartProjectTransfer(message.getAs<Message::StartProjectTransfer>());
|
||||
break;
|
||||
case Message::CloseProject::OPFLAG:
|
||||
parseCloseProject(message.getAs<Message::CloseProject>());
|
||||
break;
|
||||
case Message::RequestProjectTransfer::OPFLAG:
|
||||
parseRequestProjectTransfer(message.getAs<Message::RequestProjectTransfer>());
|
||||
break;
|
||||
case Message::EndProjectTransfer::OPFLAG:
|
||||
parseEndProjectTransfer(message.getAs<Message::EndProjectTransfer>());
|
||||
break;
|
||||
//----- SPIT Types ------
|
||||
case Message::ReportType::OPFLAG:
|
||||
parseReportType(message.getAs<Message::ReportType>());
|
||||
break;
|
||||
case Message::RemoveType::OPFLAG:
|
||||
parseRemoveType(message.getAs<Message::RemoveType>());
|
||||
//----- SPIT Objects ------
|
||||
break;
|
||||
case Message::ReportObject::OPFLAG:
|
||||
parseReportObject(message.getAs<Message::ReportObject>());
|
||||
break;
|
||||
case Message::RemoveObject::OPFLAG:
|
||||
parseRemoveObject(message.getAs<Message::RemoveObject>());
|
||||
break;
|
||||
//----- Play SPIT Objects ------
|
||||
case Message::PlayStart::OPFLAG:
|
||||
parsePlayStart(message.getAs<Message::PlayStart>());
|
||||
break;
|
||||
case Message::PlayObject::OPFLAG:
|
||||
parsePlayObject(message.getAs<Message::PlayObject>());
|
||||
break;
|
||||
case Message::PlayEnd::OPFLAG:
|
||||
parsePlayEnd(message.getAs<Message::PlayEnd>());
|
||||
break;
|
||||
case Message::ReportPlayStatus::OPFLAG:
|
||||
parseReportPlayStatus(message.getAs<Message::ReportPlayStatus>());
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(TAG, "Client::parseMessage: Unknown Message");
|
||||
}
|
||||
}
|
||||
|
||||
//----- SPIT Project ------
|
||||
void SProcessor::parseReportProject(Message::ReportProject &message) {
|
||||
ESP_LOGD(TAG, "parse ReportProject");
|
||||
mServerProjectID = message.getProjectID();
|
||||
mServerProjectName = message.getProjectName();
|
||||
mServerFramesPerSecond = message.getFramesPerSecond();
|
||||
mCallbacks.onProjectUpdate(ProjUpdate::ServerLoaded, mServerProjectID);
|
||||
|
||||
// Set all SPITTypes and SPITObjects confirmed = false
|
||||
SType::setConfirmedFalse(mSpitTypes);
|
||||
SObject::setConfirmedFalse(mSpitObjects);
|
||||
|
||||
// Send RequestProjectTransfer
|
||||
Message::RequestProjectTransfer sMRequestProjectTransfer;
|
||||
if (mInternCallbacks.sendMessage(sMRequestProjectTransfer) < 0) {
|
||||
ESP_LOGD(TAG, "Client::parseReportProject could not send RequestProjectTransfer");
|
||||
}
|
||||
|
||||
// todo Don't send the ReportProject here it should be sended after parseEndProjectTransfer
|
||||
// Send client's ReportProject
|
||||
Message::ReportProject reportProject(mProjName, mProjName);
|
||||
reportProject.setFramesPerSecond(0);
|
||||
if (mInternCallbacks.sendMessage(reportProject) < 0) {
|
||||
ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
|
||||
}
|
||||
}
|
||||
|
||||
void SProcessor::parseCloseProject(Message::CloseProject &p_CloseSPITProject) {
|
||||
ESP_LOGD(TAG, "parse CloseProject");
|
||||
string stringProjectID;
|
||||
mCallbacks.onProjectUpdate(ProjUpdate::ServerClosed, p_CloseSPITProject.getProjectID());
|
||||
SPlayer::clearPlayers();
|
||||
}
|
||||
|
||||
void SProcessor::parseRequestProjectTransfer(Message::RequestProjectTransfer &message) {
|
||||
ESP_LOGD(TAG, "parse RequestProjectTransfer");
|
||||
// StartProjectTransfer
|
||||
Message::StartProjectTransfer sMStartProjectTransfer;
|
||||
if (mInternCallbacks.sendMessage(sMStartProjectTransfer) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// send all listes SPITTypes
|
||||
for (const auto &[key, value] : mSpitTypes.getRepo()) {
|
||||
sendTypeInternal(*value);
|
||||
mInternCallbacks.delay(10);
|
||||
}
|
||||
for (auto &[key, value] : mSpitObjects.getRepo()) {
|
||||
sendObjectInternal(value.get());
|
||||
mInternCallbacks.delay(10);
|
||||
}
|
||||
|
||||
// EndProjectTransfer
|
||||
Message::EndProjectTransfer sMEndProjectTransfer;
|
||||
mInternCallbacks.sendMessage(sMEndProjectTransfer);
|
||||
}
|
||||
|
||||
void SProcessor::parseStartProjectTransfer(Message::StartProjectTransfer &message) {
|
||||
mCallbacks.onProjectUpdate(ProjUpdate::StartTransfer, mServerProjectID);
|
||||
}
|
||||
|
||||
void SProcessor::parseEndProjectTransfer(Message::EndProjectTransfer &message) {
|
||||
SObject::clearUnconfirmedObjects(mSpitObjects);
|
||||
mCallbacks.onProjectUpdate(ProjUpdate::EndTransfer, mServerProjectID);
|
||||
|
||||
// Send Message::ReportProject after the mSPITClientInterface is notfied of EndProjectTransfer
|
||||
Message::ReportProject reportSPITProject(mProjName, mProjName);
|
||||
reportSPITProject.setFramesPerSecond(0);
|
||||
if (mInternCallbacks.sendMessage(reportSPITProject) < 0) {
|
||||
ESP_LOGD(TAG, "Client::parseReportProject could not send Client's ReportProject");
|
||||
}
|
||||
}
|
||||
|
||||
void SProcessor::parseReportType(Message::ReportType &message) {
|
||||
ESP_LOGD(TAG, "parse ReportType ID %s Name %s", message.getID().c_str(), message.getName().c_str());
|
||||
SType *sType;
|
||||
bool isNew = false;
|
||||
bool isChanged = false;
|
||||
if (message.getServerRemote() == false) {
|
||||
sType = mSpitTypes.getEntry(message.getID());
|
||||
if (sType == nullptr) {
|
||||
// The user's app may veto the SPITType
|
||||
bool createdByClient = false;
|
||||
if (sType) {
|
||||
createdByClient = sType->getCreatedByClient();
|
||||
}
|
||||
|
||||
if (mCallbacks.onCheckSpitTypeVeto(false, createdByClient) == false) {
|
||||
ESP_LOGW(TAG, "TypeVeto %s / %s", message.getID().c_str(), message.getName().c_str());
|
||||
return;
|
||||
}
|
||||
auto spitType = make_unique<SType>(message.getID());
|
||||
sType = spitType.get();
|
||||
mSpitTypes.addEntry(move(spitType));
|
||||
isNew = true;
|
||||
}
|
||||
} else {
|
||||
sType = mRemoteSpitTypes.getEntry(message.getID());
|
||||
if (sType == nullptr) {
|
||||
auto spitType = make_unique<SType>(message.getID());
|
||||
sType = spitType.get();
|
||||
mRemoteSpitTypes.addEntry(move(spitType));
|
||||
isNew = true;
|
||||
}
|
||||
}
|
||||
if (!sType->setMessageOP(message)) {
|
||||
// SPITType is not changable -> send back to the server
|
||||
sendTypeInternal(*sType);
|
||||
return;
|
||||
}
|
||||
|
||||
auto eventType = isNew ? ObjectEvent::Created : ObjectEvent::Changed;
|
||||
// add or change SPITType
|
||||
mCallbacks.onSpitType(eventType, sType->ServerRemote.get(), *sType);
|
||||
|
||||
if (sType != nullptr) {
|
||||
if (sType->setConfirmed(true) == true || isChanged == true) {
|
||||
sendTypeInternal(*sType);
|
||||
}
|
||||
}
|
||||
}
|
||||
void SProcessor::parseRemoveType(Message::RemoveType &message) {
|
||||
ESP_LOGD(TAG, "parse RemoveType %s", message.getID().c_str());
|
||||
bool isRemote = false;
|
||||
string sTypeID = message.getID();
|
||||
|
||||
SType *sType = mRemoteSpitTypes.getEntry(sTypeID);
|
||||
if (!sType) {
|
||||
isRemote = true;
|
||||
} else {
|
||||
sType = mSpitTypes.getEntry(sTypeID);
|
||||
if (!sType) {
|
||||
isRemote = false;
|
||||
} else {
|
||||
// No SType with sTypeID is listet
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (sType->getCreatedByClient() && sType->Fixed.get()) {
|
||||
// the SPITyte is created by client himself and it is fixed -> don't remove the SType!!
|
||||
// Send the SPITTyp back to the server
|
||||
sendTypeInternal(*sType);
|
||||
return;
|
||||
}
|
||||
|
||||
mCallbacks.onSpitType(ObjectEvent::Deleted, isRemote, *sType);
|
||||
if (isRemote == false) {
|
||||
mSpitTypes.removeEntry(*sType);
|
||||
} else {
|
||||
mRemoteSpitTypes.removeEntry(*sType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change an existing SPIT_Type.
|
||||
* @param p_SPITType the SPITType vont
|
||||
* @return true = changed, false = not changed maybe p_SPITType is NULL or the SPITType doesn't exists
|
||||
*/
|
||||
bool SProcessor::changeType(SType *sType) {
|
||||
if (sType == nullptr)
|
||||
return false;
|
||||
SType *mod = mSpitTypes.getEntry(sType->getID());
|
||||
if (mod == nullptr)
|
||||
return false;
|
||||
|
||||
mod->DefaultDelay.set(sType->DefaultDelay.get());
|
||||
mod->DefaultDuration.set(sType->DefaultDuration.get());
|
||||
mod->Fixed.set(sType->Fixed.get());
|
||||
mod->GroupName.set(sType->GroupName.get());
|
||||
mod->Name.set(sType->Name.get());
|
||||
mod->ProjectIndepended.set(sType->ProjectIndepended.get());
|
||||
|
||||
mCallbacks.onSpitType(ObjectEvent::Changed, false, *mod);
|
||||
sendTypeInternal(*mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a client has removed a SPITType where id == p_SPITTypeID, it should send it to the server.
|
||||
* The corresponding SPITType if listet in SPITType will be deleted.
|
||||
* An eventRemoveSPITType will occur.
|
||||
* If a connection to a SPITServer is established, the SPITServer may dicard the deletion an an eventSPITType will occur
|
||||
* -> the SPITType will be listet again.
|
||||
* @param p_SPITType the id of the SPITType ro remove
|
||||
* @return 0 = is sended, -1 = is not sended
|
||||
*/
|
||||
int SProcessor::removeType(string sType) {
|
||||
if (sType.length() <= 0)
|
||||
return -1;
|
||||
SType *mod = mSpitTypes.getEntry(sType);
|
||||
if (mod == nullptr)
|
||||
return -1;
|
||||
Message::RemoveType sMRemoveSPITType;
|
||||
mod->fillMessageOP(sMRemoveSPITType);
|
||||
mCallbacks.onSpitType(ObjectEvent::Deleted, false, *mod);
|
||||
mSpitTypes.removeEntry(*mod);
|
||||
return mInternCallbacks.sendMessage(sMRemoveSPITType);
|
||||
}
|
||||
|
||||
SType *SProcessor::createType(string id, string groupName, string name, uint64_t delay, uint64_t duration, bool fixed, bool projIndipendent) {
|
||||
bool boolNew;
|
||||
SType *sType = mSpitTypes.getEntry(id);
|
||||
if (sType == nullptr) {
|
||||
auto spitType = make_unique<SType>(id, groupName, name, fixed, projIndipendent, delay, duration);
|
||||
sType = spitType.get();
|
||||
mSpitTypes.addEntry(move(spitType));
|
||||
sType->setCreatedByClient(true);
|
||||
boolNew = true;
|
||||
} else {
|
||||
sType->GroupName.set(groupName);
|
||||
sType->Name.set(name);
|
||||
sType->Fixed.set(fixed);
|
||||
sType->ProjectIndepended.set(projIndipendent);
|
||||
sType->DefaultDelay.set(delay);
|
||||
sType->DefaultDuration.set(duration);
|
||||
boolNew = false;
|
||||
}
|
||||
|
||||
auto eventType = boolNew ? ObjectEvent::Created : ObjectEvent::Changed;
|
||||
mCallbacks.onSpitType(eventType, false, *sType);
|
||||
sendTypeInternal(*sType);
|
||||
return sType;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a client has changed a SPITType, it should send it to the server to transmit the changes.
|
||||
* If the SPITType is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the changes.
|
||||
* @param sType the pointer to the changed SPITType
|
||||
* @return 0 = is sended, -1 = is not sended
|
||||
*/
|
||||
int SProcessor::sendTypeInternal(SType &sType) {
|
||||
Message::ReportType reportType;
|
||||
sType.fillMessageOP(reportType);
|
||||
return mInternCallbacks.sendMessage(reportType);
|
||||
}
|
||||
|
||||
//----- SPIT Objects ------
|
||||
void SProcessor::parseReportObject(Message::ReportObject &message) {
|
||||
ESP_LOGD(TAG, "parse ReportObject %s", message.getID().c_str());
|
||||
SObject *sObject;
|
||||
SType *sType;
|
||||
bool isNew = false;
|
||||
bool isRemote = false;
|
||||
bool isChanged = false;
|
||||
{
|
||||
ESP_LOGD(TAG, "parse ReportObject %s / %s", message.getID().c_str(), message.getName().c_str());
|
||||
if (message.getServerRemote() == false) {
|
||||
isRemote = false;
|
||||
sObject = mSpitObjects.getEntry(message.getID());
|
||||
sType = mSpitTypes.getEntry(message.getSPITTypeID());
|
||||
|
||||
if (sType == nullptr) {
|
||||
// No associated SPITType found
|
||||
if (sObject != nullptr) {
|
||||
// SpitObject exists but has no corresponding SPITType -> remove the SPITObject without sending a message
|
||||
// Maybe the SPITObject has changed the SPITTypeID to a SPITTypeID of another board
|
||||
mSpitObjects.removeEntry(*sObject);
|
||||
}
|
||||
return;
|
||||
}
|
||||
bool isKnownType = sType != nullptr;
|
||||
if (sObject == nullptr) {
|
||||
// The user's app my veto the SPITType
|
||||
if (mCallbacks.onCheckSpitObjectVeto(isKnownType) == false) {
|
||||
ESP_LOGW(TAG, "ObjectVeto %s / %s", message.getID().c_str(), message.getName().c_str());
|
||||
return;
|
||||
}
|
||||
auto spitObj = make_unique<SObject>(message.getID());
|
||||
sObject = spitObj.get();
|
||||
mSpitObjects.addEntry(move(spitObj));
|
||||
isNew = true;
|
||||
} else {
|
||||
// The user's app my veto the SPITType
|
||||
if (mCallbacks.onCheckSpitObjectVeto(isKnownType) == false) {
|
||||
// SpitObject exists and User APp denied the SPITObject -> remove the SPITObject without sending a message
|
||||
mSpitObjects.removeEntry(*sObject);
|
||||
ESP_LOGW(TAG, "TypeVeto %s / %s", message.getID().c_str(), message.getName().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isRemote = true;
|
||||
sObject = mRemoteSpitObjects.getEntry(message.getID());
|
||||
sType = mRemoteSpitTypes.getEntry(message.getSPITTypeID());
|
||||
if (sType == nullptr) {
|
||||
// No associated SPITType found
|
||||
return;
|
||||
}
|
||||
if (sObject == nullptr) {
|
||||
auto spitObj = make_unique<SObject>(message.getID());
|
||||
sObject = spitObj.get();
|
||||
mRemoteSpitObjects.addEntry(move(spitObj));
|
||||
isNew = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sObject->setMessageOP(&message)) {
|
||||
ESP_LOGE(TAG, "Change not allowed %s", sObject->getID().c_str());
|
||||
// setMessageOP error - the SPITObject can't be changed, it may be fixed and crated by this client
|
||||
sendObjectInternal(sObject);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRemote == false) {
|
||||
// set the virtual action assignment
|
||||
sObject->setActionAssignedType(sType->ActionAssigned.get());
|
||||
}
|
||||
|
||||
auto eventType = isNew ? ObjectEvent::Created : ObjectEvent::Changed;
|
||||
mCallbacks.onSpitObject(eventType, isRemote, *sType, *sObject);
|
||||
|
||||
if (sObject->setConfirmed(true) == true || isChanged == true) {
|
||||
// Confirmation has changed
|
||||
sendObjectInternal(sObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SProcessor::parseRemoveObject(Message::RemoveObject &message) {
|
||||
ESP_LOGD(TAG, "parse RemoveObject %s", message.getID().c_str());
|
||||
SObject *sObject = mRemoteSpitObjects.getEntry(message.getID());
|
||||
if (sObject != nullptr) {
|
||||
SType *sType = mRemoteSpitTypes.getEntry(sObject->SPITTypeID.get());
|
||||
if (sType != nullptr) {
|
||||
mCallbacks.onSpitObject(ObjectEvent::Deleted, true, *sType, *sObject);
|
||||
}
|
||||
mRemoteSpitObjects.removeEntry(*sObject);
|
||||
} else {
|
||||
// call removeObject, this will notify the server that the object is removed
|
||||
removeObject(message.getID());
|
||||
}
|
||||
}
|
||||
|
||||
int SProcessor::sendObjectInternal(SObject *sObject) {
|
||||
if (sObject == nullptr)
|
||||
return -1;
|
||||
Message::ReportObject reportObject;
|
||||
sObject->fillMessageOP(reportObject);
|
||||
return mInternCallbacks.sendMessage(reportObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the client changes an existing SPITObject (normally the client should not do this), then he should send the changes to the SPITServer.
|
||||
* An eventSPITObject occurs.
|
||||
* The SPITServer may discard the changes and a second eventSPITObject occurs to correct the changes.
|
||||
* @param obj the pointer to the changed SPITObject.
|
||||
* @return 0 = sended, -1 = not sended
|
||||
*/
|
||||
bool SProcessor::changeObject(SObject *sObject) {
|
||||
if (sObject == nullptr)
|
||||
return false;
|
||||
SObject *mod = mSpitObjects.getEntry(sObject->getID());
|
||||
if (mod == nullptr)
|
||||
return false;
|
||||
SType *sType = mSpitTypes.getEntry(sObject->getID());
|
||||
if (mod == nullptr)
|
||||
return false;
|
||||
|
||||
mod->setActionAssigned(sObject->getActionAssigned());
|
||||
mod->Delay.set(sObject->Delay.get());
|
||||
mod->Duration.set(sObject->Delay.get());
|
||||
mod->Fixed.set(sObject->Fixed.get());
|
||||
mod->FrameFadeInLength.set(sObject->FrameFadeInLength.get());
|
||||
mod->FrameFadeOutLength.set(sObject->FrameFadeOutLength.get());
|
||||
mod->FrameLength.set(sObject->FrameLength.get());
|
||||
mod->FrameStart.set(sObject->FrameStart.get());
|
||||
mod->Name.set(sObject->Name.get());
|
||||
mod->Remark.set(sObject->Remark.get());
|
||||
mod->SPITTypeID.set(sObject->SPITTypeID.get());
|
||||
mod->ServerParams.set(sObject->ServerParams.get());
|
||||
mod->Track.set(sObject->Track.get());
|
||||
mod->ValueFactor.set(sObject->ValueFactor.get());
|
||||
mod->ValueUse.set(sObject->ValueUse.get());
|
||||
|
||||
mCallbacks.onSpitObject(ObjectEvent::Changed, false, *sType, *mod);
|
||||
sendObjectInternal(mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the client wants to remove a SPITObject with id == p_SPITObjectID (normally the client should not do this), then he should send it to the SPITServer.
|
||||
* The corresponding SPITObject if listet in SPITObject will be deleted.
|
||||
* An eventRemoveSPITType will occur.
|
||||
* If an connection to a SPITServer is established, the SPITServer may discard the deletion and an eventSPITObject occurs
|
||||
* -> the SPITObject is listet again.
|
||||
* @param objId the id of the SPITObject to remove.
|
||||
* @return 0 = sended to the SPITServer, -1 = not sended to the SPITServer or nos SPITObject with id == objId exists.
|
||||
*/
|
||||
int SProcessor::removeObject(string objId) {
|
||||
if (objId.length() <= 0)
|
||||
return -1;
|
||||
Message::RemoveObject remObj;
|
||||
|
||||
SObject *sObject = mSpitObjects.getEntry(objId);
|
||||
if (sObject == nullptr)
|
||||
return -1;
|
||||
SType *sType = mSpitTypes.getEntry(sObject->SPITTypeID.get());
|
||||
if (sType == nullptr)
|
||||
return -1;
|
||||
|
||||
sObject->fillMessageOP(remObj);
|
||||
mCallbacks.onSpitObject(ObjectEvent::Deleted, false, *sType, *sObject);
|
||||
mSpitObjects.removeEntry(*sObject);
|
||||
return mInternCallbacks.sendMessage(remObj);
|
||||
}
|
||||
|
||||
// //----- Play SPIT Objects ------
|
||||
|
||||
void SProcessor::parsePlayStart(Message::PlayStart &message) {
|
||||
ESP_LOGD(TAG, "parse PlayStart ID: %s Name: %s Running: %d", message.getPlayerID().c_str(), message.getPlayerName().c_str(), (int)message.getPlayerIsRunning());
|
||||
SPlayer &player = SPlayer::getSPITPlayer(message.getPlayerID());
|
||||
player.setIsRunning(message.getPlayerIsRunning());
|
||||
player.setName(message.getPlayerName());
|
||||
player.setType(message.getPlayerType());
|
||||
player.setTime(message.getTime());
|
||||
player.startPlaySequence();
|
||||
|
||||
mCallbacks.onPlay(player.getID(), player.getName(), player.getType(), player.getIsRunning(), player.getTime());
|
||||
}
|
||||
|
||||
void SProcessor::parsePlayObject(Message::PlayObject &message) {
|
||||
|
||||
SPlayer &player = SPlayer::getSPITPlayer(message.getPlayerID());
|
||||
SObject *sObject = mSpitObjects.getEntry(message.getSPITObjectID());
|
||||
|
||||
if (sObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
SPlayer::PlayType *playType = player.addTypePlaying(sObject->SPITTypeID.get());
|
||||
if (playType == nullptr) {
|
||||
return;
|
||||
}
|
||||
playType->setPlayerIsRunning(player.getIsRunning());
|
||||
playType->addValue(((double)message.getValue() / 1000000), ((double)sObject->ValueFactor.get() / 1000000));
|
||||
}
|
||||
|
||||
void SProcessor::parsePlayEnd(Message::PlayEnd &message) {
|
||||
SPlayer &sPlayer = SPlayer::getSPITPlayer(message.getPlayerID());
|
||||
|
||||
auto &playTypes = sPlayer.getPlaySPITTypes();
|
||||
for (auto i = playTypes.begin(); i != playTypes.end(); i++) {
|
||||
SPlayer::PlayType *playType = i->second.get();
|
||||
bool isStarted = playType->getIsNew();
|
||||
bool iStopped = (playType->getIsPlayed() == false);
|
||||
SType *ptrSPITType = mSpitTypes.getEntry(playType->getSPITTypeID());
|
||||
if (ptrSPITType == nullptr) {
|
||||
// set isplayed to false, the ptrPlayObject will be removed by sPlayer.endPlaySequence()
|
||||
playType->setIsPlayed(false);
|
||||
continue;
|
||||
}
|
||||
mCallbacks.onPlaySpitType(playType->getPlayerID(), playType->getSPITTypeID(), playType->getPlayerIsRunning(), isStarted, iStopped, playType->getValue());
|
||||
}
|
||||
sPlayer.endPlaySequence();
|
||||
}
|
||||
|
||||
void SProcessor::parseReportPlayStatus(Message::ReportPlayStatus &message) {
|
||||
SType *sType = NULL;
|
||||
|
||||
SObject *sObject = mRemoteSpitObjects.getEntry(message.getID());
|
||||
if (sObject == nullptr) {
|
||||
sObject = mSpitObjects.getEntry(message.getID());
|
||||
if (sObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (sObject->ServerRemote.get() == false) {
|
||||
sType = mSpitTypes.getEntry(sObject->SPITTypeID.get());
|
||||
} else {
|
||||
sType = mRemoteSpitTypes.getEntry(sObject->SPITTypeID.get());
|
||||
}
|
||||
|
||||
if (sType == nullptr) {
|
||||
return;
|
||||
}
|
||||
mCallbacks.onPlayRemoteObjectStatus(*sType, *sObject, message.getFrameInsideObject(), message.getValue());
|
||||
}
|
||||
|
||||
// //--------- Remote ----------
|
||||
|
||||
/**
|
||||
* Send a remote control command to the SPITServer.
|
||||
* There may be different command types:
|
||||
* a) Some don't use value e.g. go to next scene, olay a jingle
|
||||
* b) Some use values e.g. the main sound fader
|
||||
* @param sObjectId the id of the remote SPITObject (this represents the remote control command)
|
||||
* @param valuePpm the value in ppm
|
||||
* in case a) the value is ignored
|
||||
* in case b) the value is used
|
||||
* @param valueFlag indicates how the server should use valuePpm:
|
||||
* VALUEFLAG_DIRECT (0x00) The server overwrites its existing value with p_Value
|
||||
* VALUEFLAG_INCREASE (0x01) The server increases his existing value by valuePpm
|
||||
* VALUEFLAG_DECREASE (0x01) The server decreases his existing value by valuePpm
|
||||
*/
|
||||
void SProcessor::sendRemoteObject(string sObjectId, int valuePpm, char valueFlag) {
|
||||
SObject *remoteObject = mRemoteSpitObjects.getEntry(sObjectId);
|
||||
if (remoteObject == nullptr)
|
||||
return;
|
||||
|
||||
Message::PlayStart playSPITStart(mGuid, mProjName, SPlayer::PTYPE_DISCRETE);
|
||||
playSPITStart.setPlayerIsRunning(false);
|
||||
playSPITStart.setTime(0);
|
||||
mInternCallbacks.sendMessage(playSPITStart);
|
||||
|
||||
Message::PlayObject playSPITObject;
|
||||
playSPITObject.setID(remoteObject->getID());
|
||||
playSPITObject.setPlayPrePosition(false);
|
||||
playSPITObject.setPlayerID(mGuid);
|
||||
playSPITObject.setValue(valuePpm);
|
||||
playSPITObject.setValueFlag(valueFlag);
|
||||
mInternCallbacks.sendMessage(playSPITObject);
|
||||
|
||||
Message::PlayEnd playSPITEnd(mGuid);
|
||||
mInternCallbacks.sendMessage(playSPITEnd);
|
||||
}
|
||||
|
||||
} // namespace spit
|
||||
@@ -1,5 +0,0 @@
|
||||
idf_component_register(
|
||||
SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES cmock spit
|
||||
)
|
||||
@@ -1,123 +0,0 @@
|
||||
/**
|
||||
* @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.
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
-- 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")
|
||||
@@ -11,7 +9,7 @@ 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_pLen = ProtoField.uint32("spit.paylen", "Length")
|
||||
|
||||
local f_pSession = ProtoField.string("spit.key", "Spit Session")
|
||||
local f_pKey = ProtoField.string("spit.key", "Spit Key")
|
||||
@@ -96,17 +94,6 @@ function extractVersionString(buffer)
|
||||
|
||||
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
|
||||
@@ -127,9 +114,8 @@ function spit_proto.dissector(buffer, pinfo, tree)
|
||||
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 pLen = buffer(99,4):le_uint()
|
||||
pTree:add(f_pLen, buffer(99,4)):set_text("Pyload Length: " .. pLen)
|
||||
|
||||
local info_text = "Type: " .. type
|
||||
if type == 1 then -- Connect
|
||||
@@ -180,7 +166,7 @@ function spit_proto.dissector(buffer, pinfo, tree)
|
||||
|
||||
pTree:add(f_pProjectId, buffer(103,41))
|
||||
pTree:add(f_pProjectName, buffer(144,64))
|
||||
addBigEndianValue(pTree, f_pFramesPerSec, buffer(208,4))
|
||||
pTree:add(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())
|
||||
|
||||
@@ -216,8 +202,8 @@ function spit_proto.dissector(buffer, pinfo, tree)
|
||||
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))
|
||||
pTree:add(f_pDelay, buffer(251,8))
|
||||
pTree:add(f_pDuration, buffer(259,8))
|
||||
|
||||
local group = buffer(148,39):string()
|
||||
local name = buffer(187,64):string()
|
||||
@@ -240,16 +226,17 @@ function spit_proto.dissector(buffer, pinfo, tree)
|
||||
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_pFrameStart, buffer(316,8))
|
||||
pTree:add(f_pFrameLength, buffer(324,8))
|
||||
pTree:add(f_pFrameFadeIn, buffer(332,8))
|
||||
pTree:add(f_pFrameFadeOut, buffer(340,8))
|
||||
local valueFactor = buffer(348,4):le_uint()
|
||||
pTree:add(f_pValueFactor, buffer(348,4)):set_text("Value Factor" .. valueFactor)
|
||||
pTree:add(f_pValueUse, buffer(349,1))
|
||||
addBigEndianValue(pTree, f_pTrack, buffer(350,4))
|
||||
pTree:add(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_pDelay, buffer(418,8))
|
||||
pTree:add(f_pDuration, buffer(426,8))
|
||||
pTree:add(f_pAssigned, buffer(435,1))
|
||||
|
||||
local name = buffer(147,64):string()
|
||||
@@ -270,16 +257,17 @@ function spit_proto.dissector(buffer, pinfo, tree)
|
||||
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))
|
||||
pTree:add(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_pObjectsFrames, buffer(185,8))
|
||||
pTree:add(f_pPlayerPrePos, buffer(193,1))
|
||||
addBigEndianValue(pTree, f_pValue, buffer(194,4))
|
||||
pTree:add(f_pValue, buffer(194,4))
|
||||
pTree:add(f_pValueFlag, buffer(198,1))
|
||||
|
||||
local oId = buffer(144,41):string()
|
||||
@@ -293,9 +281,10 @@ function spit_proto.dissector(buffer, pinfo, tree)
|
||||
|
||||
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))
|
||||
pTree:add(f_pObjectsFrames, buffer(144,8))
|
||||
pTree:add(f_pValue, buffer(152,4))
|
||||
info_text = string.format("Report Play Status")
|
||||
|
||||
else
|
||||
@@ -359,3 +348,15 @@ spit_proto:register_heuristic("udp", spit_proto.dissector)
|
||||
|
||||
spit_sad_proto:register_heuristic("udp", spit_sad_proto.dissector)
|
||||
|
||||
|
||||
-- local f_pFramesPerSec = ProtoField.uint32("spit.framesPerSec", "Frames per second")
|
||||
-- local f_pTrack = ProtoField.uint32("spit.track", "Track")
|
||||
-- local f_pObjectsFrames = ProtoField.uint64("spit.ObjectFrames", "Object Frames")
|
||||
-- local f_pValue = ProtoField.uint64("spit.Value", "Value")
|
||||
-- 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_pDelay = ProtoField.uint64("spit.delay", "Delay")
|
||||
-- local f_pDuration = ProtoField.uint64("spit.duration", "Duration")
|
||||
-- local f_pPlayerFrames = ProtoField.uint64("spit.PlayerFrame", "Player Frames")
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
UnitTestsFrame()
|
||||
target_link_libraries(${moduleName} PUBLIC
|
||||
fmt
|
||||
hwMock
|
||||
)
|
||||
@@ -1,320 +0,0 @@
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* @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);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,350 +0,0 @@
|
||||
/**
|
||||
* @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());
|
||||
}
|
||||
}
|
||||
@@ -1,516 +0,0 @@
|
||||
/**
|
||||
* @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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @file uTestMain.cpp
|
||||
* @author Gustice
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include "doctest/doctest.h"
|
||||
TEST_CASE("TestTest") {
|
||||
CHECK(true == true);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,15 @@
|
||||
#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)
|
||||
using AllmostFinishedCb = void (*)(uint8_t newIdx);
|
||||
WatchMotor(IStepperMotor &stepper, AllmostFinishedCb onDone)
|
||||
: _stepper(stepper),
|
||||
_onFinCb(onDone),
|
||||
_logger(logger) {
|
||||
_onFinCb(onDone) {
|
||||
}
|
||||
|
||||
void moveTo(uint8_t position, uint8_t profile, int minJumps, float accel, float speed) {
|
||||
@@ -46,12 +44,7 @@ class WatchMotor {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
_stepper.moveBy(delta + corr, profile, accel, speed, [&]() {
|
||||
if (_onFinCb) {
|
||||
_onFinCb(position);
|
||||
}
|
||||
@@ -65,6 +58,5 @@ class WatchMotor {
|
||||
private:
|
||||
IStepperMotor &_stepper;
|
||||
uint8_t _currentIndex{};
|
||||
AlmostFinishedCb _onFinCb{};
|
||||
ILogging &_logger;
|
||||
AllmostFinishedCb _onFinCb{};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
UnitTestsFrame()
|
||||
target_link_libraries(${moduleName} PUBLIC
|
||||
devHal
|
||||
bases
|
||||
)
|
||||
@@ -2,6 +2,8 @@
|
||||
* @file TestableUTest.cpp
|
||||
* @author Gustice
|
||||
* @brief
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
@@ -17,7 +19,7 @@ class StepperMotorMock : public IStepperMotor {
|
||||
lastAngle = angle;
|
||||
lastProfile = profile;
|
||||
}
|
||||
void moveBy(float angle, uint8_t profile, float accel, float speed, std::function<void(int diff)> profileDone = nullptr) override {
|
||||
void moveBy(float angle, uint8_t profile, float accel, float speed, std::function<void()> profileDone = nullptr) override {
|
||||
lastAngle = angle;
|
||||
lastProfile = profile;
|
||||
}
|
||||
@@ -35,12 +37,6 @@ class StepperMotorMock : public IStepperMotor {
|
||||
float nextPos{};
|
||||
};
|
||||
|
||||
class LoggerMock : public ILogging {
|
||||
void output(Severity severity, std::string message) override {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
void onFin(uint8_t idx) {
|
||||
}
|
||||
|
||||
@@ -51,8 +47,7 @@ class WatchFaceFixture {
|
||||
protected:
|
||||
static constexpr int MicroSteps = 32;
|
||||
StepperMotorMock motor;
|
||||
LoggerMock logger;
|
||||
WatchMotor sut{motor, onFin, logger};
|
||||
WatchMotor sut{motor, onFin};
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
+1
-1
Submodule core updated: c80f61a60a...02db420163
+10
-3
@@ -1,10 +1,17 @@
|
||||
dependencies:
|
||||
ethernet_init:
|
||||
dependencies: []
|
||||
source:
|
||||
path: /home/gustice/esp/v5.4.1/esp-idf/examples/ethernet/basic/components/ethernet_init
|
||||
type: local
|
||||
version: '*'
|
||||
idf:
|
||||
source:
|
||||
type: idf
|
||||
version: 5.4.3
|
||||
version: 5.4.1
|
||||
direct_dependencies:
|
||||
- ethernet_init
|
||||
- idf
|
||||
manifest_hash: f963becbad30dee4a0a46222b7f0ae7dd40100701f7b7147a846011f8dabe9ca
|
||||
target: esp32
|
||||
manifest_hash: dfcb516d4bd1043fe7dbc63ade7e95173fcf2993c59d7108e7b96cb5af8f7ebd
|
||||
target: esp32c6
|
||||
version: 2.0.0
|
||||
|
||||
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.
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
idf_component_register(SRCS "lightsMain.cpp"
|
||||
idf_component_register(SRCS "watchMain.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_WIFI_SSID
|
||||
string "Wi-Fi SSID"
|
||||
default "eth2ap"
|
||||
help
|
||||
Set the SSID of Wi-Fi ap interface.
|
||||
|
||||
config EXAMPLE_WIFI_PASSWORD
|
||||
string "Wi-Fi Password"
|
||||
default "12345678"
|
||||
help
|
||||
Set the password of Wi-Fi ap interface.
|
||||
|
||||
config EXAMPLE_WIFI_CHANNEL
|
||||
int "WiFi channel"
|
||||
range 1 13
|
||||
default 1
|
||||
help
|
||||
Set the channel of Wi-Fi ap.
|
||||
|
||||
config EXAMPLE_MAX_STA_CONN
|
||||
int "Maximum STA connections"
|
||||
default 4
|
||||
help
|
||||
Maximum number of the station that allowed to connect to current Wi-Fi hotspot.
|
||||
|
||||
endmenu
|
||||
@@ -1,30 +0,0 @@
|
||||
#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 *startShow = /* <mqttPrefix>/ */ "elixirLights/startShow";
|
||||
// Publishes:
|
||||
const char *showDone = /* <mqttPrefix>/ */ "elixirLights/showDone";
|
||||
} MqttTopics;
|
||||
|
||||
struct {
|
||||
const char *expectedServer = "";
|
||||
struct {
|
||||
const char *group = "CatasWatchMovement";
|
||||
const char *startShow = "StartShow";
|
||||
} Provided;
|
||||
struct {
|
||||
const char *showDone = "ShowDone";
|
||||
} Expected;
|
||||
} SpitTypes;
|
||||
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
ethernet_init:
|
||||
path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init
|
||||
@@ -1,614 +0,0 @@
|
||||
/**
|
||||
* @author Gustice
|
||||
* @brief ChaosWatch Application
|
||||
*/
|
||||
|
||||
// using Elite2D-EXMU
|
||||
// Gledopto Series With Ethernet
|
||||
// { // 13
|
||||
// 1, // eth_address,
|
||||
// 5, // eth_power,
|
||||
// 23, // eth_mdc,
|
||||
// 33, // eth_mdio,
|
||||
// ETH_PHY_LAN8720, // eth_type,
|
||||
// ETH_CLOCK_GPIO0_IN // eth_clk_mode as input
|
||||
// },
|
||||
//
|
||||
// LED-Strips: 14 - 22 - 30
|
||||
// >> update http://172.16.16.10:8000/LeoLightShow.bin
|
||||
|
||||
#include "config.hpp"
|
||||
#include "lighsMain.hpp"
|
||||
|
||||
using namespace spit;
|
||||
using namespace std;
|
||||
|
||||
string ClientName = "LeoLightsDev";
|
||||
string ProjectName = "LeoLightsProj";
|
||||
gpio_num_t LedPin = gpio_num_t::GPIO_NUM_16;
|
||||
gpio_num_t RelayPin = gpio_num_t::GPIO_NUM_18;
|
||||
|
||||
extern "C" { // This switch allows the ROS C-implementation to find this main
|
||||
void app_main(void);
|
||||
}
|
||||
|
||||
struct DeviceState {
|
||||
Color color{0x80, 0x80, 0x40}; // Color for the chosen bottle
|
||||
vector<uint8_t> grouping; // LED groups for LED-Strip
|
||||
vector<uint8_t> times; // Step times for effects
|
||||
};
|
||||
struct MasterRequest {};
|
||||
struct SlaveResponse {};
|
||||
static fos::Queue<MasterRequest> commandQ(2);
|
||||
static fos::Queue<SlaveResponse> responseQ(2);
|
||||
|
||||
DeviceState State;
|
||||
static const char* TAG = "Light";
|
||||
static const char* VERSION = "V 0.7.0";
|
||||
unique_ptr<Cli> pShell;
|
||||
|
||||
void onCommand(string name, Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "Invoking: %s", name.c_str());
|
||||
}
|
||||
|
||||
void setLogServerConfig(Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "on showLogServerConfig:");
|
||||
auto& store = NvsApi::getInstance();
|
||||
if (args.size() != 1) {
|
||||
auto logger = store.getValue("syslogDst");
|
||||
pShell->writeLine(string{"syslog destination = '"} + logger + "'");
|
||||
pShell->writeLine("provide argument to change syslog server");
|
||||
return;
|
||||
}
|
||||
pShell->writeLine(string{"setting syslog destination to = '"} + args[0] + "'");
|
||||
store.setValue("syslogDst", args[0]);
|
||||
}
|
||||
|
||||
void testLights(Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "on testLights:");
|
||||
commandQ.enqueue(make_unique<MasterRequest>());
|
||||
}
|
||||
|
||||
void showProcessValues(Cli::CArgs args) {
|
||||
pShell->writeLine("Process values:");
|
||||
char buff[256];
|
||||
|
||||
sprintf(buff, "%02x,%02x,%02x", State.color.getRed(), State.color.getGreen(), State.color.getBlue());
|
||||
std::stringstream ssC;
|
||||
for (auto& c : State.grouping) {
|
||||
ssC << string{c} << ",";
|
||||
}
|
||||
std::stringstream ssT;
|
||||
for (auto& t : State.times) {
|
||||
ssT << string{t} << ",";
|
||||
}
|
||||
pShell->writeLine(string{" Color RGB: "} + buff);
|
||||
pShell->writeLine(string{" LED-Counts: "} + ssC.str());
|
||||
pShell->writeLine(string{" Switch-Times: "} + ssT.str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Telnet socket via TCP/IP
|
||||
*
|
||||
* @details The ini-file for TeraTerm only changes CRReceive and CRSend values both to "=CR"
|
||||
* @param arg ignored task argument
|
||||
*/
|
||||
static void telnetSocketTask(int addrFamily) {
|
||||
ESP_LOGI(TAG, "Starting Telnet task");
|
||||
try {
|
||||
TelnetServer telnet(addrFamily);
|
||||
telnet.run(
|
||||
[](TcpSession& session) {
|
||||
pShell = make_unique<Cli>(session, [](string n, Cli::CArgs a) { onCommand(n, a); });
|
||||
pShell->addBinding(
|
||||
{"setLogserver", "Set log server config ip",
|
||||
[](Cli::CArgs a) { setLogServerConfig(a); }});
|
||||
|
||||
Syslog::registerCli(*pShell);
|
||||
auto& store = NvsApi::getInstance();
|
||||
store.registerCli(*pShell);
|
||||
SystemFunctions::registerCli(*pShell);
|
||||
|
||||
pShell->addBinding(
|
||||
{"setDyn", "set dynamics of movement (velocity,accelerations) as floats",
|
||||
[](Cli::CArgs a) { testLights(a); }});
|
||||
pShell->addBinding(
|
||||
{"showData", "Show process values that are input by DMX, MQTT and SPIT",
|
||||
[](Cli::CArgs a) { showProcessValues(a); }});
|
||||
},
|
||||
[](TcpSession& session) {
|
||||
pShell->process();
|
||||
Syslog::setupTask(session.getOther());
|
||||
});
|
||||
} catch (const exception& e) {
|
||||
ESP_LOGE("TCP", "%s", e.what());
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void startShow(string data) {
|
||||
ESP_LOGI(TAG, "StartShuffle command %s", data.c_str());
|
||||
try {
|
||||
Syslog::logv(Syslog::Severity::Informational, "got Shuffle-Command");
|
||||
commandQ.enqueue(make_unique<MasterRequest>());
|
||||
} catch (const exception& e) {
|
||||
ESP_LOGE(TAG, "Error to process data %s, with ex: %s", data.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint32_t DmxUniverse = 0;
|
||||
constexpr int DmxChannelCount = 9;
|
||||
array<uint8_t, 512> LedData;
|
||||
|
||||
static void UniverseCallback(const uint8_t* data, const uint16_t size) {
|
||||
ESP_LOGD(TAG, "Got DMX");
|
||||
ESP_LOG_BUFFER_HEXDUMP("DMX", data, size, ESP_LOG_DEBUG);
|
||||
Syslog::logv(Syslog::Severity::Debug, "Got DMX: r%0x g%0x b%0x i%0x ...",
|
||||
/* RGB*/ data[0], data[1], data[2], /*Intens*/ data[3]);
|
||||
|
||||
// DMX 512
|
||||
for (int i = 0; i < LedData.size() / 4;) {
|
||||
LedData[i] = data[i];
|
||||
i++;
|
||||
LedData[i] = data[i];
|
||||
i++;
|
||||
LedData[i] = data[i];
|
||||
i++;
|
||||
LedData[i] = data[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DMX-Socket for ArtNet TCP/IP
|
||||
*
|
||||
* @details Tested with [Q Light Controller+](https://www.qlcplus.org/)
|
||||
* @param args ignored task argument
|
||||
*/
|
||||
static void dmxSocketTask(int addrFamily) {
|
||||
ESP_LOGI(TAG, "Starting ArtNet task");
|
||||
constexpr uint16_t ArtNetPort = arx::artnet::DEFAULT_PORT;
|
||||
IpAdr address = addrFamily == AF_INET ? IpAdr(INADDR_ANY, ArtNetPort) : IpAdr(ArtNetPort);
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
UdpSocket socket(address);
|
||||
socket.bindTo();
|
||||
|
||||
ArtnetReceiver artnet(socket);
|
||||
artnet.subscribe(DmxUniverse, UniverseCallback);
|
||||
artnet.parse();
|
||||
// parse artnet as long socket is active, then restart socket
|
||||
while (socket.isActive()) {
|
||||
ESP_LOGD(TAG, "Waiting for data");
|
||||
artnet.parse();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
ESP_LOGE("UDP", "%s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
fos::Semaphore etherActive;
|
||||
fos::Semaphore spitProjectFinish;
|
||||
|
||||
/** Event handler for IP_EVENT_ETH_GOT_IP */
|
||||
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, "~~~~~~~~~~~");
|
||||
etherActive.give();
|
||||
}
|
||||
|
||||
static void initialize_ethernet(void) {
|
||||
uint8_t eth_port_cnt = 0;
|
||||
esp_eth_handle_t* eth_handles;
|
||||
ESP_ERROR_CHECK(eth_init(ð_handles, ð_port_cnt));
|
||||
if (eth_port_cnt > 1) {
|
||||
ESP_LOGW(TAG, "multiple Ethernet devices detected, the first initialized is to be used!");
|
||||
}
|
||||
|
||||
static esp_eth_handle_t s_eth_handle = NULL;
|
||||
s_eth_handle = eth_handles[0];
|
||||
free(eth_handles);
|
||||
|
||||
// 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());
|
||||
|
||||
// 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(s_eth_handle)));
|
||||
|
||||
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));
|
||||
ESP_ERROR_CHECK(esp_eth_start(s_eth_handle));
|
||||
}
|
||||
|
||||
namespace Effect {
|
||||
extern const WaveForm_t OffsetPulseWave{gau8_offsetPulse, cu16_TemplateLength};
|
||||
extern const WaveForm_t InitSlopeWave{gau8_initSlope, cu16_TemplateLength};
|
||||
extern const WaveForm_t OffsetSlopeWave{gau8_offsetSlope, cu16_TemplateLength};
|
||||
extern const WaveForm_t FullSlopeWave{gau8_fullSlope, cu16_TemplateLength};
|
||||
extern const WaveForm_t FullPulseWave{gau8_fullPulse, cu16_TemplateLength};
|
||||
|
||||
const Macro macDemoStart = {
|
||||
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
|
||||
{32, 1, StateMachine::UpdateIdle, 0xFF},
|
||||
};
|
||||
|
||||
const Macro macDemoPulse = {
|
||||
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
|
||||
{32, 2, StateMachine::UpdateIdle, 0xFF},
|
||||
{64, 1, &OffsetPulseWave, StateMachine::UpdateWave, 0xFF},
|
||||
};
|
||||
|
||||
const Macro macDemoFlicker = {
|
||||
{16, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
|
||||
{32, 1, StateMachine::UpdateFlicker, 0xFF},
|
||||
};
|
||||
} // namespace Effect
|
||||
|
||||
void LightingTask() {
|
||||
ESP_LOGI(TAG, "Start Lighting");
|
||||
auto const& colorSource = State.color;
|
||||
|
||||
AddressableLeRtz strip(LedPin, AddressableLeRtz::Type::Rgb, LedData.size() / 4);
|
||||
OutputPort relay(RelayPin);
|
||||
relay.write(true);
|
||||
|
||||
while (true) {
|
||||
for (int i = 0; i < (LedData.size() / 4); i++) {
|
||||
auto* c = &LedData[i * 4];
|
||||
Color C{c[0], c[1], c[2], c[3]};
|
||||
strip.set(C, i, 1);
|
||||
}
|
||||
strip.send(); // takes ca. 5ms to send all the data
|
||||
fos::Task::delayMs(20);
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalSpitObj {
|
||||
string iD;
|
||||
string groupName;
|
||||
string name;
|
||||
};
|
||||
map<string, MasterRequest> ProvidedSpitActions;
|
||||
map<string, string> ExpectedObjects;
|
||||
|
||||
void onServerEvent(SClient::ServerEvent event, const SadDetectedServer& p_DetectedServer) {
|
||||
switch (event) {
|
||||
case SClient::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 SClient::ServerEvent::Lost:
|
||||
ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data());
|
||||
|
||||
break;
|
||||
case SClient::ServerEvent::Changed:
|
||||
ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onConnectionStatus(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime,
|
||||
SClient::Connection p_ConnectionStatus, SClient::Connection p_OldConnectionStatus) {
|
||||
ESP_LOGI(TAG, "MySPITApp: eventConnectionStatus %d->%d ", (int)p_OldConnectionStatus, (int)p_ConnectionStatus);
|
||||
}
|
||||
|
||||
// The transfer of the server's SPITTypes and SPITObjects is finished.
|
||||
void onProjectUpdate(SClient::ProjUpdate state, string projectId) {
|
||||
switch (state) {
|
||||
case SClient::ProjUpdate::ServerLoaded:
|
||||
ESP_LOGI(TAG, "eventProjectReport ID: %s ", projectId.data());
|
||||
break;
|
||||
case SClient::ProjUpdate::StartTransfer:
|
||||
ESP_LOGI(TAG, "eventStartProjectTransfer");
|
||||
break;
|
||||
case SClient::ProjUpdate::EndTransfer:
|
||||
ESP_LOGI(TAG, "eventEndProjectTransfer");
|
||||
spitProjectFinish.give();
|
||||
break;
|
||||
case SClient::ProjUpdate::ServerClosed:
|
||||
ESP_LOGI(TAG, "eventProjectClosed ID: %s", projectId.data());
|
||||
// If we don't save SPITServer's project specific information
|
||||
// perhaps close all SPITObjects and RemoteSPITObjects to avoid conflicts, when the SPITServer loads a new project
|
||||
// SPITObject::clearSPITObjects();
|
||||
// SPITObject::clearSPITObjectsRemote();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool onCheckSpitTypeVeto(bool knownType, bool createdByClient) {
|
||||
return true; // Bypass veto
|
||||
if (!knownType || !createdByClient) { // Don't allow foreign SPITTypes
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onCheckSpitObjectVeto(bool knownType) {
|
||||
return true; // Bypass veto
|
||||
if (!knownType) { // Don't allow objects of unregistered SPITTypes
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called when the server has created, loaded, changed or deleted a (Remote) SPITType.
|
||||
// Remote SPITType are used in Remote SPITObjects. A Remote SPITObject is used to remote control the SPITServer.
|
||||
// May also occur when the server confirms a SPITType created or changed by the client.
|
||||
void onSpitType(SClient::ObjectEvent event, bool isRemote, const SType& sType) {
|
||||
if (isRemote) {
|
||||
if (event == SClient::ObjectEvent::Created) {
|
||||
ESP_LOGI(TAG, "NEW SPIT-REMOTE-Type ID: %s GroupName: %s Name: %s confirmed: %d", sType.getID().data(), sType.GroupName.get().data(), sType.Name.get().data(), sType.getConfirmed());
|
||||
auto typeName = sType.Name.get();
|
||||
if (ExpectedObjects.contains(typeName)) {
|
||||
ExpectedObjects[typeName] = sType.getID();
|
||||
}
|
||||
} else if (event == SClient::ObjectEvent::Changed) {
|
||||
// we had to inform all Remote SPITObjects using the p_SPITType
|
||||
// perhaps the SPITObject uses information from the SPITType
|
||||
// SPITObject *ptrSPITObject;
|
||||
// int intSPITObjectCount;
|
||||
// intSPITObjectCount = SPITObject::getSPITObjectRemoteCount();
|
||||
// for (int intObject = 0; intObject < intSPITObjectCount; intObject++) {
|
||||
// ptrSPITObject = SPITObject::getSPITObjectRemote(intObject);
|
||||
// if (ptrSPITObject == nullptr)
|
||||
// continue;
|
||||
// if (ptrSPITObject->getSPITTypeID() == p_SPITType.getID()) {
|
||||
// // call ecentSPITObjectRemote
|
||||
// // onSpitObjectRemote(SClient::ObjectEvent::Changed, p_SPITType, *ptrSPITObject);
|
||||
// }
|
||||
// }
|
||||
// ESP_LOGI(TAG, "SPIT-REMOTE-Type CHANGED ID: %s GroupName: %s Name: %s confirmed: %d", sType.getID().data(), sType.GroupName.get().data(), sType.Name.get().data(), sType.getConfirmed());
|
||||
} else if (event == SClient::ObjectEvent::Deleted) {
|
||||
ESP_LOGD(TAG, "SPIT-REMOTE-Type Removed ID: %s GroupName: %s Name: %s\n", sType.getID().data(), sType.GroupName.get().data(), sType.Name.get().data());
|
||||
}
|
||||
} else {
|
||||
if (event == SClient::ObjectEvent::Created) {
|
||||
// Whenever you provide an action for this SPITType take this over in your code.
|
||||
// call _SpitClient.setActionSPITType(sType.getID(), true);
|
||||
// ESP_LOGI(TAG, "NEW SPIT-Type ID: %s GroupName: %s Name: %s confirmed: %d", sType.getID().data(), sType.GroupName.get().data(), sType.Name.get().data(), sType.getConfirmed());
|
||||
} else if (event == SClient::ObjectEvent::Changed) {
|
||||
// ESP_LOGI(TAG, "SPIT-Type CHANGED ID: %s GroupName: %s Name: %s confirmed: %d", sType.getID().data(), sType.GroupName.get().data(), sType.Name.get().data(), sType.getConfirmed());
|
||||
} else if (event == SClient::ObjectEvent::Deleted) {
|
||||
// ESP_LOGI(TAG, "SPIT-Type Removed ID: %s GroupName: %s Name: %s\n", sType.getID().data(), sType.GroupName.get().data(), sType.Name.get().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the server has created, loaded or changed a SPITObject.
|
||||
// A Remote SPITObject is used to remote control the SPITServer.
|
||||
// May also occur when the server confirms a SPITObject created by the client, what the client should never do!!.
|
||||
// false = server changed a existing SPITObject
|
||||
// @param p_SPITType a reference to a copy of the associated SPITType instance.
|
||||
// @param p_SPITObject a reference to a copy of the SPITObject instance.
|
||||
void onSpitObject(SClient::ObjectEvent event, bool isRemote, const SType& sType, const SObject& sObject) {
|
||||
if (isRemote) {
|
||||
if (event == SClient::ObjectEvent::Created) {
|
||||
// ESP_LOGI(TAG, "NEW SPIT-REMOTE-Object ID: %s Name: %s -> SPITType: %s", sObject.getID().data(), sObject.Name.get().data(), sType.Name.get().data());
|
||||
// This is a remote SPITObject which can be used to remote control the server.
|
||||
// If you want you can list this for later use
|
||||
} else if (event == SClient::ObjectEvent::Changed) {
|
||||
// ESP_LOGI(TAG, "SPIT-REMOTE-Object CHANGED ID: %s Name: %s -> SPITType: %s", sObject.getID().data(), sObject.Name.get().data(), sType.Name.get().data());
|
||||
} else if (event == SClient::ObjectEvent::Deleted) {
|
||||
ESP_LOGD(TAG, "SPIT-REMOTE-Object Removed ID: %s Name: %s\n", sObject.getID().data(), sObject.Name.get().data());
|
||||
// This is a remote SPITObject
|
||||
// If you have listet this prior you should remove it from the list
|
||||
}
|
||||
} else {
|
||||
if (event == SClient::ObjectEvent::Created) {
|
||||
// ESP_LOGI(TAG, "NEW SPIT-Object ID: %s Name: %s -> SPITType: %s", sObject.getID().data(), sObject.Name.get().data(), sType.Name.get().data());
|
||||
// check your actions
|
||||
// Whenever you provide an action for this SPITObject take this over in your code.
|
||||
// call _SpitClient.setActionSPITObject(sObject.getID(), true);
|
||||
|
||||
// for our little excample as described in loadClientProject:
|
||||
// We have only actions for SPITTypes - means every SPITObject with the associated "Actionx"-SPITTypes will trigger the action when it is played
|
||||
//-> no need to do something here, because setActionSPITType has been set prior and the SPITObject will automatically inherits this
|
||||
// SPITObjects with other SPITTypes asscciated will trigger no actions
|
||||
|
||||
} else if (event == SClient::ObjectEvent::Changed) {
|
||||
// ESP_LOGI(TAG, "SPIT-Object CHANGED ID: %s Name: %s -> SPITType: %s", sObject.getID().data(), sObject.Name.get().data(), sType.Name.get().data());
|
||||
} else if (event == SClient::ObjectEvent::Deleted) {
|
||||
ESP_LOGD(TAG, "SPIT-Object Removed ID: %s Name: %s\n", sObject.getID().data(), sObject.Name.get().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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SPITServer may use several methods for playing SPITObjects.
|
||||
// e.g. liveSHOWsoftware has the timeline and jingles which plays objects, where the timeline the main player is.
|
||||
// SPIT distinguishes between the different players. All eventPlay... functions contain the information which player plays the SPIT object.
|
||||
void onPlay(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, uint64_t p_TimeFrames) {
|
||||
ESP_LOGD(TAG, "eventPlay Player: %s Runs: %d Time: %lld", p_PlayerName.data(), p_PlayerIsRunning, p_TimeFrames);
|
||||
|
||||
switch (p_PlayerType) {
|
||||
case SClient::PlayerType::PTYPE_MAIN:
|
||||
// p_FrameTimes contains the position inside the server's project, we can use it like a timecode
|
||||
// int intMilliseconds = (int)(((double)p_TimeFrames / (double)m_ServerFramesPerSecond) * 1000);
|
||||
break;
|
||||
case SClient::PlayerType::PTYPE_CONTINOUS:
|
||||
// The olayer is playing only single Object sequences sometime during the project
|
||||
break;
|
||||
case SClient::PlayerType::PTYPE_DISCRETE:
|
||||
// Only discrete values where submitted, e.g the fader position of remote faders.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onPlaySpitType(string p_PlayerID, string spitTypeId, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value) {
|
||||
// double doubleValue = ((double)p_PlayObject.getValue() / 1000000) * ((double)p_PlayObject.getValueFactor() / 1000000);
|
||||
ESP_LOGD(TAG, "eventPlayObject Player: %s is running: %d Object Started: %d Stopped: %d", p_PlayerID.data(), p_PlayerIsRunning, p_Started, p_Ended);
|
||||
// ESP_LOGD(TAG, " SPITType: %s SPITObject: %s Position: %lld Value: %f\n", spitTypeId.data(), p_SPITObject.getName().data(), p_PlayObject.getFrameInside(), doubleValue);
|
||||
ESP_LOGD(TAG, " SPITType: %s Value: %f\n", spitTypeId.data(), p_Value);
|
||||
|
||||
if (!ProvidedSpitActions.contains(spitTypeId)) {
|
||||
ESP_LOGE(TAG, "SPIT ID %s is not accepted", spitTypeId.c_str());
|
||||
return;
|
||||
}
|
||||
if (p_Started == true) {
|
||||
auto command = ProvidedSpitActions[spitTypeId];
|
||||
// ESP_LOGI(TAG, "Player: %s is running: %s Object", p_PlayerID.data(), spitTypeId.c_str());
|
||||
commandQ.enqueue(make_unique<MasterRequest>());
|
||||
Syslog::logv(Syslog::Severity::Informational, "Got SPIT command");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a remote SpitObject which value function is changed by the server.
|
||||
* This allows the Client to adjust its display for the remote command.
|
||||
* @param p_SPITType the assigned remote SPITType of p_SPITObject
|
||||
* @param p_SPITObject the remote SPITObject which is changed
|
||||
* @param p_FrameInsideObject can be discarded
|
||||
* @param p_Value the new value
|
||||
*/
|
||||
void onPlayRemoteObjectStatus(const SType& sType, const SObject& sObject, uint64_t frameInsideObject, int value) {
|
||||
ESP_EARLY_LOGD(TAG, "eventPlayRemoteObjectStatus RemoteSPITType: %s RemoteSPITObject: %s Position: %lld Value: %d", sType.Name.get().data(), sObject.Name.get().data(), frameInsideObject, value);
|
||||
}
|
||||
|
||||
void SpitClientApp() {
|
||||
ESP_LOGI(TAG, "Starting SPIT task");
|
||||
|
||||
auto& provided = SpitTypes.Provided;
|
||||
auto& expected = SpitTypes.Expected;
|
||||
|
||||
vector<LocalSpitObj> ProvidedObj;
|
||||
ProvidedSpitActions[provided.group] = MasterRequest{};
|
||||
ProvidedObj.push_back(LocalSpitObj{.iD = provided.group, .groupName = provided.group, .name = provided.group});
|
||||
ProvidedSpitActions[provided.startShow] = MasterRequest{};
|
||||
ProvidedObj.push_back(LocalSpitObj{.iD = provided.startShow, .groupName = provided.group, .name = provided.startShow});
|
||||
|
||||
ExpectedObjects[expected.showDone] = "";
|
||||
|
||||
auto ip = spit::Socket::getAdaptersInfo();
|
||||
spit::Socket socket(ip);
|
||||
SClient spitClient(ClientName, ProjectName, socket,
|
||||
{
|
||||
.onServerEvent = onServerEvent,
|
||||
.onConnectionStatus = onConnectionStatus,
|
||||
.onProjectUpdate = onProjectUpdate,
|
||||
.onSpitType = onSpitType,
|
||||
.onSpitObject = onSpitObject,
|
||||
.onPlay = onPlay,
|
||||
.onPlaySpitType = onPlaySpitType,
|
||||
.onPlayRemoteObjectStatus = onPlayRemoteObjectStatus,
|
||||
.onCheckSpitTypeVeto = onCheckSpitTypeVeto,
|
||||
.onCheckSpitObjectVeto = onCheckSpitObjectVeto,
|
||||
});
|
||||
|
||||
for (auto& obj : ProvidedObj) {
|
||||
SType* ptrSPITType1Fix = spitClient.createTypeFixed(obj.iD, obj.groupName, obj.name, 0, 0);
|
||||
spitClient.setActionType(ptrSPITType1Fix->getID(), true); // should be executed whenever a SPITObject with this SPITType is played
|
||||
}
|
||||
spitClient.clientProjectLoaded();
|
||||
spitClient.startServerAutoDetect();
|
||||
|
||||
spitProjectFinish.take();
|
||||
string serverProjectID = spitClient.getServerProjectID();
|
||||
string serverProjectName = spitClient.getClientProjectName();
|
||||
int serverFramesPerSecond = spitClient.getServerFramesPerSecond(); // set when the server reports his project, see eventProjectReport
|
||||
ESP_LOGI(TAG, "eventProjectReport ID: %s Name: %s FramesPerSecond: %d", serverProjectID.data(), serverProjectName.data(), serverFramesPerSecond);
|
||||
|
||||
for (auto&& obj : ExpectedObjects) {
|
||||
if (obj.second == "") {
|
||||
ESP_LOGE(TAG, "No matching Remote ID for %s", obj.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto res = responseQ.dequeue();
|
||||
spitClient.sendRemoteObject(ExpectedObjects[expected.showDone]);
|
||||
}
|
||||
}
|
||||
|
||||
void MqttThread() {
|
||||
ESP_LOGI(TAG, "Starting MQTT task");
|
||||
|
||||
auto& store = NvsApi::getInstance();
|
||||
auto broker = store.getValue(ConfigKeys.mqttBroker);
|
||||
if (broker != "") {
|
||||
ESP_LOGI(TAG, "Initializing MQTT");
|
||||
auto prefix = store.getValue(ConfigKeys.mqttPrefix);
|
||||
auto& client = MqttClient::init(broker, prefix);
|
||||
if (!client.isRunning()) {
|
||||
client.addSubscription(MqttTopics.startShow, [](string d) {
|
||||
commandQ.enqueue(make_unique<MasterRequest>());
|
||||
});
|
||||
client.start();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto res = responseQ.dequeue();
|
||||
client.publish(MqttTopics.showDone, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
initialize_ethernet();
|
||||
NvsApi::init();
|
||||
static fos::Task lightingTask(LightingTask, "Lights", 0x8000uL);
|
||||
|
||||
etherActive.take();
|
||||
ESP_LOGI(TAG, "Start net services");
|
||||
|
||||
static int ipVersion = AF_INET;
|
||||
static fos::TaskT<int> telnetSocket(telnetSocketTask, ipVersion, "tcpServer", 4096);
|
||||
// static fos::Task spit(SpitClientApp, "SpitClient");
|
||||
// static fos::Task mqtt(MqttThread, "MqttEndpoint");
|
||||
static fos::TaskT<int> dmxNode(dmxSocketTask, ipVersion, "dmxNode", 4096);
|
||||
|
||||
auto& store = NvsApi::getInstance();
|
||||
auto logger = store.getValue(ConfigKeys.syslogDest);
|
||||
if (logger != "") {
|
||||
Syslog::setupTask(IpAdr{logger, 0});
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Configuration");
|
||||
ESP_LOGI(TAG, "%s: %s", ConfigKeys.syslogDest, store.getValue(ConfigKeys.syslogDest).c_str());
|
||||
// ESP_LOGI(TAG, "%s: %s", ConfigKeys.mqttBroker, store.getValue(ConfigKeys.mqttBroker).c_str());
|
||||
// ESP_LOGI(TAG, "%s: %s", ConfigKeys.mqttPrefix, store.getValue(ConfigKeys.mqttPrefix).c_str());
|
||||
// ESP_LOGI(TAG, "%s: %s", ConfigKeys.spitServer, store.getValue(ConfigKeys.spitServer).c_str());
|
||||
|
||||
ESP_LOGI(TAG, "## Starting : %s : %s",
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME, VERSION);
|
||||
|
||||
while (true) {
|
||||
fos::Task::delayMs(5000);
|
||||
Syslog::logv(Syslog::Severity::Notice, "Min heap size: %u / FreeHeap %lu",
|
||||
heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT),
|
||||
esp_get_free_heap_size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,992 @@
|
||||
/**
|
||||
* @file watchMain.cpp
|
||||
* @author Gustice
|
||||
* @brief ChaosWatch Application
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
/* Watchface
|
||||
6/
|
||||
5 / 1
|
||||
4 2
|
||||
3
|
||||
*/
|
||||
|
||||
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"
|
||||
} 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;
|
||||
|
||||
// ToDo:
|
||||
// - MQTT Integration
|
||||
// - OTA
|
||||
// - Syslog heartbeat
|
||||
// - Streamlined DMX
|
||||
// -
|
||||
|
||||
#include "watchMain.hpp"
|
||||
|
||||
string ClientName = "CatasWatchDev";
|
||||
string ProjectName = "CatastrphicProj";
|
||||
|
||||
extern "C" { // This switch allows the ROS C-implementation to find this main
|
||||
void app_main(void);
|
||||
}
|
||||
|
||||
struct DeviceState {
|
||||
uint8_t minJumps{6};
|
||||
uint8_t maxJumps{32};
|
||||
uint8_t profile{};
|
||||
uint8_t shuffleRate{};
|
||||
float speed = 1.0; // Rad/sec
|
||||
float accel = 1.0; // Rad/sec^2
|
||||
Color color{0x80, 0x80, 0x80};
|
||||
};
|
||||
|
||||
enum class MoveType {
|
||||
StepTo,
|
||||
Demo,
|
||||
Shuffle,
|
||||
};
|
||||
enum class ResponseType {
|
||||
StepAt,
|
||||
StartMoving,
|
||||
};
|
||||
struct MoveCommand {
|
||||
MoveType type;
|
||||
// 1..6
|
||||
uint8_t pos;
|
||||
};
|
||||
struct WatchIndex {
|
||||
ResponseType type;
|
||||
// 1..6
|
||||
uint8_t pos;
|
||||
};
|
||||
struct PictoIllumCommand {
|
||||
uint8_t pos; // 0 for none / Valid indexes 1 .. 6
|
||||
};
|
||||
|
||||
static fos::Queue<MoveCommand> commandQueue(8);
|
||||
static fos::Queue<WatchIndex> responseQueue(8);
|
||||
static fos::Queue<PictoIllumCommand> pictoIllumQue(2);
|
||||
|
||||
DeviceState activeState;
|
||||
static const char *TAG = "Watch";
|
||||
static bool EthernetIsConnected = false;
|
||||
|
||||
std::unique_ptr<Cli> pShell;
|
||||
|
||||
void onCommand(std::string name, Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "Invoking: %s", name.c_str());
|
||||
}
|
||||
|
||||
void startUpdate(Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "Invoking Update");
|
||||
if (args.size() != 1) {
|
||||
pShell->write("Need URL to application'\n");
|
||||
return;
|
||||
}
|
||||
// @ToDo: Start Update here
|
||||
}
|
||||
|
||||
void getConfig(Cli::CArgs args) {
|
||||
if (args.size() != 1) {
|
||||
pShell->write("Needs string key for query'\n");
|
||||
return;
|
||||
}
|
||||
auto key = args[0];
|
||||
auto &store = NvsApi::getInstance();
|
||||
auto val = store.getValue(key);
|
||||
pShell->write(key + ": " + val + "\n");
|
||||
}
|
||||
|
||||
void testPictoIllum(Cli::CArgs args) {
|
||||
if (args.size() != 1) {
|
||||
pShell->write("Needs position argument for illuminated position 0 for off, 1..6 for pictograms'\n");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
int p = std::stoi(args[0]);
|
||||
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(p));
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGI(TAG, "Failed to parse %s and %s", args[0].c_str(), args[1].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void testMovement(Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "on triggerMovement:");
|
||||
if (args.size() != 1) {
|
||||
pShell->write("need target position (1..6)'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int p = std::stoi(args[0]);
|
||||
activeState.profile = p;
|
||||
commandQueue.enqueue(std::make_unique<MoveCommand>(MoveType::StepTo, p));
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGI(TAG, "Failed to parse %s and %s", args[0].c_str(), args[1].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void setConfig(Cli::CArgs args) {
|
||||
if (args.size() != 2) {
|
||||
pShell->write("Needs string key and value'\n");
|
||||
return;
|
||||
}
|
||||
auto key = args[0];
|
||||
auto val = args[1];
|
||||
|
||||
auto &store = NvsApi::getInstance();
|
||||
pShell->write(std::string{"Storing value = '"} + val + "'\n");
|
||||
store.setValue(key, val);
|
||||
}
|
||||
|
||||
void setLogServerConfig(Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "on showLogServerConfig:");
|
||||
auto &store = NvsApi::getInstance();
|
||||
if (args.size() != 1) {
|
||||
auto logger = store.getValue("syslogDst");
|
||||
pShell->write(std::string{"syslog destination = '"} + logger + "'\n");
|
||||
pShell->write("provide argument to change syslog server'\n");
|
||||
return;
|
||||
}
|
||||
pShell->write(std::string{"setting syslog destination to = '"} + args[0] + "'\n");
|
||||
store.setValue("syslogDst", args[0]);
|
||||
}
|
||||
|
||||
void setDynamics(Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "on setDynamics:");
|
||||
if (args.size() != 2) {
|
||||
pShell->write("need float values for velocity and acceleration'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
float v = std::stof(args[0]);
|
||||
float a = std::stof(args[1]);
|
||||
activeState.accel = a;
|
||||
activeState.speed = v;
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGI(TAG, "Failed to parse %s and %s", args[0].c_str(), args[1].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void startDemoMovement(Cli::CArgs args) {
|
||||
ESP_LOGI(TAG, "on startDemoMovement:");
|
||||
commandQueue.enqueue(std::make_unique<MoveCommand>(MoveType::Demo));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Telnet socket via TCP/IP
|
||||
*
|
||||
* @details The ini-file for TeraTerm only changes CRReceive and CRSend values both to "=CR"
|
||||
* @param arg ignored task argument
|
||||
*/
|
||||
static void telnetSocketTask(int addrFamily) {
|
||||
ESP_LOGI(TAG, "Starting Telnet task");
|
||||
try {
|
||||
TelnetServer telnet(addrFamily);
|
||||
telnet.run(
|
||||
[](TcpSession &session) {
|
||||
pShell = std::make_unique<Cli>(session, [](std::string n, Cli::CArgs a) { onCommand(n, a); });
|
||||
pShell->addBinding(
|
||||
{"update", "Start OTA-Update-Process",
|
||||
[](Cli::CArgs a) { startUpdate(a); }});
|
||||
pShell->addBinding(
|
||||
{"logserver_set", "Set log server config ip",
|
||||
[](Cli::CArgs a) { setLogServerConfig(a); }});
|
||||
|
||||
pShell->addBinding(
|
||||
{"getcfg", "Get configuration value for key",
|
||||
[](Cli::CArgs a) { getConfig(a); }});
|
||||
pShell->addBinding(
|
||||
{"setcfg", "Set configuration value by key and value",
|
||||
[](Cli::CArgs a) { setConfig(a); }});
|
||||
|
||||
pShell->addBinding(
|
||||
{"dyn_set", "set dynamics of movement (velocity,accelerations) as floats",
|
||||
[](Cli::CArgs a) { setDynamics(a); }});
|
||||
pShell->addBinding(
|
||||
{"tstMove", "start movement (profile-idx,steps) as integers ",
|
||||
[](Cli::CArgs a) { testMovement(a); }});
|
||||
|
||||
pShell->addBinding(
|
||||
{"tstIllum", "test illumination command 0=off /1..6",
|
||||
[](Cli::CArgs a) { testPictoIllum(a); }});
|
||||
},
|
||||
[](TcpSession &session) {
|
||||
pShell->process();
|
||||
Syslog::setupTask(session.getOther());
|
||||
});
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE("TCP", "%s", e.what());
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
constexpr uint32_t DmxUniverse = 0;
|
||||
constexpr int DmxChannelCount = 9;
|
||||
|
||||
uint8_t scaledRgbChannel(uint8_t value, float scale) {
|
||||
return static_cast<uint8_t>(value * scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback for ArtNet DMX-socket. Does not send data only updates the image
|
||||
*
|
||||
* @param data Pointer to dmx-values
|
||||
* @param size length of dmx-values
|
||||
*/
|
||||
static void UniverseCallback(const uint8_t *data, const uint16_t size) {
|
||||
int len = std::min(static_cast<int>(size), DmxChannelCount);
|
||||
ESP_LOGD(TAG, "Got DMX");
|
||||
ESP_LOG_BUFFER_HEXDUMP("DMX", data, len, ESP_LOG_DEBUG);
|
||||
Syslog::logv(Syslog::Severity::Debug, "Got DMX: r%0x g%0x b%0x i%0x m%i M%i p%i a%i w%i r%i",
|
||||
/* RGB*/ data[0], data[1], data[2], /*Intens*/ data[3],
|
||||
/* MinMaxJumps */ data[4], data[5], /*profile*/ data[6], /*accel/speed*/ data[7], data[8],
|
||||
/*shuffleRate*/ data[9]);
|
||||
|
||||
float intens = (float)data[3] / UINT8_MAX;
|
||||
activeState.color = Color{
|
||||
scaledRgbChannel(data[0], intens),
|
||||
scaledRgbChannel(data[1], intens),
|
||||
scaledRgbChannel(data[2], intens),
|
||||
0};
|
||||
|
||||
activeState.minJumps = data[4];
|
||||
activeState.maxJumps = data[5];
|
||||
activeState.profile = data[6];
|
||||
|
||||
uint8_t accel = data[7];
|
||||
uint8_t velo = data[8];
|
||||
activeState.accel = (float)accel / 100 + 0.5; // min .5 / max 3
|
||||
activeState.speed = (float)velo / 100 + 0.5; // min .5 / max 3
|
||||
|
||||
activeState.shuffleRate = data[9];
|
||||
}
|
||||
|
||||
void moveToSubs(std::string data) {
|
||||
ESP_LOGI(TAG, "MoveTo command '%s'", data.c_str());
|
||||
try {
|
||||
int p = std::stoi(data);
|
||||
Syslog::logv(Syslog::Severity::Informational, "got MoveTo-Cmd->%i", p);
|
||||
commandQueue.enqueue(std::make_unique<MoveCommand>(MoveType::StepTo, p));
|
||||
auto &client = MqttClient::getInstance();
|
||||
client.publish(MqttTopics.inPosition, data + "Picto");
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Error to process data %s, with ex: %s", data.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void startShuffle(std::string data) {
|
||||
ESP_LOGI(TAG, "StartShuffle command %s", data.c_str());
|
||||
|
||||
try {
|
||||
Syslog::logv(Syslog::Severity::Informational, "got Shuffle-Command");
|
||||
commandQueue.enqueue(std::make_unique<MoveCommand>(MoveType::Shuffle, 0));
|
||||
auto &client = MqttClient::getInstance();
|
||||
client.publish(MqttTopics.changingPosition, "....");
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Error to process data %s, with ex: %s", data.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DMX-Socket for ArtNet TCP/IP
|
||||
*
|
||||
* @details Tested with [Q Light Controller+](https://www.qlcplus.org/)
|
||||
* @param args ignored task argument
|
||||
*/
|
||||
static void dmxSocketSenderTask(UdpSocket &socket) {
|
||||
try {
|
||||
ArtnetSender artnet(socket);
|
||||
std::array<uint8_t, 16> data;
|
||||
while (socket.isActive()) {
|
||||
data[0]++;
|
||||
artnet.send("", 0, data.data(), data.size());
|
||||
fos::Task::delayMs(500);
|
||||
}
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE("UDP", "%s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DMX-Socket for ArtNet TCP/IP
|
||||
*
|
||||
* @details Tested with [Q Light Controller+](https://www.qlcplus.org/)
|
||||
* @param args ignored task argument
|
||||
*/
|
||||
static void dmxSocketTask(int addrFamily) {
|
||||
|
||||
ESP_LOGI(TAG, "Starting ArtNet task");
|
||||
constexpr uint16_t ArtNetPort = arx::artnet::DEFAULT_PORT;
|
||||
IpAdr address = addrFamily == AF_INET ? IpAdr(INADDR_ANY, ArtNetPort) : IpAdr(ArtNetPort);
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
UdpSocket socket(address);
|
||||
socket.bindTo();
|
||||
|
||||
ArtnetReceiver artnet(socket);
|
||||
artnet.subscribe(DmxUniverse, UniverseCallback);
|
||||
artnet.parse();
|
||||
// parse artnet as long socket is active, then restart socket
|
||||
while (socket.isActive()) {
|
||||
ESP_LOGD(TAG, "Waiting for data");
|
||||
artnet.parse();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE("UDP", "%s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
fos::Semaphore etherActive;
|
||||
fos::Semaphore spitProjectFinish;
|
||||
|
||||
/** Event handler for IP_EVENT_ETH_GOT_IP */
|
||||
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
|
||||
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, "~~~~~~~~~~~");
|
||||
etherActive.give();
|
||||
}
|
||||
|
||||
// Event handler for Ethernet
|
||||
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};
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Up");
|
||||
EthernetIsConnected = true;
|
||||
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");
|
||||
EthernetIsConnected = false;
|
||||
break;
|
||||
case ETHERNET_EVENT_START:
|
||||
ESP_LOGI(TAG, "Ethernet Started");
|
||||
break;
|
||||
case ETHERNET_EVENT_STOP:
|
||||
ESP_LOGI(TAG, "Ethernet Stopped");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize_ethernet(void) {
|
||||
uint8_t eth_port_cnt = 0;
|
||||
esp_eth_handle_t *eth_handles;
|
||||
ESP_ERROR_CHECK(example_eth_init(ð_handles, ð_port_cnt));
|
||||
if (eth_port_cnt > 1) {
|
||||
ESP_LOGW(TAG, "multiple Ethernet devices detected, the first initialized is to be used!");
|
||||
}
|
||||
|
||||
static esp_eth_handle_t s_eth_handle = NULL;
|
||||
s_eth_handle = eth_handles[0];
|
||||
free(eth_handles);
|
||||
|
||||
// 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());
|
||||
|
||||
// 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(s_eth_handle)));
|
||||
|
||||
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));
|
||||
ESP_ERROR_CHECK(esp_eth_start(s_eth_handle));
|
||||
}
|
||||
|
||||
namespace Effect {
|
||||
extern const WaveForm_t OffsetPulseWave{gau8_offsetPulse, cu16_TemplateLength};
|
||||
extern const WaveForm_t InitSlopeWave{gau8_initSlope, cu16_TemplateLength};
|
||||
extern const WaveForm_t OffsetSlopeWave{gau8_offsetSlope, cu16_TemplateLength};
|
||||
extern const WaveForm_t FullSlopeWave{gau8_fullSlope, cu16_TemplateLength};
|
||||
extern const WaveForm_t FullPulseWave{gau8_fullPulse, cu16_TemplateLength};
|
||||
|
||||
const Macro macDemoStart = {
|
||||
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
|
||||
{32, 1, StateMachine::UpdateIdle, 0xFF},
|
||||
};
|
||||
|
||||
const Macro macDemoPulse = {
|
||||
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
|
||||
{32, 2, StateMachine::UpdateIdle, 0xFF},
|
||||
{64, 1, &OffsetPulseWave, StateMachine::UpdateWave, 0xFF},
|
||||
};
|
||||
|
||||
const Macro macDemoFlicker = {
|
||||
{16, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
|
||||
{32, 1, StateMachine::UpdateFlicker, 0xFF},
|
||||
};
|
||||
}
|
||||
|
||||
void LightingTask() {
|
||||
ESP_LOGI(TAG, "Start Lighting");
|
||||
|
||||
static I2cMaster master(I2C_NUM_0,
|
||||
{ /*sda=*/GPIO_NUM_10, /*scl=*/GPIO_NUM_11}
|
||||
);
|
||||
// static PmwExpanderPca9685 pca9685(master);
|
||||
static PmwExpanderPca9685 ledDriver1(master, /*iverted=*/false);
|
||||
static PmwExpanderPca9685 ledDriver2(master, /*iverted=*/false, 0x41);
|
||||
PmwExpanderPca9685::GrayValues values[2]{};
|
||||
|
||||
OutputPort pwmEnable(GPIO_NUM_1, GpioPort::Logic::Inverted);
|
||||
pwmEnable.write(true);
|
||||
|
||||
auto const &colorSource = activeState.color;
|
||||
std::array<Effect::EffectProcessor, 6> processors{
|
||||
Effect::EffectProcessor(8),
|
||||
Effect::EffectProcessor(8),
|
||||
Effect::EffectProcessor(8),
|
||||
Effect::EffectProcessor(8),
|
||||
Effect::EffectProcessor(8),
|
||||
Effect::EffectProcessor(8)};
|
||||
processors[0].setEffect(Effect::macDark, &colorSource, 0);
|
||||
processors[1].setEffect(Effect::macDark, &colorSource, 0);
|
||||
processors[2].setEffect(Effect::macDark, &colorSource, 0);
|
||||
processors[3].setEffect(Effect::macDark, &colorSource, 0);
|
||||
processors[4].setEffect(Effect::macDark, &colorSource, 0);
|
||||
processors[5].setEffect(Effect::macDark, &colorSource, 0);
|
||||
|
||||
const std::array<Effect::Macro, 6> PictoEffects{
|
||||
Effect::macDemoPulse, // 1
|
||||
Effect::macDemoPulse,
|
||||
Effect::macDemoPulse,
|
||||
Effect::macDemoPulse,
|
||||
Effect::macStartFlicker,
|
||||
Effect::macDemoPulse}; // 6
|
||||
|
||||
uint8_t lastPicto = 1;
|
||||
|
||||
std::array<uint16_t *, 6> startPoints{
|
||||
&(values[0][4]), // 1
|
||||
&(values[1][12]),
|
||||
&(values[1][8]),
|
||||
&(values[1][4]),
|
||||
&(values[0][12]),
|
||||
&(values[0][8]), // 6
|
||||
};
|
||||
|
||||
while (true) {
|
||||
auto onPos = pictoIllumQue.dequeue(0);
|
||||
if (onPos) {
|
||||
ESP_LOGI(TAG, "Changing picto-Illum to pos = %i", onPos->pos);
|
||||
ESP_LOGI(TAG, "Current color set r%i g%i b%i ",
|
||||
activeState.color.getRed(), activeState.color.getGreen(), activeState.color.getBlue());
|
||||
auto pos = onPos->pos;
|
||||
if (pos == 0) {
|
||||
Syslog::logv(Syslog::Severity::Informational,
|
||||
"Dimming picto-illum pos:%i ", lastPicto);
|
||||
processors[lastPicto - 1].setEffect(Effect::macDark, &colorSource, 0);
|
||||
} else if ((pos >= 1) && (pos <= 6)) {
|
||||
auto idx = pos - 1;
|
||||
Syslog::logv(Syslog::Severity::Informational,
|
||||
"Firing picto-illum pos:%i ", pos);
|
||||
processors[idx].setEffect(PictoEffects[idx], &colorSource, 0);
|
||||
lastPicto = pos;
|
||||
} else {
|
||||
Syslog::logv(Syslog::Severity::Error,
|
||||
"Got invalid index for illuminated pictogram =%i ", pos);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < processors.size(); i++) {
|
||||
auto col = processors[i].tick();
|
||||
auto sp = startPoints[i];
|
||||
sp[0] = (uint16_t)(col.getWhite()) << 7;
|
||||
sp[1] = (uint16_t)(col.getBlue()) << 7;
|
||||
sp[2] = (uint16_t)(col.getGreen()) << 7;
|
||||
sp[3] = (uint16_t)(col.getRed()) << 7;
|
||||
}
|
||||
|
||||
ledDriver1.send(values[0]);
|
||||
ledDriver2.send(values[1]);
|
||||
fos::Task::delayMs(40);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementTask() {
|
||||
ESP_LOGI(TAG, "Start Stepper");
|
||||
constexpr int MicroSteps = 32;
|
||||
StepperDriverDrv8833::Pins stepperPins{
|
||||
LEDC_TIMER_0,
|
||||
{LEDC_CHANNEL_0, LEDC_CHANNEL_1, LEDC_CHANNEL_2, LEDC_CHANNEL_3},
|
||||
{GPIO_NUM_21, GPIO_NUM_20, GPIO_NUM_23, GPIO_NUM_22},
|
||||
};
|
||||
StepperDriverDrv8833 stepperDriver(stepperPins, MicroSteps, 0.25F);
|
||||
stepperDriver.setPos(0);
|
||||
|
||||
StepperConfig stepperCfg{1.8F, MicroSteps};
|
||||
InputPort initSens(GPIO_NUM_18);
|
||||
|
||||
InputPort motorFault(GPIO_NUM_8);
|
||||
motorFault.setLogic(GpioPort::Logic::Inverted);
|
||||
|
||||
OutputPort motorSleep(GPIO_NUM_15, GpioPort::Logic::Inverted);
|
||||
motorSleep.write(false);
|
||||
|
||||
StepperMotor stepper(stepperCfg, stepperDriver, initSens);
|
||||
|
||||
WatchMotor watch(stepper, [](uint8_t newPos) {
|
||||
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(newPos));
|
||||
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StepAt, newPos));
|
||||
});
|
||||
|
||||
ESP_LOGI("Stepper", "Find Home");
|
||||
stepper.findRef();
|
||||
// Todo Set by User-Interface
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
stepper.fullStep(1);
|
||||
fos::Task::delayMs(40);
|
||||
}
|
||||
(void)stepper.zeroPosition();
|
||||
while (!stepper.isIdle()) {
|
||||
fos::Task::delayMs(40);
|
||||
}
|
||||
// watch.moveTo(1, ProfileGenerator::Unitform);
|
||||
ESP_LOGI("Stepper", "Got to 1");
|
||||
// Illum 6
|
||||
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(0));
|
||||
|
||||
ESP_LOGI(TAG, "Fist Position is %.2f", watch.getScaled());
|
||||
fos::Task::delayMs(1000);
|
||||
|
||||
while (true) {
|
||||
ESP_LOGD(TAG, "Waiting for command");
|
||||
auto cmd = commandQueue.dequeue();
|
||||
if (cmd->type == MoveType::StepTo) {
|
||||
if (stepper.isIdle()) {
|
||||
int newPos = cmd->pos;
|
||||
if ((newPos >= 1) && (newPos <= 6)) {
|
||||
Syslog::logv(Syslog::Severity::Informational,
|
||||
"Triggered movement to picto pos:%i ", newPos);
|
||||
} else {
|
||||
Syslog::logv(Syslog::Severity::Error,
|
||||
"Got invalid index for illuminated pictogram =%i ", newPos);
|
||||
continue;
|
||||
}
|
||||
|
||||
Syslog::logv(Syslog::Severity::Notice,
|
||||
"Running Stepper by min%i steps with prof=%i a=%.2f w=%.2f",
|
||||
activeState.minJumps, activeState.profile, activeState.accel, activeState.speed);
|
||||
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(0));
|
||||
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StartMoving, 0));
|
||||
auto &as = activeState;
|
||||
watch.moveTo(newPos, as.profile, as.minJumps, as.accel, as.speed);
|
||||
// pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(newPos));
|
||||
// responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StepAt, newPos));
|
||||
}
|
||||
} else if (cmd->type == MoveType::Demo) {
|
||||
ESP_LOGI(TAG, "Running Demo");
|
||||
for (size_t i = ProfileGenerator::Smooth; i < ProfileGenerator::NumProfiles; i++) {
|
||||
ESP_LOGI(TAG, "Running Profile %d ", i);
|
||||
fos::Task::delayMs(1000);
|
||||
int steps[3]{4, 2, 0};
|
||||
for (size_t j = 0; j < 3; j++) {
|
||||
watch.moveTo(steps[j], i, 1, 1, 1);
|
||||
fos::Task::delayMs(1000);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fos::Task::delayMs(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
struct LocalSpitObj {
|
||||
string iD;
|
||||
string groupName;
|
||||
string name;
|
||||
};
|
||||
std::map<string, MoveCommand> ProvidedSpitActions;
|
||||
std::map<string, string> ExpectedObjects;
|
||||
|
||||
void onServerEvent(SPIT_Client::ServerEvent event, const SAD_DetectedServer &p_DetectedServer) {
|
||||
switch (event) {
|
||||
case SPIT_Client::ServerEvent::Detect:
|
||||
ESP_LOGI(TAG, "SERVER DETECTED");
|
||||
ESP_LOGI(TAG, " Name: %s", p_DetectedServer.getName().data());
|
||||
ESP_LOGI(TAG, " ID: %s", p_DetectedServer.getID().data());
|
||||
ESP_LOGI(TAG, " Computer: %s", p_DetectedServer.getComputerName().data());
|
||||
ESP_LOGI(TAG, " IP: %s", p_DetectedServer.getIP().data());
|
||||
ESP_LOGI(TAG, " Port: %s", p_DetectedServer.getPort().data());
|
||||
ESP_LOGI(TAG, " Addition: %s", p_DetectedServer.getAdditions().data());
|
||||
ESP_LOGI(TAG, " ClientIP: %s", p_DetectedServer.getClientIP().data());
|
||||
break;
|
||||
case SPIT_Client::ServerEvent::Lost:
|
||||
ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data());
|
||||
|
||||
break;
|
||||
case SPIT_Client::ServerEvent::Changed:
|
||||
ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onConnectionStatus(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime,
|
||||
SPIT_Client::Connection p_ConnectionStatus, SPIT_Client::Connection p_OldConnectionStatus) {
|
||||
ESP_LOGI(TAG, "MySPITApp: eventConnectionStatus %d->%d ", (int)p_OldConnectionStatus, (int)p_ConnectionStatus);
|
||||
}
|
||||
|
||||
// The transfer of the server's SPITTypes and SPITObjects is finished.
|
||||
void onProjectUpdate(SPIT_Client::ProjUpdate state, string projectId) {
|
||||
|
||||
switch (state) {
|
||||
case SPIT_Client::ProjUpdate::ServerLoaded:
|
||||
ESP_LOGI(TAG, "eventProjectReport ID: %s ", projectId.data());
|
||||
break;
|
||||
case SPIT_Client::ProjUpdate::StartTransfer:
|
||||
ESP_LOGI(TAG, "eventStartProjectTransfer");
|
||||
break;
|
||||
case SPIT_Client::ProjUpdate::EndTransfer:
|
||||
ESP_LOGI(TAG, "eventEndProjectTransfer");
|
||||
spitProjectFinish.give();
|
||||
break;
|
||||
case SPIT_Client::ProjUpdate::ServerClosed:
|
||||
ESP_LOGI(TAG, "eventProjectClosed ID: %s", projectId.data());
|
||||
// If we don't save SPITServer's project specific information
|
||||
// perhaps close all SPITObjects and RemoteSPITObjects to avoid conflicts, when the SPITServer loads a new project
|
||||
// SPITObject::clearSPITObjects();
|
||||
// SPITObject::clearSPITObjectsRemote();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool onCheckSpitTypeVeto(bool knownType, bool createdByClient) {
|
||||
if (!knownType || !createdByClient) { // Don't allow foreign SPITTypes
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onCheckSpitObjectVeto(bool knownType) {
|
||||
return true; // Bypass veto
|
||||
if (!knownType) { // Don't allow objects of unregistered SPITTypes
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called when the server has created, loaded, changed or deleted a (Remote) SPITType.
|
||||
// Remote SPITType are used in Remote SPITObjects. A Remote SPITObject is used to remote control the SPITServer.
|
||||
// May also occur when the server confirms a SPITType created or changed by the client.
|
||||
void onSpitType(SPIT_Client::ObjectEvent event, bool isRemote, const SPITType &p_SPITType) {
|
||||
if (isRemote) {
|
||||
if (event == SPIT_Client::ObjectEvent::Created) {
|
||||
ESP_LOGI(TAG, "NEW SPIT-REMOTE-Type ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed());
|
||||
auto typeName = p_SPITType.getName();
|
||||
if (ExpectedObjects.contains(typeName)) {
|
||||
ExpectedObjects[typeName] = p_SPITType.getID();
|
||||
}
|
||||
} else if (event == SPIT_Client::ObjectEvent::Changed) {
|
||||
// we had to inform all Remote SPITObjects using the p_SPITType
|
||||
// perhaps the SPITObject uses information from the SPITType
|
||||
// SPITObject *ptrSPITObject;
|
||||
// int intSPITObjectCount;
|
||||
// intSPITObjectCount = SPITObject::getSPITObjectRemoteCount();
|
||||
// for (int intObject = 0; intObject < intSPITObjectCount; intObject++) {
|
||||
// ptrSPITObject = SPITObject::getSPITObjectRemote(intObject);
|
||||
// if (ptrSPITObject == nullptr)
|
||||
// continue;
|
||||
// if (ptrSPITObject->getSPITTypeID() == p_SPITType.getID()) {
|
||||
// // call ecentSPITObjectRemote
|
||||
// // onSpitObjectRemote(SPIT_Client::ObjectEvent::Changed, p_SPITType, *ptrSPITObject);
|
||||
// }
|
||||
// }
|
||||
ESP_LOGI(TAG, "SPIT-REMOTE-Type CHANGED ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed());
|
||||
} else if (event == SPIT_Client::ObjectEvent::Deleted) {
|
||||
ESP_LOGD(TAG, "SPIT-REMOTE-Type Removed ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data());
|
||||
}
|
||||
} else {
|
||||
if (event == SPIT_Client::ObjectEvent::Created) {
|
||||
// Whenever you provide an action for this SPITType take this over in your code.
|
||||
// call _SpitClient.setActionSPITType(p_SPITType.getID(), true);
|
||||
ESP_LOGI(TAG, "NEW SPIT-Type ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed());
|
||||
} else if (event == SPIT_Client::ObjectEvent::Changed) {
|
||||
ESP_LOGI(TAG, "SPIT-Type CHANGED ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed());
|
||||
} else if (event == SPIT_Client::ObjectEvent::Deleted) {
|
||||
ESP_LOGI(TAG, "SPIT-Type Removed ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the server has created, loaded or changed a SPITObject.
|
||||
// A Remote SPITObject is used to remote control the SPITServer.
|
||||
// May also occur when the server confirms a SPITObject created by the client, what the client should never do!!.
|
||||
// false = server changed a existing SPITObject
|
||||
// @param p_SPITType a reference to a copy of the associated SPITType instance.
|
||||
// @param p_SPITObject a reference to a copy of the SPITObject instance.
|
||||
void onSpitObject(SPIT_Client::ObjectEvent event, bool isRemote, const SPITType &p_SPITType, const SPITObject &p_SPITObject) {
|
||||
if (isRemote) {
|
||||
if (event == SPIT_Client::ObjectEvent::Created) {
|
||||
ESP_LOGI(TAG, "NEW SPIT-REMOTE-Object ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data());
|
||||
// This is a remote SPITObject which can be used to remote control the server.
|
||||
// If you want you can list this for later use
|
||||
} else if (event == SPIT_Client::ObjectEvent::Changed) {
|
||||
ESP_LOGI(TAG, "SPIT-REMOTE-Object CHANGED ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data());
|
||||
} else if (event == SPIT_Client::ObjectEvent::Deleted) {
|
||||
ESP_LOGD(TAG, "SPIT-REMOTE-Object Removed ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data());
|
||||
// This is a remote SPITObject
|
||||
// If you have listet this prior you should remove it from the list
|
||||
}
|
||||
} else {
|
||||
if (event == SPIT_Client::ObjectEvent::Created) {
|
||||
ESP_LOGI(TAG, "NEW SPIT-Object ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data());
|
||||
// check your actions
|
||||
// Whenever you provide an action for this SPITObject take this over in your code.
|
||||
// call _SpitClient.setActionSPITObject(p_SPITObject.getID(), true);
|
||||
|
||||
// for our little excample as described in loadClientProject:
|
||||
// We have only actions for SPITTypes - means every SPITObject with the associated "Actionx"-SPITTypes will trigger the action when it is played
|
||||
//-> no need to do something here, because setActionSPITType has been set prior and the SPITObject will automatically inherits this
|
||||
// SPITObjects with other SPITTypes asscciated will trigger no actions
|
||||
|
||||
} else if (event == SPIT_Client::ObjectEvent::Changed) {
|
||||
ESP_LOGI(TAG, "SPIT-Object CHANGED ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data());
|
||||
} else if (event == SPIT_Client::ObjectEvent::Deleted) {
|
||||
ESP_LOGD(TAG, "SPIT-Object Removed ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data());
|
||||
// Check your actions
|
||||
// take the removal of the SPITObject over in your code
|
||||
|
||||
// CAUTION: Deleted SPITObjects can be added later again (perhaps per UNDO on the SPITServer)
|
||||
//-> don't remove your assigned action immediately - keep it to reassign it later
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SPITServer may use several methods for playing SPITObjects.
|
||||
// e.g. liveSHOWsoftware has the timeline and jingles which plays objects, where the timeline the main player is.
|
||||
// SPIT distinguishes between the different players. All eventPlay... functions contain the information which player plays the SPIT object.
|
||||
void onPlay(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames) {
|
||||
ESP_LOGD(TAG, "eventPlay Player: %s Runs: %d Time: %lld", p_PlayerName.data(), p_PlayerIsRunning, p_TimeFrames);
|
||||
|
||||
switch (p_PlayerType) {
|
||||
case SPIT_Client::PLAYERTYPE_MAIN:
|
||||
// p_FrameTimes contains the position inside the server's project, we can use it like a timecode
|
||||
// int intMilliseconds = (int)(((double)p_TimeFrames / (double)m_ServerFramesPerSecond) * 1000);
|
||||
break;
|
||||
case SPIT_Client::PLAYERTYPE_CONTINOUS:
|
||||
// The olayer is playing only single Object sequences sometime during the project
|
||||
break;
|
||||
case SPIT_Client::PLAYERTYPE_DISCRETE:
|
||||
// Only discrete values where submitted, e.g the fader position of remote faders.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the SPITServer plays a SPITObject. For every played SPITObject one eventPlayObject is called.
|
||||
* You can decide here which action should be done or not.
|
||||
*/
|
||||
void onPlaySpitType(string p_PlayerID, string spitTypeId, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value) {
|
||||
// double doubleValue = ((double)p_PlayObject.getValue() / 1000000) * ((double)p_PlayObject.getValueFactor() / 1000000);
|
||||
|
||||
ESP_LOGD(TAG, "eventPlayObject Player: %s is running: %d Object Started: %d Stopped: %d", p_PlayerID.data(), p_PlayerIsRunning, p_Started, p_Ended);
|
||||
// ESP_LOGD(TAG, " SPITType: %s SPITObject: %s Position: %lld Value: %f\n", spitTypeId.data(), p_SPITObject.getName().data(), p_PlayObject.getFrameInside(), doubleValue);
|
||||
ESP_LOGD(TAG, " SPITType: %s Value: %f\n", spitTypeId.data(), p_Value);
|
||||
|
||||
if (!ProvidedSpitActions.contains(spitTypeId)) {
|
||||
ESP_LOGE(TAG, "SPIT ID %s is not accepted", spitTypeId.c_str());
|
||||
return;
|
||||
}
|
||||
if (p_Started == true) {
|
||||
auto command = ProvidedSpitActions[spitTypeId];
|
||||
ESP_LOGI(TAG, "Player: %s is running: %s Object", p_PlayerID.data(), spitTypeId.c_str());
|
||||
commandQueue.enqueue(std::make_unique<MoveCommand>(command));
|
||||
Syslog::logv(Syslog::Severity::Informational, "Got SPIT command for move ot : r%d", command.pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a remote SpitObject which value function is changed by the server.
|
||||
* This allows the Client to adjust its display for the remote command.
|
||||
* @param p_SPITType the assigned remote SPITType of p_SPITObject
|
||||
* @param p_SPITObject the remote SPITObject which is changed
|
||||
* @param p_FrameInsideObject can be discarded
|
||||
* @param p_Value the new value
|
||||
*/
|
||||
void onPlayRemoteObjectStatus(const SPITType &p_SPITType, const SPITObject &p_SPITObject, long long p_FrameInsideObject, int p_Value) {
|
||||
ESP_EARLY_LOGD(TAG, "eventPlayRemoteObjectStatus RemoteSPITType: %s RemoteSPITObject: %s Position: %lld Value: %d", p_SPITType.getName().data(), p_SPITObject.getName().data(), p_FrameInsideObject, p_Value);
|
||||
}
|
||||
|
||||
void SpitClientApp() {
|
||||
ESP_LOGI(TAG, "Starting SPIT task");
|
||||
|
||||
auto &provided = SpitTypes.Provided;
|
||||
auto &expected = SpitTypes.Expected;
|
||||
std::vector<LocalSpitObj> ProvidedObj;
|
||||
ProvidedSpitActions[provided.startShuffle] = MoveCommand{.type = MoveType::Shuffle, .pos = 0};
|
||||
ProvidedObj.push_back(LocalSpitObj{.iD = provided.startShuffle, .groupName = provided.group, .name = provided.startShuffle});
|
||||
ExpectedObjects[expected.changingPos] = "";
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
ProvidedObj.push_back(LocalSpitObj{.iD = provided.moveToX[i], .groupName = provided.group, .name = provided.moveToX[i]});
|
||||
ProvidedSpitActions[provided.moveToX[i]] = MoveCommand{.type = MoveType::StepTo, .pos = (uint8_t)(i + 1)};
|
||||
ExpectedObjects[expected.inPosX[i]] = "";
|
||||
}
|
||||
|
||||
SPIT_Client spitClient(ClientName, ProjectName,
|
||||
{
|
||||
.onServerEvent = onServerEvent,
|
||||
.onConnectionStatus = onConnectionStatus,
|
||||
.onProjectUpdate = onProjectUpdate,
|
||||
.onSpitType = onSpitType,
|
||||
.onSpitObject = onSpitObject,
|
||||
.onPlay = onPlay,
|
||||
.onPlaySpitType = onPlaySpitType,
|
||||
.onPlayRemoteObjectStatus = onPlayRemoteObjectStatus,
|
||||
.onCheckSpitTypeVeto = onCheckSpitTypeVeto,
|
||||
.onCheckSpitObjectVeto = onCheckSpitObjectVeto,
|
||||
});
|
||||
|
||||
for (auto &obj : ProvidedObj) {
|
||||
SPITType *ptrSPITType1Fix = spitClient.createSPITTypeFixed(obj.iD, obj.groupName, obj.name, 0, 0);
|
||||
spitClient.setActionSPITType(ptrSPITType1Fix->getID(), true); // should be executed whenever a SPITObject with this SPITType is played
|
||||
}
|
||||
spitClient.clientProjectLoaded();
|
||||
spitClient.startServerAutoDetect();
|
||||
|
||||
spitProjectFinish.take();
|
||||
string serverProjectID = spitClient.getServerProjectID();
|
||||
string serverProjectName = spitClient.getClientProjectName();
|
||||
int serverFramesPerSecond = spitClient.getServerFramesPerSecond(); // set when the server reports his project, see eventProjectReport
|
||||
ESP_LOGI(TAG, "eventProjectReport ID: %s Name: %s FramesPerSecond: %d", serverProjectID.data(), serverProjectName.data(), serverFramesPerSecond);
|
||||
|
||||
for (auto &&obj : ExpectedObjects) {
|
||||
if (obj.second == "") {
|
||||
ESP_LOGE(TAG, "No matching Remote ID for %s", obj.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto res = responseQueue.dequeue();
|
||||
if (res->type == ResponseType::StartMoving) {
|
||||
spitClient.sendRemoteObject(ExpectedObjects[expected.changingPos]);
|
||||
} else if (res->type == ResponseType::StepAt) {
|
||||
spitClient.sendRemoteObject(ExpectedObjects[expected.inPosX[res->pos - 1]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// esp_err_t ret = nvs_flash_init();
|
||||
// if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
// ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
// ret = nvs_flash_init();
|
||||
// }
|
||||
// ESP_ERROR_CHECK(ret); // moved to NvsApi::init();
|
||||
initialize_ethernet();
|
||||
NvsApi::init();
|
||||
static fos::Task lightingTask(LightingTask, "Lights", 0x8000uL);
|
||||
static fos::Task movementTask(MovementTask, "Motor", 0x8000uL);
|
||||
|
||||
etherActive.take();
|
||||
fos::Task::delayMs(10000);
|
||||
ESP_LOGI(TAG, "Start net services");
|
||||
|
||||
// esp_log_level_set("SPIT", esp_log_level_t::ESP_LOG_DEBUG);
|
||||
|
||||
static int ipVersion = AF_INET;
|
||||
static fos::TaskT<int> telnetSocket(telnetSocketTask, ipVersion, "tcpServer", 4096);
|
||||
static fos::TaskT<int> dmxNode(dmxSocketTask, ipVersion, "dmxNode", 4096);
|
||||
// static Task otaUpdate(SystemFunctions::OtaTaskEntry, "otaTask", 8192);
|
||||
static fos::Task spit(SpitClientApp, "SpitClient");
|
||||
|
||||
auto &store = NvsApi::getInstance();
|
||||
auto logger = store.getValue(ConfigKeys.syslogDest);
|
||||
if (logger != "") {
|
||||
Syslog::setupTask(IpAdr{logger, 0});
|
||||
}
|
||||
|
||||
// auto broker = store.getValue(ConfigKeys.mqttBroker);
|
||||
// if (broker != "") {
|
||||
// ESP_LOGI(TAG, "Initializing MQTT");
|
||||
// auto prefix = store.getValue(ConfigKeys.mqttPrefix);
|
||||
// auto &client = MqttClient::init(broker, prefix);
|
||||
// if (!client.isRunning()) {
|
||||
// client.addSubscription(MqttTopics.moveTo, [](std::string d) { moveToSubs(d); });
|
||||
// client.addSubscription(MqttTopics.startShuffle, [](std::string d) { startShuffle(d); });
|
||||
// client.start();
|
||||
// }
|
||||
// }
|
||||
|
||||
while (true) {
|
||||
fos::Task::delayMs(5000);
|
||||
// ToDo send
|
||||
Syslog::logv(Syslog::Severity::Notice, "Health state");
|
||||
// ESP_LOGI(TAG, "Min heap size: %" PRIu32 " / FreeHeap %" PRIu32 "\n",
|
||||
// ESP_LOGI(TAG, "Min heap size: %u / FreeHeap %lu",
|
||||
// heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT),
|
||||
// esp_get_free_heap_size());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* @file watchMain.hpp
|
||||
* @author Gustice
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@@ -8,11 +10,6 @@
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
@@ -20,17 +17,18 @@
|
||||
#include "esp_wifi.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_private/wifi.h"
|
||||
#include "ethernet.hpp"
|
||||
#include "ethernet_init.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_eth.h"
|
||||
|
||||
// Component header
|
||||
#include "Task.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"
|
||||
@@ -40,11 +38,27 @@
|
||||
#include "nvsFunctions.hpp"
|
||||
#include "mqttClient.hpp"
|
||||
#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 "addressableLeRtz.hpp"
|
||||
#include "systemFunctions.hpp"
|
||||
|
||||
// #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 "SAD_DetectedServer.hpp"
|
||||
#include "SPITObject.h"
|
||||
#include "SPITPlayer.h"
|
||||
#include "SPITType.h"
|
||||
#include "SPIT_Client.h"
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <map>
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
.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
|
||||
@@ -1 +0,0 @@
|
||||
e00a16d6372fa31df46b32e330847d6e09af2ec184d8c7cac4d183b3daac02e5
|
||||
@@ -1,12 +0,0 @@
|
||||
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)
|
||||
@@ -1 +0,0 @@
|
||||
{"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"}]}
|
||||
@@ -1,16 +0,0 @@
|
||||
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)
|
||||
@@ -1,41 +0,0 @@
|
||||
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
|
||||
@@ -1,21 +0,0 @@
|
||||
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.
|
||||
@@ -1,6 +0,0 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=4.0'
|
||||
description: esp_telnet is a small implementation of the telnet server.
|
||||
url: https://github.com/frozen-eye/esp_telnet.git
|
||||
version: 0.0.2
|
||||
@@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <libtelnet.h>
|
||||
|
||||
static const telnet_telopt_t default_telopts[] = {
|
||||
{TELNET_TELOPT_COMPRESS2, TELNET_WILL, TELNET_DO}, {TELNET_TELOPT_ZMP, TELNET_WILL, TELNET_DO},
|
||||
{TELNET_TELOPT_MSSP, TELNET_WILL, TELNET_DONT}, {TELNET_TELOPT_NEW_ENVIRON, TELNET_WILL, TELNET_DONT},
|
||||
{TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT}, {-1, 0, 0}};
|
||||
|
||||
struct user_t {
|
||||
char* name;
|
||||
int sock;
|
||||
telnet_t* telnet;
|
||||
char linebuf[255];
|
||||
int linepos;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct telnet_server_config {
|
||||
int port;
|
||||
int stack_size;
|
||||
int task_priority;
|
||||
int task_core;
|
||||
int redirect_logs;
|
||||
int max_connections;
|
||||
const telnet_telopt_t *telnet_opts;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Telnet Server Default Configuration
|
||||
*
|
||||
*/
|
||||
#define TELNET_SERVER_DEFAULT_CONFIG \
|
||||
{ \
|
||||
.port = CONFIG_TELNET_SERVER_DEFAULT_PORT, \
|
||||
.stack_size = CONFIG_TELNET_SERVER_STACK_SIZE, \
|
||||
.task_priority = CONFIG_TELNET_SERVER_TASK_PRIORITY, \
|
||||
.task_core = CONFIG_TELNET_SERVER_TASK_CORE, \
|
||||
.redirect_logs = CONFIG_TELNET_SERVER_REDIRECT_LOGS, \
|
||||
.max_connections = CONFIG_TELNET_SERVER_MAX_CONNECTIONS, \
|
||||
.telnet_opts = default_telopts, \
|
||||
}
|
||||
|
||||
typedef struct telnet_server_config telnet_server_config_t;
|
||||
|
||||
esp_err_t telnet_server_create(telnet_server_config_t* config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,691 +0,0 @@
|
||||
/*!
|
||||
* \brief libtelnet - TELNET protocol handling library
|
||||
*
|
||||
* SUMMARY:
|
||||
*
|
||||
* libtelnet is a library for handling the TELNET protocol. It includes
|
||||
* routines for parsing incoming data from a remote peer as well as formatting
|
||||
* data to send to the remote peer.
|
||||
*
|
||||
* libtelnet uses a callback-oriented API, allowing application-specific
|
||||
* handling of various events. The callback system is also used for buffering
|
||||
* outgoing protocol data, allowing the application to maintain control over
|
||||
* the actual socket connection.
|
||||
*
|
||||
* Features supported include the full TELNET protocol, Q-method option
|
||||
* negotiation, ZMP, MCCP2, MSSP, and NEW-ENVIRON.
|
||||
*
|
||||
* CONFORMS TO:
|
||||
*
|
||||
* RFC854 - http://www.faqs.org/rfcs/rfc854.html
|
||||
* RFC855 - http://www.faqs.org/rfcs/rfc855.html
|
||||
* RFC1091 - http://www.faqs.org/rfcs/rfc1091.html
|
||||
* RFC1143 - http://www.faqs.org/rfcs/rfc1143.html
|
||||
* RFC1408 - http://www.faqs.org/rfcs/rfc1408.html
|
||||
* RFC1572 - http://www.faqs.org/rfcs/rfc1572.html
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* The author or authors of this code dedicate any and all copyright interest
|
||||
* in this code to the public domain. We make this dedication for the benefit
|
||||
* of the public at large and to the detriment of our heirs and successors. We
|
||||
* intend this dedication to be an overt act of relinquishment in perpetuity of
|
||||
* all present and future rights to this code under copyright law.
|
||||
*
|
||||
* \file libtelnet.h
|
||||
*
|
||||
* \version 0.23
|
||||
*
|
||||
* \author Sean Middleditch <sean@sourcemud.org>
|
||||
*/
|
||||
|
||||
#if !defined(LIBTELNET_INCLUDE)
|
||||
#define LIBTELNET_INCLUDE 1
|
||||
|
||||
/* standard C headers necessary for the libtelnet API */
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* C++ support */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* printf type checking feature in GCC and some other compilers */
|
||||
#if __GNUC__
|
||||
# define TELNET_GNU_PRINTF(f,a) __attribute__((format(printf, f, a))) /*!< internal helper */
|
||||
# define TELNET_GNU_SENTINEL __attribute__((sentinel)) /*!< internal helper */
|
||||
#else
|
||||
# define TELNET_GNU_PRINTF(f,a) /*!< internal helper */
|
||||
# define TELNET_GNU_SENTINEL /*!< internal helper */
|
||||
#endif
|
||||
|
||||
/* Disable environ macro for Visual C++ 2015. */
|
||||
#undef environ
|
||||
|
||||
/*! Telnet state tracker object type. */
|
||||
typedef struct telnet_t telnet_t;
|
||||
|
||||
/*! Telnet event object type. */
|
||||
typedef union telnet_event_t telnet_event_t;
|
||||
|
||||
/*! Telnet option table element type. */
|
||||
typedef struct telnet_telopt_t telnet_telopt_t;
|
||||
|
||||
/*! \name Telnet commands */
|
||||
/*@{*/
|
||||
/*! Telnet commands and special values. */
|
||||
#define TELNET_IAC 255
|
||||
#define TELNET_DONT 254
|
||||
#define TELNET_DO 253
|
||||
#define TELNET_WONT 252
|
||||
#define TELNET_WILL 251
|
||||
#define TELNET_SB 250
|
||||
#define TELNET_GA 249
|
||||
#define TELNET_EL 248
|
||||
#define TELNET_EC 247
|
||||
#define TELNET_AYT 246
|
||||
#define TELNET_AO 245
|
||||
#define TELNET_IP 244
|
||||
#define TELNET_BREAK 243
|
||||
#define TELNET_DM 242
|
||||
#define TELNET_NOP 241
|
||||
#define TELNET_SE 240
|
||||
#define TELNET_EOR 239
|
||||
#define TELNET_ABORT 238
|
||||
#define TELNET_SUSP 237
|
||||
#define TELNET_EOF 236
|
||||
/*@}*/
|
||||
|
||||
/*! \name Telnet option values. */
|
||||
/*@{*/
|
||||
/*! Telnet options. */
|
||||
#define TELNET_TELOPT_BINARY 0
|
||||
#define TELNET_TELOPT_ECHO 1
|
||||
#define TELNET_TELOPT_RCP 2
|
||||
#define TELNET_TELOPT_SGA 3
|
||||
#define TELNET_TELOPT_NAMS 4
|
||||
#define TELNET_TELOPT_STATUS 5
|
||||
#define TELNET_TELOPT_TM 6
|
||||
#define TELNET_TELOPT_RCTE 7
|
||||
#define TELNET_TELOPT_NAOL 8
|
||||
#define TELNET_TELOPT_NAOP 9
|
||||
#define TELNET_TELOPT_NAOCRD 10
|
||||
#define TELNET_TELOPT_NAOHTS 11
|
||||
#define TELNET_TELOPT_NAOHTD 12
|
||||
#define TELNET_TELOPT_NAOFFD 13
|
||||
#define TELNET_TELOPT_NAOVTS 14
|
||||
#define TELNET_TELOPT_NAOVTD 15
|
||||
#define TELNET_TELOPT_NAOLFD 16
|
||||
#define TELNET_TELOPT_XASCII 17
|
||||
#define TELNET_TELOPT_LOGOUT 18
|
||||
#define TELNET_TELOPT_BM 19
|
||||
#define TELNET_TELOPT_DET 20
|
||||
#define TELNET_TELOPT_SUPDUP 21
|
||||
#define TELNET_TELOPT_SUPDUPOUTPUT 22
|
||||
#define TELNET_TELOPT_SNDLOC 23
|
||||
#define TELNET_TELOPT_TTYPE 24
|
||||
#define TELNET_TELOPT_EOR 25
|
||||
#define TELNET_TELOPT_TUID 26
|
||||
#define TELNET_TELOPT_OUTMRK 27
|
||||
#define TELNET_TELOPT_TTYLOC 28
|
||||
#define TELNET_TELOPT_3270REGIME 29
|
||||
#define TELNET_TELOPT_X3PAD 30
|
||||
#define TELNET_TELOPT_NAWS 31
|
||||
#define TELNET_TELOPT_TSPEED 32
|
||||
#define TELNET_TELOPT_LFLOW 33
|
||||
#define TELNET_TELOPT_LINEMODE 34
|
||||
#define TELNET_TELOPT_XDISPLOC 35
|
||||
#define TELNET_TELOPT_ENVIRON 36
|
||||
#define TELNET_TELOPT_AUTHENTICATION 37
|
||||
#define TELNET_TELOPT_ENCRYPT 38
|
||||
#define TELNET_TELOPT_NEW_ENVIRON 39
|
||||
#define TELNET_TELOPT_MSSP 70
|
||||
#define TELNET_TELOPT_COMPRESS 85
|
||||
#define TELNET_TELOPT_COMPRESS2 86
|
||||
#define TELNET_TELOPT_ZMP 93
|
||||
#define TELNET_TELOPT_EXOPL 255
|
||||
|
||||
#define TELNET_TELOPT_MCCP2 86
|
||||
/*@}*/
|
||||
|
||||
/*! \name Protocol codes for TERMINAL-TYPE commands. */
|
||||
/*@{*/
|
||||
/*! TERMINAL-TYPE codes. */
|
||||
#define TELNET_TTYPE_IS 0
|
||||
#define TELNET_TTYPE_SEND 1
|
||||
/*@}*/
|
||||
|
||||
/*! \name Protocol codes for NEW-ENVIRON/ENVIRON commands. */
|
||||
/*@{*/
|
||||
/*! NEW-ENVIRON/ENVIRON codes. */
|
||||
#define TELNET_ENVIRON_IS 0
|
||||
#define TELNET_ENVIRON_SEND 1
|
||||
#define TELNET_ENVIRON_INFO 2
|
||||
#define TELNET_ENVIRON_VAR 0
|
||||
#define TELNET_ENVIRON_VALUE 1
|
||||
#define TELNET_ENVIRON_ESC 2
|
||||
#define TELNET_ENVIRON_USERVAR 3
|
||||
/*@}*/
|
||||
|
||||
/*! \name Protocol codes for MSSP commands. */
|
||||
/*@{*/
|
||||
/*! MSSP codes. */
|
||||
#define TELNET_MSSP_VAR 1
|
||||
#define TELNET_MSSP_VAL 2
|
||||
/*@}*/
|
||||
|
||||
/*! \name Telnet state tracker flags. */
|
||||
/*@{*/
|
||||
/*! Control behavior of telnet state tracker. */
|
||||
#define TELNET_FLAG_PROXY (1<<0)
|
||||
#define TELNET_FLAG_NVT_EOL (1<<1)
|
||||
|
||||
/* Internal-only bits in option flags */
|
||||
#define TELNET_FLAG_TRANSMIT_BINARY (1<<5)
|
||||
#define TELNET_FLAG_RECEIVE_BINARY (1<<6)
|
||||
#define TELNET_PFLAG_DEFLATE (1<<7)
|
||||
/*@}*/
|
||||
|
||||
/*!
|
||||
* error codes
|
||||
*/
|
||||
enum telnet_error_t {
|
||||
TELNET_EOK = 0, /*!< no error */
|
||||
TELNET_EBADVAL, /*!< invalid parameter, or API misuse */
|
||||
TELNET_ENOMEM, /*!< memory allocation failure */
|
||||
TELNET_EOVERFLOW, /*!< data exceeds buffer size */
|
||||
TELNET_EPROTOCOL, /*!< invalid sequence of special bytes */
|
||||
TELNET_ECOMPRESS /*!< error handling compressed streams */
|
||||
};
|
||||
typedef enum telnet_error_t telnet_error_t; /*!< Error code type. */
|
||||
|
||||
/*!
|
||||
* event codes
|
||||
*/
|
||||
enum telnet_event_type_t {
|
||||
TELNET_EV_DATA = 0, /*!< raw text data has been received */
|
||||
TELNET_EV_SEND, /*!< data needs to be sent to the peer */
|
||||
TELNET_EV_IAC, /*!< generic IAC code received */
|
||||
TELNET_EV_WILL, /*!< WILL option negotiation received */
|
||||
TELNET_EV_WONT, /*!< WONT option neogitation received */
|
||||
TELNET_EV_DO, /*!< DO option negotiation received */
|
||||
TELNET_EV_DONT, /*!< DONT option negotiation received */
|
||||
TELNET_EV_SUBNEGOTIATION, /*!< sub-negotiation data received */
|
||||
TELNET_EV_COMPRESS, /*!< compression has been enabled */
|
||||
TELNET_EV_ZMP, /*!< ZMP command has been received */
|
||||
TELNET_EV_TTYPE, /*!< TTYPE command has been received */
|
||||
TELNET_EV_ENVIRON, /*!< ENVIRON command has been received */
|
||||
TELNET_EV_MSSP, /*!< MSSP command has been received */
|
||||
TELNET_EV_WARNING, /*!< recoverable error has occured */
|
||||
TELNET_EV_ERROR /*!< non-recoverable error has occured */
|
||||
};
|
||||
typedef enum telnet_event_type_t telnet_event_type_t; /*!< Telnet event type. */
|
||||
|
||||
/*!
|
||||
* environ/MSSP command information
|
||||
*/
|
||||
struct telnet_environ_t {
|
||||
unsigned char type; /*!< either TELNET_ENVIRON_VAR or TELNET_ENVIRON_USERVAR */
|
||||
char *var; /*!< name of the variable being set */
|
||||
char *value; /*!< value of variable being set; empty string if no value */
|
||||
};
|
||||
|
||||
/*!
|
||||
* event information
|
||||
*/
|
||||
union telnet_event_t {
|
||||
/*!
|
||||
* \brief Event type
|
||||
*
|
||||
* The type field will determine which of the other event structure fields
|
||||
* have been filled in. For instance, if the event type is TELNET_EV_ZMP,
|
||||
* then the zmp event field (and ONLY the zmp event field) will be filled
|
||||
* in.
|
||||
*/
|
||||
enum telnet_event_type_t type;
|
||||
|
||||
/*!
|
||||
* data event: for DATA and SEND events
|
||||
*/
|
||||
struct data_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
const char *buffer; /*!< byte buffer */
|
||||
size_t size; /*!< number of bytes in buffer */
|
||||
} data; /*!< DATA and SEND */
|
||||
|
||||
/*!
|
||||
* WARNING and ERROR events
|
||||
*/
|
||||
struct error_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
const char *file; /*!< file the error occured in */
|
||||
const char *func; /*!< function the error occured in */
|
||||
const char *msg; /*!< error message string */
|
||||
int line; /*!< line of file error occured on */
|
||||
telnet_error_t errcode; /*!< error code */
|
||||
} error; /*!< WARNING and ERROR */
|
||||
|
||||
/*!
|
||||
* command event: for IAC
|
||||
*/
|
||||
struct iac_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
unsigned char cmd; /*!< telnet command received */
|
||||
} iac; /*!< IAC */
|
||||
|
||||
/*!
|
||||
* negotiation event: WILL, WONT, DO, DONT
|
||||
*/
|
||||
struct negotiate_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
unsigned char telopt; /*!< option being negotiated */
|
||||
} neg; /*!< WILL, WONT, DO, DONT */
|
||||
|
||||
/*!
|
||||
* subnegotiation event
|
||||
*/
|
||||
struct subnegotiate_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
const char *buffer; /*!< data of sub-negotiation */
|
||||
size_t size; /*!< number of bytes in buffer */
|
||||
unsigned char telopt; /*!< option code for negotiation */
|
||||
} sub; /*!< SB */
|
||||
|
||||
/*!
|
||||
* ZMP event
|
||||
*/
|
||||
struct zmp_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
const char **argv; /*!< array of argument string */
|
||||
size_t argc; /*!< number of elements in argv */
|
||||
} zmp; /*!< ZMP */
|
||||
|
||||
/*!
|
||||
* TTYPE event
|
||||
*/
|
||||
struct ttype_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
unsigned char cmd; /*!< TELNET_TTYPE_IS or TELNET_TTYPE_SEND */
|
||||
const char* name; /*!< terminal type name (IS only) */
|
||||
} ttype; /*!< TTYPE */
|
||||
|
||||
/*!
|
||||
* COMPRESS event
|
||||
*/
|
||||
struct compress_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
unsigned char state; /*!< 1 if compression is enabled,
|
||||
0 if disabled */
|
||||
} compress; /*!< COMPRESS */
|
||||
|
||||
/*!
|
||||
* ENVIRON/NEW-ENVIRON event
|
||||
*/
|
||||
struct environ_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
const struct telnet_environ_t *values; /*!< array of variable values */
|
||||
size_t size; /*!< number of elements in values */
|
||||
unsigned char cmd; /*!< SEND, IS, or INFO */
|
||||
} environ; /*!< ENVIRON, NEW-ENVIRON */
|
||||
|
||||
/*!
|
||||
* MSSP event
|
||||
*/
|
||||
struct mssp_t {
|
||||
enum telnet_event_type_t _type; /*!< alias for type */
|
||||
const struct telnet_environ_t *values; /*!< array of variable values */
|
||||
size_t size; /*!< number of elements in values */
|
||||
} mssp; /*!< MSSP */
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief event handler
|
||||
*
|
||||
* This is the type of function that must be passed to
|
||||
* telnet_init() when creating a new telnet object. The
|
||||
* function will be invoked once for every event generated
|
||||
* by the libtelnet protocol parser.
|
||||
*
|
||||
* \param telnet The telnet object that generated the event
|
||||
* \param event Event structure with details about the event
|
||||
* \param user_data User-supplied pointer
|
||||
*/
|
||||
typedef void (*telnet_event_handler_t)(telnet_t *telnet,
|
||||
telnet_event_t *event, void *user_data);
|
||||
|
||||
/*!
|
||||
* telopt support table element; use telopt of -1 for end marker
|
||||
*/
|
||||
struct telnet_telopt_t {
|
||||
short telopt; /*!< one of the TELOPT codes or -1 */
|
||||
unsigned char us; /*!< TELNET_WILL or TELNET_WONT */
|
||||
unsigned char him; /*!< TELNET_DO or TELNET_DONT */
|
||||
};
|
||||
|
||||
/*!
|
||||
* state tracker -- private data structure
|
||||
*/
|
||||
struct telnet_t;
|
||||
|
||||
/*!
|
||||
* \brief Initialize a telnet state tracker.
|
||||
*
|
||||
* This function initializes a new state tracker, which is used for all
|
||||
* other libtelnet functions. Each connection must have its own
|
||||
* telnet state tracker object.
|
||||
*
|
||||
* \param telopts Table of TELNET options the application supports.
|
||||
* \param eh Event handler function called for every event.
|
||||
* \param flags 0 or TELNET_FLAG_PROXY.
|
||||
* \param user_data Optional data pointer that will be passsed to eh.
|
||||
* \return Telnet state tracker object.
|
||||
*/
|
||||
extern telnet_t* telnet_init(const telnet_telopt_t *telopts,
|
||||
telnet_event_handler_t eh, unsigned char flags, void *user_data);
|
||||
|
||||
/*!
|
||||
* \brief Free up any memory allocated by a state tracker.
|
||||
*
|
||||
* This function must be called when a telnet state tracker is no
|
||||
* longer needed (such as after the connection has been closed) to
|
||||
* release any memory resources used by the state tracker.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
*/
|
||||
extern void telnet_free(telnet_t *telnet);
|
||||
|
||||
/*!
|
||||
* \brief Push a byte buffer into the state tracker.
|
||||
*
|
||||
* Passes one or more bytes to the telnet state tracker for
|
||||
* protocol parsing. The byte buffer is most often going to be
|
||||
* the buffer that recv() was called for while handling the
|
||||
* connection.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param buffer Pointer to byte buffer.
|
||||
* \param size Number of bytes pointed to by buffer.
|
||||
*/
|
||||
extern void telnet_recv(telnet_t *telnet, const char *buffer,
|
||||
size_t size);
|
||||
|
||||
/*!
|
||||
* \brief Send a telnet command.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param cmd Command to send.
|
||||
*/
|
||||
extern void telnet_iac(telnet_t *telnet, unsigned char cmd);
|
||||
|
||||
/*!
|
||||
* \brief Send negotiation command.
|
||||
*
|
||||
* Internally, libtelnet uses RFC1143 option negotiation rules.
|
||||
* The negotiation commands sent with this function may be ignored
|
||||
* if they are determined to be redundant.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param cmd TELNET_WILL, TELNET_WONT, TELNET_DO, or TELNET_DONT.
|
||||
* \param opt One of the TELNET_TELOPT_* values.
|
||||
*/
|
||||
extern void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char opt);
|
||||
|
||||
/*!
|
||||
* Send non-command data (escapes IAC bytes).
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param buffer Buffer of bytes to send.
|
||||
* \param size Number of bytes to send.
|
||||
*/
|
||||
extern void telnet_send(telnet_t *telnet,
|
||||
const char *buffer, size_t size);
|
||||
|
||||
/*!
|
||||
* Send non-command text (escapes IAC bytes and translates
|
||||
* \\r -> CR-NUL and \\n -> CR-LF unless in BINARY mode.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param buffer Buffer of bytes to send.
|
||||
* \param size Number of bytes to send.
|
||||
*/
|
||||
extern void telnet_send_text(telnet_t *telnet,
|
||||
const char *buffer, size_t size);
|
||||
|
||||
/*!
|
||||
* \brief Begin a sub-negotiation command.
|
||||
*
|
||||
* Sends IAC SB followed by the telopt code. All following data sent
|
||||
* will be part of the sub-negotiation, until telnet_finish_sb() is
|
||||
* called.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param telopt One of the TELNET_TELOPT_* values.
|
||||
*/
|
||||
extern void telnet_begin_sb(telnet_t *telnet,
|
||||
unsigned char telopt);
|
||||
|
||||
/*!
|
||||
* \brief Finish a sub-negotiation command.
|
||||
*
|
||||
* This must be called after a call to telnet_begin_sb() to finish a
|
||||
* sub-negotiation command.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
*/
|
||||
#define telnet_finish_sb(telnet) telnet_iac((telnet), TELNET_SE)
|
||||
|
||||
/*!
|
||||
* \brief Shortcut for sending a complete subnegotiation buffer.
|
||||
*
|
||||
* Equivalent to:
|
||||
* telnet_begin_sb(telnet, telopt);
|
||||
* telnet_send(telnet, buffer, size);
|
||||
* telnet_finish_sb(telnet);
|
||||
*
|
||||
* \param telnet Telnet state tracker format.
|
||||
* \param telopt One of the TELNET_TELOPT_* values.
|
||||
* \param buffer Byte buffer for sub-negotiation data.
|
||||
* \param size Number of bytes to use for sub-negotiation data.
|
||||
*/
|
||||
extern void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||
const char *buffer, size_t size);
|
||||
|
||||
/*!
|
||||
* \brief Begin sending compressed data.
|
||||
*
|
||||
* This function will begein sending data using the COMPRESS2 option,
|
||||
* which enables the use of zlib to compress data sent to the client.
|
||||
* The client must offer support for COMPRESS2 with option negotiation,
|
||||
* and zlib support must be compiled into libtelnet.
|
||||
*
|
||||
* Only the server may call this command.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
*/
|
||||
extern void telnet_begin_compress2(telnet_t *telnet);
|
||||
|
||||
/*!
|
||||
* \brief Send formatted data.
|
||||
*
|
||||
* This function is a wrapper around telnet_send(). It allows using
|
||||
* printf-style formatting.
|
||||
*
|
||||
* Additionally, this function will translate \\r to the CR NUL construct and
|
||||
* \\n with CR LF, as well as automatically escaping IAC bytes like
|
||||
* telnet_send().
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param fmt Format string.
|
||||
* \return Number of bytes sent.
|
||||
*/
|
||||
extern int telnet_printf(telnet_t *telnet, const char *fmt, ...)
|
||||
TELNET_GNU_PRINTF(2, 3);
|
||||
|
||||
/*!
|
||||
* \brief Send formatted data.
|
||||
*
|
||||
* See telnet_printf().
|
||||
*/
|
||||
extern int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va);
|
||||
|
||||
/*!
|
||||
* \brief Send formatted data (no newline escaping).
|
||||
*
|
||||
* This behaves identically to telnet_printf(), except that the \\r and \\n
|
||||
* characters are not translated. The IAC byte is still escaped as normal
|
||||
* with telnet_send().
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param fmt Format string.
|
||||
* \return Number of bytes sent.
|
||||
*/
|
||||
extern int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...)
|
||||
TELNET_GNU_PRINTF(2, 3);
|
||||
|
||||
/*!
|
||||
* \brief Send formatted data (no newline escaping).
|
||||
*
|
||||
* See telnet_raw_printf().
|
||||
*/
|
||||
extern int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va);
|
||||
|
||||
/*!
|
||||
* \brief Begin a new set of NEW-ENVIRON values to request or send.
|
||||
*
|
||||
* This function will begin the sub-negotiation block for sending or
|
||||
* requesting NEW-ENVIRON values.
|
||||
*
|
||||
* The telnet_finish_newenviron() macro must be called after this
|
||||
* function to terminate the NEW-ENVIRON command.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param type One of TELNET_ENVIRON_SEND, TELNET_ENVIRON_IS, or
|
||||
* TELNET_ENVIRON_INFO.
|
||||
*/
|
||||
extern void telnet_begin_newenviron(telnet_t *telnet, unsigned char type);
|
||||
|
||||
/*!
|
||||
* \brief Send a NEW-ENVIRON variable name or value.
|
||||
*
|
||||
* This can only be called between calls to telnet_begin_newenviron() and
|
||||
* telnet_finish_newenviron().
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param type One of TELNET_ENVIRON_VAR, TELNET_ENVIRON_USERVAR, or
|
||||
* TELNET_ENVIRON_VALUE.
|
||||
* \param string Variable name or value.
|
||||
*/
|
||||
extern void telnet_newenviron_value(telnet_t* telnet, unsigned char type,
|
||||
const char *string);
|
||||
|
||||
/*!
|
||||
* \brief Finish a NEW-ENVIRON command.
|
||||
*
|
||||
* This must be called after a call to telnet_begin_newenviron() to finish a
|
||||
* NEW-ENVIRON variable list.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
*/
|
||||
#define telnet_finish_newenviron(telnet) telnet_finish_sb((telnet))
|
||||
|
||||
/*!
|
||||
* \brief Send the TERMINAL-TYPE SEND command.
|
||||
*
|
||||
* Sends the sequence IAC TERMINAL-TYPE SEND.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
*/
|
||||
extern void telnet_ttype_send(telnet_t *telnet);
|
||||
|
||||
/*!
|
||||
* \brief Send the TERMINAL-TYPE IS command.
|
||||
*
|
||||
* Sends the sequence IAC TERMINAL-TYPE IS "string".
|
||||
*
|
||||
* According to the RFC, the recipient of a TERMINAL-TYPE SEND shall
|
||||
* send the next possible terminal-type the client supports. Upon sending
|
||||
* the type, the client should switch modes to begin acting as the terminal
|
||||
* type is just sent.
|
||||
*
|
||||
* The server may continue sending TERMINAL-TYPE IS until it receives a
|
||||
* terminal type is understands. To indicate to the server that it has
|
||||
* reached the end of the available optoins, the client must send the last
|
||||
* terminal type a second time. When the server receives the same terminal
|
||||
* type twice in a row, it knows it has seen all available terminal types.
|
||||
*
|
||||
* After the last terminal type is sent, if the client receives another
|
||||
* TERMINAL-TYPE SEND command, it must begin enumerating the available
|
||||
* terminal types from the very beginning. This allows the server to
|
||||
* scan the available types for a preferred terminal type and, if none
|
||||
* is found, to then ask the client to switch to an acceptable
|
||||
* alternative.
|
||||
*
|
||||
* Note that if the client only supports a single terminal type, then
|
||||
* simply sending that one type in response to every SEND will satisfy
|
||||
* the behavior requirements.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param ttype Name of the terminal-type being sent.
|
||||
*/
|
||||
extern void telnet_ttype_is(telnet_t *telnet, const char* ttype);
|
||||
|
||||
/*!
|
||||
* \brief Send a ZMP command.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param argc Number of ZMP commands being sent.
|
||||
* \param argv Array of argument strings.
|
||||
*/
|
||||
extern void telnet_send_zmp(telnet_t *telnet, size_t argc, const char **argv);
|
||||
|
||||
/*!
|
||||
* \brief Send a ZMP command.
|
||||
*
|
||||
* Arguments are listed out in var-args style. After the last argument, a
|
||||
* NULL pointer must be passed in as a sentinel value.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
*/
|
||||
extern void telnet_send_zmpv(telnet_t *telnet, ...) TELNET_GNU_SENTINEL;
|
||||
|
||||
/*!
|
||||
* \brief Send a ZMP command.
|
||||
*
|
||||
* See telnet_send_zmpv().
|
||||
*/
|
||||
extern void telnet_send_vzmpv(telnet_t *telnet, va_list va);
|
||||
|
||||
/*!
|
||||
* \brief Begin sending a ZMP command
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param cmd The first argument (command name) for the ZMP command.
|
||||
*/
|
||||
extern void telnet_begin_zmp(telnet_t *telnet, const char *cmd);
|
||||
|
||||
/*!
|
||||
* \brief Send a ZMP command argument.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
* \param arg Telnet argument string.
|
||||
*/
|
||||
extern void telnet_zmp_arg(telnet_t *telnet, const char *arg);
|
||||
|
||||
/*!
|
||||
* \brief Finish a ZMP command.
|
||||
*
|
||||
* This must be called after a call to telnet_begin_zmp() to finish a
|
||||
* ZMP argument list.
|
||||
*
|
||||
* \param telnet Telnet state tracker object.
|
||||
*/
|
||||
#define telnet_finish_zmp(telnet) telnet_finish_sb((telnet))
|
||||
|
||||
/* C++ support */
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* !defined(LIBTELNET_INCLUDE) */
|
||||
@@ -1,336 +0,0 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define LINEBUFFER_SIZE 256
|
||||
#define AWAIT_TIMEOUT 10
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <libtelnet.h>
|
||||
#include <lwip/def.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <telnet/server.h>
|
||||
|
||||
static const char* TAG = "telnet";
|
||||
static struct user_t users[CONFIG_TELNET_SERVER_MAX_CONNECTIONS + 1];
|
||||
|
||||
static void linebuffer_push(char* buffer, size_t size, int* linepos, char ch,
|
||||
void (*cb)(const char* line, size_t overflow, void* ud), void* ud)
|
||||
{
|
||||
/* CRLF -- line terminator */
|
||||
if (ch == '\n' && *linepos > 0 && buffer[*linepos - 1] == '\r') {
|
||||
/* NUL terminate (replaces \r in buffer), notify app, clear */
|
||||
buffer[*linepos - 1] = 0;
|
||||
cb(buffer, 0, ud);
|
||||
*linepos = 0;
|
||||
|
||||
/* CRNUL -- just a CR */
|
||||
}
|
||||
else if (ch == 0 && *linepos > 0 && buffer[*linepos - 1] == '\r') {
|
||||
/* do nothing, the CR is already in the buffer */
|
||||
|
||||
/* anything else (including technically invalid CR followed by
|
||||
* anything besides LF or NUL -- just buffer if we have room
|
||||
* \r
|
||||
*/
|
||||
}
|
||||
else if (*linepos != (int)size) {
|
||||
buffer[(*linepos)++] = ch;
|
||||
|
||||
/* buffer overflow */
|
||||
}
|
||||
else {
|
||||
/* terminate (NOTE: eats a byte), notify app, clear buffer */
|
||||
buffer[size - 1] = 0;
|
||||
cb(buffer, size - 1, ud);
|
||||
*linepos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _message(const char* from, const char* msg)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i != CONFIG_TELNET_SERVER_MAX_CONNECTIONS; ++i) {
|
||||
if (users[i].sock != -1 && users[i].name != 0 && strcmp(users[i].name, from) != 0) {
|
||||
telnet_printf(users[i].telnet, "%s: \"%s\"\n", from, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _broadcast(const char* from, const char* msg)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i != CONFIG_TELNET_SERVER_MAX_CONNECTIONS; ++i) {
|
||||
if (users[i].sock != -1) {
|
||||
telnet_printf(users[i].telnet, "%s: \"%s\"\n", from, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _send(int sock, const char* buffer, size_t size)
|
||||
{
|
||||
int rs;
|
||||
|
||||
/* ignore on invalid socket */
|
||||
if (sock == -1)
|
||||
return;
|
||||
|
||||
/* send data */
|
||||
while (size > 0) {
|
||||
if ((rs = send(sock, buffer, (int)size, 0)) == -1) {
|
||||
if (errno != EINTR && errno != ECONNRESET) {
|
||||
ESP_LOGW(TAG, "send() failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (rs == 0) {
|
||||
ESP_LOGE(TAG, "send() unexpectedly returned 0");
|
||||
return;
|
||||
}
|
||||
|
||||
/* update pointer and size to see if we've got more to send */
|
||||
buffer += rs;
|
||||
size -= rs;
|
||||
}
|
||||
}
|
||||
|
||||
/* process input line */
|
||||
static void _online(const char* line, size_t overflow, void* ud)
|
||||
{
|
||||
struct user_t* user = (struct user_t*)ud;
|
||||
int i;
|
||||
|
||||
(void)overflow;
|
||||
|
||||
/* if the user has no name, this is his "login" */
|
||||
if (user->name == 0) {
|
||||
/* must not be empty, must be at least 32 chars */
|
||||
if (strlen(line) == 0 || strlen(line) > 32) {
|
||||
telnet_printf(user->telnet, "Invalid name. Enter name: ");
|
||||
return;
|
||||
}
|
||||
|
||||
/* must not already exist */
|
||||
for (i = 0; i != CONFIG_TELNET_SERVER_MAX_CONNECTIONS; ++i) {
|
||||
if (users[i].name != 0 && strcmp(users[i].name, line) == 0) {
|
||||
telnet_printf(user->telnet, "Name already in use. Enter name: ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* keep name */
|
||||
user->name = strdup(line);
|
||||
telnet_printf(user->telnet, "Welcome, %s!\n", line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* execute a command, need to send to the system */
|
||||
// _message(user->name, line);
|
||||
}
|
||||
|
||||
static void _input(struct user_t* user, const char* buffer, size_t size)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; user->sock != -1 && i != size; ++i) {
|
||||
linebuffer_push(user->linebuf, sizeof(user->linebuf), &user->linepos, (char)buffer[i], _online, user);
|
||||
}
|
||||
}
|
||||
|
||||
static void _event_handler(telnet_t* telnet, telnet_event_t* ev, void* user_data)
|
||||
{
|
||||
struct user_t* user = (struct user_t*)user_data;
|
||||
|
||||
switch (ev->type) {
|
||||
/* data received */
|
||||
case TELNET_EV_DATA:
|
||||
_input(user, ev->data.buffer, ev->data.size);
|
||||
// telnet_negotiate(telnet, TELNET_WONT, TELNET_TELOPT_ECHO);
|
||||
// telnet_negotiate(telnet, TELNET_WILL, TELNET_TELOPT_ECHO);
|
||||
break;
|
||||
/* data must be sent */
|
||||
case TELNET_EV_SEND: _send(user->sock, ev->data.buffer, ev->data.size); break;
|
||||
/* enable compress2 if accepted by client */
|
||||
case TELNET_EV_DO:
|
||||
if (ev->neg.telopt == TELNET_TELOPT_COMPRESS2)
|
||||
telnet_begin_compress2(telnet);
|
||||
break;
|
||||
/* error */
|
||||
case TELNET_EV_ERROR:
|
||||
close(user->sock);
|
||||
user->sock = -1;
|
||||
if (user->name != 0) {
|
||||
_message(user->name, "** HAS HAD AN ERROR **");
|
||||
free(user->name);
|
||||
user->name = 0;
|
||||
}
|
||||
telnet_free(user->telnet);
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void telnet_task(void* arg)
|
||||
{
|
||||
static char buffer[512];
|
||||
static struct sockaddr_in addr;
|
||||
static telnet_server_config_t config;
|
||||
|
||||
// save the configuration
|
||||
memcpy(&config, arg, sizeof(telnet_server_config_t));
|
||||
|
||||
int listen_sock;
|
||||
int client_sock;
|
||||
int rs;
|
||||
int i;
|
||||
socklen_t addrlen;
|
||||
struct pollfd pfd[config.max_connections + 1];
|
||||
|
||||
/* initialize data structures */
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
memset(users, 0, sizeof(users));
|
||||
for (i = 0; i != config.max_connections; ++i) {
|
||||
users[i].sock = -1;
|
||||
}
|
||||
|
||||
/* create listening socket */
|
||||
if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
ESP_LOGE(TAG, "socket() failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
/* reuse address option */
|
||||
rs = 1;
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&rs, sizeof(rs));
|
||||
|
||||
/* bind to listening addr/port */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons(config.port);
|
||||
if (bind(listen_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||
ESP_LOGE(TAG, "bind() failed: %s", strerror(errno));
|
||||
close(listen_sock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* listen for clients */
|
||||
if (listen(listen_sock, 3) == -1) {
|
||||
ESP_LOGE(TAG, "listen() failed: %s", strerror(errno));
|
||||
close(listen_sock);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Telnet server listening on port %d", config.port);
|
||||
|
||||
/* initialize listening descriptors */
|
||||
pfd[config.max_connections].fd = listen_sock;
|
||||
pfd[config.max_connections].events = POLLIN;
|
||||
|
||||
/* loop for ever */
|
||||
while (true) {
|
||||
/* prepare for poll */
|
||||
for (i = 0; i != config.max_connections; ++i) {
|
||||
if (users[i].sock != -1) {
|
||||
pfd[i].fd = users[i].sock;
|
||||
pfd[i].events = POLLIN;
|
||||
}
|
||||
else {
|
||||
pfd[i].fd = -1;
|
||||
pfd[i].events = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* poll */
|
||||
rs = poll(pfd, config.max_connections + 1, AWAIT_TIMEOUT);
|
||||
if (rs == -1 && errno != EINTR) {
|
||||
ESP_LOGE(TAG, "poll() failed: %s", strerror(errno));
|
||||
close(listen_sock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* new connection */
|
||||
if (pfd[config.max_connections].revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | POLLERR | POLLHUP)) {
|
||||
/* acept the sock */
|
||||
ESP_LOGW(TAG, "New connection");
|
||||
addrlen = sizeof(addr);
|
||||
if ((client_sock = accept(listen_sock, (struct sockaddr*)&addr, &addrlen)) == -1) {
|
||||
ESP_LOGE(TAG, "accept() failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Connection received");
|
||||
|
||||
/* find a free user */
|
||||
for (i = 0; i != config.max_connections; ++i) {
|
||||
if (users[i].sock == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == config.max_connections) {
|
||||
ESP_LOGV(TAG, " rejected (too many users)");
|
||||
_send(client_sock, "Too many users.\n", 16);
|
||||
close(client_sock);
|
||||
}
|
||||
|
||||
/* init, welcome */
|
||||
users[i].sock = client_sock;
|
||||
users[i].telnet = telnet_init(config.telnet_opts, _event_handler, 0, &users[i]);
|
||||
telnet_negotiate(users[i].telnet, TELNET_WILL, TELNET_TELOPT_COMPRESS2);
|
||||
telnet_printf(users[i].telnet, "Enter name: ");
|
||||
|
||||
// telnet_negotiate(users[i].telnet, TELNET_WILL, TELNET_TELOPT_ECHO);
|
||||
}
|
||||
|
||||
/* read from client */
|
||||
for (i = 0; i != config.max_connections; ++i) {
|
||||
/* skip users that aren't actually connected */
|
||||
if (users[i].sock == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pfd[i].revents & (POLLIN | POLLERR | POLLHUP)) {
|
||||
if ((rs = recv(users[i].sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||
telnet_recv(users[i].telnet, buffer, rs);
|
||||
}
|
||||
else if (rs == 0) {
|
||||
ESP_LOGV(TAG, "Connection closed.");
|
||||
close(users[i].sock);
|
||||
users[i].sock = -1;
|
||||
if (users[i].name != 0) {
|
||||
// _message(users[i].name, "** HAS DISCONNECTED **");
|
||||
free(users[i].name);
|
||||
users[i].name = 0;
|
||||
}
|
||||
telnet_free(users[i].telnet);
|
||||
}
|
||||
else if (errno != EINTR) {
|
||||
ESP_LOGE(TAG, "recv(client) failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TaskHandle_t xHandle = NULL;
|
||||
|
||||
esp_err_t telnet_server_create(telnet_server_config_t* config)
|
||||
{
|
||||
if (config == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
BaseType_t xReturned = xTaskCreate(telnet_task, "telnet_task", config->stack_size, config, config->task_priority, &xHandle);
|
||||
if (xReturned == pdPASS) {
|
||||
ESP_LOGV(TAG, "Telnet task created successfully.");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "Failed to create telnet task.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, , 0x4000,
|
||||
otadata, data, ota, , 0x2000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
ota_0, app, ota_0, , 1536K,
|
||||
ota_1, app, ota_1, , 1536K,
|
||||
spiffs, data, spiffs, , 936K,
|
||||
|
+30
-20
@@ -2,6 +2,32 @@
|
||||
# Compiler options
|
||||
#
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME="ChaosWatch"
|
||||
|
||||
#
|
||||
# Example Ethernet Configuration
|
||||
#
|
||||
CONFIG_EXAMPLE_USE_SPI_ETHERNET=y
|
||||
CONFIG_EXAMPLE_SPI_ETHERNETS_NUM=1
|
||||
# CONFIG_EXAMPLE_USE_DM9051 is not set
|
||||
# CONFIG_EXAMPLE_USE_KSZ8851SNL is not set
|
||||
CONFIG_EXAMPLE_USE_W5500=y
|
||||
CONFIG_EXAMPLE_ETH_SPI_HOST=1
|
||||
CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO=6
|
||||
CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO=7
|
||||
CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO=2
|
||||
CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ=16
|
||||
CONFIG_EXAMPLE_ETH_SPI_CS0_GPIO=3
|
||||
CONFIG_EXAMPLE_ETH_SPI_INT0_GPIO=4
|
||||
CONFIG_EXAMPLE_ETH_SPI_POLLING0_MS=0
|
||||
CONFIG_EXAMPLE_ETH_SPI_PHY_RST0_GPIO=-1
|
||||
CONFIG_EXAMPLE_ETH_SPI_PHY_ADDR0=1
|
||||
# end of Example Ethernet Configuration
|
||||
|
||||
#
|
||||
# Ethernet
|
||||
#
|
||||
CONFIG_ETH_SPI_ETHERNET_W5500=y
|
||||
|
||||
#
|
||||
# Wi-Fi
|
||||
@@ -11,27 +37,11 @@ CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
#
|
||||
# LWIP
|
||||
#
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME="LeoLights"
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME="ChaosWatch"
|
||||
|
||||
#
|
||||
# Ethernet
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_ETH_PHY_LAN87XX=y
|
||||
|
||||
CONFIG_ETH_MDC_GPIO=23
|
||||
CONFIG_ETH_MDIO_GPIO=33
|
||||
CONFIG_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_ETH_PHY_ADDR=1
|
||||
|
||||
#
|
||||
# OTA over plain HTTP (no TLS server in use yet)
|
||||
#
|
||||
CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP=y
|
||||
|
||||
# Enable filesystem
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ set(EXTRA_COMPONENT_DIRS
|
||||
)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(IntegrationTest)
|
||||
project(INTEGRATION_TESTS_FW)
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
dependencies:
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 5.3.0
|
||||
manifest_hash: c4f4ec05313d427eb56c633f78ce213e553379725bf2af3c511665f930571beb
|
||||
target: esp32c6
|
||||
version: 1.0.0
|
||||
@@ -2,6 +2,8 @@
|
||||
* @file watchMain.cpp
|
||||
* @author Gustice
|
||||
* @brief ChaosWatch Application
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
/// NOTE: Create IDF shell navigate to directory ("test/integration")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Compiler options
|
||||
#
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
|
||||
#
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||
|
||||
#
|
||||
# Log output
|
||||
#
|
||||
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y
|
||||
CONFIG_LOG_MAXIMUM_LEVEL=4
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"cmake.cmakePath": "C:/msys64/usr/bin/cmake.exe"
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(UnitTests)
|
||||
include(../../core/test/unitOnHost/test_core.cmake)
|
||||
|
||||
UnitTestSetup()
|
||||
enable_testing()
|
||||
|
||||
project(UnitTests)
|
||||
addSubDirs_ofRoot("${CMAKE_CURRENT_LIST_DIR}/../../components")
|
||||
addSubDirs_ofRoot("${CMAKE_CURRENT_LIST_DIR}/../../core/components")
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../core/test/unitOnHost/hwMock" hwMock)
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../core/test/unitOnHost/netMock" netMock)
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../core/test/unitOnHost/osMock" osMock)
|
||||
|
||||
@@ -14,7 +14,7 @@ set(EXTRA_COMPONENT_DIRS
|
||||
# - when invoking CMake directly: cmake -D TEST_COMPONENTS="xxxxx" ..
|
||||
# - when using idf.py: idf.py -T xxxxx build
|
||||
#
|
||||
set(TEST_COMPONENTS "testable freeRtosApi hwHal spit" CACHE STRING "List of components to test" FORCE)
|
||||
set(TEST_COMPONENTS "testable freeRtosApi hwHal" CACHE STRING "List of components to test")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(unit_test)
|
||||
project(unit_test_test)
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
* @file unitTest.cpp
|
||||
* @author Gustice
|
||||
* @brief Unit/Integration-Test frame for hardware bound components
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
extern "C" { // This switch allows the ROS C-implementation to find this main
|
||||
void app_main(void);
|
||||
@@ -33,9 +33,5 @@ void app_main(void) {
|
||||
printf("# - run tagged with [tag], \n");
|
||||
printf("# - run all other than ![tag])\n");
|
||||
printf("# Exit with 'Ctrl-]'\n");
|
||||
// unity_run_menu(); // Watchdog needs to
|
||||
|
||||
while (true) {
|
||||
vTaskDelay(10);
|
||||
}
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user