Challenge 3: Parilux
The Serilux only needs one LED to be controlled. The Parilux has more potential for control: 4 LED's and several inputs and outputs for custom applications. It is more expensive than Serilux (although it's still cheap) but easy to make and use, as you will see.
The challenge is to make the Parilux LED's blink in a controlled fashion. You have to make a program that will change the state of the LED's when the user presses a key, clicks a button or issues a command. Or a combination of these.
Solutions
As usual I made several solutions, each in its own programming language. The Parilux card is the official IWM 2008 challenge. But I like to get a headstart and make solutions now. Thus far I made software blinkers in the following languages:
Linux : Modula-2
This is a short one. Just to show that long programs in most cases tend to hide something. Like the inability of the programmer... This program looks a lot like the Serilux program. It's just slightly more versatile. One learns by doing.
MODULE parilux1;
IMPORT InOut, IOport; (* Use these librarie modules *)
CONST LPTbase = 0EFF0H; (* The IO port is at this address *)
VAR val : CARDINAL; (* val keeps the value of the IO register *)
ch : CHAR; (* ch stores the latest character read in *)
BEGIN
IF IOport.IOperm (LPTbase, LPTbase, TRUE) = FALSE THEN
InOut.WriteString ("Could not get IO permission.");
InOut.WriteLn
END; (* Try to get permission to access LPTport *)
val := IOport.InPort (LPTbase); (* Get the initial value of LPTport register *)
LOOP (* Start an infinite loop *)
InOut.Read (ch); (* Read a character from the keyboard *)
CASE ch OF (* Choose which character to act on *)
"x",
"X" : EXIT | (* 'x' = exit from LOOP *)
"1" : val := CARDINAL ( BITSET (val) / {0}); (* toggle bit 0 *)
IOport.OutPort (LPTbase, val) | (* Write it to IO port *)
"2" : val := CARDINAL ( BITSET (val) / {1}); (* toggle bit 1 *)
IOport.OutPort (LPTbase, val) |
"3" : val := CARDINAL ( BITSET (val) / {2}); (* toggle bit 2 *)
IOport.OutPort (LPTbase, val) |
"4" : val := CARDINAL ( BITSET (val) / {3}); (* toggle bit 3 *)
IOport.OutPort (LPTbase, val)
ELSE
InOut.Write (".")
END
END;
IF IOport.IOperm (LPTbase, LPTbase, FALSE) = FALSE THEN (* Release IO port *)
InOut.WriteString ("Could not release IO permission.");
InOut.WriteLn
END
END parilux1.
What it boils down to is:
val := CARDINAL ( BITSET (val) / {0});
First, the variable 'val' is typecast to a BITSET. This means it is now treated as a SET of individual bits.
Next, the '/' determines that the operation will be 'XOR'. The bit to be XORred is mentioned between the curly
braces "{" and "}". After the XOR operation, the collection of BITS is changed back into a CARDINAL.
Compile as usual, preferably as root:
jan@beryllium:~/modula/parilux$ su Password: beryllium:/home/jan/modula/parilux# mocka Mocka 0608m >> i parilux1 >> p parilux1 .. Compiling Program Module parilux1 I/0001 II/0001 .. Linking parilux1 >> ./parilux1 0 0 1 1 >> q beryllium:/home/jan/modula/parilux# chmod 4755 parilux1 beryllium:/home/jan/modula/parilux# exit exit jan@beryllium:~/modula/parilux$ ls -lh parilux1* -rwsr-xr-x 1 root root 24K 2007-09-06 00:33 parilux1 -rw-r--r-- 1 jan users 934 2007-09-06 00:33 parilux1.mod jan@beryllium:~/modula/parilux$It works and I am kind of prowd of it. Programming can be so much fun. As my friend FP is already finding out.
Linux : Tcl/Tk
I like programming in Modula-2. But I also like programming in Tcl/Tk. It is fast to develop magnificant user
interfaces and with a little help from Mocka you can make perfect programs for which neither Tcl nor Tk was
ever designed.
On the right you see the Tcl/Tk program which will control the states of the LED's via simple mouse clicks. This program, just like Serilux, relies heavily on two small 'filters' written in Modula-2: IOrd2 and IOwr2. The source code of the 'program' (more strictly, this is a script) is below:
#!/usr/bin/wish
set Data0 0 // Define variables and set them to an initial value
set Data1 0
set Data2 0
set Data3 0
set Data4 0
set Data5 0
set Data6 0
set Data7 0
set Ctrl1 0
set Ctrl2 1
set Ctrl3 1
set Ctrl4 0
proc sync {} \ // Define a procedure {without parameters}
{
global Data0 Data1 Data2 Data3 Data4 Data5 Data6 Data7 Ctrl1 Ctrl2 Ctrl3 Ctrl4
set outs [expr $Data0 + $Data1*2 + $Data2*4 + $Data3*8 + $Data4*16 + $Data5*32 + $Data6*64 + $Data7*128]
exec IOwr2 EFF0 $outs // WRITE the outputs
set ins [exec IOrd2 EFF1] // READ the inputs
set Ctrl1 [expr ($ins/32) % 2]
set Ctrl2 [expr ($ins/64) % 2]
set Ctrl3 [expr !($ins/128)]
set Ctrl4 [expr ($ins/16) % 2] // All four inputs decoded and ready to display
}
frame .frm1 -relief groove // A frame is a container to hold widgets
frame .frm2 -relief groove
frame .frm3 -relief groove
frame .frm4 -relief groove
frame .frm5 -relief groove
frame .frm6 -relief groove
frame .frm7 -relief groove
frame .frm8 -relief groove
frame .frm9 -relief groove
frame .frm10
frame .frm11
frame .frm12
button .out1 -text "Toggle" -command {set Data0 [expr !$Data0]; sync } // Buttons and their actions
button .out2 -text "Toggle" -command {set Data1 [expr !$Data1]; sync }
button .out3 -text "Toggle" -command {set Data2 [expr !$Data2]; sync }
button .out4 -text "Toggle" -command {set Data3 [expr !$Data3]; sync }
button .out5 -text "Toggle" -command {set Data4 [expr !$Data4]; sync }
button .out6 -text "Toggle" -command {set Data5 [expr !$Data5]; sync }
button .out7 -text "Toggle" -command {set Data6 [expr !$Data6]; sync }
button .out8 -text "Toggle" -command {set Data7 [expr !$Data7]; sync }
button .sync -text "Sync" -command { sync }
button .quit -text "Quit" -command { destroy .}
checkbutton .out1c -text "LED 1" -variable Data0
checkbutton .out2c -text "LED 2" -variable Data1
checkbutton .out3c -text "LED 3" -variable Data2
checkbutton .out4c -text "LED 4" -variable Data3
checkbutton .out5c -text "OC 1" -variable Data4
checkbutton .out6c -text "OC 2" -variable Data5
checkbutton .out7c -text "OC 3" -variable Data6
checkbutton .out8c -text "Select" -variable Data7
checkbutton .in1 -text "IN 1" -variable Ctrl1
checkbutton .in2 -text "IN 2" -variable Ctrl2
checkbutton .in3 -text "IN 3" -variable Ctrl3
checkbutton .in4 -text "IN 4" -variable Ctrl4
pack .out1 .out1c -in .frm1 -side top -padx 2m -pady 2m // Compose the order in which the
pack .out2 .out2c -in .frm2 -side top -padx 2m -pady 2m // buttons are displayed on screen
pack .out3 .out3c -in .frm3 -side top -padx 2m -pady 2m
pack .out4 .out4c -in .frm4 -side top -padx 2m -pady 2m
pack .out5 .out5c -in .frm5 -side top -padx 2m -pady 2m
pack .out6 .out6c -in .frm6 -side top -padx 2m -pady 2m
pack .out7 .out7c -in .frm7 -side top -padx 2m -pady 2m
pack .out8 .out8c -in .frm8 -side top -padx 2m -pady 2m
pack .frm1 .frm2 .frm3 .frm4 -in .frm10 -side left -fill x
pack .frm5 .frm6 .frm7 .frm8 -in .frm11 -side left -fill x
pack .in1 .in2 .in3 .in4 -in .frm9 -side left -padx 2m -pady 2m -fill x
pack .sync .quit -in .frm12 -side left -padx 2m -pady 2m
pack .frm10 .frm11 -fill x // These frames are 3 levels deep!
pack .frm9
pack .frm12
As with the Serilux program, the majority of the lines in the script have to deal with the user interface
(buttons and packing them in a geometrical order). The actual 'program' lines are only very few. Most of them
are in the 'sync' procedure. The rest is manipulation of variables.
Linux : C
It took me some time but I managed to get a working version. Here is the source:
/*
* * Parilux1 controller
* * Jan Wagemakers en Pros (1997)
* * Jan Verhoeven (2007)
* */
#include <stdio.h>
#include <stdlib.h>
#include <sys/io.h>
#define LPTport 0xEFF0
int main ()
{
unsigned short int val, shift;
int ch;
ioperm (LPTport, 1, 1);
ch = 'A';
val = inb (LPTport);
while (ch != 'x')
{
ch = getchar ();
if (ch > ' ') shift = ch - 49; else continue;
val = val ^ (1 << shift);
outb (val, LPTport);
}
ioperm (LPTport, 1, 0);
printf ("\nC you later! \n");
return (0);
}
Try to figure out why and how it works. Here are the directions for compilation:
jan@beryllium:~/modula/parilux$ su Password: beryllium:/home/jan/modula/parilux# jed par.c beryllium:/home/jan/modula/parilux# gcc -s -w -o PC par.c beryllium:/home/jan/modula/parilux# chmod 4755 PC beryllium:/home/jan/modula/parilux# exit exit jan@beryllium:~/modula/parilux$ ./PC 1 1 2 2 3 3 4 4 x C you later! jan@beryllium:~/modula/parilux$ ls -lh PC -rwsr-xr-x 1 root root 3.2K 2007-09-06 22:36 PC jan@beryllium:~/modula/parilux$Now, I must admit, this source is kind of nice. It's not like a poem, like Modula-2 is, but it is neat and it is VERY compact: 3 Kb instead of 24!
jan@beryllium:~/modula/parilux$ ls -lh -rw-r--r-- 1 jan users 551 2007-09-06 22:36 par.c -rwsr-xr-x 1 root root 24K 2007-09-06 00:33 parilux1 -rwsr-xr-x 1 root root 3.2K 2007-09-06 22:36 PC
DOS : Power C
Coming up, but if you can do it for me, I would be mighty pleased.
Page created on 4 September 2007 and
Page equipped with FroogleBuster technology