KM3NeT CLB  2.0
KM3NeT CLB v2 Embedded Software
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clbstate.c
1 /*
2  * state.c
3  *
4  * Created on: 6 aug. 2013
5  * Author: vincentb
6  */
7 
8 #include "clbstate.h"
9 
10 #include "appcode.h"
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <assert.h>
15 
16 #include "util/log.h"
17 #include "kernel/err.h"
18 #include "kernel/scheduler.h"
19 #include "drv/wb/ticks.h" // TODO: remove this, its not nice layering
20 #include "remote/msg_clb.h"
21 
23 
24 
25 
26 static bool _changeEmitHoldOff = false;
27 static bool _stateChanged = false;
28 
29 #define SEQ_AUTO_DELAY 100
30 
31 static ClbEvent * _seq;
32 static int _seqLen;
33 static int _seqTaskId;
34 
35 typedef struct
36 {
37  ClbState source;
38  ClbState target;
39 } Transition;
40 
41 static const Transition tansitionTable[] = {
42  { clbStateUndefined, clbStateIdle }, // Boot
43  { clbStateIdle, clbStateStandBy }, // Init
44  { clbStateStandBy, clbStateReady }, // Ready
45  { clbStateReady, clbStateRunning }, // Start
46  { clbStateRunning, clbStatePaused }, // Pause
47  { clbStatePaused, clbStateRunning }, // Continue
48  { clbStatePaused, clbStateStandBy }, // Stop
49  { clbStateReady, clbStateStandBy }, // Quit
50  { clbStateStandBy, clbStateIdle } // Reset
51 };
52 
53 const char * const clbSubsystemNames[CLB_SUB_CNT] = {
54 #define SUBS(IDX, ID, NAME) #NAME,
55 SUBSYSTEMS
56 #undef SUBS
57 };
58 
59 uint8_t clbSys2Idx[CLB_SUB_MAX];
60 
61 const char * const clbStateNames[6] = {
62  "Undefined", "Idle", "StandBy", "Ready", "Paused", "Running"
63 };
64 
65 
66 const char * const clbEventNames[9] = {
67  "Boot",
68  "Init",
69  "Configure",
70  "Start",
71  "Pause",
72  "Continue",
73  "Stop",
74  "Quit",
75  "Reset"
76 };
77 
78 
79 typedef struct
80 {
81  void (*execEvent)(ClbEvent event);
82  bool (*update)();
83  int errorCode;
84  const char * errorMsg;
85  ClbState state;
86  uint8_t status; // bitmask containing status bits
87  uint8_t id; // actual subsystem ID code
88 } ClbSubSys;
89 
90 static ClbSubSys _subSystems[CLB_SUB_CNT];
91 
93 {
94  assert(idx >= 0 && idx < CLB_SUB_CNT);
95 
96  return _subSystems[idx].state;
97 }
98 
99 int clbSubId(int idx)
100 {
101  assert(idx >= 0 && idx < CLB_SUB_CNT);
102  return _subSystems[idx].id;
103 }
104 
105 
106 bool clbStateError(int idx, int * code, const char ** message)
107 {
108  assert(idx >= 0 && idx < CLB_SUB_CNT);
109  if (_subSystems[idx].errorCode == E_NONE) return false;
110 
111  *code = _subSystems[idx].errorCode;
112  *message = _subSystems[idx].errorMsg;
113 
114  return true;
115 }
116 
117 
118 uint8_t clbStatus(int idx)
119 {
120  return _subSystems[idx].status;
121 }
122 
123 /*
124  * Checks whether or not a specific transition is possible for the given subsystem.
125  */
126 static bool clbCheckGoto(int idx, ClbEvent event)
127 {
128  ClbState state = _subSystems[idx].state;
129 
130  // currently it is in transit, so we don't want to change it!
131  if (_subSystems[idx].status & CLB_STATUS_PENDING) return false;
132 
133  if ((state >= clbStateUndefined && state <= clbStateRunning) &&
134  (event >= clbEventBoot && event <= clbEventReset))
135  {
136  if (tansitionTable[event].source == state)
137  return true;
138  }
139 
140 
141  // FIX 20160704 VVB - Be silent about failed state changes
142  return false; // errSet(ERROR(E_CLBSTATE_STATECHANGE));
143 
144 }
145 
146 
147 
148 /*
149  * Invokes the different subsystem changeState functions.
150  */
151 static bool clbEventInternal(int idx, ClbEvent event)
152 {
153  // when changing a lot of state, hold off the emitting of state change messages
154  _changeEmitHoldOff = true;
155  int i;
156  if (idx == CLB_SUB_ALL)
157  {
158  for (i = 0; i < CLB_SUB_CNT; ++i) clbEventInternal(i, event);
159  } else
160  {
161  if (event == clbEventReset || event == clbEventBoot) {
162  // clear all errors on reset or boot
163  _subSystems[idx].errorCode = E_NONE;
164  _subSystems[idx].errorMsg = NULL;
165  _subSystems[idx].status = 0;
166  }
167  // logDebug("Event received, for subsystems %d, %d", subsys, event);
168  assert(idx < CLB_SUB_CNT);
169  if (clbCheckGoto(idx, event))
170  {
171  _subSystems[idx].status |= CLB_STATUS_PENDING;
172  _subSystems[idx].execEvent(event);
173  }
174 
175  if (errHas())
176  {
177  // if there is an uncaptured errro, clear state
178  logWarn("Uncaptured event processing error, subsys %s:", clbSubsystemNames[idx]);
179  _subSystems[idx].status &= ~CLB_STATUS_PENDING;
180  errPrint(true);
181  }
182 
183 
184  }
185 
186  _changeEmitHoldOff = false;
187 
188  // supress events until sequence finished.
189  if (_seqLen > 0) return true;
190 
191  // when state indeed changes, just emit one.
192  if (_stateChanged)
193  {
194  _stateChanged = false;
196  }
197 
198  return true;
199 }
200 
201 /*
202  * Indicates a changed state.
203  */
204 void _clbStateUpdate(int idx, ClbEvent event, uint8_t status)
205 {
206  assert(idx >= 0 && idx < CLB_SUB_CNT);
207  ClbState state = tansitionTable[event].target;
208  // logDebug("State Change: Index=%d, Subsystem=%d, state=%d", idx, _subSystems[idx].id, state);
209 
210  assert (tansitionTable[event].source == _subSystems[idx].state);
211 
212  _subSystems[idx].state = state;
213  _subSystems[idx].status = status;
214 
215  // if you need to hold off, just wait.
216  if (_changeEmitHoldOff) _stateChanged = true;
217  else evtClbEmitStateChange();
218 }
219 
220 
221 bool clbEvent(int idx, ClbEvent event)
222 {
223  static ClbEvent lastEvent = clbEventReset;
224  if((idx < 0 || idx >= CLB_SUB_CNT) && idx != CLB_SUB_ALL) {
225  return errSet(ERROR_CTX(E_INVARGUMENT));
226  }
227  if (event < 0 || event > clbEventReset) {
228  return errSet(ERROR_CTX(E_INVARGUMENT));
229  }
230 
231  if (_seqLen > 0) return true;
232  if (lastEvent != event) {
233  // only log for subsystem sys
234  if (idx == CLB_SUB_SYS) logInfo("Event received: %s", clbEventNames[event]);
235  lastEvent = event;
236  }
237  return clbEventInternal(idx, event);
238 }
239 
240 
241 void clbClearErrorState(int idx)
242 {
243  assert((idx >= 0 && idx < CLB_SUB_CNT));
244 
245  if (idx == CLB_SUB_ALL)
246  {
247  // if index is all, clear all.
248  for (int i = 0; i< CLB_SUB_CNT; i++) clbClearErrorState(i);
249  return;
250  }
251 
252  _subSystems[idx].state &= ~CLB_STATUS_ERROR;
253  _subSystems[idx].errorCode = 0;
254  _subSystems[idx].errorMsg = NULL;
255 }
256 
257 
258 void _clbStateError(int idx, int errorCode, const char * errorMsg, const char * name)
259 {
260  // once an error has been reported, it can not be overwritten
261  if (_subSystems[idx].errorCode != E_NONE) return;
262 
263  // You can not set the 'none' error. Clearing happens through state changes.
264  if (errorCode == E_NONE) return;
265 
266  if (name == NULL) name = "Unknown";
267 
268 
269  _subSystems[idx].status |= CLB_STATUS_ERROR;
270  // FIX 20160704 VVB: If error, clear pending state
271  _subSystems[idx].status &= CLB_STATUS_PENDING;
272  _subSystems[idx].errorCode = errorCode;
273  _subSystems[idx].errorMsg = errorMsg;
274 
275  logError("Subsystem %s failed: %s (%08x) - %s", clbSubsystemNames[idx], errorMsg, errorCode, name);
276  // indicate error state ?
277 // clbStateUpdateInternal(subsys, clbStateError, _subSystems[subsys].status);
278 
279 }
280 
281 
283 {
284  // first clear any errors which where not captured. Tsk tsk tsk.
285  if (errHas()) errPrint(true);
286  int i;
287  uint32_t curTicks = ticks();
288  for (i = CLB_SUB_CNT - 1; i >= 0; --i)
289  {
290  if (_subSystems[i].update) {
291  _subSystems[i].update(_subSystems[i].state, curTicks);
292  // check if the subsystem failed, if so, report it.
293  if (errHas())
294  {
295  _clbStateError(i, errGet(), errGetDescr(), 0);
296  errClear();
297  }
298  }
299  }
300 }
301 
302 
303 static void clbStateAuto()
304 {
305  _seq++;
306  _seqLen--;
307 
308  if (_seqLen == 0) {
310  } else {
311  clbEventInternal(CLB_SUB_ALL, *_seq);
312  schdRunDelay(_seqTaskId, SEQ_AUTO_DELAY);
313  }
314 
315 }
316 
317 void clbAutoEventSeq(ClbEvent * events, int seqLen)
318 {
319  if (_seq != NULL) return;
320  _seq = events;
321  _seqLen = seqLen;
322  clbEventInternal(CLB_SUB_ALL, *_seq);
323  schdRunDelay(_seqTaskId, SEQ_AUTO_DELAY);
324 }
325 
326 
328 {
329  int i;
330  for (i = 0; i < CLB_SUB_CNT; ++i)
331  {
332  _subSystems[i].state = clbStateUndefined;
333  }
334 
335  for (i = 0; i < CLB_SUB_MAX; ++i) {
336  clbSys2Idx[i] = -1;
337  }
338 
339 #define SUBS(IDX, ID, NAME) _subSystems[IDX].execEvent = (_subs ## NAME ## ExecEvent); \
340  _subSystems[IDX].update = (_subs ## NAME ## Update); \
341  _subSystems[IDX].id = ID; \
342  clbSys2Idx[ID] = IDX;
343 
344 
345 SUBSYSTEMS
346 
347 #undef SUBS
348 
349 /* for (i = 0; i < CLB_SUB_CNT; ++i) {
350  logInfo("SubSystem %d: %s (id=%d)", i, clbSubsystemNames[i], _subSystems[i].id);
351  }*/
352 
353  // move all subsystems to idle
354  clbEventInternal(CLB_SUB_ALL, clbEventBoot);
355  schdRegister(clbStateAuto, false, &_seqTaskId);
356 }
357 
bool errHas()
Returns whether there is an error pending.
Definition: err.c:52
Ready state.
Definition: clbstate.h:64
const char *const clbEventNames[9]
All state change event names.
Definition: clbstate.c:66
Idle state.
Definition: clbstate.h:62
ClbEvent
All state change events.
Definition: clbstate.h:88
Application specific error codes.
White Rabbit simple timer &#39;Ticks&#39; driver.
ClbState clbState(int idx)
Returns the current clbSubState for the specified subsystem.
Definition: clbstate.c:92
bool schdRegister(SchdTaskF task, bool priority, int *taskId)
Register a task with the scheduler.
Definition: scheduler.c:95
bool clbEvent(int idx, ClbEvent event)
Request a subsystem to go to a certain state.
Definition: clbstate.c:221
const char * errGetDescr()
Returns the last error description, if any, else null.
Definition: err.c:57
Simple task scheduler for tasks.
Running state.
Definition: clbstate.h:66
void clbClearErrorState(int idx)
Clears the error state of the specific subsystem.
Definition: clbstate.c:241
void clbAutoEventSeq(ClbEvent *events, int seqLen)
Executes an autonomous a sequence of events.
Definition: clbstate.c:317
static uint32_t ticks()
Nr of ticks since device start up.
Definition: ticks.h:37
bool clbStateError(int idx, int *code, const char **message)
Retrieves the error of a subsystem (if any).
Definition: clbstate.c:106
uint8_t clbSys2Idx[6]
Mapping from subsystem ID to index.
Definition: clbstate.c:59
CLB Remote message processor.
void clbUpdateSubsys()
Invoked the update method on each subsystem.
Definition: clbstate.c:282
#define logWarn(MSG,...)
Format a log message with warning level.
Definition: log.h:219
#define E_NONE
Zero is no error.
Definition: errorcode.h:94
#define E_INVARGUMENT
Generic error: invalid argument.
Definition: errorcode.h:112
Paused state.
Definition: clbstate.h:65
const char *const clbSubsystemNames[5]
Contains a list of all the subsystems.
Definition: clbstate.c:53
void schdRunDelay(int taskId, int interval)
Schedule a task to run after a delay.
Definition: scheduler.c:201
int clbSubId(int idx)
Returns the subsystem ID code for the provided index.
Definition: clbstate.c:99
ClbState
Various states.
Definition: clbstate.h:59
Manages the global system error.
Undefined =&gt; Idle, for internal use only.
Definition: clbstate.h:91
void errPrint(bool clear)
Prints the last error.
Definition: err.c:79
#define CLB_STATUS_PENDING
Indicates that the subsystem is in transit to a new state.
Definition: clbstate.h:114
StandBy =&gt; Idle.
Definition: clbstate.h:99
void clbStateInit()
Initializes the state machine.
Definition: clbstate.c:327
StandBy state.
Definition: clbstate.h:63
const char *const clbStateNames[6]
Contains list of the state names.
Definition: clbstate.c:61
void errClear()
Clears the current error.
Definition: err.c:46
#define CLB_SUB_ALL
Indicates all subsystems. Can be used in clbStateGoto.
Definition: clbstate.h:111
uint32_t errGet()
Returns the last error code, or null.
Definition: err.c:74
#define logError(MSG,...)
Format a log message with fatal level.
Definition: log.h:232
#define LOG_DEF(NAME,...)
Define a logger for a module.
Definition: log.h:129
The CLB stare module tracks is responsible for state management of the various sub-systems on the CLB...
bool errSet(uint32_t code, const char *error, const char *name)
Sets an error.
bool evtClbEmitStateChange()
Indicates the CLB to emit a state change event to the slow control.
Definition: msg_clb.c:194
Implements a generic logger facility.
void _clbStateError(int idx, int error, const char *message, const char *name)
Invoked by subsystem to indicate an error happened.
Definition: clbstate.c:258
#define logInfo(MSG,...)
Write a log message with formatting on info level.
Definition: log.h:202
void _clbStateUpdate(int idx, ClbEvent event, uint8_t status)
Invoked by the subsystem to indicate a state change has happened.
Definition: clbstate.c:204
Undefined state (prior to module init, should never be seen on shore)
Definition: clbstate.h:61
uint8_t clbStatus(int idx)
Returns the current subsystem status.
Definition: clbstate.c:118