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

Add ZeDMD WiFi support #49

Merged
merged 9 commits into from
Sep 8, 2024
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ PUPVideosPath =
PUPExactColorMatch = 0

[ZeDMD]
# Set to 1 if ZeDMD is attached.
# Set to 1 if ZeDMD or ZeDMD WiFi is attached.
Enabled = 1
# Disable auto-detection and provide a fixed serial port.
Device =
Expand All @@ -203,6 +203,12 @@ RGBOrder = -1
Brightness = -1
# Set to 1 to permantenly store the overwritten settings above in ZeDMD internally.
SaveSettings = 0
# ZeDMD WiFi enabled? This will disable COM port communication
WiFiEnabled = 0
# ZeDMD WiFi IP address, you must fill this in for WiFi to work
WiFiAddr =
# ZeDMD Wifi Port number, you can leave this empty and it will default to 3333
WiFiPort =

[Pixelcade]
# Set to 1 if Pixelcade is attached
Expand Down
10 changes: 8 additions & 2 deletions dmdserver.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

[DMDServer]
# The address (interface) to listen for TCP connections.
Addr = localhost
Addr = 0.0.0.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @jsm174 that 127.0.0.1 is the better and safer default.
I understand that the usage should be as easy as possible.
But you don't sell a car without a handbrake just because people might to forget to release it before driving.
The default usage for dmdserver is to run on the same machine as the clients like VPX or batocera. In your new handheld device, dmdserver will also run on the same device or you would use libdmdutil directly (embedded in VPX).

# The port to listen for TCP connections.
Port = 6789
# Set to 1 if Serum colorization should be used, 0 if not.
Expand All @@ -16,7 +16,7 @@ PUPVideosPath =
PUPExactColorMatch = 1

[ZeDMD]
# Set to 1 if ZeDMD is attached.
# Set to 1 if ZeDMD or ZeDMD WiFI is attached.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DMDext we treat ZeDMD and ZeDMD WiFi as different devices. For example, ZeDMDWiFi doesn't support setting brightness or RGB order over the WiFi stream.

And it would be nice to have the possibility to attach two devices, one via USB within the cab and a second via WiFi at the wall ;-)

But maybe we can do the split in a second step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we only need to modify findDisplays to get simultaneous functionality working. My question is: how should we handle failures? If I have both a ZeDMD Serial and a ZeDMD Wifi configured in the dmdserver.ini, should the thread stop if it fails to find one of them, or should it continue with whichever one is available?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DMDext we treat ZeDMD and ZeDMD WiFi as different devices. For example, ZeDMDWiFi doesn't support setting brightness or RGB order over the WiFi stream.

And it would be nice to have the possibility to attach two devices, one via USB within the cab and a second via WiFi at the wall ;-)

But maybe we can do the split in a second step.

See the latest commit; i have changed it to working with 2 at the same time and seperated the config stuff.

Copy link
Contributor Author

@bartdesign bartdesign Sep 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I've set up error handling so that the system will continue if it finds at least one of the two configured displays. Let me know what you think is the best approach for handling this.

Enabled = 1
# Disable auto-detection and provide a fixed serial port.
Device =
Expand All @@ -33,6 +33,12 @@ RGBOrder = -1
Brightness = -1
# Set to 1 to permantenly store the overwritten settings above in ZeDMD internally.
SaveSettings = 0
# ZeDMD WiFi enabled? This will disable COM port communication
WiFiEnabled = 0
# ZeDMD WiFi IP address, you must fill this in for WiFi to work
WiFiAddr =
# ZeDMD Wifi Port number, you can leave this empty and it will default to 3333
WiFiPort =
bartdesign marked this conversation as resolved.
Show resolved Hide resolved

[Pixelcade]
# Set to 1 if Pixelcade is attached
Expand Down
9 changes: 9 additions & 0 deletions include/DMDUtil/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ class DMDUTILAPI Config
void SetZeDMDBrightness(int brightness) { m_zedmdBrightness = brightness; }
bool IsZeDMDSaveSettings() const { return m_zedmdSaveSettings; }
void SetZeDMDSaveSettings(bool saveSettings) { m_zedmdSaveSettings = saveSettings; }
bool IsZeDMDWiFiEnabled() const { return m_zedmdWiFiEnabled; }
void SetZeDMDWiFiEnabled(bool WiFiEnabled) { m_zedmdWiFiEnabled = WiFiEnabled; }
const char* GetZeDMDWiFiAddr() const { return m_zedmdWiFiAddr.c_str(); }
void SetZeDMDWiFiAddr(const char* ipaddr) { m_zedmdWiFiAddr = ipaddr; }
int GetZeDMDWiFiPort() const { return m_zedmdWiFiPort; }
void SetZeDMDWiFiPort(int port) { m_zedmdWiFiPort = port; }
bool IsPixelcade() const { return m_pixelcade; }
void SetPixelcade(bool pixelcade) { m_pixelcade = pixelcade; }
void SetPixelcadeDevice(const char* port) { m_pixelcadeDevice = port; }
Expand Down Expand Up @@ -101,6 +107,9 @@ class DMDUTILAPI Config
int m_zedmdRgbOrder;
int m_zedmdBrightness;
bool m_zedmdSaveSettings;
bool m_zedmdWiFiEnabled;
std::string m_zedmdWiFiAddr;
int m_zedmdWiFiPort;
bool m_dmdServer;
std::string m_dmdServerAddr;
int m_dmdServerPort;
Expand Down
55 changes: 39 additions & 16 deletions src/DMD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,25 +476,48 @@ void DMD::FindDisplays()
pZeDMD = new ZeDMD();
pZeDMD->SetLogCallback(ZeDMDLogCallback, nullptr);

