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
@@ -288,39 +288,51 @@ module Cosmos
288
288
  packet.buffer = "\x00\x00\x00\x01" * 16
289
289
  expect(packet.get_item("ITEM1").range).to eql (1..2)
290
290
  expect(packet.get_item("ITEM1").default).to eql 3
291
+ expect(packet.get_item("ITEM1").id_value).to eql 3
291
292
  expect(packet.read("ITEM1")).to eql 0x01000000
292
293
  expect(packet.get_item("ITEM2").range).to eql (4..5)
293
294
  expect(packet.get_item("ITEM2").default).to eql 6
295
+ expect(packet.get_item("ITEM2").id_value).to eql nil
294
296
  expect(packet.read("ITEM2")).to eql 0x01000000
295
297
  expect(packet.get_item("ITEM3").range).to be_nil
296
298
  expect(packet.get_item("ITEM3").default).to eql []
299
+ expect(packet.get_item("ITEM3").id_value).to eql nil
297
300
  expect(packet.read("ITEM3")).to eql [0x01000000, 0x01000000]
298
301
  expect(packet.get_item("ITEM4").range).to eql (7..8)
299
302
  expect(packet.get_item("ITEM4").default).to eql 9
303
+ expect(packet.get_item("ITEM4").id_value).to eql 9
300
304
  expect(packet.read("ITEM4")).to eql 0x01000000
301
305
  expect(packet.get_item("ITEM5").range).to eql (10..11)
302
306
  expect(packet.get_item("ITEM5").default).to eql 12
307
+ expect(packet.get_item("ITEM5").id_value).to eql nil
303
308
  expect(packet.read("ITEM5")).to eql 0x01000000
304
309
  expect(packet.get_item("ITEM6").range).to be_nil
305
310
  expect(packet.get_item("ITEM6").default).to eql []
311
+ expect(packet.get_item("ITEM6").id_value).to eql nil
306
312
  expect(packet.read("ITEM6")).to eql [0x01000000, 0x01000000]
307
313
  expect(packet.get_item("ITEM10").range).to eql (13..14)
308
314
  expect(packet.get_item("ITEM10").default).to eql 15
315
+ expect(packet.get_item("ITEM10").id_value).to eql 15
309
316
  expect(packet.read("ITEM10")).to eql 0x00000001
310
317
  expect(packet.get_item("ITEM20").range).to eql (16..17)
311
318
  expect(packet.get_item("ITEM20").default).to eql 18
319
+ expect(packet.get_item("ITEM20").id_value).to eql nil
312
320
  expect(packet.read("ITEM20")).to eql 0x00000001
313
321
  expect(packet.get_item("ITEM30").range).to be_nil
314
322
  expect(packet.get_item("ITEM30").default).to eql []
323
+ expect(packet.get_item("ITEM30").id_value).to eql nil
315
324
  expect(packet.read("ITEM30")).to eql [0x00000001, 0x00000001]
316
325
  expect(packet.get_item("ITEM40").range).to eql (19..20)
317
326
  expect(packet.get_item("ITEM40").default).to eql 21
327
+ expect(packet.get_item("ITEM40").id_value).to eql 21
318
328
  expect(packet.read("ITEM40")).to eql 0x00000001
319
329
  expect(packet.get_item("ITEM50").range).to eql (22..23)
320
330
  expect(packet.get_item("ITEM50").default).to eql 24
331
+ expect(packet.get_item("ITEM50").id_value).to eql nil
321
332
  expect(packet.read("ITEM50")).to eql 0x00000001
322
333
  expect(packet.get_item("ITEM60").range).to be_nil
323
334
  expect(packet.get_item("ITEM60").default).to eql []
335
+ expect(packet.get_item("ITEM60").id_value).to eql nil
324
336
  expect(packet.read("ITEM60")).to eql [0x00000001, 0x00000001]
325
337
  tf.unlink
326
338
  end
