cosmos 3.1.2 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/Manifest.txt +17 -1
  4. data/autohotkey/tools/test_runner2.ahk +1 -0
  5. data/autohotkey/tools/tlm_grapher.ahk +13 -1
  6. data/data/crc.txt +39 -30
  7. data/demo/config/data/crc.txt +3 -3
  8. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +3 -1
  9. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +7 -1
  10. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +6 -1
  11. data/lib/cosmos.rb +2 -2
  12. data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -5
  13. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +0 -7
  14. data/lib/cosmos/gui/line_graph/overview_graph.rb +12 -2
  15. data/lib/cosmos/gui/utilities/script_module_gui.rb +11 -3
  16. data/lib/cosmos/interfaces/interface.rb +12 -0
  17. data/lib/cosmos/interfaces/stream_interface.rb +1 -21
  18. data/lib/cosmos/interfaces/tcpip_server_interface.rb +10 -0
  19. data/lib/cosmos/io/json_drb_object.rb +75 -56
  20. data/lib/cosmos/io/tcpip_server.rb +1 -11
  21. data/lib/cosmos/packet_logs.rb +1 -0
  22. data/lib/cosmos/packet_logs/ccsds_log_reader.rb +103 -0
  23. data/lib/cosmos/packets/packet.rb +70 -1
  24. data/lib/cosmos/packets/packet_config.rb +59 -611
  25. data/lib/cosmos/packets/parsers/format_string_parser.rb +58 -0
  26. data/lib/cosmos/packets/parsers/limits_parser.rb +146 -0
  27. data/lib/cosmos/packets/parsers/limits_response_parser.rb +52 -0
  28. data/lib/cosmos/packets/parsers/macro_parser.rb +116 -0
  29. data/lib/cosmos/packets/parsers/packet_item_parser.rb +215 -0
  30. data/lib/cosmos/packets/parsers/packet_parser.rb +123 -0
  31. data/lib/cosmos/packets/parsers/processor_parser.rb +63 -0
  32. data/lib/cosmos/packets/parsers/state_parser.rb +116 -0
  33. data/lib/cosmos/packets/structure.rb +59 -22
  34. data/lib/cosmos/packets/structure_item.rb +1 -1
  35. data/lib/cosmos/script/script.rb +4 -5
  36. data/lib/cosmos/streams/serial_stream.rb +5 -0
  37. data/lib/cosmos/streams/stream.rb +8 -2
  38. data/lib/cosmos/streams/stream_protocol.rb +1 -0
  39. data/lib/cosmos/streams/tcpip_client_stream.rb +37 -7
  40. data/lib/cosmos/streams/tcpip_socket_stream.rb +9 -6
  41. data/lib/cosmos/system/target.rb +3 -6
  42. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +57 -48
  43. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +7 -3
  44. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +1 -1
  45. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +7 -1
  46. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +1 -2
  47. data/lib/cosmos/top_level.rb +22 -11
  48. data/lib/cosmos/utilities/message_log.rb +14 -9
  49. data/lib/cosmos/version.rb +5 -5
  50. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +16 -16
  51. data/spec/interfaces/linc_interface_spec.rb +3 -0
  52. data/spec/interfaces/tcpip_client_interface_spec.rb +1 -0
  53. data/spec/interfaces/tcpip_server_interface_spec.rb +9 -0
  54. data/spec/io/json_drb_object_spec.rb +1 -1
  55. data/spec/io/serial_driver_spec.rb +0 -1
  56. data/spec/packet_logs/packet_log_writer_spec.rb +5 -3
  57. data/spec/packets/packet_config_spec.rb +22 -837
  58. data/spec/packets/packet_item_spec.rb +10 -10
  59. data/spec/packets/packet_spec.rb +239 -1
  60. data/spec/packets/parsers/format_string_parser_spec.rb +122 -0
  61. data/spec/packets/parsers/limits_parser_spec.rb +282 -0
  62. data/spec/packets/parsers/limits_response_parser_spec.rb +149 -0
  63. data/spec/packets/parsers/macro_parser_spec.rb +184 -0
  64. data/spec/packets/parsers/packet_item_parser_spec.rb +306 -0
  65. data/spec/packets/parsers/packet_parser_spec.rb +99 -0
  66. data/spec/packets/parsers/processor_parser_spec.rb +114 -0
  67. data/spec/packets/parsers/state_parser_spec.rb +156 -0
  68. data/spec/packets/structure_item_spec.rb +14 -14
  69. data/spec/packets/structure_spec.rb +162 -16
  70. data/spec/streams/fixed_stream_protocol_spec.rb +7 -4
  71. data/spec/streams/length_stream_protocol_spec.rb +3 -0
  72. data/spec/streams/preidentified_stream_protocol_spec.rb +3 -0
  73. data/spec/streams/serial_stream_spec.rb +12 -0
  74. data/spec/streams/stream_protocol_spec.rb +14 -0
  75. data/spec/streams/stream_spec.rb +1 -0
  76. data/spec/streams/tcpip_client_stream_spec.rb +3 -0
  77. data/spec/streams/tcpip_socket_stream_spec.rb +15 -3
  78. data/spec/streams/template_stream_protocol_spec.rb +5 -0
  79. data/spec/streams/terminated_stream_protocol_spec.rb +4 -0
  80. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +21 -1
  81. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +1 -1
  82. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +1 -1
  83. metadata +19 -3
@@ -32,6 +32,7 @@ module Cosmos
32
32
  @filename = ''
33
33
  @file = nil
34
34
  @start_time = nil
35
+ @mutex = Mutex.new
35
36
  end
36
37
 
37
38
  # Ensures the log file is opened and ready to write. It then writes the
@@ -39,34 +40,38 @@ module Cosmos
39
40
  #
40
41
  # @param message [String] Message to write to the log
41
42
  def write(message)
42
- if @file.nil? or @file.closed? or (not File.exist?(@filename))
43
- start()
44
- end
43
+ @mutex.synchronize do
44
+ if @file.nil? or @file.closed? or (not File.exist?(@filename))
45
+ start(false)
46
+ end
45
47
 
46
- @file.write(message)
47
- # While it's nice to flush the IO this is an extreme slowdown
48
- #@file.flush
48
+ @file.write(message)
49
+ end
49
50
  end
50
51
 
51
52
  # Closes the message log and marks it read only
52
- def stop
53
+ def stop(take_mutex = true)
54
+ @mutex.lock if take_mutex
53
55
  if @file and not @file.closed?
54
56
  @file.close
55
57
  Cosmos.set_working_dir do
56
58
  File.chmod(0444, @filename)
57
59
  end
58
60
  end
61
+ @mutex.unlock if take_mutex
59
62
  end
60
63
 
61
64
  # Creates a new message log and sets the filename
62
- def start
65
+ def start(take_mutex = true)
66
+ @mutex.lock if take_mutex
63
67
  # Prevent starting files too fast
64
68
  sleep(0.1) until !File.exist?(File.join(@log_dir, File.build_timestamped_filename([@tool_name, 'messages'])))
65
- stop()
69
+ stop(false)
66
70
  Cosmos.set_working_dir do
67
71
  @filename = File.join(@log_dir, File.build_timestamped_filename([@tool_name, 'messages']))
68
72
  @file = File.open(@filename, 'a')
69
73
  end
74
+ @mutex.unlock if take_mutex
70
75
  end
71
76
 
72
77
  end # class MessageLog
@@ -1,12 +1,12 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- COSMOS_VERSION = '3.1.2'
3
+ COSMOS_VERSION = '3.2.0'
4
4
  module Cosmos
