26c3 (the 26th Chaos Communications Congress, in Berlin) featured three programmable large flashing C letters outside the front entrance - DieDreiC.
Light patterns could be uploaded by anyone with a web browser in a low level language which directly controlled individual bulbs. Like several others, I felt the urge to write a higher level language to generate lower level code. What follows is a brief description of that language.
One goal was to make use of Haskell's strong typing. The low level languge has many untyped integer fields and I found when I was experimenting that I got confused about these a bit.
data LampID = SpecificLamp BulbID | AllLamp | Random | SpecificLetter Letter
LampID
identifies a lamp or set of lamps - the various selections here map
to the options available in the underlying language. Random
in this case means random-at-the-time-of-pattern-execution, not at the time
of executing the Haskell code
(unlike other random behaviour in this high level language).
data Letter = LeftLetter | MiddleLetter | RightLetter instance Random Letter
Letter
refers to one of the three full C letters. It is an
instance of Random
so that one full letter can be chosen
randomly.
data BulbID = BulbID Char deriving Show
BulbID
refers to a specific light bulb. These are identified
by a letter A-O. At the moment there is no checking that you only construct
BulbIDs with those letters, so this is something that future development
should fix.
data Color = Color Int Int Int instance Random Color black = Color 0 0 0 red = Color 255 0 0 green = Color 0 255 0 yellow = Color 255 255 0 blue = Color 0 0 255 magenta = Color 255 0 255 cyan = Color 0 255 255 white = Color 255 255 255
Color
represents an RGB colour, with components between
0 and 255. As with BulbID, nothing enforces that range on the constructor, so
its possible to construct invalid colours. This should be fixed. The
Random
type class is implemented so that random colours can be
chosen (at haskell-script-execution time). The 8 main colours are defined
as constants for easy use in patterns.
Commands live in the DDC monad, and are run with the runDDC
IO action.
This monad makes available basic commands that correspond closely with the low level language, as well as a random number generator and a number of library routines.
A non-exhaustive selection of these:
wait n
waits for n milliseconds
colorLetter letter color
colours the specified letter with the specified colour
colorEverything color
colours all three letters with the specified colour
blankEverything = colorEverything black
blanks the whole display
Here is a complete program which flashes the first letter red, then the second letter green, then the third letter blue:
import DDC main = runDDC $ do blankEverything wait 1000 illuminateLetter LeftLetter red illuminateLetter MiddleLetter green illuminateLetter RightLetter blue wait 5000 illuminateLetter letter color = do colorLetter letter color wait 5000 colorLetter letter black
The example program can be compiled and run like this, generating on stdout the low level code to paste into the DDC web interface:
$ ghc --make RGB-seq.hs [1 of 2] Compiling DDC ( DDC.hs, DDC.o ) [2 of 2] Compiling Main ( RGB-seq.hs, RGB-seq.o ) Linking RGB-seq ... $ ./RGB-seq C ALL #000000 W 1000 C 1 #FF0000 [...etc...]
The DDC monad provides access to the Haskell random number generator. In
addition to generating random values of standard Haskell types, DDC
types Letter
and Color
can be generated too.
The randomDDC
command returns a random value, and the
randomRangeDDC
command returns a random value within a
specified range. The type of the
random value is determined by Haskell type inference so often it is
unnecessary to specify which type is required.
Here is an example program which makes 19 flashes of random letters in
random colours, with a random delay between flashes. Note how the types
for the random letter and colour are not specified but are determined by
their use later on with the colorLetter
command.
import DDC import Control.Monad main = runDDC anim anim = do blankEverything replicateM_ 19 randomFlash randomFlash = do letter <- randomDDC color <- randomDDC colorLetter letter color wait 100 blankEverything t <- randomRangeDDC (800,1500) wait t
Tarball of git repository: 26c3-ddc-0.1.tar.gz (3mb)