KM3NeT CLB  2.0
KM3NeT CLB v2 Embedded Software
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
msg.h File Reference

Handles MCF packed messages from the higher protocol layer. More...

#include "errorcode.h"
#include "cfg_msg.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "util/databuffer.h"
#include "kernel/err.h"
#include "net/net.h"
#include "net/mcf.h"

Go to the source code of this file.

Data Structures

struct  MsgId
 If defined, events will not require an acknowledge. More...
 

Macros

#define E_MSG_TYPE_UNKNOWN   ( E_MSG + 0x01 )
 Message unknown.
 
#define E_MSG_TYPE_UNKNOWN_DESCR   "Unknown message"
 
#define E_MSG_FUNCTION   ( E_MSG + 0x02 )
 Message function returned false.
 
#define E_MSG_FUNCTION_DESCR   "Function error"
 
#define E_MSG_CLASS_UNSUPPORT   ( E_MSG + 0x03 )
 Message class received not supported.
 
#define E_MSG_CLASS_UNSUPPORT_DESCR   "Class not supported"
 
#define MSG_CMD(CMD_TYPE, CMD_STUB)   bool _msg ## CMD_STUB (MsgId * id, DataBuffer * buf);
 Generate all message callbacks.
 
#define MSG_EVT(EVT_TYPE, EVT_STUB)   void _evt ## EVT_STUB (MsgId * id, DataBuffer * buf);
 

Functions

void msgRx (SockAddr *addr, uint8_t *data, int len)
 Receive a packet with data as a command. More...
 
void _msgRxCmd (MsgId id, DataBuffer *buf)
 Invoked when a command is received. More...
 
bool msgTxReply (MsgId *id, DataBuffer *buf)
 Invoke to send a reply. More...
 
static bool msgTxReplyAck (MsgId *id)
 Replies a simple ACK with no content. More...
 
void msgSetEvtTarget (SockAddr *sockAddr)
 Set the target for all events, or pass NULL to unset. More...
 
void msgGetEvtTarget (SockAddr *sockAddr)
 Returns the event target address. More...
 
bool msgTxEvent (int msgType, DataBuffer *buf)
 Invoked to send an event. More...
 
bool msgTxError (MsgId *id, int errCode, const char *errMsg, const char *name)
 Invoke to send an error response. More...
 
static bool msgTxCurError (MsgId *id)
 Invoke to reply the current global error. More...
 
bool msgStartStoreCmds (SockAddr *client, DataBuffer *target)
 Indicates that the next commands received should be stored. More...
 
bool msgStopStoreCmds ()
 Stops the storage of commands. More...
 
bool msgExecCmds (SockAddr client, DataBuffer *commands, DataBuffer *replies)
 Executes the given commands in the databuffer as if they where send by the 'client' address. More...
 
bool msgRxBufCheck (DataBuffer *buf)
 Checks the received buffer, and logs an error if there is something wrong. More...
 
void _msgTx (SockAddr *addr, uint8_t *data, int len)
 Stub function, invoked by RMT when sending a MCF packet. More...
 
bool _msgBusRead (MsgId *id, DataBuffer *buf)
 Reads an address.
 
bool _msgBusWrite (MsgId *id, DataBuffer *buf)
 Writes one or more addresses.
 
bool _msgI2CRead (MsgId *id, DataBuffer *buf)
 
bool _msgI2CWrite (MsgId *id, DataBuffer *buf)
 
bool _msgUartTx (MsgId *id, DataBuffer *buf)
 
bool _msgUartRx (MsgId *id, DataBuffer *buf)
 
bool _msgFlashRead (MsgId *id, DataBuffer *buf)
 
bool _msgRxPktLogRead (MsgId *id, DataBuffer *buf)
 
bool _msgRxPktLogReset (MsgId *id, DataBuffer *buf)
 
bool _msgPing (MsgId *id, DataBuffer *buf)
 Reads an address.
 
bool _msgDateRev (MsgId *id, DataBuffer *buf)
 
bool _msgEvtTarget (MsgId *id, DataBuffer *buf)
 
bool _msgReset (MsgId *id, DataBuffer *buf)
 
bool _msgSysUpdateStart (MsgId *id, DataBuffer *buf)
 
bool _msgSysUpdateRecv (MsgId *id, DataBuffer *buf)
 
bool _msgSysUpdateEnd (MsgId *id, DataBuffer *buf)
 
bool _msgSysUpdateVerify (MsgId *id, DataBuffer *buf)
 
bool _msgBoot (MsgId *id, DataBuffer *buf)
 
