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.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/Manifest.txt +17 -1
- data/autohotkey/tools/test_runner2.ahk +1 -0
- data/autohotkey/tools/tlm_grapher.ahk +13 -1
- data/data/crc.txt +39 -30
- data/demo/config/data/crc.txt +3 -3
- data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +3 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +7 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +6 -1
- data/lib/cosmos.rb +2 -2
- data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -5
- data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +0 -7
- data/lib/cosmos/gui/line_graph/overview_graph.rb +12 -2
- data/lib/cosmos/gui/utilities/script_module_gui.rb +11 -3
- data/lib/cosmos/interfaces/interface.rb +12 -0
- data/lib/cosmos/interfaces/stream_interface.rb +1 -21
- data/lib/cosmos/interfaces/tcpip_server_interface.rb +10 -0
- data/lib/cosmos/io/json_drb_object.rb +75 -56
- data/lib/cosmos/io/tcpip_server.rb +1 -11
- data/lib/cosmos/packet_logs.rb +1 -0
- data/lib/cosmos/packet_logs/ccsds_log_reader.rb +103 -0
- data/lib/cosmos/packets/packet.rb +70 -1
- data/lib/cosmos/packets/packet_config.rb +59 -611
- data/lib/cosmos/packets/parsers/format_string_parser.rb +58 -0
- data/lib/cosmos/packets/parsers/limits_parser.rb +146 -0
- data/lib/cosmos/packets/parsers/limits_response_parser.rb +52 -0
- data/lib/cosmos/packets/parsers/macro_parser.rb +116 -0
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +215 -0
- data/lib/cosmos/packets/parsers/packet_parser.rb +123 -0
- data/lib/cosmos/packets/parsers/processor_parser.rb +63 -0
- data/lib/cosmos/packets/parsers/state_parser.rb +116 -0
- data/lib/cosmos/packets/structure.rb +59 -22
- data/lib/cosmos/packets/structure_item.rb +1 -1
- data/lib/cosmos/script/script.rb +4 -5
- data/lib/cosmos/streams/serial_stream.rb +5 -0
- data/lib/cosmos/streams/stream.rb +8 -2
- data/lib/cosmos/streams/stream_protocol.rb +1 -0
- data/lib/cosmos/streams/tcpip_client_stream.rb +37 -7
- data/lib/cosmos/streams/tcpip_socket_stream.rb +9 -6
- data/lib/cosmos/system/target.rb +3 -6
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +57 -48
- data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +7 -3
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +1 -1
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +7 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +1 -2
- data/lib/cosmos/top_level.rb +22 -11
- data/lib/cosmos/utilities/message_log.rb +14 -9
- data/lib/cosmos/version.rb +5 -5
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +16 -16
- data/spec/interfaces/linc_interface_spec.rb +3 -0
- data/spec/interfaces/tcpip_client_interface_spec.rb +1 -0
- data/spec/interfaces/tcpip_server_interface_spec.rb +9 -0
- data/spec/io/json_drb_object_spec.rb +1 -1
- data/spec/io/serial_driver_spec.rb +0 -1
- data/spec/packet_logs/packet_log_writer_spec.rb +5 -3
- data/spec/packets/packet_config_spec.rb +22 -837
- data/spec/packets/packet_item_spec.rb +10 -10
- data/spec/packets/packet_spec.rb +239 -1
- data/spec/packets/parsers/format_string_parser_spec.rb +122 -0
- data/spec/packets/parsers/limits_parser_spec.rb +282 -0
- data/spec/packets/parsers/limits_response_parser_spec.rb +149 -0
- data/spec/packets/parsers/macro_parser_spec.rb +184 -0
- data/spec/packets/parsers/packet_item_parser_spec.rb +306 -0
- data/spec/packets/parsers/packet_parser_spec.rb +99 -0
- data/spec/packets/parsers/processor_parser_spec.rb +114 -0
- data/spec/packets/parsers/state_parser_spec.rb +156 -0
- data/spec/packets/structure_item_spec.rb +14 -14
- data/spec/packets/structure_spec.rb +162 -16
- data/spec/streams/fixed_stream_protocol_spec.rb +7 -4
- data/spec/streams/length_stream_protocol_spec.rb +3 -0
- data/spec/streams/preidentified_stream_protocol_spec.rb +3 -0
- data/spec/streams/serial_stream_spec.rb +12 -0
- data/spec/streams/stream_protocol_spec.rb +14 -0
- data/spec/streams/stream_spec.rb +1 -0
- data/spec/streams/tcpip_client_stream_spec.rb +3 -0
- data/spec/streams/tcpip_socket_stream_spec.rb +15 -3
- data/spec/streams/template_stream_protocol_spec.rb +5 -0
- data/spec/streams/terminated_stream_protocol_spec.rb +4 -0
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +21 -1
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +1 -1
- data/spec/tools/cmd_tlm_server/interfaces_spec.rb +1 -1
- metadata +19 -3
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
module Cosmos
|
|
12
|
+
|
|
13
|
+
class FormatStringParser
|
|
14
|
+
# @param parser [ConfigParser] Configuration parser
|
|
15
|
+
# @param item [Packet] The current item
|
|
16
|
+
def self.parse(parser, item)
|
|
17
|
+
@parser = FormatStringParser.new(parser)
|
|
18
|
+
@parser.verify_parameters()
|
|
19
|
+
@parser.create_format_string(item)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param parser [ConfigParser] Configuration parser
|
|
23
|
+
def initialize(parser)
|
|
24
|
+
@parser = parser
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def verify_parameters
|
|
28
|
+
@usage = "FORMAT_STRING <PRINTF STYLE STRING>"
|
|
29
|
+
@parser.verify_num_parameters(1, 1, @usage)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @param item [PacketItem] The item the limits response should be added to
|
|
33
|
+
def create_format_string(item)
|
|
34
|
+
item.format_string = @parser.parameters[0]
|
|
35
|
+
# Only test the format string if there is not a read conversion because
|
|
36
|
+
# read conversion can return any type
|
|
37
|
+
test_format_string(item) unless item.read_conversion
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def test_format_string(item)
|
|
43
|
+
case item.data_type
|
|
44
|
+
when :INT, :UINT
|
|
45
|
+
sprintf(item.format_string, 0)
|
|
46
|
+
when :FLOAT
|
|
47
|
+
sprintf(item.format_string, 0.0)
|
|
48
|
+
when :STRING, :BLOCK
|
|
49
|
+
sprintf(item.format_string, 'Hello')
|
|
50
|
+
else
|
|
51
|
+
# Nothing to do
|
|
52
|
+
end
|
|
53
|
+
rescue Exception
|
|
54
|
+
raise @parser.error("Invalid FORMAT_STRING specified for type #{item.data_type}: #{@parser.parameters[0]}", @usage)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end # module Cosmos
|
|
@@ -0,0 +1,146 @@
|
|
|
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
|
+
module Cosmos
|
|
12
|
+
|
|
13
|
+
class LimitsParser
|
|
14
|
+
# @param parser [ConfigParser] Configuration parser
|
|
15
|
+
# @param packet [Packet] The current packet
|
|
16
|
+
# @param cmd_or_tlm [String] Whether this is a command or telemetry packet
|
|
17
|
+
# @param item [PacketItem] The packet item to create limits on
|
|
18
|
+
# @param warnings [Array<String>] Array of string warnings which will be
|
|
19
|
+
# appended with any warnings found when parsing the limits
|
|
20
|
+
def self.parse(parser, packet, cmd_or_tlm, item, warnings)
|
|
21
|
+
@parser = LimitsParser.new(parser)
|
|
22
|
+
@parser.verify_parameters(cmd_or_tlm)
|
|
23
|
+
@parser.create_limits(packet, item, warnings)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(parser)
|
|
27
|
+
@parser = parser
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param cmd_or_tlm [String] Whether this is a command or telemetry packet
|
|
31
|
+
def verify_parameters(cmd_or_tlm)
|
|
32
|
+
if cmd_or_tlm == PacketConfig::COMMAND
|
|
33
|
+
raise @parser.error("LIMITS only applies to telemetry items")
|
|
34
|
+
end
|
|
35
|
+
@usage = "LIMITS <LIMITS SET> <PERSISTENCE> <ENABLED/DISABLED> <RED LOW LIMIT> <YELLOW LOW LIMIT> <YELLOW HIGH LIMIT> <RED HIGH LIMIT> <GREEN LOW LIMIT (Optional)> <GREEN HIGH LIMIT (Optional)>"
|
|
36
|
+
@parser.verify_num_parameters(7, 9, @usage)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param packet [Packet] The packet the item should be added to
|
|
40
|
+
def create_limits(packet, item, warnings)
|
|
41
|
+
limits_set = get_limits_set()
|
|
42
|
+
initialize_limits_values(packet, item)
|
|
43
|
+
ensure_consistency_with_default(packet, item, warnings)
|
|
44
|
+
|
|
45
|
+
item.limits.values[limits_set] = get_values()
|
|
46
|
+
item.limits.enabled = get_enabled()
|
|
47
|
+
item.limits.persistence_setting = get_persistence()
|
|
48
|
+
item.limits.persistence_count = 0
|
|
49
|
+
|
|
50
|
+
packet.update_limits_items_cache
|
|
51
|
+
limits_set
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def initialize_limits_values(packet, item)
|
|
57
|
+
limits_set = get_limits_set()
|
|
58
|
+
# Values must be initialized with a :DEFAULT key
|
|
59
|
+
if !item.limits.values
|
|
60
|
+
if limits_set == :DEFAULT
|
|
61
|
+
item.limits.values = {:DEFAULT => []}
|
|
62
|
+
else
|
|
63
|
+
raise @parser.error("DEFAULT limits set must be defined for #{packet.target_name} #{packet.packet_name} #{item.name} before setting limits set #{limits_set}")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def ensure_consistency_with_default(packet, item, warnings)
|
|
69
|
+
# Nothing to do if we're already :DEFAULT
|
|
70
|
+
return if get_limits_set() == :DEFAULT
|
|
71
|
+
|
|
72
|
+
msg = "TELEMETRY Item #{packet.target_name} #{packet.packet_name} #{item.name} #{get_limits_set()} limits _TYPE_ setting conflict with DEFAULT"
|
|
73
|
+
# XOR our setting with the items current setting
|
|
74
|
+
# If it returns true then we have a mismatch and log the error
|
|
75
|
+
if (get_enabled() ^ item.limits.enabled)
|
|
76
|
+
warnings << msg.sub('_TYPE_', 'enable')
|
|
77
|
+
Logger.instance.warn warnings[-1]
|
|
78
|
+
end
|
|
79
|
+
if item.limits.persistence_setting != get_persistence()
|
|
80
|
+
warnings << msg.sub('_TYPE_', 'persistence')
|
|
81
|
+
Logger.instance.warn warnings[-1]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def get_limits_set
|
|
86
|
+
@parser.parameters[0].upcase.to_sym
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def get_persistence
|
|
90
|
+
Integer(@parser.parameters[1])
|
|
91
|
+
rescue
|
|
92
|
+
raise @parser.error("Persistence must be an integer.", @usage)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def get_enabled
|
|
96
|
+
enabled = @parser.parameters[2].upcase
|
|
97
|
+
if enabled != 'ENABLED' and enabled != 'DISABLED'
|
|
98
|
+
raise @parser.error("Initial LIMITS state must be ENABLED or DISABLED.", @usage)
|
|
99
|
+
end
|
|
100
|
+
enabled == 'ENABLED' ? true : false
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def get_values
|
|
104
|
+
values = get_red_yellow_values()
|
|
105
|
+
values += get_green_values(values[1], values[2])
|
|
106
|
+
values
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def get_red_yellow_values
|
|
110
|
+
params = @parser.parameters
|
|
111
|
+
err = nil
|
|
112
|
+
red_low = Float(params[3]) rescue err = "red low"
|
|
113
|
+
yellow_low = Float(params[4]) rescue err = "yellow low"
|
|
114
|
+
yellow_high = Float(params[5]) rescue err = "yellow high"
|
|
115
|
+
red_high = Float(params[6]) rescue err = "red high"
|
|
116
|
+
raise @parser.error("Invalid #{err} limit value. Limits can be integers or floats.", @usage) if err
|
|
117
|
+
|
|
118
|
+
# Verify valid limits are specified
|
|
119
|
+
if (red_low > yellow_low) or (yellow_low >= yellow_high) or (yellow_high > red_high)
|
|
120
|
+
raise @parser.error("Invalid limits specified. Ensure yellow limits are within red limits.", @usage)
|
|
121
|
+
end
|
|
122
|
+
[red_low, yellow_low, yellow_high, red_high]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def get_green_values(yellow_low, yellow_high)
|
|
126
|
+
params = @parser.parameters
|
|
127
|
+
# Since our initial parameter check verifies between 7 and 9 we do a
|
|
128
|
+
# special check for 8 parameters which is an error
|
|
129
|
+
if params.length == 8
|
|
130
|
+
raise @parser.error("Must give both a green low and green high value.", @usage)
|
|
131
|
+
end
|
|
132
|
+
return [] unless params.length == 9
|
|
133
|
+
|
|
134
|
+
err = nil
|
|
135
|
+
green_low = Float(params[7]) rescue err = "green low"
|
|
136
|
+
green_high = Float(params[8]) rescue err = "green high"
|
|
137
|
+
raise @parser.error("Invalid #{err} limit value. Limits can be integers or floats.", @usage) if err
|
|
138
|
+
|
|
139
|
+
if (yellow_low > green_low) or (green_low >= green_high) or (green_high > yellow_high)
|
|
140
|
+
raise @parser.error("Invalid limits specified. Ensure green limits are within yellow limits.", @usage)
|
|
141
|
+
end
|
|
142
|
+
[green_low, green_high]
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
end
|
|
146
|
+
end # module Cosmos
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
module Cosmos
|
|
12
|
+
|
|
13
|
+
class LimitsResponseParser
|
|
14
|
+
# @param parser [ConfigParser] Configuration parser
|
|
15
|
+
# @param item [Packet] The current item
|
|
16
|
+
# @param cmd_or_tlm [String] Whether this is a command or telemetry packet
|
|
17
|
+
def self.parse(parser, item, cmd_or_tlm)
|
|
18
|
+
@parser = LimitsResponseParser.new(parser)
|
|
19
|
+
@parser.verify_parameters(cmd_or_tlm)
|
|
20
|
+
@parser.create_limits_response(item)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param parser [ConfigParser] Configuration parser
|
|
24
|
+
def initialize(parser)
|
|
25
|
+
@parser = parser
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param cmd_or_tlm [String] Whether this is a command or telemetry packet
|
|
29
|
+
def verify_parameters(cmd_or_tlm)
|
|
30
|
+
if cmd_or_tlm == PacketConfig::COMMAND
|
|
31
|
+
raise @parser.error("LIMITS_RESPONSE only applies to telemetry items")
|
|
32
|
+
end
|
|
33
|
+
@usage = "LIMITS_RESPONSE <RESPONSE CLASS FILENAME> <RESPONSE SPECIFIC OPTIONS>"
|
|
34
|
+
@parser.verify_num_parameters(1, nil, @usage)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param item [PacketItem] The item the limits response should be added to
|
|
38
|
+
def create_limits_response(item)
|
|
39
|
+
# require should be performed in target.txt
|
|
40
|
+
klass = @parser.parameters[0].filename_to_class_name.to_class
|
|
41
|
+
raise @parser.error("#{@parser.parameters[0].filename_to_class_name} class not found. Did you require the file in target.txt?", @usage) unless klass
|
|
42
|
+
if @parser.parameters[1]
|
|
43
|
+
item.limits.response = klass.new(*@parser.parameters[1..(@parser.parameters.length - 1)])
|
|
44
|
+
else
|
|
45
|
+
item.limits.response = klass.new
|
|
46
|
+
end
|
|
47
|
+
rescue Exception => err
|
|
48
|
+
raise @parser.error(err, @usage)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end # module Cosmos
|
|
@@ -0,0 +1,116 @@
|
|
|
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 'ostruct'
|
|
12
|
+
|
|
13
|
+
module Cosmos
|
|
14
|
+
class MacroParser
|
|
15
|
+
# Adds a new item to the Macro
|
|
16
|
+
def self.new_item
|
|
17
|
+
return unless @macro
|
|
18
|
+
@macro.new_item
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Starts a new Macro
|
|
22
|
+
#
|
|
23
|
+
# @param parser [ConfigParser] Configuration Parser
|
|
24
|
+
def self.start(parser)
|
|
25
|
+
if @macro
|
|
26
|
+
@macro = nil
|
|
27
|
+
raise parser.error("First close the previous MACRO_APPEND_START with a MACRO_APPEND_END")
|
|
28
|
+
else
|
|
29
|
+
@macro = MacroParser.new(parser)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Ends the Macro and adds all the items to the packet
|
|
34
|
+
#
|
|
35
|
+
# @param parser [ConfigParser] Configuration Parser
|
|
36
|
+
# @param packet [Packet] Packet to add the macro items to
|
|
37
|
+
def self.end(parser, packet)
|
|
38
|
+
raise parser.error("First start a macro with MACRO_APPEND_START") unless @macro
|
|
39
|
+
@macro.complete(packet)
|
|
40
|
+
ensure
|
|
41
|
+
# Ensure this class instance variable gets cleared so we can process the
|
|
42
|
+
# next call to start
|
|
43
|
+
@macro = nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param parser [ConfigParser] Configuration Parser
|
|
47
|
+
def initialize(parser)
|
|
48
|
+
@parser = parser
|
|
49
|
+
@usage = '#{keyword} <FIRST INDEX> <LAST INDEX> [NAME FORMAT]'
|
|
50
|
+
parser.verify_num_parameters(2, 3, @usage)
|
|
51
|
+
@macro = OpenStruct.new(:started => true, :list => [])
|
|
52
|
+
first_index = parser.parameters[0].to_i
|
|
53
|
+
last_index = parser.parameters[1].to_i
|
|
54
|
+
if first_index < last_index
|
|
55
|
+
@macro.indices = (first_index..last_index).to_a
|
|
56
|
+
else
|
|
57
|
+
@macro.indices = (last_index..first_index).to_a
|
|
58
|
+
end
|
|
59
|
+
@macro.format = parser.parameters[2] ? parser.parameters[2] : '%s%d'
|
|
60
|
+
@macro.format_order = get_format_order()
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def new_item
|
|
64
|
+
if @parser.keyword.include?('APPEND')
|
|
65
|
+
@macro.list << @parser.parameters[0].upcase
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def complete(packet)
|
|
70
|
+
@parser.verify_num_parameters(0, 0, @parser.keyword)
|
|
71
|
+
raise @parser.error("Missing MACRO_APPEND_START before this config.line.", @parser.keyword) unless @macro
|
|
72
|
+
raise @parser.error("No items appended in MACRO_APPEND list", @parser.keyword) if @macro.list.empty?
|
|
73
|
+
|
|
74
|
+
create_new_packet_items(packet)#, new_item_names)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def format_item_name(name, index)
|
|
80
|
+
if @macro.format_order == 'sd'
|
|
81
|
+
sprintf(@macro.format, name, index)
|
|
82
|
+
else
|
|
83
|
+
sprintf(@macro.format, index, name)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def create_new_packet_items(packet)
|
|
88
|
+
@macro.list.each do |name|
|
|
89
|
+
original_item_name = name
|
|
90
|
+
# Shift off the macro indices because since the first item already
|
|
91
|
+
# exists we just rename it
|
|
92
|
+
new_name = format_item_name(name, @macro.indices.shift)
|
|
93
|
+
item = packet.rename_item(name, new_name)
|
|
94
|
+
|
|
95
|
+
# The renaming indices create new items
|
|
96
|
+
@macro.indices.each do |index|
|
|
97
|
+
new_item = item.clone
|
|
98
|
+
new_item.name = format_item_name(original_item_name, index)
|
|
99
|
+
packet.append(new_item)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def get_format_order()
|
|
105
|
+
string_index = @macro.format.index(/%\d*s/)
|
|
106
|
+
num_index = @macro.format.index(/%\d*d/)
|
|
107
|
+
raise parser.error("Invalid NAME FORMAT (#{@macro.format}) for MACRO_APPEND_START", @usage) unless string_index && num_index
|
|
108
|
+
if string_index < num_index
|
|
109
|
+
@macro.format_order = 'sd'
|
|
110
|
+
else
|
|
111
|
+
@macro.format_order = 'ds'
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
end # module Cosmos
|
|
@@ -0,0 +1,215 @@
|
|
|
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 'cosmos/packets/packet_config'
|
|
12
|
+
require 'cosmos/packets/packet_item'
|
|
13
|
+
|
|
14
|
+
module Cosmos
|
|
15
|
+
|
|
16
|
+
class PacketItemParser
|
|
17
|
+
# @param parser [ConfigParser] Configuration parser
|
|
18
|
+
# @param packet [Packet] The packet the item should be added to
|
|
19
|
+
# @param cmd_or_tlm [String] Whether this is :bn
|
|
20
|
+
def self.parse(parser, packet, cmd_or_tlm)
|
|
21
|
+
parser = PacketItemParser.new(parser)
|
|
22
|
+
parser.verify_parameters(cmd_or_tlm)
|
|
23
|
+
parser.create_packet_item(packet, cmd_or_tlm)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @param parser [ConfigParser] Configuration parser
|
|
27
|
+
def initialize(parser)
|
|
28
|
+
@parser = parser
|
|
29
|
+
@usage = get_usage()
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def verify_parameters(cmd_or_tlm)
|
|
33
|
+
if @parser.keyword.include?('ITEM') && cmd_or_tlm == PacketConfig::COMMAND
|
|
34
|
+
raise @parser.error("ITEM types are only valid with TELEMETRY", @usage)
|
|
35
|
+
elsif @parser.keyword.include?('PARAMETER') && cmd_or_tlm == PacketConfig::TELEMETRY
|
|
36
|
+
raise @parser.error("PARAMETER types are only valid with COMMAND", @usage)
|
|
37
|
+
end
|
|
38
|
+
# The usage is formatted with brackets <XXX> around each option so
|
|
39
|
+
# count the number of open brackets to determine the number of options
|
|
40
|
+
max_options = @usage.count("<")
|
|
41
|
+
# The last two options (description and endianness) are optional
|
|
42
|
+
@parser.verify_num_parameters(max_options-2, max_options, @usage)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def create_packet_item(packet, cmd_or_tlm)
|
|
46
|
+
item = PacketItem.new(@parser.parameters[0],
|
|
47
|
+
get_bit_offset(),
|
|
48
|
+
get_bit_size(),
|
|
49
|
+
get_data_type(),
|
|
50
|
+
get_endianness(packet),
|
|
51
|
+
get_array_size(),
|
|
52
|
+
:ERROR) # overflow
|
|
53
|
+
if cmd_or_tlm == PacketConfig::COMMAND
|
|
54
|
+
item.range = get_range()
|
|
55
|
+
item.default = get_default()
|
|
56
|
+
end
|
|
57
|
+
item.id_value = get_id_value()
|
|
58
|
+
item.description = get_description()
|
|
59
|
+
if append?
|
|
60
|
+
item = packet.append(item)
|
|
61
|
+
else
|
|
62
|
+
item = packet.define(item)
|
|
63
|
+
end
|
|
64
|
+
item
|
|
65
|
+
rescue => err
|
|
66
|
+
raise @parser.error(err, @usage)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def append?
|
|
72
|
+
@parser.keyword.include?("APPEND")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def get_data_type
|
|
76
|
+
index = append? ? 2 : 3
|
|
77
|
+
@parser.parameters[index].upcase.to_sym
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def get_bit_offset
|
|
81
|
+
return 0 if append?
|
|
82
|
+
Integer(@parser.parameters[1])
|
|
83
|
+
rescue => err # In case Integer fails
|
|
84
|
+
raise @parser.error(err, @usage)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def get_bit_size
|
|
88
|
+
index = append? ? 1 : 2
|
|
89
|
+
Integer(@parser.parameters[index])
|
|
90
|
+
rescue => err
|
|
91
|
+
raise @parser.error(err, @usage)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def get_array_size
|
|
95
|
+
return nil unless (@parser.keyword.include?('ARRAY'))
|
|
96
|
+
index = append? ? 3 : 4
|
|
97
|
+
Integer(@parser.parameters[index])
|
|
98
|
+
rescue => err
|
|
99
|
+
raise @parser.error(err, @usage)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def get_endianness(packet)
|
|
103
|
+
params = @parser.parameters
|
|
104
|
+
max_options = @usage.count("<")
|
|
105
|
+
if params[max_options-1]
|
|
106
|
+
endianness = params[max_options-1].to_s.upcase.intern
|
|
107
|
+
if endianness != :BIG_ENDIAN and endianness != :LITTLE_ENDIAN
|
|
108
|
+
raise @parser.error("Invalid endianness #{endianness}. Must be BIG_ENDIAN or LITTLE_ENDIAN.", @usage)
|
|
109
|
+
end
|
|
110
|
+
else
|
|
111
|
+
endianness = packet.default_endianness
|
|
112
|
+
end
|
|
113
|
+
endianness
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def get_range
|
|
117
|
+
return nil if @parser.keyword.include?('ARRAY')
|
|
118
|
+
data_type = get_data_type()
|
|
119
|
+
return nil if data_type == :STRING or data_type == :BLOCK
|
|
120
|
+
|
|
121
|
+
index = append? ? 3 : 4
|
|
122
|
+
(ConfigParser.handle_defined_constants(@parser.parameters[index].convert_to_value))..(ConfigParser.handle_defined_constants(@parser.parameters[index+1].convert_to_value))
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def get_default
|
|
126
|
+
return [] if @parser.keyword.include?('ARRAY')
|
|
127
|
+
|
|
128
|
+
index = append? ? 3 : 4
|
|
129
|
+
data_type = get_data_type()
|
|
130
|
+
if data_type == :STRING or data_type == :BLOCK
|
|
131
|
+
return @parser.parameters[index]
|
|
132
|
+
else
|
|
133
|
+
return ConfigParser.handle_defined_constants(@parser.parameters[index+2].convert_to_value)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def get_id_value
|
|
138
|
+
return nil unless @parser.keyword.include?('ID_')
|
|
139
|
+
data_type = get_data_type
|
|
140
|
+
if @parser.keyword.include?('ITEM')
|
|
141
|
+
index = append? ? 3 : 4
|
|
142
|
+
else # PARAMETER
|
|
143
|
+
index = append? ? 5 : 6
|
|
144
|
+
# STRING and BLOCK PARAMETERS don't have min and max values
|
|
145
|
+
index -= 2 if data_type == :STRING || data_type == :BLOCK
|
|
146
|
+
end
|
|
147
|
+
if data_type == :DERIVED
|
|
148
|
+
raise @parser.error("DERIVED data type not allowed for Identifier")
|
|
149
|
+
end
|
|
150
|
+
@parser.parameters[index]
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def get_description
|
|
154
|
+
max_options = @usage.count("<")
|
|
155
|
+
@parser.parameters[max_options-2] if @parser.parameters[max_options-2]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# There are many different usages of the ITEM and PARAMETER keywords so
|
|
159
|
+
# parse the keyword and parameters to generate the correct usage information.
|
|
160
|
+
def get_usage
|
|
161
|
+
keyword = @parser.keyword
|
|
162
|
+
params = @parser.parameters
|
|
163
|
+
usage = "#{keyword} <ITEM NAME> "
|
|
164
|
+
usage << "<BIT OFFSET> " unless keyword.include?("APPEND")
|
|
165
|
+
usage << bit_size_usage()
|
|
166
|
+
usage << type_usage()
|
|
167
|
+
usage << "<TOTAL ARRAY BIT SIZE> " if keyword.include?("ARRAY")
|
|
168
|
+
usage << id_usage()
|
|
169
|
+
usage << "<DESCRIPTION (Optional)> <ENDIANNESS (Optional)>"
|
|
170
|
+
usage
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def bit_size_usage
|
|
174
|
+
if @parser.keyword.include?("ARRAY")
|
|
175
|
+
"<ARRAY ITEM BIT SIZE> "
|
|
176
|
+
else
|
|
177
|
+
"<BIT SIZE> "
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def type_usage
|
|
182
|
+
keyword = @parser.keyword
|
|
183
|
+
# Item type usage is simple so just return it
|
|
184
|
+
return "<TYPE: INT/UINT/FLOAT/STRING/BLOCK/DERIVED> " if keyword.include?("ITEM")
|
|
185
|
+
|
|
186
|
+
# Build up the parameter type usage based on the keyword
|
|
187
|
+
usage = "<TYPE: "
|
|
188
|
+
params = @parser.parameters
|
|
189
|
+
# ARRAY types don't have min or max or default values
|
|
190
|
+
if keyword.include?("ARRAY")
|
|
191
|
+
usage << "INT/UINT/FLOAT/STRING/BLOCK> "
|
|
192
|
+
else
|
|
193
|
+
# STRING and BLOCK types do not have min or max values
|
|
194
|
+
if get_data_type() == :STRING || get_data_type() == :BLOCK
|
|
195
|
+
usage << "STRING/BLOCK> "
|
|
196
|
+
else
|
|
197
|
+
usage << "INT/UINT/FLOAT> <MIN VALUE> <MAX VALUE> "
|
|
198
|
+
end
|
|
199
|
+
# ID Values do not have default values
|
|
200
|
+
usage << "<DEFAULT_VALUE> " unless keyword.include?("ID")
|
|
201
|
+
end
|
|
202
|
+
usage
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def id_usage
|
|
206
|
+
return '' unless @parser.keyword.include?("ID")
|
|
207
|
+
if @parser.keyword.include?("PARAMETER")
|
|
208
|
+
"<DEFAULT AND ID VALUE> "
|
|
209
|
+
else
|
|
210
|
+
"<ID VALUE> "
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
end # module Cosmos
|