Migrating Basilisk Modules from Version 1.X to 2.X
Motivation
This document discusses what coding related changes occurred with the new messaging system in Basilisk version 2.0 and higher. However, nothing is for free. Making these changes was not possible without breaking existing code. This migration help page outlines all the Basilisk coding related changes that have occurred. This facilities the process of upgrading legacy Basilisk C and C++ code to function with the new message system, etc.
For changes related to updating Basilisk python scripts, see Migrating Basilisk Scripts from Version 1.X to 2.X.
Message Names
See Migrating Basilisk Scripts from Version 1.X to 2.X for the discussion on how module input and output messages no longer have name and ID variables.
Creating New Message Definitions
See Message Definitions for how new message C structures can be created and added to the Basilisk project.
Step-By-Step Guide to Upgrade a Basilisk Modules
All the existing BSK 1.x messaging functionality exists with the new BSK 2.0 messaging system. This facilitates the migration to 2.0 as it requires some commands to be changed, but none of the code logic should have to change. As before, the message interfaces vary between C and C++ modules.
Changed Importing of Some Files
If your module uses:
#include "simulation/simFswInterfaceMessages/macroDefinitions.h"
this file has now moved to:
#include "architecture/utilities/macroDefinitions.h"
Further, all includes should be done relative to the Basilisk/src
directory. This means:
#include "sensors/magnetometer/magnetometer.h"
should be changed to:
#include "simulation/sensors/magnetometer/magnetometer.h"
Updating a C Module
Updating the
module.h
file:Remove the import of the C interface to the old messaging system, delete this line
#include "messaging/static_messaging.h"
The message wrappers being included below replace this step.
Update the
#include
statement to read in the message definition through#include "cMsgCInterface/ModuleMsg_C.h"
This import provides access to the message object as well as the C message structure definition.
Replace the
char
message name variablemoduleOutMsgName
and associatedint_32t
message ID variablemoduleOutMsgId
withModuleMsg_C moduleOutMsg; // sensor output message ModuleMsg_C moduleInMsg; // sensor input message
Note that the
Fsw
,Int
andSim
message distinctions are now dropped in the new messaging system. This step is the same regardless if this message connects to/from a C or C++ Basilisk module.If you want to create an array of output messages, this can be done with
SomeMsg_C descriptionOutMsgs[10];
Remove the
CrossInit_xxxx()
method, it is no longer used. If you initialized any code in this function, move that code to the moduleReset_xxxx()
function.Clean up the
SelfInit_xxxx()
method to only initialize the output messages. All other code and setup should be moved to theReset_xxxx()
function.
Updating the
module.c
file:To initialize the module output message in
SelfInit_xxxx()
, replaceconfigData->moduleOutMsgId = CreateNewMessage(configData->moduleOutMsgName, sizeof(ModuleFswOutMsg), "ModuleFswOutMsg", moduleID);
with
ModuleMsg_C_init(&configData->moduleOutMsg);
To check if an output message has been linked to other input message, use
ModuleMsg_C_isLinked(&configData->moduleOutMsg);
To connect to an input message, delete
configData->moduleInMsgId = subscribeToMessage(configData->moduleInMsgName, sizeof(ModuleFswMsg), moduleID);
The input messages are connected when then Basilisk simulation is scripted in python. No additional code is required in your C code. Remove the
CrossInit_xxxx()
method, it is no longer used. If you initialized any code in this function, move that code to the moduleReset_xxxx()
function.To create a local variable of the message content structure (payload) itself, use
ModuleMsgPayload msgBuffer;
To read in a message, replace
ModuleFswMsg msgBuffer; memset(&msgBuffer, 0x0, sizeof(ModuleFswMsg)); ReadMessage(configData->moduleInMsgId, &timeOfMsgWritten, &sizeOfMsgWritten, sizeof(ModuleFswMsg), (void*) &(sc), msgBuffer);
with
ModuleMsgPayload msgBuffer; msgBuffer = ModuleMsg_C_read(&configData->moduleInMsg);
To check is a message has been connected to, check the value of
ModuleMsg_C_isLinked()
To check if a message has ever been written to, check the value of
ModuleMsg_C_isWritten()
To get the time when a message was written, use
ModuleMsg_C_timeWritten()
To get the ID of the module who wrote the message, use
ModuleMsg_C_moduleID()
To zero a message payload variable
someMsgBuffer
of typeSomeMsgPayload
, while enjoying strong type checking, you can remove the use ofmemset()
and use insteadSomeMsgPayload someMsgBuffer; someMsgBuffer = SomeMsg_C_zeroMsgPayload();
To write to an output message, assuming
outputMsgBuffer
is a local variable holding the message content (payload), replacememset(&outputMsgBuffer, 0x0, sizeof(ModuleFswMsg)); outputMsgBuffer.variable = 42; // specify output msg values WriteMessage(configData->moduleOutMsgId, callTime, sizeof(ModuleIntMsg), (void*) &(outputMsgBuffer), moduleID);
with
outputMsgBuffer = ModuleMsg_C_zeroMsgPayload(); outputMsgBuffer.variable = 42; // specify output msg values ModuleMsg_C_write(&outputMsgBuffer, &configData->moduleOutMsg, moduleID, callTime);
Note that you should still zero the local
outputMsgBuffer
structure in C Modules such that the message has zero default values if some fields are note set.
Updating the
module.i
file:In the
GEN_SIZEOF()
commands used to be used to get the size of a message in Python. This is no longer required with the new message system. Thus, theseGEN_SIZEOF()
commands can be removed. To create and access messages from Python themessage2
package is now used.Update the
#include
statement and add thestruct
statement to read%include "architecture/msgPayloadDefC/ModuleMsgPayload.h" struct ModuleMsg_C;
Any custom Swig’d interfaces to access message content, such as
ARRAYASLIST(FSWdeviceAvailability)
should be removed from the
module.i
file and moved tosrc/architecture/messaging/messaging.i
file instead. These interfaces can now be used by any module by importingmessages2
in the Basilisk python script.If you want to create an array of output messages
SomeMsg_C
, the array of messages must be swig’d to be accessible from python. In the module*.i
file, add this statementSTRUCTASLIST(SomeMsg_C)
The location of
swig_common_model
has moved toarchitecture
. Thus, replace:from Basilisk.simulation.swig_common_model import *
with:
from Basilisk.architecture.swig_common_model import *
Updating the
module.rst
documentation file:In the table of module messages, update any message variable names that were changed as well as the message definition from
SomeFswMsgPayload
toSomeMsgPayload
.If applicable, update the module msg I/O illustration
Updating a C++ Module
Updating the
module.h
file:Update the
#include
statement to read in a C message definition through#include "architecture/msgPayloadDefC/SomeMsgPayload.h"
To include a C++ message definition use
#include "architecture/msgPayloadDefCpp/SomeMsgPayload.h"
Replace the include statement for the old message system
#include "architecture/messaging/system_messaging.h"
with the include for the new message system
#include "architecture/messaging/messaging.h"
Remove both the
SelfInit()
andCrossInit()
methods, they are longer used. If you initialized any code in these functions, move that code to the moduleReset()
method.For output messages, replace the
std::string
message name variablemoduleOutMsgName
and associatedint_32t
message ID variablemoduleOutMsgId
with thepublic
variable:Message<OutputMsgPayload> moduleOutMsg; //!< sensor output message
This creates an instance of the output message object that is contained within this module.
For input messages, replace the
std::string
message name variablemoduleInMsgName
and associatedint_32t
message ID variablemoduleInMsgId
with thepublic
functor:ReadFunctor<InputMsgPayload> moduleInMsg; //!< sensor input message
It is possible to create a vector of output message pointers of type
SomeMsgPayload
usingstd::vector<Message<SomeMsgPayload>*> descriptionOutMsgs;
Similarly, you can create a vector of input message reader objects of type
SomeMsgPayload
using the following statement. Note that you can directly create message reader instances, and not pointers to such objects as with a vector of output messages.std::vector<ReadFunctor<SomeMsgPayload>> descriptionInMsgs;
Updating the
module.cpp
file:There is no need for additional code to create an output connector. Thus, delete old message creation code such as:
this->moduleOutMsgId = SystemMessaging::GetInstance()->CreateNewMessage(this->moduleOutMsgName, sizeof(ModuleSimMsg), this->numOutMsgBuffers, "ModuleSimMsg", this->moduleID);
The new message object is automatically created through the above process in the
module.h
file. In fact, deleted theSelfInit()
method as it is no longer needed with C++ modules. The output message object automatically connect to themselves in their constructors. Any other code in theSelfInit()
method should be moved to theReset()
method.If a
std::vector
of output message pointers of typeSomeMsgPayload
was created in the module*.h
file then these message objects must be created dynamically in the*.cpp
code usingMessage<SomeMsgPayload> *msg; msg = new Message<SomeMsgPayload>; this->descriptionOutMsgs.push_back(msg);
Don’t forget to delete these message allocation in the module deconstructor.
If you have a
std::vector
of input message objects, these are typically provided to the BSK module in Python through a support function. For example, consider the case where the module has a vector of planet state input messages that can be configured. The methodaddPlanet()
then receives the message object pointer as shown below. Next, the vectorplanetInMsgs
must have a reader to the provided message object added. The message method.addSubscriber()
returns a reader object, essentially an input message linked to this output message. The code below assumes the module also has astd::vector
of the planet state payload structure to act as the input buffer variables. ThisaddPlanet
routine below creates such buffer variables and adds them to theplanetMsgData
vector each time a planet is added.void BskModuleName::addPlanet(Message<SpicePlanetStateMsgPayload> *planetSpiceMsg) { /* add a message reader to the vector of input messages */ this->planetInMsgs.push_back(planetSpiceMsg->addSubscriber()); /* expand the planet state input buffer vector */ SpicePlanetStateMsgPayload plMsg; this->planetMsgData.push_back(plMsg); }
To check is an output message has been connected to, check the value of
this->moduleOutMsg.isLinked()
To subscribe to an input message, this is now accomplished in the Basilisk Python script where the message to module connections are setup now. Thus, delete code such as this:
this->moduleInMsgID = SystemMessaging::GetInstance()->subscribeToMessage(this->moduleInMsgName, sizeof(ModuleFswMsg), moduleID);
Remove the
CrossInit()
method, it is longer used. If you initialized any code in this method, move that code to the moduleReset()
method.To read an input message, replace old code such as:
InputFswMsg moduleInMsgBuffer; memset(&moduleInMsgBuffer, 0x0, sizeof(InputFswMsg)); this->moduleInMsg = SystemMessaging::GetInstance()->ReadMessage(this->moduleInMsgID, &LocalHeader, sizeof(InputFswMsg), reinterpret_cast<uint8_t*> (&(moduleInMsgBuffer)), moduleID);
with this new code:
InputMsgPayload moduleInMsgBuffer; moduleInMsgBuffer = this->moduleInMsg();
Take a moment to marvel at the simplicity of this message reading!
To check is an input message has been connected to, check the value of
this->moduleInMsg.isLinked()
To check if a message has ever been written to, check the value of
this->moduleInMsg.isWritten()
To get the time when a message was written, use
this->moduleInMsg.timeWritten()
To get the ID of the module who wrote the message, use
this->moduleInMsg.moduleID()
To zero a local message structure variable
someMsgBuffer
of typeSomeMsgPayload
, remove the use ofmemset()
and rather use the following. If the msg buffer variable is for use with an output messagesomeOutMsg
, then useSomeMsgPayload someMsgBuffer; someMsgBuffer = this->someOutMsg.zeroMsgPayload;
If the buffer is related to an input message
someInMsg
, the same basic syntax works. Just replacesomeOutMsg
withsomeInMsg
above. This ensures the correct message type is zero’d and assigned to the local buffer variable.To write to an output message, replace this old code:
SystemMessaging::GetInstance()->WriteMessage(this->moduleOutMsgId, clockTime, sizeof(OutputSimMsg), reinterpret_cast<uint8_t*> (&outMsgBuffer), this->moduleID);
with this new code:
this->moduleOutMsg.write(&outMsgBuffer, this->moduleID, clockTime);
Again, stop and marvel.
Updating the
module.i
file:The location of
swig_common_model
has moved toarchitecture
. Thus, replace:from Basilisk.simulation.swig_common_model import *
with:
from Basilisk.architecture.swig_common_model import *
In the
GEN_SIZEOF()
commands used to be used to get the size of a message in Python. This is no longer required with the new message system. Thus, theseGEN_SIZEOF()
commands can be removed. To create and access messages from Python themessage2
package is now used.Update the C message definition include statement from
%include "simMessages/OutputSimMsg.h"
to use the new common message folder location
%include "architecture/msgPayloadDefC/OutputMsgPayload.h" struct OutputMsg_C;
If including a C++ message payload definition, then only use:
%include "architecture/msgPayloadDefCpp/OutputMsgPayload.h"
Any custom Swig’d interfaces to access message content, such as
%template(RWConfigVector) vector<RWConfigSimMsg>;
should be removed the
module.i
file and moved tosrc/architecture/messaging/messaging.i
file instead. These interfaces can now be used by any module by importingmessaging
in the Basilisk python script.To create the swig interface to a vector of output message pointers of type
SomeMsgPayload
, near the bottom of themessaging.i
file add this line:%template(SomeOutMsgsVector) std::vector<Message<SomeMsgPayload>*>;
Updating the
module.rst
documentation file:In the table of module messages, update any message variable names that were changed as well as the message definition from
SomeFswMsgPayload
toSomeMsgPayload
.If applicable, update the module msg I/O illustration
If there are links to message types in the source method descriptions, update these to use the new message payload declaration.