About C:Amie · Technical Articles · GFX & Artwork · Analog C:Amie Edition Thursday, 23 November 2017

Adafruit USB + Serial RGB Backlight Character LCD Backpack VBScript API

System Requirements:

  • Adafruit USB Serial RGB Backlight Character LCD Backpack

The Problem:

I recently needed a fast, cheap and modular way to output small amounts of information from a headless Windows 7 appliance, something that didn't require a large amount of electrical engineering work or assembly while at the same time working over USB.

I accidentally stumbled upon a product by Adafruit, who seem to be tightly aligned with the Raspberry Pi/Arduino, however USB is USB which means that making it cooperate with Win32 wouldn't be particularly challenging.

Being the lazy person that I am, I never much care for the idea of having to repeatedly type out control commands through a command line parser to get what I want and quite frankly, getting a NT Command Prompt to reliably pass anything out to a Serial Port is more or less a futile exercise unless you are using Plink or replace the shell entirely with something more robust.

My solution was quite simple, create a O-O VBScript API for running it via CScript that can in turn be called from the NT command line where required.

More Info

This API does what I require it to do. I have implemented all of the main command syntax from the Adafruit documentation (links below). It is classful and self contained. As long as you can create a FileSystemObject and can find the COM Port, you can make use of it.

' AdafruitUsbSerial Application Programming Interface v1.0.4
' © C:Amie | www.c-amie.co.uk 1996 - 2014
' Not for commercial reproduction without the express permission of the author
' No warranty is offered or implied as a result of downloading or using this API

Class AdafruitUsbSerial

private m_ForReading

private m_SCREEN_OFF
private m_SCREEN_ON
private m_AUTO_SCROLL_ON
private m_AUTO_SCROLL_OFF
private m_CLEAR_SCREEN
private m_SET_STARTUP_SPLASH
private m_SET_CURSOR_POSITION
private m_SET_CURSOR_HOME
private m_SET_CURSOR_BACK
private m_SET_CURSOR_FORWARD
private m_SET_UNDERLINE_ON
private m_SET_UNDERLINE_OFF
private m_SET_BLINK_ON
private m_SET_BLINK_OFF
private m_SET_RGB
private m_SET_CONTRAST
private m_SET_BRIGHTNESS

private m_iPortNumber
private m_byteCharacterLength
private m_bolDebug
private m_bolAutoScroll
private m_bolUnderlineCursor
private m_bolBlinkCursor

private m_fso private

sub Class_Initialize
  m_ForReading = 1
  m_SCREEN_OFF = chr(254) & chr(70)
  m_SCREEN_ON = chr(254) & chr(66)
  m_AUTO_SCROLL_ON = chr(254) & chr(81)
  m_AUTO_SCROLL_OFF = chr(254) & chr(82)
  m_CLEAR_SCREEN = chr(254) & chr(88)
  m_SET_STARTUP_SPLASH = chr(254) & chr(64)
  m_SET_CURSOR_POSITION = chr(254) & chr(71)
  m_SET_CURSOR_HOME = chr(254) & chr(72)
  m_SET_CURSOR_BACK = chr(254) & chr(76)
  m_SET_CURSOR_FORWARD = chr(254) & chr(77)
  m_SET_UNDERLINE_ON = chr(254) & chr(74)
  m_SET_UNDERLINE_OFF = chr(254) & chr(75)
  m_SET_BLINK_ON = chr(254) & chr(83)
  m_SET_BLINK_OFF = chr(254) & chr(84)
  m_SET_RGB = chr(254) & chr(208)
  m_SET_CONTRAST = chr(254) & chr(80)
  m_SET_BRIGHTNESS = chr(254) & chr(153)

  m_iPortNumber = 1
  m_byteCharacterLength = 32
  m_bolDebug = false
  m_bolAutoScroll = true
  m_bolUnderlineCursor = false
  m_bolBlinkCursor = false

   set m_fso = CreateObject("Scripting.FileSystemObject")
end sub

private sub Class_Terminate
  set m_fso = nothing
end sub

' PROPERTIES
public property get PortNumber
  PortNumber = m_iPortNumber
end property

public property let PortNumber(ByRef iIn)
  m_iPortNumber = iIn
end property

