Add StateMachine to CmdThread
CmdThread
works with a single client thread. A simple way to extend the support to multiple client threads is to add a StateMachine
class that will provide:
- Improved atomic control of Cmd/State management over current
sendCmdIf
- Transition of states: Ready -> Starting -> Exposure -> Stopping -> Ready
class CmdThread {
public:
...
enum CmdAction {
Accept, Deny, Ignore,
};
typedef std::pair<CmdAction, State> CmdResp;
...
CmdResp sendCmd(Cmd cmd);
...
protected:
class StateMachine {
public:
virtual CmdResp onCmd(Cmd Cmd, State state) = 0;
virtual State onAck(Cmd Cmd, State state) = 0;
};
typedef std::pair<Cmd, State> CmdState;
virtual StateMachine *getStateMachine();
CmdState waitNextCmd();
...
};
The onCmd
method will be invoked in CmdThread::sendCmd
.
If the returned action is Deny
an Exception
is thrown; if
Ignore
no cmd is sent and the State is not changed. If Accept
is returned, the new state is set to Result::second. For instance,
a simplified version for the Simulator
(ignoring other states):
CmdThread::CmdResp SimuThread::StateMachine::onCmd(Cmd Cmd, State state)
{
switch (cmd) {
case StartAcq:
switch (state) {
case Ready:
return CmdResp(Accept, Starting);
default:
return CmdResp(Deny, state);
};
case StopAcq:
switch (state) {
case Ready:
case Stopping:
return CmdResp(Ignore, state);
case Starting:
return CmdResp(Accept, Ready);
case Exposure:
return CmdResp(Accept, Stopping);
};
};
}
The onAck
method will be executed in the thread context inside
waitNextCmd
, and will return the new state:
State SimuThread::StateMachine::onAck(Cmd Cmd, State state)
{
if ((cmd == StartAcq) && (state == Starting))
return Exposure;
if ((cmd == StopAcq) &&
((state == Ready) || (state == Stopping)))
return Ready;
THROW_HW_ERROR(Error) << "Invalid combination: "
<< DEB_VAR2(cmd, state);
}
The m_cmd
member will become again an int
, instead of std::queue<int>
.
Edited by Laurent Claustre