Class: Cosmos::BurstProtocol

Inherits:
Protocol show all
Defined in:
lib/cosmos/interfaces/protocols/burst_protocol.rb

Overview

Reads all data available on the interface and creates a packet with that data.

Instance Attribute Summary

Attributes inherited from Protocol

#allow_empty_data, #interface

Instance Method Summary collapse

Methods inherited from Protocol

#connect_reset, #disconnect_reset, #post_write_interface, #read_packet

Constructor Details

#initialize(discard_leading_bytes = 0, sync_pattern = nil, fill_fields = false, allow_empty_data = nil) ⇒ BurstProtocol

Returns a new instance of BurstProtocol.

Parameters:

  • discard_leading_bytes (Integer) (defaults to: 0)

    The number of bytes to discard from the binary data after reading. Note that this is often used to remove a sync pattern from the final packet data.

  • 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.

  • fill_fields (Boolean) (defaults to: false)

    Fill any required fields when writing packets

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

    See Protocol#initialize



36
37
38
39
40
41
42
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 36

def initialize(discard_leading_bytes = 0, sync_pattern = nil, fill_fields = false, allow_empty_data = nil)
  super(allow_empty_data)
  @discard_leading_bytes = discard_leading_bytes.to_i
  @sync_pattern = ConfigParser.handle_nil(sync_pattern)
  @sync_pattern = @sync_pattern.hex_to_byte_string if @sync_pattern
  @fill_fields = ConfigParser.handle_true_false(fill_fields)
end

Instance Method Details

#handle_sync_patternBoolean

Returns control code (nil, :STOP).

Returns:

  • (Boolean)

    control code (nil, :STOP)



117
118
119
120
121
122
123
124
125
126
127
128
129
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
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 117

def handle_sync_pattern
  if @sync_pattern and @sync_state == :SEARCHING
    loop do
      # Make sure we have some data to look for a sync word in
      return :STOP if @data.length < @sync_pattern.length

      # Find the beginning of the sync pattern
      sync_index = @data.index(@sync_pattern.getbyte(0).chr)
      if sync_index
        # Make sure we have enough data for the whole sync pattern past this index
        return :STOP if @data.length < (sync_index + @sync_pattern.length)

        # Check for the rest of the sync pattern
        found = true
        index = sync_index
        @sync_pattern.each_byte do |byte|
          if @data.getbyte(index) != byte
            found = false
            break
          end
          index += 1
        end

        if found
          if sync_index != 0
            discard_length = @data[0..(sync_index - 1)].length
            log_discard(discard_length, true)
            # Delete Data Before Sync Pattern
            @data.replace(@data[sync_index..-1])
          end
          @sync_state = :FOUND
          return nil

        else # not found
          log_discard(@data[0..sync_index].length, false)
          # Delete Data Before and including first character of suspected sync Pattern
          @data.replace(@data[(sync_index + 1)..-1])
          next
        end # if found

      else # sync_index = nil
        log_discard(@data.length, false)
        @data.replace('')
        return :STOP
      end # unless sync_index.nil?
    end # end loop
  end # if @sync_pattern
  nil
end

#log_discard(length, found) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 167

def log_discard(length, found)
  Logger.error("#{@interface ? @interface.name : ""}: Sync #{'not ' unless found}found. Discarding #{length} bytes of data.")
  if @data.length >= 0
    Logger.error(sprintf("Starting: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
                         @data.length >= 1 ? @data.getbyte(0) : 0,
                         @data.length >= 2 ? @data.getbyte(1) : 0,
                         @data.length >= 3 ? @data.getbyte(2) : 0,
                         @data.length >= 4 ? @data.getbyte(3) : 0,
                         @data.length >= 5 ? @data.getbyte(4) : 0,
                         @data.length >= 6 ? @data.getbyte(5) : 0))
  end
end

#read_data(data) ⇒ String|nil

Reads from the interface. It can look for a sync pattern before creating a Packet. It can discard a set number of bytes at the beginning before creating the Packet.

Returns:

  • (String|nil)

    Data for a packet consisting of the bytes read



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 56

def read_data(data)
  @data << data

  control = handle_sync_pattern()
  return control if control and data.length > 0

  # Reduce the data to a single packet
  packet_data = reduce_to_single_packet()

  # Potentially allow blank string to be sent to other protocols if no packet is ready in this one
  if Symbol === packet_data
    if (data.length <= 0) and packet_data == :STOP
      return super(data)
    else
      return packet_data
    end
  end

  @sync_state = :SEARCHING

  # Discard leading bytes if necessary
  packet_data.replace(packet_data[@discard_leading_bytes..-1]) if @discard_leading_bytes > 0
  packet_data
end

#reduce_to_single_packetObject



180
181
182
183
184
185
186
187
188
189
190
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 180

def reduce_to_single_packet
  if @data.length <= 0
    # Need some data
    return :STOP
  end

  # Reduce to packet data and clear data for next packet
  packet_data = @data.clone
  @data.replace('')
  packet_data
end

#resetObject



44
45
46
47
48
49
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 44

def reset
  super()
  @data = ''
  @data.force_encoding('ASCII-8BIT')
  @sync_state = :SEARCHING
end

#write_data(data) ⇒ String

Called to perform modifications on write data before sending it to the interface

Parameters:

  • data (String)

    Raw packet data

Returns:

  • (String)

    Potentially modified packet data



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 101

def write_data(data)
  # If we're filling the sync pattern and discarding the leading bytes
  # during a read then we need to put them back during a write.
  # If we're discarding the bytes then by definition they can't be part
  # of the packet so we just modify the data.
  if @fill_fields && @discard_leading_bytes > 0
    data = ("\x00" * @discard_leading_bytes) << data
    if @sync_pattern
      BinaryAccessor.write(@sync_pattern, 0, @sync_pattern.length * 8, :BLOCK,
                           data, :BIG_ENDIAN, :ERROR)
    end
  end
  super(data)
end

#write_packet(packet) ⇒ Packet

Called to perform modifications on a command packet before it is sent

Parameters:

  • packet (Packet)

    Original packet

Returns:

  • (Packet)

    Potentially modified packet



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/cosmos/interfaces/protocols/burst_protocol.rb', line 85

def write_packet(packet)
  # If we're filling the sync pattern and the sync pattern is part of the
  # packet (since we're not discarding any leading bytes) then we have to
  # fill the sync pattern in the actual packet so do it here.
  if @fill_fields && @sync_pattern && @discard_leading_bytes == 0
    # Directly write the packet buffer and fill in the sync pattern
    BinaryAccessor.write(@sync_pattern, 0, @sync_pattern.length * 8, :BLOCK,
                         packet.buffer(false), :BIG_ENDIAN, :ERROR)
  end
  packet
end