public property get CharacterLength
  CharacterLength = m_byteCharacterLength
end property

public property let CharacterLength(ByRef byteIn)
  m_byteCharacterLength = byteIn
end property

public property get Debug()
  Debug = m_bolDebug
end property

public property let Debug(ByRef bolIn)
  m_bolDebug = bolIn
end property

public property get AutoScroll()
  AutoScroll = m_bolAutoScroll
end property

public property let AutoScroll(ByRef bolIn)
  if (bolIn) then
    me.write(m_AUTO_SCROLL_ON)
  else
    me.write(m_AUTO_SCROLL_OFF)
  end if
  m_bolAutoScroll = bolIn
end property

public property get Underline()
  Underline = m_bolUnderlineCursor
end property

public property let Underline(ByRef bolIn)
  if (bolIn) then
    me.write(m_SET_UNDERLINE_ON)
  else
    me.write(m_SET_UNDERLINE_OFF)
  end if
  m_bolUnderlineCursor = bolIn
end property

public property get Blink()
  Blink = m_bolBlinkCursor
end property

public property let Blink(ByRef bolIn)
  if (bolIn) then
    me.write(m_SET_BLINK_ON)
  else
    me.write(m_SET_BLINK_OFF)
  end if
  m_bolBlinkCursor = bolIn
end property

' METHODS
public sub clearScreen()
  me.write(m_CLEAR_SCREEN)
  end sub public sub screenOn()
  me.write(m_SCREEN_ON)
end sub

public sub screenOff()
  me.write(m_SCREEN_OFF)
end sub

public sub changeSplashScreen(ByVal strIn)
  strIn = Left(strIn, m_byteCharacters)
  ' Force it to be exactly 32 characters by padding
  do while (Len(strIn) < m_byteCharacters)
    strIn = (strIn & " ")
  loop
  me.clearScreen()
  me.home()
  me.write(m_SET_STARTUP_SPLASH)
  me.write(strIn)
end sub

public sub backlight(ByRef byteR, ByRef byteG, ByRef byteB)
  me.write(m_SET_RGB)
  me.write(chr(byteR))
  me.write(chr(byteG))
  me.write(chr(byteB))
end sub

' Valid Range 0 - 255. Values between 180 and 220 are suggested
public sub contrast(ByRef byteIn)
  me.write(m_SET_CONTRAST)
  me.write(chr(byteIn))
end sub

' Valid Range 0 - 255.
public sub brightness(ByRef byteIn)
  me.write(m_SET_BRIGHTNESS)
  me.write(chr(byteIn))
end sub

public sub setCursorPosition(ByRef iX, ByRef iY)
  me.write(m_SET_CURSOR_POSITION)
  me.write(chr(iX))
  me.write(chr(iY))
end sub

public sub home()
  me.write(m_SET_CURSOR_HOME)
end sub

public sub back()
  me.write(m_SET_CURSOR_BACK)
end sub

public sub goBack(ByRef iIn)
  Dim i
  for i = 1 to iIn
    me.write(m_SET_CURSOR_BACK)
  next
end sub

public sub forward()
  me.write(m_SET_CURSOR_FORWARD)
end sub

public sub goForward(ByRef iIn)
  Dim i
  for i = 1 to iIn
    me.write(m_SET_CURSOR_FORWARD)
  next
end sub

public sub delete()
  me.write(m_SET_CURSOR_BACK)
  me.write(" ")
  me.write(m_SET_CURSOR_BACK)
end sub

public sub write(ByRef strIn)
  Dim serialWriter
  if (me.Debug) then
    wscript.echo strIn
  end if
  set serialWriter = m_fso.CreateTextFile("COM" & m_iPortNumber & ":",True)
  serialWriter.Write(strIn)
  serialWriter.Close()
  set serialWriter = nothing
end sub

public sub teletype(ByRef strIn, ByRef iDelayMs)
  Dim i
  Dim iLen
  iLen = Len(strIn)
  for i = 1 to iLen
    me.write(Mid(strIn, i, 1))
    WScript.Sleep(iDelayMs)
  next
end sub

