问题
I need some help according to follow problem which I have to implemented it using jSpin
and promela
language.
A home alarm system can be activated and deactivated using a personal ID key or password, after activation the system enters a waiting period of about 30 seconds, time that allows users to evacuate the secured area after which the alarm is armed, also when an intrusion is detected the alarm has a built in waiting period or delay of 15 seconds to allow the intruder to enter the password or swipe the card key thus identifying himself, in case that the identification is not made within the allocated 15 seconds the alarm will go off and will be on until an id card or password is used to deactivate it.
Here is what I tried:
mtype = {sigact, sigdeact};
chan signal = [0] of {mtype};
chan password = [0] of { int };
/*chan syntax for declaring and initializing message passing channels*/
int count;
bool alarm_off = true; /*The initial state of the alarm is off*/
active proctype alarm()
{
off:
if
:: count >= 30 -> atomic {signal!sigdeact; count = 0;alarm_off = false; goto on;}
:: else -> atomic {count++; alarm_off = true; goto off;}
fi;
on:
if
:: count >=15 -> atomic { signal!sigact; count = 0;
alarm_off = false; goto off;}
:: else -> atomic {signal!sigact; alarm_off = true; goto pending;}
fi;
pending:
if
:: count >= 30 -> atomic {count = 0; alarm_off = false; goto on;}
:: count < 30 -> atomic {count++; alarm_off = false; goto pending;}
fi;
}
active proctype user()
{
password ! 1234 //1234 is the password I sent.
input: atomic { signal?sigact -> alarm_off = true; goto off; }
}
In the user
proctype I send the password
password ! 1234
How can I verify if the password is 1234
and how can I adapt it to own cases ( on
, off
, pending
) based on the verification ?
回答1:
As the code in the example doesn't appear to follow the specification, at least in the way I understand it, I wrote an example from scratch.
Please note that the following model (source code) is purposely very verbose and redundant in its structure, so that its easier to recognise its logic blocks and --hopefully-- understand it. In practice, one would use some inline function to handle input. I also didn't use SIGACT, SIGDEACT
which appeared in the original model, since I could not figure out who was supposed to read those messages neither from the original model (source code) nor from the specification.
#define ALARM_OFF 1
#define ALARM_COUNTDOWN 2
#define ALARM_ARMED 4
#define ALARM_INTRUSION 8
#define ALARM_FIRED 16
#define INPUT_SET_PASSWORD 1
#define INPUT_CHECK_PASSWORD 2
#define INPUT_INTRUDER 4
mtype = { SIGACT, SIGDEACT };
init {
chan alarm_out = [1] of { mtype };
chan alarm_in = [1] of { byte, short };
run alarm(alarm_in, alarm_out);
run user(alarm_in);
run event(alarm_in);
}
proctype alarm(chan input, output)
{
byte count;
byte state = ALARM_OFF;
short passwd = 1234;
short tmp = 0;
off:
if
:: nempty(input) ->
if
:: input?INPUT_SET_PASSWORD(tmp) ->
passwd = tmp;
:: input?INPUT_CHECK_PASSWORD(tmp) ->
if
:: tmp == passwd ->
atomic {
state = ALARM_COUNTDOWN;
count = 0;
goto countdown;
}
:: else ->
skip;
fi;
:: input?INPUT_INTRUDER(tmp) ->
skip;
fi;
:: empty(input) -> skip;
fi;
goto off;
countdown:
if
:: count < 30 ->
if
:: nempty(input) ->
if
:: input?INPUT_SET_PASSWORD(tmp) ->
skip; // error: cannot be done now (?)
:: input?INPUT_CHECK_PASSWORD(tmp) ->
if
:: tmp == passwd ->
atomic {
state = ALARM_OFF;
count = 0;
goto off;
}
:: else ->
skip; // error: incorrect password (?)
fi;
:: input?INPUT_INTRUDER(tmp) ->
skip;
fi;
:: empty(input) ->
skip;
fi;
:: else ->
atomic {
state = ALARM_ARMED;
count = 0;
goto armed;
}
fi;
count++;
goto countdown;
armed:
if
:: nempty(input) ->
if
:: input?INPUT_SET_PASSWORD(tmp) ->
skip; // error: cannot be done now (?)
:: input?INPUT_CHECK_PASSWORD(tmp) ->
if
:: tmp == passwd ->
atomic {
state = ALARM_OFF;
count = 0;
goto off;
}
:: else ->
skip; // error: incorrect password (?)
// maybe it should be handled like
// INPUT_INTRUDER(tmp)
fi;
:: input?INPUT_INTRUDER(tmp) ->
atomic {
state = ALARM_INTRUSION;
count = 0;
goto intruder_detected;
}
fi;
:: empty(input) ->
skip;
fi;
goto armed;
intruder_detected:
if
:: count < 15 ->
if
:: nempty(input) ->
if
:: input?INPUT_SET_PASSWORD(tmp) ->
skip; // error: cannot be done now (?)
:: input?INPUT_CHECK_PASSWORD(tmp);
if
:: tmp == passwd ->
atomic {
state = ALARM_ARMED;
count = 0;
goto armed;
}
:: else ->
skip; // error: incorrect password (?)
fi;
:: input?INPUT_INTRUDER(tmp) ->
skip;
fi;
:: empty(input) ->
skip;
fi;
:: count >= 15 ->
atomic {
state = ALARM_FIRED;
count = 0;
goto alarm_fired;
}
fi;
count++;
goto intruder_detected;
alarm_fired:
if
:: nempty(input) ->
if
:: input?INPUT_SET_PASSWORD(tmp) ->
skip; // error: cannot be done now (?)
:: input?INPUT_CHECK_PASSWORD(tmp);
if
:: tmp == passwd ->
atomic {
state = ALARM_OFF;
count = 0;
goto off;
}
:: else ->
skip; // error: incorrect password (?)
// warn user but keep alarm on
fi;
:: input?INPUT_INTRUDER(tmp) ->
skip;
fi;
:: empty(input) ->
skip;
fi;
goto alarm_fired;
};
proctype user(chan output)
{
output ! INPUT_CHECK_PASSWORD(1234);
};
proctype event(chan output)
{
output ! INPUT_INTRUDER(0);
};
So, basically you have to check both the input
(if any!) and the value of count
in order to perform a transition in the internal FSM of the alarm
system.
In the example I added a proctype
of name event
which will randomly send a single INPUT_INTRUDER
input signal to the alarm
system. This, in combination with the user
typing his own password, can be used to trigger the chain of events which would cause the alarm to fire.
来源:https://stackoverflow.com/questions/47272662/how-can-i-bind-the-given-input-to-another-proctype-function