@@ -0,0 +1,398 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'spec_helper'
12
+ require 'cosmos'
13
+ require 'cosmos/packets/packet_config'
14
+ require 'tempfile'
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:UnitSet/>
30
+ </xtce:Parameter>
31
+ </xtce:ParameterSet>
32
+ <xtce:ContainerSet>
33
+ <xtce:SequenceContainer name="B_Base" abstract="true">
34
+ <xtce:EntryList>
35
+ <xtce:ParameterRefEntry parameterRef="A"/>
36
+ </xtce:EntryList>
37
+ </xtce:SequenceContainer>
38
+ <xtce:SequenceContainer name="B" shortDescription="B">
39
+ <xtce:EntryList/>
40
+ <xtce:BaseContainer containerRef="B_Base">
41
+ </xtce:BaseContainer>
42
+ </xtce:SequenceContainer>
43
+ </xtce:ContainerSet>
44
+ </xtce:TelemetryMetaData>
45
+ </xtce:SpaceSystem>
46
+ END
47
+
48
+ module Cosmos
49
+
50
+ describe XtceParser do
51
+ after(:all) do
52
+ #clean_config()
53
+ end
54
+
55
+ def xml_file(target)
56
+ tf = Tempfile.new(['unittest', '.xtce'])
57
+ tf.puts '<?xml version="1.0" encoding="UTF-8"?>'
58
+ tf.puts "<xtce:SpaceSystem xmlns:xtce=\"http://www.omg.org/space/xtce\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"#{target}\" xsi:schemaLocation=\"http://www.omg.org/space/xtce http://www.omg.org/spec/XTCE/20061101/06-11-06.xsd\">"
59
+ yield tf
60
+ tf.puts '</xtce:SpaceSystem>'
61
+ tf.close
62
+ tf
63
+ end
64
+
65
+ def telemetry_file(target)
66
+ xml_file(target) do |tf|
67
+ tf.puts ' <xtce:TelemetryMetaData>'
68
+ yield tf
69
+ tf.puts ' </xtce:TelemetryMetaData>'
70
+ end
71
+ end
72
+
73
+ def add_tlm_packet_item(tf, packet, item)
74
+ tf.puts "<xtce:ParameterTypeSet>"
75
+ tf.puts " <xtce:IntegerParameterType name=\"#{item}_Type\" shortDescription=\"#{item} Description\" signed=\"false\">"
76
+ tf.puts " <xtce:IntegerDataEncoding sizeInBits=\"8\" encoding=\"unsigned\"/>"
77
+ yield tf
78
+ tf.puts " </xtce:IntegerParameterType>"
79
+ tf.puts "</xtce:ParameterTypeSet>"
80
+ tf.puts "<xtce:ParameterSet>"
81
+ tf.puts " <xtce:Parameter name=\"#{item}\" parameterTypeRef=\"#{item}_Type\"/>"
82
+ tf.puts "</xtce:ParameterSet>"
83
+ tf.puts "<xtce:ContainerSet>"
84
+ tf.puts " <xtce:SequenceContainer name=\"#{packet}_Base\" abstract=\"true\">"
85
+ tf.puts " <xtce:EntryList>"
86
+ tf.puts " <xtce:ParameterRefEntry parameterRef=\"#{item}\"/>"
87
+ tf.puts " </xtce:EntryList>"
88
+ tf.puts " </xtce:SequenceContainer>"
89
+ tf.puts " <xtce:SequenceContainer name=\"#{packet}\" shortDescription=\"Telemetry\">"
90
+ tf.puts " <xtce:EntryList/>"
91
+ tf.puts " <xtce:BaseContainer containerRef=\"#{packet}_Base\"/>"
92
+ tf.puts " </xtce:SequenceContainer>"
93
+ tf.puts "</xtce:ContainerSet>"
94
+ end
95
+
96
+ def command_file(target)
97
+ xml_file(target) do |tf|
98
+ tf.puts ' <xtce:CommandMetaData>'
99
+ yield tf
100
+ tf.puts ' </xtce:CommandMetaData>'
101
+ end
102
+ end
103
+
104
+ def add_cmd_packet_item(tf, packet, item)
105
+ tf.puts "<xtce:ArgumentTypeSet>"
106
+ tf.puts " <xtce:IntegerArgumentType name=\"#{item}_Type\" initialValue=\"0\" shortDescription=\"#{item} description\" signed=\"false\">"
107
+ tf.puts " <xtce:ByteOrderList>"
108
+ tf.puts " <xtce:Byte byteSignificance=\"0\"/>"
109
+ tf.puts " <xtce:Byte byteSignificance=\"1\"/>"
110
+ tf.puts " </xtce:ByteOrderList>"
111
+ tf.puts " <xtce:UnitSet/>"
112
+ tf.puts " <xtce:IntegerDataEncoding sizeInBits=\"16\" encoding=\"unsigned\"/>"
113
+ tf.puts " <xtce:ValidRange minInclusive=\"0\" maxInclusive=\"0\"/>"
114
+ tf.puts " </xtce:IntegerArgumentType>"
115
+ tf.puts "</xtce:ArgumentTypeSet>"
116
+ tf.puts "<xtce:MetaCommandSet>"
117
+ tf.puts " <xtce:MetaCommand name=\"#{packet}_Base\" abstract=\"true\">"
118
+ tf.puts " <xtce:ArgumentList>"
119
+ tf.puts " <xtce:Argument name=\"#{item}\" argumentTypeRef=\"#{item}_Type\"/>"
120
+ tf.puts " </xtce:ArgumentList>"
121
+ tf.puts " <xtce:CommandContainer name=\"#{packet}_CommandContainer\">"
122
+ tf.puts " <xtce:EntryList>"
123
+ tf.puts " <xtce:ArgumentRefEntry argumentRef=\"#{item}\"/>"
124
+ tf.puts " </xtce:EntryList>"
125
+ tf.puts " </xtce:CommandContainer>"
126
+ tf.puts " </xtce:MetaCommand>"
127
+ tf.puts " <xtce:MetaCommand name=\"#{packet}\" shortDescription=\"#{packet} description\">"
128
+ tf.puts " <xtce:BaseMetaCommand metaCommandRef=\"#{packet}_Base\"/>"
129
+ tf.puts " </xtce:MetaCommand>"
130
+ tf.puts "</xtce:MetaCommandSet>"
131
+ end
132
+
133
+ describe "process_file" do
134
+ before(:each) do
135
+ @pc = PacketConfig.new
136
+ end
137
+
138
+ it "processes xtce telemetry" do
139
+ tf = Tempfile.new(['unittest', '.xtce'])
140
+ tf.puts XTCE_START
141
+ tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned"/>'
142
+ tf.puts XTCE_END
143
+ tf.close
144
+
145
+ @pc.process_file(tf.path, 'TEST')
146
+ packet = @pc.telemetry['TEST']['B']
147
+ expect(packet).to_not be_nil
148
+ expect(packet.get_item('A').endianness).to eql :BIG_ENDIAN
149
+ tf.unlink
150
+ end
151
+
152
+ it "processes xtce commands" do
153
+ tf = Tempfile.new(['unittest', '.xtce'])
154
+ tf = command_file("TGT") do |tf|
155
+ add_cmd_packet_item(tf, "PKT", "PARAM1")
156
+ end
157
+
158
+ @pc.process_file(tf.path, 'TGT')
159
+ packet = @pc.commands['TGT']['PKT']
160
+ expect(packet).to_not be_nil
161
+ expect(packet.get_item('PARAM1').bit_offset).to eql 0
162
+ expect(packet.get_item('PARAM1').bit_size).to eql 16
163
+ expect(packet.get_item('PARAM1').data_type).to eql :UINT
164
+ expect(packet.get_item('PARAM1').endianness).to eql :LITTLE_ENDIAN
165
+ tf.unlink
166
+ end
167
+
168
+ context "with units" do
169
+ it "processes description and value" do
170
+ tf = telemetry_file("TGT") do |tf|
171
+ add_tlm_packet_item(tf, "PKT", "TEMP1") do |tf|
172
+ tf.puts '<xtce:UnitSet>'
173
+ tf.puts '<xtce:Unit description="Volts">V</xtce:Unit>'
174
+ tf.puts '</xtce:UnitSet>'
175
+ end
176
+ end
177
+
178
+ @pc.process_file(tf.path, 'TGT')
179
+ packet = @pc.telemetry['TGT']['PKT']
180
+ expect(packet).to_not be_nil
181
+ expect(packet.get_item('TEMP1').units).to eql 'V'
182
+ expect(packet.get_item('TEMP1').units_full).to eql 'Volts'
183
+ tf.unlink
184
+ end
185
+
186
+ it "processes description only" do
187
+ tf = telemetry_file("TGT") do |tf|
188
+ add_tlm_packet_item(tf, "PKT", "TEMP1") do |tf|
189
+ tf.puts '<xtce:UnitSet>'
190
+ tf.puts '<xtce:Unit description="Volts"/>'
191
+ tf.puts '</xtce:UnitSet>'
192
+ end
193
+ end
194
+
195
+ @pc.process_file(tf.path, 'TGT')
196
+ packet = @pc.telemetry['TGT']['PKT']
197
+ expect(packet).to_not be_nil
198
+ expect(packet.get_item('TEMP1').units).to eql 'Volts'
199
+ expect(packet.get_item('TEMP1').units_full).to eql 'Volts'
200
+ tf.unlink
201
+ end
202
+
203
+ it "processes value only" do
204
+ tf = telemetry_file("TGT") do |tf|
205
+ add_tlm_packet_item(tf, "PKT", "TEMP1") do |tf|
206
+ tf.puts '<xtce:UnitSet>'
207
+ tf.puts '<xtce:Unit>V</xtce:Unit>'
208
+ tf.puts '</xtce:UnitSet>'
209
+ end
210
+ end
211
+
212
+ @pc.process_file(tf.path, 'TGT')
213
+ packet = @pc.telemetry['TGT']['PKT']
214
+ expect(packet).to_not be_nil
215
+ expect(packet.get_item('TEMP1').units).to eql 'V'
216
+ expect(packet.get_item('TEMP1').units_full).to eql 'V'
217
+ tf.unlink
218
+ end
219
+
220
+ it "processes multiple units" do
221
+ tf = telemetry_file("TGT") do |tf|
222
+ add_tlm_packet_item(tf, "PKT", "TEMP1") do |tf|
223
+ tf.puts '<xtce:UnitSet>'
224
+ tf.puts '<xtce:Unit description="Volts">V</xtce:Unit>'
225
+ tf.puts '<xtce:Unit description="Mega">M</xtce:Unit>'
226
+ tf.puts '</xtce:UnitSet>'
227
+ end
228
+ end
229
+
230
+ @pc.process_file(tf.path, 'TGT')
231
+ packet = @pc.telemetry['TGT']['PKT']
232
+ expect(packet).to_not be_nil
233
+ expect(packet.get_item('TEMP1').units).to eql 'V/M'
234
+ expect(packet.get_item('TEMP1').units_full).to eql 'Volts/Mega'
235
+ tf.unlink
236
+ end
237
+ end
238
+
239
+ it "processes explicit big endian xtce telemetry" do
240
+ tf = Tempfile.new(['unittest', '.xtce'])
241
+ tf.puts XTCE_START
242
+ tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
243
+ tf.puts ' <xtce:ByteOrderList>' + "\n"
244
+ tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
245
+ tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
246
+ tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
247
+ tf.puts ' <xtce:Byte byteSignificance="0"/>' + "\n"
248
+ tf.puts ' </xtce:ByteOrderList>' + "\n"
249
+ tf.puts '</xtce:IntegerDataEncoding>' + "\n"
250
+ tf.puts XTCE_END
251
+ tf.close
252
+
253
+ @pc.process_file(tf.path, 'TEST')
254
+
255
+ packet = @pc.telemetry['TEST']['B']
256
+ expect(packet).to_not be_nil
257
+ expect(packet.get_item('A').endianness).to eql :BIG_ENDIAN
258
+ expect(@pc.warnings).to be_empty
259
+
260
+ tf.unlink
261
+ end
262
+
263
+ it "processes explicit little endian xtce telemetry" do
264
+ tf = Tempfile.new(['unittest', '.xtce'])
265
+ tf.puts XTCE_START
266
+ tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
267
+ tf.puts '
268
+ <xtce:ByteOrderList>' + "\n"
269
+ tf.puts ' <xtce:Byte byteSignificance="0"/>' + "\n"
270
+ tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
271
+ tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
272
+ tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
273
+ tf.puts ' </xtce:ByteOrderList>' + "\n"
274
+ tf.puts '</xtce:IntegerDataEncoding>' + "\n"
275
+ tf.puts XTCE_END
276
+ tf.close
277
+
278
+ @pc.process_file(tf.path, 'TEST')
279
+
280
+ packet = @pc.telemetry['TEST']['B']
281
+ expect(packet).to_not be_nil
282
+ expect(packet.get_item('A').endianness).to eql :LITTLE_ENDIAN
283
+ expect(@pc.warnings).to be_empty
284
+
285
+ tf.unlink
286
+ end
287
+
288
+ it "warns of bad byteorderlist no zero xtce telemetry" do
289
+ tf = Tempfile.new(['unittest', '.xtce'])
290
+ tf.puts XTCE_START
291
+ tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
292
+ tf.puts ' <xtce:ByteOrderList>' + "\n"
293
+ tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
294
+ tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
295
+ tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
296
+ tf.puts ' <xtce:Byte byteSignificance="4"/>' + "\n"
297
+ tf.puts ' </xtce:ByteOrderList>' + "\n"
298
+ tf.puts '</xtce:IntegerDataEncoding>' + "\n"
299
+ tf.puts XTCE_END
300
+ tf.close
301
+
302
+ @pc.process_file(tf.path, 'TEST')
303
+
304
+ packet = @pc.telemetry['TEST']['B']
305
+ expect(packet).to_not be_nil
306
+ expect(packet.get_item('A').endianness).to eql :BIG_ENDIAN
307
+ expect(@pc.warnings).to_not be_empty
308
+
309
+ tf.unlink
310
+ end
311
+
312
+ it "warns of bad byteorderlist scrambled xtce telemetry" do
313
+ tf = Tempfile.new(['unittest', '.xtce'])
314
+ tf.puts XTCE_START
315
+ tf.puts '<xtce:IntegerDataEncoding sizeInBits="32" encoding="unsigned">' + "\n"
316
+ tf.puts ' <xtce:ByteOrderList>' + "\n"
317
+ tf.puts ' <xtce:Byte byteSignificance="0"/>' + "\n"
318
+ tf.puts ' <xtce:Byte byteSignificance="2"/>' + "\n"
319
+ tf.puts ' <xtce:Byte byteSignificance="1"/>' + "\n"
320
+ tf.puts ' <xtce:Byte byteSignificance="3"/>' + "\n"
321
+ tf.puts ' </xtce:ByteOrderList>' + "\n"
322
+ tf.puts '</xtce:IntegerDataEncoding>' + "\n"
323
+ tf.puts XTCE_END
324
+ tf.close
325
+
326
+ @pc.process_file(tf.path, 'TEST')
327
+
328
+ packet = @pc.telemetry['TEST']['B']
329
+ expect(packet).to_not be_nil
330
+ expect(packet.get_item('A').endianness).to eql :LITTLE_ENDIAN
331
+ expect(@pc.warnings).to_not be_empty
332
+
333
+ tf.unlink
334
+ end
335
+
336
+ it "outputs parsed definitions back to a file" do
337
+ tf = Tempfile.new('unittest')
338
+ cmd = "COMMAND TGT1 CMDPKT LITTLE_ENDIAN \"Command\"\n"\
339
+ " ID_PARAMETER CMD_OPCODE 0 16 UINT 0 0 0 \"Opcode\"\n"\
340
+ " PARAMETER CMD_UNSIGNED 16 16 UINT 0 65535 1 \"Unsigned\"\n"\
341
+ " STATE FALSE 0\n"\
342
+ " STATE TRUE 1\n"\
343
+ " PARAMETER CMD_SIGNED 32 16 INT -100 100 0 \"Signed\"\n"\
344
+ " UNITS Kilos K\n"\
345
+ " ARRAY_PARAMETER CMD_ARRAY 48 64 FLOAT 640 \"Array of 10 64bit floats\"\n"\
346
+ " PARAMETER CMD_FLOAT 688 32 FLOAT MIN MAX 10.0 \"Float\"\n"\
347
+ " POLY_WRITE_CONVERSION 10.0 0.5 0.25\n"\
348
+ " PARAMETER CMD_DOUBLE 720 64 FLOAT MIN MAX 0.0 \"Double\"\n"\
349
+ " PARAMETER CMD_STRING 784 32 STRING \"DEAD\" \"String\"\n"\
350
+ " PARAMETER CMD_STRING2 816 32 STRING 0xDEAD \"Binary\"\n"\
351
+ " PARAMETER CMD_BLOCK 848 32 BLOCK 0xBEEF \"Block\"\n"
352
+ tf.puts cmd
353
+ tlm1 = "TELEMETRY TGT1 TLMPKT BIG_ENDIAN \"Telemetry\"\n"\
354
+ " ID_ITEM TLM_OPCODE 0 8 UINT 1 \"Opcode\"\n"\
355
+ " ITEM UNSIGNED 8 8 UINT \"Unsigned\"\n"\
356
+ " STATE FALSE 0\n"\
357
+ " STATE TRUE 1\n"\
358
+ " ITEM SIGNED 16 8 INT \"Signed\"\n"\
359
+ " UNITS Kilos K\n"\
360
+ " ARRAY_ITEM ARRAY 24 8 UINT 80 \"Array\"\n"\
361
+ " ITEM FLOAT 104 32 FLOAT \"Float\"\n"\
362
+ " POLY_READ_CONVERSION 10.0 0.5 0.25\n"\
363
+ " ITEM DOUBLE 136 64 FLOAT \"Double\"\n"\
364
+ " LIMITS DEFAULT 1 ENABLED -80.0 -70.0 60.0 80.0\n"\
365
+ " ITEM STRING 200 32 STRING \"String\"\n"\
366
+ " ITEM BLOCK 232 32 BLOCK \"Block\"\n"\
367
+ " ITEM NOT_PACKED 300 8 UINT \"Not packed\"\n"
368
+ tf.puts tlm1
369
+ tlm2 = "TELEMETRY TGT1 TLMPKT2 BIG_ENDIAN \"Telemetry\"\n"\
370
+ " ID_ITEM TLM_OPCODE2 0 8 UINT 1 \"Opcode\"\n"\
371
+ " ITEM UNSIGNED2 8 32 UINT \"Little endian\" LITTLE_ENDIAN\n"\
372
+ " UNITS Kilos K\n"\
373
+ " ITEM SIGNED2 40 8 INT \"Signed\"\n"\
374
+ " LIMITS DEFAULT 1 ENABLED -80.0 -70.0 60.0 80.0\n"\
375
+ " ITEM SIGNED3 48 8 INT \"Signed3\"\n"
376
+ tf.puts tlm2
377
+ limits = "LIMITS_GROUP TVAC\n"\
378
+ " LIMITS_GROUP_ITEM TGT1 TLMPKT UNSIGNED\n"
379
+ tf.puts limits
380
+ tf.close
381
+ @pc.process_file(tf.path, "TGT1")
382
+ @pc.to_xtce(System.paths["LOGS"])
383
+ xml_path = File.join(System.paths["LOGS"], "TGT1", "cmd_tlm", "tgt1.xtce")
384
+ expect(File.exist?(xml_path)).to be true
385
+ @pc.process_file(xml_path, "TGT1")
386
+ @pc.to_config(System.paths["LOGS"])
387
+ cmd_config_path = File.join(System.paths["LOGS"], "TGT1", "cmd_tlm", "tgt1_cmd.txt")
388
+ expect(File.read(cmd_config_path)).to include(cmd)
389
+ tlm_config_path = File.join(System.paths["LOGS"], "TGT1", "cmd_tlm", "tgt1_tlm.txt")
390
+ tlm = File.read(tlm_config_path)
391
+ expect(tlm).to include(tlm1)
392
+ expect(tlm).to include(tlm2)
393
+ tf.unlink
394
+ end
395
+
396
+ end # describe "process_file"
397
+ end
398
+ end
@@ -0,0 +1,401 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'spec_helper'
12
+ require 'cosmos'
13
+ require 'cosmos/tools/tlm_viewer/tlm_viewer_config'
14
+ require 'tempfile'
15
+ require 'ostruct'
16
+
17
+ module Cosmos
18
+
19
+ describe TlmViewerConfig do
20
+ before(:all) do
21
+ # Allow the require widget to work
22
+ Cosmos.add_to_search_path(File.join(Cosmos::USERPATH,'../../lib/cosmos/tools/tlm_viewer/widgets'))
23
+ end
24
+
25
+ describe "initialize" do
26
+ it "checks for a given filename" do
27
+ expect { TlmViewerConfig.new('blah_file.txt') }.to raise_error("Configuration file blah_file.txt does not exist.")
28
+ end
29
+
30
+ it "raises on unknown parameters" do
31
+ tf = Tempfile.new('mylauncher.txt')
32
+ tf.puts "UNKNOWN"
33
+ tf.close
34
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
35
+ tf.unlink
36
+ end
37
+
38
+ describe 'NEW_COLUMN' do
39
+ it "creates a new column in the configuration" do
40
+ tf = Tempfile.new('mylauncher.txt')
41
+ tf.puts "NEW_COLUMN"
42
+ tf.close
43
+
44
+ tvc = TlmViewerConfig.new(tf.path)
45
+ expect(tvc.columns.length).to eq 2 # Starts with 1 by default
46
+ tf.unlink
47
+
48
+ tf = Tempfile.new('mylauncher.txt')
49
+ tf.puts "NEW_COLUMN"
50
+ tf.puts "NEW_COLUMN"
51
+ tf.close
52
+
53
+ tvc = TlmViewerConfig.new(tf.path)
54
+ expect(tvc.columns.length).to eq 3
55
+ tf.unlink
56
+ end
57
+
58
+ it "raises with parameters" do
59
+ tf = Tempfile.new('mylauncher.txt')
60
+ tf.puts "NEW_COLUMN 2"
61
+ tf.close
62
+
63
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
64
+ tf.unlink
65
+ end
66
+ end
67
+
68
+ describe 'AUTO_TARGETS' do
69
+ it "automatically parses all target screen directories" do
70
+ tf = Tempfile.new('mylauncher.txt')
71
+ tf.puts "AUTO_TARGETS"
72
+ tf.close
73
+
74
+ tvc = TlmViewerConfig.new(tf.path)
75
+ expect(tvc.screen_infos.include?("INST HS")).to be true
76
+ expect(tvc.screen_infos.include?("SYSTEM STATUS")).to be true
77
+ tf.unlink
78
+ end
79
+
80
+ it "raises with parameters" do
81
+ tf = Tempfile.new('mylauncher.txt')
82
+ tf.puts "AUTO_TARGETS TRUE"
83
+ tf.close
84
+
85
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
86
+ tf.unlink
87
+ end
88
+ end
89
+
90
+ describe 'AUTO_TARGET' do
91
+ it "automatically parses the target screen directories" do
92
+ tf = Tempfile.new('mylauncher.txt')
93
+ tf.puts "AUTO_TARGET INST"
94
+ tf.close
95
+
96
+ tvc = TlmViewerConfig.new(tf.path)
97
+ expect(tvc.screen_infos.include?("INST HS")).to be true
98
+ expect(tvc.screen_infos.include?("SYSTEM STATUS")).to be false
99
+ tf.unlink
100
+ end
101
+
102
+ it "raises with parameters" do
103
+ tf = Tempfile.new('mylauncher.txt')
104
+ tf.puts "AUTO_TARGET"
105
+ tf.close
106
+
107
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
108
+ tf.unlink
109
+ end
110
+
111
+ it "raises with more than one parameter" do
112
+ tf = Tempfile.new('mylauncher.txt')
113
+ tf.puts "AUTO_TARGET INST TRUE"
114
+ tf.close
115
+
116
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
117
+ tf.unlink
118
+ end
119
+
120
+ it "raises with an unknown target" do
121
+ tf = Tempfile.new('mylauncher.txt')
122
+ tf.puts "AUTO_TARGET BLAH"
123
+ tf.close
124
+
125
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
126
+ tf.unlink
127
+ end
128
+ end
129
+
130
+ describe 'TARGET' do
131
+ it "raises with no parameters" do
132
+ tf = Tempfile.new('mylauncher.txt')
133
+ tf.puts "TARGET"
134
+ tf.close
135
+
136
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
137
+ tf.unlink
138
+ end
139
+
140
+ it "raises with more than one parameter" do
141
+ tf = Tempfile.new('mylauncher.txt')
142
+ tf.puts "TARGET INST TRUE"
143
+ tf.close
144
+
145
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
146
+ tf.unlink
147
+ end
148
+
149
+ it "raises with an unknown target" do
150
+ tf = Tempfile.new('mylauncher.txt')
151
+ tf.puts "TARGET BLAH"
152
+ tf.close
153
+
154
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
155
+ tf.unlink
156
+ end
157
+ end
158
+
159
+ describe "SCREEN" do
160
+ it "parses a specified target, screen and position" do
161
+ tf = Tempfile.new('mylauncher.txt')
162
+ tf.puts "TARGET INST"
163
+ tf.puts "SCREEN hs.txt 100 200"
164
+ tf.close
165
+
166
+ tvc = TlmViewerConfig.new(tf.path)
167
+ expect(tvc.screen_infos.include?("INST HS")).to be true
168
+ expect(tvc.screen_infos["INST HS"].x_pos).to eql 100
169
+ expect(tvc.screen_infos["INST HS"].y_pos).to eql 200
170
+ tf.unlink
171
+ end
172
+
173
+ it "raises unless preceeded by TARGET" do
174
+ tf = Tempfile.new('mylauncher.txt')
175
+ tf.puts "SCREEN hs.txt"
176
+ tf.close
177
+
178
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
179
+ tf.unlink
180
+ end
181
+
182
+ it "raises with no parameters" do
183
+ tf = Tempfile.new('mylauncher.txt')
184
+ tf.puts "TARGET INST"
185
+ tf.puts "SCREEN"
186
+ tf.close
187
+
188
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
189
+ tf.unlink
190
+ end
191
+
192
+ it "raises with more than 3 parameters" do
193
+ tf = Tempfile.new('mylauncher.txt')
194
+ tf.puts "TARGET INST"
195
+ tf.puts "SCREEN hs.txt 100 200 300"
196
+ tf.close
197
+
198
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
199
+ tf.unlink
200
+ end
201
+ end
202
+
203
+ describe "SHOW_ON_STARTUP" do
204
+ it "indicates a screen should be shown when TlmViewer launches" do
205
+ tf = Tempfile.new('mylauncher.txt')
206
+ tf.puts "TARGET INST"
207
+ tf.puts "SCREEN hs.txt 100 200"
208
+ tf.puts "SHOW_ON_STARTUP"
209
+ tf.close
210
+
211
+ tvc = TlmViewerConfig.new(tf.path)
212
+ expect(tvc.screen_infos.include?("INST HS")).to be true
213
+ expect(tvc.screen_infos["INST HS"].show_on_startup).to be true
214
+ tf.unlink
215
+ end
216
+
217
+ it "raises unless preceeded by SCREEN" do
218
+ tf = Tempfile.new('mylauncher.txt')
219
+ tf.puts "SHOW_ON_STARTUP"
220
+ tf.close
221
+
222
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
223
+ tf.unlink
224
+ end
225
+
226
+ it "raises with parameters" do
227
+ tf = Tempfile.new('mylauncher.txt')
228
+ tf.puts "TARGET INST"
229
+ tf.puts "SCREEN hs.txt"
230
+ tf.puts "SHOW_ON_STARTUP TRUE"
231
+ tf.close
232
+
233
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
234
+ tf.unlink
235
+ end
236
+ end
237
+
238
+ describe "ADD_SHOW_ON_STARTUP" do
239
+ it "indicates a screen should be shown when TlmViewer launches" do
240
+ tf = Tempfile.new('mylauncher.txt')
241
+ tf.puts "AUTO_TARGETS"
242
+ tf.puts "ADD_SHOW_ON_STARTUP INST HS 100 200"
243
+ tf.close
244
+
245
+ tvc = TlmViewerConfig.new(tf.path)
246
+ expect(tvc.screen_infos.include?("INST HS")).to be true
247
+ expect(tvc.screen_infos["INST HS"].show_on_startup).to be true
248
+ tf.unlink
249
+ end
250
+
251
+ it "raises if the screen wasn't previously defined" do
252
+ tf = Tempfile.new('mylauncher.txt')
253
+ tf.puts "ADD_SHOW_ON_STARTUP INST HS 100 200"
254
+ tf.close
255
+
256
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
257
+ tf.unlink
258
+ end
259
+
260
+ it "raises with less than 2 parameters" do
261
+ tf = Tempfile.new('mylauncher.txt')
262
+ tf.puts "ADD_SHOW_ON_STARTUP INST"
263
+ tf.close
264
+
265
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
266
+ tf.unlink
267
+ end
268
+
269
+ it "raises with more than 4 parameters" do
270
+ tf = Tempfile.new('mylauncher.txt')
271
+ tf.puts "ADD_SHOW_ON_STARTUP INST hs.txt 100 200 300"
272
+ tf.close
273
+
274
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
275
+ tf.unlink
276
+ end
277
+ end
278
+
279
+ describe "GROUP" do
280
+ it "defines a new group in TlmViewer" do
281
+ tf = Tempfile.new('mylauncher.txt')
282
+ tf.puts "GROUP Tester"
283
+ tf.close
284
+
285
+ tvc = TlmViewerConfig.new(tf.path)
286
+ expect(tvc.columns[0].keys.include?("Tester")).to be true
287
+ tf.unlink
288
+ end
289
+
290
+ it "raises with no parameters" do
291
+ tf = Tempfile.new('mylauncher.txt')
292
+ tf.puts "GROUP"
293
+ tf.close
294
+
295
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
296
+ tf.unlink
297
+ end
298
+
299
+ it "raises with more than 1 parameter" do
300
+ tf = Tempfile.new('mylauncher.txt')
301
+ tf.puts "GROUP Tester Tester"
302
+ tf.close
303
+
304
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
305
+ tf.unlink
306
+ end
307
+ end
308
+
309
+ describe "GROUP_SCREEN" do
310
+ it "defines a screen in a group" do
311
+ tf = Tempfile.new('mylauncher.txt')
312
+ #tf.puts "AUTO_TARGETS"
313
+ tf.puts "TARGET INST"
314
+ tf.puts "SCREEN hs.txt"
315
+ tf.puts "GROUP Tester"
316
+ tf.puts "GROUP_SCREEN INST HS 100 200"
317
+ tf.close
318
+
319
+ tvc = TlmViewerConfig.new(tf.path)
320
+ expect(tvc.columns[0]["Tester"]["INST_HS"].group).to eql "Tester"
321
+ tf.unlink
322
+ end
323
+
324
+ it "raises with less than 2 parameters" do
325
+ tf = Tempfile.new('mylauncher.txt')
326
+ tf.puts "GROUP_SCREEN INST"
327
+ tf.close
328
+
329
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
330
+ tf.unlink
331
+ end
332
+
333
+ it "raises with more than 4 parameter" do
334
+ tf = Tempfile.new('mylauncher.txt')
335
+ tf.puts "GROUP_SCREEN INST HS 100 200 300"
336
+ tf.close
337
+
338
+ expect { TlmViewerConfig.new(tf.path) }.to raise_error(Cosmos::ConfigParser::Error)
339
+ tf.unlink
340
+ end
341
+ end
342
+
343
+ describe "to_save" do
344
+ it "saves AUTO_TARGETS as TARGET/SCREEN" do
345
+ tf = Tempfile.new('mylauncher.txt')
346
+ tf.puts "AUTO_TARGETS"
347
+ tf.close
348
+
349
+ tvc = TlmViewerConfig.new(tf.path)
350
+ config_file = File.join(Cosmos::USERPATH, "test_config.txt")
351
+ tvc.save(config_file)
352
+ tf.unlink
353
+
354
+ config = File.read(config_file)
355
+ expect(config).to match /TARGET "INST"/
356
+ expect(config).to match /SCREEN "hs.txt"/
357
+ expect(config).to match /TARGET "SYSTEM"/
358
+ expect(config).to match /SCREEN "status.txt"/
359
+ end
360
+
361
+ it "saves the configuration" do
362
+ tf = Tempfile.new('mylauncher.txt')
363
+ inst_hs = "TARGET \"INST\"\n"\
364
+ " SCREEN \"hs.txt\"\n"\
365
+ " SHOW_ON_STARTUP\n"
366
+ tf.puts inst_hs
367
+ tf.puts "NEW_COLUMN"
368
+ test_group = "GROUP \"Test\"\n"\
369
+ " GROUP_SCREEN SYSTEM STATUS 100 200\n"\
370
+ " GROUP_SCREEN INST HS\n"\
371
+ " SHOW_ON_STARTUP\n"
372
+ tf.puts test_group
373
+ another_group = "GROUP \"2Another\"\n"\
374
+ " GROUP_SCREEN INST HS\n"\
375
+ " GROUP_SCREEN SYSTEM STATUS 300 400\n"\
376
+ " SHOW_ON_STARTUP\n"
377
+ tf.puts another_group
378
+ tf.puts "NEW_COLUMN"
379
+ tf.puts "TARGET SYSTEM"
380
+ tf.puts " SCREEN status.txt"
381
+ tf.puts "ADD_SHOW_ON_STARTUP SYSTEM STATUS 500 600"
382
+ tf.close
383
+
384
+ tvc = TlmViewerConfig.new(tf.path)
385
+ config_file = File.join(Cosmos::USERPATH, "test_config.txt")
386
+ tvc.save(config_file)
387
+ tf.unlink
388
+
389
+ config = File.read(config_file)
390
+ expect(config).to include(inst_hs)
391
+ expect(config).to include(test_group)
392
+ expect(config).to include(test_group)
393
+ expect(config).to include("TARGET \"SYSTEM\"\n SCREEN \"status.txt\" 500 600\n SHOW_ON_STARTUP")
394
+ expect(config.scan(/NEW_COLUMN/).count).to eql 2
395
+ end
396
+ end
397
+
398
+ end
399
+ end
400
+ end
401
+