How to blink a light in 10 different programming languages
mcconn.xyz
mcconn.xyz
Seriously, not even one Asm example? If you have a PC that has a parallel port and can boot to DOS, you can stick a LED in series with a 100-ohm resistor across pins 2(+) and 18(-) and do this:
mov dx, 378h
xor ax, ax
blinkloop:
out dx, al
mov cx, 36
call delay
not ax
jmp blinkloop
delay:
hlt
loop delay
ret
I find it somewhat amazing that this program, in Assembly, is actually shorter than the 10 HLL programs in the article. section .text
global _start
_start:
; Write the ‘1’ to a file
mov eax, 4 ; sys_write
mov edx, 1 ; # of bytes to write
mov ecx, ‘1’ ; Means light should be on
mov ebx, file_open ; File descriptor
mov eax, 4 ; Call to sys_write
int 0x80 ; Call kernel to write file
; Close file
move eax, 6
mov mov ebx,
int 0x80 ; Call kernel to close file
; Quit to OS
move eax, 1 ; SYS_EXIT
int 0x80 ; Call kernel to exit to OS
section.data
filename db ‘/sys/class/leds/beaglebone:green:usr0/brightness’,0
len equ $-filename
section .bss
file_open resb 1
state db ‘1’I think it's very important that programmers are exposed to such "absolute minimum simplicity" solutions, as it helps greatly with understanding the essence of the problem and its solution - in this case it's nothing more than toggling a bit in an I/O port. Complexity can be added afterwards as needed, but not gratuitously.
I like how one of the other comments here and in the article mentions that there's no error handling in many of the examples, since it brings up another point about complexity: it can introduce opportunities for errors. If you're working with the GPIO directly, errors either can't occur, or they're hardware-level (e.g. shorted output) and nothing can really be done about it anyway unless the hardware has additional features for signaling such conditions. If you're going through the OS' filesystem, errors can occur at any one of the multiple layers for not-so-related reasons to the actual task. One should then ask the question of whether the code that's added to handle errors is actually doing something useful for the task, or serves no purpose beyond satisfying the other layers of complexity that introduce them.
https://dotnetfiddle.net/afyTvh
using System;
using System.IO;
using System.Threading;
public class Blink
{
const string FilePath = @"/sys/class/leds/beaglebone\:green\:usr0/brightness";
const int BlinkDelay = 2000;
public static void Main()
{
using (var writer = new StreamWriter(FilePath))
{
for (var state = true; true; state = !state)
{
writer.Write((state ? 1 : 0).ToString("00"));
Thread.Sleep(2000);
}
}
}
}
Reactive Extensions (C#)https://dotnetfiddle.net/bpOF5e
Observable
.Repeat(Observable.Unit)
.Select((index, _) => index % 2)
.Select(string.Format({0:00})
.Delay(TimeSpan.FromSeconds(2))
.Aggregate(
new StreamWriter(@"/sys/class/leds/beaglebone\:green\:usr0/brightness"),
writer => (writer, state) => writer.Write(state)
)
.Subscribe(writer => writer.Close());https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...
#!/bin/bash -e
STATE=1
while : do
echo $STATE > /sys/class/leds/beaglebone\:green\:usr0/brightness
let STATE=1-$STATE
sleep 2
done
While all of the programs can be made smaller in size the bash script is probably the default way that the script would be tossed together. Bash has a ton of problems, but sadly between it and the standard unix commands you can get the job done too quickly and easily.That wasn't a subshell - $(( )) is Arithmetic Expansion. (you may be thinking of $( ) for Command Substitution)
$ echo $BASH_SUBSHELL $((BASH_SUBSHELL)) $(echo $BASH_SUBSHELL)
0 0 1
Now, using the result of a boolean is a bit strange; I would have used your math with the modern expansion style: # the new style allows spaces
STATE=$(( 1 - $STATE ))In predicate contexts (which means return code in bash) like if, while or the left hand side of '&&', consider using (( )) - this has an exit code of 0 if the arithmetic expression is true (non-zero) and 1 otherwise. Use it like this:
let x=3*3
if (( x > 5 )); then
echo greater than five
else
echo less than or equal to five
end var lightsOn = true;
setInterval(blink, 2000);
function blink() {
var fs = require("fs");
fs.writeFile("/sys/class/leds/beaglebone:green:usr0/brightness", lightsOn, function (err) {
if (err) throw err;
});
lightsOn = lightsOn ? false : true;
}lightsOn = !lightsOn;
I'll see myself out.
lightsOn = !lightsOn || lightsOn
import Control.Concurrent (threadDelay)
import System.IO
main :: IO ()
main = withFile "/sys/class/leds/beaglebone:green:usr0/brightness" AppendMode go
where put h s = hPutStrLn h s >> threadDelay 2000000
go h = let m = put h "0" >> put h "1" >> m in m go h = let m = put h "0" >> put h "1" >> m in m
Rather than: go h = put h "0" >> put h "1"
Oh, recursion...$ ghc -o blink blink.hs [1 of 1] Compiling Main ( blink.hs, blink.o )
blink.hs:7:22: parse error on input `='
main :: IO ()
main = withFile ledFile AppendMode $ \h -> do
let put s = hPutStrLn h s >> threadDelay 2000000
forever $ do
put "0"
put "1"
where
ledFile = "/sys/class/leds/beaglebone:green:usr0/brightness"Also, if one was going to use the ensure block, use nil? not '== nil'
import 'dart:async';
import 'dart:io';
main() {
var file = new File('/sys/class/leds/beaglebone:green:usr0/brightness');
var state = 0;
new Timer.periodic(new Duration(seconds: 2), (_) {
state = 1 - state;
file.writeAsStringSync('0$state', flush: true);
});
}
While it's not the most concise version, it's certainly very readable. Everyone can clearly see that the duration is 2 seconds and that that boolean flag is for flushing, because that's exactly what the code says. 'x: $x, y: $y'
is a lot easier to type than: 'x: ' + x + ', y: ' + y
I actually had to triple check that line. Concatenation is very error-prone. I often mess it up.String interpolation is a fairly popular feature nowadays:
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 i := 0; i < 3*2; i++ {
_, err = f.WriteString(strconv.Itoa(state))
if err != nil {
log.Fatal(err)
}
time.Sleep(2 * time.Second)
state = 1 - state
}
} // npm install bonescript
var b = require('bonescript');
b.pinMode('P8_13', b.OUTPUT);
b.digitalWrite('P8_13', 1);
Pretty sure Bonescript is just doing the filesystem stuff under the hood, though doing memory mapping would be way nicer.It would make the whole thing less scary for beginners and there are tons of examples and documentation out there.
On most embedded systems and FPGAs faffing with the toolchain and hunting in the documentation is 99% of the effort of getting an LED blinking, that's why it's used as the embedded 'hello world'.
An example of LED toggling via mmap on the Beaglebone is here: https://github.com/MarkAYoder/BeagleBoard-exercises/blob/mas... (and the associated tutorial: http://elinux.org/EBC_Exercise_11b_gpio_via_mmap)