cosmos 4.1.0 → 4.1.1

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +5 -0
  3. data/appveyor.yml +2 -0
  4. data/autohotkey/tools/replay.ahk +45 -45
  5. data/autohotkey/tools/script_runner.ahk +3 -9
  6. data/cosmos.gemspec +1 -1
  7. data/data/config/interface_modifiers.yaml +23 -0
  8. data/data/config/screen.yaml +1 -1
  9. data/data/crc.txt +20 -18
  10. data/demo/config/targets/INST/cmd_tlm_server.txt +1 -1
  11. data/lib/cosmos/config/config_parser.rb +8 -3
  12. data/lib/cosmos/gui/dialogs/exception_dialog.rb +20 -5
  13. data/lib/cosmos/interfaces/protocols/burst_protocol.rb +13 -3
  14. data/lib/cosmos/interfaces/protocols/crc_protocol.rb +27 -3
  15. data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +4 -2
  16. data/lib/cosmos/interfaces/protocols/length_protocol.rb +4 -2
  17. data/lib/cosmos/interfaces/protocols/override_protocol.rb +2 -2
  18. data/lib/cosmos/interfaces/protocols/preidentified_protocol.rb +3 -2
  19. data/lib/cosmos/interfaces/protocols/protocol.rb +16 -4
  20. data/lib/cosmos/interfaces/protocols/template_protocol.rb +7 -2
  21. data/lib/cosmos/interfaces/protocols/terminated_protocol.rb +4 -2
  22. data/lib/cosmos/packets/packet_config.rb +19 -859
  23. data/lib/cosmos/packets/packet_item.rb +56 -201
  24. data/lib/cosmos/packets/parsers/xtce_converter.rb +440 -0
  25. data/lib/cosmos/packets/parsers/xtce_parser.rb +682 -0
  26. data/lib/cosmos/tools/config_editor/config_editor.rb +143 -5
  27. data/lib/cosmos/tools/tlm_viewer/screen.rb +1 -1
  28. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +5 -3
  29. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +40 -27
  30. data/lib/cosmos/version.rb +4 -4
  31. data/spec/config/config_parser_spec.rb +39 -2
  32. data/spec/install/config/targets/INST/screens/hs.txt +42 -0
  33. data/spec/install/config/targets/INST/target.txt +2 -0
  34. data/spec/interfaces/protocols/burst_protocol_spec.rb +18 -0
  35. data/spec/interfaces/protocols/length_protocol_spec.rb +49 -0
  36. data/spec/interfaces/udp_interface_spec.rb +0 -9
  37. data/spec/packets/packet_config_spec.rb +21 -144
  38. data/spec/packets/packet_item_spec.rb +68 -4
  39. data/spec/packets/parsers/packet_item_parser_spec.rb +12 -0
  40. data/spec/packets/parsers/xtce_parser_spec.rb +398 -0
  41. data/spec/tools/tlm_viewer/tlm_viewer_config_spec.rb +401 -0
  42. metadata +9 -10
