Skip to content

Commit

Permalink
introduced AltColorHeader
Browse files Browse the repository at this point in the history
  • Loading branch information
mkalkbrenner committed Mar 8, 2024
1 parent 62210d3 commit 935fbca
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 35 deletions.
19 changes: 7 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,12 @@ The DmdStreamHeader is defined as a struct:
```
struct DMDUtil::DMD::StreamHeader
{
char protocol[10] = "DMDStream"; // \0 terminated string
char header[10] = "DMDStream"; // \0 terminated string
uint8_t version = 1;
Mode mode = Mode::Data; // int
Mode mode = Mode::Data; // int
uint16_t width = 0;
uint16_t height = 0;
uint32_t length = 0;
char name[16] = {0}; // \0 terminated string, ROM name
char path[256] = {0}; // \0 terminated string, altcolor path
};
```
Expand All @@ -97,9 +95,11 @@ Each pixel consist of one uint16_t having its color encoded in 16bit according t
`Mode::Data` is a serialized stream of the `DMDUtil::DMD::Update` struct.
It will be sent from a client which uses libdmdutil itself (for example VPX Standalone or PPUC).
In case of `Mode::Data`, `StreamHeader.width`, `StreamHeader.height` and `StreamHeader.length` should be set to zero.
`StreamHeader.name` and `StreamHeader.path` have to be set to the ROM name and the altcolor path if Serum colorization should be used.
The data itself contains that information and a lot of additional data like instructions to map alphanummeric displays to DMDs or
colorizations of grayscale content.
There will be an additional `AltColorHeader` header sent before the data to the transmit the ROM name and the altcolor path
in case Serum colorization should be used.
The data itself contains a lot of additional data like instructions to map alphanummeric displays to DMDs or colorizations of
grayscale content.

So if you want to write a general purpose client to display images or text, you're adviced to use `Mode::RGB24` or `Mode::RGB216`!

### Notes
Expand All @@ -108,9 +108,6 @@ At the moment, `StreamHeader.length` is a redundant information as it could be c
`StreamHeader.height` in combination with `StreamHeader.mode`.
But if data compression will be supported in future versions, it will become important.

In case of `Mode::RGB24` and `Mode::RGB216` it seems strange to append 16 + 256 zeros to the end of the header.
But for effency and maintainability we decided to work with a fixed header size for all modes.

### Examples

To send a RGB24 image of 4x2 pixels, you have to sent these two packages:
Expand All @@ -122,8 +119,6 @@ To send a RGB24 image of 4x2 pixels, you have to sent these two packages:
0x04 0x00 // width 4 (if your system is big endian, the byte order needs to be swapped)
0x02 0x00 // height 2 (if your system is big endian, the byte order needs to be swapped)
0x18 0x00 0x00 0x00 // length 24 (if your system is big endian, the byte order needs to be swapped)
0x00 ... // 16 bytes of zeros
0x00 ... // 256 bytes of zeros
```

```
Expand Down
7 changes: 6 additions & 1 deletion include/DMDUtil/DMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,17 @@ class DMDUTILAPI DMD

struct StreamHeader
{
char protocol[10] = "DMDStream";
char header[10] = "DMDStream";
uint8_t version = 1;
Mode mode = Mode::Data; // int
uint16_t width = 0;
uint16_t height = 0;
uint32_t length = 0;
};

struct AltColorHeader
{
char header[9] = "AltColor";
char name[DMDUTIL_MAX_NAME_SIZE] = {0};
char path[DMDUTIL_MAX_ALTCOLORPATH_SIZE] = {0};
};
Expand Down
10 changes: 6 additions & 4 deletions src/DMD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,12 @@ void DMD::QueueUpdate(Update dmdUpdate)

