Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
5309bad
added Serum Scene support
mkalkbrenner Jul 29, 2025
98188bb
fixed altcolor path
mkalkbrenner Jul 29, 2025
cca680f
allow trigger repeat
mkalkbrenner Jul 30, 2025
97de831
empty buffer
mkalkbrenner Jul 30, 2025
d7d78cf
handle bit depth
mkalkbrenner Jul 30, 2025
bb98712
fixed scene template for bit depth 4
mkalkbrenner Jul 30, 2025
efbef63
fixed scene frame timings
mkalkbrenner Jul 30, 2025
356a185
fixed rotation and scene timeouts
mkalkbrenner Jul 30, 2025
e16a161
another fix
mkalkbrenner Jul 30, 2025
45d51a5
fixed rotations and scenes
mkalkbrenner Jul 30, 2025
57d6b36
added dmdutil-generate-scene
mkalkbrenner Jul 30, 2025
8511867
added frame group support
mkalkbrenner Jul 31, 2025
ac622f9
mplemented frame groups, random, repeat, ...
mkalkbrenner Jul 31, 2025
8c25066
implemented llop
mkalkbrenner Jul 31, 2025
739751c
added debug output
mkalkbrenner Aug 1, 2025
e52e781
added info
mkalkbrenner Aug 1, 2025
aada773
fixed some timings
mkalkbrenner Aug 3, 2025
f43423c
fixed GenerateRandomSuffix
mkalkbrenner Aug 4, 2025
c65c5aa
trigger PUP scenes from outside
mkalkbrenner Aug 4, 2025
27be38a
support 256x64 RGB24DMDs with Serum
mkalkbrenner Aug 5, 2025
7eaeb3d
fixed Serum HD for RGB24DMD
mkalkbrenner Aug 5, 2025
78297e5
prepared better trigger handling
mkalkbrenner Aug 5, 2025
71328d6
fixed HD info, added debug output
mkalkbrenner Aug 6, 2025
a6977ca
improved 32 vs 64
mkalkbrenner Aug 6, 2025
afb09a1
fixed network conversion
mkalkbrenner Aug 6, 2025
89044f5
initialize update
mkalkbrenner Aug 6, 2025
a01e995
only render required resolution
mkalkbrenner Aug 6, 2025
bde19ab
turned DMD server into re-usable libraray functionality
mkalkbrenner Aug 8, 2025
10f9069
renamed src/dmdServer.cpp -> src/DMDServer.cpp
mkalkbrenner Aug 8, 2025
ad075ab
fixed includes
mkalkbrenner Aug 8, 2025
829d84f
removed redundant parts
mkalkbrenner Aug 8, 2025
cdb2dae
scale RGB24DMD
mkalkbrenner Aug 8, 2025
41eff53
fixed thread disconnect
mkalkbrenner Aug 8, 2025
706cdf3
fixed issue when Serum gets overlayed by non-Serum via dmdserver
mkalkbrenner Aug 9, 2025
5d2ffdf
fixed edge case that sometimes an "old" frame or a "too new" frame ge…
mkalkbrenner Aug 11, 2025
39abb86
increased buffer
mkalkbrenner Aug 11, 2025
aa34e85
improved serum handling
mkalkbrenner Aug 12, 2025
b7419e9
fixed hasDsiplay()
mkalkbrenner Aug 12, 2025
a34f65e
fixed accept loop
mkalkbrenner Aug 12, 2025
7b62f01
fixed return type
mkalkbrenner Aug 12, 2025
007656d
fixed hasDisplay()
mkalkbrenner Aug 12, 2025
060235a
updated libserum_concentrate
mkalkbrenner Aug 17, 2025
73e1f36
added sanitizer
mkalkbrenner Aug 17, 2025
29573f8
don't upscale on a 192x64 RGB24DMD
mkalkbrenner Aug 18, 2025
2061c30
allow graceful shutdown of dmdserver via SIGTERM, related to #66
mkalkbrenner Aug 18, 2025
c24d38f
clear m_pUpdateBufferQueue on shutdown
mkalkbrenner Aug 18, 2025
55509ef
added message
mkalkbrenner Aug 18, 2025
c7321ca
fixed paths from ini file
mkalkbrenner Aug 18, 2025
63a5b7a
avoid memory leak in config parsing
mkalkbrenner Aug 19, 2025
9d2a39f
updated libserum_concentrate, use logger in scene generator
mkalkbrenner Aug 20, 2025
1dd9a17
moved scene generator class to libserum_concentrate
mkalkbrenner Aug 21, 2025
d8a0fa5
added header
mkalkbrenner Aug 21, 2025
7f4e44c
added missing headers
mkalkbrenner Aug 23, 2025
0eef2a5
added README, set version number
mkalkbrenner Aug 23, 2025
9919c13
show black screen on dmdserver disconnect
mkalkbrenner Aug 25, 2025
90cd9ce
fixed windows compile issue
mkalkbrenner Aug 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/libdmdutil.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ jobs:
cp build/Release/dmdutil_static.lib tmp
cp build/Release/dmdutil_test_s.exe tmp
cp build/Release/dmdutil_test.exe tmp
cp build/Release/dmdutil-generate-scenes.exe tmp
cp -r test tmp/
else
ARTIFACT_PATH="libdmdutil-${{ needs.version.outputs.tag }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz"
Expand All @@ -114,13 +115,15 @@ jobs:
cp build/dmdserver_test tmp
cp build/dmdutil_test_s tmp
cp build/dmdutil_test tmp
cp build/dmdutil-generate-scenes tmp
elif [[ "${{ matrix.platform }}" == "linux" ]]; then
cp build/libdmdutil.a tmp
cp -a build/*.{so,so.*} tmp
cp build/dmdserver tmp
cp build/dmdserver_test tmp
cp build/dmdutil_test_s tmp
cp build/dmdutil_test tmp
cp build/dmdutil-generate-scenes tmp
elif [[ "${{ matrix.platform }}" == "ios" || "${{ matrix.platform }}" == "ios-simulator" || "${{ matrix.platform }}" == "tvos" ]]; then
cp build/libdmdutil.a tmp
cp -a build/*.dylib tmp
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ third-party/include/cargs.h
third-party/include/*.hpp
third-party/include/libserialport.h
third-party/include/pupdmd.h
third-party/include/SceneGenerator.h
third-party/include/serum.h
third-party/include/serum-decode.h
third-party/include/ZeDMD.h
third-party/include/LZ4Stream.h
third-party/include/lz4
.DS_Store
22 changes: 21 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ set(ARCH "x64" CACHE STRING "Arch")
option(BUILD_SHARED "Option to build shared library" ON)
option(BUILD_STATIC "Option to build static library" ON)
option(POST_BUILD_COPY_EXT_LIBS "Option to copy external libraries to build directory" ON)
option(ENABLE_SANITIZERS "Enable AddressSanitizer and UBSan for Debug builds" OFF)

message(STATUS "PLATFORM: ${PLATFORM}")
message(STATUS "ARCH: ${ARCH}")

message(STATUS "BUILD_SHARED: ${BUILD_SHARED}")
message(STATUS "BUILD_STATIC: ${BUILD_STATIC}")
message(STATUS "POST_BUILD_COPY_EXT_LIBS: ${POST_BUILD_COPY_EXT_LIBS}")
message(STATUS "ENABLE_SANITIZERS: ${ENABLE_SANITIZERS}")

if(PLATFORM STREQUAL "macos")
set(CMAKE_OSX_DEPLOYMENT_TARGET 14.0)
Expand Down Expand Up @@ -67,6 +69,18 @@ set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_C_VISIBILITY_PRESET hidden)

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
if(ENABLE_SANITIZERS AND (PLATFORM STREQUAL "macos" OR PLATFORM STREQUAL "linux"))
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)

add_compile_options(-fsanitize=undefined)
add_link_options(-fsanitize=undefined)

add_compile_options(-fno-omit-frame-pointer)
endif()
endif()

set(DMDUTIL_SOURCES
src/Config.cpp
src/DMD.cpp
Expand All @@ -75,6 +89,7 @@ set(DMDUTIL_SOURCES
src/ConsoleDMD.cpp
src/Logger.cpp
src/AlphaNumeric.cpp
src/DMDServer.cpp
)

if(PLATFORM STREQUAL "win" OR PLATFORM STREQUAL "macos" OR PLATFORM STREQUAL "linux")
Expand Down Expand Up @@ -143,7 +158,7 @@ if(BUILD_SHARED)

if(PLATFORM STREQUAL "win" OR PLATFORM STREQUAL "macos" OR PLATFORM STREQUAL "linux")
add_executable(dmdserver
src/dmdServer.cpp
src/server.cpp
src/Logger.cpp
)
target_link_libraries(dmdserver PUBLIC dmdutil_shared)
Expand All @@ -158,6 +173,11 @@ if(BUILD_SHARED)
)
target_link_libraries(dmdutil_test PUBLIC dmdutil_shared)

add_executable(dmdutil-generate-scenes
src/generateScenesDump.cpp
)
target_link_libraries(dmdutil-generate-scenes PUBLIC dmdutil_shared)

if(POST_BUILD_COPY_EXT_LIBS)
if(PLATFORM STREQUAL "win")
if(ARCH STREQUAL "x64")
Expand Down
60 changes: 30 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,35 +47,17 @@ void test()
Per default it listens on port 6789 on localhost and accepts "raw" TCP connections.

`dmdserver` accepts these command line options:
* -c --config
* Config file
* optional
* default is no config file
* -o --alt-color-path
* "Fixed alt color path, overwriting paths transmitted by DMDUpdates
* optional
* -a --addr
* IP address or host name
* optional
* default is `localhost`
* -p --port
* Port
* optional
* default is `6789`
* -w --wait-for-displays
* Don't terminate if no displays are connected
* optional
* default is to terminate the server process if no displays could be found
* -l --logging
* Enable logging to stderr
* optional
* default is no logging
* -v --verbose
* Enables verbose logging, includes normal logging
* optional
* default is no logging
* -h --help
* Show help
```
-c, --config=VALUE Config file (optional, default is no config file)
-o, --alt-color-path=VALUE Fixed alt color path, overwriting paths transmitted by DMDUpdates (optional)
-u, --pup-videos-path=VALUE Fixed PupVideos path, overwriting paths transmitted by DMDUpdates (optional)
-a, --addr=VALUE IP address or host name (optional, default is 'localhost')
-p, --port=VALUE Port (optional, default is '6789')
-w, --wait-for-displays Don't terminate if no displays are connected (optional, default is to terminate the server process if no displays could be found)
-l, --logging Enable logging to stderr (optional, default is no logging)
-v, --verbose-logging Enables verbose logging, includes normal logging (optional, default is no logging)
-h, --help Show help
```

`dmdserver` expects two packages to render a DMD frame. The first one is a DmdStream header followed by the "data".

Expand Down Expand Up @@ -209,7 +191,7 @@ SaveSettings = 0
# Set to 1 if ZeDMD-WiFi is available.
Enabled = 0
# Enter your ZeDMD WiFi IP address here
WiFiAddr =
WiFiAddr =

[Pixelcade]
# Set to 1 if Pixelcade is attached
Expand All @@ -218,6 +200,24 @@ Enabled = 1
Device =
```

## Serum PUP Scenes Generator

Serum PUP Scenes are a new feature of libserum_concentrate.
Such scenes base on a defined number of fake frames at a given frame rate.
These frames can be added to the ROM's original frames or overlay some original frames.
The purpose is to add new animations or to replace existing frames with smoother aniations.
Therefore, a colorization other needs a set of scene frames that could be colorized in the colorization editor.
The `dmdutil-generate-scenes` tool generates a dump of such scene frames according to the PUP Scenes specification CSV file.

`dmdutil-generate-scenes` accepts these command line options:
```
-c, --csv=VALUE PUP scenes CSV file to parse
-o, --output=VALUE Output dump file to generate
-d, --depth=VALUE Bit depth of the DMD frames (2 or 4) (optional, default is 2)
-i, --id=VALUE PUP scene trigger ID to generate (optional, default is all scenes)
-h, --help Show help
```

## Building:

#### Windows (x64)
Expand Down
4 changes: 2 additions & 2 deletions dmdserver.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ SaveSettings = 0
# Set to 1 if ZeDMD-WiFi is available.
Enabled = 0
# Enter your ZeDMD WiFi IP address here
WiFiAddr =
WiFiAddr =

[Pixelcade]
# Set to 1 if Pixelcade is attached
Enabled = 1
Enabled = 0
# Disable auto-detection and provide a fixed serial port
Device =
39 changes: 20 additions & 19 deletions include/DMDUtil/DMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
#define DMDUTILCALLBACK
#endif

#define DMDUTIL_FRAME_BUFFER_SIZE 32
#define DMDUTIL_FRAME_BUFFER_SIZE 128 // Must be a divider of 65535! Must not exceed 256!
#define DMDUTIL_MIN_FRAMES_BEHIND 4
#define DMDUTIL_MAX_FRAMES_BEHIND 16
#define DMDUTIL_MAX_FRAMES_BEHIND 32
#define DMDUTIL_MAX_NAME_SIZE 16
#define DMDUTIL_MAX_PATH_SIZE 256
#define DMDUTIL_MAX_TRANSITIONAL_FRAME_DURATION 25
Expand Down Expand Up @@ -68,7 +68,6 @@ class PixelcadeDMD;
class LevelDMD;
class RGB24DMD;
class ConsoleDMD;

class DMDServerConnector;

class DMDUTILAPI DMD
Expand All @@ -77,7 +76,7 @@ class DMDUTILAPI DMD
DMD();
~DMD();

enum class Mode
enum class Mode : int
{
Unknown = 0,
Data = 1,
Expand Down Expand Up @@ -108,20 +107,20 @@ class DMDUTILAPI DMD
#pragma pack(push, 1) // Align to 1-byte boundaries, important for sending over socket.
struct Update
{
Mode mode;
AlphaNumericLayout layout;
int depth;
uint8_t data[256 * 64 * 3];
uint16_t segData[256 * 64]; // RGB16 or segment data or SerumV1 palette
Mode mode = Mode::Data; // int
AlphaNumericLayout layout = AlphaNumericLayout::NoLayout; // int
int depth = 2;
uint8_t data[256 * 64 * 3] = {0};
uint16_t segData[256 * 64] = {0}; // RGB16 or segment data or SerumV1 palette
uint16_t segData2[128];
bool hasData;
bool hasSegData;
bool hasSegData2;
uint8_t r;
uint8_t g;
uint8_t b;
uint16_t width;
uint16_t height;
bool hasData = false;
bool hasSegData = false;
bool hasSegData2 = false;
uint8_t r = 255;
uint8_t g = 255;
uint8_t b = 255;
uint16_t width = 128;
uint16_t height = 32;

DMDUTILAPI void convertToHostByteOrder();
DMDUTILAPI Update toNetworkByteOrder() const;
Expand Down Expand Up @@ -161,6 +160,7 @@ class DMDUTILAPI DMD
void SetRomName(const char* name);
void SetAltColorPath(const char* path);
void SetPUPVideosPath(const char* path);
void SetPUPTrigger(const char source, const uint16_t id, const uint8_t value = 1);
void DumpDMDTxt();
void DumpDMDRaw();
LevelDMD* CreateLevelDMD(uint16_t width, uint16_t height, bool sam);
Expand All @@ -185,7 +185,7 @@ class DMDUTILAPI DMD
Update* m_pUpdateBufferQueue[DMDUTIL_FRAME_BUFFER_SIZE];
std::shared_ptr<Update> m_updateBuffered;

uint8_t GetNextBufferQueuePosition(uint8_t bufferPosition, const uint8_t updateBufferQueuePosition);
uint16_t GetNextBufferQueuePosition(uint16_t bufferPosition, const uint16_t updateBufferQueuePosition);
bool ConnectDMDServer();
bool UpdatePalette(uint8_t* pPalette, uint8_t depth, uint8_t r, uint8_t g, uint8_t b);
void UpdateData(const uint8_t* pData, int depth, uint16_t width, uint16_t height, uint8_t r, uint8_t g, uint8_t b,
Expand Down Expand Up @@ -232,7 +232,8 @@ class DMDUTILAPI DMD
std::condition_variable_any m_dmdCV;
std::atomic<bool> m_dmdFrameReady;
std::atomic<bool> m_stopFlag;
std::atomic<uint8_t> m_updateBufferQueuePosition;
std::atomic<uint16_t> m_updateBufferQueuePosition;
std::atomic<uint16_t> m_pupSceneId;

bool m_hasUpdateBuffered = false;
static bool m_finding;
Expand Down
44 changes: 44 additions & 0 deletions include/DMDUtil/DMDServer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <atomic>
#include <mutex>
#include <thread>
#include <vector>

#include "DMDUtil/DMD.h"
#include "sockpp/tcp_acceptor.h"

#define DMDSERVER_MAX_WIDTH 256
#define DMDSERVER_MAX_HEIGHT 64

namespace DMDUtil
{

class DMDUTILAPI DMDServer
{
public:
DMDServer(DMD* dmd, bool fixedAltColorPath = false, bool fixedPupPath = false);
~DMDServer();

bool Start(const char* addr, in_port_t port);
void Stop();
bool IsRunning() const { return m_running.load(std::memory_order_acquire); }

private:
void AcceptLoop();
void ClientThread(sockpp::tcp_socket sock, uint32_t threadId);

DMD* m_dmd;
bool m_fixedAltColorPath;
bool m_fixedPupPath;
std::atomic<bool> m_running{false};
sockpp::tcp_acceptor m_acceptor;

uint32_t m_currentThreadId{0};
std::mutex m_threadMutex;
uint32_t m_disconnectOtherClients{0};
std::vector<uint32_t> m_threads;
std::thread* m_acceptThread{nullptr};
};

} // namespace DMDUtil
7 changes: 4 additions & 3 deletions include/DMDUtil/DMDUtil.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#pragma once

#define DMDUTIL_VERSION_MAJOR 0 // X Digits
#define DMDUTIL_VERSION_MINOR 9 // Max 2 Digits
#define DMDUTIL_VERSION_PATCH 2 // Max 2 Digits
#define DMDUTIL_VERSION_MAJOR 0 // X Digits
#define DMDUTIL_VERSION_MINOR 10 // Max 2 Digits
#define DMDUTIL_VERSION_PATCH 0 // Max 2 Digits

#define _DMDUTIL_STR(x) #x
#define DMDUTIL_STR(x) _DMDUTIL_STR(x)
Expand All @@ -14,5 +14,6 @@
#include "Config.h"
#include "ConsoleDMD.h"
#include "DMD.h"
#include "DMDServer.h"
#include "LevelDMD.h"
#include "RGB24DMD.h"
2 changes: 1 addition & 1 deletion include/DMDUtil/RGB24DMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DMDUTILAPI RGB24DMD
RGB24DMD(uint16_t width, uint16_t height);
~RGB24DMD();

virtual void Update(uint8_t* pRGB24Data);
virtual void Update(uint8_t* pRGB24Data, uint16_t width = 0, uint16_t height = 0);
int GetWidth() const { return m_width; }
int GetHeight() const { return m_height; }
int GetLength() const { return m_length; }
Expand Down
3 changes: 3 additions & 0 deletions platforms/android/arm64-v8a/external.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ cmake \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-B build
cmake --build build -- -j${NUM_PROCS}
cp -r third-party/include/lz4 ../../third-party/include/
cp src/LZ4Stream.h ../../third-party/include/
cp src/SceneGenerator.h ../../third-party/include/
cp src/serum.h ../../third-party/include/
cp src/serum-decode.h ../../third-party/include/
cp build/libserum.so ../../third-party/runtime-libs/android/arm64-v8a/
Expand Down
4 changes: 2 additions & 2 deletions platforms/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

set -e

LIBZEDMD_SHA=154772800e8f36378c629f066bfee563862728ac
LIBSERUM_SHA=607bee2ab6e73a08a28f207a42be676e967cf876
LIBZEDMD_SHA=542340d5d230ab78a175747a45f6cef415e2c774
LIBSERUM_SHA=ca191d72183c50854c2bd0058b305a7a57b71e03
LIBPUPDMD_SHA=124f45e5ddd59ceb339591de88fcca72f8c54612

if [ -z "${BUILD_TYPE}" ]; then
Expand Down
3 changes: 3 additions & 0 deletions platforms/ios-simulator/arm64/external.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ cmake \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-B build
cmake --build build -- -j${NUM_PROCS}
cp -r third-party/include/lz4 ../../third-party/include/
cp src/LZ4Stream.h ../../third-party/include/
cp src/SceneGenerator.h ../../third-party/include/
cp src/serum.h ../../third-party/include/
cp src/serum-decode.h ../../third-party/include/
cp build/libserum.a ../../third-party/build-libs/ios-simulator/arm64/
Expand Down
3 changes: 3 additions & 0 deletions platforms/ios/arm64/external.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ cmake \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-B build
cmake --build build -- -j${NUM_PROCS}
cp -r third-party/include/lz4 ../../third-party/include/
cp src/LZ4Stream.h ../../third-party/include/
cp src/SceneGenerator.h ../../third-party/include/
cp src/serum.h ../../third-party/include/
cp src/serum-decode.h ../../third-party/include/
cp build/libserum.a ../../third-party/build-libs/ios/arm64/
Expand Down
Loading
Loading