@@ -0,0 +1,42 @@
1
+ SCREEN AUTO AUTO 0.5
2
+ GLOBAL_SETTING LABELVALUELIMITSBAR COLORBLIND TRUE
3
+
4
+ VERTICAL
5
+
6
+ TITLE "Instrument Health and Status"
7
+ SETTING BACKCOLOR 162 181 205
8
+ SETTING TEXTCOLOR black
9
+
10
+ VERTICALBOX
11
+ SECTIONHEADER "General Telemetry"
12
+ NAMED_WIDGET COLLECT_TYPE COMBOBOX NORMAL SPECIAL
13
+ BUTTON 'Start Collect' 'target_name = get_target_name("INST"); cmd("#{target_name} COLLECT with TYPE NORMAL, DURATION 5")'
14
+ FORMATVALUE INST HEALTH_STATUS COLLECTS "0x%08X"
15
+ LABELVALUE INST HEALTH_STATUS COLLECT_TYPE
16
+ LABELVALUE INST HEALTH_STATUS DURATION
17
+ LABELVALUE INST HEALTH_STATUS ASCIICMD WITH_UNITS 30
18
+ END
19
+ SETTING BACKCOLOR 163 185 163
20
+
21
+ VERTICALBOX
22
+ SECTIONHEADER "Temperatures"
23
+ LABELTRENDLIMITSBAR INST HEALTH_STATUS TEMP1 WITH_UNITS 5
24
+ LABELVALUELIMITSBAR INST HEALTH_STATUS TEMP2 CONVERTED 25
25
+ # LABELVALUELIMITSBAR INST HEALTH_STATUS TEMP2 RAW 20 # RAW is not allowed for LIMITSBAR widgets
26
+ LABELVALUELIMITSBAR INST HEALTH_STATUS TEMP2 FORMATTED
27
+ LABELVALUELIMITSBAR INST HEALTH_STATUS TEMP2 WITH_UNITS
28
+ LABELVALUELIMITSBAR INST HEALTH_STATUS TEMP3
29
+ LABELVALUELIMITSBAR INST HEALTH_STATUS TEMP4
30
+ SETTING GRAY_TOLERANCE 0.1
31
+ END
32
+ SETTING BACKCOLOR 203 173 158
33
+
34
+ VERTICALBOX
35
+ SECTIONHEADER "Ground Station"
36
+ LABELVALUE INST HEALTH_STATUS GROUND1STATUS
37
+ LABELVALUE INST HEALTH_STATUS GROUND2STATUS
38
+ END
39
+
40
+ SETTING BACKCOLOR 207 171 169
41
+ END
42
+ SETTING BACKCOLOR 162 181 205
@@ -8,3 +8,5 @@ IGNORE_PARAMETER CCSDSSEQFLAGS
8
8
  IGNORE_PARAMETER CCSDSSEQCNT
9
9
  IGNORE_PARAMETER CCSDSLENGTH
10
10
  IGNORE_PARAMETER PKTID
11
+
12
+ AUTO_SCREEN_SUBSTITUTE
@@ -197,6 +197,24 @@ module Cosmos
197
197
  pkt = @interface.read
198
198
  expect(pkt.length).to eql 3 # sync plus one byte
199
199
  end
200
+
201
+ it "handle auto allow_empty_data correctly" do
202
+ @interface.add_protocol(BurstProtocol, [0, nil, false, nil], :READ_WRITE)
203
+ expect(@interface.read_protocols[0].read_data("")).to eql :STOP
204
+ expect(@interface.read_protocols[0].read_data("A")).to eql "A"
205
+ @interface.add_protocol(BurstProtocol, [0, nil, false, nil], :READ_WRITE)
206
+ expect(@interface.read_protocols[0].read_data("")).to eql ""
207
+ expect(@interface.read_protocols[1].read_data("")).to eql :STOP
208
+ expect(@interface.read_protocols[0].read_data("A")).to eql "A"
209
+ expect(@interface.read_protocols[1].read_data("A")).to eql "A"
210
+ @interface.add_protocol(BurstProtocol, [0, nil, false, nil], :READ_WRITE)
211
+ expect(@interface.read_protocols[0].read_data("")).to eql ""
212
+ expect(@interface.read_protocols[1].read_data("")).to eql ""
213
+ expect(@interface.read_protocols[2].read_data("")).to eql :STOP
214
+ expect(@interface.read_protocols[0].read_data("A")).to eql "A"
215
+ expect(@interface.read_protocols[1].read_data("A")).to eql "A"
216
+ expect(@interface.read_protocols[2].read_data("A")).to eql "A"
217
+ end
200
218
  end
201
219
 
202
220
  describe "write" do
@@ -46,6 +46,55 @@ module Cosmos
46
46
  end
47
47
 
48
48
  describe "read" do
