AvBrand Exploring Technology
- Introduction
- Part 1 - Installation of the Car PC
- Part 2 - Adding a Rear-View Camera
- Part 3 - Time for some Software!
- Part 4 - An LED message sign
- Part 5 - Voice Commands
- Part 6 - Phone Integration
- Part 7 - XM Radio Integration
- Part 8 - Permanent Internet
- Part 9 - Front Camera
- Part 10 - Digital Dash
- Part 11 - Shuttle Jog Wheel
- Frequently Asked Questions
Old LED Sign Technical Details
The specific sign I was using is the NS-500UA from AffordableLED. You can buy it here for $229. Affordable LED NS-500UAThe features it has that make it the right sign for the job:
- It uses high-brightness LEDs. Indoor signs, especially common 3-color ones, cannot be read in sunlight during the day.
- The amber color is the only one legally allowed to be used in Ontario and many other places. A sign with red LED's could be considered as having an "intermittent" light, which is only allowed for turn signals and emergency vehicles. Other colours, such as blue, green, and white, are not allowed for rear-facing at all.
- It has a serial port and includes the cable, and the protocol was easy to reverse-engineer.
- It is relatively inexpensive compared to many signs
- It is powered by 5V, therefore easily married into a car (I'd still recommend using a proper 12v power supply).
- It is a reasonable size, small enough to fit in the back window, but large enough to be seen from quite a distance.
The Serial Protocol
I used the included software and a serial port sniffing application to reverse-engineer the protocol that the NS-500UA uses. I've included it on this page. If you find this useful, please be sure to give me credit. The code below is in Visual Basic 6 language.
Private Sub setSignText(inTxt As String) Dim i As Long On Error Resume Next ' Set the com port to the sign's port. Form1.COM3.CommPort = Val(readConfigValue("ledsign", "comport")) ' Attempt to open the com port If Not Form1.COM3.PortOpen Then Form1.COM3.PortOpen = True If Err.Number <> 0 Then addToLog "[LEDSIGN]", "COM Port error:", Err.Description Exit Sub ' Error opening port End If With Form1.COM3 ' Select the com port. ' Send the initialization bytes .Output = Chr(&H0) .Output = Chr(&HFF) .Output = Chr(&HFF) .Output = Chr(&H0) .Output = Chr(&HB) ' Next, the sign seems to expect bytes 0 to 127 to be sent. For i = 0 To 127 .Output = Chr(i) Next ' Some more init bytes. .Output = Chr(&H0) .Output = Chr(&HFF) ' Start of message? ' This byte seems to indicate what to do: ' 1 : Program sign file <- that's the one we care about ' 2 : Schedule ' 5 : Hourly alarm ' 8 : Set time and date .Output = Chr(&H1) ' Which file to use. ' We just want to overwrite what's on the sign, so we're going to send file 01. .Output = "01" ' Set to default color and font .Output = Chr(&HEF) & Chr(&HB0) & Chr(&HEF) & Chr(&HA2) ' Send the actual text to display, replacing any control codes with their binary equivalents .Output = fixText(inTxt) ' End of message .Output = Chr(&HFF) & Chr(&HFF) & Chr(&H0) End With End Sub
Private Function fixText(s As String) As String ' Replace control codes in the string to the bytes the sign is expecting. Dim sC As String Dim eC As String ' Default color and font sC = Chr(&HFF) ' Control byte eC = Chr(&HEF) & Chr(&HB0) & Chr(&HEF) & Chr(&HA2) s = Replace(s, "\n", Chr(&HFF)) ' Line break s = Replace(s, "<CYCLIC>", sC & Chr(&H1) & eC) s = Replace(s, "<IMMEDIATE>", sC & Chr(&H2) & eC) s = Replace(s, "<OPENFROMRIGHT>", sC & Chr(&H3) & eC) s = Replace(s, "<OPENFROMLEFT>", sC & Chr(&H4) & eC) s = Replace(s, "<OPENFROMCENTER>", sC & Chr(&H5) & eC) s = Replace(s, "<OPENTOCENTER>", sC & Chr(&H6) & eC) s = Replace(s, "<COVERFROMCENTER>", sC & Chr(&H7) & eC) s = Replace(s, "<COVERFROMRIGHT>", sC & Chr(&H8) & eC) s = Replace(s, "<COVERFROMLEFT>", sC & Chr(&H9) & eC) s = Replace(s, "<COVERTOCENTER>", sC & Chr(&HA) & eC) s = Replace(s, "<SCROLLUP>", sC & Chr(&HB) & eC) s = Replace(s, "<SCROLLDOWN>", sC & Chr(&HC) & eC) s = Replace(s, "<INTERLACE1>", sC & Chr(&HD) & eC) s = Replace(s, "<INTERLACE2>", sC & Chr(&HE) & eC) s = Replace(s, "<COVERUP>", sC & Chr(&HF) & eC) s = Replace(s, "<COVERDOWN>", sC & Chr(&H10) & eC) s = Replace(s, "<SCANLINE>", sC & Chr(&H11) & eC) s = Replace(s, "<EXPLODE>", sC & Chr(&H12) & eC) s = Replace(s, "<PACMAN>", sC & Chr(&H13) & eC) s = Replace(s, "<STACK>", sC & Chr(&H14) & eC) s = Replace(s, "<SHOOT>", sC & Chr(&H15) & eC) s = Replace(s, "<FLASH>", sC & Chr(&H16) & eC) s = Replace(s, "<RANDOM>", sC & Chr(&H17) & eC) s = Replace(s, "<SLIDEIN>", sC & Chr(&H18) & eC) s = Replace(s, "<AUTO>", sC & Chr(&H19) & eC) ' Effects 1D-1F : nothing ' Unknown 00-0F ' Unknown 10-1F ' Unknown 20-2F ' Unknown 30-3F ' Unknown 40-4F ' Unknown 50-5F ' Symbols 60-7D s = Replace(s, "<SUN>", Chr(&HEF) & Chr(&H60)) s = Replace(s, "<CLOUDY>", Chr(&HEF) & Chr(&H61)) s = Replace(s, "<RAIN>", Chr(&HEF) & Chr(&H62)) s = Replace(s, "<CLOCK>", Chr(&HEF) & Chr(&H63)) s = Replace(s, "<PHONE>", Chr(&HEF) & Chr(&H64)) s = Replace(s, "<SPECS>", Chr(&HEF) & Chr(&H65)) s = Replace(s, "<FAUCET>", Chr(&HEF) & Chr(&H66)) s = Replace(s, "<ROCKET>", Chr(&HEF) & Chr(&H67)) s = Replace(s, "<BUG>", Chr(&HEF) & Chr(&H68)) s = Replace(s, "<KEY>", Chr(&HEF) & Chr(&H69)) s = Replace(s, "<SHIRT>", Chr(&HEF) & Chr(&H6A)) s = Replace(s, "<CHOPPER>", Chr(&HEF) & Chr(&H6B)) s = Replace(s, "<CAR>", Chr(&HEF) & Chr(&H6C)) s = Replace(s, "<DUCK>", Chr(&HEF) & Chr(&H6D)) s = Replace(s, "<HOUSE>", Chr(&HEF) & Chr(&H6E)) s = Replace(s, "<TEAPOT>", Chr(&HEF) & Chr(&H6F)) s = Replace(s, "<TREES>", Chr(&HEF) & Chr(&H70)) s = Replace(s, "<SWAN>", Chr(&HEF) & Chr(&H71)) s = Replace(s, "<MBIKE>", Chr(&HEF) & Chr(&H72)) s = Replace(s, "<BIKE>", Chr(&HEF) & Chr(&H73)) s = Replace(s, "<CROWN>", Chr(&HEF) & Chr(&H74)) s = Replace(s, "<STRAWBERRY>", Chr(&HEF) & Chr(&H75)) s = Replace(s, "<ARROWRIGHT>", Chr(&HEF) & Chr(&H76)) s = Replace(s, "<ARROWLEFT>", Chr(&HEF) & Chr(&H77)) s = Replace(s, "<ARROWDOWNLEFT>", Chr(&HEF) & Chr(&H78)) s = Replace(s, "<ARROWUPLEFT>", Chr(&HEF) & Chr(&H79)) s = Replace(s, "<CUP>", Chr(&HEF) & Chr(&H7A)) s = Replace(s, "<CHAIR>", Chr(&HEF) & Chr(&H7B)) s = Replace(s, "<SHOE>", Chr(&HEF) & Chr(&H7C)) s = Replace(s, "<GLASS>", Chr(&HEF) & Chr(&H7D)) ' 7E : Blank ' 7F : Blank ' Time & Date 80 - 83 s = Replace(s, "<TIME>", Chr(&HEF) & Chr(&H80)) s = Replace(s, "<DATE>", Chr(&HEF) & Chr(&H81)) s = Replace(s, "<TEMP>", Chr(&HEF) & Chr(&H82)) ' Doesn't work on the NS-500UA ' 90-97: Cartoons s = Replace(s, "<MERRYXMAS>", Chr(&HEF) & Chr(&H90)) s = Replace(s, "<HAPPYNEWYEAR>", Chr(&HEF) & Chr(&H91)) s = Replace(s, "<4THJULY>", Chr(&HEF) & Chr(&H92)) s = Replace(s, "<HAPPYEASTER>", Chr(&HEF) & Chr(&H93)) s = Replace(s, "<HALLOWEEN>", Chr(&HEF) & Chr(&H94)) s = Replace(s, "<DONTDRINKDRIVE>", Chr(&HEF) & Chr(&H95)) s = Replace(s, "<NOSMOKING>", Chr(&HEF) & Chr(&H96)) s = Replace(s, "<WELCOME>", Chr(&HEF) & Chr(&H97)) ' 98-9F: same graphics again ' A0-A6: Fonts s = Replace(s, "<FONT1>", Chr(&HEF) & Chr(&HA0)) ' Small s = Replace(s, "<FONT2>", Chr(&HEF) & Chr(&HA1)) ' Boxy s = Replace(s, "<FONT3>", Chr(&HEF) & Chr(&HA2)) ' Normal s = Replace(s, "<FONT4>", Chr(&HEF) & Chr(&HA3)) ' Pretty Fat s = Replace(s, "<FONT5>", Chr(&HEF) & Chr(&HA4)) ' Fat s = Replace(s, "<FONT6>", Chr(&HEF) & Chr(&HA5)) ' Super fat s = Replace(s, "<FONT7>", Chr(&HEF) & Chr(&HA6)) ' Small fonts ' A7-AF: Missing fonts, mem glitches ' B0-BF: Colors ' The NS-500UA supports only one color s = Replace(s, "<COLOR1>", Chr(&HEF) & Chr(&HB0)) s = Replace(s, "<COLOR2>", Chr(&HEF) & Chr(&HB1)) ' C0-C7: Speeds s = Replace(s, "<SPEED0>", Chr(&HEF) & Chr(&HC0)) ' Fastest s = Replace(s, "<SPEED1>", Chr(&HEF) & Chr(&HC1)) s = Replace(s, "<SPEED2>", Chr(&HEF) & Chr(&HC2)) s = Replace(s, "<SPEED3>", Chr(&HEF) & Chr(&HC3)) s = Replace(s, "<SPEED4>", Chr(&HEF) & Chr(&HC4)) s = Replace(s, "<SPEED5>", Chr(&HEF) & Chr(&HC5)) s = Replace(s, "<SPEED6>", Chr(&HEF) & Chr(&HC6)) s = Replace(s, "<SPEED7>", Chr(&HEF) & Chr(&HC7)) ' Slowest ' C8-CF: Pauses s = Replace(s, "<PAUSE1>", Chr(&HEF) & Chr(&HC8)) s = Replace(s, "<PAUSE2>", Chr(&HEF) & Chr(&HC9)) s = Replace(s, "<PAUSE3>", Chr(&HEF) & Chr(&HCA)) s = Replace(s, "<PAUSE4>", Chr(&HEF) & Chr(&HCB)) s = Replace(s, "<PAUSE5>", Chr(&HEF) & Chr(&HCC)) s = Replace(s, "<PAUSE6>", Chr(&HEF) & Chr(&HCD)) s = Replace(s, "<PAUSE7>", Chr(&HEF) & Chr(&HCE)) s = Replace(s, "<PAUSE8>", Chr(&HEF) & Chr(&HCF)) ' D0-D7: More graphics ' D8-DF: These graphics s = Replace(s, "<CITYSCAPE>", Chr(&HEF) & Chr(&HD8)) s = Replace(s, "<TRAFFIC>", Chr(&HEF) & Chr(&HD9)) s = Replace(s, "<TEAPARTY>", Chr(&HEF) & Chr(&HDA)) s = Replace(s, "<TELEPHONE>", Chr(&HEF) & Chr(&HDB)) s = Replace(s, "<SUNSET>", Chr(&HEF) & Chr(&HDC)) s = Replace(s, "<CARGOSHIP>", Chr(&HEF) & Chr(&HDD)) s = Replace(s, "<SWIMMERS>", Chr(&HEF) & Chr(&HDE)) s = Replace(s, "<MOUSE>", Chr(&HEF) & Chr(&HDF)) ' Beep E0 - E2 s = Replace(s, "<BEEP1>", Chr(&HEF) & Chr(&HE0)) ' 3 beeps s = Replace(s, "<BEEP2>", Chr(&HEF) & Chr(&HE1)) ' 3 short beeps s = Replace(s, "<BEEP3>", Chr(&HEF) & Chr(&HE2)) ' Short beep s = Replace(s, "<BEEP4>", Chr(&HEF) & Chr(&HE3)) ' More beeps s = Replace(s, "<BEEP5>", Chr(&HEF) & Chr(&HE4)) ' Short beep s = Replace(s, "<BEEP6>", Chr(&HEF) & Chr(&HE5)) ' Long beep s = Replace(s, "<BEEP7>", Chr(&HEF) & Chr(&HE6)) ' More beeps s = Replace(s, "<BEEP8>", Chr(&HEF) & Chr(&HE7)) ' Continuous beeping long s = Replace(s, "<BEEP9>", Chr(&HEF) & Chr(&HE8)) ' Continuous beeping short s = Replace(s, "<BEEP10>", Chr(&HEF) & Chr(&HE9)) ' Beeps s = Replace(s, "<BEEP11>", Chr(&HEF) & Chr(&HEA)) ' Really long beep fixText = s End Function
Here are some examples of the messages you see on my sign:
setSignText "<OPENFROMRIGHT>< < < < < <" setSignText "<OPENFROMLEFT>> > > > > >" setSignText "<OPENFROMCENTER>< < < > > >" setSignText "<FLASH>Backing Up<IMMEDIATE>Backing Up<PAUSE8>" setSignText "<OPENFROMCENTER>Thank you!<PAUSE4><OPENFROMCENTER> <PAUSE8>" setSignText "<FLASH>Sorry!<IMMEDIATE>Sorry!<PAUSE8>" setSignText "<IMMEDIATE>Go Around Me<PAUSE8>" setSignText "Please turn off your highbeams! " setSignText "<IMMEDIATE>Nice Car!<PAUSE8>" setSignText "<SCROLLUP>Traffic Ahead<SCROLLUP> Use Alternate Route " setSignText "I'm listening to: " & realCurrSong & " <PAUSE8>" setSignText "<FLASH>ALERT!<SLIDEIN>Your LEFT HEADLIGHT is Broken! <PAUSE8>" setSignText "<FLASH>ALERT!<SLIDEIN>Your RIGHT HEADLIGHT is Broken! <PAUSE8>" setSignText "<FLASH>SLOW DOWN<SLIDEIN>This isn't a race! <PAUSE8>" setSignText "<FLASH>Follow Me!<IMMEDIATE>Follow Me!<PAUSE8>"