5
5
  module Version
6
6
  MAJOR = '3'
7
- MINOR = '1'
8
- PATCH = '2'
9
- BUILD = '5864bf4376d74014c01d625e46b5aefc843908ba'
7
+ MINOR = '2'
8
+ PATCH = '0'
9
+ BUILD = '29c04013a08ebeab57b88412820e0cd79782c49f'
10
10
  end
11
- VERSION = '3.1.2'
11
+ VERSION = '3.2.0'
12
12
  end
@@ -44,31 +44,31 @@ module Cosmos
44
44
  sleep 0.1 # Give the server time to really stop all the Threads
45
45
  end
46
46
 
47
- specify { @ctsi.methods.should include(:cmd) }
47
+ specify { expect(@ctsi.methods).to include(:cmd) }
48
48
 
49
49
  describe "connect, connected?, disconnect" do
50
- it "should subscribe to the server" do
50
+ it "subscribes to the server" do
51
51
  expect { @ctsi.connect }.to_not raise_error
52
- @ctsi.connected?.should be_truthy
52
+ expect(@ctsi.connected?).to be true
53
53
  expect { @ctsi.disconnect}.to_not raise_error
54
- @ctsi.connected?.should be_falsey
54
+ expect(@ctsi.connected?).to be false
55
55
  end
56
56
  end
57
57
 
58
58
  describe "write_raw_allowed?" do
59
- it "should be false" do
60
- @ctsi.write_raw_allowed?.should be_falsey
59
+ it "returns false" do
60
+ expect(@ctsi.write_raw_allowed?).to be false
61
61
  end
62
62
  end
63
63
 
64
64
  describe "write_raw" do
65
- it "should raise an error" do
65
+ it "raises an error" do
66
66
  expect { @ctsi.write_raw(nil) }.to raise_error(/write_raw not implemented/)
67
67
  end
68
68
  end
69
69
 
70
70
  describe "read" do
71
- it "should first return the COSMOS VERSION packet and then COSMOS LIMITS_CHANGE" do
71
+ it "returns the COSMOS VERSION packet and then COSMOS LIMITS_CHANGE" do
72
72
  @ctsi.connect
73
73
 
74
74
  pkt = Packet.new("TGT","PKT")
@@ -78,25 +78,25 @@ module Cosmos
78
78
  @cts.limits_change_callback(pkt, pi, :RED, 100, true)
79
79
 
80
80
  result = @ctsi.read
81
- result.read('CTDB').should eql "Demo Version"
81
+ expect(result.read('CTDB')).to eql "Demo Version"
82
82
 
83
83
  result = @ctsi.read
84
- result.read('TARGET').should eql "TGT"
85
- result.read('PACKET').should eql "PKT"
86
- result.read('ITEM').should eql "ITEM"
87
- result.read('OLD_STATE').should eql "RED"
88
- result.read('NEW_STATE').should eql "GREEN"
84
+ expect(result.read('TARGET')).to eql "TGT"
85
+ expect(result.read('PACKET')).to eql "PKT"
86
+ expect(result.read('ITEM')).to eql "ITEM"
87
+ expect(result.read('OLD_STATE')).to eql "RED"
88
+ expect(result.read('NEW_STATE')).to eql "GREEN"
89
89
  end
90
90
  end
91
91
 
92
92
  describe "write" do
93
- it "should raise an error if the packet is not identified" do
93
+ it "raises an error if the packet is not identified" do
94
94
  pkt = Packet.new("COSMOS","STARTLOGGING")
95
95
  pkt.buffer = "\x00\x00\x00\x00\x00\x00\x00\x00"
96
96
  expect { @ctsi.write(pkt) }.to raise_error(/Unknown command/)
97
97
  end
98
98
 
99
- it "should raise an error if the command is not recognized" do
99
+ it "raises an error if the command is not recognized" do
100
100
  pkt = Packet.new("COSMOS","DOSOMETHING")
101
101
  pkt.buffer = "\x00\x00\x00\x00\x00\x00\x00\x00"
102
102
  expect { @ctsi.write(pkt) }.to raise_error(/Unknown command/)
@@ -22,6 +22,7 @@ module Cosmos
22
22
  describe "connect" do
23
23
  it "should pass a new TcpipClientStream to the stream protocol" do
24
24
  stream = double("stream")
25
+ allow(stream).to receive(:connect)
25
26
  expect(TcpipClientStream).to receive(:new) { stream }
26
27
  expect(stream).to receive(:connected?) { true }
27
28
  expect(stream).to receive(:raw_logger_pair=) { nil }
@@ -36,6 +37,7 @@ module Cosmos
36
37
  describe "write" do
37
38
  before(:each) do
38
39
  stream = double("stream")
40
+ allow(stream).to receive(:connect)
39
41
  expect(TcpipClientStream).to receive(:new) { stream }
40
42
  allow(stream).to receive(:connected?) { true }
41
43
  allow(stream).to receive(:write)
@@ -159,6 +161,7 @@ module Cosmos
159
161
  describe "read" do
160
162
  before(:each) do
161
163
  stream = double("stream")
164
+ allow(stream).to receive(:connect)
162
165
  expect(TcpipClientStream).to receive(:new) { stream }
163
166
  allow(stream).to receive(:connected?) { true }
164
167
  allow(stream).to receive(:write)
@@ -40,6 +40,7 @@ module Cosmos
40
40
  describe "connect" do
41
41
  it "should pass a new TcpipClientStream to the stream protocol" do
42
42
  stream = double("stream")
43
+ allow(stream).to receive(:connect)
43
44
  expect(TcpipClientStream).to receive(:new) { stream }
44
45
  expect(stream).to receive(:connected?) { true }
45
46
  expect(stream).to receive(:raw_logger_pair=) { nil }
@@ -146,6 +146,15 @@ module Cosmos
146
146
  expect { i.write_raw('') }.to raise_error("TEST")
147
147
  end
148
148
  end
149
+
150
+ describe "set_option" do
151
+ it "should set the listen address for the tcpip_server" do
152
+ expect(@stream).to receive(:listen_address=).with('127.0.0.1')
153
+ i = TcpipServerInterface.new('8888','8889','5','5','burst')
154
+ i.set_option('LISTEN_ADDRESS', ['127.0.0.1'])
155
+ end
156
+ end
157
+
149
158
  end
150
159
  end
151
160
 
@@ -40,7 +40,7 @@ module Cosmos
40
40
  it "should raise an exception if the remote connection can't be made" do
41
41
  json = JsonDRb.new
42
42
  json.start_service('127.0.0.1', 7777, self)
43
- allow(TCPSocket).to receive(:new) { raise "Error" }
43
+ allow_any_instance_of(Socket).to receive(:connect_nonblock) { raise "Error" }
44
44
  obj = JsonDRbObject.new("localhost", 7777)
45
45
  expect { obj.my_method(10) }.to raise_error(DRb::DRbConnError)
46
46
  obj.disconnect
@@ -40,7 +40,6 @@ module Cosmos
40
40
 
41
41
  it "should defer to the posix serial driver on nix" do
42
42
  class PosixSerialDriver
43
- def initialize(port,baud); end
44
43
  end
45
44
  allow(Kernel).to receive(:is_windows?).and_return(false)
46
45
  driver = double("PosixSerialDriver")
@@ -130,9 +130,11 @@ module Cosmos
130
130
  Dir[File.join(@log_path,"*.bin")].length.should eql 2
131
131
  # Check that the log files have timestamps which are 3 (or 4) seconds apart
132
132
  files = Dir[File.join(@log_path,"*tlm.bin")].sort
