KM3NeT CLB  2.0
KM3NeT CLB v2 Embedded Software
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
msg.h
Go to the documentation of this file.
1 /*
2  * KM3NeT CLB v2 Firmware
3  * ----------------------
4  *
5  * Copyright 2013 National Institute for Subatomic Physics Nikhef
6  *
7  * All Rights Reserved.
8  *
9  *
10  * File : mcflayer.h
11  * Created : 9 jul. 2013
12  * Author : Vincent van Beveren
13  */
14 
15 #ifndef MSG_H_
16 #define MSG_H_
17 
18 /**
19  * @file
20  *
21  * @ingroup network
22  *
23  * Handles MCF packed messages from the higher protocol layer.
24  *
25  * Commands & Replies
26  * ==================
27  * From the lower-level protocol layer (in this case SRP, but it might just as well be TCP/IP),
28  * the _msgRx() command is invoked. The received packets are unpacked, and its contents decoded.
29  *
30  * For each command a function prototype is generated, which should be implemented by the higher
31  * level functions. These commands get a message identifier and a DataBuffer containing the content
32  * of the message.
33  *
34  * For example, the ReadAddr message is defined as follows:
35  * MSG_CMD(GROUP_DEBUG, 1, ReadAddr)
36  *
37  * The message module will then generate a stub-signature as follows:
38  *
39  * @code
40  * bool _msgReadAddr(MsgId * msgId, DataBuffer * content)
41  * @endcode
42  *
43  * However, the implementation is left to the higher-level layers.
44  *
45  * There are 3 ways in which you can generate a reply:
46  * 1. Synchronous (returns < 100ms)
47  * 2. ASynchronous (returns < 1 second)
48  * 3. Synchronous + Event (anything > second)
49  *
50  * Which to take depends on the situation, however, take care with option 1, since it will stall
51  * the network stack.
52  *
53  * Synchronous
54  * -----------
55  * Synchronous replies are replies which yield a result immediately. They will be used most common
56  * situations.
57  *
58  * For example, the following code returns a number of memory addresses read.
59  * @code
60  * bool _msgReadAddr(MsgId * msgId, DataBuffer * cmd)
61  * {
62  * uint32_t * addr;
63  * uint16_t count;
64  * // parse command arguments
65  * dbReadUInt(cmd, &addr); // read first argument, the offset address
66  * dbReadUShort(cmd, &count); // read second argument the count
67  * if (count > MAX_READS) { // can't read that many addresses
68  * msgTxError(msgId, E_INVALID_ARGUMENT); // return an error
69  * return true; // true only means 'I've handled the error'
70  * }
71  *
72  * // create reply arguments
73  * DataBuffer rply = DB_BUF_INIT(replyBuf, MAX_SIZE); // initialize reply buffer
74  * dbWriteUShort(&reply, count); // return no of elements in return array
75  * for (i = 0; i < count; ++i, ++addr) // for each address
76  * dbWriteUInt(&reply, *addr); // load the data into the reply buffer
77  *
78  * msgTxReply(msgId, &reply); // send the reply to the message processing
79  * return true;
80  * }
81  * @endcode
82  *
83  *
84  * ASynchronous
85  * ------------
86  * However, it is not required to generate a reply inside the processing function. Functions which
87  * require some asynchronous processing, but don't take more than a second, can use asynchronous
88  * processing.
89  * @code
90  * static volatile MsgId _asyncMsgId;
91  * static volatile bool _asyncBusy;
92  *
93  * bool _msgCalibrateTDCs(MsgId * msgId, DataBuffer * cmd)
94  * {
95  * if (_eventBusy) return false; // its better to generate a nice reply, but this will do
96  *
97  * _asyncMsgId = *msgId; // must copy it: pointer no longer valid after function!
98  * _asyncBusy = true;
99  *
100  * tdcCalibrateAll();
101  *
102  * return true; // don't generate a reply
103  * }
104  *
105  * void replyTDCCalibratResult()
106  * {
107  * int i;
108  * DataBuffer rply = DB_BUF_INIT(replyBuf, MAX_SIZE); // initialize reply buffer
109  * dbWriteUShort(&reply, TDC_CHANNELS); // return no of elements in return array
110  * for (i = 0; i < TDC_CHANNELS; ++i) // for each channel
111  * dbWriteUInt(&reply, tdcGetCalibValue(i)); // load the TDC calibration value
112  *
113  * msgTxReypl(&_asyncMsgId, &reply); // create the event
114  *
115  * _asyncBusy = false; // allow new async replies
116  *
117  * return true;
118  *
119  * }
120  *
121  * // TDC IRQ
122  * void IRQ_HANDLER(TDC_IRQ) {
123  * // take it outside of the interrupt handler, message processing is not thread safe.
124  * if (tdcGetIrq() & TDC_IRQ_CALIBRATION_DONE) {
125  * schdCallOnce(replyTDCCalibratResult); // command, not yet implemented.
126  * tdcClearIrq(TDC_IRQ_CALIBRATION_DONE);
127  * }
128  * }
129  * @endcode
130  *
131  *
132  * Event Reply
133  * -----------
134  * An event reply is used when the function takes even more time. For simplicity sake we will use
135  * the same code as before, and modify it to be an event.
136  *
137  * First of all the code immediately generates an OK reply. Second the function msgTxReplyEvent
138  * is used instead of msgTxReply. Those are the only differences at this side.
139  *
140  * In practice what will happen on the shore-station side is that the function is invoked, and
141  * returns immediately, later on the reply will be passed to the shore-station API and returned
142  * through an asynchronous listener.
143  *
144  * @code
145  * static volatile MsgId _eventMsgId;
146  * static volatile bool _eventBusy;
147  *
148  * bool _msgCalibrateTDCs(MsgId * msgId, DataBuffer * cmd)
149  * {
150  * if (_eventBusy) return false; // its better to generate a nice reply, but this will do
151  *
152  * _eventMsgId = *msgId; // must copy it, pointer no longer valid after this function!
153  * _eventBusy = true;
154  *
155  * tdcCalibrateAll();
156  *
157  * msgTxReply(msgId, NULL); // generate simple Ok.
158  *
159  * return true;
160  * }
161  *
162  * void replyTDCCalibratResult()
163  * {
164  * int i;
165  * DataBuffer reply = DB_BUF_INIT(replyBuf, MAX_SIZE); // initialize reply buffer
166  * dbWriteUShort(&reply, TDC_CHANNELS); // return no of elements in return array
167  * for (i = 0; i < TDC_CHANNELS; ++i) // for each channel
168  * dbWriteUInt(&reply, tdcGetCalibValue(i)); // load the TDC calibration value
169  *
170  * msgTxReplyEvent(&_eventMsgId, &reply); // create the reply event
171  *
172  * _eventBusy = false; // allow new events
173  *
174  * return true;
175  *
176  * }
177  *
178  * // TDC IRQ
179  * void IRQ_HANDLER(TDC_IRQ) {
180  * // take it outside of the interrupt handler, message processing is not thread safe.
181  * if (tdcGetIrq() & TDC_IRQ_CALIBRATION_DONE) {
182  * schdCallOnce(replyTDCCalibratResult); // command, not yet implemented.
183  * tdcClearIrq(TDC_IRQ_CALIBRATION_DONE);
184  * }
185  * }
186  * @endcode
187  *
188  * Stand-Alone Events
189  * ==================
190  * The Msg module can also be used to generate periodic stand-alone events. These can be used to
191  * communicate status updates, or maybe unexpected failures.
192  *
193  * However, the address to send the event to should be known before hand. To do this we first need
194  * to configure the receiver. For this we have defined the 'ConfStatusReceiver' command which takes
195  * the sender of the command to be the receiver for asynchronous events. This command should be
196  * invoked by the shore station before events can be send.
197  * @code
198  *
199  * static SockAddr _statusRecv;
200  * static bool _statusRecvValid;
201  *
202  * // configures the address to send status events to.
203  * bool _msgConfStatusReceiver(MsgId * msgId, DataBuffer * cmd)
204  * {
205  * _statusRecv = msgId->addr; // copy socket address from message ID;
206  * _statusRecvValid = true;
207  *
208  * msgTxReply(msgId, NULL); // generate simple Ok.
209  *
210  * return true;
211  * }
212  * @endcode
213  *
214  * Once this is done, we can schedule a periodic function to create status messages.
215  *
216  * @code
217  * #define MSG_EVT_STATUS MSG_MK_TYPE(GROUP_CLB, 1)
218  *
219  * static int statusTask;
220  *
221  * static void statusFull(DataBuffer * eventData)
222  * {
223  * // outside of scope of example, fills the event with the required fields.
224  * }
225  *
226  * // called every second
227  * void statusPeridoic()
228  * {
229  * if (!_statusRecValid) return; // no valid sender address, cancel.
230  * uint8_t eventBuf[MAX_SIZE];
231  * DataBuffer event = DB_BUF_INIT(eventBuf, MAX_SIZE);
232  * statusFill(&eventBuf);
233  * msgTxEvent(MSG_EVT_STATUS, &statusRecv, &event);
234  * }
235  *
236  *
237  * bool statusInit()
238  * {
239  * if (!schdRegister(statusPeriodic, false, &statusTask)) return false;
240  * if (!schdPeriodic(statusTask, 1000)) return false;
241  * }
242  * @endcode
243  *
244  * Other remarks
245  * =============
246  * Message Container Format is just what it is, a format. It does not imply any kind of protocol.
247  * The Msg module, however, uses it to parse and format messages. Still on the remote side it is
248  * expected that a command always yields a reply within a specified time. Care must be taken by
249  * the higher-level layer, that is, a command implementation, to always generate a reply. In its
250  * simplest form this is done by returning false in the stub function. Failure to do so will cause
251  * time-out's on the shore-station, and may hold-up processes.
252  *
253  *
254  */
255 #include "errorcode.h"
256 #include "cfg_msg.h"
257 
258 #include <stdint.h>
259 #include <stdbool.h>
260 #include <stdlib.h>
261 
262 #include "util/databuffer.h"
263 #include "kernel/err.h"
264 
265 #include "net/net.h"
266 #include "net/mcf.h"
267 
268 //! If defined, events will not require an acknowledge
269 // #define MSG_DONTACK_EVENTS
270 
271 /**
272  * A MsgId is a struct which contains all information required to generate a valid reply.
273  */
274 typedef struct {
275  SockAddr addr; ///< the address of the sender
276  uint16_t msgType; ///< the message type
277  uint16_t msgId; ///< the message identifier
278 } MsgId;
279 
280 // all these errors are returned to the sender, so you will never see them in the error
281 // module.
282 #define E_MSG_TYPE_UNKNOWN ( E_MSG + 0x01 ) ///< Message unknown
283 #define E_MSG_TYPE_UNKNOWN_DESCR "Unknown message"
284 #define E_MSG_FUNCTION ( E_MSG + 0x02 ) ///< Message function returned false.
285 #define E_MSG_FUNCTION_DESCR "Function error"
286 #define E_MSG_CLASS_UNSUPPORT ( E_MSG + 0x03 ) ///< Message class received not supported.
287 #define E_MSG_CLASS_UNSUPPORT_DESCR "Class not supported"
288 
289 /**
290  * Receive a packet with data as a command.
291  *
292  * @param addr Source address
293  * @param data Pointer to the message data
294  * @param len Length of the message
295  */
296 void msgRx(SockAddr * addr, uint8_t * data, int len);
297 
298 /**
299  * Invoked when a command is received.
300  *
301  * @param id
302  * @param buf
303  */
304 void _msgRxCmd(MsgId id, DataBuffer * buf);
305 
306 
307 
308 /**
309  * Invoke to send a reply.
310  *
311  * @param id The message ID
312  * @param buf The content to send.
313  */
314 bool msgTxReply(MsgId * id, DataBuffer * buf);
315 
316 /**
317  * Replies a simple ACK with no content.
318  *
319  * Same as msgTxReply(id, NULL);
320  *
321  * @param id The message ID
322  */
323 static inline bool msgTxReplyAck(MsgId * id)
324 {
325  return msgTxReply(id, NULL);
326 }
327 
328 /**
329  * Set the target for all events, or pass NULL to unset. This will prevent any messages to be
330  * send.
331  *
332  * @param sockAddr The event target socket address.
333  */
334 void msgSetEvtTarget(SockAddr * sockAddr);
335 
336 /**
337  * Returns the event target address.
338  *
339  * @param sockAddr The socket address.
340  */
341 void msgGetEvtTarget(SockAddr * sockAddr);
342 
343 /**
344  * Invoked to send an event.
345  *
346  * @param msgType The message type
347  * @param buf The buffer object with the content.
348  *
349  * @retval true Was send.
350  * @retval false Was not send.
351  */
352 bool msgTxEvent(int msgType, DataBuffer * buf);
353 
354 
355 
356 /**
357  * Invoke to send an error response.
358  *
359  * @param id The message ID
360  * @param errCode The error code to reply.
361  * @param errMsg The error message to response, may be empty or NULL.
362  * @param name Name of the error generator
363  *
364  * @retval true Was send.
365  * @retval false Was not send.
366  */
367 bool msgTxError(MsgId * id, int errCode, const char * errMsg, const char * name);
368 
369 /**
370  * Invoke to reply the current global error.
371  * Error will be cleared afterwards.
372  *
373  * @param id The message ID
374  *
375  * @retval true Was send.
376  * @retval false Was not send.
377  */
378 static inline bool msgTxCurError(MsgId * id)
379 {
380  bool r = msgTxError(id, errGet(), errGetDescr(), errGetName());
381  errClear();
382  return r;
383 }
384 
385 /**
386  * Indicates that the next commands received should be stored.
387  *
388  * @param client The client address to receive from. All others will be
389  * executed, not stored.
390  * @param store true - Store, false - Do not queue received commands.
391  *
392  * @retval true Storage of commands started
393  * @retval false Storage of commands not started, see errCode() for more info.
394  */
395 bool msgStartStoreCmds(SockAddr * client, DataBuffer * target);
396 
397 /**
398  * Stops the storage of commands.
399  *
400  * @retval true Storage of commands succesfully stopped
401  * @retval false Storage of commands failed.
402  */
403 bool msgStopStoreCmds();
404 
405 /**
406  * Executes the given commands in the databuffer as if they where
407  * send by the 'client' address.
408  *
409  * @param client Address from which the commands appear to
410  * be executed.
411  * @param commands A buffer containing the commands
412  *
413  * @retval true Commands where executed.
414  * @retval false Commands could not be executed. See errCode() for more information.
415  */
416 bool msgExecCmds(SockAddr client, DataBuffer * commands, DataBuffer * replies);
417 
418 /**
419  * Checks the received buffer, and logs an error if there is something wrong.
420  * Must be invoked after all data has been read.
421  *
422  * @param buf The buffer to check
423  *
424  * @retval true The buffer is OK, and all content has been processed.
425  * @retval false The buffer is not OK, or not all commands have been processed.
426  */
427 bool msgRxBufCheck(DataBuffer * buf);
428 
429 /**
430  * Stub function, invoked by RMT when sending a MCF packet.
431  *
432  * @param addr Target address
433  * @param data Pointer to the data
434  * @param len Length of the message.
435  */
436 void _msgTx(SockAddr * addr, uint8_t * data, int len);
437 
438 /**
439  * Generate all message callbacks.
440  */
441 #define MSG_CMD(CMD_TYPE, CMD_STUB) \
442  bool _msg ## CMD_STUB (MsgId * id, DataBuffer * buf);
444 
445 #undef MSG_CMD
446 
447 
448 #define MSG_EVT(EVT_TYPE, EVT_STUB) \
449  void _evt ## EVT_STUB (MsgId * id, DataBuffer * buf);
451 
452 #undef MSG_EVT
453 
454 // stops the message callbacks.
455 
456 #endif /* MCFLAYER_H_ */
void msgGetEvtTarget(SockAddr *sockAddr)
Returns the event target address.
Definition: msg.c:264
void _msgTx(SockAddr *addr, uint8_t *data, int len)
Stub function, invoked by RMT when sending a MCF packet.
Definition: network.c:623
bool msgStopStoreCmds()
Stops the storage of commands.
bool msgTxEvent(int msgType, DataBuffer *buf)
Invoked to send an event.
Definition: msg.c:269
Message Container Format formatter / parser.
void _msgRxCmd(MsgId id, DataBuffer *buf)
Invoked when a command is received.
const char * errGetDescr()
Returns the last error description, if any, else null.
Definition: err.c:57
bool msgStartStoreCmds(SockAddr *client, DataBuffer *target)
Indicates that the next commands received should be stored.
static bool msgTxCurError(MsgId *id)
Invoke to reply the current global error.
Definition: msg.h:378
Defines a DataBuffer structure.
Definition: databuffer.h:45
uint16_t msgType
the message type
Definition: msg.h:276
void msgSetEvtTarget(SockAddr *sockAddr)
Set the target for all events, or pass NULL to unset.
Definition: msg.c:251
Combination of IP address and port.
Definition: net.h:31
Manages the global system error.
#define MSG_COMMANDS
List containing all commands.
Definition: cfg_msg.h:565
bool msgTxReply(MsgId *id, DataBuffer *buf)
Invoke to send a reply.
Definition: msg.c:286
DataBuffer reads and writes data into a buffer in the same format as defined in the data Java DataOut...
bool msgTxError(MsgId *id, int errCode, const char *errMsg, const char *name)
Invoke to send an error response.
Definition: msg.c:293
void msgRx(SockAddr *addr, uint8_t *data, int len)
Receive a packet with data as a command.
Definition: msg.c:194
void errClear()
Clears the current error.
Definition: err.c:46
bool msgRxBufCheck(DataBuffer *buf)
Checks the received buffer, and logs an error if there is something wrong.
Definition: msg.c:141
#define MSG_EVENTS
List containing all events.
Definition: cfg_msg.h:561
uint32_t errGet()
Returns the last error code, or null.
Definition: err.c:74
This module is responsible for distributing error codes.
Defines all remote commands.
SockAddr addr
the address of the sender
Definition: msg.h:275
If defined, events will not require an acknowledge.
Definition: msg.h:274
const char * errGetName()
Returns the last error cause name, or null.
Definition: err.c:65
static bool msgTxReplyAck(MsgId *id)
Replies a simple ACK with no content.
Definition: msg.h:323
uint16_t msgId
the message identifier
Definition: msg.h:277
bool msgExecCmds(SockAddr client, DataBuffer *commands, DataBuffer *replies)
Executes the given commands in the databuffer as if they where send by the &#39;client&#39; address...