if (pConfig->GetZeDMDDevice() != nullptr && pConfig->GetZeDMDDevice()[0] != '\0')
pZeDMD->SetDevice(pConfig->GetZeDMDDevice());

bool open = false;
if ((open = pZeDMD->Open()))

if (pConfig->IsZeDMDWiFiEnabled())
{
if (pConfig->GetZeDMDBrightness() != -1) pZeDMD->SetBrightness(pConfig->GetZeDMDBrightness());
if (pConfig->IsZeDMDSaveSettings())
std::string WiFiAddr = pConfig->GetZeDMDWiFiAddr() ? pConfig->GetZeDMDWiFiAddr() : "";
uint16_t udpPortNumber = pConfig->GetZeDMDWiFiPort() > 0 ? pConfig->GetZeDMDWiFiPort() : 3333;

if (WiFiAddr.empty())
{
DMDUtil::Log(DMDUtil_LogLevel_ERROR, "ERROR: ZeDMD WiFi IP address is not configured.");
}

// Proceed only if the WiFiAddr is valid.
if (!WiFiAddr.empty() && (open = pZeDMD->OpenWiFi(WiFiAddr.c_str(), udpPortNumber)))
{
// Fix RGB and brightness
bartdesign marked this conversation as resolved.
Show resolved Hide resolved
std::stringstream logMessage;
logMessage << "ZeDMD WiFi enabled, connected to " << WiFiAddr << ":" << udpPortNumber << ".";
DMDUtil::Log(DMDUtil_LogLevel_INFO, logMessage.str().c_str());
}
}
else // Serial communication
{
if (pConfig->GetZeDMDDevice() != nullptr && pConfig->GetZeDMDDevice()[0] != '\0')
pZeDMD->SetDevice(pConfig->GetZeDMDDevice());

if ((open = pZeDMD->Open()))
{
if (pConfig->GetZeDMDRGBOrder() != -1) pZeDMD->SetRGBOrder(pConfig->GetZeDMDRGBOrder());
pZeDMD->SaveSettings();
if (pConfig->GetZeDMDRGBOrder() != -1)
if (pConfig->GetZeDMDBrightness() != -1) pZeDMD->SetBrightness(pConfig->GetZeDMDBrightness());
if (pConfig->IsZeDMDSaveSettings())
{
// Setting the RGBOrder requires a reboot.
pZeDMD->Reset();
std::this_thread::sleep_for(std::chrono::seconds(8));
pZeDMD->Close();
std::this_thread::sleep_for(std::chrono::seconds(1));
open = pZeDMD->Open();
if (pConfig->GetZeDMDRGBOrder() != -1) pZeDMD->SetRGBOrder(pConfig->GetZeDMDRGBOrder());
pZeDMD->SaveSettings();
if (pConfig->GetZeDMDRGBOrder() != -1)
{
// Setting the RGBOrder requires a reboot.
pZeDMD->Reset();
std::this_thread::sleep_for(std::chrono::seconds(8));
pZeDMD->Close();
std::this_thread::sleep_for(std::chrono::seconds(1));
open = pZeDMD->Open();
}
}
}
}
Expand Down Expand Up @@ -1386,7 +1409,7 @@ void DMD::AdjustRGB24Depth(uint8_t* pData, uint8_t* pDstData, int length, uint8_
level = (uint8_t)(v >> 4);

int pos2 = level * 3;
pDstData[pos ] = palette[pos2];
pDstData[pos] = palette[pos2];
pDstData[pos + 1] = palette[pos2 + 1];
pDstData[pos + 2] = palette[pos2 + 2];
}
Expand Down
6 changes: 5 additions & 1 deletion src/dmdServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ int main(int argc, char* argv[])
pConfig->SetZeDMDRGBOrder(r.Get<int>("ZeDMD", "RGBOrder", -1));
pConfig->SetZeDMDBrightness(r.Get<int>("ZeDMD", "Brightness", -1));
pConfig->SetZeDMDSaveSettings(r.Get<bool>("ZeDMD", "SaveSettings", false));
// ZeDMD WiFi
pConfig->SetZeDMDWiFiEnabled(r.Get<bool>("ZeDMD", "WiFiEnabled", false));
pConfig->SetZeDMDWiFiAddr(r.Get<string>("ZeDMD", "WiFiAddr", "").c_str());
pConfig->SetZeDMDWiFiPort(r.Get<int>("ZeDMD", "WiFiPort", 3333));
// Pixelcade
pConfig->SetPixelcade(r.Get<bool>("Pixelcade", "Enabled", true));
pConfig->SetPixelcadeDevice(r.Get<string>("Pixelcade", "Device", "").c_str());
Expand Down Expand Up @@ -334,7 +338,7 @@ int main(int argc, char* argv[])

sockpp::initialize();
if (opt_verbose)
DMDUtil::Log(DMDUtil_LogLevel_INFO, "Opening DMDServer, listining for TCP connections on %s:%d",
DMDUtil::Log(DMDUtil_LogLevel_INFO, "Opening DMDServer, listening for TCP connections on %s:%d",
pConfig->GetDMDServerAddr(), pConfig->GetDMDServerPort());
sockpp::tcp_acceptor acc({pConfig->GetDMDServerAddr(), (in_port_t)pConfig->GetDMDServerPort()});
if (!acc)
Expand Down