133
- log1_seconds = files[0].split('_')[-3].to_i * 60 + files[0].split('_')[-2].to_i
134
- log2_seconds = files[1].split('_')[-3].to_i * 60 + files[1].split('_')[-2].to_i
135
- (log2_seconds - log1_seconds).should be_within(2).of(3)
133
+ split1 = files[0].split('_')
134
+ split2 = files[1].split('_')
135
+ log1_time = Time.new(split1[-7].to_i, split1[-6].to_i, split1[-5].to_i, split1[-4].to_i, split1[-3].to_i, split1[-2].to_i)
136
+ log2_time = Time.new(split2[-7].to_i, split2[-6].to_i, split2[-5].to_i, split2[-4].to_i, split2[-3].to_i, split2[-2].to_i)
137
+ (log2_time - log1_time).should be_within(2).of(3)
136
138
  plw.shutdown
137
139
  # Monkey patch the constant back to the default
138
140
  PacketLogWriter.__send__(:remove_const,:CYCLE_TIME_INTERVAL)
@@ -30,115 +30,12 @@ module Cosmos
30
30
  tf.unlink
31
31
  end
32
32
 
33
- it "should complain about overlapping items" do
34
- tf = Tempfile.new('unittest')
35
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
36
- tf.puts ' ITEM item1 0 8 UINT'
37
- tf.puts ' ITEM item2 0 8 UINT'
38
- tf.close
39
- @pc.process_file(tf.path, "TGT1")
40
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 0 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
41
- tf.unlink
42
- end
43
-
44
- it "should not complain with non-overlapping negative offsets" do
45
- tf = Tempfile.new('unittest')
46
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
47
- tf.puts ' ITEM item1 0 8 UINT'
48
- tf.puts ' ITEM item2 8 -16 BLOCK'
49
- tf.puts ' ITEM item3 -16 16 UINT'
50
- tf.close
51
- @pc.process_file(tf.path, "TGT1")
52
- @pc.warnings[0].should be_nil
53
- tf.unlink
54
- end
55
-
56
- it "should complain with overlapping negative offsets" do
57
- tf = Tempfile.new('unittest')
58
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
59
- tf.puts ' ITEM item1 0 8 UINT'
60
- tf.puts ' ITEM item2 8 -16 BLOCK'
61
- tf.puts ' ITEM item3 -17 16 UINT'
62
- tf.close
63
- @pc.process_file(tf.path, "TGT1")
64
- @pc.warnings[0].should eql "Bit definition overlap at bit offset -17 for Telemetry packet TGT1 PKT2 items ITEM3 and ITEM2"
65
- tf.unlink
66
- end
67
-
68
- it "should complain about intersecting items" do
69
- tf = Tempfile.new('unittest')
70
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
71
- tf.puts ' ITEM item1 0 32 UINT'
72
- tf.puts ' ITEM item2 16 32 UINT'
73
- tf.close
74
- @pc.process_file(tf.path, "TGT1")
75
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 16 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
76
- tf.unlink
77
- end
78
-
79
- it "should complain about array overlapping items" do
80
- tf = Tempfile.new('unittest')
81
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
82
- tf.puts ' ARRAY_ITEM item1 0 8 UINT 32'
83
- tf.puts ' ARRAY_ITEM item2 0 8 UINT 32'
84
- tf.close
85
- @pc.process_file(tf.path, "TGT1")
86
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 0 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
87
- tf.unlink
88
- end
89
-
90
- it "should not complain with array non-overlapping negative offsets" do
91
- tf = Tempfile.new('unittest')
92
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
93
- tf.puts ' ITEM item1 0 8 UINT'
94
- tf.puts ' ARRAY_ITEM item2 8 8 INT -16'
95
- tf.puts ' ITEM item3 -16 16 UINT'
96
- tf.close
97
- @pc.process_file(tf.path, "TGT1")
98
- @pc.warnings[0].should be_nil
99
- tf.unlink
100
- end
101
-
102
- it "should complain with array overlapping negative offsets" do
103
- tf = Tempfile.new('unittest')
104
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
105
- tf.puts ' ITEM item1 0 8 UINT'
106
- tf.puts ' ARRAY_ITEM item2 8 8 INT -16'
107
- tf.puts ' ITEM item3 -17 16 UINT'
108
- tf.close
109
- @pc.process_file(tf.path, "TGT1")
110
- @pc.warnings[0].should eql "Bit definition overlap at bit offset -17 for Telemetry packet TGT1 PKT2 items ITEM3 and ITEM2"
111
- tf.unlink
112
- end
113
-
114
- it "should complain about array intersecting items" do
115
- tf = Tempfile.new('unittest')
116
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
117
- tf.puts ' ARRAY_ITEM item1 0 8 UINT 32'
118
- tf.puts ' ARRAY_ITEM item2 16 8 UINT 32'
119
- tf.close
120
- @pc.process_file(tf.path, "TGT1")
121
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 16 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
122
- tf.unlink
123
- end
124
-
125
- it "should not complain about nonoverlapping little endian bitfields" do
126
- tf = Tempfile.new('unittest')
127
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
128
- tf.puts ' ITEM item1 12 12 UINT'
129
- tf.puts ' ITEM item2 16 16 UINT'
130
- tf.close
131
- @pc.process_file(tf.path, "TGT1")
132
- @pc.warnings[0].should be_nil
133
- tf.unlink
134
- end
135
-
136
33
  context "with all telemetry keywords" do
137
34
  before(:all) do
138
35
  # top level keywords
139
- @top_keywords = %w(TELEMETRY SELECT_TELEMETRY LIMITS_GROUP LIMITS_GROUP_ITEM)
36
+ @top_keywords = %w(SELECT_COMMAND SELECT_TELEMETRY LIMITS_GROUP LIMITS_GROUP_ITEM)
140
37
  # Keywords that require a current packet from TELEMETRY keyword
141
- @tlm_keywords = %w(SELECT_ITEM ITEM ID_ITEM ARRAY_ITEM APPEND_ITEM APPEND_ID_ITEM APPEND_ARRAY_ITEM MACRO_APPEND_START MACRO_APPEND_END PROCESSOR META)
38
+ @tlm_keywords = %w(SELECT_ITEM ITEM ID_ITEM ARRAY_ITEM APPEND_ITEM APPEND_ID_ITEM APPEND_ARRAY_ITEM PROCESSOR META)
142
39
  # Keywords that require both a current packet and current item
143
40
  @item_keywords = %w(STATE READ_CONVERSION WRITE_CONVERSION POLY_READ_CONVERSION POLY_WRITE_CONVERSION SEG_POLY_READ_CONVERSION SEG_POLY_WRITE_CONVERSION GENERIC_READ_CONVERSION_START GENERIC_WRITE_CONVERSION_START LIMITS LIMITS_RESPONSE UNITS FORMAT_STRING DESCRIPTION META)
144
41
  end
@@ -177,7 +74,6 @@ module Cosmos
177
74
  end
178
75
 
179
76
  @tlm_keywords.each do |keyword|
180
- next if %w(MACRO_APPEND_END).include? keyword
181
77
  tf = Tempfile.new('unittest')
182
78
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
183
79
  tf.puts keyword
@@ -202,8 +98,8 @@ module Cosmos
202
98
  @top_keywords.each do |keyword|
203
99
  tf = Tempfile.new('unittest')
204
100
  case keyword
205
- when "TELEMETRY"
206
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet" extra'
101
+ when "SELECT_COMMAND"
102
+ tf.puts 'SELECT_COMMAND tgt1 pkt1 extra'
207
103
  when "SELECT_TELEMETRY"
