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 a
rgument; 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 theSys
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.