blob: 545b091b4748a538da305863debe775637be9ba2 [file] [log] [blame]
MODULE main
VAR
CN : Controller_Synth(SC.mode_event_Gs, SC.mode_event_CBs, SC.init_state_Gs, SC.init_state_CBs);
SC: System_Configuration(CN.cmd_to_Gs, CN.cmd_to_CBs);
-- -----------------------------------------------------------
-- Definition of the properties that verify the requirements:
-- R1: No bus will be connected to more than 1 power source at any time.
--
-- is_broken is true iff the bus is (or was) connected to more than 1
-- power source.
INVARSPEC NAME R1_true := !(SC.B1.is_broken | SC.B2.is_broken | SC.B3.is_broken);
-- R2: If any power source is on, then all busses will be powered
--
-- In R2 we verify that the requirement holds, if there are less than 3 faults
INVARSPEC
NAME R2_true :=
((SC.G1.is_on | SC.G2.is_on | SC.G3.is_on) & (CN.MN.faults_counter < 3)) ->
(SC.B1.is_powered & SC.B2.is_powered & SC.B3.is_powered);
-- In R2 we verify that there is at least a configuration in which all the
-- buses are unpowered. (E.g., the safe configuration where everything is
-- off)
INVARSPEC
NAME R2_false :=
((SC.G1.is_on | SC.G2.is_on | SC.G3.is_on)) ->
(SC.B1.is_powered & SC.B2.is_powered & SC.B3.is_powered);
INVARSPEC NAME R2_fta := (SC.B1.is_powered & SC.B2.is_powered & SC.B3.is_powered);
INVARSPEC NAME R2_fta_B1 := (SC.B1.is_powered);
INVARSPEC NAME R2_fta_B2 := (SC.B2.is_powered);
INVARSPEC NAME R2_fta_B3 := (SC.B3.is_powered);
-- R4: If no power source is on, then all buses will be unpowered
INVARSPEC
NAME R4_true :=
((SC.G1.is_off & SC.G2.is_off & SC.G3.is_off) ->
(!SC.B1.is_powered & !SC.B2.is_powered & !SC.B3.is_powered));
-- R6: Never more than two generators on unless required in case of failure
INVARSPEC
NAME R6_true :=
(CN.MN.faults_counter = 0) -> (SC.G1.is_off | SC.G2.is_off | SC.G3.is_off)
-- ---------------------------------------------------------------------
-- ----------------------------------------------------------
-- We verify that the monitor correctly knows the state of
-- the system at anytime
INVARSPEC NAME Monitor_State_Consistency_true :=
(SC.G1.state = CN.MN.state_est_G1) &
(SC.G2.state = CN.MN.state_est_G2) &
(SC.G3.state = CN.MN.state_est_G3) &
(SC.GB1.state = CN.MN.state_est_GB1) &
(SC.GB2.state = CN.MN.state_est_GB2) &
(SC.GB3.state = CN.MN.state_est_GB3) &
(SC.BB1.state = CN.MN.state_est_BB1) &
(SC.BB2.state = CN.MN.state_est_BB2) &
(SC.BB3.state = CN.MN.state_est_BB3);
-- -------------------------------------------------------------------------
-- From each nominal state it is always possible to end up in a faulty state
CTLSPEC
NAME system_can_always_fail_true :=
AG( CN.MN.faults_counter = 0 -> EX (CN.MN.faults_counter >0))
-- We also verify that there is always a path in which there is no fault
CTLSPEC
NAME system_can_always_work_true :=
EG (CN.MN.faults_counter = 0);
-- -------------------------------------------------------------------------
-- -------------------------------------------------------------------
-- We can verify that each component can always go from a nominal state
-- to a faulty state:
-- Generators can always go to a faulty state
CTLSPEC
NAME G1_can_always_fail_true :=
AG( CN.MN.mode_est_G1 = ok -> EX (CN.MN.mode_est_G1 = ko))
CTLSPEC
NAME G2_can_always_fail_true :=
AG( CN.MN.mode_est_G2 = ok -> EX (CN.MN.mode_est_G2 = ko))
CTLSPEC
NAME G3_can_always_fail_true :=
AG( CN.MN.mode_est_G3 = ok -> EX (CN.MN.mode_est_G3 = ko))
-- and also switches can always become stuck_at_open or stuck_at_close
-- GB1, GB2, GB3:
CTLSPEC
NAME GB1_can_always_fail_true :=
AG( CN.MN.mode_est_GB1 = ok ->
EX (CN.MN.mode_est_GB1 = ko_open) &
EX (CN.MN.mode_est_GB1 = ko_closed) )
CTLSPEC
NAME GB2_can_always_fail_true :=
AG( CN.MN.mode_est_GB2 = ok ->
EX (CN.MN.mode_est_GB2 = ko_open) &
EX (CN.MN.mode_est_GB2 = ko_closed) )
CTLSPEC
NAME GB3_can_always_fail_true :=
AG( CN.MN.mode_est_GB3 = ok ->
EX (CN.MN.mode_est_GB3 = ko_open) &
EX (CN.MN.mode_est_GB3 = ko_closed) )
-- BB1, BB2, BB3:
CTLSPEC
NAME BB1_can_always_fail_true :=
AG( CN.MN.mode_est_BB1 = ok ->
EX (CN.MN.mode_est_BB1 = ko_open) &
EX (CN.MN.mode_est_BB1 = ko_closed) )
CTLSPEC
NAME BB2_can_always_fail_true :=
AG( CN.MN.mode_est_BB2 = ok ->
EX (CN.MN.mode_est_BB2 = ko_open) &
EX (CN.MN.mode_est_BB2 = ko_closed) )
CTLSPEC
NAME BB3_can_always_fail_true :=
AG( CN.MN.mode_est_BB3 = ok ->
EX (CN.MN.mode_est_BB3 = ko_open) &
EX (CN.MN.mode_est_BB3 = ko_closed) )
-- ---------------------------------------------------------------
-- ---------------------------------------------------------------
-- If there are no faults, the system is in the base configuration
DEFINE
base_conf := SC.G1.is_on & SC.G2.is_on & SC.G3.is_off &
SC.GB1.is_closed & SC.GB2.is_closed & SC.GB3.is_open &
SC.BB1.is_open & SC.BB2.is_closed & SC.BB3.is_open;
LTLSPEC
NAME system_in_base_configuration_until_fault_true :=
( base_conf U (CN.MN.faults_counter > 0)) | G base_conf;
-- ---------------------------------------------------------------
-- END MODULE MAIN --
MODULE System_Configuration(cmd_to_Gs, cmd_to_CBs)
DEFINE
init_state_G1 := on;
init_state_G2 := on;
init_state_G3 := off;
init_state_GB1 := closed;
init_state_GB2 := closed;
init_state_GB3 := open;
init_state_BB1 := open;
init_state_BB2 := closed;
init_state_BB3 := open;
VAR
G1 : Generator(cmd_to_Gs[index_G1], init_state_G1);
G2 : Generator(cmd_to_Gs[index_G2], init_state_G2);
G3 : Generator(cmd_to_Gs[index_G3], init_state_G3);
GB1 : Switch(cmd_to_CBs[index_GB1], init_state_GB1);
GB2 : Switch(cmd_to_CBs[index_GB2], init_state_GB2);
GB3 : Switch(cmd_to_CBs[index_GB3], init_state_GB3);
BB1 : Switch(cmd_to_CBs[index_BB1], init_state_BB1);
BB2 : Switch(cmd_to_CBs[index_BB2], init_state_BB2);
BB3 : Switch(cmd_to_CBs[index_BB3], init_state_BB3);
B1 : Bus(B1_poweredby_G1, B1_poweredby_G2, B1_poweredby_G3);
B2 : Bus(B2_poweredby_G1, B2_poweredby_G2, B2_poweredby_G3);
B3 : Bus(B3_poweredby_G1, B3_poweredby_G2, B3_poweredby_G3);
-- Definition of the signals (in matrix format) used by Controller to know the state of the single components --
DEFINE
init_state_Gs := [
init_state_G1,
init_state_G2,
init_state_G3];
init_state_CBs := [
init_state_GB1,
init_state_GB2,
init_state_GB3,
init_state_BB1,
init_state_BB2,
init_state_BB3];
DEFINE
index_GB1 := 0;
index_GB2 := 1;
index_GB3 := 2;
index_BB1 := 3;
index_BB2 := 4;
index_BB3 := 5;
index_G1 := 0;
index_G2 := 1;
index_G3 := 2;
DEFINE
mode_event_Gs := [
fault_event_off_Gs,
nominal_event_Gs];
mode_event_CBs := [
fault_event_open_CBs,
fault_event_closed_CBs,
nominal_event_CBs];
DEFINE
fault_event_open_CBs := [
GB1.fault_event_stuck_at_open,
GB2.fault_event_stuck_at_open,
GB3.fault_event_stuck_at_open,
BB1.fault_event_stuck_at_open,
BB2.fault_event_stuck_at_open,
BB3.fault_event_stuck_at_open];
fault_event_closed_CBs := [
GB1.fault_event_stuck_at_closed,
GB2.fault_event_stuck_at_closed,
GB3.fault_event_stuck_at_closed,
BB1.fault_event_stuck_at_closed,
BB2.fault_event_stuck_at_closed,
BB3.fault_event_stuck_at_closed];
nominal_event_CBs := [
GB1.nominal_event,
GB2.nominal_event,
GB3.nominal_event,
BB1.nominal_event,
BB2.nominal_event,
BB3.nominal_event];
DEFINE
fault_event_off_Gs := [
G1.fault_event_stuck_at_off,
G2.fault_event_stuck_at_off,
G3.fault_event_stuck_at_off];
nominal_event_Gs := [
G1.nominal_event,
G2.nominal_event,
G3.nominal_event];
-- Definition of the possible paths to Bus 1 --
DEFINE
B1_poweredby_G1_U := (G1.is_on) & (GB1.is_closed);
B1_poweredby_G2_L := B3_poweredby_G2_L & (BB3.is_closed);
B1_poweredby_G2_R := B2_poweredby_G2_U & (BB1.is_closed);
B1_poweredby_G3_L := B3_poweredby_G3_U & (BB3.is_closed);
B1_poweredby_G3_R := B2_poweredby_G3_R & (BB1.is_closed);
-- Definition of the possible paths to Bus 2 --
DEFINE
B2_poweredby_G1_L := B1_poweredby_G1_U & (BB1.is_closed);
B2_poweredby_G1_R := B3_poweredby_G1_R & (BB2.is_closed);
B2_poweredby_G2_U := (G2.is_on) & (GB2.is_closed);
B2_poweredby_G3_L := B1_poweredby_G3_L & (BB1.is_closed);
B2_poweredby_G3_R := B3_poweredby_G3_U & (BB2.is_closed);
-- Definition of the possible paths to Bus 3 --
DEFINE
B3_poweredby_G1_L := B2_poweredby_G1_L & (BB2.is_closed);
B3_poweredby_G1_R := B1_poweredby_G1_U & (BB3.is_closed);
B3_poweredby_G2_L := B2_poweredby_G2_U & (BB2.is_closed);
B3_poweredby_G2_R := B1_poweredby_G2_R & (BB3.is_closed);
B3_poweredby_G3_U := (G3.is_on) & (GB3.is_closed);
-- Definition of the possible inputs for Bus 1 --
DEFINE
B1_poweredby_G1 := B1_poweredby_G1_U;
B1_poweredby_G2 := B1_poweredby_G2_R | B1_poweredby_G2_L;
B1_poweredby_G3 := B1_poweredby_G3_R | B1_poweredby_G3_L;
-- Definition of the possible inputs for Bus 2 --
DEFINE
B2_poweredby_G1 := B2_poweredby_G1_R | B2_poweredby_G1_L;
B2_poweredby_G2 := B2_poweredby_G2_U;
B2_poweredby_G3 := B2_poweredby_G3_R | B2_poweredby_G3_L;
-- Definition of the possible inputs for Bus 3 --
DEFINE
B3_poweredby_G1 := B3_poweredby_G1_R | B3_poweredby_G1_L;
B3_poweredby_G2 := B3_poweredby_G2_R | B3_poweredby_G2_L;
B3_poweredby_G3 := B3_poweredby_G3_U;
-- END MODULE SYSTEM CONFIGURATION --
MODULE Generator(cmd, init_state)
VAR
state : {on, off};
-- Definition of the transition labels between nominal and faulty state --
IVAR
fault_event_stuck_at_off : boolean;
nominal_event : boolean;
TRANS
nominal_event = FALSE;
DEFINE
is_on := (state = on);
DEFINE
is_off := (state = off);
ASSIGN
next(state) :=
case
(cmd = cmd_on) : on;
(cmd = cmd_off) : off;
TRUE : state;
esac;
ASSIGN
init(state) := init_state;
-- END MODULE GENERATOR --
MODULE Switch(cmd, init_state)
VAR
state : {open, closed};
-- Definition of the transition labels between nominal and faulty states --
IVAR
fault_event_stuck_at_closed : boolean;
fault_event_stuck_at_open : boolean;
nominal_event : boolean;
DEFINE
is_closed := (state = closed);
DEFINE
is_open := (state = open);
ASSIGN
next(state) :=
case
(cmd = cmd_open) : open;
(cmd = cmd_closed) : closed;
TRUE : state;
esac;
ASSIGN
init(state) := init_state;
-- END MODULE SWITCH --
MODULE Bus(in1, in2, in3)
VAR
state : {working, broken};
DEFINE
is_broken := (state = broken);
DEFINE
is_powered := (state = working) & (count((in1), (in2), (in3)) = 1);
-- When the bus is overpowered it becomes broken and unfixable --
ASSIGN
init(state) :=
case
(count((in1), (in2), (in3)) > 1) : broken;
TRUE : working;
esac;
next(state) :=
case
next((count((in1), (in2), (in3)) > 1)) : broken;
TRUE : state;
esac;
-- END MODULE BUS --
-- The Synthesized controller is built by defining the constraints that
-- we want our system to satisfy. When a fault occurs, the controller
-- will try to find a configuration for the system that satisfies all
-- the requirements.
-- As opposed to the Explicit Faults controller, this strategy results
-- in a much simpler (and compact) controller.
--
-- In order to work, the Synthesized controller uses a Monitor. The
-- Monitor has two goals:
-- 1. keep track of the modes of each component
-- 2. predict the behaviour of a command
-- With these information, the controller can reason on what would
-- happen if he issues a certain command. E.g., if G1 is faulty
-- (stuck_at_off) then the controller can issue the command do_on
-- but this will have no effect since the generator is faulty.
-- The monitor will, therefore, estimate that this command will
-- not be useful and say that the component will stay
-- The module takes as parameter the mode events and the initial states
-- of the components. The mode events are the signals that denote a
-- transition from healthy to faulty (or viceversa).
MODULE Controller_Synth(mode_event_Gs, mode_event_CBs, init_state_Gs, init_state_CBs)
-- The controller uses a Monitor. This monitor takes as parameter
-- the mode signals (mode_event_*) the command signals (cmd_to_*)
-- and the initial configuration of each component (init_state_*)
VAR
MN : Monitor(mode_event_Gs, mode_event_CBs, cmd_to_Gs, cmd_to_CBs, init_state_Gs, init_state_CBs);
-- We define the possible commands for each component.
-- Apart from the commands to bring the system into
-- a particular state, we have also the nop command.
-- This command is useful if we know that a component
-- is already in a particular state and we do not want
-- to modify it.
IVAR
cmd_to_GB1 : {cmd_closed, cmd_open, nop};
cmd_to_GB2 : {cmd_closed, cmd_open, nop};
cmd_to_GB3 : {cmd_closed, cmd_open, nop};
cmd_to_BB1 : {cmd_closed, cmd_open, nop};
cmd_to_BB2 : {cmd_closed, cmd_open, nop};
cmd_to_BB3 : {cmd_closed, cmd_open, nop};
cmd_to_G1 : {cmd_on, cmd_off, nop};
cmd_to_G2 : {cmd_on, cmd_off, nop};
cmd_to_G3 : {cmd_on, cmd_off, nop};
-- We now group the commands by component's type:
-- cmd_to_Gs and cmd_to_CBs
DEFINE
cmd_to_Gs := [
cmd_to_G1,
cmd_to_G2,
cmd_to_G3];
cmd_to_CBs := [
cmd_to_GB1,
cmd_to_GB2,
cmd_to_GB3,
cmd_to_BB1,
cmd_to_BB2,
cmd_to_BB3];
-- In general, there are two ways of disable the block
-- G1+GB1: 1) turn off G1 or 2) open GB1 (or both).
-- To avoid this non-determinism we add the following
-- assumption: When GBn is open the Gn must be off.
TRANS
(next(MN.state_est_GB1) = open) -> (cmd_to_G1 = cmd_off);
TRANS
(next(MN.state_est_GB2) = open) -> (cmd_to_G2 = cmd_off);
TRANS
(next(MN.state_est_GB3) = open) -> (cmd_to_G3 = cmd_off);
-- Similarly to what we did in the System model, we need
-- to keep track of the information of which Bus is powered
-- by which generator and how.
-- Note, however, that in this case we are not interested in
-- the current state of the system, but in the future state
-- (i.e., next( ) ).
-- This means that, e.g., B1_poweredby_G1_U should be read
-- as follows: the bus B1 will be powered by G1 from above.
-- Remember that Up,Left and Right indicate where the power
-- comes from from the point of view of the Bus. E.g.,
-- B1_poweredby_G2_L identify the path BB2+BB3 from G2 to B1
-- Definition of the possible paths to Bus 1 --
DEFINE
B1_poweredby_G1_U := (next(MN.state_est_G1) = on) & (next(MN.state_est_GB1) = closed);
B1_poweredby_G2_L := B3_poweredby_G2_L & (next(MN.state_est_BB3) = closed);
B1_poweredby_G2_R := B2_poweredby_G2_U & (next(MN.state_est_BB1) = closed);
B1_poweredby_G3_L := B3_poweredby_G3_U & (next(MN.state_est_BB3) = closed);
B1_poweredby_G3_R := B2_poweredby_G3_R & (next(MN.state_est_BB1) = closed);
-- Definition of the possible paths to Bus 2 --
DEFINE
B2_poweredby_G1_L := B1_poweredby_G1_U & (next(MN.state_est_BB1) = closed);
B2_poweredby_G1_R := B3_poweredby_G1_R & (next(MN.state_est_BB2) = closed);
B2_poweredby_G2_U := (next(MN.state_est_G2) = on) & (next(MN.state_est_GB2) = closed);
B2_poweredby_G3_L := B1_poweredby_G3_L & (next(MN.state_est_BB1) = closed);
B2_poweredby_G3_R := B3_poweredby_G3_U & (next(MN.state_est_BB2) = closed);
-- Definition of the possible paths to Bus 3 --
DEFINE
B3_poweredby_G1_L := B2_poweredby_G1_L & (next(MN.state_est_BB2) = closed);
B3_poweredby_G1_R := B1_poweredby_G1_U & (next(MN.state_est_BB3) = closed);
B3_poweredby_G2_L := B2_poweredby_G2_U & (next(MN.state_est_BB2) = closed);
B3_poweredby_G2_R := B1_poweredby_G2_R & (next(MN.state_est_BB3) = closed);
B3_poweredby_G3_U := (next(MN.state_est_G3) = on) & (next(MN.state_est_GB3) = closed);
-- We now abstract from the particular path used to power
-- the bus, and simply say which generator will power
-- the bus.
DEFINE
B1_poweredby_G1 := B1_poweredby_G1_U;
B1_poweredby_G2 := B1_poweredby_G2_R | B1_poweredby_G2_L;
B1_poweredby_G3 := B1_poweredby_G3_R | B1_poweredby_G3_L;
DEFINE
B2_poweredby_G1 := B2_poweredby_G1_R | B2_poweredby_G1_L;
B2_poweredby_G2 := B2_poweredby_G2_U;
B2_poweredby_G3 := B2_poweredby_G3_R | B2_poweredby_G3_L;
DEFINE
B3_poweredby_G1 := B3_poweredby_G1_R | B3_poweredby_G1_L;
B3_poweredby_G2 := B3_poweredby_G2_R | B3_poweredby_G2_L;
B3_poweredby_G3 := B3_poweredby_G3_U;
-- We can now encode the logic of the controller.
-- In order to do so, we define the constraints that represent
-- our requirements.
-- Requirement R1 --
-- R1: No bus will be connected to more than 1 power source at any time.
--
-- This requirement is formalized in two steps:
-- 1. We explicit that a Bus is working if and only if
-- it is not powered by more than two generators
-- 2. We force all the Buses to be working.
DEFINE
B1_is_working :=
(B1_poweredby_G1 -> !B1_poweredby_G2) &
(B1_poweredby_G2 -> !B1_poweredby_G3) &
(B1_poweredby_G3 -> !B1_poweredby_G1);
DEFINE
B2_is_working :=
(B2_poweredby_G1 -> !B2_poweredby_G2) &
(B2_poweredby_G2 -> !B2_poweredby_G3) &
(B2_poweredby_G3 -> !B2_poweredby_G1);
DEFINE
B3_is_working :=
(B3_poweredby_G1 -> !B3_poweredby_G2) &
(B3_poweredby_G2 -> !B3_poweredby_G3) &
(B3_poweredby_G3 -> !B3_poweredby_G1);
-- This TRANS forces all the buses to be working.
TRANS
B1_is_working &
B2_is_working &
B3_is_working;
-- In order to encode R3, we need to define the commands
-- that will bring our system into a configuration
-- in which a bus will be powered by a particular generator
-- through a particular path.
-- E.g., cmd_B1_poweredby_G1_U is the command that requires
-- G1 to go in the state on and GB1 in the state closed.
DEFINE
cmd_B1_poweredby_G1_U := (cmd_to_G1 = cmd_on) & (cmd_to_GB1 = cmd_closed);
cmd_B1_poweredby_G2_R := cmd_B2_poweredby_G2_U & (cmd_to_BB1 = cmd_closed);
cmd_B1_poweredby_G2_L := cmd_B3_poweredby_G2_L & (cmd_to_BB3 = cmd_closed);
cmd_B1_poweredby_G3_L := cmd_B3_poweredby_G3_U & (cmd_to_BB3 = cmd_closed);
cmd_B1_poweredby_G3_R := cmd_B2_poweredby_G3_R & (cmd_to_BB1 = cmd_closed);
DEFINE
cmd_B2_poweredby_G2_U := (cmd_to_G2 = cmd_on) & (cmd_to_GB2 = cmd_closed);
cmd_B2_poweredby_G1_L := cmd_B1_poweredby_G1_U & (cmd_to_BB1 = cmd_closed);
cmd_B2_poweredby_G1_R := cmd_B3_poweredby_G1_R & (cmd_to_BB2 = cmd_closed);
cmd_B2_poweredby_G3_R := cmd_B3_poweredby_G3_U & (cmd_to_BB2 = cmd_closed);
cmd_B2_poweredby_G3_L := cmd_B1_poweredby_G3_L & (cmd_to_BB1 = cmd_closed);
DEFINE
cmd_B3_poweredby_G2_L := cmd_B2_poweredby_G2_U & (cmd_to_BB2 = cmd_closed);
cmd_B3_poweredby_G2_R := cmd_B1_poweredby_G2_R & (cmd_to_BB3 = cmd_closed);
cmd_B3_poweredby_G1_R := cmd_B1_poweredby_G1_U & (cmd_to_BB3 = cmd_closed);
cmd_B3_poweredby_G1_L := cmd_B2_poweredby_G1_L & (cmd_to_BB2 = cmd_closed);
cmd_B3_poweredby_G3_U := (cmd_to_G3 = cmd_on) & (cmd_to_GB3 = cmd_closed);
-- Since there could be faults in the system, we need to check whether it is
-- possible to go into a particular configuration. For example, if a
-- switch is stuck_at_open, we cannot go into a configuration that requires
-- the switch to be closed. We identify with these can_do_* DEFINEs.
DEFINE
can_do_B1_poweredby_G1_U := (next(MN.mode_est_G1) = ok) & (next(MN.mode_est_GB1) in {ok, ko_closed});
can_do_B1_poweredby_G2_R := can_do_B2_poweredby_G2_U & (next(MN.mode_est_BB1) in {ok, ko_closed});
can_do_B1_poweredby_G2_L := can_do_B3_poweredby_G2_L & (next(MN.mode_est_BB3) in {ok, ko_closed});
can_do_B1_poweredby_G3_L := can_do_B3_poweredby_G3_U & (next(MN.mode_est_BB3) in {ok, ko_closed});
can_do_B1_poweredby_G3_R := can_do_B2_poweredby_G3_R & (next(MN.mode_est_BB1) in {ok, ko_closed});
DEFINE
can_do_B2_poweredby_G2_U := (next(MN.mode_est_G2) = ok) & (next(MN.mode_est_GB2) in {ok, ko_closed});
can_do_B2_poweredby_G1_L := can_do_B1_poweredby_G1_U & (next(MN.mode_est_BB1) in {ok, ko_closed});
can_do_B2_poweredby_G1_R := can_do_B3_poweredby_G1_R & (next(MN.mode_est_BB2) in {ok, ko_closed});
can_do_B2_poweredby_G3_R := can_do_B3_poweredby_G3_U & (next(MN.mode_est_BB2) in {ok, ko_closed});
can_do_B2_poweredby_G3_L := can_do_B1_poweredby_G3_L & (next(MN.mode_est_BB1) in {ok, ko_closed});
DEFINE
can_do_B3_poweredby_G2_L := can_do_B2_poweredby_G2_U & (next(MN.mode_est_BB2) in {ok, ko_closed});
can_do_B3_poweredby_G2_R := can_do_B1_poweredby_G2_R & (next(MN.mode_est_BB3) in {ok, ko_closed});
can_do_B3_poweredby_G1_R := can_do_B1_poweredby_G1_U & (next(MN.mode_est_BB3) in {ok, ko_closed});
can_do_B3_poweredby_G1_L := can_do_B2_poweredby_G1_L & (next(MN.mode_est_BB2) in {ok, ko_closed});
can_do_B3_poweredby_G3_U := (next(MN.mode_est_G3) = ok) & (next(MN.mode_est_GB3) in {ok, ko_closed});
-- Requirement R3 --
-- R3: Path and Generator priority
--
-- R3 is formalized by specifying the priority of the
-- different configurations. In particular, we use a
-- case statement in order to prioritize the choices
-- for each bus.
-- E.g., for B1 we specify that the best configuration
-- is being powered by G1 from above (G1_U),
-- followed by being powered by G2 from the right
-- (G2_R) etc.
-- B1 preferences
TRANS
case
can_do_B1_poweredby_G1_U : cmd_B1_poweredby_G1_U;
can_do_B1_poweredby_G2_R : cmd_B1_poweredby_G2_R;
can_do_B1_poweredby_G2_L : cmd_B1_poweredby_G2_L;
can_do_B1_poweredby_G3_L : cmd_B1_poweredby_G3_L;
can_do_B1_poweredby_G3_R : cmd_B1_poweredby_G3_R;
TRUE : TRUE;
esac;
-- B2 preferences
TRANS
case
can_do_B2_poweredby_G2_U : cmd_B2_poweredby_G2_U;
can_do_B2_poweredby_G1_L : cmd_B2_poweredby_G1_L;
can_do_B2_poweredby_G1_R : cmd_B2_poweredby_G1_R;
can_do_B2_poweredby_G3_R : cmd_B2_poweredby_G3_R;
can_do_B2_poweredby_G3_L : cmd_B2_poweredby_G3_L;
TRUE : TRUE;
esac;
-- B3 preferences
TRANS
case
can_do_B3_poweredby_G2_L : cmd_B3_poweredby_G2_L;
can_do_B3_poweredby_G2_R : cmd_B3_poweredby_G2_R;
can_do_B3_poweredby_G1_R : cmd_B3_poweredby_G1_R;
can_do_B3_poweredby_G1_L : cmd_B3_poweredby_G1_L;
can_do_B3_poweredby_G3_U : cmd_B3_poweredby_G3_U;
TRUE : TRUE;
esac;
-- END MODULE CONTROLLER --
MODULE Monitor(mode_event_Gs, mode_event_CBs, cmd_to_Gs, cmd_to_CBs, init_state_Gs, init_state_CBs)
-- Definition of the monitors for the circuit components --
VAR
mode_est_GB1 : {ok, ko_open, ko_closed};
mode_est_GB2 : {ok, ko_open, ko_closed};
mode_est_GB3 : {ok, ko_open, ko_closed};
mode_est_BB1 : {ok, ko_open, ko_closed};
mode_est_BB2 : {ok, ko_open, ko_closed};
mode_est_BB3 : {ok, ko_open, ko_closed};
mode_est_G1 : {ok, ko};
mode_est_G2 : {ok, ko};
mode_est_G3 : {ok, ko};
VAR
state_est_G1 : {on, off};
state_est_G2 : {on, off};
state_est_G3 : {on, off};
state_est_GB1 : {closed, open};
state_est_GB2 : {closed, open};
state_est_GB3 : {closed, open};
state_est_BB1 : {closed, open};
state_est_BB2 : {closed, open};
state_est_BB3 : {closed, open};
DEFINE
faults_counter := count(
(mode_est_GB1 != ok),
(mode_est_GB2 != ok),
(mode_est_GB3 != ok),
(mode_est_BB1 != ok),
(mode_est_BB2 != ok),
(mode_est_BB3 != ok),
(mode_est_G1 != ok),
(mode_est_G2 != ok),
(mode_est_G3 != ok));
-- Definition of the components signals used to monitor their funtionality --
DEFINE
fault_event_open_CBs := mode_event_CBs[0];
fault_event_closed_CBs := mode_event_CBs[1];
nominal_event_CBs := mode_event_CBs[2];
fault_event_off_Gs := mode_event_Gs[0];
nominal_event_Gs := mode_event_Gs[1];
index_GB1 := 0;
index_GB2 := 1;
index_GB3 := 2;
index_BB1 := 3;
index_BB2 := 4;
index_BB3 := 5;
index_G1 := 0;
index_G2 := 1;
index_G3 := 2;
ASSIGN
init(mode_est_GB1) := ok;
next(mode_est_GB1) :=
case
fault_event_open_CBs[index_GB1] : ko_open;
fault_event_closed_CBs[index_GB1] : ko_closed;
nominal_event_CBs[index_GB1] : ok;
TRUE : mode_est_GB1;
esac;
ASSIGN
init(mode_est_GB2) := ok;
next(mode_est_GB2) :=
case
fault_event_open_CBs[index_GB2] : ko_open;
fault_event_closed_CBs[index_GB2] : ko_closed;
nominal_event_CBs[index_GB2] : ok;
TRUE : mode_est_GB2;
esac;
ASSIGN
init(mode_est_GB3) := ok;
next(mode_est_GB3) :=
case
fault_event_open_CBs[index_GB3] : ko_open;
fault_event_closed_CBs[index_GB3] : ko_closed;
nominal_event_CBs[index_GB3] : ok;
TRUE : mode_est_GB3;
esac;
ASSIGN
init(mode_est_BB1) := ok;
next(mode_est_BB1) :=
case
fault_event_open_CBs[index_BB1] : ko_open;
fault_event_closed_CBs[index_BB1] : ko_closed;
nominal_event_CBs[index_BB1] : ok;
TRUE : mode_est_BB1;
esac;
ASSIGN
init(mode_est_BB2) := ok;
next(mode_est_BB2) :=
case
fault_event_open_CBs[index_BB2] : ko_open;
fault_event_closed_CBs[index_BB2] : ko_closed;
nominal_event_CBs[index_BB2] : ok;
TRUE : mode_est_BB2;
esac;
init(mode_est_BB3) := ok;
next(mode_est_BB3) :=
case
fault_event_open_CBs[index_BB3] : ko_open;
fault_event_closed_CBs[index_BB3] : ko_closed;
nominal_event_CBs[index_BB3] : ok;
TRUE : mode_est_BB3;
esac;
ASSIGN
init(mode_est_G1) := ok;
next(mode_est_G1) :=
case
fault_event_off_Gs[index_G1] : ko;
nominal_event_Gs[index_G1] : ok;
TRUE : mode_est_G1;
esac;
ASSIGN
init(mode_est_G2) := ok;
next(mode_est_G2) :=
case
fault_event_off_Gs[index_G2] : ko;
nominal_event_Gs[index_G2] : ok;
TRUE : mode_est_G2;
esac;
ASSIGN
init(mode_est_G3) := ok;
next(mode_est_G3) :=
case
fault_event_off_Gs[index_G3] : ko;
nominal_event_Gs[index_G3] : ok;
TRUE : mode_est_G3;
esac;
ASSIGN
init(state_est_G1) := init_state_Gs[index_G1];
next(state_est_G1) :=
case
fault_event_off_Gs[index_G1] : off;
(next(mode_est_G1) = ok) & (cmd_to_Gs[index_G1] = cmd_on) : on;
(next(mode_est_G1) = ok) & (cmd_to_Gs[index_G1] = cmd_off) : off;
TRUE : state_est_G1;
esac;
ASSIGN
init(state_est_G2) := init_state_Gs[index_G2];
next(state_est_G2) :=
case
fault_event_off_Gs[index_G2] : off;
(next(mode_est_G2) = ok) & (cmd_to_Gs[index_G2] = cmd_on) : on;
(next(mode_est_G2) = ok) & (cmd_to_Gs[index_G2] = cmd_off) : off;
TRUE : state_est_G2;
esac;
ASSIGN
init(state_est_G3) := init_state_Gs[index_G3];
next(state_est_G3) :=
case
fault_event_off_Gs[index_G3] : off;
(next(mode_est_G3) = ok) & (cmd_to_Gs[index_G3] = cmd_on) : on;
(next(mode_est_G3) = ok) & (cmd_to_Gs[index_G3] = cmd_off) : off;
TRUE : state_est_G3;
esac;
ASSIGN
init(state_est_GB1) := init_state_CBs[index_GB1];
next(state_est_GB1) :=
case
fault_event_open_CBs[index_GB1] : open;
fault_event_closed_CBs[index_GB1] : closed;
(next(mode_est_GB1) = ok) & (cmd_to_CBs[index_GB1] = cmd_open) : open;
(next(mode_est_GB1) = ok) & (cmd_to_CBs[index_GB1] = cmd_closed) : closed;
TRUE : state_est_GB1;
esac;
ASSIGN
init(state_est_GB2) := init_state_CBs[index_GB2];
next(state_est_GB2) :=
case
fault_event_open_CBs[index_GB2] : open;
fault_event_closed_CBs[index_GB2] : closed;
(next(mode_est_GB2) = ok) & (cmd_to_CBs[index_GB2] = cmd_open) : open;
(next(mode_est_GB2) = ok) & (cmd_to_CBs[index_GB2] = cmd_closed) : closed;
TRUE : state_est_GB2;
esac;
ASSIGN
init(state_est_GB3) := init_state_CBs[index_GB3];
next(state_est_GB3) :=
case
fault_event_open_CBs[index_GB3] : open;
fault_event_closed_CBs[index_GB3] : closed;
(next(mode_est_GB3) = ok) & (cmd_to_CBs[index_GB3] = cmd_open) : open;
(next(mode_est_GB3) = ok) & (cmd_to_CBs[index_GB3] = cmd_closed) : closed;
TRUE : state_est_GB3;
esac;
ASSIGN
init(state_est_BB1) := init_state_CBs[index_BB1];
next(state_est_BB1) :=
case
fault_event_open_CBs[index_BB1] : open;
fault_event_closed_CBs[index_BB1] : closed;
(next(mode_est_BB1) = ok) & (cmd_to_CBs[index_BB1] = cmd_open) : open;
(next(mode_est_BB1) = ok) & (cmd_to_CBs[index_BB1] = cmd_closed) : closed;
TRUE : state_est_BB1;
esac;
ASSIGN
init(state_est_BB2) := init_state_CBs[index_BB2];
next(state_est_BB2) :=
case
fault_event_open_CBs[index_BB2] : open;
fault_event_closed_CBs[index_BB2] : closed;
(next(mode_est_BB2) = ok) & (cmd_to_CBs[index_BB2] = cmd_open) : open;
(next(mode_est_BB2) = ok) & (cmd_to_CBs[index_BB2] = cmd_closed) : closed;
TRUE : state_est_BB2;
esac;
ASSIGN
init(state_est_BB3) := init_state_CBs[index_BB3];
next(state_est_BB3) :=
case
fault_event_open_CBs[index_BB3] : open;
fault_event_closed_CBs[index_BB3] : closed;
(next(mode_est_BB3) = ok) & (cmd_to_CBs[index_BB3] = cmd_open) : open;
(next(mode_est_BB3) = ok) & (cmd_to_CBs[index_BB3] = cmd_closed) : closed;
TRUE : state_est_BB3;
esac;
-- END MODULE MONITOR --