208
104
  tf.puts 'SELECT_TELEMETRY tgt1 pkt1 extra'
209
105
  when 'LIMITS_GROUP'
@@ -217,7 +113,7 @@ module Cosmos
217
113
  end
218
114
 
219
115
  @tlm_keywords.each do |keyword|
220
- next if %w(MACRO_APPEND_END PROCESSOR META).include? keyword
116
+ next if %w(PROCESSOR META).include? keyword
221
117
  tf = Tempfile.new('unittest')
222
118
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
223
119
  case keyword
@@ -236,10 +132,6 @@ module Cosmos
236
132
  when "SELECT_ITEM"
237
133
  tf.puts 'ITEM myitem 0 8 UINT'
238
134
  tf.puts 'SELECT_ITEM myitem extra'
239
- when "MACRO_APPEND_START"
240
- tf.puts 'MACRO_APPEND_START 0 1 "%s_%d" extra'
241
- when "ACRO_APPEND_END"
242
- tf.puts 'MACRO_APPEND_END extra'
243
135
  end
244
136
  tf.close
245
137
  expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Too many parameters for #{keyword}/)
@@ -271,47 +163,6 @@ module Cosmos
271
163
  end
272
164
  end
273
165
 
274
- context "with COMMAND or TELEMETRY" do
275
- it "should complain about invalid endianness" do
276
- %w(COMMAND TELEMETRY).each do |keyword|
277
- tf = Tempfile.new('unittest')
278
- tf.puts keyword + ' tgt1 pkt1 MIDDLE_ENDIAN "Packet"'
279
- tf.close
280
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid endianness MIDDLE_ENDIAN. Must be BIG_ENDIAN or LITTLE_ENDIAN.")
281
- tf.unlink
282
- end
283
- end
284
-
285
- it "should process target, packet, endianness, description" do
286
- %w(COMMAND TELEMETRY).each do |keyword|
287
- tf = Tempfile.new('unittest')
288
- tf.puts keyword + ' tgt1 pkt1 LITTLE_ENDIAN "Packet"'
289
- tf.close
290
- @pc.process_file(tf.path, "TGT1")
291
- pkt = @pc.commands["TGT1"]["PKT1"] if keyword == 'COMMAND'
292
- pkt = @pc.telemetry["TGT1"]["PKT1"] if keyword == 'TELEMETRY'
293
- pkt.target_name.should eql "TGT1"
294
- pkt.packet_name.should eql "PKT1"
295
- pkt.default_endianness.should eql :LITTLE_ENDIAN
296
- pkt.description.should eql "Packet"
297
- tf.unlink
298
- end
299
- end
300
-
301
- it "should substitute the target name" do
302
- %w(COMMAND TELEMETRY).each do |keyword|
303
- tf = Tempfile.new('unittest')
304
- tf.puts keyword + ' tgt1 pkt1 LITTLE_ENDIAN "Packet"'
305
- tf.close
306
- @pc.process_file(tf.path, "NEW")
307
- pkt = @pc.commands["NEW"]["PKT1"] if keyword == 'COMMAND'
308
- pkt = @pc.telemetry["NEW"]["PKT1"] if keyword == 'TELEMETRY'
309
- pkt.target_name.should eql "NEW"
310
- tf.unlink
311
- end
312
- end
313
- end
314
-
315
166
  context "with SELECT_COMMAND or SELECT_TELEMETRY" do
316
167
  it "should complain if the packet is not found" do
317
168
  %w(SELECT_COMMAND SELECT_TELEMETRY).each do |keyword|
@@ -442,176 +293,21 @@ module Cosmos
442
293
  end
443
294
  end
444
295
 
445
- context "with keywords including ITEM" do
446
- it "should only allow DERIVED items with offset 0 and size 0" do
447
- tf = Tempfile.new('unittest')
448
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
449
- tf.puts ' ITEM ITEM1 8 0 DERIVED'
450
- tf.close
451
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_offset of zero/)
452
- tf.unlink
453
-
454
- tf = Tempfile.new('unittest')
455
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
456
- tf.puts ' ITEM ITEM1 0 8 DERIVED'
457
- tf.close
458
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_size of zero/)
459
- tf.unlink
460
-
296
+ context "with MACRO_APPEND" do
297
+ it "creates a range of items" do
461
298
  tf = Tempfile.new('unittest')