49
+ it "caches data for reads correctly" do
50
+ @interface.instance_variable_set(:@stream, LengthStream.new)
51
+ @interface.add_protocol(LengthProtocol, [
52
+ 0, # bit offset
53
+ 8, # bit size
54
+ 0, # length offset
55
+ 1, # bytes per count
56
+ 'BIG_ENDIAN'], :READ_WRITE)
57
+ $buffer = "\x02\x03\x02\x05"
58
+ packet = @interface.read
59
+ expect(packet.buffer.length).to eql 2
60
+ expect(packet.buffer).to eql "\x02\x03"
61
+ packet = @interface.read
62
+ expect(packet.buffer.length).to eql 2
63
+ expect(packet.buffer).to eql "\x02\x05"
64
+ expect(@interface.read_protocols[0].read_data("\x03\x01\x02\x03\x04\x05")).to eql "\x03\x01\x02"
65
+ expect(@interface.read_protocols[0].read_data("")).to eql "\x03\x04\x05"
66
+ expect(@interface.read_protocols[0].read_data("")).to eql :STOP
67
+ end
68
+
69
+ # This test case uses two length protocols to verify that data flows correctly between the two protocols and that earlier data
70
+ # is removed correctly using discard leading bytes. In general it is not typical to use two different length protocols, but it could
71
+ # be useful to pull out a packet inside of a packet.
72
+ it "caches data for reads correctly with multiple protocols" do
73
+ @interface.instance_variable_set(:@stream, LengthStream.new)
74
+ @interface.add_protocol(LengthProtocol, [
75
+ 0, # bit offset
76
+ 8, # bit size
77
+ 0, # length offset
78
+ 1, # bytes per count
79
+ 'BIG_ENDIAN'], :READ_WRITE)
80
+ @interface.add_protocol(LengthProtocol, [
81
+ 0, # bit offset
82
+ 8, # bit size
83
+ 0, # length offset
84
+ 1, # bytes per count
85
+ 'BIG_ENDIAN',
86
+ 1], :READ_WRITE) # Discard leading bytes set to 1
87
+ # The second protocol above will receive the two byte packets from the first protocol and
88
+ # then drop the length field.
89
+ $buffer = "\x02\x03\x02\x05"
90
+ packet = @interface.read
91
+ expect(packet.buffer.length).to eql 1
92
+ expect(packet.buffer).to eql "\x03"
93
+ packet = @interface.read
94
+ expect(packet.buffer.length).to eql 1
95
+ expect(packet.buffer).to eql "\x05"
96
+ end
97
+
49
98
  it "reads LITTLE_ENDIAN length fields from the stream" do
50
99
  @interface.instance_variable_set(:@stream, LengthStream.new)
