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
@@ -0,0 +1,156 @@
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 'cosmos/packets/parsers/state_parser'
15
+ require 'tempfile'
16
+
17
+ module Cosmos
18
+
19
+ describe StateParser do
20
+
21
+ describe "process_file" do
22
+ before(:each) do
23
+ @pc = PacketConfig.new
24
+ end
25
+
26
+ it "should complain if a current item is not defined" do
27
+ # Check for missing ITEM definitions
28
+ tf = Tempfile.new('unittest')
29
+ tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
30
+ tf.puts 'STATE'
31
+ tf.close
32
+ expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "No current item for STATE")
33
+ tf.unlink
34
+ end
35
+
36
+ it "should complain if there are not enough parameters" do
37
+ tf = Tempfile.new('unittest')
38
+ tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
39
+ tf.puts 'ITEM myitem 0 8 UINT "Test Item"'
40
+ tf.puts 'STATE'
41
+ tf.close
42
+ expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Not enough parameters for STATE/)
43
+ tf.unlink
44
+ end
45
+
46
+ it "should complain if there are too many parameters" do
47
+ tf = Tempfile.new('unittest')
48
+ tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
49
+ tf.puts 'ITEM myitem 0 8 UINT "Test Item"'
50
+ tf.puts 'STATE mystate 0 RED extra'
51
+ tf.close
52
+ expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Too many parameters for STATE/)
53
+ tf.unlink
54
+ end
55
+
56
+ it "should support STRING items" do
57
+ tf = Tempfile.new('unittest')
58
+ tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
59
+ tf.puts ' APPEND_ITEM item1 128 STRING "state item"'
60
+ tf.puts ' STATE FALSE "FALSE STRING"'
61
+ tf.puts ' STATE TRUE "TRUE STRING"'
62
+ tf.close
63
+ @pc.process_file(tf.path, "TGT1")
64
+ @pc.telemetry["TGT1"]["PKT1"].write("ITEM1", "TRUE STRING")
65
+ @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql "TRUE"
66
+ @pc.telemetry["TGT1"]["PKT1"].write("ITEM1", "FALSE STRING")
67
+ @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql "FALSE"
68
+ tf.unlink
69
+ end
70
+
71
+ it "should warn about duplicate states and replace the duplicate" do
72
+ tf = Tempfile.new('unittest')
73
+ tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
74
+ tf.puts ' APPEND_PARAMETER item1 8 UINT 0 2 0 "state item"'
75
+ tf.puts ' STATE FALSE 0'
76
+ tf.puts ' STATE TRUE 1'
77
+ tf.puts ' STATE FALSE 2'
78
+ tf.close
79
+ @pc.process_file(tf.path, "TGT1")
80
+ @pc.warnings.should include("Duplicate state defined on line 5: STATE FALSE 2")
81
+ @pc.commands["TGT1"]["PKT1"].buffer = "\x00"
82
+ @pc.commands["TGT1"]["PKT1"].read("ITEM1").should eql 0
83
+ @pc.commands["TGT1"]["PKT1"].buffer = "\x02"
84
+ @pc.commands["TGT1"]["PKT1"].read("ITEM1").should eql "FALSE"
85
+ tf.unlink
86
+ end
87
+
88
+ context "with telemetry" do
89
+ it "should only allow GREEN YELLOW or RED" do
90
+ tf = Tempfile.new('unittest')
91
+ tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
92
+ tf.puts ' APPEND_ITEM item1 8 UINT "state item"'
93
+ tf.puts ' STATE WORST 1 ORANGE'
94
+ tf.close
95
+ expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Invalid state color ORANGE/)
96
+ tf.unlink
97
+ end
98
+
99
+ it "should record the state values and colors" do
100
+ tf = Tempfile.new('unittest')
101
+ tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
102
+ tf.puts ' APPEND_ITEM item1 8 UINT "state item"'
103
+ tf.puts ' STATE STATE1 1 RED'
104
+ tf.puts ' STATE STATE2 2 YELLOW'
105
+ tf.puts ' STATE STATE3 3 GREEN'
106
+ tf.puts ' STATE STATE4 4'
107
+ tf.close
108
+ @pc.process_file(tf.path, "TGT1")
109
+ index = 1
110
+ colors = [:RED, :YELLOW, :GREEN]
111
+ @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"].states.each do |name,val|
112
+ name.should eql "STATE#{index}"
113
+ val.should eql index
114
+ @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"].state_colors[name].should eql colors[index - 1]
115
+
116
+ index += 1
117
+ end
118
+ @pc.telemetry["TGT1"]["PKT1"].limits_items.should eql [@pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]]
119
+ tf.unlink
120
+ end
121
+ end
122
+
123
+ context "with command" do
124
+ it "should only allow HAZARDOUS as the third param" do
125
+ tf = Tempfile.new('unittest')
126
+ tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
127
+ tf.puts ' APPEND_PARAMETER item1 8 UINT 0 0 0'
128
+ tf.puts ' STATE WORST 0 RED'
129
+ tf.close
130
+ expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /HAZARDOUS expected as third parameter/)
131
+ tf.unlink
132
+ end
133
+
134
+ it "should take HAZARDOUS and an optional description" do
135
+ tf = Tempfile.new('unittest')
136
+ tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
137
+ tf.puts ' APPEND_PARAMETER item1 8 UINT 1 3 1'
138
+ tf.puts ' STATE GOOD 1'
139
+ tf.puts ' STATE BAD 2 HAZARDOUS'
140
+ tf.puts ' STATE WORST 3 HAZARDOUS "Hazardous description"'
141
+ tf.close
142
+ @pc.process_file(tf.path, "TGT1")
143
+ @pc.commands["TGT1"]["PKT1"].buffer = "\x01"
144
+ @pc.commands["TGT1"]["PKT1"].check_limits
145
+ @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["GOOD"].should be_nil
146
+ @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["BAD"].should_not be_nil
147
+ @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["WORST"].should_not be_nil
148
+ @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["WORST"].should eql "Hazardous description"
149
+ @pc.commands["TGT1"]["PKT1"].limits_items.should be_empty
150
+ tf.unlink
151
+ end
152
+ end
153
+
154
+ end
155
+ end
156
+ end
@@ -18,7 +18,7 @@ module Cosmos
18
18
 