462
299
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
463
- tf.puts ' ITEM ITEM1 0 0 DERIVED'
464
- tf.close
465
- @pc.process_file(tf.path, "TGT1")
466
- @pc.telemetry["TGT1"]["PKT1"].items.keys.should include('ITEM1')
467
- tf.unlink
468
- end
469
-
470
- it "should accept types INT UINT FLOAT STRING BLOCK" do
471
- tf = Tempfile.new('unittest')
472
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
473
- tf.puts ' ID_ITEM ITEM1 0 32 INT 0'
474
- tf.puts ' ITEM ITEM2 0 32 UINT'
475
- tf.puts ' ARRAY_ITEM ITEM3 0 32 FLOAT 64'
476
- tf.puts ' APPEND_ID_ITEM ITEM4 32 STRING "ABCD"'
477
- tf.puts ' APPEND_ITEM ITEM5 32 BLOCK'
478
- tf.puts ' APPEND_ARRAY_ITEM ITEM6 32 BLOCK 64'
479
- tf.close
480
- @pc.process_file(tf.path, "TGT1")
481
- @pc.telemetry["TGT1"]["PKT1"].items.keys.should include('ITEM1','ITEM2','ITEM3','ITEM4','ITEM5','ITEM6')
482
- id_items = []
483
- id_items << @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]
484
- id_items << @pc.telemetry["TGT1"]["PKT1"].items["ITEM4"]
485
- @pc.telemetry["TGT1"]["PKT1"].id_items.should eql id_items
486
- tf.unlink
487
- end
488
-
489
- it "should support arbitrary endianness per item" do
490
- tf = Tempfile.new('unittest')
491
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
492
- tf.puts ' ID_ITEM ITEM1 0 32 UINT 0 "" LITTLE_ENDIAN'
493
- tf.puts ' ITEM ITEM2 0 32 UINT "" LITTLE_ENDIAN'
494
- tf.puts ' ARRAY_ITEM ITEM3 0 32 UINT 64 "" LITTLE_ENDIAN'
495
- tf.puts ' APPEND_ID_ITEM ITEM4 32 UINT 1 "" LITTLE_ENDIAN'
496
- tf.puts ' APPEND_ITEM ITEM5 32 UINT "" LITTLE_ENDIAN'
497
- tf.puts ' APPEND_ARRAY_ITEM ITEM6 32 UINT 64 "" LITTLE_ENDIAN'
498
- tf.puts ' ID_ITEM ITEM10 224 32 UINT 0 "" BIG_ENDIAN'
499
- tf.puts ' ITEM ITEM20 256 32 UINT "" BIG_ENDIAN'
500
- tf.puts ' ARRAY_ITEM ITEM30 0 32 UINT 64 "" BIG_ENDIAN'
501
- tf.puts ' APPEND_ID_ITEM ITEM40 32 UINT 1 "" BIG_ENDIAN'
502
- tf.puts ' APPEND_ITEM ITEM50 32 UINT "" BIG_ENDIAN'
503
- tf.puts ' APPEND_ARRAY_ITEM ITEM60 32 UINT 64 "" BIG_ENDIAN'
504
- tf.close
505
- @pc.process_file(tf.path, "TGT1")
506
- packet = @pc.telemetry["TGT1"]["PKT1"]
507
- packet.buffer = "\x00\x00\x00\x01" * 16
508
- packet.read("ITEM1").should eql 0x01000000
509
- packet.read("ITEM2").should eql 0x01000000
510
- packet.read("ITEM3").should eql [0x01000000, 0x01000000]
511
- packet.read("ITEM4").should eql 0x01000000
512
- packet.read("ITEM5").should eql 0x01000000
513
- packet.read("ITEM6").should eql [0x01000000, 0x01000000]
514
- packet.read("ITEM10").should eql 0x00000001
515
- packet.read("ITEM20").should eql 0x00000001
516
- packet.read("ITEM30").should eql [0x00000001, 0x00000001]
517
- packet.read("ITEM40").should eql 0x00000001
518
- packet.read("ITEM50").should eql 0x00000001
519
- packet.read("ITEM60").should eql [0x00000001, 0x00000001]
520
- tf.unlink
521
- end
522
- end
523
-
524
- context "with keywords including PARAMETER" do
525
- it "should only allow DERIVED items with offset 0 and size 0" do
526
- tf = Tempfile.new('unittest')
527
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
528
- tf.puts ' PARAMETER ITEM1 8 0 DERIVED 0 0 0'
529
- tf.close
530
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_offset of zero/)
531
- tf.unlink
532
-
533
- tf = Tempfile.new('unittest')
534
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
535
- tf.puts ' PARAMETER ITEM1 0 8 DERIVED 0 0 0'
536
- tf.close
537
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_size of zero/)
538
- tf.unlink
539
-
540
- tf = Tempfile.new('unittest')
541
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
542
- tf.puts ' PARAMETER ITEM1 0 0 DERIVED 0 0 0'
543
- tf.close
544
- @pc.process_file(tf.path, "TGT1")
545
- @pc.commands["TGT1"]["PKT1"].items.keys.should include('ITEM1')
546
- tf.unlink
547
- end
548
-
549
- it "should not allow ID_PARAMETER with DERIVED type" do
550
- tf = Tempfile.new('unittest')
551
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
552
- tf.puts ' ID_PARAMETER ITEM1 0 0 DERIVED 0 0 0'
553
- tf.close
554
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED data type not allowed/)
555
- tf.unlink
556
- end
557
-
558
- it "should not allow APPEND_ID_PARAMETER with DERIVED type" do
559
- tf = Tempfile.new('unittest')
560
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
561
- tf.puts ' APPEND_ID_PARAMETER ITEM1 0 DERIVED 0 0 0'
562
- tf.close
563
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED data type not allowed/)
564
- tf.unlink
565
- end
566
-
567
- it "should accept types INT UINT FLOAT STRING BLOCK" do
568
- tf = Tempfile.new('unittest')
569
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
570
- tf.puts ' ID_PARAMETER ITEM1 0 32 INT 0 0 0'
571
- tf.puts ' ID_PARAMETER ITEM2 32 32 STRING "ABCD"'
572
- tf.puts ' PARAMETER ITEM3 64 32 UINT 0 0 0'
573
- tf.puts ' ARRAY_PARAMETER ITEM4 96 32 FLOAT 64'
574
- tf.puts ' APPEND_ID_PARAMETER ITEM5 32 UINT 0 0 0'
575
- tf.puts ' APPEND_ID_PARAMETER ITEM6 32 STRING "ABCD"'
576
- tf.puts ' APPEND_PARAMETER ITEM7 32 BLOCK "1234"'
577
- tf.puts ' APPEND_ARRAY_PARAMETER ITEM8 32 BLOCK 64'
578
- tf.close
579
- @pc.process_file(tf.path, "TGT1")
580
- @pc.commands["TGT1"]["PKT1"].items.keys.should include('ITEM1','ITEM2','ITEM3','ITEM4','ITEM5','ITEM6','ITEM7','ITEM8')
581
- tf.unlink
582
- end
583
-
584
- it "should support arbitrary endianness per item" do
585
- tf = Tempfile.new('unittest')
586
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
587
- tf.puts ' ID_PARAMETER ITEM1 0 32 UINT 0 0 0 "" LITTLE_ENDIAN'
588
- tf.puts ' PARAMETER ITEM2 0 32 UINT 0 0 0 "" LITTLE_ENDIAN'
589
- tf.puts ' ARRAY_PARAMETER ITEM3 0 32 UINT 64 "" LITTLE_ENDIAN'
590
- tf.puts ' APPEND_ID_PARAMETER ITEM4 32 UINT 0 0 0 "" LITTLE_ENDIAN'
591
- tf.puts ' APPEND_PARAMETER ITEM5 32 UINT 0 0 0 "" LITTLE_ENDIAN'
592
- tf.puts ' APPEND_ARRAY_PARAMETER ITEM6 32 UINT 64 "" LITTLE_ENDIAN'
593
- tf.puts ' ID_PARAMETER ITEM10 224 32 UINT 0 0 0 "" BIG_ENDIAN'
594
- tf.puts ' PARAMETER ITEM20 256 32 UINT 0 0 0 "" BIG_ENDIAN'
595
- tf.puts ' ARRAY_PARAMETER ITEM30 0 32 UINT 64 "" BIG_ENDIAN'
596
- tf.puts ' APPEND_ID_PARAMETER ITEM40 32 UINT 0 0 0 "" BIG_ENDIAN'
597
- tf.puts ' APPEND_PARAMETER ITEM50 32 UINT 0 0 0 "" BIG_ENDIAN'
598
- tf.puts ' APPEND_ARRAY_PARAMETER ITEM60 32 UINT 64 "" BIG_ENDIAN'
300
+ tf.puts 'MACRO_APPEND_START 1 3'
301
+ tf.puts ' APPEND_ITEM BYTE 8 UINT "Setting #x"'
302
+ tf.puts 'MACRO_APPEND_END'
599
303
  tf.close
600
304
  @pc.process_file(tf.path, "TGT1")
601
- packet = @pc.commands["TGT1"]["PKT1"]
602
- packet.buffer = "\x00\x00\x00\x01" * 16
603
- packet.read("ITEM1").should eql 0x01000000
604
- packet.read("ITEM2").should eql 0x01000000
605
- packet.read("ITEM3").should eql [0x01000000, 0x01000000]
606
- packet.read("ITEM4").should eql 0x01000000
607
- packet.read("ITEM5").should eql 0x01000000
608
- packet.read("ITEM6").should eql [0x01000000, 0x01000000]
609
- packet.read("ITEM10").should eql 0x00000001
610
- packet.read("ITEM20").should eql 0x00000001
611
- packet.read("ITEM30").should eql [0x00000001, 0x00000001]
612
- packet.read("ITEM40").should eql 0x00000001
613
- packet.read("ITEM50").should eql 0x00000001
614
- packet.read("ITEM60").should eql [0x00000001, 0x00000001]
305
+ pkt = @pc.telemetry["TGT1"]["PKT1"]
306
+ expect(pkt.items.length).to eql 6 # 3 plus the RECEIVED_XXX items
307
+ expect(pkt.items.keys).to include('BYTE1','BYTE2','BYTE3')
308
+ expect(pkt.sorted_items[3].name).to eql 'BYTE1'
309
+ expect(pkt.sorted_items[4].name).to eql 'BYTE2'
310
+ expect(pkt.sorted_items[5].name).to eql 'BYTE3'
615
311
  tf.unlink
616
312
  end
617
313
  end
@@ -651,56 +347,6 @@ module Cosmos
651
347
  end
652
348
  end
653
349
 