bool _msgGoldenStop (MsgId *id, DataBuffer *buf)
 
bool _msgGoldenUnlock (MsgId *id, DataBuffer *buf)
 
bool _msgLogGet (MsgId *id, DataBuffer *buf)
 
bool _msgPLogGet (MsgId *id, DataBuffer *buf)
 
bool _msgImgGet (MsgId *id, DataBuffer *buf)
 
bool _msgCoreDumpClr (MsgId *id, DataBuffer *buf)
 
bool _msgConTunInit (MsgId *id, DataBuffer *buf)
 
bool _msgConTunSend (MsgId *id, DataBuffer *buf)
 
bool _msgRtConfig (MsgId *id, DataBuffer *buf)
 
bool _msgClbGetState (MsgId *id, DataBuffer *buf)
 
bool _msgClbEvent (MsgId *id, DataBuffer *buf)
 
bool _msgClbGetVars (MsgId *id, DataBuffer *buf)
 
bool _msgClbSetVars (MsgId *id, DataBuffer *buf)
 
bool _msgClbSubVars (MsgId *id, DataBuffer *buf)
 
bool _msgClbUnSubVars (MsgId *id, DataBuffer *buf)
 
bool _msgClbExtUpdate (MsgId *id, DataBuffer *buf)
 
bool _msgClbClrErrState (MsgId *id, DataBuffer *buf)
 
bool _msgClbSubVarsRate (MsgId *id, DataBuffer *buf)
 
bool _msgNetMuxDest (MsgId *id, DataBuffer *buf)
 
bool _msgNetWlTuneInfo (MsgId *id, DataBuffer *buf)
 Request the wavelength tuning subsystem state.
 
bool _msgNetWlTuneSet (MsgId *id, DataBuffer *buf)
 Set the wavelength tuning word.
 
bool _msgNetWlTuneAck (MsgId *id, DataBuffer *buf)
 Acknowledge the wavelength tuning.
 
bool _msgInsAHRSSetReg (MsgId *id, DataBuffer *buf)
 Writes a register of the AHRS.
 
bool _msgInsAHRSGetReg (MsgId *id, DataBuffer *buf)
 Reads a register of the AHRS.
 
bool _msgInsAHRSGetRegEx (MsgId *id, DataBuffer *buf)
 
bool _msgBseConfigure (MsgId *id, DataBuffer *buf)
 
bool _msgBseReset (MsgId *id, DataBuffer *buf)
 
bool _msgBseEdfaDbgCmd (MsgId *id, DataBuffer *buf)
 
bool _msgBseEdfaDbgCmdRply (MsgId *id, DataBuffer *buf)
 
bool _msgBseBpsDbgCmdRply (MsgId *id, DataBuffer *buf)
 
void _evtSysUpdateRecv (MsgId *id, DataBuffer *buf)
 
void _evtConTunRecv (MsgId *id, DataBuffer *buf)
 

Detailed Description

Handles MCF packed messages from the higher protocol layer.

Commands & Replies

From the lower-level protocol layer (in this case SRP, but it might just as well be TCP/IP), the _msgRx() command is invoked. The received packets are unpacked, and its contents decoded.

For each command a function prototype is generated, which should be implemented by the higher level functions. These commands get a message identifier and a DataBuffer containing the content of the message.

For example, the ReadAddr message is defined as follows: MSG_CMD(GROUP_DEBUG, 1, ReadAddr)

The message module will then generate a stub-signature as follows:

bool _msgReadAddr(MsgId * msgId, DataBuffer * content)

However, the implementation is left to the higher-level layers.

There are 3 ways in which you can generate a reply:

  1. Synchronous (returns < 100ms)
  2. ASynchronous (returns < 1 second)
  3. Synchronous + Event (anything > second)

Which to take depends on the situation, however, take care with option 1, since it will stall the network stack.

Synchronous

Synchronous replies are replies which yield a result immediately. They will be used most common situations.

For example, the following code returns a number of memory addresses read.

bool _msgReadAddr(MsgId * msgId, DataBuffer * cmd)
{
uint32_t * addr;
uint16_t count;
// parse command arguments
dbReadUInt(cmd, &addr); // read first argument, the offset address
dbReadUShort(cmd, &count); // read second argument the count
if (count > MAX_READS) { // can't read that many addresses
msgTxError(msgId, E_INVALID_ARGUMENT); // return an error
return true; // true only means 'I've handled the error'
}
// create reply arguments
DataBuffer rply = DB_BUF_INIT(replyBuf, MAX_SIZE); // initialize reply buffer
dbWriteUShort(&reply, count); // return no of elements in return array
for (i = 0; i < count; ++i, ++addr) // for each address
dbWriteUInt(&reply, *addr); // load the data into the reply buffer
msgTxReply(msgId, &reply); // send the reply to the message processing
return true;
}

