From f73c1ecb53a390f3bde47153a2641d3b7f4e93a2 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 19 Feb 2024 13:10:27 +0100 Subject: [PATCH] added ConsoleDMD (#8) --- CMakeLists.txt | 1 + include/DMDUtil/ConsoleDMD.h | 21 +++++++++++ include/DMDUtil/DMD.h | 6 +++ src/ConsoleDMD.cpp | 45 ++++++++++++++++++++++ src/DMD.cpp | 73 ++++++++++++++++++++++++++++++++++++ src/test.cpp | 4 ++ 6 files changed, 150 insertions(+) create mode 100644 include/DMDUtil/ConsoleDMD.h create mode 100644 src/ConsoleDMD.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 93c8de1..3f2d844 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ set(DMDUTIL_SOURCES src/DMD.cpp src/LevelDMD.cpp src/RGB24DMD.cpp + src/ConsoleDMD.cpp src/Logger.cpp src/AlphaNumeric.cpp src/FrameUtil.cpp diff --git a/include/DMDUtil/ConsoleDMD.h b/include/DMDUtil/ConsoleDMD.h new file mode 100644 index 0000000..c8536a7 --- /dev/null +++ b/include/DMDUtil/ConsoleDMD.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace DMDUtil +{ + +class ConsoleDMD +{ + public: + ConsoleDMD(FILE* f); + ~ConsoleDMD(); + + void Render(uint8_t* buffer, uint16_t width, uint16_t height, uint8_t bitDepth); + + private: + FILE* out; +}; + +} // namespace DMDUtil diff --git a/include/DMDUtil/DMD.h b/include/DMDUtil/DMD.h index 90af35b..183bc06 100644 --- a/include/DMDUtil/DMD.h +++ b/include/DMDUtil/DMD.h @@ -55,6 +55,7 @@ class Serum; class PixelcadeDMD; class LevelDMD; class RGB24DMD; +class ConsoleDMD; class DMDUTILAPI DMD { @@ -71,6 +72,8 @@ class DMDUTILAPI DMD bool DestroyLevelDMD(LevelDMD* pLevelDMD); RGB24DMD* CreateRGB24DMD(uint16_t width, uint16_t height); bool DestroyRGB24DMD(RGB24DMD* pRGB24DMD); + ConsoleDMD* CreateConsoleDMD(FILE* f = stdout); + bool DestroyConsoleDMD(ConsoleDMD* pConsoleDMD); void UpdateData(const uint8_t* pData, int depth, uint16_t width, uint16_t height, uint8_t r, uint8_t g, uint8_t b, const char* name = nullptr); void UpdateRGB24Data(const uint8_t* pData, int depth, uint16_t width, uint16_t height, uint8_t r, uint8_t g, @@ -119,6 +122,7 @@ class DMDUTILAPI DMD void DmdFrameReadyResetThread(); void LevelDMDThread(); void RGB24DMDThread(); + void ConsoleDMDThread(); void ZeDMDThread(); void DumpDMDTxtThread(); void DumpDMDRawThread(); @@ -129,9 +133,11 @@ class DMDUTILAPI DMD ZeDMD* m_pZeDMD; std::vector m_levelDMDs; std::vector m_rgb24DMDs; + std::vector m_consoleDMDs; std::thread* m_pLevelDMDThread; std::thread* m_pRGB24DMDThread; + std::thread* m_pConsoleDMDThread; std::thread* m_pZeDMDThread; std::thread* m_pdmdFrameReadyResetThread; std::thread* m_pDumpDMDTxtThread; diff --git a/src/ConsoleDMD.cpp b/src/ConsoleDMD.cpp new file mode 100644 index 0000000..32cd4b3 --- /dev/null +++ b/src/ConsoleDMD.cpp @@ -0,0 +1,45 @@ +#include "DMDUtil/ConsoleDMD.h" + +#include + +namespace DMDUtil +{ + +ConsoleDMD::ConsoleDMD(FILE* f) { out = f; } + +ConsoleDMD::~ConsoleDMD() {} + +void ConsoleDMD::Render(uint8_t* buffer, uint16_t width, uint16_t height, uint8_t bitDepth) +{ + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x++) + { + uint8_t value = buffer[y * width + x]; + if (bitDepth > 2) + { + fprintf(out, "%2x", value); + } + else + { + switch (value) + { + case 0: + fprintf(out, "\033[0;40m⚫\033[0m"); + break; + case 1: + fprintf(out, "\033[0;40m🟤\033[0m"); + break; + case 2: + fprintf(out, "\033[0;40m🟠\033[0m"); + break; + case 3: + fprintf(out, "\033[0;40m🟡\033[0m"); + break; + } + } + } + fprintf(out, "\n"); + } +} +} // namespace DMDUtil \ No newline at end of file diff --git a/src/DMD.cpp b/src/DMD.cpp index 5b705e3..52854d9 100644 --- a/src/DMD.cpp +++ b/src/DMD.cpp @@ -1,6 +1,7 @@ #include "DMDUtil/DMD.h" #include "DMDUtil/Config.h" +#include "DMDUtil/ConsoleDMD.h" #include "DMDUtil/LevelDMD.h" #include "DMDUtil/RGB24DMD.h" @@ -45,6 +46,7 @@ DMD::DMD() m_pZeDMDThread = nullptr; m_pLevelDMDThread = nullptr; m_pRGB24DMDThread = nullptr; + m_pConsoleDMDThread = nullptr; m_pDumpDMDTxtThread = nullptr; m_pDumpDMDRawThread = nullptr; #if !( \ @@ -82,6 +84,13 @@ DMD::~DMD() m_pRGB24DMDThread = nullptr; } + if (m_pConsoleDMDThread) + { + m_pConsoleDMDThread->join(); + delete m_pConsoleDMDThread; + m_pConsoleDMDThread = nullptr; + } + if (m_pZeDMDThread) { m_pZeDMDThread->join(); @@ -124,6 +133,7 @@ DMD::~DMD() for (LevelDMD* pLevelDMD : m_levelDMDs) delete pLevelDMD; for (RGB24DMD* pRGB24DMD : m_rgb24DMDs) delete pRGB24DMD; + for (ConsoleDMD* pConsoleDMD : m_consoleDMDs) delete pConsoleDMD; } bool DMD::IsFinding() { return m_finding; } @@ -195,6 +205,32 @@ bool DMD::DestroyRGB24DMD(RGB24DMD* pRGB24DMD) return false; } +ConsoleDMD* DMD::CreateConsoleDMD(FILE* f) +{ + ConsoleDMD* const pConsoleDMD = new ConsoleDMD(f); + m_consoleDMDs.push_back(pConsoleDMD); + if (!m_pConsoleDMDThread) m_pConsoleDMDThread = new std::thread(&DMD::ConsoleDMDThread, this); + return pConsoleDMD; +} + +bool DMD::DestroyConsoleDMD(ConsoleDMD* pConsoleDMD) +{ + auto it = std::find(m_consoleDMDs.begin(), m_consoleDMDs.end(), pConsoleDMD); + if (it != m_consoleDMDs.end()) + { + m_consoleDMDs.erase(it); + delete pConsoleDMD; + + if (m_consoleDMDs.empty()) + { + //@todo terminate ConsoleDMDThread + } + + return true; + } + return false; +} + void DMD::UpdateData(const uint8_t* pData, int depth, uint16_t width, uint16_t height, uint8_t r, uint8_t g, uint8_t b, DMDMode mode, const char* name) { @@ -838,6 +874,43 @@ void DMD::RGB24DMDThread() } } +void DMD::ConsoleDMDThread() +{ + int bufferPosition = 0; + uint8_t renderBuffer[256 * 64] = {0}; + + while (true) + { + std::shared_lock sl(m_dmdSharedMutex); + m_dmdCV.wait(sl, [&]() { return m_dmdFrameReady || m_stopFlag; }); + sl.unlock(); + if (m_stopFlag) + { + return; + } + + while (!m_stopFlag && bufferPosition != m_updateBufferPosition) + { + if (++bufferPosition >= DMDUTIL_FRAME_BUFFER_SIZE) bufferPosition = 0; + + if (!m_consoleDMDs.empty() && m_updateBuffer[bufferPosition]->mode == DMDMode::Data && + m_updateBuffer[bufferPosition]->hasData) + { + int length = m_updateBuffer[bufferPosition]->width * m_updateBuffer[bufferPosition]->height; + if (memcmp(renderBuffer, m_updateBuffer[bufferPosition]->data, length) != 0) + { + memcpy(renderBuffer, m_updateBuffer[bufferPosition]->data, length); + for (ConsoleDMD* pConsoleDMD : m_consoleDMDs) + { + pConsoleDMD->Render(renderBuffer, m_updateBuffer[bufferPosition]->width, + m_updateBuffer[bufferPosition]->height, m_updateBuffer[bufferPosition]->depth); + } + } + } + } + } +} + bool DMD::UpdatePalette(uint8_t* pPalette, uint8_t depth, uint8_t r, uint8_t g, uint8_t b) { if (depth != 2 && depth != 4) return false; diff --git a/src/test.cpp b/src/test.cpp index 47b9a5b..f601aa8 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -6,6 +6,7 @@ #include "DMDUtil/DMDUtil.h" #include "DMDUtil/LevelDMD.h" #include "DMDUtil/RGB24DMD.h" +#include "DMDUtil/ConsoleDMD.h" void DMDUTILCALLBACK LogCallback(const char* format, va_list args) { @@ -89,11 +90,14 @@ int main(int argc, const char* argv[]) DMDUtil::LevelDMD* pLevelDMD196_4; DMDUtil::RGB24DMD* pRGB24DMD128; DMDUtil::RGB24DMD* pRGB24DMD196; + DMDUtil::ConsoleDMD* pConsoleDMD; int ms = 200; for (int i = 0; i < 4; i++) { + if (i == 0) pConsoleDMD = pDmd->CreateConsoleDMD(); if (i == 0) pLevelDMD128_2 = pDmd->CreateLevelDMD(128, 32, 2); + if (i == 1) pDmd->DestroyConsoleDMD(pConsoleDMD); if (i == 1) pLevelDMD128_4 = pDmd->CreateLevelDMD(128, 32, 4); if (i == 2) pLevelDMD196_4 = pDmd->CreateLevelDMD(192, 64, 4); if (i == 3) pDmd->DestroyLevelDMD(pLevelDMD128_2);