654
- context "with MACRO_APPEND_START" do
655
- it "should add items to the packet" do
656
- tf = Tempfile.new('unittest')
657
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
658
- tf.puts 'MACRO_APPEND_START 1 5'
659
- tf.puts 'APPEND_ITEM BIT 16 UINT "Setting #x"'
660
- tf.puts ' STATE BAD 0 RED'
661
- tf.puts ' STATE GOOD 1 GREEN'
662
- tf.puts 'MACRO_APPEND_END'
663
- tf.close
664
- @pc.process_file(tf.path, "TGT1")
665
- pkt = @pc.telemetry["TGT1"]["PKT1"]
666
- pkt.items.keys.should include('BIT1','BIT2','BIT3','BIT4','BIT5')
667
- limits_items = []
668
- pkt.items.each do |name, item|
669
- limits_items << item if name =~ /BIT/
670
- end
671
- pkt.limits_items.should eql limits_items
672
- tf.unlink
673
- end
674
-
675
- it "should array items to the packet" do
676
- tf = Tempfile.new('unittest')
677
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
678
- tf.puts 'MACRO_APPEND_START 1 5'
679
- tf.puts 'APPEND_ARRAY_ITEM BIT 16 INT 64 "Int Array Parameter"'
680
- tf.puts 'MACRO_APPEND_END'
681
- tf.close
682
- @pc.process_file(tf.path, "TGT1")
683
- pkt = @pc.telemetry["TGT1"]["PKT1"]
684
- pkt.items.keys.should include('BIT1','BIT2','BIT3','BIT4','BIT5')
685
- pkt.limits_items.should be_empty
686
- tf.unlink
687
- end
688
-
689
- it "should work with printf format strings" do
690
- tf = Tempfile.new('unittest')
691
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
692
- tf.puts 'MACRO_APPEND_START 1 5 "%d%s"'
693
- tf.puts 'APPEND_ID_ITEM BIT 16 UINT 0 "Setting #x"'
694
- tf.puts 'MACRO_APPEND_END'
695
- tf.close
696
- @pc.process_file(tf.path, "TGT1")
697
- pkt = @pc.telemetry["TGT1"]["PKT1"]
698
- pkt.items.keys.should include('1BIT','2BIT','3BIT','4BIT','5BIT')
699
- pkt.limits_items.should be_empty
700
- tf.unlink
701
- end
702
- end
703
-
704
350
  context "with ALLOW_SHORT" do
705
351
  it "should mark the packet as allowing short buffers" do
706
352
  tf = Tempfile.new('unittest')
@@ -806,106 +452,6 @@ module Cosmos
806
452
  end
807
453
  end
808
454
 
809
- context "with STATE" do
810
- it "should support STRING items" do
811
- tf = Tempfile.new('unittest')
812
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
813
- tf.puts ' APPEND_ITEM item1 128 STRING "state item"'
814
- tf.puts ' STATE FALSE "FALSE STRING"'
815
- tf.puts ' STATE TRUE "TRUE STRING"'
816
- tf.close
817
- @pc.process_file(tf.path, "TGT1")
818
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1", "TRUE STRING")
819
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql "TRUE"
820
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1", "FALSE STRING")
821
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql "FALSE"
822
- tf.unlink
823
- end
824
-
825
- it "should warn about duplicate states and replace the duplicate" do
826
- tf = Tempfile.new('unittest')
827
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
828
- tf.puts ' APPEND_PARAMETER item1 8 UINT 0 2 0 "state item"'
829
- tf.puts ' STATE FALSE 0'
830
- tf.puts ' STATE TRUE 1'
831
- tf.puts ' STATE FALSE 2'
832
- tf.close
833
- @pc.process_file(tf.path, "TGT1")
834
- @pc.warnings.should include("Duplicate state defined on line 5: STATE FALSE 2")
835
- @pc.commands["TGT1"]["PKT1"].buffer = "\x00"
836
- @pc.commands["TGT1"]["PKT1"].read("ITEM1").should eql 0
837
- @pc.commands["TGT1"]["PKT1"].buffer = "\x02"
838
- @pc.commands["TGT1"]["PKT1"].read("ITEM1").should eql "FALSE"
839
- tf.unlink
840
- end
841
-
842
- context "with telemetry" do
843
- it "should only allow GREEN YELLOW or RED" do
844
- tf = Tempfile.new('unittest')
845
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
846
- tf.puts ' APPEND_ITEM item1 8 UINT "state item"'
847
- tf.puts ' STATE WORST 1 ORANGE'
848
- tf.close
849
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Invalid state color ORANGE/)
850
- tf.unlink
851
- end
852
-
853
- it "should record the state values and colors" do
854
- tf = Tempfile.new('unittest')
855
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
856
- tf.puts ' APPEND_ITEM item1 8 UINT "state item"'
857
- tf.puts ' STATE STATE1 1 RED'
858
- tf.puts ' STATE STATE2 2 YELLOW'
859
- tf.puts ' STATE STATE3 3 GREEN'
860
- tf.puts ' STATE STATE4 4'
861
- tf.close
862
- @pc.process_file(tf.path, "TGT1")
863
- index = 1
864
- colors = [:RED, :YELLOW, :GREEN]
865
- @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"].states.each do |name,val|
866
- name.should eql "STATE#{index}"
867
- val.should eql index
868
- @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"].state_colors[name].should eql colors[index - 1]
869
-
870
- index += 1
871
- end
872
- @pc.telemetry["TGT1"]["PKT1"].limits_items.should eql [@pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]]
873
- tf.unlink
874
- end
875
- end
876
-
877
- context "with command" do
878
- it "should only allow HAZARDOUS as the third param" do
879
- tf = Tempfile.new('unittest')
880
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
881
- tf.puts ' APPEND_PARAMETER item1 8 UINT 0 0 0'
882
- tf.puts ' STATE WORST 0 RED'
883
- tf.close
884
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /HAZARDOUS expected as third parameter/)
885
- tf.unlink
886
- end
887
-
888
- it "should take HAZARDOUS and an optional description" do
889
- tf = Tempfile.new('unittest')
890
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
891
- tf.puts ' APPEND_PARAMETER item1 8 UINT 1 3 1'
892
- tf.puts ' STATE GOOD 1'
893
- tf.puts ' STATE BAD 2 HAZARDOUS'
894
- tf.puts ' STATE WORST 3 HAZARDOUS "Hazardous description"'
895
- tf.close
896
- @pc.process_file(tf.path, "TGT1")
897
- @pc.commands["TGT1"]["PKT1"].buffer = "\x01"
898
- @pc.commands["TGT1"]["PKT1"].check_limits
899
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["GOOD"].should be_nil
900
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["BAD"].should_not be_nil
901
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["WORST"].should_not be_nil
902
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["WORST"].should eql "Hazardous description"
903
- @pc.commands["TGT1"]["PKT1"].limits_items.should be_empty
904
- tf.unlink
905
- end
906
- end
907
- end
908
-
909
455
  context "with READ_CONVERSION and WRITE_CONVERSION" do
910
456
  it "should complain about missing conversion file" do
911
457
  filename = File.join(File.dirname(__FILE__), "../test_only.rb")
@@ -993,76 +539,6 @@ module Cosmos
993
539
  end
994
540
  end
995
541
 
