Class: OpenC3::PreidentifiedProtocol

Inherits:
BurstProtocol show all
Defined in:
lib/openc3/interfaces/protocols/preidentified_protocol.rb

Overview

Delineates packets using the OpenC3 preidentification system

Constant Summary collapse

COSMOS4_STORED_FLAG_MASK =
0x80
COSMOS4_EXTRA_FLAG_MASK =
0x40

Instance Attribute Summary

Attributes inherited from Protocol

#allow_empty_data, #extra, #interface

Instance Method Summary collapse

Methods inherited from BurstProtocol

#handle_sync_pattern, #log_discard, #read_data

Methods inherited from Protocol

#connect_reset, #disconnect_reset, #post_write_interface, #protocol_cmd, #read_data, #read_protocol_input_base, #read_protocol_output_base, #write_protocol_input_base, #write_protocol_output_base

Constructor Details

#initialize(sync_pattern = nil, max_length = nil, _unused = nil, allow_empty_data = nil) ⇒ PreidentifiedProtocol

Returns a new instance of PreidentifiedProtocol.

Parameters:

  • max_length (Integer) (defaults to: nil)

    The maximum allowed value of the length field

  • _unused (Integer) (defaults to: nil)

    Legacy version number - unused

  • allow_empty_data (true/false/nil) (defaults to: nil)

    See Protocol#initialize

  • sync_pattern (String) (defaults to: nil)

    String representing a hex number ("0x1234") that will be searched for in the raw data. Bytes encountered before this pattern is found are discarded.



35
36
37
38
39
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 35

def initialize(sync_pattern = nil, max_length = nil, _unused = nil, allow_empty_data = nil)
  super(0, sync_pattern, false, allow_empty_data)
  @max_length = ConfigParser.handle_nil(max_length)
  @max_length = Integer(@max_length) if @max_length
end

Instance Method Details

#read_detailsObject



213
214
215
216
217
218
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 213

def read_details
  result = super()
  result['max_length'] = @max_length
  result['reduction_state'] = @reduction_state
  return result
end

#read_length_field_followed_by_string(length_num_bytes) ⇒ Object

protected



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 100

def read_length_field_followed_by_string(length_num_bytes)
  # Read bytes for string length
  return :STOP if @data.length < length_num_bytes

  string_length = @data[0..(length_num_bytes - 1)]

  case length_num_bytes
  when 1
    string_length = string_length.unpack('C')[0] # UINT8
  when 2
    string_length = string_length.unpack('n')[0] # UINT16
  when 4
    string_length = string_length.unpack('N')[0] # UINT32
    raise "Length value received larger than max_length: #{string_length} > #{@max_length}" if @max_length and string_length > @max_length
  else
    raise "Unsupported length given to read_length_field_followed_by_string: #{length_num_bytes}"
  end

  # Read String
  return :STOP if @data.length < (string_length + length_num_bytes)

  next_index = string_length + length_num_bytes
  string = @data[length_num_bytes..(next_index - 1)]

  # Remove data from current_data
  @data.replace(@data[next_index..-1])

  return string
end

#read_packet(packet) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 46

def read_packet(packet)
  packet.received_time = @read_received_time
  packet.target_name = @read_target_name
  packet.packet_name = @read_packet_name
  packet.stored = @read_stored
  if packet.extra and @read_extra
    packet.extra.merge(@read_extra)
  else
    packet.extra = @read_extra
  end
  return packet
end

#reduce_to_single_packetObject



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 130