if (m_pDMDServerConnector)
{
StreamHeader header;
strcpy(header.name, m_romName);
strcpy(header.path, m_altColorPath);
m_pDMDServerConnector->write_n(&header, sizeof(StreamHeader));
StreamHeader streamHeader;
m_pDMDServerConnector->write_n(&streamHeader, sizeof(StreamHeader));
AltColorHeader altColorHeader;
strcpy(altColorHeader.name, m_romName);
strcpy(altColorHeader.path, m_altColorPath);
m_pDMDServerConnector->write_n(&altColorHeader, sizeof(AltColorHeader));
m_pDMDServerConnector->write_n(&dmdUpdate, sizeof(Update));
}
})
Expand Down
47 changes: 29 additions & 18 deletions src/dmdServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void DMDUTILCALLBACK LogCallback(const char* format, va_list args)
void run(sockpp::tcp_socket sock, uint32_t threadId)
{
uint8_t buffer[sizeof(DMDUtil::DMD::Update)];
DMDUtil::DMD::StreamHeader* pHeader = (DMDUtil::DMD::StreamHeader*)malloc(sizeof(DMDUtil::DMD::StreamHeader));
DMDUtil::DMD::StreamHeader* pStreamHeader = (DMDUtil::DMD::StreamHeader*)malloc(sizeof(DMDUtil::DMD::StreamHeader));
ssize_t n;

while ((n = sock.read_n(buffer, sizeof(DMDUtil::DMD::StreamHeader))) > 0)
Expand All @@ -56,44 +56,55 @@ void run(sockpp::tcp_socket sock, uint32_t threadId)
{
// At the moment the server only listens on localhost.
// Therefore, we don't have to take care about litte vs. big endian and can use memcpy.
memcpy(pHeader, buffer, n);
if (strcmp(pHeader->protocol, "DMDStream") == 0 && pHeader->version == 1)
memcpy(pStreamHeader, buffer, n);
if (strcmp(pStreamHeader->header, "DMDStream") == 0 && pStreamHeader->version == 1)
{
switch (pHeader->mode)
switch (pStreamHeader->mode)
{
case DMDUtil::DMD::Mode::Data:
if ((n = sock.read_n(buffer, sizeof(DMDUtil::DMD::Update))) == sizeof(DMDUtil::DMD::Update) &&
if ((n = sock.read_n(buffer, sizeof(DMDUtil::DMD::AltColorHeader))) ==
sizeof(DMDUtil::DMD::AltColorHeader) &&
threadId == currentThreadId)
{
DMDUtil::DMD::Update data;
memcpy(&data, buffer, n);
DMDUtil::DMD::AltColorHeader altColorHeader;
memcpy(&altColorHeader, buffer, n);

if (data.width <= DMDSERVER_MAX_WIDTH && data.height <= DMDSERVER_MAX_HEIGHT)
if (strcmp(altColorHeader.header, "AltColor") == 0 &&
(n = sock.read_n(buffer, sizeof(DMDUtil::DMD::Update))) == sizeof(DMDUtil::DMD::Update) &&
threadId == currentThreadId)
{
pDmd->SetRomName(pHeader->name);
pDmd->SetAltColorPath(pHeader->path);
DMDUtil::DMD::Update data;
memcpy(&data, buffer, n);

pDmd->QueueUpdate(data);
if (data.width <= DMDSERVER_MAX_WIDTH && data.height <= DMDSERVER_MAX_HEIGHT)
{
pDmd->SetRomName(altColorHeader.name);
pDmd->SetAltColorPath(altColorHeader.path);

pDmd->QueueUpdate(data);
}
}
}
break;

case DMDUtil::DMD::Mode::RGB16:
if ((n = sock.read_n(buffer, pHeader->length)) == pHeader->length && threadId == currentThreadId &&
pHeader->width <= DMDSERVER_MAX_WIDTH && pHeader->height <= DMDSERVER_MAX_HEIGHT)
if ((n = sock.read_n(buffer, pStreamHeader->length)) == pStreamHeader->length &&
threadId == currentThreadId && pStreamHeader->width <= DMDSERVER_MAX_WIDTH &&
pStreamHeader->height <= DMDSERVER_MAX_HEIGHT)
{
// At the moment the server only listens on localhost.
// Therefore, we don't have to take care about litte vs. big endian and can use the buffer as uint16_t as
// it is.
pDmd->UpdateRGB16Data((uint16_t*)buffer, pHeader->width, pHeader->height);
pDmd->UpdateRGB16Data((uint16_t*)buffer, pStreamHeader->width, pStreamHeader->height);
}
break;

case DMDUtil::DMD::Mode::RGB24:
if ((n = sock.read_n(buffer, pHeader->length)) == pHeader->length && threadId == currentThreadId &&
pHeader->width <= DMDSERVER_MAX_WIDTH && pHeader->height <= DMDSERVER_MAX_HEIGHT)
if ((n = sock.read_n(buffer, pStreamHeader->length)) == pStreamHeader->length &&
threadId == currentThreadId && pStreamHeader->width <= DMDSERVER_MAX_WIDTH &&
pStreamHeader->height <= DMDSERVER_MAX_HEIGHT)
{
pDmd->UpdateRGB24Data(buffer, pHeader->width, pHeader->height);
pDmd->UpdateRGB24Data(buffer, pStreamHeader->width, pStreamHeader->height);
}
break;

Expand All @@ -113,7 +124,7 @@ void run(sockpp::tcp_socket sock, uint32_t threadId)
threads.erase(remove(threads.begin(), threads.end(), threadId), threads.end());
currentThreadId = threads.back();

free(pHeader);
free(pStreamHeader);
}

int main(int argc, char* argv[])
Expand Down

0 comments on commit 935fbca

Please sign in to comment.