#INCLUDE "plumbing.module" VAL out.pin IS 2 : VAL in.pin IS 3 : VAL door.pin IS 4 : VAL pir.pin IS 5 : VAL flow.pin IS 6 : VAL spray.led.reset.pin IS 7: VAL lockout.motor.open IS 9 : VAL lockout.motor.close IS 10 : VAL lockout.led IS 11 : VAL armed.led IS 12 : VAL spray.led IS 13 : PROTOCOL BLINK IS INT; INT; INT: PROC monitor.pin (VAL INT pin, suspend.time, CHAN SIGNAL out!, term?, suspend?) --general pin interrupt monitor LEVEL now, prev: TIMER tim: INT t: SEQ digital.read (pin, prev) INITIAL BOOL active IS TRUE: WHILE active SEQ tim ? t PRI ALT term ? SIGNAL active := FALSE suspend ? SIGNAL delay (suspend.time) tim ? AFTER t PLUS 10 SEQ digital.read (pin, now) IF (now = LOW) AND (prev = HIGH) SEQ out ! SIGNAL TRUE SKIP prev := now : PROC flap.state (CHAN BOOL output!, CHAN SIGNAL term?) --emits TRUE or FALSE to show whether cat is on or out (based on cat flap sensors) CHAN SIGNAL cat.in, cat.out, term.out, term.in, susp.out, susp.in: TIMER tim: INT t1, t2: PAR monitor.pin (out.pin, 0, cat.out!, term.out?, susp.out?) monitor.pin (in.pin, 0, cat.in!, term.in?, susp.in?) INITIAL BOOL armed IS TRUE: INITIAL BOOL active IS TRUE: SEQ WHILE active SEQ tim ? t1 PRI ALT term ? SIGNAL active := FALSE tim ? AFTER t1 PLUS 10 SEQ tim ? t2 PRI ALT cat.out ? SIGNAL armed := FALSE cat.in ? SIGNAL armed := TRUE tim ? AFTER t2 PLUS 10 SKIP output ! armed term.out ! SIGNAL term.in ! SIGNAL : PROC pin.timeout (VAL INT pin, timeout.secs, CHAN SIGNAL output!, term?) -- emits a signal if a pin remains LOW for longer than the specified timeout period in secs LEVEL l: TIMER tim: INT t, prev, now: INITIAL BOOL active IS TRUE: SEQ tim ? prev WHILE active SEQ tim ? t PRI ALT term ? SIGNAL active := FALSE tim ? AFTER t PLUS 10 SEQ tim ? now digital.read (pin, l) IF l = HIGH tim ? prev TRUE SKIP IF (now MINUS prev) >= (timeout.secs * 1000) output ! SIGNAL TRUE SKIP : PROC blinker (CHAN BLINK blink?, VAL INT pin, CHAN SIGNAL cancel?, term?) --blinks an LED for specified duration, on time and off time --on time and off time is in millisecs, duration in secs: if 0 then will carry on indefinitely until halted by either... --blinking can be cancelled by a SIGNAL --PROC can be terminated by a SIGNAL --requires PROTOCOL BLINK IS INT; INT; INT: in definitions TIMER tim: INT now, start, cycle.start, on.time, off.time, duration: INITIAL BOOL active IS TRUE: INITIAL BOOL running IS FALSE: INITIAL BOOL on IS FALSE: INITIAL BOOL run IS FALSE: SEQ WHILE active SEQ tim ? now PRI ALT blink ? on.time; off.time; duration SEQ run := TRUE tim ? start cancel ? SIGNAL running := FALSE term ? SIGNAL active := FALSE tim ? AFTER now PLUS 10 SEQ IF run SEQ tim ? cycle.start run :=FALSE running := TRUE TRUE SKIP IF running IF (duration = 0) OR ((start PLUS (duration * 1000)) AFTER now) IF ((cycle.start PLUS on.time) AFTER now) AND (NOT (on)) SEQ digital.write (pin, HIGH) on := TRUE (now AFTER (cycle.start PLUS on.time)) AND on SEQ digital.write (pin, LOW) on := FALSE (now AFTER ((cycle.start PLUS on.time) PLUS off.time)) tim ? cycle.start TRUE SKIP TRUE running := FALSE TRUE SKIP : PROC spray (CHAN SIGNAL fire?, term?, CHAN BLINK blink!) --sprays water when receives fire SIGNAL INITIAL BOOL active IS TRUE: TIMER tim: INT t: WHILE active SEQ tim ? t PRI ALT fire ? SIGNAL SEQ --write to fire pin TBC blink ! 100; 100; 2 delay (2000) blink ! 50; 5000; 0 term ? SIGNAL SEQ active := FALSE tim ? AFTER t PLUS 10 SKIP : PROC set.pin.modes () SEQ digital.mode (in.pin, INPUT) digital.mode (out.pin, INPUT) digital.mode (pir.pin, INPUT) digital.mode (door.pin, INPUT) digital.mode (flow.pin, INPUT) digital.mode (spray.led.reset.pin, INPUT) digital.mode (armed.led, OUTPUT) digital.mode (spray.led, OUTPUT) digital.mode (lockout.led, OUTPUT) digital.mode (lockout.motor.open, OUTPUT) digital.mode (lockout.motor.close, OUTPUT) digital.write (armed.led, LOW) digital.write (spray.led, LOW) : PROC lock.out (VAL BOOL lockout) --drives lockout valve open or closed SEQ IF lockout SEQ digital.write (lockout.led, HIGH) digital.write (lockout.motor.close, HIGH) delay (500) --drive motor to close valve for half a second digital.write (lockout.motor.close, LOW) digital.write (armed.led, LOW) NOT lockout SEQ digital.write (lockout.led, LOW) digital.write (lockout.motor.open, HIGH) delay (500) --drive motor to open valve for half a second digital.write (lockout.motor.open, LOW) : PROC main () CHAN BLINK blink: CHAN BOOL flap: CHAN SIGNAL fire, door, pir, flow, spray.led.reset: CHAN SIGNAL flap.term, fire.term, door.term, pir.term, flow.term, blinker.term, spray.led.reset.term: CHAN SIGNAL door.susp, pir.susp, spray.led.reset.susp: INITIAL BOOL armed IS TRUE: INITIAL BOOL lockout IS FALSE: INT t: TIMER tim: SEQ set.pin.modes() lock.out (FALSE) PAR flap.state (flap!, flap.term?) --monitors cat flap and sets armed state pin.timeout (flow.pin, 10, flow!, flow.term?) -- monitors water flow to prevent a flood monitor.pin (door.pin, 0, door!, door.term?, door.susp?) -- monitors back door monitor.pin (pir.pin, 10000, pir!, pir.term?, pir.susp?) -- monitors PIR, suspends for 10 secs following FIRE event spray (fire?, fire.term?, blink!) -- sets spray switch listening blinker (blink?, spray.led, spray.led.reset?, blinker.term?) -- sets fire blinker listening monitor.pin (spray.led.reset.pin, 0, spray.led.reset!, spray.led.reset.term?, spray.led.reset.susp?) -- monitors spray led reset button SEQ WHILE NOT lockout SEQ flap ? armed IF armed digital.write (armed.led, HIGH) NOT armed digital.write (armed.led, LOW) tim ? t PRI ALT flow ? SIGNAL lockout := TRUE door ? SIGNAL lockout := TRUE pir ? SIGNAL IF armed PAR pir.susp ! SIGNAL fire ! SIGNAL NOT armed SKIP tim ? AFTER t PLUS 10 SKIP PAR lock.out (TRUE) flap.term ! SIGNAL flow.term ! SIGNAL door.term ! SIGNAL pir.term ! SIGNAL fire.term ! SIGNAL blinker.term ! SIGNAL spray.led.reset.term ! SIGNAL :