[Contents]
[Prev] [Next] [Limbo Basics] [Limbo Programming] [Language Definition]

Real remote control

The module is used by creating a channel and passing it to the module's init function, which returns a success/error indicator and starts an asynchronous process to read the remote control. The user of the module executes a receive on the channel whenever it wishes to accept a button-push.

The (abridged) module declaration is

Ir : module
{
	# Code buttons on IR remote control
	Zero :	con 0;
	One :	con 1;
	. . .	Mute :	con 23;
		Error :	con 9999;

	init : fn(c : chan of int): int;
	PATH : con "/dis/ir.dis";
	SIMPATH : con "/dis/irsim.dis";
};

The implementation for the real remote control is:

implement Ir;

include "ir.m";
include "sys.m";
FD, Dir : import Sys;

sys : Sys;

init(keys : chan of int) : int
{
	cfd, dfd: ref FD;

	sys = load Sys Sys->PATH;

	cfd = sys->open("/dev/eia1ctl", sys->OWRITE);
	if(cfd == nil)
		return -1;
	sys->fprint(cfd, "b9600");

	dfd = sys->open("/dev/eia1", sys->OREAD);
	cfd = nil;

	spawn reader(keys, dfd);
	return 0;
}

The init routine accepts a chan argument; it will be used by the module to send codes for the buttons pressed by the user. In this routine, the calls to sys->open and sys->fprint open and set up the device data and control files /dev/eia1 and /dev/eia1ctl used to communicate with the device itself. The important step is at the end: the spawn statement creates a new, asynchronous task to read the device, using a routine that is passed the communications channel and the FD for the device:

reader(keys: chan of int, dfd: ref FD)
{
	n, ta, tb: int;
	dir: Dir;
	b1:= array[1] of byte;
	b2:= array[1] of byte;

	# find the number of bytes already
	# queued and flush that many
	(n, dir) = sys->fstat(dfd);
	if(n >= 0 && dir.length > 0) {
		while(dir.length) {
			n = sys->read(dfd,
			 	array[dir.length] of byte,
				dir.length);
			if(n < 0)
				break;
			dir.length -= n;
		}
	}

pair:
	for(;;) {
		n = sys->read(dfd, b1, len b1);
		if(n <= 0)
			break;
		ta = sys->millisec();
		# Button pushes are pairs of characters
		# that arrive closer together than
		# 200 ms. Longer than that is likely
		# to be noise.
		for(;;) {
			n = sys->read(dfd, b2, 1);
			if (n <= 0)
				break pair;
			tb = sys->millisec();
			if (tb - ta <= 200)
				break;
			ta = tb;
			b1[0] = b2[0];
		}
		# map the character pair; the significant
		# bits are the lowest 5.
	case ((int b1[0]&16r1f)<<5) | (int b2[0]&16r1f) {
		975 => n = Ir->Zero;
		479 => n = Ir->One;
		. . .
		791 => n = Ir->Mute;
		* => n = Ir->Error;
		}
		# found a button-push; send the value
		keys <-= n;
	}
	keys <-= Ir->Error;
}


 The code in the middle is related to noise-filtering and is uninteresting in detail except as it illustrates some of the methods provided by the Sys module; the crucial actions are found at the bottom, where the routine sends either a true button-push or an error code over the channel to the module's client.



[Contents]
[Prev] [Next] [Limbo Basics] [Limbo Programming] [Language Definition]

Copyright © 1998, Lucent Technologies, Inc. All rights reserved.