nasa / fprime

F´ - A flight software and embedded systems framework
https://fprime.jpl.nasa.gov
Apache License 2.0
9.95k stars 1.28k forks source link

toString doesn't display the last item in a struct #2748

Open ReggieMarr opened 1 month ago

ReggieMarr commented 1 month ago
F` version v3.1.1
****

Problem Description

Files generated by fpp tools doesn't produce the format string correctly and so the last member of a string doesn't show up as expected. For example

The take the following struct defined in fpp:

  enum CMD_STATUS : U16 {
    NA = 0,
    ACK = 0x5,
    NOT_ACK = 0x6,
    BUSY = 0x7,
    NCE = 0x8,
    STACK_FULL = 0x9,
    TEMP_NOT_ACC = 0x10
  };

  constant ESUP_HEADER_ID = 0x50555345

# NOTE that in byte form it will be represented with LE
  struct EsupPacketHeader {
    HeaderId: U32
    ModuleId: U16
    DataLength: U16
    CmdStatus: CMD_STATUS
  } default {HeaderId = ESUP_HEADER_ID, CmdStatus=CMD_STATUS.NA}

    struct EsupStatusGet {
        Header: EsupPacketHeader
        CmdId: EsupCmdId
        TypeId: U16
        SystemState: U8 @< 1,2,3,4 (1 byte unsigned char value)
        StatusFlags: U8 @< 1 byte unsigned char value
        Reserved: U16 @< 2 byte unsigned short value
        CpuTemperature: F32 @< -40 to 125 °C (4 byte float value)
        FirmwareVersion: U32 @< firmware version (4 byte unsigned int value)
    } default {CmdId = EsupCmdId.ConfGet, TypeId = EsupCmdType.StatusRep}

I then go to print out the contents like so:

static bool receiveEsupStatusResponse(int serialPort, EsupCmdId cmdId, boost::span<BYTE, GET_PADDED_SIZE(EsupStatusGet::SERIALIZED_SIZE)> txBuff) {
        // Wait for a reply
        EsupStatusGet cmdResult;

        size_t bytesRead = read(serialPort, txBuff.data(), txBuff.size());
        if (bytesRead > 0) {
            FW_CHECK(bytesRead <= txBuff.size(), "Error deserializing response", return false; );
            LE_ExternalDeSerializeBuffer responseBuff(txBuff.data(), bytesRead);
            cmdResult.deserialize(responseBuff);
            Fw::String ackString;
            cmdResult.toString(ackString);
            std::cout << std::string(ackString.toChar()) << std::endl;
        } else {
            std::cout << "No reply received." << std::endl;
        }

        return true;
  }

I get the following:

(Header = (HeaderId = 1347769157, ModuleId = 8203, DataLength = 0, CmdStatus = ), CmdId = ConfGet, TypeId = 0, SystemState = 162, StatusFlags = 187, Reserved = 53517, CpuTemperature = 0, FirmwareVersion = )

Where I would normally expect to see something like this (the actual values don't matter for these purposes just that there is something to print):

(Header = (HeaderId = 1347769157, ModuleId = 8203, DataLength = 0, CmdStatus = ACK ), CmdId = ConfGet, TypeId = 0, SystemState = 162, StatusFlags = 187, Reserved = 53517, CpuTemperature = 0, FirmwareVersion = 102444)

I've found this is consistent across pretty much all the fpp serializable objects and it really comes down to the last member of the struct doesn't have a format string generated along with it

So for example we see with the header type the following gets generated:

void EsupPacketHeader::toString(Fw::StringBase& text) const {

    static const char * formatString =
       "("
       "HeaderId = %u, "
       "ModuleId = %u, "
       "DataLength = %u, "
       "CmdStatus = "
       ")";

    // declare strings to hold any serializable toString() arguments

    Fw::String CmdStatusStr;
    this->m_CmdStatus.toString(CmdStatusStr);

    char outputString[FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE];
    (void)snprintf(outputString,FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE,formatString
       ,this->m_HeaderId
       ,this->m_ModuleId
       ,this->m_DataLength
       ,CmdStatusStr.toChar()
    );
    outputString[FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE-1] = 0; // NULL terminate

    text = outputString;
}

With the CmdStatus missing the "%s".

I'm not really sure what the source of the error is since the xml seems to be fine:

<serializable namespace="FlightComputer" name="EsupPacketHeader">
  <import_enum_type>FlightComputer/TransmitterInterface/CMD_STATUSEnumAi.xml</import_enum_type>
  <members>
    <member name="HeaderId" type="U32" format="%u">
      <default>1347769157</default>
    </member>
    <member name="ModuleId" type="U16" format="%u">
      <default>0</default>
    </member>
    <member name="DataLength" type="U16" format="%u">
      <default>0</default>
    </member>
    <member name="CmdStatus" type="FlightComputer::CMD_STATUS" format="%s">
      <default>FlightComputer::CMD_STATUS::NA</default>
    </member>
  </members>
</serializable>

I took a look in array_cpp.py and array_cpp.tmpl but couldn't make sense of the issue there.

If I can get some help on this that'd be much appreciated.