/
limits.rb
264 lines (242 loc) · 10.5 KB
/
limits.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# encoding: ascii-8bit
# Copyright 2014 Ball Aerospace & Technologies Corp.
# All Rights Reserved.
#
# This program is free software; you can modify and/or redistribute it
# under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 3 with
# attribution addendums as found in the LICENSE.txt
require 'cosmos/packets/packet_config'
module Cosmos
# Limits uses PacketConfig to parse the command and telemetry
# configuration files. It provides the API layer which other classes use to
# access information about and manipulate limits. This includes getting,
# setting and checking individual limit items as well as manipulating limits
# groups.
class Limits
attr_reader :config
LATEST_PACKET_NAME = 'LATEST'.freeze
# @param config [PacketConfig] Packet configuration to use to access the
# limits information
def initialize(config)
@config = config
end
# (see PacketConfig#warnings)
def warnings
return @config.warnings
end
# (see PacketConfig#limits_sets)
def sets
return @config.limits_sets
end
# @param config [PacketConfig] Set the packet configuration to a new
# configuration. This will change everything this class returns!
def config=(config)
@config = config
end
# (see Cosmos::Packet#out_of_limits)
def out_of_limits
items = []
@config.telemetry.each do |target_name, target_packets|
target_packets.each do |packet_name, packet|
new_items = packet.out_of_limits
items.concat(new_items)
end
end
return items
end
# @param ignored_items [Array<Array<String, String, String>>] Items to ignore from the consideration
# @return [Symbol] The overall limits state for the system
def overall_limits_state(ignored_items = nil)
overall = :GREEN
limits_packet_stale = false
items_out_of_limits = []
# Note: If anything with limits is stale then overall limits state cannot be green or blue
@config.telemetry.each do |target_name, target_packets|
target_packets.each do |packet_name, packet|
if packet.stale && !packet.limits_items.empty?
if ignored_items
all_ignored = true
packet.limits_items.each do |item|
all_ignored = false unless includes_item?(ignored_items, target_name, packet_name, item.name)
end
else
all_ignored = false
end
limits_packet_stale = true unless all_ignored
end
items_out_of_limits.concat(packet.out_of_limits)
end
end
items_out_of_limits.each do |target_name, packet_name, item_name, limits_state|
next if ignored_items && includes_item?(ignored_items, target_name, packet_name, item_name)
case overall
# If our overall state is currently blue or green we can go to any state
when :BLUE, :GREEN, :GREEN_HIGH, :GREEN_LOW
overall = limits_state
# If our overal state is yellow we can only go higher to red
when :YELLOW, :YELLOW_HIGH, :YELLOW_LOW
if limits_state == :RED || limits_state == :RED_HIGH || limits_state == :RED_LOW
overall = limits_state
break # Red is as high as we go so no need to look for more
end
end
end
overall = :GREEN if overall == :GREEN_HIGH || overall == :GREEN_LOW || overall == :BLUE
overall = :YELLOW if overall == :YELLOW_HIGH || overall == :YELLOW_LOW
overall = :RED if overall == :RED_HIGH || overall == :RED_LOW
overall = :STALE if (overall == :GREEN || overall == :BLUE) && limits_packet_stale
return overall
end
# @return [Hash(String, Array)] The defined limits groups
def groups
return @config.limits_groups
end
# Enables limit checking for all the items in the given group.
#
# @param group_name [String] Name of the group to enable
def enable_group(group_name)
group_upcase = group_name.to_s.upcase
limits_group = @config.limits_groups[group_upcase]
if limits_group
limits_group.each do |target_name, packet_name, item_name|
enable(target_name, packet_name, item_name)
end
else
raise "LIMITS_GROUP #{group_upcase} undefined. Ensure your telemetry definition contains the line: LIMITS_GROUP #{group_upcase}"
end
end
# Disables limit checking for all the items in the given group.
#
# @param group_name [String] Name of the group to disable
def disable_group(group_name)
group_upcase = group_name.to_s.upcase
limits_group = @config.limits_groups[group_upcase]
if limits_group
limits_group.each do |target_name, packet_name, item_name|
disable(target_name, packet_name, item_name)
end
else
raise "LIMITS_GROUP #{group_upcase} undefined. Ensure your telemetry definition contains the line: LIMITS_GROUP #{group_upcase}"
end
end
# Checks whether the limits are enabled for the specified item
#
# @param target_name [String] The target name
# @param packet_name [String] The packet name. Must be a defined packet name and not 'LATEST'.
# @param item_name [String] The item name
def enabled?(target_name, packet_name, item_name)
get_packet(target_name, packet_name).get_item(item_name).limits.enabled
end
# Enables limit checking for the specified item
#
# @param (see #enabled?)
def enable(target_name, packet_name, item_name)
get_packet(target_name, packet_name).enable_limits(item_name)
end
# Disables limit checking for the specified item
#
# @param (see #enabled?)
def disable(target_name, packet_name, item_name)
get_packet(target_name, packet_name).disable_limits(item_name)
end
# Get the limits for a telemetry item
#
# @param target_name [String] Target Name
# @param packet_name [String] Packet Name
# @param item_name [String] Item Name
# @param limits_set [String or Symbol or nil] Desired Limits set. nil = current limits set
# @return [Array<limits_set, persistence, enabled, red_low, yellow_low, red_high, yellow_high, green_low (optional), green_high (optional)] Limits information
def get(target_name, packet_name, item_name, limits_set = nil)
limits = get_packet(target_name, packet_name).get_item(item_name).limits
if limits.values
if limits_set
limits_set = limits_set.to_s.upcase.intern
else
limits_set = System.limits_set
end
limits_for_set = limits.values[limits_set]
if limits_for_set
return [limits_set, limits.persistence_setting, limits.enabled, limits_for_set[0], limits_for_set[1], limits_for_set[2], limits_for_set[3], limits_for_set[4], limits_for_set[5]]
else
return [nil, nil, nil, nil, nil, nil, nil, nil, nil]
end
else
return [nil, nil, nil, nil, nil, nil, nil, nil, nil]
end
end
# Set the limits for a telemetry item
#
# @param target_name [String] Target Name
# @param packet_name [String] Packet Name
# @param item_name [String] Item Name
# @param red_low [Float] Red Low Limit
# @param yellow_low [Float] Yellow Low Limit
# @param yellow_high [Float] Yellow High Limit
# @param red_high [Float] Red High Limit
# @param green_low [Float] Green Low Limit
# @param green_high [Float] Green High Limit
# @param limits_set [String or Symbol or nil] Desired Limits set. nil = current limits set, recommend using :CUSTOM
# @param persistence [Integer] The number of samples the value must be out of limits before detecting a limits change. nil = Leave unchanged
# @param enabled [Boolean] If limits monitoring is enabled for this item
# @return [Array<limits_set, persistence, enabled, red_low, yellow_low, red_high, yellow_high, green_low (optional), green_high (optional)] Limits information
def set(target_name, packet_name, item_name, red_low, yellow_low, yellow_high, red_high, green_low = nil, green_high = nil, limits_set = :CUSTOM, persistence = nil, enabled = true)
packet = get_packet(target_name, packet_name)
item = packet.get_item(item_name)
limits = item.limits
if limits_set
limits_set = limits_set.to_s.upcase.intern
else
limits_set = System.limits_set
end
if !limits.values
if limits_set == :DEFAULT
limits.values = {:DEFAULT => []}
else
raise "DEFAULT limits must be defined for #{target_name} #{packet_name} #{item_name} before setting limits set #{limits_set}"
end
end
limits_for_set = limits.values[limits_set]
unless limits_for_set
limits.values[limits_set] = []
limits_for_set = limits.values[limits_set]
end
limits_for_set[0] = red_low.to_f
limits_for_set[1] = yellow_low.to_f
limits_for_set[2] = yellow_high.to_f
limits_for_set[3] = red_high.to_f
limits_for_set.delete_at(5) if limits_for_set[5]
limits_for_set.delete_at(4) if limits_for_set[4]
if green_low && green_high
limits_for_set[4] = green_low.to_f
limits_for_set[5] = green_high.to_f
end
limits.enabled = enabled
limits.persistence_setting = Integer(persistence) if persistence
packet.update_limits_items_cache(item)
@config.limits_sets << limits_set
@config.limits_sets.uniq!
return [limits_set, limits.persistence_setting, limits.enabled, limits_for_set[0], limits_for_set[1], limits_for_set[2], limits_for_set[3], limits_for_set[4], limits_for_set[5]]
end
protected
def get_packet(target_name, packet_name)
raise "LATEST packet not valid" if packet_name.upcase == LATEST_PACKET_NAME
packets = @config.telemetry[target_name.to_s.upcase]
raise "Telemetry target '#{target_name.to_s.upcase}' does not exist" unless packets
packet = packets[packet_name.to_s.upcase]
raise "Telemetry packet '#{target_name.to_s.upcase} #{packet_name.to_s.upcase}' does not exist" unless packet
return packet
end
def includes_item?(ignored_items, target_name, packet_name, item_name)
ignored_items.each do |array_target_name, array_packet_name, array_item_name|
if ((array_target_name == target_name) &&
(array_packet_name == packet_name) &&
# If the item name is nil we're ignoring an entire packet
(array_item_name == item_name || array_item_name.nil?))
return true
end
end
return false
end
end
end