# 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>] 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 []} 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