How to control a device from Small Basic

Imagine we would like to turn on and off a light from a Small Basic program: A classic embedded systems task.

There are several ways to implement such a system. In the old days, one would build a microcomputer with an RS-232 serial port into the light controller. We would then connect a cable from the serial port on the device to the serial port on the Windows computer, possibly with a 25-9 pin adapter, crossover cable, null modem adapter, etc. Then we would try to figure out the baud rate, parity settings, and which serial port was which on our computer. If we were determined we would eventually get it working. After installing the LitDev extension for serial port support, we can now control the light from Small Basic by sending commands out the serial port to the light controller.

The cable challenges and bit rate limitations of serial ports led to the introduction of USB (Universal Serial Bus), which standardized the cabling and increased the baud rate by orders of magnitude. But USB brings its own peculiar challenges, including the fact that devices can wind up at different addresses depending on which port they are plugged into. Still, one can now build a microcomputer with a USB port into the light controller and eventually get it working from Small Basic using the LitDev extension.

A third option is to build a microcomputer with either wired or wireless Ethernet into the light controller. If the microcomputer runs a mini-web server with something like CGI (Common Gateway Interface), one can easily issue commands to it from a web browser, or from Small Basic using the Network object.


The Raspberry Pi

There are hundreds of microcomputer boards available that can be used for such a device server. We can narrow the field by concentrating only on those that are well supported and cost less than $30. Certainly among the most popular in this range is the Raspberry Pi (http://www.raspberrypi.org), with more than five million sold. The Raspberry Pi has been available in five production models (A, B, A+, B+, 2B). The B and B+ models have two or four USB ports and built-in wired Ethernet. The A and A+ models have only one USB port and no built-in networking, but cost less and consume considerably less power. The original A and B models have a 26-pin expansion header. The A+ and B+ models have a 40-pin expansion header (26 pins of which are the same as the A and B). The very latest Raspberry Pi 2 Model B is mechanically interchangeable with the B+ but offers a faster quad-core processor and twice the RAM.

 Figure 1 - Raspberry Pi Model A+

The Raspberry Pi Model A+ is the least expensive and most power efficient member of the family, with a suggested retail price of USD $20. The actual street price runs $25 at time of writing. We will need to add a wireless Ethernet adapter (the Edimax EW-7811U is strongly recommended), a micro-SD card for booting the operating system, and a micro-USB power source, probably bringing the total system price over USD $30.

Interface connectors on the A+ are a micro USB slave port (+5V power supply only), a couple of flat cable connectors for LCD display and camera modules, an HDMI video output jack, a 3.5 mm Audio/Video jack, one USB host port, and the 40 pin expansion header J8. For this article, a 2 gigabyte micro-SD card and an Edimax EW-7811U wireless Ethernet adapter are permanently installed. Figure 1 above shows the Raspberry Pi A+ used for this article. Along the left edge of the board, the micro-SD card is barely visible. The wireless network adapter is plugged into the USB host port on the right edge of the board. The 40-pin expansion header J8 is visible along the top edge of the board.


Raspbian Linux Operating System

The usual operating system for the Raspberry Pi is Raspbian Linux, which is essentially Debian Linux recompiled for the processor in the Raspberry Pi. It must be installed onto the micro-SD card, which is then inserted into the Raspberry Pi. The micro-SD card must be reformatted with two partitions: A small DOS FAT file system partition which contains the boot files, and a larger Linux OS file system partition which contains the rest of the operating system.

Raspbian Linux is both a strength and weakness of the Raspberry Pi. With its Unix heritage, it is unbelievably powerful for such a small computer.  The downside is that  for a headless (no keyboard or display) embedded system, Raspbian Linux leaves a lot to be desired. Installing, configuring, and administering it is not trivial. The operating system partition can be corrupted if the system is not shut down in an orderly fashion. Furthermore, the flash memory cells on the micro-SD card will eventually wear out. SD cards are cheap and easy to use, designed for casual recording of photographs and the like rather than for operating system partitions.


MuntsOS

MuntsOS is an extremely reduced distribution of the Linux operating system. It is delivered as a single Linux kernel image file with the main or root file system built into it. When the kernel boots on a target computer, it unpacks a fresh copy of the root file system into RAM and uses it there. The Raspberry Pi boots from a micro-SD card, but after it has finished booting it no longer accesses the micro-SD card. This has several advantages. First, the RAM file system is very fast, much faster the micro-SD card. Second, it cannot be corrupted by pulling power without performing an orderly shutdown. Every time the Raspberry Pi boots, it unpacks a new and fresh copy of the root file system from the kernel image. Third, it does not routinely write to the micro-SD card, which helps avoid wearing out the flash memory cells in the card.


The Thin Server

A system design pattern called the Thin Server is essentially an inversion of the Thin Client concept that Sun Microsystems and other companies began marketing at the close of the 20th century. The idea behind the JavaStation and other thin client devices was to relocate as much of the software complexity and processing power as possible from the client computer to the server. The client computer was to be little more than a network interface for the user's mouse, keyboard, display monitor, and audio. All of the user's application software would run on the server, where it could be centrally managed.

In contrast, a Thin Server is little more than a network interface for a single I/O device. Ideally, a Thin Server will be built from a cheap and ubiquitous network microcomputer like the Raspberry Pi. The software must be easy to install from a user's PC or Mac without requiring any special programming tools. It must be able to run headless, administered via the network. It must be able to survive without orderly shutdowns, and must not write much to flash media. It must provide a network based API (Application Programming Interface) using HTTP as a lowest common denominator.

MuntsOS, with its operating system running entirely from RAM, serves well for the Thin Server, and in fact the two concepts have evolved together over the past few years.


GPIO

General Purpose Input/Output pins are connections available on microcomputers like the Raspberry Pi. GPIO pins carry digital signals (on/off or high/low or binary 1/0) between the microcomputer and the external device. A GPIO pin can be configured as an Input, meaning the signal flows from the external device to the microcomputer, or as an Output, meaning the signal flows from the microcomputer to the external device.

The Linux operating system numbers GPIO pins from 0 (GPIO0, GPIO1, .). Note that the Linux GPIO pin number usually does not correspond to any physical pin number. Some processors may have hundreds of GPIO pins available. Linux treats each pin as a separate I/O device. The Raspberry Pi Model A+ brings out a number of GPIO pins, along with power and ground to the J8 expansion header. See Figure 2.

Figure 2 - J8 Expansion Header

The Raspberry Pi GPIO pins are 3.3V signals, meaning outputs switch between ground and +3.3V, and inputs must not be connected to voltages below ground or above +3.3V. They cannot deliver very much power, and will almost always need some sort of driver or amplifier for real device loads such as motors and lights. It is barely possible to drive a single LED (Light Emitting Diode) from a GPIO pin, but this cannot be recommended. Use some sort of driver or amplifier such as the ULN2003A.

Note that some of the Raspberry Pi expansion header pins have alternate functions. For example, GPIO14 and GPIO15 can also be used for a serial port. Such pins may not be available for GPIO.

For experimentation, it is convenient to connect the Raspberry Pi to a solderless breadboard with an adapter like the Adafruit T-Cobbler Plus to the J8 expansion header. Figure 3 shows the Raspberry Pi Model A+ connected to a solderless breadboard.

Figure 3 - Breadboard Connection


A Thin Server for GPIO

Setting up a Raspberry Pi GPIO Thin Server is very simple. Just download the zip file at:

http://repo.munts.com/muntsos/thinservers/muntsos-gpio-server-RaspberryPi1.zip (for Raspberry Pi Model 1 A, A+, B, B+ or Zero Wireless)

http://repo.munts.com/muntsos/thinservers/muntsos-gpio-server-RaspberryPi2.zip (for Raspberry Pi Model 2 B or Model 3 B)

and extract it to a freshly FAT32 formatted micro-SD card. It includes support for the Edimax EW-7811U wireless network adapter (and others using similar Realtek chip sets). The zip file contains the MuntsOS kernel image file plus a number of other binary and text files the Raspberry Pi requires for booting. Then edit the text file:

autoexec.d/00-wlan-RaspberryPi

on the micro-SD card to configure the thin server's host name, network SSID and encryption key. Eject the micro-SD card from our PC or Mac, and insert it into the socket on the bottom of the Raspberry Pi board. When we power on the Raspberry Pi, it will boot MuntsOS from the micro-SD card and attach to the wireless network.

Discovering the IP address the Raspberry Pi has acquired may prove tricky. The easiest way to find its address is with the Apple Bonjour MDNS (Multicast Dynamic Name Service) service, which for Windows is part of the iTunes package but can be installed separately. The Raspberry Pi GPIO Thin Server will register itself as hostname.local, where hostname is whatever name we wrote in 00-wlan-RaspberryPi (or RaspberryPi-MuntsOS.local by default). If the DHCP server assigns the Raspberry Pi a host name, the name newhostname.local will also be registered, where newhostname is the first part of the newly assigned host name.

For example, if we write foo as the host name in 00-wlan-RaspberryPi, and the local DHCP server subsequently assigns the host name bar.munts.net, the Raspberry Pi will respond to both foo.local and bar.local.

Without MDNS finding the IP address will be more difficult. If we have administrative access to the DHCP server for the wireless network, we may be able to retrieve the IP address assignment from it. If worst comes to worst, we can attach a keyboard and display (HDMI) to the Raspberry Pi and log in (user root, password default) and run the ifconfig command to find out what its IP address is.


GPIO Server API

The web server running on the GPIO Thin Server responds to requests of the following forms:

http://servername:8083/GPIO/ddr/n,s Set data direction (0=input, 1=output)

http://servername:8083/GPIO/get/n Get pin (state 0=OFF, 1=ON)

http://servername:8083/GPIO/put/n,s Put pin (state 0=OFF, 1=ON)

where servername is the IP address or host name, n is the GPIO pin number (as numbered by the Linux operating system), and s is the new state 0 or 1. As an example, the following sequence of requests sent from a browser to a Raspberry Pi GPIO Thin Server will configure GPIO26 (which happens to be pin 37 of the J8 expansion header) as an output and turn it on:

http://foo.local:8083/GPIO/ddr/26,1

http://foo.local:8083/GPIO/put/26,1


Putting It All Together

Figure 4 - LED Connections

Figure 4 shows a Fritzing diagram for connecting a single LED to the Raspberry Pi A+ J8 expansion header. The GPIO26 signal drives a ULN2003A low side switch, which serves to amplify the current enough to turn on an LED. The ULN2003A has been around a long time (the particular unit used for this article was manufactured in 1978!) but is still very useful. It is a low side switch device, meaning it pulls current to ground. A load, such as the LED, must be connected between a positive supply voltage (+3.3V from the Raspberry Pi in this case) and one of the ULN2003A outputs. The flat side of the LED and/or shorter lead connects to ULN2003A pin 10 and the round side and/or longer lead connects to the 220 ohm resistor.

A sample program for turning the LED on and off from Small Basic is available, with publication ID PCD388-0. The sample program is divided into three main sections.


Figure 5 - LED Control Program

The first section lays out the GUI (Graphical User Interface), placing a server prompt, a text box for the server name, and a button initially labeled "Connect":

' Lay out GUI
GraphicsWindow.Width = 300
GraphicsWindow.Height = 130
GraphicsWindow.Title = "LED Control Program"
GraphicsWindow.Show()
GraphicsWindow.DrawText(40, 30, "Server:")
ServerBox = Controls.AddTextBox(100, 28)
ConnectButton = Controls.AddButton("Connect", 120, 80)
Controls.ButtonClicked = ButtonHandler
The second section is the button handler subroutine, which contains the bulk of the program logic:
' Everything interesting happens in the button handler subroutine
Controls.ButtonClicked = ButtonHandler
Sub ButtonHandler
  b = Controls.LastClickedButton
  c = Controls.GetButtonCaption(b)
  If c = "Connect" Then
    servername = Controls.GetTextBoxText(ServerBox)
    pin = 26
    direction = 1
    PutDDR()
    data = 0
    PutGPIO()
    Controls.SetButtonCaption(b, " ON ")
  EndIf
  If c = " ON " Then
    pin = 26
    data = 1
    PutGPIO()
    Controls.SetButtonCaption(b, " OFF ")
  EndIf
  If c = " OFF " Then
    pin = 26
    data = 0
    PutGPIO()
    Controls.SetButtonCaption(b, " ON ")
  EndIf
EndSub
The last section of the program contains subroutines that wrap the HTTP server API:
' Write GPIO data direction bit
  
' Parameter variables:
' servername -- IP address or host name
' pin -- GPIO pin number (2-26, as numbered by Linux)
' direction -- 0 for input, 1 for output
Sub PutDDR
  webpage = Network.GetWebPageContents("http://" + servername + ":8083/GPIO/ddr/" + pin + "," + direction)
  
  If Text.StartsWith(webpage, "DDR" + pin + "=") Then
  Else
    GraphicsWindow.ShowMessage(webpage, "GPIO Server Error")
  EndIf
EndSub
' Read GPIO data bit
  
' Parameter variables:
' servername -- IP address or host name
' pin -- GPIO pin number (2-26, as numbered by Linux)
' data -- Set to 0 or 1
Sub GetGPIO
  webpage = Network.GetWebPageContents("http://" + servername + ":8083/GPIO/get/" + pin)
   
  If Text.StartsWith(webpage, "GPIO" + pin + "=") Then
    data = Text.GetSubTextToEnd(webpage, Text.GetIndexOf(webpage, "=") + 1)
  Else
    GraphicsWindow.ShowMessage(webpage, "GPIO Server Error")
  EndIf
EndSub
' Write GPIO data bit
' Parameter variables:
' servername -- IP address or host name
' pin -- GPIO pin number (2-26, as numbered by Linux)
' data -- 0=OFF (low), 1=ON (high)
Sub PutGPIO
  webpage = Network.GetWebPageContents("http://" + servername + ":8083/GPIO/put/" + pin + "," + data)
  If Text.StartsWith(webpage, "GPIO" + pin + "=") Then
  Else
    GraphicsWindow.ShowMessage(webpage, "GPIO Server Error")
  EndIf
EndSub