ASynchronous

However, it is not required to generate a reply inside the processing function. Functions which require some asynchronous processing, but don't take more than a second, can use asynchronous processing.

static volatile MsgId _asyncMsgId;
static volatile bool _asyncBusy;
bool _msgCalibrateTDCs(MsgId * msgId, DataBuffer * cmd)
{
if (_eventBusy) return false; // its better to generate a nice reply, but this will do
_asyncMsgId = *msgId; // must copy it: pointer no longer valid after function!
_asyncBusy = true;
tdcCalibrateAll();
return true; // don't generate a reply
}
void replyTDCCalibratResult()
{
int i;
DataBuffer rply = DB_BUF_INIT(replyBuf, MAX_SIZE); // initialize reply buffer
dbWriteUShort(&reply, TDC_CHANNELS); // return no of elements in return array
for (i = 0; i < TDC_CHANNELS; ++i) // for each channel
dbWriteUInt(&reply, tdcGetCalibValue(i)); // load the TDC calibration value
msgTxReypl(&_asyncMsgId, &reply); // create the event
_asyncBusy = false; // allow new async replies
return true;
}
// TDC IRQ
void IRQ_HANDLER(TDC_IRQ) {
// take it outside of the interrupt handler, message processing is not thread safe.
if (tdcGetIrq() & TDC_IRQ_CALIBRATION_DONE) {
schdCallOnce(replyTDCCalibratResult); // command, not yet implemented.
tdcClearIrq(TDC_IRQ_CALIBRATION_DONE);
}
}

Event Reply

An event reply is used when the function takes even more time. For simplicity sake we will use the same code as before, and modify it to be an event.

First of all the code immediately generates an OK reply. Second the function msgTxReplyEvent is used instead of msgTxReply. Those are the only differences at this side.

In practice what will happen on the shore-station side is that the function is invoked, and returns immediately, later on the reply will be passed to the shore-station API and returned through an asynchronous listener.

static volatile MsgId _eventMsgId;
static volatile bool _eventBusy;
bool _msgCalibrateTDCs(MsgId * msgId, DataBuffer * cmd)
{
if (_eventBusy) return false; // its better to generate a nice reply, but this will do
_eventMsgId = *msgId; // must copy it, pointer no longer valid after this function!
_eventBusy = true;
tdcCalibrateAll();
msgTxReply(msgId, NULL); // generate simple Ok.
return true;
}
void replyTDCCalibratResult()
{
int i;
DataBuffer reply = DB_BUF_INIT(replyBuf, MAX_SIZE); // initialize reply buffer
dbWriteUShort(&reply, TDC_CHANNELS); // return no of elements in return array
for (i = 0; i < TDC_CHANNELS; ++i) // for each channel
dbWriteUInt(&reply, tdcGetCalibValue(i)); // load the TDC calibration value
msgTxReplyEvent(&_eventMsgId, &reply); // create the reply event
_eventBusy = false; // allow new events
return true;
}
// TDC IRQ
void IRQ_HANDLER(TDC_IRQ) {
// take it outside of the interrupt handler, message processing is not thread safe.
if (tdcGetIrq() & TDC_IRQ_CALIBRATION_DONE) {
schdCallOnce(replyTDCCalibratResult); // command, not yet implemented.
tdcClearIrq(TDC_IRQ_CALIBRATION_DONE);
}
}

Stand-Alone Events

The Msg module can also be used to generate periodic stand-alone events. These can be used to communicate status updates, or maybe unexpected failures.

However, the address to send the event to should be known before hand. To do this we first need to configure the receiver. For this we have defined the 'ConfStatusReceiver' command which takes the sender of the command to be the receiver for asynchronous events. This command should be invoked by the shore station before events can be send.

static SockAddr _statusRecv;
static bool _statusRecvValid;
// configures the address to send status events to.
bool _msgConfStatusReceiver(MsgId * msgId, DataBuffer * cmd)
{
_statusRecv = msgId->addr; // copy socket address from message ID;
_statusRecvValid = true;
msgTxReply(msgId, NULL); // generate simple Ok.
return true;
}

Once this is done, we can schedule a periodic function to create status messages.

