Module Definition File

The module function is defined in the SomeModule.cpp file. This page outlines key expected behaviors.

Constructor

The constructor ensure that all class variables that require default values are setup correctly. For example, in the tutorial SomeModule class we are using in this documenation, assume the class variable dummy must be 42 be default. This is done using:

/*! Module Constructor */
SomeModule::SomeModule()
{
    self->dummy = 42.0;
}

Instead of declaring default values in the constructor, this can also be done in the module *.h file by using the default value in the variable definition.

Destructor

The module destructor should ensure the module is closed down properly. It might have to close a file handle, or free up the memory of dynamically allocated message objects to a vector of output messages.

Reset Method

The Reset() method should be used to

  • Restore module variables if needed. For example, the integral feedback gain variable might be reset to 0.

  • Perform one-time message reads such as reading in the reaction wheel or spacecraft configuration message. etc. Whenever Reset() is called the module should read in these messages again to use the latest values.

  • Check that required input messages are connected. If a required input message is not connected when Reset() is called, then log a BSK error message.

  • Ensure that required variables are set to acceptable values. For example, assume the gain variable is defaulted to zero. The Reset() method would check that the gain value is no longer the default value.

The following sample code assumes that the class variable value should be re-set to 0 on Reset(), and that someInMsg is a required input message:L

/*! Reset the module.
 @return void
 */
void SomeModule::Reset(uint64_t CurrentSimNanos)
{
    this->value = 0.0;

    if (!this->someInMsg.isLinked()) {
        bskLogger.bskLog(BSK_ERROR, "SomeModule does not have someInMsg connected!");
    }

    if (this->gain <= 0) {
        bskLogger.bskLog(BSK_ERROR, "The required gain value was not set to a positive value.");
    }
}

Update Method

The UpdateState() is the method that is called each time the Basilisk simulation runs the module. This method needs to perform all the required BSK module function, including reading in input messages and writing to output messages. In the sample code below the message reading and writing, as well as the module function is done directly within this UpdateState() method. Some modules also create additional class method to separate out the various functions. This is left up to the module developer as a code design choice.

void CppModuleTemplate::UpdateState(uint64_t CurrentSimNanos)
{
    SomeMsgPayload outMsgBuffer;       /*!< local output message copy */
    SomeMsgPayload inMsgBuffer;        /*!< local copy of input message */

    // always zero the output buffer first
    outMsgBuffer = this->dataOutMsg.zeroMsgPayload;

    /*! - Read the input messages */
    inMsgBuffer = this->dataInMsg();

    /* As an example of a module function, here we simply copy input message content to output message. */
    v3Copy(inMsgBuffer.dataVector, outMsgBuffer.dataVector);

    /*! - write the module output message */
    this->dataOutMsg.write(&outMsgBuffer, this->moduleID, CurrentSimNanos);
}

Warning

It is critical that each module zeros the content of the output messages on each update cycle. This way we are not writing stale or uninitialized data to a message. When reading a message BSK assumes that each message content has been either zero’d or written to.

Vector of Input/Output Messages

If the module contains a vector of input messages called moreInMsgs, you most likely will need to write a public method for the user to add input reader message objects to this vector variables. Below a sample addMsgToModule() method is illustrated that receives a pointer to a message object, stores a copy of the reader object to this message in the standard vector, and expands the vector of read message value buffer with a new message paylod copy.

/*! Method description
 @param tmpMsg The message object pointer
 @return void
 */
void SomeModule::addMsgToModule(Message<SomeMsgPayload> *tmpMsg)
{
    /* add the message reader to the vector of input messages */
    this->moreInMsgs.push_back(tmpMsg->addSubscriber());

    /* expand vector of message data copies with another element */
    SomeMsgPayload tmpMsg;
    this->moreInMsgsBuffer.push_back(tmpMsg);

    /* create output message */
    Message<SomeMsgPayload> *msg;
    msg = new Message<SomeMsgPayload>;
    this->moreOutMsgs.push_back(msg);
}

If the module contains a vector of output messages, then a public module method needs to be written to create these output vector message instances. The above sample code illustrate a common scenario where the number of input and output messages is the same. For example, in Module: eclipse for each spacecraft state input message added a corresponding eclipse output message must be created.

Note that with the new call above the memory associated with this output message object instance is retained after the method is exited. In this case the module deconstructor needs to free up the associated message memory. For the above example this could be done using:

SomeModule::~SomeModule()
{
    for (long unsigned int c=0; c<this->moreOutMsgs.size(); c++) {
        delete this->moreOutMsgs.at(c);
    }
}

Setters

Assume the module has a user configurable variable called gain. This variable should be a private variable and be set through the setGain() method. If possible, the setter method should check that valid values are provided or throw an error.