51
100
  @interface.add_protocol(LengthProtocol, [
@@ -100,15 +100,6 @@ module Cosmos
100
100
  end
101
101
 
102
102
  describe "read" do
103
- it "stops the read thread if no read port given" do
104
- i = UdpInterface.new('localhost','8888','nil')
105
- i.connect
106
- thread = Thread.new { i.read }
107
- sleep 0.1
108
- expect(thread.stop?).to be true
109
- Cosmos.kill_thread(nil, thread)
110
- end
111
-
112
103
  it "stops the read thread if there is an IOError" do
113
104
  read = double("read")
114
105
  allow(read).to receive(:read).and_raise(IOError)
@@ -13,36 +13,6 @@ require 'cosmos'
13
13
  require 'cosmos/packets/packet_config'
14
14
  require 'tempfile'
15
15
 
16
- XTCE_START =<<END
17
- <?xml version="1.0" encoding="UTF-8"?>
18
- <xtce:SpaceSystem xmlns:xtce="http://www.omg.org/space/xtce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="INST" xsi:schemaLocation="http://www.omg.org/space/xtce http://www.omg.org/spec/XTCE/20061101/06-11-06.xsd">
19
- <xtce:TelemetryMetaData>
20
- <xtce:ParameterTypeSet>
21
- <xtce:IntegerParameterType name="A_Type" shortDescription="A" signed="false">
22
- <xtce:UnitSet/>
23
- END
24
- XTCE_END =<<END
25
- </xtce:IntegerParameterType>
26
- </xtce:ParameterTypeSet>
27
- <xtce:ParameterSet>
28
- <xtce:Parameter name="A" parameterTypeRef="A_Type"/>
29
- </xtce:ParameterSet>
30
- <xtce:ContainerSet>
31
- <xtce:SequenceContainer name="B_Base" abstract="true">
32
- <xtce:EntryList>
33
- <xtce:ParameterRefEntry parameterRef="A"/>
34
- </xtce:EntryList>
35
- </xtce:SequenceContainer>
36
- <xtce:SequenceContainer name="B" shortDescription="B">
37
- <xtce:EntryList/>
38
- <xtce:BaseContainer containerRef="B_Base">
39
- </xtce:BaseContainer>
40
- </xtce:SequenceContainer>
41
- </xtce:ContainerSet>
42
- </xtce:TelemetryMetaData>
43
- </xtce:SpaceSystem>
44
- END
45
-
46
16
  module Cosmos
47
17
 
48
18
  describe PacketConfig do
@@ -52,120 +22,6 @@ module Cosmos
52
22
  @pc = PacketConfig.new
53
23
  end
54
24
 
55
- describe "xtce support" do
56
- it "processes xtce telemetry" do
57
- tf = Tempfile.new(['unittest', '.xtce'])
58
- tf.puts XTCE_START
59
- tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned"/>'
60
- tf.puts XTCE_END
61
- tf.close
62
-
63
- @pc.process_file(tf.path, 'TEST')
64
-
65
- packet = @pc.telemetry['TEST']['B']
66
- expect(packet).to_not be_nil
67
- expect(packet.get_item('A').endianness).to eql :BIG_ENDIAN
68
-
69
- tf.unlink
70
- end
71
-
72
- it "processes explicit big endian xtce telemetry" do
73
- tf = Tempfile.new(['unittest', '.xtce'])
74
- tf.puts XTCE_START
75
- tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
76
- tf.puts ' <xtce:ByteOrderList>' + "\n"
77
- tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
78
- tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
79
- tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
80
- tf.puts ' <xtce:Byte byteSignificance="0"/>' + "\n"
81
- tf.puts ' </xtce:ByteOrderList>' + "\n"
82
- tf.puts '</xtce:IntegerDataEncoding>' + "\n"
83
- tf.puts XTCE_END
84
- tf.close
85
-
86
- @pc.process_file(tf.path, 'TEST')
87
-
88
- packet = @pc.telemetry['TEST']['B']
89
- expect(packet).to_not be_nil
90
- expect(packet.get_item('A').endianness).to eql :BIG_ENDIAN
91
- expect(@pc.warnings).to be_empty
92
-
93
- tf.unlink
94
- end
95
-
96
- it "processes explicit little endian xtce telemetry" do
97
- tf = Tempfile.new(['unittest', '.xtce'])
98
- tf.puts XTCE_START
99
- tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
100
- tf.puts ' <xtce:ByteOrderList>' + "\n"
101
- tf.puts ' <xtce:Byte byteSignificance="0"/>' + "\n"
102
- tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
103
- tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
104
- tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
105
- tf.puts ' </xtce:ByteOrderList>' + "\n"
106
- tf.puts '</xtce:IntegerDataEncoding>' + "\n"
107
- tf.puts XTCE_END
108
- tf.close
109
-
110
- @pc.process_file(tf.path, 'TEST')
111
-
112
- packet = @pc.telemetry['TEST']['B']
113
- expect(packet).to_not be_nil
114
- expect(packet.get_item('A').endianness).to eql :LITTLE_ENDIAN
115
- expect(@pc.warnings).to be_empty
116
-
117
- tf.unlink
118
- end
119
-
120
- it "warn of bad byteorderlist no zero xtce telemetry" do
121
- tf = Tempfile.new(['unittest', '.xtce'])
122
- tf.puts XTCE_START
123
- tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
124
- tf.puts ' <xtce:ByteOrderList>' + "\n"
125
- tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
126
- tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
127
- tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
128
- tf.puts ' <xtce:Byte byteSignificance="4"/>' + "\n"
129
- tf.puts ' </xtce:ByteOrderList>' + "\n"
130
- tf.puts '</xtce:IntegerDataEncoding>' + "\n"
131
- tf.puts XTCE_END
132
- tf.close
133
-
134
- @pc.process_file(tf.path, 'TEST')
135
-
136
- packet = @pc.telemetry['TEST']['B']
137
- expect(packet).to_not be_nil
138
- expect(packet.get_item('A').endianness).to eql :BIG_ENDIAN
139
- expect(@pc.warnings).to_not be_empty
140
-
141
- tf.unlink
142
- end
143
-
144
- it "warn of bad byteorderlist scrambled xtce telemetry" do
145
- tf = Tempfile.new(['unittest', '.xtce'])
146
- tf.puts XTCE_START
147
- tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
148
- tf.puts ' <xtce:ByteOrderList>' + "\n"
149
- tf.puts ' <xtce:Byte byteSignificance="0"/>' + "\n"
150
- tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
151
- tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
152
- tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
153
- tf.puts ' </xtce:ByteOrderList>' + "\n"
154
- tf.puts '</xtce:IntegerDataEncoding>' + "\n"
155
- tf.puts XTCE_END
156
- tf.close
157
-
158
- @pc.process_file(tf.path, 'TEST')
159
-
160
- packet = @pc.telemetry['TEST']['B']
161
- expect(packet).to_not be_nil
162
- expect(packet.get_item('A').endianness).to eql :LITTLE_ENDIAN
163
- expect(@pc.warnings).to_not be_empty
164
-
165
- tf.unlink
166
- end
167
- end
168
-
169
25
  it "complains about unknown keywords" do
170
26
  tf = Tempfile.new('unittest')
171
27
  tf.puts("BLAH")
@@ -174,6 +30,27 @@ module Cosmos
174
30
  tf.unlink
175
31
  end
176
32
 
33
+ it "outputs parsed definitions back to a file" do
34
+ tf = Tempfile.new('unittest')
35
+ tlm = "TELEMETRY TGT1 PKT1 LITTLE_ENDIAN \"Telemetry\"\n"\
36
+ " ITEM BYTE 0 8 UINT \"Item\"\n"
37
+ tf.write tlm
38
+ cmd = "COMMAND TGT1 PKT1 LITTLE_ENDIAN \"Command\"\n"\
39
+ " PARAMETER PARAM 0 16 UINT 0 0 0 \"Param\"\n"
40
+ tf.write cmd
41
+ limits = "LIMITS_GROUP TVAC\n"\
42
+ " LIMITS_GROUP_ITEM TGT1 PKT1 ITEM1\n"
43
+ tf.write limits
44
+ tf.close
45
+ @pc.process_file(tf.path, "TGT1")
46
+ @pc.to_config(System.paths["LOGS"])
47
+ @pc.to_xtce(System.paths["LOGS"])
48
+ expect(cmd.strip).to eql File.read(File.join(System.paths["LOGS"], 'TGT1', 'cmd_tlm', 'tgt1_cmd.txt')).strip
49
+ expect(tlm.strip).to eql File.read(File.join(System.paths["LOGS"], 'TGT1', 'cmd_tlm', 'tgt1_tlm.txt')).strip
50
+ expect(limits.strip).to eql File.read(File.join(System.paths["LOGS"], 'SYSTEM', 'cmd_tlm', 'limits_groups.txt')).strip
51
+ tf.unlink
52
+ end
53
+
177
54
  context "with all telemetry keywords" do
178
55
  before(:all) do
179
56
  # top level keywords
@@ -24,6 +24,7 @@ module Cosmos
24
24
  it "sets the format_string" do
25
25
  @pi.format_string = "%5.1f"
26
26
  expect(@pi.format_string).to eql "%5.1f"
27
+ expect(@pi.to_config(:TELEMETRY, :BIG_ENDIAN)).to match /FORMAT_STRING %5.1f/
27
28
  end
28
29
 
29
30
  it "sets the format_string to nil" do
@@ -47,6 +48,10 @@ module Cosmos
47
48
  c = GenericConversion.new("value / 2")
48
49
  @pi.read_conversion = c
49
50
  expect(@pi.read_conversion.to_s == c.to_s).to be true
51
+ config = @pi.to_config(:TELEMETRY, :BIG_ENDIAN)
52
+ expect(config).to match /GENERIC_READ_CONVERSION_START/
53
+ expect(config).to match /value \/ 2/
54
+ expect(config).to match /GENERIC_READ_CONVERSION_END/
50
55
  end
51
56
 
52
57
  it "sets the read_conversion to nil" do
@@ -64,6 +69,10 @@ module Cosmos
64
69
  c = GenericConversion.new("value / 2")
65
70
  @pi.write_conversion = c
66
71
  expect(@pi.write_conversion.to_s == c.to_s).to be true
72
+ config = @pi.to_config(:TELEMETRY, :BIG_ENDIAN)
73
+ expect(config).to match /GENERIC_WRITE_CONVERSION_START/
74
+ expect(config).to match /value \/ 2/
75
+ expect(config).to match /GENERIC_WRITE_CONVERSION_END/
67
76
  end
68
77
 
69
78
  it "sets the write_conversion to nil" do
@@ -78,14 +87,22 @@ module Cosmos
78
87
 
79
88
  describe "id_value=" do
80
89
  it "accepts id values according to data_type" do
90
+ @pi.range = (0..10)
81
91
  @pi.id_value = 10
82
92
  expect(@pi.id_value).to eql 10
83
93
  @pi.data_type = :FLOAT
84
94
  @pi.id_value = 10.0
85
95
  expect(@pi.id_value).to eql 10.0
96
+ expect(@pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/ID_PARAMETER TEST 0 32 FLOAT 0 10 10.0/)
97
+ expect(@pi.to_config(:TELEMETRY, :BIG_ENDIAN)).to match(/ID_ITEM TEST 0 32 FLOAT 10.0/)
86
98
  @pi.data_type = :STRING
87
99
  @pi.id_value = "HI"
88
100
  expect(@pi.id_value).to eql "HI"
101
+ expect(@pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/ID_PARAMETER TEST 0 32 STRING "HI"/)
102
+ expect(@pi.to_config(:TELEMETRY, :BIG_ENDIAN)).to match(/ID_ITEM TEST 0 32 STRING "HI"/)
103
+ @pi.id_value = "\xDE\xAD\xBE\xEF" # binary
104
+ expect(@pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/ID_PARAMETER TEST 0 32 STRING 0xDEADBEEF/)
105
+ expect(@pi.to_config(:TELEMETRY, :BIG_ENDIAN)).to match(/ID_ITEM TEST 0 32 STRING 0xDEADBEEF/)
89
106
  end
90
107
 
91
108
  it "sets the id_value to nil" do
@@ -105,6 +122,9 @@ module Cosmos
105
122
  states = {"TRUE"=>1, "FALSE"=>0}
106
123
  @pi.states = states
107
124
  expect(@pi.states).to eql states
125
+ config = @pi.to_config(:TELEMETRY, :BIG_ENDIAN)
126
+ expect(config).to match(/STATE TRUE 1/)
127
+ expect(config).to match(/STATE FALSE 0/)
108
128
  end
109
129
 
110
130
  it "sets the states to nil" do
@@ -122,6 +142,7 @@ module Cosmos
122
142
  description = "this is it"
123
143
  @pi.description = description
124
144
  expect(@pi.description).to eql description
145
+ expect(@pi.to_config(:TELEMETRY, :BIG_ENDIAN)).to match(/ITEM TEST 0 32 UINT "this is it"/)
125
146
  end
126
147
 
127
148
  it "sets the description to nil" do
@@ -156,6 +177,8 @@ module Cosmos
156
177
  units = "V"
157
178
  @pi.units = units
158
179
  expect(@pi.units).to eql units
180
+ @pi.units_full = "Volts"
181
+ expect(@pi.to_config(:TELEMETRY, :BIG_ENDIAN)).to match(/UNITS Volts V/)
159
182
  end
160
183
 
161
184
  it "sets the units to nil" do
@@ -173,15 +196,25 @@ module Cosmos
173
196
  pi = PacketItem.new("test", 0, 8, :INT, :BIG_ENDIAN, 16)
174
197
  pi.default = [1, -1]
175
198
  expect(pi.default).to eql [1, -1]
199
+ expect(pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/ARRAY_PARAMETER TEST 0 8 INT 16/)
200
+ expect(pi.to_config(:TELEMETRY, :BIG_ENDIAN)).to match(/ARRAY_ITEM TEST 0 8 INT 16/)
176
201
  pi = PacketItem.new("test", 0, 32, :UINT, :BIG_ENDIAN, nil)
202
+ pi.range = (0..10)
177
203
  pi.default = 0x01020304
178
204
  expect(pi.default).to eql 0x01020304
205
+ expect(pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/PARAMETER TEST 0 32 UINT 0 10 16909060/)
179
206
  pi = PacketItem.new("test", 0, 32, :FLOAT, :BIG_ENDIAN, nil)
207
+ pi.range = (-10..10)
180
208
  pi.default = 5.5
181
209
  expect(pi.default).to eql 5.5
210
+ expect(pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/PARAMETER TEST 0 32 FLOAT -10 10 5.5/)
182
211
  pi = PacketItem.new("test", 0, 32, :STRING, :BIG_ENDIAN, nil)
183
212
  pi.default = "HI"
184
213
  expect(pi.default).to eql "HI"
214
+ expect(pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/PARAMETER TEST 0 32 STRING "HI"/)
215
+ pi = PacketItem.new("test", 0, 32, :STRING, :BIG_ENDIAN, nil)
216
+ pi.default = "\xDE\xAD\xBE\xEF"
217
+ expect(pi.to_config(:COMMAND, :BIG_ENDIAN)).to match(/PARAMETER TEST 0 32 STRING 0xDEADBEEF/)
185
218
  end
186
219
 
187
220
  it "sets the default to nil" do
@@ -269,6 +302,12 @@ module Cosmos
269
302
  expect(@pi.hazardous).to eql hazardous
270
303
  expect(@pi.hazardous["TRUE"]).to eql hazardous["TRUE"]
271
304
  expect(@pi.hazardous["FALSE"]).to eql hazardous["FALSE"]
305
+
306
+ @pi.range = (0..1)
307
+ @pi.states = {"TRUE"=>1, "FALSE"=>0}
308
+ config = @pi.to_config(:COMMAND, :BIG_ENDIAN)
309
+ expect(config).to match(/STATE TRUE 1/)
310
+ expect(config).to match(/STATE FALSE 0 HAZARDOUS "NO FALSE ALLOWED"/)
272
311
  end
273
312
 
274
313
  it "sets hazardous to nil" do
@@ -286,6 +325,12 @@ module Cosmos
286
325
  state_colors = {"TRUE"=>:GREEN, "FALSE"=>:RED}
287
326
  @pi.state_colors = state_colors
288
327
  expect(@pi.state_colors).to eql state_colors
328
+
329
+ @pi.range = (0..1)
330
+ @pi.states = {"TRUE"=>1, "FALSE"=>0}
331
+ config = @pi.to_config(:TELEMETRY, :BIG_ENDIAN)
332
+ expect(config).to match(/STATE TRUE 1 GREEN/)
333
+ expect(config).to match(/STATE FALSE 0 RED/)
289
334
  end
290
335
 
291
336
  it "sets the state_colors to nil" do
@@ -301,7 +346,16 @@ module Cosmos
301
346
  describe "limits=" do
302
347
  it "accepts limits as a PacketItemLimits" do
303
348
  limits = PacketItemLimits.new
349
+ limits.values = {DEFAULT: [10, 20, 80, 90, 40, 50], TVAC: [100, 200, 800, 900]}
304
350
  @pi.limits = limits
351
+ config = @pi.to_config(:TELEMETRY, :BIG_ENDIAN)
352
+ expect(config).to match(/LIMITS DEFAULT 1 DISABLED 10 20 80 90 40 50/)
353
+ expect(config).to match(/LIMITS TVAC 1 DISABLED 100 200 800 900/)
354
+ @pi.limits.enabled = true
355
+ @pi.limits.persistence_setting = 3
356
+ config = @pi.to_config(:TELEMETRY, :BIG_ENDIAN)
357
+ expect(config).to match(/LIMITS DEFAULT 3 ENABLED 10 20 80 90 40 50/)
358
+ expect(config).to match(/LIMITS TVAC 3 ENABLED 100 200 800 900/)
305
359
  end
306
360
 
307
361
  it "sets the limits to nil" do
@@ -314,10 +368,20 @@ module Cosmos
314
368
  end
315
369
  end
316
370
 
317
- describe "meta" do
318
- it "allows adding items to the meta hash" do
319
- @pi.meta['TYPE'] = 'float32'
320
- expect(@pi.meta['TYPE']).to eql 'float32'
371
+ describe "meta=" do
372
+ it "only allows a hash" do
373
+ expect { @pi.meta = 1 }.to raise_error(ArgumentError, /must be a Hash/)
374
+ end
375
+
376
+ it "sets the meta hash" do
377
+ @pi.meta = { 'TYPE' => ['float32', 'uint8'], 'TEST' => ["test string"] }
378
+ expect(@pi.meta['TYPE']).to eql ['float32', 'uint8']
379
+ expect(@pi.meta['TEST']).to eql ["test string"]
380
+ config = @pi.to_config(:TELEMETRY, :BIG_ENDIAN)
381
+ expect(config).to match(/META TYPE float32 uint8/)
382
+ expect(config).to match(/META TEST "test string"/)
383
+ @pi.meta = nil # Clear the meta hash
384
+ expect(@pi.meta.empty?).to be true # Clearing it results in empty hash
321
385
  end
322
386
  end
323
387