diff --git a/src/ZeDMD.cpp b/src/ZeDMD.cpp index eaa3e11..62db11e 100644 --- a/src/ZeDMD.cpp +++ b/src/ZeDMD.cpp @@ -288,7 +288,7 @@ void ZeDMD::ClearScreen() } else if (m_wifi) { - m_pZeDMDWiFi->QueueCommand(ZEDMD_WIFI_COMMAND::UDP_ClearScreen); + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::ClearScreen); } } @@ -310,7 +310,7 @@ void ZeDMD::RenderGray2(uint8_t *pFrame) if (m_wifi) { - m_pZeDMDWiFi->QueueCommand(ZEDMD_WIFI_COMMAND::UDP_RGB24, m_pPlanes, bufferSize * 3, width, height); + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); } m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); } @@ -345,7 +345,7 @@ void ZeDMD::RenderGray4(uint8_t *pFrame) if (m_wifi) { - m_pZeDMDWiFi->QueueCommand(ZEDMD_WIFI_COMMAND::UDP_RGB24, m_pPlanes, bufferSize * 3, width, height); + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); } m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); } @@ -384,7 +384,7 @@ void ZeDMD::RenderColoredGray6(uint8_t *pFrame, uint8_t *pRotations) if (m_wifi) { - m_pZeDMDWiFi->QueueCommand(ZEDMD_WIFI_COMMAND::UDP_RGB24, m_pPlanes, bufferSize * 3, width, height); + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); } m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); } @@ -420,7 +420,7 @@ void ZeDMD::RenderRgb24(uint8_t *pFrame) if (m_wifi) { - m_pZeDMDWiFi->QueueCommand(ZEDMD_WIFI_COMMAND::UDP_RGB24, m_pPlanes, bufferSize, width, height); + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize, width, height); } else if (m_hd || m_streaming) { diff --git a/src/ZeDMDComm.cpp b/src/ZeDMDComm.cpp index 91b4d34..1a3962c 100644 --- a/src/ZeDMDComm.cpp +++ b/src/ZeDMDComm.cpp @@ -48,7 +48,7 @@ void ZeDMDComm::Run() LogMessage("ZeDMDComm run thread starting"); int8_t lastStreamId = -1; - while (m_serialPort.IsOpen()) + while (IsConnected()) { m_frameQueueMutex.lock(); @@ -81,7 +81,7 @@ void ZeDMDComm::Run() delay = m_delayedFrameReady; m_delayedFrameMutex.unlock(); - if (delay && m_frameCounter > 2) { + if (delay && m_frameCounter > ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX_DELAYED) { while (m_frames.size() > 0) { m_frames.pop(); @@ -135,7 +135,7 @@ void ZeDMDComm::Run() void ZeDMDComm::QueueCommand(char command, uint8_t *data, int size, int8_t streamId, bool delayed) { - if (!m_serialPort.IsOpen()) + if (!IsConnected()) { return; } @@ -201,6 +201,16 @@ void ZeDMDComm::QueueCommand(char command, uint8_t *data, int size, uint16_t wid uint16_t bufferSize = 0; uint8_t idx = 0; uint8_t zone[16 * 8 * 3] = { 0 }; + uint16_t zonesBytesLimit = 0; + if (m_zonesBytesLimit) { + while (zonesBytesLimit < m_zonesBytesLimit) + { + zonesBytesLimit += m_zoneWidth * m_zoneHeight * 3 + 1; + } + } + else { + zonesBytesLimit = width * m_zoneHeight * 3 + 16; + } if (++m_streamId > 64) { @@ -240,7 +250,7 @@ void ZeDMDComm::QueueCommand(char command, uint8_t *data, int size, uint16_t wid memcpy(&buffer[bufferSize], zone, m_zoneWidth * m_zoneHeight * 3); bufferSize += m_zoneWidth * m_zoneHeight * 3; - if (bufferSize >= (width * m_zoneHeight * 3 + 16)) + if (bufferSize >= zonesBytesLimit) { QueueCommand(command, buffer, bufferSize, m_streamId, delayed); bufferSize = 0; @@ -330,7 +340,7 @@ bool ZeDMDComm::Connect() void ZeDMDComm::Disconnect() { - if (!m_serialPort.IsOpen()) + if (!IsConnected()) return; Reset(); @@ -425,6 +435,11 @@ bool ZeDMDComm::Connect(char *pDevice) return false; } +bool ZeDMDComm::IsConnected() +{ + return m_serialPort.IsOpen(); +} + void ZeDMDComm::Reset() { m_serialPort.ClearDTR(); diff --git a/src/ZeDMDComm.h b/src/ZeDMDComm.h index 685f63f..ad1eed6 100644 --- a/src/ZeDMDComm.h +++ b/src/ZeDMDComm.h @@ -76,6 +76,7 @@ struct ZeDMDFrame #define ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT 10 #define ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX 8 +#define ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX_DELAYED 2 #ifdef __ANDROID__ typedef void *(*ZeDMD_AndroidGetJNIEnvFunc)(); @@ -102,8 +103,9 @@ class ZeDMDComm void IgnoreDevice(const char *ignore_device); void SetDevice(const char *device); - bool Connect(); - void Disconnect(); + virtual bool Connect(); + virtual void Disconnect(); + virtual bool IsConnected(); void Run(); void QueueCommand(char command, uint8_t *buffer, int size, uint16_t width, uint16_t height); @@ -115,20 +117,24 @@ class ZeDMDComm uint16_t GetWidth(); uint16_t GetHeight(); +protected: + virtual bool StreamBytes(ZeDMDFrame* pFrame); + virtual void Reset(); + + uint16_t m_zonesBytesLimit = 0; + uint8_t m_zoneWidth = 8; + uint8_t m_zoneHeight = 4; + private: void LogMessage(const char *format, ...); bool Connect(char *pName); - void Reset(); - bool StreamBytes(ZeDMDFrame *pFrame); ZeDMD_LogMessageCallback m_logMessageCallback = nullptr; const void *m_logMessageUserData = nullptr; uint64_t m_zoneHashes[128] = {0}; uint16_t m_width = 128; uint16_t m_height = 32; - uint8_t m_zoneWidth = 8; - uint8_t m_zoneHeight = 4; int8_t m_streamId = -1; int8_t m_lastStreamId = -1; uint8_t m_flowControlCounter = 0; diff --git a/src/ZeDMDWiFi.cpp b/src/ZeDMDWiFi.cpp index 2fb3c87..dd29894 100644 --- a/src/ZeDMDWiFi.cpp +++ b/src/ZeDMDWiFi.cpp @@ -2,99 +2,6 @@ #include "miniz/miniz.h" #include "komihash/komihash.h" -ZeDMDWiFi::ZeDMDWiFi() -{ - m_pThread = NULL; -} - -ZeDMDWiFi::~ZeDMDWiFi() -{ - if (m_pThread) - { - m_pThread->join(); - - delete m_pThread; - } -} - -void ZeDMDWiFi::SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void *userData) -{ - m_logMessageCallback = callback; - m_logMessageUserData = userData; -} - -void ZeDMDWiFi::LogMessage(const char *format, ...) -{ - if (!m_logMessageCallback) - return; - - va_list args; - va_start(args, format); - (*(m_logMessageCallback))(format, args, m_logMessageUserData); - va_end(args); -} - -void ZeDMDWiFi::Run() -{ - m_pThread = new std::thread([this]() - { - LogMessage("ZeDMDWiFi run thread starting"); - - while (true) - { - m_frameQueueMutex.lock(); - - if (m_frames.empty()) - { - m_frameQueueMutex.unlock(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - ZeDMDWiFiFrame frame = m_frames.front(); - m_frames.pop(); - m_frameQueueMutex.unlock(); - - StreamBytes(&frame); - - if (frame.data) - { - free(frame.data); - } - } - - LogMessage("ZeDMDWiFi run thread finished"); }); -} - -void ZeDMDWiFi::QueueCommand(char command, uint8_t *data, int size, uint16_t width, uint16_t height) -{ - ZeDMDWiFiFrame frame = {0}; - frame.command = command; - frame.size = size; - frame.width = width; - frame.height = height; - - if (data && size > 0) - { - frame.data = (uint8_t *)malloc(size); - memcpy(frame.data, data, size); - } - - m_frameQueueMutex.lock(); - m_frames.push(frame); - m_frameQueueMutex.unlock(); -} - -void ZeDMDWiFi::QueueCommand(char command, uint8_t value) -{ - QueueCommand(command, &value, 1, 0, 0); -} - -void ZeDMDWiFi::QueueCommand(char command) -{ - QueueCommand(command, NULL, 0, 0, 0); -} - bool ZeDMDWiFi::Connect(const char *ip, int port) { #if defined(_WIN32) || defined(_WIN64) @@ -113,6 +20,7 @@ bool ZeDMDWiFi::Connect(const char *ip, int port) m_wifiServer.sin_family = AF_INET; m_wifiServer.sin_port = htons(port); m_wifiServer.sin_addr.s_addr = inet_addr(ip); + m_connected = true; return true; } @@ -126,20 +34,25 @@ void ZeDMDWiFi::Disconnect() #endif } +bool ZeDMDWiFi::IsConnected() +{ + return m_connected; +} + void ZeDMDWiFi::Reset() { } -void ZeDMDWiFi::StreamBytes(ZeDMDWiFiFrame *pFrame) +bool ZeDMDWiFi::StreamBytes(ZeDMDFrame *pFrame) { // An UDP package should not exceed the MTU (WiFi rx_buffer in ESP32 is 1460 bytes). - // We send obe zones of 16 * 8 pixels: - // 128 pixels, 3 bytes RGB per pixel, 5 byte command header: 389 bytes - // And we additionally use compression. + // We send 4 zones of 16 * 8 pixels: + // 512 pixels, 3 bytes RGB per pixel, 4 bytes for zones index, 4 bytes command header: 1544 bytes + // As we additionally use compression, that should be safe. - if (pFrame->size < ZEDMD_WIFI_FRAME_SIZE_COMMAND_LIMIT) + if (pFrame->size < ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT) { - uint8_t data[ZEDMD_WIFI_FRAME_SIZE_COMMAND_LIMIT + 4] = {0}; + uint8_t data[ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT + 4] = {0}; data[0] = pFrame->command; // command data[1] = 0; // not compressed data[2] = (uint8_t)(pFrame->size >> 8 & 0xFF); @@ -159,73 +72,29 @@ void ZeDMDWiFi::StreamBytes(ZeDMDWiFiFrame *pFrame) #endif std::this_thread::sleep_for(std::chrono::milliseconds(10)); } - return; + return true; } - - uint8_t idx = 0; - for (uint16_t y = 0; y < pFrame->height; y += 8) + else { - for (uint16_t x = 0; x < pFrame->width; x += 16) - { - uint8_t data[16 * 8 * 3 + 4] = {0}; - data[0] = pFrame->command; // command - - uint8_t zone[16 * 8 * 3] = {0}; - for (uint8_t z = 0; z < 8; z++) - { - memcpy(&zone[z * 16 * 3], &pFrame->data[((y + z) * pFrame->width + x) * 3], 16 * 3); - } - - uint64_t hash = komihash(zone, 16 * 8 * 3, 0); - if (hash != m_zoneHashes[idx]) - { - m_zoneHashes[idx] = hash; - - if (m_compression) - { - data[1] = (uint8_t)(128 | idx); // compressed + zone index - - mz_ulong compressedSize = 16 * 8 * 3; - int status = mz_compress(&data[4], &compressedSize, zone, 16 * 8 * 3); - data[2] = (uint8_t)(compressedSize >> 8 & 0xFF); - data[3] = (uint8_t)(compressedSize & 0xFF); - - if (status == MZ_OK) - { -#if defined(_WIN32) || defined(_WIN64) - sendto(m_wifiSocket, (const char *)data, compressedSize + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); -#else - sendto(m_wifiSocket, data, compressedSize + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); -#endif - } - } - else - { - data[1] = (uint8_t)idx; // not compressed + zone index + uint8_t data[ZEDMD_WIFI_ZONES_BYTES_LIMIT] = { 0 }; + data[0] = pFrame->command; // command + data[1] = (uint8_t)(128 | (pFrame->size / (m_zoneWidth * m_zoneHeight * 3 + 1))); // compressed + zone index - int size = 16 * 8 * 3; - data[2] = (uint8_t)(size >> 8 & 0xFF); - data[3] = (uint8_t)(size & 0xFF); - memcpy(&data[4], zone, size); + mz_ulong compressedSize = pFrame->size; + int status = mz_compress(&data[4], &compressedSize, pFrame->data, pFrame->size); + data[2] = (uint8_t)(compressedSize >> 8 & 0xFF); + data[3] = (uint8_t)(compressedSize & 0xFF); + if (status == MZ_OK) + { #if defined(_WIN32) || defined(_WIN64) - sendto(m_wifiSocket, (const char *)data, size + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); + sendto(m_wifiSocket, (const char*)data, compressedSize + 4, 0, (struct sockaddr*)&m_wifiServer, sizeof(m_wifiServer)); #else - sendto(m_wifiSocket, data, size + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); + sendto(m_wifiSocket, data, compressedSize + 4, 0, (struct sockaddr*)&m_wifiServer, sizeof(m_wifiServer)); #endif - } - } - idx++; - } + return true; + } } -} -uint16_t ZeDMDWiFi::GetWidth() -{ - return m_width; + return false; } - -uint16_t ZeDMDWiFi::GetHeight() -{ - return m_height; -} \ No newline at end of file diff --git a/src/ZeDMDWiFi.h b/src/ZeDMDWiFi.h index 537888e..519986a 100644 --- a/src/ZeDMDWiFi.h +++ b/src/ZeDMDWiFi.h @@ -9,73 +9,28 @@ #include #define CALLBACK #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "ZeDMDComm.h" -typedef enum -{ - UDP_RGB24 = 0x04, - UDP_ClearScreen = 0x0a, -} ZEDMD_WIFI_COMMAND; +#define ZEDMD_WIFI_ZONES_BYTES_LIMIT 1800 -struct ZeDMDWiFiFrame -{ - uint8_t command; - uint8_t *data; - int size; - int width; - uint8_t height; -}; - -#define ZEDMD_WIFI_FRAME_SIZE_COMMAND_LIMIT 10 - -typedef void(CALLBACK *ZeDMD_LogMessageCallback)(const char *format, va_list args, const void *userData); - -class ZeDMDWiFi +class ZeDMDWiFi : public ZeDMDComm { public: - ZeDMDWiFi(); - ~ZeDMDWiFi(); - - void SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void *userData); - - bool Connect(const char *ip, int port); - void Disconnect(); + ZeDMDWiFi() : ZeDMDComm() + { + m_zonesBytesLimit = ZEDMD_WIFI_ZONES_BYTES_LIMIT; + } - void Run(); - void QueueCommand(char command, uint8_t *buffer, int size, uint16_t width, uint16_t height); - void QueueCommand(char command); - void QueueCommand(char command, uint8_t value); + virtual bool Connect(const char *ip, int port); + virtual void Disconnect(); + virtual bool IsConnected(); - uint16_t GetWidth(); - uint16_t GetHeight(); +protected: + virtual bool StreamBytes(ZeDMDFrame* pFrame); + virtual void Reset(); private: - void LogMessage(const char *format, ...); - - void Reset(); - void StreamBytes(ZeDMDWiFiFrame *pFrame); - - ZeDMD_LogMessageCallback m_logMessageCallback = nullptr; - const void *m_logMessageUserData = nullptr; - - uint16_t m_width = 128; - uint16_t m_height = 32; - - bool m_compression = true; - uint64_t m_zoneHashes[128] = {0}; - int m_wifiSocket; struct sockaddr_in m_wifiServer; - - std::queue m_frames; - std::thread *m_pThread; - std::mutex m_frameQueueMutex; + bool m_connected = false; }; \ No newline at end of file