996
- context "with PROCESSOR" do
997
- it "should complain about missing processor file" do
998
- filename = File.join(File.dirname(__FILE__), "../test_only.rb")
999
- File.delete(filename) if File.exist?(filename)
1000
- @pc = PacketConfig.new
1001
-
1002
- tf = Tempfile.new('unittest')
1003
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1004
- tf.puts ' PROCESSOR TEST test_only.rb'
1005
- tf.close
1006
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /TestOnly class not found/)
1007
- tf.unlink
1008
- end
1009
-
1010
- it "should complain about a non Cosmos::Processor class" do
1011
- filename = File.join(File.dirname(__FILE__), "../processor1.rb")
1012
- File.open(filename, 'w') do |file|
1013
- file.puts "class Processor1"
1014
- file.puts " def call(packet,buffer)"
1015
- file.puts " end"
1016
- file.puts "end"
1017
- end
1018
- load 'processor1.rb'
1019
- File.delete(filename) if File.exist?(filename)
1020
-
1021
- tf = Tempfile.new('unittest')
1022
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1023
- tf.puts ' PROCESSOR P1 processor1.rb'
1024
- tf.close
1025
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /processor must be a Cosmos::Processor but is a Processor1/)
1026
- tf.unlink
1027
- end
1028
-
1029
- it "should parse the processor" do
1030
- filename = File.join(File.dirname(__FILE__), "../processor2.rb")
1031
- File.open(filename, 'w') do |file|
1032
- file.puts "require 'cosmos/processors/processor'"
1033
- file.puts "class Processor2 < Cosmos::Processor"
1034
- file.puts " def call(packet,buffer)"
1035
- file.puts " @results[:TEST] = 5"
1036
- file.puts " end"
1037
- file.puts "end"
1038
- end
1039
- load 'processor2.rb'
1040
-
1041
- tf = Tempfile.new('unittest')
1042
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1043
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1044
- tf.puts ' READ_CONVERSION processor_conversion.rb P2 TEST'
1045
- tf.puts ' PROCESSOR P2 processor2.rb'
1046
- tf.puts ' PROCESSOR P3 processor2.rb RAW'
1047
- tf.close
1048
- @pc.process_file(tf.path, "TGT1")
1049
- @pc.telemetry["TGT1"]["PKT1"].buffer = "\x01\x01"
1050
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql 5
1051
- tf.unlink
1052
-
1053
- File.delete(filename) if File.exist?(filename)
1054
- end
1055
-
1056
- it "should complain if applied to a command packet" do
1057
- tf = Tempfile.new('unittest')
1058
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1059
- tf.puts ' PROCESSOR P1 processor1.rb'
1060
- tf.close
1061
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "PROCESSOR only applies to telemetry packets")
1062
- tf.unlink
1063
- end
1064
- end
1065
-
1066
542
  context "with POLY_READ_CONVERSION and POLY_WRITE_CONVERSION" do
1067
543
  it "should perform a polynomial conversion" do
1068
544
  tf = Tempfile.new('unittest')
@@ -1163,313 +639,22 @@ module Cosmos
1163
639
  end
1164
640
 
1165
641
  context "with LIMITS" do
1166
- it "should complain if applied to a command PARAMETER" do
1167
- tf = Tempfile.new('unittest')
1168
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1169
- tf.puts ' APPEND_PARAMETER item1 16 UINT 0 0 0 "Item"'
1170
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 3 5'
1171
- tf.close
1172
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "LIMITS only applies to telemetry items")
1173
- tf.unlink
1174
- end
1175
-
1176
- it "should complain if the second parameter isn't a number" do
1177
- tf = Tempfile.new('unittest')
1178
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1179
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1180
- tf.puts ' LIMITS DEFAULT TRUE ENABLED 1 2 6 7 3 5'
1181
- tf.close
1182
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Ensure persistence is an integer/)
1183
- tf.unlink
1184
- end
1185
-
1186
- it "should complain if the third parameter isn't ENABLED or DISABLED" do
1187
- tf = Tempfile.new('unittest')
1188
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1189
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1190
- tf.puts ' LIMITS DEFAULT 3 TRUE 1 2 6 7 3 5'
1191
- tf.close
1192
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Initial state must be ENABLED or DISABLED/)
1193
- tf.unlink
1194
- end
1195
-
1196
- it "should complain if the 4 limits are out of order" do
1197
- tf = Tempfile.new('unittest')
1198
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1199
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1200
- tf.puts ' LIMITS DEFAULT 3 ENABLED 2 1 3 4'
1201
- tf.close
1202
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1203
- tf.unlink
1204
-
1205
- tf = Tempfile.new('unittest')
1206
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1207
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1208
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 5 3 7'
1209
- tf.close
1210
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1211
- tf.unlink
1212
-
1213
- tf = Tempfile.new('unittest')
1214
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1215
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1216
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 5 4'
1217
- tf.close
1218
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1219
- tf.unlink
1220
-
1221
- tf = Tempfile.new('unittest')
1222
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1223
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1224
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 3 0'
1225
- tf.close
1226
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1227
- tf.unlink
1228
- end
1229
-
1230
- it "should complain if the 6 limits are out of order" do
1231
- tf = Tempfile.new('unittest')
1232
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1233
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1234
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 0 5'
1235
- tf.close
1236
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1237
- tf.unlink
1238
-
1239
- tf = Tempfile.new('unittest')
1240
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1241
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1242
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 3 6 7 2 5'
1243
- tf.close
1244
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1245
- tf.unlink
1246
-
1247
- tf = Tempfile.new('unittest')
1248
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1249
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1250
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 8 3 7'
1251
- tf.close
1252
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1253
- tf.unlink
1254
-
1255
- tf = Tempfile.new('unittest')
1256
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1257
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1258
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 8 3 9'
1259
- tf.close
1260
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1261
- tf.unlink
1262
-
1263
- tf = Tempfile.new('unittest')
1264
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1265
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1266
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 8 4 3'
1267
- tf.close
1268
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1269
- tf.unlink
1270
- end
1271
-
1272
- it "should take 4 limits values" do
642
+ it "ensures limits sets have unique names" do
1273
643
  tf = Tempfile.new('unittest')
1274
644
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1275
645
  tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1276
646
  tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7'
647
+ tf.puts ' LIMITS TVAC 1 ENABLED 1 2 6 7'
648
+ tf.puts ' LIMITS DEFAULT 1 ENABLED 8 9 12 13'
1277
649
  tf.close
1278
650
  @pc.process_file(tf.path, "TGT1")
1279
651
  item = @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]
1280
- item.limits.values[:DEFAULT].should_not be_nil
1281
- @pc.telemetry["TGT1"]["PKT1"].buffer = "\x04"
1282
- @pc.telemetry["TGT1"]["PKT1"].enable_limits("ITEM1")
1283
- @pc.telemetry["TGT1"]["PKT1"].check_limits
1284
- item.limits.state.should eql :GREEN
1285
- @pc.telemetry["TGT1"]["PKT1"].limits_items.should eql [item]
1286
- tf.unlink
1287
- end
1288
-
1289
- it "should take 6 limits values" do
1290
- tf = Tempfile.new('unittest')
1291
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1292
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1293
- tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7 3 5'
1294
- tf.close
1295
- @pc.process_file(tf.path, "TGT1")
1296
- item = @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]
1297
- item.limits.values[:DEFAULT].should_not be_nil
652
+ expect(item.limits.values.length).to eql 2
653
+ # Verify the last defined DEFAULT limits wins
1298
654
  @pc.telemetry["TGT1"]["PKT1"].buffer = "\x04"
1299
655
  @pc.telemetry["TGT1"]["PKT1"].enable_limits("ITEM1")
1300
656
  @pc.telemetry["TGT1"]["PKT1"].check_limits