public function testComPort(ByRef byteNumber)
  Dim serialWriter
  if (me.Debug) then
    wscript.echo "Attempting communications with COM" & byteNumber
  end if
  On Error Resume Next
    set serialWriter = m_fso.CreateTextFile("COM" & byteNumber & ":",True)
    serialWriter.Write("Initialising...")
    serialWriter.Close()
    set serialWriter = nothing
    if (err.number = 0) then
      testComPort = true
    else
      testComPort = false
    end if
  On Error Goto 0
end function

End Class

Copy it into your VBScript project file or into a dedicated class file and include it. Once it is in scope, the example below shows a general usage pattern for the main API.

It is recommended that all projects include and set the first 8 lines shown below, just so that you can ensure that you are tuning your project in the way that you want it. The remainder of the code shows examples of how to use the functions.

As a result of the USB driver allocating COM ports in a fairly dynamic way under Win32, you cannot expect to hard code your COM Port inside the project - particularly if the physical USB port that the backpack is connected to changes. Consequently, you can use testComPort() to attempt to locate the correct port as shown below. The function will terminate on the first port that it finds with an active serial output line available, if you have multiple active serial ports available on your project, the function may find the wrong port.

Finally, Adafruit recommends - at a minimum -adding a 10 millisecond delay between each command, which is not shown below. You should use WScript.Sleep(10) to achieve similar under VBScript. If you don't, everything shown below with the exception of the executing of the Teletype macro will occur in well under a second.

Dim usbSerial
set usbSerial = new AdafruitUsbSerial
    usbSerial.PortNumber = 3              ' Set to COM3
    usbSerial.Debug = true                ' Inputs will be written back to WScript
    usbSerial.CharacterLength = 32        ' 32 is the default
    usbSerial.AutoScroll = true           ' Enable/Disable Auto Scroll
    usbSerial.Underline = true            ' Enable Cursor Underline
    usbSerial.Blink = true                ' Enable Cursor Blink

' Find the first live COM Port if you don't know where it is
Dim iComPort
for iComPort = 1 to 30
  if (usbSerial.testComPort(iComPort)) then
    usbSerial.PortNumber = iComPort
    Exit For
  end if
next

' Write Text
usbSerial.write("some text")

' Write on both lines
usbSerial.write("line one" & vblf & "line two")

' Clear the screen
usbSerial.clearScreen()

' Screen Off
usbSerial.screenOff()

' Screen On
usbSerial.screenOn()

' Change the Backlight Colour
call usbSerial.backlight(255, 0, 255) ' Sets the RGB values (Fuchsia in this case)

' Set the screen brightness
usbSerial.brightness(180) ' 0 - 255

' Set the screen contrast
usbSerial.contrast(180) ' 0 - 255

' Set the Cursor Position
usbSerial.home()                  ' Moves to character 1, row 1
usbSerial.back()                  ' Moves the cursor back 1 character
usbSerial.forward()               ' Moves the cursor forward 1 character
usbSerial.goBack(5)               ' Steps the cursor back 5 characters
usbSerial.goForward(6)            ' Progresses the cursor forward 6 characters
usbSerial.setCursorPosition(5,1)  ' Sets the cursor to Character 5 on Row 1
usbSerial.delete()                ' Moves the cursor back 1 and clears the previous character

' Teletype (Macro)
call usbSerial.teletype("this will teletype out", 100) ' Write the text, with a 0.1 second character delay

' Change the Adafruit Splash Screen (Auto truncated/padded to usbSerial.CharacterLength)
usbSerial.changeSplashScreen("This is a splash screen message")

' Clean up and free resources
set usbSerial = nothing

Thanks to a structured API it is as easy as that!

View: Adafruit: Command Reference
View: Adafruit: Sending Text

See Also

View: Adafruit

 

Article Published: Wednesday, 31 December, 2014
Article Revision Date: Tuesday, 27 January, 2015

This site is not associated with the Microsoft Corporation. The information on this page is provided as is and is free for those who visit to use. Microsoft Operating Systems, Internet Browsers and applications are the property of the Microsoft Corporation. Windows software patches and updates are the property of the Microsoft Corporation and are provided through the hard work and dedication of the Microsoft Security, Operating System, and Application development teams.

© C:Amie
1996 - 2017. All Rights Reserved (4,384)
All trademarks mentioned are the property of their respective owners.