Using Message Objects#
The message template classes are defined in src/architecture/messaging/messaging.h.
Include this header in any module that reads or writes messages.
Input Messages (ReadFunctor<T>)#
Declaring an Input#
Add a public member in the module header:
ReadFunctor<SomeMsgPayload> someInMsg;
Reading a Message#
Call the read functor like a function. It returns a deep copy of the latest payload:
SomeMsgPayload localBuffer = this->someInMsg();
Note
The local buffer does not need to be zero-initialised – the read functor overwrites it entirely. A compile-time error is raised if the buffer type does not match the message type.
Helper Methods#
isLinked()Returns
trueif the input is connected to an output message.isWritten()Returns
trueif the connected output has been written to at least once.timeWritten()Returns the simulation time (nanoseconds,
uint64_t) at which the connected message was last written.moduleID()Returns the
int64_tID of the module that wrote the message. C/C++ module IDs are strictly positive; Python module IDs are strictly negative.
Example:
if (this->someInMsg.isLinked()) {
SomeMsgPayload data = this->someInMsg();
}
Output Messages (Message<T>)#
Declaring an Output#
Add a public member in the module header:
Message<SomeMsgPayload> someOutMsg;
Writing a Message#
Fill a zero-initialised local buffer and call write():
SomeMsgPayload buf{};
buf.dataVector[0] = 1.0;
this->someOutMsg.write(&buf, this->moduleID, currentSimNanos);
Note
Always zero-initialise the output buffer with {} to avoid writing
uninitialised values. A compile-time error is raised if the buffer type
does not match the message type.
Helper Methods#
isLinked()Returns
trueif any input message (including arecorder()) is subscribed to this output.addSubscriber()Returns a
ReadFunctor<T>that can read this output message.addAuthor()Returns the write functor, granting write access to the message object.
Vectors of Input Messages#
Declare a vector of read functors and a corresponding private buffer vector:
public:
std::vector<ReadFunctor<SomeMsgPayload>> moreInMsgs;
private:
std::vector<SomeMsgPayload> moreInMsgsBuffer;
Use a public method to let the user add input messages:
void SomeModule::addMsgToModule(Message<SomeMsgPayload> *tmpMsg)
{
this->moreInMsgs.push_back(tmpMsg->addSubscriber());
SomeMsgPayload emptyBuf;
this->moreInMsgsBuffer.push_back(emptyBuf);
}
Vectors of Output Messages#
Output message vectors use pointers because each Message object must
persist after the helper method returns:
public:
std::vector<Message<SomeMsgPayload>*> moreOutMsgs;
Create output messages dynamically:
Message<SomeMsgPayload> *msg = new Message<SomeMsgPayload>;
this->moreOutMsgs.push_back(msg);
Free the memory in the destructor:
SomeModule::~SomeModule()
{
for (auto *msg : this->moreOutMsgs) {
delete msg;
}
}
See eclipse for a real-world example where each spacecraft state input message is paired with a corresponding eclipse output message.
Best Practices#
Always zero-initialise output buffers with
{}before writing.Check
isLinked()inreset()for required input messages and log an error if the message is not connected.Avoid dynamic allocation in tight loops – prefer fixed-size arrays where possible.
Next Steps#
Messaging System Overview – high-level introduction to the messaging system
Creating New Message Types – how to define new payload structs