#define MSG_EVT_STATUS MSG_MK_TYPE(GROUP_CLB, 1)
static int statusTask;
static void statusFull(DataBuffer * eventData)
{
// outside of scope of example, fills the event with the required fields.
}
// called every second
void statusPeridoic()
{
if (!_statusRecValid) return; // no valid sender address, cancel.
uint8_t eventBuf[MAX_SIZE];
DataBuffer event = DB_BUF_INIT(eventBuf, MAX_SIZE);
statusFill(&eventBuf);
msgTxEvent(MSG_EVT_STATUS, &statusRecv, &event);
}
bool statusInit()
{
if (!schdRegister(statusPeriodic, false, &statusTask)) return false;
if (!schdPeriodic(statusTask, 1000)) return false;
}

Other remarks

Message Container Format is just what it is, a format. It does not imply any kind of protocol. The Msg module, however, uses it to parse and format messages. Still on the remote side it is expected that a command always yields a reply within a specified time. Care must be taken by the higher-level layer, that is, a command implementation, to always generate a reply. In its simplest form this is done by returning false in the stub function. Failure to do so will cause time-out's on the shore-station, and may hold-up processes.

Definition in file msg.h.

Function Documentation

void _msgRxCmd ( MsgId  id,
DataBuffer buf 
)

Invoked when a command is received.

Parameters
id
buf
void _msgTx ( SockAddr addr,
uint8_t *  message,
int  len 
)

Stub function, invoked by RMT when sending a MCF packet.

Parameters
addrTarget address
dataPointer to the data
lenLength of the message.

Stub function, invoked by RMT when sending a MCF packet.

Definition at line 623 of file network.c.

bool msgExecCmds ( SockAddr  client,
DataBuffer commands,
DataBuffer replies 
)

Executes the given commands in the databuffer as if they where send by the 'client' address.

Parameters
clientAddress from which the commands appear to be executed.
commandsA buffer containing the commands
Return values
trueCommands where executed.
falseCommands could not be executed. See errCode() for more information.
void msgGetEvtTarget ( SockAddr sockAddr)

Returns the event target address.

Parameters
sockAddrThe socket address.

Definition at line 264 of file msg.c.

void msgRx ( SockAddr addr,
uint8_t *  data,
int  len 
)

Receive a packet with data as a command.

Parameters
addrSource address
dataPointer to the message data
lenLength of the message

Definition at line 194 of file msg.c.

bool msgRxBufCheck ( DataBuffer buf)

Checks the received buffer, and logs an error if there is something wrong.

Must be invoked after all data has been read.

Parameters
bufThe buffer to check
Return values
trueThe buffer is OK, and all content has been processed.
falseThe buffer is not OK, or not all commands have been processed.

Definition at line 141 of file msg.c.

void msgSetEvtTarget ( SockAddr sockAddr)

Set the target for all events, or pass NULL to unset.

This will prevent any messages to be send.

Parameters
sockAddrThe event target socket address.

Definition at line 251 of file msg.c.

bool msgStartStoreCmds ( SockAddr client,
DataBuffer target 
)

Indicates that the next commands received should be stored.

Parameters
clientThe client address to receive from. All others will be executed, not stored.
storetrue - Store, false - Do not queue received commands.
Return values
trueStorage of commands started
falseStorage of commands not started, see errCode() for more info.
bool msgStopStoreCmds ( )

Stops the storage of commands.

Return values
trueStorage of commands succesfully stopped
falseStorage of commands failed.
static bool msgTxCurError ( MsgId id)
inlinestatic

Invoke to reply the current global error.

Error will be cleared afterwards.

Parameters
idThe message ID
Return values
trueWas send.
falseWas not send.

Definition at line 378 of file msg.h.

bool msgTxError ( MsgId id,
int  errCode,
const char *  errMsg,
const char *  name 
)

Invoke to send an error response.

Parameters
idThe message ID
errCodeThe error code to reply.
errMsgThe error message to response, may be empty or NULL.
nameName of the error generator
Return values
trueWas send.
falseWas not send.

Definition at line 293 of file msg.c.

bool msgTxEvent ( int  msgType,
DataBuffer buf 
)

Invoked to send an event.

Parameters
msgTypeThe message type
bufThe buffer object with the content.
Return values
trueWas send.
falseWas not send.

Definition at line 269 of file msg.c.

bool msgTxReply ( MsgId id,
DataBuffer buf 
)

Invoke to send a reply.

Parameters
idThe message ID
bufThe content to send.

Definition at line 286 of file msg.c.

static bool msgTxReplyAck ( MsgId id)
inlinestatic

Replies a simple ACK with no content.

Same as msgTxReply(id, NULL);

Parameters
idThe message ID

Definition at line 323 of file msg.h.