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:
  1. Do the preparations and declarations
  2. Request permission to use the I/O port
  3. Read the current value of the I/O port
  4. Enter an infinite loop and:
  5. Release permission to use the I/O port.
Like with the Serilux program one of the program lines looks like a poem...
	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.
I call this beautiful. It is clear. No guessing like in C or C++.

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.
Still: Tcl/Tk is a mighty fine language. And who cares if it is interpreted, on a 3 GHz Pentium IV?

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