cosmos 4.1.0 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
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