From 741aaef61d427b95fafaa561ee844188f0f794ee Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 2 Feb 2025 13:27:53 +0100 Subject: [PATCH] added zedmd-client, less strict handshake --- CMakeLists.txt | 179 ++++++++--- platforms/linux/aarch64/external.sh | 18 ++ platforms/linux/x64/external.sh | 18 ++ platforms/macos/arm64/external.sh | 20 ++ platforms/macos/x64/external.sh | 20 ++ platforms/win/x64/cargs/001.patch | 38 +++ platforms/win/x64/external.sh | 20 ++ platforms/win/x86/external.sh | 20 ++ src/ZeDMD.cpp | 157 +++++++++- src/ZeDMD.h | 91 ++++++ src/ZeDMDComm.cpp | 2 +- src/ZeDMDComm.h | 11 + src/client.cpp | 443 ++++++++++++++++++++++++++++ third-party/include/cargs.h | 175 +++++++++++ 14 files changed, 1169 insertions(+), 43 deletions(-) create mode 100644 platforms/win/x64/cargs/001.patch create mode 100644 src/client.cpp create mode 100644 third-party/include/cargs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d86d845..926cfc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,37 +141,76 @@ if(BUILD_SHARED) install(FILES src/ZeDMD.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include) if(PLATFORM STREQUAL "win" OR PLATFORM STREQUAL "macos" OR PLATFORM STREQUAL "linux") - add_executable(zedmd_test + add_executable(zedmd-test src/test.cpp ) - target_link_libraries(zedmd_test PUBLIC zedmd_shared) + target_link_libraries(zedmd-test PUBLIC zedmd_shared) if(POST_BUILD_COPY_EXT_LIBS) if(PLATFORM STREQUAL "win") if(ARCH STREQUAL "x64") - add_custom_command(TARGET zedmd_test POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp64.dll" "$" + add_custom_command(TARGET zedmd-test POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp64.dll" "$" ) else() - add_custom_command(TARGET zedmd_test POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp.dll" "$" + add_custom_command(TARGET zedmd-test POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp.dll" "$" ) endif() elseif(PLATFORM STREQUAL "macos") - add_custom_command(TARGET zedmd_test POST_BUILD - COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.dylib" "$" + add_custom_command(TARGET zedmd-test POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.dylib" "$" ) elseif(PLATFORM STREQUAL "linux") - add_custom_command(TARGET zedmd_test POST_BUILD - COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so" "$" - COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so.*" "$" + add_custom_command(TARGET zedmd-test POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so" "$" + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so.*" "$" + ) + endif() + endif() + + add_executable(zedmd-client + src/client.cpp + ) + + target_link_libraries(zedmd-client PUBLIC zedmd_shared cargs) + + if(POST_BUILD_COPY_EXT_LIBS) + if(PLATFORM STREQUAL "win") + if(ARCH STREQUAL "x64") + add_custom_command(TARGET zedmd-client POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/cargs64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/cargs64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp64.dll" "$" + ) + else() + add_custom_command(TARGET zedmd-client POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/cargs.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/cargs.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp.dll" "$" + ) + endif() + elseif(PLATFORM STREQUAL "macos") + add_custom_command(TARGET zedmd-client POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.dylib" "$" + ) + elseif(PLATFORM STREQUAL "linux") + add_custom_command(TARGET zedmd-client POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so" "$" + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so.*" "$" ) endif() endif() @@ -199,58 +238,118 @@ if(BUILD_STATIC) install(FILES src/ZeDMD.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include) if(PLATFORM STREQUAL "win" OR PLATFORM STREQUAL "macos" OR PLATFORM STREQUAL "linux") - add_executable(zedmd_test_s + add_executable(zedmd-test-portable src/test.cpp ) if(PLATFORM STREQUAL "win") - target_link_directories(zedmd_test_s PUBLIC + target_link_directories(zedmd-test-portable PUBLIC + third-party/build-libs/${PLATFORM}/${ARCH} + third-party/runtime-libs/${PLATFORM}/${ARCH} + ) + + if(ARCH STREQUAL "x64") + target_link_libraries(zedmd-test-portable PUBLIC zedmd_static cargs64 libserialport64 sockpp64 ws2_32) + else() + target_link_libraries(zedmd-test-portable PUBLIC zedmd_static cargs libserialport sockpp ws2_32) + endif() + elseif(PLATFORM STREQUAL "macos") + target_link_directories(zedmd-test-portable PUBLIC + third-party/runtime-libs/${PLATFORM}/${ARCH} + ) + target_link_libraries(zedmd-test-portable PUBLIC zedmd_static cargs serialport sockpp) + elseif(PLATFORM STREQUAL "linux") + target_link_directories(zedmd-test-portable PUBLIC + third-party/runtime-libs/${PLATFORM}/${ARCH} + ) + target_link_libraries(zedmd-test-portable PUBLIC zedmd_static cargs serialport sockpp) + endif() + + if(POST_BUILD_COPY_EXT_LIBS) + if(PLATFORM STREQUAL "win") + if(ARCH STREQUAL "x64") + add_custom_command(TARGET zedmd-test-portable POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp64.dll" "$" + ) + else() + add_custom_command(TARGET zedmd-test-portable POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp.dll" "$" + ) + endif() + elseif(PLATFORM STREQUAL "macos") + add_custom_command(TARGET zedmd-test-portable POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.dylib" "$" + ) + elseif(PLATFORM STREQUAL "linux") + add_custom_command(TARGET zedmd-test-portable POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so" "$" + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so.*" "$" + ) + endif() + endif() + + add_executable(zedmd-client-portable + src/client.cpp + ) + + if(PLATFORM STREQUAL "win") + target_link_directories(zedmd-client-portable PUBLIC third-party/build-libs/${PLATFORM}/${ARCH} third-party/runtime-libs/${PLATFORM}/${ARCH} ) if(ARCH STREQUAL "x64") - target_link_libraries(zedmd_test_s PUBLIC zedmd_static libserialport64 sockpp64 ws2_32) + target_link_libraries(zedmd-client-portable PUBLIC zedmd_static cargs64 libserialport64 sockpp64 ws2_32) else() - target_link_libraries(zedmd_test_s PUBLIC zedmd_static libserialport sockpp ws2_32) + target_link_libraries(zedmd-client-portable PUBLIC zedmd_static cargs libserialport sockpp ws2_32) endif() elseif(PLATFORM STREQUAL "macos") - target_link_directories(zedmd_test_s PUBLIC + target_link_directories(zedmd-client-portable PUBLIC third-party/runtime-libs/${PLATFORM}/${ARCH} ) - target_link_libraries(zedmd_test_s PUBLIC zedmd_static serialport sockpp) + target_link_libraries(zedmd-client-portable PUBLIC zedmd_static cargs serialport sockpp) elseif(PLATFORM STREQUAL "linux") - target_link_directories(zedmd_test_s PUBLIC + target_link_directories(zedmd-client-portable PUBLIC third-party/runtime-libs/${PLATFORM}/${ARCH} ) - target_link_libraries(zedmd_test_s PUBLIC zedmd_static serialport sockpp) + target_link_libraries(zedmd-client-portable PUBLIC zedmd_static cargs serialport sockpp) endif() if(POST_BUILD_COPY_EXT_LIBS) if(PLATFORM STREQUAL "win") if(ARCH STREQUAL "x64") - add_custom_command(TARGET zedmd_test_s POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp64.dll" "$" + add_custom_command(TARGET zedmd-client-portable POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/cargs64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/cargs64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp64.dll" "$" ) else() - add_custom_command(TARGET zedmd_test_s POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp.dll" "$" + add_custom_command(TARGET zedmd-client-portable POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/cargs.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/cargs.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/sockpp.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/sockpp.dll" "$" ) endif() elseif(PLATFORM STREQUAL "macos") - add_custom_command(TARGET zedmd_test_s POST_BUILD - COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.dylib" "$" + add_custom_command(TARGET zedmd-client-portable POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.dylib" "$" ) elseif(PLATFORM STREQUAL "linux") - add_custom_command(TARGET zedmd_test_s POST_BUILD - COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so" "$" - COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so.*" "$" + add_custom_command(TARGET zedmd-client-portable POST_BUILD + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so" "$" + COMMAND cp -a "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/*.so.*" "$" ) endif() endif() diff --git a/platforms/linux/aarch64/external.sh b/platforms/linux/aarch64/external.sh index 8fe6ef1..537f53a 100755 --- a/platforms/linux/aarch64/external.sh +++ b/platforms/linux/aarch64/external.sh @@ -2,6 +2,7 @@ set -e +CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBSERIALPORT_SHA=21b3dfe5f68c205be4086469335fd2fc2ce11ed2 LIBFRAMEUTIL_SHA=30048ca23d41ca0a8f7d5ab75d3f646a19a90182 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f @@ -9,6 +10,7 @@ SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f NUM_PROCS=$(nproc) echo "Building libraries..." +echo " CARGS_SHA: ${CARGS_SHA}" echo " LIBSERIALPORT_SHA: ${LIBSERIALPORT_SHA}" echo " LIBFRAMEUTIL_SHA: ${LIBFRAMEUTIL_SHA}" echo " SOCKPP_SHA: ${SOCKPP_SHA}" @@ -23,6 +25,22 @@ rm -rf external mkdir external cd external +# +# build cargs and copy to external +# + +curl -sL https://github.com/likle/cargs/archive/${CARGS_SHA}.zip -o cargs.zip +unzip cargs.zip +cd cargs-${CARGS_SHA} +cmake \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -B build +cmake --build build -- -j${NUM_PROCS} +cp include/cargs.h ../../third-party/include/ +cp -a build/*.so ../../third-party/runtime-libs/linux/aarch64/ +cd .. + # # build libserialport and copy to platform/arch # diff --git a/platforms/linux/x64/external.sh b/platforms/linux/x64/external.sh index c9d45f6..c2302a0 100755 --- a/platforms/linux/x64/external.sh +++ b/platforms/linux/x64/external.sh @@ -2,6 +2,7 @@ set -e +CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBSERIALPORT_SHA=21b3dfe5f68c205be4086469335fd2fc2ce11ed2 LIBFRAMEUTIL_SHA=30048ca23d41ca0a8f7d5ab75d3f646a19a90182 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f @@ -9,6 +10,7 @@ SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f NUM_PROCS=$(nproc) echo "Building libraries..." +echo " CARGS_SHA: ${CARGS_SHA}" echo " LIBSERIALPORT_SHA: ${LIBSERIALPORT_SHA}" echo " LIBFRAMEUTIL_SHA: ${LIBFRAMEUTIL_SHA}" echo " SOCKPP_SHA: ${SOCKPP_SHA}" @@ -23,6 +25,22 @@ rm -rf external mkdir external cd external +# +# build cargs and copy to external +# + +curl -sL https://github.com/likle/cargs/archive/${CARGS_SHA}.zip -o cargs.zip +unzip cargs.zip +cd cargs-${CARGS_SHA} +cmake \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -B build +cmake --build build -- -j${NUM_PROCS} +cp include/cargs.h ../../third-party/include/ +cp -a build/*.so ../../third-party/runtime-libs/linux/x64/ +cd .. + # # build libserialport and copy to platform/arch # diff --git a/platforms/macos/arm64/external.sh b/platforms/macos/arm64/external.sh index 4e1390a..e5da573 100755 --- a/platforms/macos/arm64/external.sh +++ b/platforms/macos/arm64/external.sh @@ -2,6 +2,7 @@ set -e +CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBSERIALPORT_SHA=21b3dfe5f68c205be4086469335fd2fc2ce11ed2 LIBFRAMEUTIL_SHA=30048ca23d41ca0a8f7d5ab75d3f646a19a90182 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f @@ -9,6 +10,7 @@ SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f NUM_PROCS=$(sysctl -n hw.ncpu) echo "Building libraries..." +echo " CARGS_SHA: ${CARGS_SHA}" echo " LIBSERIALPORT_SHA: ${LIBSERIALPORT_SHA}" echo " LIBFRAMEUTIL_SHA: ${LIBFRAMEUTIL_SHA}" echo " SOCKPP_SHA: ${SOCKPP_SHA}" @@ -23,6 +25,24 @@ rm -rf external mkdir external cd external +# +# build cargs and copy to external +# + +curl -sL https://github.com/likle/cargs/archive/${CARGS_SHA}.zip -o cargs.zip +unzip cargs.zip +cd cargs-${CARGS_SHA} +cmake \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -B build +cmake --build build -- -j${NUM_PROCS} +cp include/cargs.h ../../third-party/include/ +cp -a build/*.dylib ../../third-party/runtime-libs/macos/arm64/ +cd .. + # # build libserialport and copy to platform/arch # diff --git a/platforms/macos/x64/external.sh b/platforms/macos/x64/external.sh index d9433d2..0ab048a 100755 --- a/platforms/macos/x64/external.sh +++ b/platforms/macos/x64/external.sh @@ -2,6 +2,7 @@ set -e +CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBSERIALPORT_SHA=21b3dfe5f68c205be4086469335fd2fc2ce11ed2 LIBFRAMEUTIL_SHA=30048ca23d41ca0a8f7d5ab75d3f646a19a90182 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f @@ -9,6 +10,7 @@ SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f NUM_PROCS=$(sysctl -n hw.ncpu) echo "Building libraries..." +echo " CARGS_SHA: ${CARGS_SHA}" echo " LIBSERIALPORT_SHA: ${LIBSERIALPORT_SHA}" echo " LIBFRAMEUTIL_SHA: ${LIBFRAMEUTIL_SHA}" echo " SOCKPP_SHA: ${SOCKPP_SHA}" @@ -23,6 +25,24 @@ rm -rf external mkdir external cd external +# +# build cargs and copy to external +# + +curl -sL https://github.com/likle/cargs/archive/${CARGS_SHA}.zip -o cargs.zip +unzip cargs.zip +cd cargs-${CARGS_SHA} +cmake \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_OSX_ARCHITECTURES=x86_64 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -B build +cmake --build build -- -j${NUM_PROCS} +cp include/cargs.h ../../third-party/include/ +cp -a build/*.dylib ../../third-party/runtime-libs/macos/x64/ +cd .. + # # build libserialport and copy to platform/arch # diff --git a/platforms/win/x64/cargs/001.patch b/platforms/win/x64/cargs/001.patch new file mode 100644 index 0000000..3bde423 --- /dev/null +++ b/platforms/win/x64/cargs/001.patch @@ -0,0 +1,38 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b6f828f..6be0845 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -18,7 +18,7 @@ + set(CMAKE_C_STANDARD 11) + + # setup target and directory names +-set(LIBRARY_TARGET "cargs") ++set(LIBRARY_TARGET "cargs64") + set(INCLUDE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include") + set(SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src") + +@@ -51,12 +51,12 @@ + $ + $ + ) +-set_target_properties(cargs PROPERTIES PUBLIC_HEADER "${INCLUDE_DIRECTORY}/cargs.h") +-set_target_properties(cargs PROPERTIES DEFINE_SYMBOL CAG_EXPORTS) ++set_target_properties(cargs64 PROPERTIES PUBLIC_HEADER "${INCLUDE_DIRECTORY}/cargs.h") ++set_target_properties(cargs64 PROPERTIES DEFINE_SYMBOL CAG_EXPORTS) + + # add shared library macro + if(BUILD_SHARED_LIBS) +- target_compile_definitions(cargs PUBLIC CAG_SHARED) ++ target_compile_definitions(cargs64 PUBLIC CAG_SHARED) + endif() + + # add tests +@@ -104,7 +104,7 @@ + COMPATIBILITY SameMajorVersion) + + # installing +-install(TARGETS cargs ++install(TARGETS cargs64 + EXPORT CargsTargets) + + install(FILES diff --git a/platforms/win/x64/external.sh b/platforms/win/x64/external.sh index b28afac..4a5b305 100755 --- a/platforms/win/x64/external.sh +++ b/platforms/win/x64/external.sh @@ -2,11 +2,13 @@ set -e +CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBSERIALPORT_SHA=21b3dfe5f68c205be4086469335fd2fc2ce11ed2 LIBFRAMEUTIL_SHA=30048ca23d41ca0a8f7d5ab75d3f646a19a90182 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f echo "Building libraries..." +echo " CARGS_SHA: ${CARGS_SHA}" echo " LIBSERIALPORT_SHA: ${LIBSERIALPORT_SHA}" echo " LIBFRAMEUTIL_SHA: ${LIBFRAMEUTIL_SHA}" echo " SOCKPP_SHA: ${SOCKPP_SHA}" @@ -20,6 +22,24 @@ rm -rf external mkdir external cd external +# +# build cargs and copy to external +# + +curl -sL https://github.com/likle/cargs/archive/${CARGS_SHA}.zip -o cargs.zip +unzip cargs.zip +cd cargs-${CARGS_SHA} +patch -p1 < ../../platforms/win/x64/cargs/001.patch +cmake \ + -G "Visual Studio 17 2022" \ + -DBUILD_SHARED_LIBS=ON \ + -B build +cmake --build build --config ${BUILD_TYPE} +cp include/cargs.h ../../third-party/include/ +cp build/${BUILD_TYPE}/cargs64.lib ../../third-party/build-libs/win/x64/ +cp build/${BUILD_TYPE}/cargs64.dll ../../third-party/runtime-libs/win/x64/ +cd .. + # # build libserialport and copy to platform/arch # diff --git a/platforms/win/x86/external.sh b/platforms/win/x86/external.sh index 6a438d8..8446b91 100755 --- a/platforms/win/x86/external.sh +++ b/platforms/win/x86/external.sh @@ -2,11 +2,13 @@ set -e +CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBSERIALPORT_SHA=21b3dfe5f68c205be4086469335fd2fc2ce11ed2 LIBFRAMEUTIL_SHA=30048ca23d41ca0a8f7d5ab75d3f646a19a90182 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f echo "Building libraries..." +echo " CARGS_SHA: ${CARGS_SHA}" echo " LIBSERIALPORT_SHA: ${LIBSERIALPORT_SHA}" echo " LIBFRAMEUTIL_SHA: ${LIBFRAMEUTIL_SHA}" echo " SOCKPP_SHA: ${SOCKPP_SHA}" @@ -20,6 +22,24 @@ rm -rf external mkdir external cd external +# +# build cargs and copy to external +# + +curl -sL https://github.com/likle/cargs/archive/${CARGS_SHA}.zip -o cargs.zip +unzip cargs.zip +cd cargs-${CARGS_SHA} +cmake \ + -G "Visual Studio 17 2022" \ + -DBUILD_SHARED_LIBS=ON \ + -A Win32 \ + -B build +cmake --build build --config ${BUILD_TYPE} +cp include/cargs.h ../../third-party/include/ +cp build/${BUILD_TYPE}/cargs.lib ../../third-party/build-libs/win/x86/ +cp build/${BUILD_TYPE}/cargs.dll ../../third-party/runtime-libs/win/x86/ +cd .. + # # build libserialport and copy to platform/arch # diff --git a/src/ZeDMD.cpp b/src/ZeDMD.cpp index 00917ad..103d529 100644 --- a/src/ZeDMD.cpp +++ b/src/ZeDMD.cpp @@ -169,12 +169,135 @@ void ZeDMD::DisableDebug() void ZeDMD::SetRGBOrder(uint8_t rgbOrder) { - if (m_usb) m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGBOrder, rgbOrder); + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGBOrder, rgbOrder); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGBOrder, rgbOrder); + } } void ZeDMD::SetBrightness(uint8_t brightness) { - if (m_usb) m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::Brightness, brightness); + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::Brightness, brightness); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::Brightness, brightness); + } +} + +void ZeDMD::SetPanelClockPhase(uint8_t clockPhase) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetClkphase, clockPhase); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetClkphase, clockPhase); + } +} + +void ZeDMD::SetPanelI2sSpeed(uint8_t i2sSpeed) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetI2sspeed, i2sSpeed); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetI2sspeed, i2sSpeed); + } +} + +void ZeDMD::SetPanelLatchBlanking(uint8_t latchBlanking) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetLatchBlanking, latchBlanking); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetLatchBlanking, latchBlanking); + } +} + +void ZeDMD::SetPanelMinRefreshRate(uint8_t minRefreshRate) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetMinRefreshRate, minRefreshRate); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetMinRefreshRate, minRefreshRate); + } +} + +void ZeDMD::SetPanelDriver(uint8_t driver) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetDriver, driver); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetDriver, driver); + } +} + +void ZeDMD::SetTransport(uint8_t transport) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetTransport, transport); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetTransport, transport); + } +} + +void ZeDMD::SetUdpDelay(uint8_t udpDelay) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetUdpDelay, udpDelay); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetUdpDelay, udpDelay); + } +} + +void ZeDMD::SetUsbPackageSize(uint16_t usbPackageSize) +{ + uint8_t multiplier = (uint8_t)(usbPackageSize / 32); + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetUsbPackageSizeMultiplier, multiplier); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetUsbPackageSizeMultiplier, multiplier); + } +} + +void ZeDMD::SetYOffset(uint8_t yOffset) +{ + if (m_usb) + { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetYOffset, yOffset); + } + else if (m_wifi) + { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::SetYOffset, yOffset); + } } void ZeDMD::SaveSettings() @@ -509,6 +632,36 @@ ZEDMDAPI void ZeDMD_SetWiFiPassword(ZeDMD* pZeDMD, const char* const password) return pZeDMD->SetWiFiPassword(password); } +ZEDMDAPI void ZeDMD_SetPanelClockPhase(ZeDMD* pZeDMD, uint8_t clockPhase) +{ + return pZeDMD->SetPanelClockPhase(clockPhase); +} + +ZEDMDAPI void ZeDMD_SetPanelI2sSpeed(ZeDMD* pZeDMD, uint8_t i2sSpeed) { return pZeDMD->SetPanelI2sSpeed(i2sSpeed); } + +ZEDMDAPI void ZeDMD_SetPanelLatchBlanking(ZeDMD* pZeDMD, uint8_t latchBlanking) +{ + return pZeDMD->SetPanelLatchBlanking(latchBlanking); +} + +ZEDMDAPI void ZeDMD_SetPanelMinRefreshRate(ZeDMD* pZeDMD, uint8_t minRefreshRate) +{ + return pZeDMD->SetPanelMinRefreshRate(minRefreshRate); +} + +ZEDMDAPI void ZeDMD_SetPanelDriver(ZeDMD* pZeDMD, uint8_t driver) { return pZeDMD->SetPanelDriver(driver); } + +ZEDMDAPI void ZeDMD_SetTransport(ZeDMD* pZeDMD, uint8_t transport) { return pZeDMD->SetTransport(transport); } + +ZEDMDAPI void ZeDMD_SetUdpDelay(ZeDMD* pZeDMD, uint8_t udpDelay) { return pZeDMD->SetUdpDelay(udpDelay); } + +ZEDMDAPI void ZeDMD_SetUsbPackageSize(ZeDMD* pZeDMD, uint16_t usbPackageSize) +{ + return pZeDMD->SetUsbPackageSize(usbPackageSize); +} + +ZEDMDAPI void ZeDMD_SetYOffset(ZeDMD* pZeDMD, uint8_t yOffset) { return pZeDMD->SetYOffset(yOffset); } + ZEDMDAPI void ZeDMD_SetWiFiPort(ZeDMD* pZeDMD, int port) { return pZeDMD->SetWiFiPort(port); } ZEDMDAPI void ZeDMD_ClearScreen(ZeDMD* pZeDMD) { return pZeDMD->ClearScreen(); } diff --git a/src/ZeDMD.h b/src/ZeDMD.h index e795f58..54b1f3b 100644 --- a/src/ZeDMD.h +++ b/src/ZeDMD.h @@ -265,6 +265,88 @@ class ZEDMDAPI ZeDMD */ void SetWiFiPort(int port); + /** @brief Set the panel clock phase + * + * Set the clock phase of the LED panels. + * @see https://github.com/PPUC/ZeDMD + * + * @param clockPhase a value between 0 and 1 + */ + void SetPanelClockPhase(uint8_t clockPhase); + + /** @brief Set the panel i2s speed + * + * Set the i2s speed of the LED panels. + * @see https://github.com/PPUC/ZeDMD + * + * @param i2sspeed a value of 8, 16 or 20 + */ + void SetPanelI2sSpeed(uint8_t i2sSpeed); + + /** @brief Set the panel latch blanking + * + * Set the latch blanking of the LED panels. + * @see https://github.com/PPUC/ZeDMD + * + * @param clkphase a value between 0 and 4 + */ + void SetPanelLatchBlanking(uint8_t latchBlanking); + + /** @brief Set the panel minimla refresh rate + * + * Set the minimal refresh rate of the LED panels. + * @see https://github.com/PPUC/ZeDMD + * + * @param minRefreshRate a value between 0 and 1 + */ + void SetPanelMinRefreshRate(uint8_t minRefreshRate); + + /** @brief Set the panel driver + * + * Set the driver of the LED panels. + * @see https://github.com/PPUC/ZeDMD + * + * @param driver a value between 0 and 6; 0(SHIFTREG), 1(FM6124), 2(FM6126A), 3(ICN2038S), 4(MBI5124), 5(SM5266P), + * 6(DP3246_SM5368) + */ + void SetPanelDriver(uint8_t driver); + + /** @brief Set the transport + * + * Set the transport of ZeDMD. Note, this is just to change ZeDMD's settings, not for connecting. + * @see https://github.com/PPUC/ZeDMD + * + * @param transport a value between 0 and 3; 0(USB), 1(UDP), 2(TCP), 3(SPI) + */ + void SetTransport(uint8_t transport); + + /** @brief Set the UDP delay + * + * Set the UDP Delay. + * @see https://github.com/PPUC/ZeDMD + * + * @param udpDelay a value between 0 and 9 + */ + void SetUdpDelay(uint8_t udpDelay); + + /** @brief Set the USB package size + * + * Set the USB package size. + * @see https://github.com/PPUC/ZeDMD + * + * @param usbPackageSize a value between 32 and 1920, but only multiple of 32 + */ + void SetUsbPackageSize(uint16_t usbPackageSize); + + /** @brief Set the Y-offset of 128x64 panels + * + * Set the Y-offset of 128x64 panels. + * @see https://github.com/PPUC/ZeDMD + * + * @param yOffset a value between 0 and 32 + */ + void SetYOffset(uint8_t yOffset); + /** @brief Save the current setting * * Saves all current setting within ZeDMD's EEPROM to be used @@ -368,6 +450,15 @@ extern "C" extern ZEDMDAPI void ZeDMD_SetWiFiSSID(ZeDMD* pZeDMD, const char* const ssid); extern ZEDMDAPI void ZeDMD_SetWiFiPassword(ZeDMD* pZeDMD, const char* const password); extern ZEDMDAPI void ZeDMD_SetWiFiPort(ZeDMD* pZeDMD, int port); + extern ZEDMDAPI void ZeDMD_SetPanelClockPhase(ZeDMD* pZeDMD, uint8_t clockPhase); + extern ZEDMDAPI void ZeDMD_SetPanelI2sSpeed(ZeDMD* pZeDMD, uint8_t i2sSpeed); + extern ZEDMDAPI void ZeDMD_SetPanelLatchBlanking(ZeDMD* pZeDMD, uint8_t latchBlanking); + extern ZEDMDAPI void ZeDMD_SetPanelMinRefreshRate(ZeDMD* pZeDMD, uint8_t minRefreshRate); + extern ZEDMDAPI void ZeDMD_SetPanelDriver(ZeDMD* pZeDMD, uint8_t driver); + extern ZEDMDAPI void ZeDMD_SetTransport(ZeDMD* pZeDMD, uint8_t transport); + extern ZEDMDAPI void ZeDMD_SetUdpDelay(ZeDMD* pZeDMD, uint8_t udpDelay); + extern ZEDMDAPI void ZeDMD_SetUsbPackageSize(ZeDMD* pZeDMD, uint16_t usbPackageSize); + extern ZEDMDAPI void ZeDMD_SetYOffset(ZeDMD* pZeDMD, uint8_t yOffset); extern ZEDMDAPI void ZeDMD_ClearScreen(ZeDMD* pZeDMD); extern ZEDMDAPI void ZeDMD_RenderRgb888(ZeDMD* pZeDMD, uint8_t* frame); diff --git a/src/ZeDMDComm.cpp b/src/ZeDMDComm.cpp index bea369d..13f8401 100644 --- a/src/ZeDMDComm.cpp +++ b/src/ZeDMDComm.cpp @@ -497,7 +497,7 @@ bool ZeDMDComm::Handshake(char* pDevice) data[FRAME_HEADER_SIZE + CTRL_CHARS_HEADER_SIZE + 3] = 0; // Compression flag int result = sp_blocking_write(m_pSerialPort, data, ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE, ZEDMD_COMM_SERIAL_WRITE_TIMEOUT); - if (result == ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE) + if (result >= ZEDMD_COMM_MIN_SERIAL_WRITE_AT_ONCE) { std::this_thread::sleep_for(std::chrono::milliseconds(200)); memset(data, 0, ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE); diff --git a/src/ZeDMDComm.h b/src/ZeDMDComm.h index c0d9e0b..2401488 100644 --- a/src/ZeDMDComm.h +++ b/src/ZeDMDComm.h @@ -29,6 +29,7 @@ #define ZEDMD_COMM_BAUD_RATE 921600 #define ZEDMD_S3_COMM_BAUD_RATE 2000000 +#define ZEDMD_COMM_MIN_SERIAL_WRITE_AT_ONCE 32 #define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 1920 #define ZEDMD_COMM_SERIAL_READ_TIMEOUT 16 @@ -60,6 +61,16 @@ typedef enum GetVersionBytes = 0x20, GetResolution = 0x21, + SetClkphase = 0x28, + SetI2sspeed = 0x29, + SetLatchBlanking = 0x2a, + SetMinRefreshRate = 0x2b, + SetDriver = 0x2c, + SetTransport = 0x2d, + SetUdpDelay = 0x2e, + SetUsbPackageSizeMultiplier = 0x2f, + SetYOffset = 0x30, + RGB565ZonesStream = 0x05, RenderRGB565Frame = 0x06, diff --git a/src/client.cpp b/src/client.cpp new file mode 100644 index 0000000..abd10ea --- /dev/null +++ b/src/client.cpp @@ -0,0 +1,443 @@ +/** + * ZeDMD command line client + * + * --help + * --version + * --port Serial port to connect. If omitted, auto-discovery will be used. + * --info Show information about ZeDMD. + * --ip-address IP address to connect. If omitted, auto-discovery will be used. + * --set-brightness 0..15 + * --set-debug 0,1 + * --set-panel-clkphase 0,1 + * --set-panel-driver 0(SHIFTREG),1(FM6124),2(FM6126A),3(ICN2038S),4(MBI5124),5(SM5266P),6(DP3246_SM5368) + * --set-panel-i2sspeed 8,16,20 + * --set-panel-latch-blanking 0,1,2,3,4 + * --set-panel-min-refresh-rate 30..120 + * --set-rgb-order 0..5 + * --set-transport 0(USB),1(UDP),2(TCP),3(SPI) + * --set-udp-delay 0..9 + * --set-usb-package-size 32..1920 (step 32) + * --set-wifi-ssid + * --set-wifi-password + * --set-wifi-port + * --set-y-offset 0..32 + * + * @todo + * --download-config + * --upload-config + * --upload-screensaver + */ + +#include + +#include + +#include "ZeDMD.h" +#include "cargs.h" + +static struct cag_option options[] = { + {.identifier = 'h', .access_letters = "h", .access_name = "help", .description = "Show zedmd-client help"}, + {.identifier = 'v', .access_letters = "v", .access_name = "version", .description = "Show zedmd-client version"}, + {.identifier = 'p', + .access_letters = "p", + .access_name = "port", + .value_name = "VALUE", + .description = "Serial port to connect. If omitted, auto-discovery will be used."}, + {.identifier = 'i', + .access_letters = "i", + .access_name = "info", + .value_name = NULL, + .description = "Show information about ZeDMD."}, + {.identifier = 'a', + .access_letters = "a", + .access_name = "ip-address", + .value_name = "VALUE", + .description = "IP address to connect. If omitted, auto-discovery will be used."}, + {.identifier = 'b', + .access_letters = "b", + .access_name = "set-brightness", + .value_name = "VALUE", + .description = "0..15"}, + {.identifier = 'd', .access_letters = "d", .access_name = "set-debug", .value_name = "VALUE", .description = "0,1"}, + {.identifier = '0', .access_name = "set-panel-clkphase", .value_name = "VALUE", .description = "0,1"}, + {.identifier = '1', + .access_name = "set-panel-driver", + .value_name = "VALUE", + .description = "0(SHIFTREG),1(FM6124),2(FM6126A),3(ICN2038S),4(MBI5124),5(SM5266P),6(DP3246_SM5368)"}, + {.identifier = '2', .access_name = "set-panel-i2sspeed", .value_name = "VALUE", .description = "8,16,20"}, + {.identifier = '3', .access_name = "set-panel-latch-blanking", .value_name = "VALUE", .description = "0,1,2,3,4"}, + {.identifier = '4', .access_name = "set-panel-min-refresh-rate", .value_name = "VALUE", .description = "30..120"}, + {.identifier = '5', .access_name = "set-rgb-order", .value_name = "VALUE", .description = "0..5"}, + {.identifier = 't', + .access_letters = "t", + .access_name = "set-transport", + .value_name = "VALUE", + .description = "0(USB),1(WiFi UDP),2(WiFi TCP),3(SPI)"}, + {.identifier = 'u', + .access_letters = "u", + .access_name = "set-udp-delay", + .value_name = "VALUE", + .description = "0..9"}, + {.identifier = 's', + .access_letters = "s", + .access_name = "set-usb-package-size", + .value_name = "VALUE", + .description = "32..1920 (step 32)"}, + {.identifier = '6', .access_name = "set-wifi-ssid", .value_name = "VALUE", .description = "WiFi network SSID"}, + {.identifier = '7', + .access_name = "set-wifi-password", + .value_name = "VALUE", + .description = "WiFi network passwrord"}, + {.identifier = '8', + .access_name = "set-wifi-port", + .value_name = "VALUE", + .description = "WiFi network port (default is 3333)"}, + {.identifier = 'y', + .access_letters = "y", + .access_name = "set-y-offset", + .value_name = "VALUE", + .description = "0..32"}}; + +void ZEDMDCALLBACK LogCallback(const char* format, va_list args, const void* pUserData) +{ + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), format, args); + + printf("%s\n", buffer); +} + +int main(int argc, char* argv[]) +{ + char identifier; + cag_option_context cag_context; + + const char* opt_port = NULL; + const char* opt_ip_address = NULL; + bool opt_info = false; + bool opt_version = false; + const char* opt_brightness = NULL; + const char* opt_debug = NULL; + const char* opt_panel_clkphase = NULL; + const char* opt_panel_i2sspeed = NULL; + const char* opt_panel_latch_blanking = NULL; + const char* opt_panel_min_refresh_rate = NULL; + const char* opt_panel_driver = NULL; + const char* opt_rgb_order = NULL; + const char* opt_transport = NULL; + const char* opt_udp_delay = NULL; + const char* opt_usb_package_size = NULL; + const char* opt_wifi_ssid = NULL; + const char* opt_wifi_password = NULL; + const char* opt_wifi_port = NULL; + const char* opt_y_offset = NULL; + + bool has_other_options_than_h = false; + cag_option_prepare(&cag_context, options, CAG_ARRAY_SIZE(options), argc, argv); + while (cag_option_fetch(&cag_context)) + { + identifier = cag_option_get(&cag_context); + switch (identifier) + { + case 'v': + opt_version = true; + has_other_options_than_h = true; + break; + case 'p': + opt_port = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case 'i': + opt_info = true; + has_other_options_than_h = true; + break; + case 'a': + opt_ip_address = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case 'b': + opt_brightness = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case 'd': + opt_debug = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '0': + opt_panel_clkphase = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '1': + opt_panel_driver = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '2': + opt_panel_i2sspeed = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '3': + opt_panel_latch_blanking = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '4': + opt_panel_min_refresh_rate = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '5': + opt_rgb_order = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case 't': + opt_transport = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case 'u': + opt_udp_delay = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case 's': + opt_usb_package_size = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '6': + opt_wifi_ssid = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '7': + opt_wifi_password = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case '8': + opt_wifi_port = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + case 'y': + opt_y_offset = cag_option_get_value(&cag_context); + has_other_options_than_h = true; + break; + } + } + + if (!has_other_options_than_h) + { + printf("Usage: zedmd-client [OPTION]...\n"); + cag_option_print(options, CAG_ARRAY_SIZE(options), stdout); + printf("Warning: It is recommended to use an USB conection to change settings.\n"); + printf("It might work over WiFi, but especially UDP is not reliable.\n"); + printf("Use this command to switch to USB first:\n"); + printf("zedmd-client --set-transport=0\n"); + return 0; + } + + uint8_t brightness; + if (opt_brightness) + { + brightness = (uint8_t)std::stoi(std::string(opt_brightness)); + if (!(brightness >= 0 && brightness <= 15)) + { + printf("Error: brightness has to be betwen 0 and 15.\n"); + return -1; + } + } + + bool debug; + if (opt_debug) + { + uint8_t debug = (uint8_t)std::stoi(std::string(opt_debug)); + if (debug != 0 && debug != 1) + { + printf("Error: debug has to 0 or 1.\n"); + return -1; + } + } + + uint8_t panel_clkphase; + if (opt_panel_clkphase) + { + panel_clkphase = (uint8_t)std::stoi(std::string(opt_panel_clkphase)); + if (panel_clkphase != 0 && panel_clkphase != 1) + { + printf("Error: panel-clkphase has to 0 or 1.\n"); + return -1; + } + } + + uint8_t panel_driver; + if (opt_panel_driver) + { + panel_driver = (uint8_t)std::stoi(std::string(opt_panel_driver)); + if (!(panel_driver >= 0 && panel_driver <= 6)) + { + printf("Error: panel-driver has to between 0 and 6.\n"); + return -1; + } + } + + uint8_t panel_i2sspeed; + if (opt_panel_i2sspeed) + { + panel_i2sspeed = (uint8_t)std::stoi(std::string(opt_panel_i2sspeed)); + if (panel_i2sspeed != 8 && panel_clkphase != 16 && panel_clkphase != 20) + { + printf("Error: panel-i2sspeed has to be 8, 16 or 20.\n"); + return -1; + } + } + + uint8_t panel_latch_blanking; + if (opt_panel_latch_blanking) + { + panel_latch_blanking = (uint8_t)std::stoi(std::string(opt_panel_latch_blanking)); + if (!(panel_latch_blanking >= 0 && panel_latch_blanking <= 4)) + { + printf("Error: panel-latch-blanking has to be between 0 and 4.\n"); + return -1; + } + } + + uint8_t panel_min_refresh_rate; + if (opt_panel_min_refresh_rate) + { + panel_min_refresh_rate = (uint8_t)std::stoi(std::string(opt_panel_min_refresh_rate)); + if (!(panel_min_refresh_rate >= 30 && panel_min_refresh_rate <= 120)) + { + printf("Error: panel-min-refresh-rate has to between 30 and 120.\n"); + return -1; + } + } + + uint8_t rgb_order; + if (opt_rgb_order) + { + rgb_order = (uint8_t)std::stoi(std::string(opt_rgb_order)); + if (!(rgb_order >= 0 && rgb_order <= 5)) + { + printf("Error: rgb-order has to between 0 and 5.\n"); + return -1; + } + } + + uint8_t transport; + if (opt_transport) + { + transport = (uint8_t)std::stoi(std::string(opt_transport)); + if (!(transport >= 0 && transport <= 3)) + { + printf("Error: transport has to be betwen 0 and 15.\n"); + return -1; + } + } + + uint8_t udp_delay; + if (opt_udp_delay) + { + udp_delay = (uint8_t)std::stoi(std::string(opt_udp_delay)); + if (!(udp_delay >= 0 && udp_delay <= 9)) + { + printf("Error: udp-delay has to be betwen 0 and 9.\n"); + return -1; + } + } + + uint16_t usb_package_size; + if (opt_usb_package_size) + { + usb_package_size = (uint8_t)std::stoi(std::string(opt_usb_package_size)); + if (!(usb_package_size >= 32 && usb_package_size <= 1920 && (usb_package_size % 32 == 0))) + { + printf("Error: usb-package-size has to be betwen 32 and 1920, using steps of 32, so 32, 64, 96, 128, ...\n"); + return -1; + } + } + + uint8_t y_offset; + if (opt_y_offset) + { + y_offset = (uint8_t)std::stoi(std::string(opt_y_offset)); + if (!(y_offset >= 0 && y_offset <= 32)) + { + printf("Error: y-offset has to be betwen 0 and 32.\n"); + return -1; + } + } + + if (opt_port && opt_ip_address) + { + printf("Error: provide port or ip-address to connect, but not both..\n"); + return -1; + } + + ZeDMD* pZeDMD = new ZeDMD(); + + if (opt_version) + { + printf("zedmd-client version %s.\n", pZeDMD->GetVersion()); + delete pZeDMD; + pZeDMD = nullptr; + return -1; + } + + pZeDMD->SetLogCallback(LogCallback, nullptr); + + if (opt_ip_address) + { + if (!pZeDMD->OpenWiFi(opt_ip_address)) + { + printf("Unable to open connection to ZeDMD via WiFi.\n"); + delete pZeDMD; + pZeDMD = nullptr; + return -1; + } + } + else if (opt_port) + { + pZeDMD->SetDevice(opt_port); + + if (!pZeDMD->Open()) + { + printf("Unable to open connection to ZeDMD via USB.\n"); + delete pZeDMD; + pZeDMD = nullptr; + return -1; + } + } + else + { + if (!pZeDMD->Open() && !pZeDMD->OpenDefaultWiFi()) + { + printf("Unable to open connection to ZeDMD via USB or WiFi.\n"); + delete pZeDMD; + pZeDMD = nullptr; + return -1; + } + } + + if (opt_info) + { + printf("Info\n"); + } + + if (opt_brightness) pZeDMD->SetBrightness(brightness); + if (opt_debug) + pZeDMD->EnableDebug(); + else + pZeDMD->DisableDebug(); + if (opt_panel_clkphase) pZeDMD->SetBrightness(brightness); + if (opt_panel_driver) pZeDMD->SetBrightness(brightness); + if (opt_panel_i2sspeed) pZeDMD->SetBrightness(brightness); + if (opt_panel_latch_blanking) pZeDMD->SetBrightness(brightness); + if (opt_panel_min_refresh_rate) pZeDMD->SetBrightness(brightness); + if (opt_rgb_order) pZeDMD->SetRGBOrder(rgb_order); + if (opt_transport) pZeDMD->SetBrightness(brightness); + if (opt_udp_delay) pZeDMD->SetBrightness(brightness); + if (opt_usb_package_size) pZeDMD->SetBrightness(usb_package_size); + if (opt_wifi_ssid) pZeDMD->SetWiFiSSID(opt_wifi_ssid); + if (opt_wifi_password) pZeDMD->SetWiFiSSID(opt_wifi_password); + if (opt_wifi_port) pZeDMD->SetWiFiSSID(opt_wifi_port); + if (opt_y_offset) pZeDMD->SetBrightness(brightness); + pZeDMD->SaveSettings(); + + pZeDMD->Close(); + delete pZeDMD; + pZeDMD = nullptr; + return 0; +} diff --git a/third-party/include/cargs.h b/third-party/include/cargs.h new file mode 100644 index 0000000..f390f12 --- /dev/null +++ b/third-party/include/cargs.h @@ -0,0 +1,175 @@ +#pragma once + +/** + * This is a simple alternative cross-platform implementation of getopt, which + * is used to parse argument strings submitted to the executable (argc and argv + * which are received in the main function). + */ + +#ifndef CAG_LIBRARY_H +#define CAG_LIBRARY_H + +#include +#include +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +#define CAG_EXPORT __declspec(dllexport) +#define CAG_IMPORT __declspec(dllimport) +#elif __GNUC__ >= 4 +#define CAG_EXPORT __attribute__((visibility("default"))) +#define CAG_IMPORT __attribute__((visibility("default"))) +#else +#define CAG_EXPORT +#define CAG_IMPORT +#endif + +#if defined(CAG_SHARED) +#if defined(CAG_EXPORTS) +#define CAG_PUBLIC CAG_EXPORT +#else +#define CAG_PUBLIC CAG_IMPORT +#endif +#else +#define CAG_PUBLIC +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * An option is used to describe a flag/argument option submitted when the + * program is run. + */ +typedef struct cag_option +{ + const char identifier; + const char *access_letters; + const char *access_name; + const char *value_name; + const char *description; +} cag_option; + +/** + * A context is used to iterate over all options provided. It stores the parsing + * state. + */ +typedef struct cag_option_context +{ + const struct cag_option *options; + size_t option_count; + int argc; + char **argv; + int index; + int inner_index; + int failed_index; + bool forced_end; + char identifier; + char *value; +} cag_option_context; + +/** + * This is just a small macro which calculates the size of an array. + */ +#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +/** + * @brief Prints all options to the terminal. + * + * This function prints all options to the terminal. This can be used to + * generate the output for a "--help" option. + * + * @param options The options which will be printed. + * @param option_count The option count which will be printed. + * @param destination The destination where the output will be printed. + */ +CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count, + FILE *destination); + +/** + * @brief Prepare argument options context for parsing. + * + * This function prepares the context for iteration and initializes the context + * with the supplied options and arguments. After the context has been prepared, + * it can be used to fetch arguments from it. + * + * @param context The context which will be initialized. + * @param options The registered options which are available for the program. + * @param option_count The amount of options which are available for the + * program. + * @param argc The amount of arguments the user supplied in the main function. + * @param argv A pointer to the arguments of the main function. + */ +CAG_PUBLIC void cag_option_prepare(cag_option_context *context, + const cag_option *options, size_t option_count, int argc, char **argv); + +/** + * @brief Fetches an option from the argument list. + * + * This function fetches a single option from the argument list. The context + * will be moved to that item. Information can be extracted from the context + * after the item has been fetched. + * The arguments will be re-ordered, which means that non-option arguments will + * be moved to the end of the argument list. After all options have been + * fetched, all non-option arguments will be positioned after the index of + * the context. + * + * @param context The context from which we will fetch the option. + * @return Returns true if there was another option or false if the end is + * reached. + */ +CAG_PUBLIC bool cag_option_fetch(cag_option_context *context); + +/** + * @brief Gets the identifier of the option. + * + * This function gets the identifier of the option, which should be unique to + * this option and can be used to determine what kind of option this is. + * + * @param context The context from which the option was fetched. + * @return Returns the identifier of the option. + */ +CAG_PUBLIC char cag_option_get(const cag_option_context *context); + +/** + * @brief Gets the value from the option. + * + * This function gets the value from the option, if any. If the option does not + * contain a value, this function will return NULL. + * + * @param context The context from which the option was fetched. + * @return Returns a pointer to the value or NULL if there is no value. + */ +CAG_PUBLIC const char *cag_option_get_value(const cag_option_context *context); + +/** + * @brief Gets the current index of the context. + * + * This function gets the index within the argv arguments of the context. The + * context always points to the next item which it will inspect. This is + * particularly useful to inspect the original argument array, or to get + * non-option arguments after option fetching has finished. + * + * @param context The context from which the option was fetched. + * @return Returns the current index of the context. + */ +CAG_PUBLIC int cag_option_get_index(const cag_option_context *context); + +/** + * @brief Gets an invalid option if found + * + * This function gets an invalid option if an option doesn't match one of options + * from `cag_option` list. This is useful if you want more detailed error + * about an invalid option found. + * + * @param context The context from which the option was fetched. + * @return Returns a string where it contains the invalid option. + */ +CAG_PUBLIC const char *cag_option_get_invalid(const cag_option_context *context); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif