Class: OpenC3::SystemConfig

Inherits:
Object show all
Defined in:
lib/openc3/system/system_config.rb

Overview

System is the primary entry point into the OpenC3 framework. It captures system wide configuration items such as the available ports and paths to various files used by the system. The #commands, #telemetry, and #limits class variables are the primary access points for applications. The #targets variable provides access to all the targets defined by the system. Its primary responsibily is to load the system configuration file and create all the Target instances. It also saves and restores configurations using a hashing checksum over the entire configuration to detect changes.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename) ⇒ SystemConfig

Returns a new instance of SystemConfig.

Parameters:

  • filename (String)

    Full path to the system configuration file to read.



61
62
63
# File 'lib/openc3/system/system_config.rb', line 61

def initialize(filename)
  reset_variables(filename)
end

Instance Attribute Details

#classificiation_bannerHash<String,String> (readonly)

Returns Hash of the text/color to use for the classificaiton banner.

Returns:

  • (Hash<String,String>)

    Hash of the text/color to use for the classificaiton banner



57
58
59
# File 'lib/openc3/system/system_config.rb', line 57

def classificiation_banner
  @classificiation_banner
end

#soundBoolean (readonly)

Returns Whether to use sound for alerts.

Returns:

  • (Boolean)

    Whether to use sound for alerts



47
48
49
# File 'lib/openc3/system/system_config.rb', line 47

def sound
  @sound
end

#staleness_secondsInteger (readonly)

Returns The number of seconds before a telemetry packet is considered stale.

Returns:

  • (Integer)

    The number of seconds before a telemetry packet is considered stale



53
54
55
# File 'lib/openc3/system/system_config.rb', line 53

def staleness_seconds
  @staleness_seconds
end

#targetsHash<String,Target> (readonly)

Returns Hash of all the known targets.

Returns:



51
52
53
# File 'lib/openc3/system/system_config.rb', line 51

def targets
  @targets
end

#use_dnsBoolean (readonly)

Returns Whether to use DNS to lookup IP addresses or not.

Returns:

  • (Boolean)

    Whether to use DNS to lookup IP addresses or not



49
50
51
# File 'lib/openc3/system/system_config.rb', line 49

def use_dns
  @use_dns
end

#use_utcBoolean (readonly)

Returns Whether to use UTC or local times.

Returns:

  • (Boolean)

    Whether to use UTC or local times



55
56
57
# File 'lib/openc3/system/system_config.rb', line 55

def use_utc
  @use_utc
end

#userpathString (readonly)

Returns Base path of the configuration.

Returns:

  • (String)

    Base path of the configuration



45
46
47
# File 'lib/openc3/system/system_config.rb', line 45

def userpath
  @userpath
end

Instance Method Details

#process_file(filename, targets_config_dir) ⇒ Object

Process the system.txt configuration file

Parameters:

  • filename (String)

    The configuration file

  • targets_config_dir (String)

    The configuration directory to search for the target command and telemetry files.



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
# File 'lib/openc3/system/system_config.rb', line 91

def process_file(filename, targets_config_dir)
  parser = ConfigParser.new("https://docs.openc3.com/docs")

  # First pass - Everything except targets
  parser.parse_file(filename) do |keyword, parameters|
    case keyword
    when 'AUTO_DECLARE_TARGETS', 'DECLARE_TARGET', 'DECLARE_GEM_TARGET', 'DECLARE_GEM_MULTI_TARGET'
      # Will be handled by second pass

    when 'PORT', 'LISTEN_HOST', 'CONNECT_HOST', 'PATH', 'DEFAULT_PACKET_LOG_WRITER', 'DEFAULT_PACKET_LOG_READER',
      'ALLOW_ACCESS', 'ADD_HASH_FILE', 'ADD_MD5_FILE', 'HASHING_ALGORITHM'
      # Not used by OpenC3 5

    when 'ENABLE_SOUND'
      usage = "#{keyword}"
      parser.verify_num_parameters(0, 0, usage)
      @sound = true

    when 'DISABLE_DNS'
      usage = "#{keyword}"
      parser.verify_num_parameters(0, 0, usage)
      @use_dns = false

    when 'ENABLE_DNS'
      usage = "#{keyword}"
      parser.verify_num_parameters(0, 0, usage)
      @use_dns = true

    when 'STALENESS_SECONDS'
      parser.verify_num_parameters(1, 1, "#{keyword} <Value in Seconds>")
      @staleness_seconds = Integer(parameters[0])

    when 'META_INIT'
      parser.verify_num_parameters(1, 1, "#{keyword} <Filename>")
      @meta_init_filename = ConfigParser.handle_nil(parameters[0])

    when 'TIME_ZONE_UTC'
      parser.verify_num_parameters(0, 0, "#{keyword}")
      @use_utc = true

    when 'CLASSIFICATION'
      parser.verify_num_parameters(2, 4, "#{keyword} <Display_Text> <Color Name|Red> <Green> <Blue>")
      # Determine if the OpenC3 color already exists, otherwise create a new one
      if OpenC3.constants.include? parameters[1].upcase.to_sym
        # We were given a named color that already exists in OpenC3
        color = parameters[1].upcase
      else
        if parameters.length < 4
          # We were given a named color, but it didn't exist in OpenC3 already
          color = OpenC3.getColor(parameters[1].upcase)
        else
          # We were given RGB values
          color = OpenC3.getColor(parameters[1], parameters[2], parameters[3])
        end
      end

      @classificiation_banner = { 'display_text' => parameters[0],
                                  'color' => color }

    else
      # blank lines will have a nil keyword and should not raise an exception
      raise parser.error("Unknown keyword '#{keyword}'") if keyword
    end # case keyword
  end # parser.parse_file

  # Explicitly set up time to use UTC or local
  if @use_utc
    Time.use_utc()
  else
    Time.use_local()
  end

  # Second pass - Process targets
  process_targets(parser, filename, targets_config_dir)
