Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rgb565 #17

Merged
merged 11 commits into from
Jan 21, 2024
37 changes: 36 additions & 1 deletion src/ZeDMD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ ZeDMD::ZeDMD() {
m_pScaledFrameBuffer = nullptr;
m_pCommandBuffer = nullptr;
m_pPlanes = nullptr;
m_pRgb565Buffer = nullptr;

m_pZeDMDComm = new ZeDMDComm();
m_pZeDMDWiFi = new ZeDMDWiFi();
Expand All @@ -41,6 +42,10 @@ ZeDMD::~ZeDMD() {
if (m_pPlanes) {
delete m_pPlanes;
}

if (m_pRgb565Buffer) {
delete m_pRgb565Buffer;
}
}

void ZeDMD::SetLogCallback(ZeDMD_LogCallback callback, const void* userData) {
Expand Down Expand Up @@ -187,6 +192,7 @@ bool ZeDMD::Open() {
m_pCommandBuffer =
(uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3 + 192);
m_pPlanes = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3);
m_pRgb565Buffer = (uint16_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT);

m_hd = (m_pZeDMDComm->GetWidth() == 256);

Expand Down Expand Up @@ -262,6 +268,8 @@ void ZeDMD::ClearScreen() {
} else if (m_wifi) {
m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::ClearScreen);
}
// "Blank" the frame buffer.
memset(m_pFrameBuffer, 0, ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3);
}

void ZeDMD::RenderGray2(uint8_t* pFrame) {
Expand Down Expand Up @@ -388,7 +396,7 @@ void ZeDMD::RenderRgb24(uint8_t* pFrame) {
if (m_wifi) {
m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes,
bufferSize, width, height);
} else if (m_hd || m_rgb24Streaming) {
} else if (m_hd || m_rgb24Streaming || m_streaming) {
m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes,
bufferSize, width, height);
} else if (m_usb) {
Expand All @@ -397,6 +405,29 @@ void ZeDMD::RenderRgb24(uint8_t* pFrame) {
}
}

void ZeDMD::RenderRgb24EncodedAs565(uint8_t* pFrame) {
if (!m_usb || !UpdateFrameBuffer24(pFrame)) {
return;
}

uint16_t width;
uint16_t height;

int bufferSize = Scale(m_pPlanes, m_pFrameBuffer, 3, &width, &height);
int rgb565BufferSize = bufferSize / 3;
for (uint16_t i = 0; i < rgb565BufferSize; i++) {
m_pRgb565Buffer[i] = (((uint16_t)(m_pPlanes[i * 3] & 0xF8)) << 8) |
(((uint16_t)(m_pPlanes[i * 3 + 1] & 0xFC)) << 3) |
(m_pPlanes[i * 3 + 2] >> 3);
}

if (m_usb) {
m_pZeDMDComm->QueueRgb565Command(ZEDMD_COMM_COMMAND::RGB565ZonesStream,
m_pRgb565Buffer, rgb565BufferSize, width,
height);
}
}

