Reverse engineering an LCD wall’s communications protocol

Kye Lewis
Kye Lewis
Sep 8, 2018 · 5 min read

Not satisfied with 80s-style consumer IR control? I’m not.

I want to build a modern wireless tablet setup & control for a newly-acquired LCD Wall product.

In order to do that, I need to find out more about the proprietary communications protocol behind it.


Finding the original software

After checking google for software for hours, I tracked down the original control software by emailing the manufacturer, who sent us a handy Dropbox link to the latest software version. That was easy enough!


Run the software and see what happens

Luckily the username and password were tucked in this text document in the software folder.

Through an obscure username/password combination, some somewhat broken translation and needless complexity in the software, I worked out how to make it function just fine.

But that’s not modern enough- it would be confusing for staff operating it, and far less efficient than it could be. There’s still room for improvement..


Starting to reverse engineer the software

For this particular software, there were some obvious signs it was a .NET application- it used an SQLite database, it contained a number of .NET specific files within the folder, and named .NET in the text file with the passwords from the last step.

I dug in to a free .NET decompiler — ILSpy (https://github.com/icsharpcode/ILSpy) — to see if this was the right path to go down. Opening the executable in ILSpy showed the resources, but not the code in the way I expected.

It looks like we have some extra work to do.

The manufacturer has used an obfuscater called ConfuserEx to try to prevent reverse engineering of this software.

Luckily most obsfucation software like this is only a slight annoyance and can be reversed- in this case, an existing bit of software called NoFuserEx provided the assistance I needed. Once I ran the .exe through NoFuserEx, I got…

This looks much more useful.

A much more useful result for us.


Digging through the code to find what is needed

The window we’re looking for in code… the original software wasn’t quite so well translated, but the translation file was easy to update.

When setting up these particular monitors, the first has direct Ethernet control- the rest link through with RS232 (serial) connection.

Each individual monitor takes an identical video input, and then displays only the part of the video image relevant to where it is on the wall- in this way, one video signal can be spanned across multiple monitors.

An example of a 4x4 Video Wall setup taken from Google Image Search.

Initially, none of the panels knows where it is located on the wall, and therefore they don’t know which part of the image they are supposed to display.

The software has a “Set ID” function that, according to the manual, takes a four-digit temporary code displayed on the screen and allows you to use that to tell the monitors where they are physically positioned in that grid.

The software splits the four-digit code on the TV in to two parts (Code1 and Code2), and then asks you for an LcdId- which is a two digit number consisting of the column followed by the row that you want to move that display to.

The code for this popup is found under EditLCDViewModel

This code sets up a six-byte array with some values, and then runs it through a SendMsg method which eventually send the command to the monitor.

Initially the byte array looks like:

213, byte.MaxValue, 0, 0, 0, 170

byte.MaxValue is always 255, so it can be written as:

215, 255, 0, 0, 0, 170

The code then proceeds to update the three zeros with the contents of Code1, Code2 and LcdId such that you get:

215, 255, Code1, Code2, LcdId, 170

So for example, if the screen is displaying code 1234, and you want it to be in column 2, row 5, you should send:

215, 255, 12, 34, 25, 170

So let’s test that out in a small program to check that it works!


A quick test in Go to make sure it’s correct

From the software setup dialogs, I already know that the default IP address on the monitor is 192.168.0.66, and the default communications port is TCP Port 1024. So now all that’s left to do is write some code.

A simple, imperfect Go program to send the commands.
The output of the program shows it working as planned, outputting the Code 1, Code 2 and LcdId for each monitor in order

The code runs, and all works to plan! All you have to do is run the command, entering the wall dimensions, and a list of the codes in order from left to right, top to bottom, and the hard work is done for you!


Next Steps?

Right now you still need to use the remote to display the codes on the monitors, making this code not so useful.

Thankfully, the menu can be triggered through IP as well.

Some notes I’ve taken from the code going along for the large list of commands the software has.

Once that’s in place and working, I’ll get to the task of writing a small iPad app using Flutter that can streamline this setup.

Less time spent fussing on the tech on-site so there’s more time to spend on more important things!

UPDATE: I created a list of useful network commands discovered at:
https://themodernmachine.nyc3.digitaloceanspaces.com/PJ-B551P-V6F%20Seamless%20Monitor%20Network%20Protocol.pdf


If you liked any of the content here, please leave some feedback on Medium or get in contact!

Kye Lewis

Written by

Kye Lewis

Technical Director & technology advocate. I follow cryptocurrency, personal transport, wearables. Opinions are my own.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade