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, 0x00 all on. right most byte is left most on the display at 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0x00

First byte is brightness

Second byte is vertical row 0x5 is the bottom, two lines are written at once. If you give it 0x6 it’ll write the first line to the last row, then wrap after a few that disappear.

It takes 0x9 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 ] = 0x0;

    // 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,   0x00 – right hand side 5 LEDS on
offset 4,   0x00 – middle 8 LEDS all on
offset 5,   0x00 – left 8 LEDS all on

offset 6,   0x00 – right hand side 5 leds on , second row
offset 7,   0x00 – middle 8 LEDS all on, second row
offset 8,   0x00 – 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 ] = 0x0;

            // 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