How to blink a light in 10+ different programming languages
Purpose
The purpose of this post is to demonstrate the diversity and availability of programming languages on embedded Linux platforms, like the BeagleBone and Raspberry Pi. It is not meant to demonstrate how it would or could be done on platform X or platform Y, such as Arduino. Additionally, it based on and assumed that the Linux kernel has included the [GPIO Sysfs Interface for Userspace][linuxgpio]. If you are not familiar with it, it maps the SoCs hardware to the Linux file system. For example, on the BeagleBone, there are 4 ‘user’ leds that are mapped to the file system as follows.
/sys/class/leds/beaglebone\:green\:usr[0-3]
Why do this?
The examples below are simple and basically open a file and write to it, however, I think it demonstrates two things:
- There are serveral languages that are quite easily installed from the package manager of the Linux distribution running on the SoC.
- The blinking light is the hardware hacking equivalent of the ‘Hello World’ program in software. If you can blink a light programatically, you can extend that to reading sensors and controlling actuators.
You can use these examples as a starting point and extend them to your own projects. I am personally interested in the ‘Internet of Things’ and/or Home Automation.
A great book that I’ve read on the BeagleBone is by Derek Molloy.
I’ve also used the BeagleBone Black and RPi 2 for these examples:
First Steps
I am making the following assumptions:
- you already have a Linux version running on your platform
- a package manager is available to install software (the examples below use debian’s apt-get)
- you can connect into your platform, either through telnet or ssh
- you can compile and run the various examples based on the programming language (although I should add that as well to the examples)
Notes about the examples
- I am using the default provided user leds on BeagleBone which are mapped via GPIO Sysfs
- these are simple examples and wouldn’t be used in production and therefore best practices are not always applied (see Why do this?)
- all the examples work, they blink an led on a beaglebone
- the examples could be coded differently to demonstrate the same thing
(1) Bash Shell
The first language we’ll use is the ‘bash’ shell. It’s installed by default.
#!/bin/bash
STATE=0
while :
do
STATE=$((STATE==0))
echo $STATE > /sys/class/leds/beaglebone\:green\:usr0/brightness
sleep 2
done
(2) Perl
Perl is installed by default.
#!/usr/bin/perl
use warnings;
my $state = 1;
my $filename = "/sys/class/leds/beaglebone:green:usr0/brightness";
while (1) {
open LED , ">>$filename" or die "Error opening $filename: $!";
syswrite (LED, $state , 1);
$state = 1 - $state;
sleep 2;
}
(3) C
The C compiler (gcc) is installed by default.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp = NULL;
char *filename = "/sys/class/leds/beaglebone:green:usr0/brightness";
int state = 1;
int retval = 0;
if ((fp = fopen(filename, "w")) == NULL) {
printf("failed to fopen led\n");
exit(-1);
}
for (;;) {
if ((retval = fputc('0' + state, fp)) == EOF) {
printf("failed to fputc led\n");
exit(-1);
}
fflush(fp);
sleep (2);
state = 1 - state;
}
}
(4) C++
The C++ compiler (g++) isn’t installed by default:
# sudo apt-get install g++
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <stdlib.h>
using namespace std;
int main() {
ofstream led;
string filename("/sys/class/leds/beaglebone:green:usr0/brightness");
int state = 1;
led.open (filename.c_str(), ios::binary);
if (led.is_open()) {
while (true) {
led << state << endl;
sleep (2);
state = 1 - state;
}
}
else {
cout << "failed to open led" << endl;
exit(-1);
}
}
(5) Python
Python is installed by default.
import time
filename = "/sys/class/leds/beaglebone:green:usr0/brightness"
f = open(filename, "w")
state = 1
while True:
f.write(str(state))
f.flush()
time.sleep(2)
state = 1 - state
(6) Ruby
Ruby is not installed by default:
# sudo apt-get install ruby
#!/usr/bin/ruby
filename = "/sys/class/leds/beaglebone:green:usr0/brightness"
state = 1
begin
file = File.open(filename, "w")
loop do
file.write(state.to_s)
file.flush
sleep(2)
state = 1 - state
end
rescue IOError => e
puts "failed: #{e}"
ensure
file.close unless file == nil
end
(7) Java
Java is not installed by default:
# sudo apt-get install openjdk-7-jdk
import java.io.*;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
public class Blink {
public static void main(String[] args) throws IOException, InterruptedException {
int state = 1;
Path path = Paths.get("/sys/class/leds/beaglebone:green:usr0/brightness");
try(BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
while (true) {
writer.write('0' + state);
writer.flush();
Thread.sleep(2000);
state = 1 - state;
}
}
}
}
(8) Scala
Scala is not installed by default:
# sudo apt-get install scala
import java.io.File
import java.io.FileWriter
import java.io.BufferedWriter
object Blink {
def main(args: Array[String]) {
var state = 1
val file = new File("/sys/class/leds/beaglebone:green:usr0/brightness")
val writer = new BufferedWriter(new FileWriter(file))
while (true) {
writer.write('0' + state)
writer.flush()
Thread.sleep (2000)
state = 1 - state;
}
}
}
(9) Go
Go is not installed by default
# sudo apt-get install golang
package main
import (
"log"
"os"
"strconv"
"time"
)
func main() {
f, err := os.OpenFile("/sys/class/leds/beaglebone:green:usr0/brightness", os.O_RDWR, 0666)
if err != nil {
log.Fatal(err)
}
defer f.Close()
state := 1
for {
_, err = f.WriteString(strconv.Itoa(state))
if err != nil {
log.Fatal(err)
}
time.Sleep(2 * time.Second)
state = 1 - state
}
}
(10) Clojure
Clojure is not installed by default:
# sudo apt-get install clojure1.4
(defn blink []
(with-open [fw (clojure.java.io/writer "/sys/class/leds/beaglebone:green:usr0/brightness" :append true)]
(loop [state 1]
(.write fw (Integer/toString state))
(.flush fw)
(Thread/sleep 2000)
(recur (- 1 state)))))
(blink)
(11) Pascal
Pascal is not installed by default:
# sudo apt-get install fpc
{$IFDEF FPC}
{$MODE DELPHI}
{$ENDIF}
Program Blink;
uses
Sysutils;
const
LED_FNAME = '/sys/class/leds/beaglebone:green:usr0/brightness';
var
Led: TextFile;
State: Integer;
begin
State:=1;
try
Assign(Led, LED_FNAME);
Append(Led);
While true do
begin
Writeln(Led, State);
Flush(Led);
Sleep(2000);
State:=1-State;
end;
except
on E: EInOutError do
Writeln('failed: ', E.Message);
end;
CloseFile(led);
end.
(12) NodeJS
NodeJS is not installed by default:
# sudo apt-get install nodejs
var state = 1;
setInterval(blink, 2000);
function blink() {
var fs = require("fs");
fs.writeFile("/sys/class/leds/beaglebone:green:usr0/brightness", state, function (err) {
if (err) throw err;
});
state = 1 - state;
}
(13) Haskell
Haskell (ghc) is not installed by default:
# sudo apt-get install ghc
TODO
(13) Rust
Rust is not installed by default:
TODO
[linuxgpio]: https://www.kernel.org/doc/Documentation/gpio/sysfs.txt