1301
- item.limits.state.should eql :BLUE
1302
- @pc.telemetry["TGT1"]["PKT1"].limits_items.should eql [item]
1303
- tf.unlink
1304
- end
1305
- end
1306
-
1307
- context "with LIMITS_RESPONSE" do
1308
- it "should complain if applied to a command PARAMETER" do
1309
- tf = Tempfile.new('unittest')
1310
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1311
- tf.puts ' APPEND_PARAMETER item1 16 UINT 0 0 0 "Item"'
1312
- tf.puts ' LIMITS_RESPONSE test.rb'
1313
- tf.close
1314
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "LIMITS_RESPONSE only applies to telemetry items")
1315
- tf.unlink
1316
- end
1317
-
1318
- it "should complain about missing response file" do
1319
- filename = File.join(File.dirname(__FILE__), "../test_only.rb")
1320
- File.delete(filename) if File.exist?(filename)
1321
- @pc = PacketConfig.new
1322
-
1323
- tf = Tempfile.new('unittest')
1324
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1325
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1326
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 3 5'
1327
- tf.puts ' LIMITS_RESPONSE test_only.rb'
1328
- tf.close
1329
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /TestOnly class not found/)
1330
- tf.unlink
1331
- end
1332
-
1333
- it "should complain about a non Cosmos::LimitsResponse class" do
1334
- filename = File.join(File.dirname(__FILE__), "../limits_response1.rb")
1335
- File.open(filename, 'w') do |file|
1336
- file.puts "class LimitsResponse1"
1337
- file.puts " def call(target_name, packet_name, item, old_limits_state, new_limits_state)"
1338
- file.puts " end"
1339
- file.puts "end"
1340
- end
1341
- load 'limits_response1.rb'
1342
- File.delete(filename) if File.exist?(filename)
1343
-
1344
- tf = Tempfile.new('unittest')
1345
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1346
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1347
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 3 5'
1348
- tf.puts ' LIMITS_RESPONSE limits_response1.rb'
1349
- tf.close
1350
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /response must be a Cosmos::LimitsResponse but is a LimitsResponse1/)
1351
- tf.unlink
1352
- end
1353
-
1354
- it "should set the response" do
1355
- filename = File.join(File.dirname(__FILE__), "../limits_response2.rb")
1356
- File.open(filename, 'w') do |file|
1357
- file.puts "require 'cosmos/packets/limits_response'"
1358
- file.puts "class LimitsResponse2 < Cosmos::LimitsResponse"
1359
- file.puts " def call(target_name, packet_name, item, old_limits_state, new_limits_state)"
1360
- file.puts " puts \"\#{target_name} \#{packet_name} \#{item.name} \#{old_limits_state} \#{new_limits_state}\""
1361
- file.puts " end"
1362
- file.puts "end"
1363
- end
1364
- load 'limits_response2.rb'
1365
-
1366
- tf = Tempfile.new('unittest')
1367
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1368
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1369
- tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7 3 5'
1370
- tf.puts ' LIMITS_RESPONSE limits_response2.rb'
1371
- tf.close
1372
- @pc.process_file(tf.path, "TGT1")
1373
- pkt = @pc.telemetry["TGT1"]["PKT1"]
1374
- pkt.get_item("ITEM1").limits.response.class.should eql LimitsResponse2
1375
-
1376
- File.delete(filename) if File.exist?(filename)
1377
- tf.unlink
1378
- end
1379
-
1380
- it "should call the response with parameters" do
1381
- filename = File.join(File.dirname(__FILE__), "../limits_response2.rb")
1382
- File.open(filename, 'w') do |file|
1383
- file.puts "require 'cosmos/packets/limits_response'"
1384
- file.puts "class LimitsResponse2 < Cosmos::LimitsResponse"
1385
- file.puts " def initialize(val)"
1386
- file.puts " puts \"initialize: \#{val}\""
1387
- file.puts " end"
1388
- file.puts " def call(target_name, packet_name, item, old_limits_state, new_limits_state)"
1389
- file.puts " puts \"\#{target_name} \#{packet_name} \#{item.name} \#{old_limits_state} \#{new_limits_state}\""
1390
- file.puts " end"
1391
- file.puts "end"
1392
- end
1393
- load 'limits_response2.rb'
1394
-
1395
- tf = Tempfile.new('unittest')
1396
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1397
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1398
- tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7 3 5'
1399
- tf.puts ' LIMITS_RESPONSE limits_response2.rb 2'
1400
- tf.close
1401
- capture_io do |stdout|
1402
- @pc.process_file(tf.path, "TGT1")
1403
- stdout.string.should eql "initialize: 2\n"
1404
- end
1405
-
1406
- File.delete(filename) if File.exist?(filename)
1407
- tf.unlink
1408
- end
1409
- end
1410
-
1411
- context "with FORMAT_STRING" do
1412
- it "should complain about invalid format strings" do
1413
- tf = Tempfile.new('unittest')
1414
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1415
- tf.puts ' ITEM item1 0 8 INT'
1416
- tf.puts ' FORMAT_STRING "%*s"'
1417
- tf.close
1418
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid FORMAT_STRING specified for type INT: %*s")
1419
- tf.unlink
1420
-
1421
- tf = Tempfile.new('unittest')
1422
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1423
- tf.puts ' ITEM item1 0 8 STRING'
1424
- tf.puts ' FORMAT_STRING "%d"'
1425
- tf.close
1426
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid FORMAT_STRING specified for type STRING: %d")
1427
- tf.unlink
1428
- end
1429
-
1430
- it "should format integers" do
1431
- tf = Tempfile.new('unittest')
1432
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1433
- tf.puts ' ITEM item1 0 8 INT'
1434
- tf.puts ' FORMAT_STRING "d%d"'
1435
- tf.puts ' ITEM item2 0 8 UINT'
1436
- tf.puts ' FORMAT_STRING "u%u"'
1437
- tf.puts ' ITEM item3 0 8 UINT'
1438
- tf.puts ' FORMAT_STRING "0x%x"'
1439
- tf.close
1440
- @pc.process_file(tf.path, "TGT1")
1441
- @pc.telemetry["TGT1"]["PKT1"].buffer = "\x0a\x0b\x0c"
1442
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1",:FORMATTED).should eql "d10"
1443
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM2",:FORMATTED).should eql "u10"
1444
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM3",:FORMATTED).should eql "0xa"
1445
- tf.unlink
1446
- end
1447
-
1448
- it "should format floats" do
1449
- tf = Tempfile.new('unittest')
1450
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1451
- tf.puts ' ITEM item1 0 32 FLOAT'
1452
- tf.puts ' FORMAT_STRING "%3.3f"'
1453
- tf.close
1454
- @pc.process_file(tf.path, "TGT1")
1455
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1",12345.12345)
1456
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1",:FORMATTED).should eql "12345.123"
1457
- tf.unlink
1458
- end
1459
-
1460
- it "should format strings and blocks" do
1461
- tf = Tempfile.new('unittest')
1462
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1463
- tf.puts ' ITEM item1 0 32 STRING'
1464
- tf.puts ' FORMAT_STRING "String: %s"'
1465
- tf.puts ' ITEM item2 0 32 BLOCK'
1466
- tf.puts ' FORMAT_STRING "Block: %s"'
1467
- tf.close
1468
- @pc.process_file(tf.path, "TGT1")
1469
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1","HI")
1470
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1",:FORMATTED).should eql "String: HI"
1471
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM2","\x00\x01\x02\x03")
1472
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM2",:FORMATTED).should eql "Block: \x00\x01\x02\x03"
657
+ item.limits.state.should eql :RED_LOW
1473
658
  tf.unlink
1474
659
  end
1475
660
  end