Hacking the Dream Cheeky USB LED Message Board
For some reason I always pick up these dumb scrolling message things at Fry’s, first one had an embedded uC that Furan had hacked by RE’ing the wires and installing a new uC, this one has USB but doesn’t work without the program running on the Host PC….
So lets hack it..
First thing is that it is a USB HID , so that is fairly straightforward. HID Write comes into play here. Jan Axelson is pretty much the standard for USB/serial etc http://www.lvr.com/hidpage.htm
A quick poke around the bytes look like, brightness, location, data. 0xFF is all off, 0×00 all on. right most byte is left most on the display at 0×00 0×00 0xFF 0xFF 0xFF 0xFF 0×00
First byte is brightness
Second byte is vertical row 0×5 is the bottom, two lines are written at once. If you give it 0×6 it’ll write the first line to the last row, then wrap after a few that disappear.
It takes 0×9 message length, and no read back.
That’s it on the hardware side really!
Using usbhido_vc6 as an example, all you have to do is FindHid() with the VID/PID set, and then do
I just threw in some junk code to show it working
if( MyDeviceDetected ) {
// always
OutputReport[0 ] = 0×0;// brightness 0 .. 15
OutputReport[1 ] = 15;OutputReport[2 ] = row;
row+=2;
row%=8;
// fill in some random data
for( int i= 3 ; i < 10 ;i ++ ) {
OutputReport[i]++;;
}if (WriteHandle != INVALID_HANDLE_VALUE)
{
HRESULT Result = HidD_SetOutputReport
(WriteHandle,
OutputReport,
9); // fixed length (comes from device report)
}
}
It’s trivial to treat the output as a frame buffer, 21×7
so the header of the OutputReport[] looks like
offset 0, always 00
offset 1, brightness, 0-15
offset 2, row *2
then the remaining bytes are
offset 3, 0×00 – right hand side 5 LEDS on
offset 4, 0×00 – middle 8 LEDS all on
offset 5, 0×00 – left 8 LEDS all on
offset 6, 0×00 – right hand side 5 leds on , second row
offset 7, 0×00 – middle 8 LEDS all on, second row
offset 8, 0×00 – left 8 LEDS all on, second row
0xfe in an 8 LED cell, would mean the leftmost LED was ON and the others off
0xaa would be ON,OFF,ON,OFF,ON,OFF since the leds are reversed, since 1 is LED off.
a quick #define in c for the 5 LED’s
#define LED_5(a,b,c,d,e) ( (!e<<4) + (!d<<3) + (!c<<2) + (!b<<1) + (!a) )
The 8’s
#define LED_8(a,b,c,d,e,f,g,h) ( (!h<<7) + (!g<<6) + (!f<<5) + (!e<<4) + (!d<<3) + (!c<<2) + (!b<<1) + (!a) )
You can use the 8 macro for the 5 LEDs, since it ignores the top ones, so LED_8(1,1,1,1,1,0,0,0) is equivalent to LED_5(1,1,1,1,1)
One whole row, left to right would be
OutputReport[5] = LED_8(1,1,1,1 ,1,1,1,1) ;
OutputReport[4] = LED_8(1,1,1,1, 1,1,1,1) ;
OutputReport[3] = LED_8(1,1,1,1 ,1,0,0,0) ;
And some equally hacky code just to see if the above all works in principle.
#define LED_8(a,b,c,d,e,f,g,h) ( (!h<<7) + (!g<<6) + (!f<<5) + (!e<<4) + (!d<<3) + (!c<<2) + (!b<<1) + (!a) )
#define FB(x) (framebuffer[x + (y*21)]?1:0)
#define _ 0
#define W 1unsigned char framebuffer[21 * 7] = {
W, _, W, _, W, W, _, W, _, _, W, _, _, W, W, W, _, W, _, W, _,
W, _, W, _, W, _, _, W, _, _, W, _, _, W, _, W, _, W, _, W, _,
W, _, W, _, W, _, _, W, _, _, W, _, _, W, _, W, _, W, _, W, _,
W, W, W, _, W, W, _, W, _, _, W, _, _, W, _, W, _, W, _, W, _,
W, _, W, _, W, _, _, W, _, _, W, _, _, W, _, W, _, W, _, W, _,
W, _, W, _, W, _, _, W, _, _, W, _, _, W, _, W, _, _, _, _, _,
W, _, W, _, W, W, _, W, W, _, W, W, _, W, W, W, _, W, _, W, _
};
#undef _
#undef Wvoid CCreamDeekyDlg::OnTimer(UINT_PTR nIDEvent)
{
int y;CDialog::OnTimer(nIDEvent);
if( MyDeviceDetected ) {
for( y = 0 ; y < 7 ; y++ ) {
// always
OutputReport[0 ] = 0×0;// brightness 0 .. 15
OutputReport[1 ] = 1;OutputReport[2 ] = y;
OutputReport[5] = LED_8(FB( 0),FB( 1),FB( 2),FB( 3),FB( 4),FB( 5),FB( 6),FB( 7));
OutputReport[4] = LED_8(FB( 8),FB( 9),FB(10),FB(11),FB(12),FB(13),FB(14),FB(15));
OutputReport[3] = LED_8(FB(16),FB(17),FB(18),FB(19),FB(20),0,0,0);y++;
OutputReport[8] = LED_8(FB( 0),FB( 1),FB( 2),FB( 3),FB( 4),FB( 5),FB( 6),FB( 7));
OutputReport[7] = LED_8(FB( 8),FB( 9),FB(10),FB(11),FB(12),FB(13),FB(14),FB(15));
OutputReport[6] = LED_8(FB(16),FB(17),FB(18),FB(19),FB(20),0,0,0);if (WriteHandle != INVALID_HANDLE_VALUE)
{
HRESULT Result = HidD_SetOutputReport
(WriteHandle,
OutputReport,
9);
}
}
}
}
and it does , that’s brightness level 1, but its an iPhone..
Next i think i’ll see if i can implement per LED brightness, I’m hoping POV will let me write multiple times on the same row.
Chrysilis 6:28 am on December 3, 2009 Permalink |
I just pulled mine out for some christmas messaging and eagerly await further developments!
Manzed 5:20 pm on August 1, 2010 Permalink |
Wow nice, I have no clue about the HID stuff but I guess it shouldn’t be a brainer to come up with a VB script that writes any message to it? You know, I’d like to let people leave comments on a website and have it sent to a little HTTP-server on my comp, then pass the message on to VB and have it displayed on the LED. Oh and received email headers could be displayed too. All I’d need is the VB code, any clue how to make that possible?
Manzed 6:01 pm on August 1, 2010 Permalink |
oh i just found something here – http://board.homeseer.com/showthread.php?t=129324
“There is a 3rd Party interface for the Dream Cheeky LED sign available. This allows Cmd line control and even has client/server facilities, font and graphic editing.”
Exactly what i want.
http://sourceforge.net/project/platformdownload.php?group_id=257864
Duncan 11:31 pm on September 17, 2010 Permalink |
Any further developments on this? I am looking for a way to visibly report on the latest build coming out of CruiseControl.NET, and figured this board would be awesome for “BUILD FAILING” messages… and maybe the name of the programmer who broke the build. Anyway, I don’t want to have to load software, I’d want something that would be .bat / .com friendly. Surely it’s trivial to call a .exe from a .bat and pass in a string, which is passed to the message board, yes?
Ryan 7:19 am on May 15, 2011 Permalink |
Hi there.
Good job! I just want to know if there is visual basic source code to use with the cheeky LED display that I can download somewhere?
Many thanks
Ryan
zaphodikus 8:32 pm on December 4, 2012 Permalink |
I’m a bit worried about accuracy and the unusual use of math here, “It’s trivial to treat the output as a frame buffer, 21×7″ . Are we saying the device has 148 pixels and they are written to from left-to right, not top to bottom as one might expect?
charliex 10:09 pm on December 4, 2012 Permalink |
It’s definitely 21×7, honestly i don’t recall if its left to to right or to bottom addressing, but you’d deal with that in the per write routines anyway. I do recall it being left to right.