def reduce_to_single_packet
  # Discard sync pattern if present
  if @sync_pattern
    if @reduction_state == :START
      return :STOP if @data.length < @sync_pattern.length

      @data.replace(@data[(@sync_pattern.length)..-1])
      @reduction_state = :SYNC_REMOVED
    end
  elsif @reduction_state == :START
    @reduction_state = :SYNC_REMOVED
  end

  if @reduction_state == :SYNC_REMOVED
    # Read and remove flags
    return :STOP if @data.length < 1

    flags = @data[0].unpack('C')[0] # byte
    @data.replace(@data[1..-1])
    @read_stored = false
    @read_stored = true if (flags & COSMOS4_STORED_FLAG_MASK) != 0
    @read_extra = nil
    if (flags & COSMOS4_EXTRA_FLAG_MASK) != 0
      @reduction_state = :NEED_EXTRA
    else
      @reduction_state = :FLAGS_REMOVED
    end
  end

  if @reduction_state == :NEED_EXTRA
    # Read and remove extra
    @read_extra = read_length_field_followed_by_string(4)
    return :STOP if @read_extra == :STOP

    @read_extra = JSON.parse(@read_extra, allow_nan: true, create_additions: true)
    @reduction_state = :FLAGS_REMOVED
  end

  if @reduction_state == :FLAGS_REMOVED
    # Read and remove packet received time
    return :STOP if @data.length < 8

    time_seconds = @data[0..3].unpack('N')[0] # UINT32
    time_microseconds = @data[4..7].unpack('N')[0] # UINT32
    @read_received_time = Time.at(time_seconds, time_microseconds).sys
    @data.replace(@data[8..-1])
    @reduction_state = :TIME_REMOVED
  end

  if @reduction_state == :TIME_REMOVED
    # Read and remove the target name
    @read_target_name = read_length_field_followed_by_string(1)
    return :STOP if @read_target_name == :STOP

    @reduction_state = :TARGET_NAME_REMOVED
  end

  if @reduction_state == :TARGET_NAME_REMOVED
    # Read and remove the packet name
    @read_packet_name = read_length_field_followed_by_string(1)
    return :STOP if @read_packet_name == :STOP

    @reduction_state = :PACKET_NAME_REMOVED
  end

  if @reduction_state == :PACKET_NAME_REMOVED
    # Read packet data and return
    packet_data = read_length_field_followed_by_string(4)
    return :STOP if packet_data == :STOP

    @reduction_state = :START
    return packet_data, @extra
  end

  raise "Error should never reach end of method #{@reduction_state}"
end

#resetObject



41
42
43
44
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 41

def reset
  super()
  @reduction_state = :START
end

#write_data(data, extra = nil) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 78

def write_data(data, extra = nil)
  data_length = [data.length].pack('N') # UINT32
  data_to_send = ''
  data_to_send << @sync_pattern if @sync_pattern
  data_to_send << @write_flags
  if @write_extra
    data_to_send << [@write_extra.length].pack('N')
    data_to_send << @write_extra
  end
  data_to_send << @write_time_seconds
  data_to_send << @write_time_microseconds
  data_to_send << @write_target_name.length
  data_to_send << @write_target_name
  data_to_send << @write_packet_name.length
  data_to_send << @write_packet_name
  data_to_send << data_length
  data_to_send << data
  return data_to_send, extra
end

#write_detailsObject



207
208
209
210
211
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 207

def write_details
  result = super()
  result['max_length'] = @max_length
  return result
end

#write_packet(packet) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/openc3/interfaces/protocols/preidentified_protocol.rb', line 59

def write_packet(packet)
  received_time = packet.received_time
  received_time = Time.now unless received_time
  @write_time_seconds = [received_time.tv_sec].pack('N') # UINT32
  @write_time_microseconds = [received_time.tv_usec].pack('N') # UINT32
  @write_target_name = packet.target_name
  @write_target_name = 'UNKNOWN' unless @write_target_name
  @write_packet_name = packet.packet_name
  @write_packet_name = 'UNKNOWN' unless @write_packet_name
  @write_flags = 0
  @write_flags |= COSMOS4_STORED_FLAG_MASK if packet.stored
  @write_extra = nil
  if packet.extra
    @write_flags |= COSMOS4_EXTRA_FLAG_MASK
    @write_extra = packet.extra.as_json().to_json(allow_nan: true)
  end
  return packet
end