end

#process_targets(parser, filename, targets_config_dir) ⇒ Object

Parse the system.txt configuration file looking for keywords associated with targets and create all the Target instances in the system.

Parameters:

  • parser (ConfigParser)

    Parser created by process_file

  • filename (String)

    The configuration file

  • targets_config_dir (String)

    The configuration directory to search for the target command and telemetry files.



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
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/openc3/system/system_config.rb', line 173

def process_targets(parser, filename, targets_config_dir)
  parser.parse_file(filename) do |keyword, parameters|
    case keyword
    when 'AUTO_DECLARE_TARGETS'
      usage = "#{keyword}"
      parser.verify_num_parameters(0, 0, usage)
      path = File.join(@userpath, 'config', 'targets')
      unless File.exist? path
        raise parser.error("#{path} must exist", usage)
      end

      dirs = []
      configuration_dir = File.join(@userpath, 'config', 'targets')
      Dir.foreach(configuration_dir) { |dir_filename| dirs << dir_filename }
      dirs.sort!
      dirs.each do |dir_filename|
        if dir_filename[0] != '.'
          if dir_filename == dir_filename.upcase
            # If any of the targets original directory name matches the
            # current directory then it must have been already processed by
            # DECLARE_TARGET so we skip it.
            next if @targets.select { |_name, target| target.original_name == dir_filename }.length > 0
            next if dir_filename == 'SYSTEM'

            target = Target.new(dir_filename, nil, targets_config_dir)
            @targets[target.name] = target
          else
            raise parser.error("Target folder must be uppercase: '#{dir_filename}'")
          end
        end
      end
      auto_detect_gem_based_targets()

    when 'DECLARE_TARGET'
      usage = "#{keyword} <TARGET NAME> <SUBSTITUTE TARGET NAME (Optional)> <TARGET FILENAME (Optional - defaults to target.txt)>"
      parser.verify_num_parameters(1, 3, usage)
      target_name = parameters[0].to_s.upcase

      if targets_config_dir
        folder_name = File.join(targets_config_dir, target_name)
      else
        folder_name = File.join(@userpath, 'config', 'targets', target_name)
      end
      unless Dir.exist?(folder_name)
        raise parser.error("Target folder must exist '#{folder_name}'.")
      end

      substitute_name = nil
      substitute_name = ConfigParser.handle_nil(parameters[1])
      if substitute_name
        substitute_name = substitute_name.to_s.upcase
        original_name = target_name
        target_name = substitute_name
      else
        original_name = nil
      end

      target = Target.new(target_name, original_name, targets_config_dir, ConfigParser.handle_nil(parameters[2]))
      @targets[target.name] = target

    when 'DECLARE_GEM_TARGET'
      usage = "#{keyword} <GEM NAME> <SUBSTITUTE TARGET NAME (Optional)> <TARGET FILENAME (Optional - defaults to target.txt)>"
      parser.verify_num_parameters(1, 3, usage)
      # Remove 'openc3' from the gem name 'openc3-power-supply'
      target_name = parameters[0].split('-')[1..-1].join('-').to_s.upcase
      gem_dir = Gem::Specification.find_by_name(parameters[0]).gem_dir
      substitute_name = nil
      substitute_name = ConfigParser.handle_nil(parameters[1])
      if substitute_name
        substitute_name = substitute_name.to_s.upcase
        original_name = target_name
        target_name = substitute_name
      else
        original_name = nil
      end
      target = Target.new(target_name, original_name, targets_config_dir, ConfigParser.handle_nil(parameters[2]), gem_dir)
      @targets[target.name] = target

    when 'DECLARE_GEM_MULTI_TARGET'
      usage = "#{keyword} <GEM NAME> <TARGET NAME> <SUBSTITUTE TARGET NAME (Optional)> <TARGET FILENAME (Optional - defaults to target.txt)>"
      parser.verify_num_parameters(2, 4, usage)
      target_name = parameters[1].to_s.upcase
      gem_dir = Gem::Specification.find_by_name(parameters[0]).gem_dir
      gem_dir = File.join(gem_dir, target_name)
      substitute_name = nil
      substitute_name = ConfigParser.handle_nil(parameters[2])
      if substitute_name
        substitute_name = substitute_name.to_s.upcase
        original_name = target_name
        target_name = substitute_name
      else
        original_name = nil
      end
      target = Target.new(target_name, original_name, targets_config_dir, ConfigParser.handle_nil(parameters[3]), gem_dir)
      @targets[target.name] = target

    end # case keyword
  end # parser.parse_file

  # Make sure SYSTEM target is always present and added last
  unless @targets.key?('SYSTEM')
    target = Target.new('SYSTEM', nil, targets_config_dir)
    @targets[target.name] = target
  end
end

#reset_variables(filename) ⇒ Object

Resets the System’s internal state to defaults.

Parameters:

  • filename (String)

    Path to system.txt config file to process. Defaults to config/system/system.txt



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/openc3/system/system_config.rb', line 68

def reset_variables(filename)
  @targets = {}
  @config = nil
  @commands = nil
  @telemetry = nil
  @limits = nil
  @sound = false
  @use_dns = false
  @staleness_seconds = 30
  @use_utc = false
  @meta_init_filename = nil
  @userpath = File.expand_path(File.join(File.dirname(filename), '..', '..'))
  process_file(filename, File.join(@userpath, 'config', 'targets'))
  @initial_filename = filename
  @initial_config = nil
  @config_blacklist = {}
end