any necessary changes are made (for example, turning the lights on or off, turning on the heater or the AC, etc.) and the controller returns to the main loop. On a message from the master controller, the appliance controller sets its mode accordingly. If the message isonthen before returning to the main loop, poll messages are sent and the replies handled. This ensures that at least one update is made each time the controller is turned on.
Figure 5.12 shows some sample code from the climate controller. The code not shown follows a similar pattern. Also, the implementation of the other appliance controllers is structured in the same way.
The Master Controller
The master controller is implemented as a main event loop in which it receives commands from the user. Each command is handled by setting the current mode and by sendingonandoffmessages to the appliance controllers. Once a reply is received from all of them, a success message is sent back to the user. Figure 5.13 shows some sample code from the implementation of the master controller.
module ClimateCtrl {
export ClimateCtrlInterf;
import ts = TemperatureSensorInterf;
... // the type and constant definitions corresponding to the interface const hysteresis : int = 2;
active process climate() { var state : int = off;
var curr_temp : int = 25; var target_temp : int = 25;
var from_ts : chan[int] = mkchan of int[1];
var heater : int = off; var cooler : int = off;
function poll_sensors_and_update() { var temp : int;
send(ts.poll, {req = ts.get, reply_c = from_ts});
recv(from_ts, temp);
curr_temp = temp;
if
:: curr_temp <= target_temp - hysteresis -> heater = on; cooler = off;
:: curr_temp >= target_temp + hysteresis -> heater = off; cooler = on;
:: else -> heater = off; cooler = off;
fi }
function handle_on(seq_no : int, reply_c:chan[cmd_reply]) { state = on;
poll_sensors_and_update();
send(reply_c,{seq_no = seq_no, status = success, value = 0});
}
function handle_command(m : cmd_msg) { if
:: m.cmd == on -> handle_on(m.seq_no, m.reply_c);
:: ...
fi }
function run() { var m : cmd_msg;
var len : int = 0;
do
:: true ->
len = length(cmds);
if
:: len == 0 && state == 0 -> poll_sensors_and_update();
:: else -> sel
:: recv(cmds,m) -> handle_command(m);
:: timeout -> assert false;
les fi
:: else -> assert false;
od } } }
Figure 5.12: the AAL implementation of the climate controller
module MasterCtrl {
export MasterCtrlInterf;
import ic = IntLightCtrlInterf;
... // type and constant definitions from the interface
const usr_cmds : chan[usr_cmd_msg] = mkchan of usr_cmd_msg[1];
active process master() { var mode : int = at_home_day;
var from_ic : chan[ic.cmd_reply] = mkchan of ic.cmd_reply[1];
...
function operate_int_light(seq_no : int, op:int) { var m : ic.cmd_reply;
send(ic.cmds, {seq_no = seq_no, cmd = op, reply_c = from_ic});
recv(from_ic, m);
}
function handle_at_home_day(seq_no : int, reply_c : chan[usr_cmd_reply]) { var t : int;
printf("mc: handling at_home_day, seq_no = %d\n", seq_no);
mode = at_home_day;
operate_int_light(seq_no, ic.on);
... // interact with the other appliance controllers
send(reply_c, {seq_no = seq_no, status = success, value = 0});
}
function handle_usr_msg(m : usr_cmd_msg) { if
:: m.cmd == at_home_day -> handle_at_home_day(m.seq_no, m.reply_c);
:: ...
fi }
function run() { var m : usr_cmd_msg;
do
:: true ->
sel
:: recv(usr_cmds,m) -> handle_usr_msg(m);
:: timeout -> assert false;
les
:: else -> assert false;
od } } }
Figure 5.13: the AAL implementation of the master controller
the sensors it uses. Our first attempts at testing the climate controller revealed a problem with the specification of the temperature sensor. The generated stub module was sending more messages
than it was supposed to as replies to a poll request.
We were using the common LTL formula:
ltl poll_sensor(rc): [](poll(rc) => X(<>value(rc,v)));
To inspect the problem we looked at the automaton generated for this formula (Figure 5.14).
We saw that the automaton was not quite what we expected.
T0_init poll
accept_S1 valuepoll
value
Figure 5.14: the Büchi automaton generated for the initial poll_sensor LTL formula
The automaton shows that the sequence of messages can start with a reply which should not be allowed as no poll request was made. To fix this problem we added the constraint that there should not be avalue before apoll at the beginning of the execution. This is formalized in LTL as: ((!value(rc)) U poll(rc)). The change did not completely fixed our problem.
T0_init
T0_S3 poll
poll
accept_S3 valuepoll
value
Figure 5.15: the Büchi automaton generated for the poll_sensor LTL formula after removing the possibility of initial value messages
The new automaton (Figure 5.15) looks closer to what we expected, but it allows any number of contiguous poll requests to be answered by any number of contiguous value replies. This does not correspond to what we want: a single poll request followed by a single value reply.
To remove the possibility of multiple contiguous poll requests we have imposed the restriction that a poll request is immediately followed by a value reply. To remove the possibility of multiple value replies to the same poll request we have imposed the restriction that after we send a value reply, no more values are sent until a poll message is received.
The new LTL formula is the one presented in the Specifications section:
ltl poll_sensor(rc) : ((!value(rc)) U poll(rc))
&& [](poll(rc) => X(value(rc)))
&& [](value(rc) => X((!value(rc)) U poll(rc)));
T0_init
accept_S3 pollvalue
Figure 5.16: the Büchi automaton generated for the poll_sensor LTL formula
The automata generated (Figure 5.16) corresponds exactly to the desired behavior of a sensor.
Chapter 6
Conclusions and Future Directions
In this chapter we present a summary of the thesis and hint at how our work could be further extended in the future.