bool ZeDMD::UpdateFrameBuffer8(uint8_t* pFrame) {
if (!memcmp(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight)) {
return false;
Expand Down Expand Up @@ -867,3 +898,7 @@ ZEDMDAPI void ZeDMD_RenderColoredGray6(ZeDMD* pZeDMD, uint8_t* frame,
ZEDMDAPI void ZeDMD_RenderRgb24(ZeDMD* pZeDMD, uint8_t* frame) {
return pZeDMD->RenderRgb24(frame);
}

ZEDMDAPI void ZeDMD_RenderRgb24EncodedAs565(ZeDMD* pZeDMD, uint8_t* frame) {
return pZeDMD->RenderRgb24EncodedAs565(frame);
}
8 changes: 6 additions & 2 deletions src/ZeDMD.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#pragma once

#define ZEDMD_VERSION_MAJOR 0 // X Digits
#define ZEDMD_VERSION_MINOR 4 // Max 2 Digits
#define ZEDMD_VERSION_PATCH 1 // Max 2 Digits
#define ZEDMD_VERSION_MINOR 5 // Max 2 Digits
#define ZEDMD_VERSION_PATCH 0 // Max 2 Digits

#define _ZEDMD_STR(x) #x
#define ZEDMD_STR(x) _ZEDMD_STR(x)
Expand Down Expand Up @@ -78,6 +78,7 @@ class ZEDMDAPI ZeDMD {
void RenderColoredGray6(uint8_t* frame, uint8_t* palette, uint8_t* rotations);
void RenderColoredGray6(uint8_t* frame, uint8_t* rotations);
void RenderRgb24(uint8_t* frame);
void RenderRgb24EncodedAs565(uint8_t* frame);

private:
bool UpdateFrameBuffer8(uint8_t* pFrame);
Expand Down Expand Up @@ -111,6 +112,7 @@ class ZEDMDAPI ZeDMD {
uint8_t* m_pScaledFrameBuffer;
uint8_t* m_pCommandBuffer;
uint8_t* m_pPlanes;
uint16_t* m_pRgb565Buffer;

uint8_t m_palette4[4 * 3] = {0};
uint8_t m_palette16[16 * 3] = {0};
Expand Down Expand Up @@ -166,6 +168,8 @@ extern ZEDMDAPI void ZeDMD_RenderGray4(ZeDMD* pZeDMD, uint8_t* frame);
extern ZEDMDAPI void ZeDMD_RenderColoredGray6(ZeDMD* pZeDMD, uint8_t* frame,
uint8_t* rotations);
extern ZEDMDAPI void ZeDMD_RenderRgb24(ZeDMD* pZeDMD, uint8_t* frame);
extern ZEDMDAPI void ZeDMD_RenderRgb24EncodedAs565(ZeDMD* pZeDMD,
uint8_t* frame);

#ifdef __cplusplus
}
Expand Down
87 changes: 85 additions & 2 deletions src/ZeDMDComm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ void ZeDMDComm::Run() {
int8_t lastStreamId = -1;

while (IsConnected()) {
bool frame_completed = false;

m_frameQueueMutex.lock();

if (m_frames.empty()) {
Expand Down Expand Up @@ -89,12 +91,14 @@ void ZeDMDComm::Run() {
if (frame.streamId != lastStreamId) {
if (lastStreamId != -1) {
m_frameCounter--;
frame_completed = true;
}

lastStreamId = frame.streamId;
}
} else {
m_frameCounter--;
frame_completed = true;
}

m_frameQueueMutex.unlock();
Expand All @@ -112,6 +116,7 @@ void ZeDMDComm::Run() {
}

if (!success) {
// Allow ZeDMD to empty its buffers.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
}
Expand Down Expand Up @@ -147,6 +152,8 @@ void ZeDMDComm::QueueCommand(char command, uint8_t* data, int size,
m_delayedFrameReady = true;
m_delayedFrameMutex.unlock();
m_lastStreamId = -1;
// Next streaming needs to be complete.
memset(m_zoneHashes, 0, sizeof(m_zoneHashes));
}
// delayed streamed zones
else if (streamId != -1 && delayed) {
Expand All @@ -162,6 +169,10 @@ void ZeDMDComm::QueueCommand(char command, uint8_t* data, int size,
}
m_frames.push(frame);
m_frameQueueMutex.unlock();
if (streamId == -1) {
// Next streaming needs to be complete.
memset(m_zoneHashes, 0, sizeof(m_zoneHashes));
}
}
}

Expand Down Expand Up @@ -203,7 +214,7 @@ void ZeDMDComm::QueueCommand(char command, uint8_t* data, int size,

m_delayedFrameMutex.unlock();
// A delayed frame needs to be complete.
memset(m_zoneHashes, 0, 128);
memset(m_zoneHashes, 0, sizeof(m_zoneHashes));
}

for (uint16_t y = 0; y < height; y += m_zoneHeight) {
Expand Down Expand Up @@ -241,6 +252,78 @@ void ZeDMDComm::QueueCommand(char command, uint8_t* data, int size,
}
}

void ZeDMDComm::QueueRgb565Command(char command, uint16_t* data, int size,
uint16_t width, uint16_t height) {
uint8_t buffer[256 * 16 * 2 + 16];
uint16_t bufferSize = 0;
uint8_t idx = 0;
uint8_t zone[16 * 8 * 2] = {0};
uint16_t zonesBytesLimit = 0;
if (m_zonesBytesLimit) {
while (zonesBytesLimit < m_zonesBytesLimit) {
zonesBytesLimit += m_zoneWidth * m_zoneHeight * 2 + 1;
}
} else {
zonesBytesLimit = width * m_zoneHeight * 2 + 16;
}

if (++m_streamId > 64) {
m_streamId = 0;
}

bool delayed = false;
if (FillDelayed()) {
delayed = true;
m_delayedFrameMutex.lock();
m_delayedFrameReady = false;
while (m_delayedFrames.size() > 0) {
m_delayedFrames.pop();
}

m_delayedFrameMutex.unlock();
// A delayed frame needs to be complete.
memset(m_zoneHashes, 0, sizeof(m_zoneHashes));
}

for (uint16_t y = 0; y < height; y += m_zoneHeight) {
for (uint16_t x = 0; x < width; x += m_zoneWidth) {
for (uint8_t zy = 0; zy < m_zoneHeight; zy++) {
for (uint8_t zx = 0; zx < m_zoneWidth; zx++) {
zone[(zy * m_zoneWidth + zx) * 2] =
data[((y + zy) * width) + x + zx] >> 8;
zone[(zy * m_zoneWidth + zx) * 2 + 1] =
data[((y + zy) * width) + x + zx] & 0xFF;
}
}

uint64_t hash = komihash(zone, m_zoneWidth * m_zoneHeight * 2, 0);
if (hash != m_zoneHashes[idx]) {
m_zoneHashes[idx] = hash;

buffer[bufferSize++] = idx;
memcpy(&buffer[bufferSize], zone, m_zoneWidth * m_zoneHeight * 2);
bufferSize += m_zoneWidth * m_zoneHeight * 2;

if (bufferSize >= zonesBytesLimit) {
QueueCommand(command, buffer, bufferSize, m_streamId, delayed);
bufferSize = 0;
}
}
idx++;
}
}

if (bufferSize > 0) {
QueueCommand(command, buffer, bufferSize, m_streamId, delayed);
}

if (delayed) {
m_delayedFrameMutex.lock();
m_delayedFrameReady = true;
m_delayedFrameMutex.unlock();
}
}

bool ZeDMDComm::FillDelayed() {
uint8_t count = 0;
bool delayed = false;
Expand Down Expand Up @@ -400,7 +483,7 @@ bool ZeDMDComm::Connect(char* pDevice) {
ZEDMD_COMM_SERIAL_READ_TIMEOUT) &&
data[0] == 'R') {
data[0] = ZEDMD_COMM_COMMAND::Chunk;
data[1] = ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE / 256;
data[1] = ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE / 32;
sp_blocking_write(m_pSerialPort, (void*)CTRL_CHARS_HEADER, 6,
ZEDMD_COMM_SERIAL_WRITE_TIMEOUT);
sp_blocking_write(m_pSerialPort, (void*)data, 2,
Expand Down
7 changes: 5 additions & 2 deletions src/ZeDMDComm.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ typedef enum {

RGB24 = 0x03,
RGB24ZonesStream = 0x04,
RGB565ZonesStream = 0x05,
Gray2 = 0x08,
ColGray4 = 0x09,
ColGray6 = 0x0b,
Expand All @@ -69,11 +70,11 @@ struct ZeDMDFrame {
#define ZEDMD_COMM_BAUD_RATE 921600

#if defined(_WIN32) || defined(_WIN64)
#define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 8192
#define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 1888
#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 16
#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16
#else
#define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 4096
#define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 1888
#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 32
#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16
#endif
Expand Down Expand Up @@ -107,6 +108,8 @@ class ZeDMDComm {
void Run();
void QueueCommand(char command, uint8_t* buffer, int size, uint16_t width,
uint16_t height);
void QueueRgb565Command(char command, uint16_t* buffer, int size,
uint16_t width, uint16_t height);
void QueueCommand(char command, uint8_t* buffer, int size,
int8_t streamId = -1, bool delayed = false);
void QueueCommand(char command);
Expand Down
Loading
Loading