Hacking the Dream Cheeky USB LED Message Board

 Dream Cheeky

 

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

 

shw

shw1

 

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 1

unsigned 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 W

void 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..

IMG_1134

 

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.

About these ads