"blinkenlightd" is a background service ("daemon") written for the BeagleBone. It publishes the attached console panels to Blinkenlight API clients. It normally does not talk to users, but communicates over these other interfaces:
- It provides a BlinkenLight API server interface for clients, see the "Blinkenlight API" page.
- It converts the digital signals connected to the BlinkenBoards to usable "control values". The information how to do this is read from a configuration file.
- It uses the file interface "/dev/blinkenbus" to control the BlinkenBoards.
Connecting panels to BlinkenBoards
If you connected the wires from a vintage panel to the I/O chips on the BlinkenBoard, you typically
- solder some kind of connectors onto the patch field
- and route wires from the connectors to the terminals of the input or output register chips.
It doesn't always looks nice, if a programmer tries to solder:
The assignment between console panel functions and I/O register bit positions must be evaluated by software then.
Problem: decoding/encoding bit patterns into control values
Translating raw digital I/O signals to useful application data involves lot of bit masking and bit shifting. This is usually done in program code which is specialized for the hardware in use.
Example 1:
The 11/40 console panel has a 18 bit switch row for data entry, it is labled "SR" by DEC (for "Switch Register). Let's say the wires coming from SR are connected to the BlinkenBoard with address 1 as follows:
Panel | BlinkenBoard | ||
signal | board address |
register | bits |
SR0..SR7 | #1 | IN0 | 0..7 |
SR8..SR15 | #1 | IN1 | 0..7 |
SR16,SR17 | #1 | IN2 | 0..1 |
To get the 18 bit data value for the Blinkenlight API control object, you would use C code like this:
SR_value = get_board_register_data(1, 0)
| ( get_board_register_data(1, 1) << 8)
| ( get_board_register_data(1, 2) << 16) ;
Example 2:
The LED "VIRTUAL" is connected to bit 6 of output register 2 on board #1.
To set the LED, this code would be necessary:
tmpval = cached_OUT2_value ;
if (led_virtual)
tmpval |= 0x40 ; // set bit 6
else
tmpval &= ~0x40 ; // clear bit 6
set_board_register_data(1, 2, tmpval ) ;
cached_OUT2_value = tmpval ;
So for each connection schema, specialized decoding logic must be programmed.
Solution: generic logic and a configuration file
The program code of blinkenlightd does not contain any special code for a certain console panel.
Instead actual wiring is read from a configuration file. If wires are changed on the patch field of a BlinkenBoard, only the configuration file must be changed accordingly.
Bit masking and shifting is done by fixed generic logic in blinkenlightd.
This diagram illustrates how raw digital I/O data from the panel is mapped to proper "control" values:
(click image to enlarge)
The configuration file is also a good documentation about what you've done on the patch field!
The name of the configuration file is normally "/etc/blinkenlightd.conf", since it is the setup file for a Linux service.
In the attachement you find two files:
- the grammar of the configuration files (I used the wunderful "ANTLR" parser generator).
- the full configuration file for the PDP-11/40 panel.
FULL configuration file entry for Example 1:
control =
{
// 18 switches, for data and address input
name = "SR", // "Switch register"
type = SWITCH,
encoding = BINARY,
blinkenbus_wiring =
{
// 18 wires, connected to board 1, input register chips 0, 1 and 2
register_wiring =
{
value_bit_offset = 0, // define bits 0..7 of value
board = 0x01,
register = IN0,
bits = 0..7, // lsb on register = lsb in value!
levels = active_high // is default
}, //
register_wiring =
{
value_bit_offset = 8, // define bits 8..15 of value
board = 0x01,
register = IN1,
bits = 0..7 // lsb on register = lsb in value!
}, //
register_wiring =
{
value_bit_offset = 16, // define bits 16..17 of value
board = 0x01,
register = IN2,
bits = 0..1// only 2 lsb bits for addr 16 & 17
}
}
},
FULL configuration file entry FOR EXAMPLE 2:
control =
{
name = "VIRTUAL",
type = LAMP,
encoding = BINARY,
blinkenbus_wiring =
{
register_wiring =
{
value_bit_offset = 0,
board = 0x01,
register = OUT2,
bits = 6
}
}
}
* * * * *
Normally blinkenlightd runs without user interaction. But it has two interactive modes:
Using blinkenlightd to test the configuration file
blinkenlightd can check the configuration file for logical errors. Call it with these options:
blinkenlightd -c configuration_file_name -t
Using blinkenlightd to simulate the console panel defined in the configuration file
This is tricky. If you call blinkenlightd like this
blinkenlightd -c configuration_file_name -s
it goes into interactive simulation mode.
It does not access the real console panel over "/dev/blinkenbus" anymore, instead it shows a crude text simulation of the panel described in the configuration file:
The function is simple:
- A list of the output controls and input controls with their current values is shown.
- If a client sets an output control value over Blinkenlight API, the display is updated.
- The value of an input control (a simulated switch) can be set by the user. A Blinkenlight API client gets the new input value on the next call to blinkenlightd.
In simulation mode, blinkenlight does not access any hardware over /dev/blinkenbus. So it can run on any platform, it is not bound to the BeagleBone.
If you like to impress people on an exhibition, you must write an graphical console panel simulator. But blinkenlightd in simulation mode is a valuable tool to develop or debug machine simulation clients without access to a physical BeagleBone/BlinkenBus/BlinkenBoard/panel installation.
blinkenlight_panel_config.g -- ANTLR grammar definition for blinkenlightd configuration file
pdp11-40.conf -- blinkenlightd config file for PDP-11/40 panel