BallAerospace / COSMOS

Ball Aerospace COSMOS
https://ballaerospace.github.io/cosmos-website/
Other
360 stars 129 forks source link

Using enumerations in XTCE results in incorrectly-encoded values in output #768

Closed lenlope closed 4 years ago

lenlope commented 6 years ago

In my XTCE file, I have the following enum type definition:

<xtce:EnumeratedArgumentType name="LogLevelType">
     <xtce:BinaryDataEncoding>
     <xtce:SizeInBits>
        <xtce:FixedValue>8</xtce:FixedValue>
     </xtce:SizeInBits>
    </xtce:BinaryDataEncoding>
    <xtce:EnumerationList>
    <xtce:Enumeration value="0"   label="NONE" />
    <xtce:Enumeration value="1"   label="ERROR" />
    <xtce:Enumeration value="2"   label="WARN" />
    <xtce:Enumeration value="3"   label="INFORM" />
    <xtce:Enumeration value="4"   label="DEBUG" />
    <xtce:Enumeration value="5"   label="TRACE" />
    <xtce:Enumeration value="6"   label="INVALID" />
    <xtce:Enumeration value="255" label="RESERVED255" />
    </xtce:EnumerationList>
</xtce:EnumeratedArgumentType>

And the following command definition which uses this enum:

<xtce:MetaCommand name="SetLogLevel">   
    <xtce:ArgumentList>
        <xtce:Argument name="LogLevel" argumentTypeRef="LogLevelType"/>
    </xtce:ArgumentList>                      
    <xtce:CommandContainer name="SetLogLevel">
        <xtce:EntryList>       
        <xtce:ArgumentRefEntry argumentRef="LogLevel" />
    </xtce:EntryList>
    </xtce:CommandContainer>                         
</xtce:MetaCommand>

When I use Command Sender to send the above command with the "LogLevel" value as 5 (TRACE), it does not seem to encode the value correctly as observed in Wireshark. These are the outputs I see:

In Command Sender: cmd("POLARIS SETLOGLEVEL with LOGLEVEL 'TRACE'")

In Wireshark (hex): 35 (the byte value is expected to be "05" instead)

So as a result, my payload controller does not recognize the command argument. So I have to resort to using an integer type for the "LogLevel" argument instead, which is not desired.

ghost commented 6 years ago

I implemented your XTCE definition directly and COSMOS parsed the states correctly, i.e. "TRACE" => 5. However, hex 35 is ASCII '5' so it seems like maybe your definition is not being treated as an integer but instead interpreted as ASCII. I don't see that when I parse your definition above but check that you aren't creating strings somewhere.

lenlope commented 6 years ago

Hi Jason, I think I figured out the source of the issue, but I'm not sure how to go about solving it. So I do have a custom protocol which overrides both write_data() and write_packet(), which I think may be muddling things. write_data() works like thus: It creates a temp buffer, adds a few custom bytes to it, and then simply iterates over each byte in the "data" argument and copies them into temp buffer. Finally, "data" is replaced by the contents of the temp buffer. write_packet() is a little more involved: Again, it creates a temp buffer, and then iterates over each byte in the "packet.buffer" argument. Some bytes are copied straight into temp buffer whereas other bytes need to be encoded a certain way. And finally as before, "packet.buffer" is replaced by the contents of the temp buffer. However as a note, the log level argument is not one of these bytes that needs to be transformed; it just gets copied. The issue that I'm seeing is, right off the bat, the "data" argument in write_packet() is a string, and when I do a puts of each byte in the string, I can see that the log level argument of 5 appears as "5" rather than the byte 0x05. For some reason, this issue does not present itself when the field type is an integer rather than an enum in Command Sender.

ghost commented 6 years ago

I'd recommend you read the Packet class documentation if you haven't already: http://cosmosrb.com/docs/packet_class/. There are various ways of pulling information out of a packet. The default read method returns the converted value which would be a String. You probably want the raw value.

lenlope commented 6 years ago

This is helpful information, and I think it would work for use in my write_data() method, where I don't need to twiddle the data at the raw byte level. But in write_packet(), I do need to operate at that level. In that, I was using "the string containing the raw binary buffer." I believe where I'm running into trouble is when I convert that string to a raw byte array, twiddle some bytes, and convert it back to a string. I may be making incorrect assumptions on the content/format of the string, so do you have any advice on how I could proceed with this approach?

lenlope commented 6 years ago

I also want to add that I just did a quick sanity check where I completely ripped out all special processing in the write_packet() and write_data() methods in my custom protocol class so that they simply return the "packet" and/or "data" argument passed in. And I'm still seeing the value of "TRACE (5)" being encoded as 0x35 in Wireshark.

ghost commented 6 years ago

@lenlope did you ever solve this?

lenlope commented 6 years ago

Hi @jasonatball , No I have not done anything further than in my last comment. I've boiled it down to the bare minimum where it's just returning the same packet/data string being passed in- not sure what else to try.

ghost commented 6 years ago

@ryanatball Do you have any suggestions?

lenlope commented 6 years ago

I guess the most direct way is to use my aforementioned enum and command definition, issue it in Command Sender, and monitor the raw output in Wireshark or even in View Raw in COSMOS. The key is that I had a custom protocol defined for reads and writes. Here it is presented in its simplest form:

` require 'cosmos/packets/binary_accessor' require 'cosmos/interfaces/protocols/protocol' require 'cosmos/config/config_parser'

module Cosmos class MyProtocol < Protocol

def initialize(allow_empty_data = nil)
  super(allow_empty_data)
end

def read_packet(packet)
  return packet
end

def read_data(data)
  return data
end

def write_packet(packet)
  return packet
end

def write_data(data)
  return data
end

end end `

Now obviously my real custom protocol does more stuff in write_packet() and write_data(), so my initial suspicion was maybe I wasn't manipulating the packet and data arguments correctly. But with the above, I can even reproduce the enum encoding error (a value of TRACE or 5 in Command Sender shows up as 0x35). I suppose I could try it and see what happens if I don't have this custom protocol layer at all. But as Jason alluded to above, I can confirm that I'm not "creating strings" anywhere else.

ghost commented 4 years ago

Hopefully you figured this out.