19
19
  describe "name=" do
20
20
  it "should create new structure items" do
21
- StructureItem.new("test", 0, 8, :UINT, :BIG_ENDIAN, nil).name.should eql "test"
21
+ StructureItem.new("test", 0, 8, :UINT, :BIG_ENDIAN, nil).name.should eql "TEST"
22
22
  end
23
23
 
24
24
  it "should complain about non String names" do
@@ -38,7 +38,7 @@ module Cosmos
38
38
  end
39
39
 
40
40
  it "should complain about bad endianness" do
41
- expect { StructureItem.new("test", 0, 8, :UINT, :BLAH, nil) }.to raise_error(ArgumentError, "test: unknown endianness: BLAH - Must be :BIG_ENDIAN or :LITTLE_ENDIAN")
41
+ expect { StructureItem.new("test", 0, 8, :UINT, :BLAH, nil) }.to raise_error(ArgumentError, "TEST: unknown endianness: BLAH - Must be :BIG_ENDIAN or :LITTLE_ENDIAN")
42
42
  end
43
43
  end
44
44
 
@@ -51,7 +51,7 @@ module Cosmos
51
51
  end
52
52
 
53
53
  it "should complain about bad data types" do
54
- expect { StructureItem.new("test", 0, 0, :UNKNOWN, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: unknown data_type: UNKNOWN - Must be :INT, :UINT, :FLOAT, :STRING, :BLOCK, or :DERIVED")
54
+ expect { StructureItem.new("test", 0, 0, :UNKNOWN, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: unknown data_type: UNKNOWN - Must be :INT, :UINT, :FLOAT, :STRING, :BLOCK, or :DERIVED")
55
55
  end
56
56
  end
57
57
 
@@ -63,39 +63,39 @@ module Cosmos
63
63
  end
64
64
 
65
65
  it "should complain about bad overflow types" do
66
- expect { StructureItem.new("test", 0, 32, :INT, :BIG_ENDIAN, nil, :UNKNOWN) }.to raise_error(ArgumentError, "test: unknown overflow type: UNKNOWN - Must be :ERROR, :ERROR_ALLOW_HEX, :TRUNCATE, or :SATURATE")
66
+ expect { StructureItem.new("test", 0, 32, :INT, :BIG_ENDIAN, nil, :UNKNOWN) }.to raise_error(ArgumentError, "TEST: unknown overflow type: UNKNOWN - Must be :ERROR, :ERROR_ALLOW_HEX, :TRUNCATE, or :SATURATE")
67
67
  end
68
68
  end
69
69
 
70
70
  describe "bit_offset=" do
71
71
  it "should compain about bad bit offsets types" do
72
- expect { StructureItem.new("test", nil, 8, :UINT, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: bit_offset must be a Fixnum")
72
+ expect { StructureItem.new("test", nil, 8, :UINT, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: bit_offset must be a Fixnum")
73
73
  end
74
74
 
75
75
  it "should complain about unaligned bit offsets" do
76
76
  %w(FLOAT STRING BLOCK).each do |type|
77
- expect { StructureItem.new("test", 1, 32, type.to_sym, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: bit_offset for :FLOAT, :STRING, and :BLOCK items must be byte aligned")
77
+ expect { StructureItem.new("test", 1, 32, type.to_sym, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: bit_offset for :FLOAT, :STRING, and :BLOCK items must be byte aligned")
78
78
  end
79
79
  end
80
80
 
81
81
  it "should complain about non zero DERIVED bit offsets" do
82
- expect { StructureItem.new("test", 8, 0, :DERIVED, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: DERIVED items must have bit_offset of zero")
82
+ expect { StructureItem.new("test", 8, 0, :DERIVED, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: DERIVED items must have bit_offset of zero")
83
83
  end
84
84
  end
85
85
 
86
86
  describe "bit_size=" do
87
87
  it "should complain about bad bit sizes types" do
88
- expect { StructureItem.new("test", 0, nil, :UINT, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: bit_size must be a Fixnum")
88
+ expect { StructureItem.new("test", 0, nil, :UINT, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: bit_size must be a Fixnum")
89
89
  end
90
90
 
91
91
  it "should complain about 0 size INT, UINT, and FLOAT" do
92
92
  %w(INT UINT FLOAT).each do |type|
93
- expect { StructureItem.new("test", 0, 0, type.to_sym, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: bit_size cannot be negative or zero for :INT, :UINT, and :FLOAT items: 0")
93
+ expect { StructureItem.new("test", 0, 0, type.to_sym, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: bit_size cannot be negative or zero for :INT, :UINT, and :FLOAT items: 0")
94
94
  end
95
95
  end
96
96
 
97
97
  it "should complain about bad float bit sizes" do
98
- expect { StructureItem.new("test", 0, 8, :FLOAT, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: bit_size for FLOAT items must be 32 or 64. Given: 8")
98
+ expect { StructureItem.new("test", 0, 8, :FLOAT, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: bit_size for FLOAT items must be 32 or 64. Given: 8")
99
99
  end
100
100
 
101
101
  it "should create 32 and 64 bit floats" do
@@ -104,17 +104,17 @@ module Cosmos
104
104
  end
105
105
 
106
106
  it "should complain about non zero DERIVED bit sizes" do
107
- expect { StructureItem.new("test", 0, 8, :DERIVED, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "test: DERIVED items must have bit_size of zero")
107
+ expect { StructureItem.new("test", 0, 8, :DERIVED, :BIG_ENDIAN, nil) }.to raise_error(ArgumentError, "TEST: DERIVED items must have bit_size of zero")
108
108
  end
109
109
  end
110
110
 
111
111
  describe "array_size=" do
112
112
  it "should complain about bad array size types" do
113
- expect { StructureItem.new("test", 0, 8, :UINT, :BIG_ENDIAN, "") }.to raise_error(ArgumentError, "test: array_size must be a Fixnum")
113
+ expect { StructureItem.new("test", 0, 8, :UINT, :BIG_ENDIAN, "") }.to raise_error(ArgumentError, "TEST: array_size must be a Fixnum")
114
114
  end
115
115
 
116
116
  it "should complain about array size != multiple of bit size" do
117
- expect { StructureItem.new("test", 0, 8, :UINT, :BIG_ENDIAN, 10) }.to raise_error(ArgumentError, "test: array_size must be a multiple of bit_size")
117
+ expect { StructureItem.new("test", 0, 8, :UINT, :BIG_ENDIAN, 10) }.to raise_error(ArgumentError, "TEST: array_size must be a multiple of bit_size")
118
118
  end
119
119
 
120
120
  it "should not complain about array size != multiple of bit size with negative array size" do
@@ -181,7 +181,7 @@ module Cosmos
181
181
  hash = item.to_hash
182
182
  hash.keys.length.should eql 7
183
183
  hash.keys.should include('name','bit_offset','bit_size','data_type','endianness','array_size', 'overflow')
184
- hash["name"].should eql "test"
184
+ hash["name"].should eql "TEST"
185
185
  hash["bit_offset"].should eql 0
186
186
  hash["bit_size"].should eql 8
187
187
  hash["data_type"].should eql :UINT
@@ -34,6 +34,31 @@ module Cosmos
34
34
  end
35
35
  end # describe "initialize"
36
36
 
37
+ describe "defined?" do
38
+ it "returns true if any items have been defined" do
39
+ s = Structure.new
40
+ expect(s.defined?).to be false
41
+ s.define_item("test1",0,8,:UINT)
42
+ expect(s.defined?).to be true
43
+ end
44
+ end
45
+
46
+ describe "rename_item" do
47
+ it "renames a previously defined item" do
48
+ s = Structure.new
49
+ s.items["test1"].should be_nil
50
+ s.sorted_items[0].should be_nil
51
+ s.define_item("test1", 0, 8, :UINT)
52
+ s.items["TEST1"].should_not be_nil
53
+ s.sorted_items[0].should_not be_nil
54
+ s.sorted_items[0].name.should eql "TEST1"
55
+ s.rename_item("TEST1", "TEST2")
56
+ s.items["TEST1"].should be_nil
57
+ s.items["TEST2"].should_not be_nil
58
+ s.sorted_items[0].name.should eql "TEST2"
59
+ end
60
+ end
61
+
37
62
  describe "define_item" do
38
63
  before(:each) do
39
64
  @s = Structure.new
@@ -47,21 +72,21 @@ module Cosmos
47
72
  @s.sorted_items[0].should_not be_nil
48
73
  @s.sorted_items[0].name.should eql "TEST1"
49
74
  @s.defined_length.should eql 1
50
- @s.fixed_size.should be_truthy
75
+ @s.fixed_size.should be true
51
76
  end
52
77
 
53
- it "should add items with negative offsets" do
78
+ it "adds items with negative bit offsets" do
54
79
  @s.define_item("test1", -8, 8, :UINT)
55
80
  @s.defined_length.should eql 1
56
81
  @s.define_item("test2", 0, 4, :UINT)
57
82
  @s.defined_length.should eql 2
58
83
  @s.define_item("test3", 4, 4, :UINT)
59
84
  @s.defined_length.should eql 2
60
- @s.define_item("test4", 8, 0, :BLOCK)
61
- @s.defined_length.should eql 2
62
- @s.define_item("test5", -16, 8, :UINT)
85
+ @s.define_item("test4", 16, 0, :BLOCK)
63
86
  @s.defined_length.should eql 3
64
- @s.fixed_size.should be_falsey
87
+ @s.define_item("test5", -16, 8, :UINT)
88
+ @s.defined_length.should eql 4
89
+ @s.fixed_size.should be false
65
90
  end
66
91
 
67
92
  it "should add item with negative offset" do
@@ -81,7 +106,7 @@ module Cosmos
81
106
  @s.defined_length.should eql 3
82
107
  @s.define_item("test4", 8, 0, :BLOCK)
83
108
  @s.defined_length.should eql 3
84
- @s.fixed_size.should be_falsey
109
+ @s.fixed_size.should be false
85
110
  end
86
111
 
87
112
  it "should recalulate sorted_items when adding multiple items" do
@@ -94,7 +119,7 @@ module Cosmos
94
119
  @s.define_item("test3", 16, 8, :UINT)
95
120
  @s.sorted_items[-1].name.should eql "TEST3"
96
121
  @s.defined_length.should eql 5
97
- @s.fixed_size.should be_truthy
122
+ @s.fixed_size.should be true
98
123
  end
99
124
 
100
125
  it "should overwrite existing items" do
@@ -108,21 +133,73 @@ module Cosmos
108
133
  @s.items["TEST1"].bit_size.should eql 16
109
134
  @s.items["TEST1"].data_type.should eql :INT
110
135
  @s.defined_length.should eql 2
111
- @s.fixed_size.should be_truthy
136
+ @s.fixed_size.should be true
112
137
  end
113
138
  end # describe "define_item"
114
139
 
115
- describe "append_item" do
140
+ describe "define" do
116
141
  before(:each) do
117
142
  @s = Structure.new
118
143
  end
119
144
 
120
- it "should append an item to items" do
121
- @s.define_item("test1", 0, 8, :UINT)
145
+ it "adds the item to items and sorted_items" do
146
+ @s.items["test1"].should be_nil
147
+ @s.sorted_items[0].should be_nil
148
+ si = StructureItem.new("test1",0,8,:UINT,:BIG_ENDIAN)
149
+ @s.define(si)
150
+ @s.items["TEST1"].should_not be_nil
151
+ @s.sorted_items[0].should_not be_nil
152
+ @s.sorted_items[0].name.should eql "TEST1"
153
+ @s.defined_length.should eql 1
154
+ @s.fixed_size.should be true
155
+ end
156
+
157
+ it "allows items to be defined on top of each other" do
158
+ @s.items["test1"].should be_nil
159
+ @s.sorted_items[0].should be_nil
160
+ si = StructureItem.new("test1",0,8,:UINT,:BIG_ENDIAN)
161
+ @s.define(si)
162
+ @s.sorted_items[0].name.should eql "TEST1"
163
+ @s.items["TEST1"].bit_offset.should eql 0
122
164
  @s.items["TEST1"].bit_size.should eql 8
165
+ @s.items["TEST1"].data_type.should eql :UINT
166
+ @s.defined_length.should eql 1
167
+ si = StructureItem.new("test2",0,16,:INT,:BIG_ENDIAN)
168
+ @s.define(si)
169
+ @s.sorted_items[1].name.should eql "TEST2"
170
+ @s.items["TEST2"].bit_offset.should eql 0
171
+ @s.items["TEST2"].bit_size.should eql 16
172
+ @s.items["TEST2"].data_type.should eql :INT
173
+ @s.defined_length.should eql 2
174
+ buffer = "\x01\x02"
175
+ @s.read_item(@s.get_item("test1"), :RAW, buffer).should eql 1
176
+ @s.read_item(@s.get_item("test2"), :RAW, buffer).should eql 258
177
+ end
178
+
179
+ it "should overwrite existing items" do
180
+ si = StructureItem.new("test1",0,8,:UINT,:BIG_ENDIAN)
181
+ @s.define(si)
123
182
  @s.sorted_items[0].name.should eql "TEST1"
124
- @s.sorted_items[1].should be_nil
183
+ @s.items["TEST1"].bit_size.should eql 8
184
+ @s.items["TEST1"].data_type.should eql :UINT
125
185
  @s.defined_length.should eql 1
186
+ si = StructureItem.new("test1",0,16,:INT,:BIG_ENDIAN)
187
+ @s.define(si)
188
+ @s.sorted_items[0].name.should eql "TEST1"
189
+ @s.items["TEST1"].bit_size.should eql 16
190
+ @s.items["TEST1"].data_type.should eql :INT
191
+ @s.defined_length.should eql 2
192
+ @s.fixed_size.should be true
193
+ end
194
+ end
195
+
196
+ describe "append_item" do
197
+ before(:each) do
198
+ @s = Structure.new
199
+ end
200
+
201
+ it "should append an item to items" do
202
+ @s.define_item("test1", 0, 8, :UINT)
126
203
  @s.append_item("test2", 16, :UINT)
127
204
  @s.items["TEST2"].bit_size.should eql 16
128
205
  @s.sorted_items[0].name.should eql "TEST1"
@@ -152,7 +229,29 @@ module Cosmos
152
229
  @s.define_item("test1", 0, 8, :UINT, -8)
153
230
  expect { @s.append_item("test2", 8, :UINT) }.to raise_error(ArgumentError, "Can't append an item after a variably sized item")
154
231
  end
155
- end # describe "define_item"
232
+ end
233
+
234
+ describe "append" do
235
+ before(:each) do
236
+ @s = Structure.new
237
+ end
238
+
239
+ it "appends an item to the structure" do
240
+ @s.define_item("test1", 0, 8, :UINT)
241
+ item = StructureItem.new("test2", 0, 16, :UINT, :BIG_ENDIAN)
242
+ @s.append(item)
243
+ # Bit offset should change because we appended the item
244
+ @s.items["TEST2"].bit_offset.should eql 8
245
+ @s.sorted_items[0].name.should eql "TEST1"
246
+ @s.sorted_items[1].name.should eql "TEST2"
247
+ @s.defined_length.should eql 3
248
+ end
249
+
250
+ it "should complain if appending after a variably sized item" do
251
+ @s.define_item("test1", 0, 0, :BLOCK)
252
+ expect { @s.append(@item) }.to raise_error(ArgumentError, "Can't append an item after a variably sized item")
253
+ end
254
+ end
156
255
 
157
256
  describe "get_item" do
158
257
  before(:each) do
@@ -281,7 +380,7 @@ module Cosmos
281
380
  end
282
381
 
283
382
  describe "read_all" do
284
- it "should read all defined items" do
383
+ it "reads all defined items" do
285
384
  s = Structure.new(:BIG_ENDIAN)
286
385
  s.append_item("test1", 8, :UINT, 16)
287
386
  s.append_item("test2", 16, :UINT)
@@ -296,6 +395,22 @@ module Cosmos
296
395
  vals[1][1].should eql 0x0304
297
396
  vals[2][1].should eql 0x05060708
298
397
  end
398
+
399
+ it "reads all defined items synchronized" do
400
+ s = Structure.new(:BIG_ENDIAN)
401
+ s.append_item("test1", 8, :UINT, 16)
402
+ s.append_item("test2", 16, :UINT)
403
+ s.append_item("test3", 32, :UINT)
404
+
405
+ buffer = "\x01\x02\x03\x04\x05\x06\x07\x08"
406
+ vals = s.read_all(:RAW, buffer, false)
407
+ vals[0][0].should eql "TEST1"
408
+ vals[1][0].should eql "TEST2"
409
+ vals[2][0].should eql "TEST3"
410
+ vals[0][1].should eql [1,2]
411
+ vals[1][1].should eql 0x0304
412
+ vals[2][1].should eql 0x05060708
413
+ end
299
414
  end
300
415
 
301
416
  describe "formatted" do
@@ -312,10 +427,24 @@ module Cosmos
312
427
  s.formatted.should include("TEST3")
313
428
  s.formatted.should include("00000000: 07 08 09 0A")
314
429
  end
430
+
431
+ it "should alter the indentation of the item" do
432
+ s = Structure.new(:BIG_ENDIAN)
433
+ s.append_item("test1", 8, :UINT, 16)
434
+ s.write("test1", [1,2])
435
+ s.append_item("test2", 16, :UINT)
436
+ s.write("test2", 3456)
437
+ s.append_item("test3", 32, :BLOCK)
438
+ s.write("test3", "\x07\x08\x09\x0A")
439
+ s.formatted(:CONVERTED, 4).should include(" TEST1: [1, 2]")
440
+ s.formatted(:CONVERTED, 4).should include(" TEST2: 3456")
441
+ s.formatted(:CONVERTED, 4).should include(" TEST3")
442
+ s.formatted(:CONVERTED, 4).should include(" 00000000: 07 08 09 0A")
443
+ end
315
444
  end
316
445
 
317
446
  describe "buffer" do
318
- it "should return the buffer" do
447
+ it "returns the buffer" do
319
448
  s = Structure.new(:BIG_ENDIAN)
320
449
  s.append_item("test1", 8, :UINT, 16)
321
450
  s.write("test1", [1,2])
@@ -324,6 +453,8 @@ module Cosmos
324
453
  s.append_item("test3", 32, :UINT)
325
454
  s.write("test3", 0x05060708)
326
455
  s.buffer.should eql "\x01\x02\x03\x04\x05\x06\x07\x08"
456
+ expect(s.buffer).to_not be s.buffer
457
+ expect(s.buffer(false)).to be s.buffer(false)
327
458
  end
328
459
  end
329
460
 
@@ -376,8 +507,16 @@ module Cosmos
376
507
  s.write("test2", 0x0304)
377
508
  s.append_item("test3", 32, :UINT)
378
509
  s.write("test3", 0x05060708)
510
+ # Get a reference to the original buffer
511
+ old_buffer = s.buffer(false)
379
512
 
380
513
  s2 = s.clone
514
+ # Ensure we didn't modify the original buffer object
515
+ expect(s.buffer(false)).to be old_buffer
516
+ # Check that they are equal in value
517
+ expect(s2.buffer(false)).to eql s.buffer(false)
518
+ # But not the same object
519
+ expect(s2.buffer(false)).to_not be s.buffer(false)
381
520
  s2.read("test1").should eql [1,2]
382
521
  s2.read("test2").should eql 0x0304
383
522
  s2.read("test3").should eql 0x05060708
@@ -407,6 +546,13 @@ module Cosmos
407
546
  s.test1.should eql [3,4]
408
547
  end
409
548
 
549
+ it "raises an exception if there is no buffer" do
550
+ s = Structure.new(:BIG_ENDIAN, nil)
551
+ s.append_item("test1", 8, :UINT, 16)
552
+ s.enable_method_missing
553
+ expect { s.test1 }.to raise_error(/No buffer/)
554
+ end
555
+
410
556
  it "should complain if it can't find an item" do
411
557
  s = Structure.new(:BIG_ENDIAN)
412
558
  s.enable_method_missing