openc3 5.0.6
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 +7 -0
- data/Gemfile +18 -0
- data/Guardfile +35 -0
- data/LICENSE.txt +727 -0
- data/README.md +37 -0
- data/Rakefile +131 -0
- data/bin/cstol_converter +1178 -0
- data/bin/openc3cli +531 -0
- data/bin/rubysloc +139 -0
- data/data/config/_array_params.yaml +23 -0
- data/data/config/_id_items.yaml +24 -0
- data/data/config/_id_params.yaml +58 -0
- data/data/config/_interfaces.yaml +214 -0
- data/data/config/_interfaces.yaml.err +1017 -0
- data/data/config/_items.yaml +20 -0
- data/data/config/_params.yaml +60 -0
- data/data/config/cmd_tlm_server.yaml +136 -0
- data/data/config/command.yaml +44 -0
- data/data/config/command_modifiers.yaml +160 -0
- data/data/config/command_telemetry.yaml +3 -0
- data/data/config/interface_modifiers.yaml +104 -0
- data/data/config/item_modifiers.yaml +221 -0
- data/data/config/microservice.yaml +78 -0
- data/data/config/param_item_modifiers.yaml +52 -0
- data/data/config/parameter_modifiers.yaml +200 -0
- data/data/config/plugins.yaml +80 -0
- data/data/config/protocols.yaml +290 -0
- data/data/config/screen.yaml +147 -0
- data/data/config/table_manager.yaml +89 -0
- data/data/config/table_parameter_modifiers.yaml +9 -0
- data/data/config/target.yaml +142 -0
- data/data/config/target_config.yaml +94 -0
- data/data/config/telemetry.yaml +87 -0
- data/data/config/telemetry_modifiers.yaml +159 -0
- data/data/config/tool.yaml +63 -0
- data/data/config/unknown.yaml +3 -0
- data/data/config/widgets.yaml +1505 -0
- data/ext/mkrf_conf.rb +49 -0
- data/ext/openc3/ext/array/array.c +122 -0
- data/ext/openc3/ext/array/extconf.rb +13 -0
- data/ext/openc3/ext/buffered_file/buffered_file.c +198 -0
- data/ext/openc3/ext/buffered_file/extconf.rb +13 -0
- data/ext/openc3/ext/config_parser/config_parser.c +280 -0
- data/ext/openc3/ext/config_parser/extconf.rb +13 -0
- data/ext/openc3/ext/crc/crc.c +351 -0
- data/ext/openc3/ext/crc/extconf.rb +13 -0
- data/ext/openc3/ext/openc3_io/extconf.rb +13 -0
- data/ext/openc3/ext/openc3_io/openc3_io.c +158 -0
- data/ext/openc3/ext/packet/extconf.rb +13 -0
- data/ext/openc3/ext/packet/packet.c +318 -0
- data/ext/openc3/ext/platform/extconf.rb +13 -0
- data/ext/openc3/ext/platform/platform.c +134 -0
- data/ext/openc3/ext/polynomial_conversion/extconf.rb +13 -0
- data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +79 -0
- data/ext/openc3/ext/string/extconf.rb +13 -0
- data/ext/openc3/ext/string/string.c +63 -0
- data/ext/openc3/ext/structure/structure.c +1719 -0
- data/ext/openc3/ext/tabbed_plots_config/extconf.rb +13 -0
- data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +62 -0
- data/ext/openc3/ext/telemetry/extconf.rb +13 -0
- data/ext/openc3/ext/telemetry/telemetry.c +336 -0
- data/lib/cosmos.rb +20 -0
- data/lib/cosmosc2.rb +20 -0
- data/lib/openc3/api/api.rb +39 -0
- data/lib/openc3/api/authorized_api.rb +30 -0
- data/lib/openc3/api/cmd_api.rb +451 -0
- data/lib/openc3/api/config_api.rb +58 -0
- data/lib/openc3/api/interface_api.rb +117 -0
- data/lib/openc3/api/limits_api.rb +375 -0
- data/lib/openc3/api/router_api.rb +117 -0
- data/lib/openc3/api/settings_api.rb +70 -0
- data/lib/openc3/api/target_api.rb +78 -0
- data/lib/openc3/api/tlm_api.rb +455 -0
- data/lib/openc3/bridge/bridge.rb +54 -0
- data/lib/openc3/bridge/bridge_config.rb +167 -0
- data/lib/openc3/bridge/bridge_interface_thread.rb +42 -0
- data/lib/openc3/bridge/bridge_router_thread.rb +42 -0
- data/lib/openc3/ccsds/ccsds_packet.rb +68 -0
- data/lib/openc3/ccsds/ccsds_parser.rb +148 -0
- data/lib/openc3/config/config_parser.rb +549 -0
- data/lib/openc3/config/meta_config_parser.rb +74 -0
- data/lib/openc3/conversions/conversion.rb +70 -0
- data/lib/openc3/conversions/generic_conversion.rb +83 -0
- data/lib/openc3/conversions/packet_time_formatted_conversion.rb +43 -0
- data/lib/openc3/conversions/packet_time_seconds_conversion.rb +43 -0
- data/lib/openc3/conversions/polynomial_conversion.rb +87 -0
- data/lib/openc3/conversions/processor_conversion.rb +70 -0
- data/lib/openc3/conversions/received_count_conversion.rb +38 -0
- data/lib/openc3/conversions/received_time_formatted_conversion.rb +42 -0
- data/lib/openc3/conversions/received_time_seconds_conversion.rb +42 -0
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +171 -0
- data/lib/openc3/conversions/unix_time_conversion.rb +68 -0
- data/lib/openc3/conversions/unix_time_formatted_conversion.rb +49 -0
- data/lib/openc3/conversions/unix_time_seconds_conversion.rb +49 -0
- data/lib/openc3/conversions.rb +34 -0
- data/lib/openc3/core_ext/array.rb +416 -0
- data/lib/openc3/core_ext/binding.rb +29 -0
- data/lib/openc3/core_ext/class.rb +72 -0
- data/lib/openc3/core_ext/exception.rb +61 -0
- data/lib/openc3/core_ext/file.rb +83 -0
- data/lib/openc3/core_ext/hash.rb +37 -0
- data/lib/openc3/core_ext/io.rb +134 -0
- data/lib/openc3/core_ext/kernel.rb +42 -0
- data/lib/openc3/core_ext/math.rb +128 -0
- data/lib/openc3/core_ext/matrix.rb +156 -0
- data/lib/openc3/core_ext/objectspace.rb +36 -0
- data/lib/openc3/core_ext/openc3_io.rb +57 -0
- data/lib/openc3/core_ext/range.rb +27 -0
- data/lib/openc3/core_ext/socket.rb +38 -0
- data/lib/openc3/core_ext/string.rb +389 -0
- data/lib/openc3/core_ext/stringio.rb +33 -0
- data/lib/openc3/core_ext/time.rb +508 -0
- data/lib/openc3/core_ext.rb +36 -0
- data/lib/openc3/interfaces/interface.rb +498 -0
- data/lib/openc3/interfaces/linc_interface.rb +475 -0
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +192 -0
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +193 -0
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +155 -0
- data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +56 -0
- data/lib/openc3/interfaces/protocols/length_protocol.rb +165 -0
- data/lib/openc3/interfaces/protocols/override_protocol.rb +60 -0
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +206 -0
- data/lib/openc3/interfaces/protocols/protocol.rb +82 -0
- data/lib/openc3/interfaces/protocols/template_protocol.rb +261 -0
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +93 -0
- data/lib/openc3/interfaces/serial_interface.rb +94 -0
- data/lib/openc3/interfaces/simulated_target_interface.rb +168 -0
- data/lib/openc3/interfaces/stream_interface.rb +81 -0
- data/lib/openc3/interfaces/tcpip_client_interface.rb +69 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +629 -0
- data/lib/openc3/interfaces/udp_interface.rb +169 -0
- data/lib/openc3/interfaces.rb +44 -0
- data/lib/openc3/io/buffered_file.rb +109 -0
- data/lib/openc3/io/io_multiplexer.rb +80 -0
- data/lib/openc3/io/json_api_object.rb +208 -0
- data/lib/openc3/io/json_drb.rb +335 -0
- data/lib/openc3/io/json_drb_object.rb +114 -0
- data/lib/openc3/io/json_drb_rack.rb +84 -0
- data/lib/openc3/io/json_rpc.rb +420 -0
- data/lib/openc3/io/openc3_snmp.rb +58 -0
- data/lib/openc3/io/posix_serial_driver.rb +156 -0
- data/lib/openc3/io/raw_logger.rb +167 -0
- data/lib/openc3/io/raw_logger_pair.rb +77 -0
- data/lib/openc3/io/serial_driver.rb +105 -0
- data/lib/openc3/io/stderr.rb +43 -0
- data/lib/openc3/io/stdout.rb +43 -0
- data/lib/openc3/io/udp_sockets.rb +194 -0
- data/lib/openc3/io/win32_serial_driver.rb +196 -0
- data/lib/openc3/logs/log_writer.rb +302 -0
- data/lib/openc3/logs/packet_log_constants.rb +62 -0
- data/lib/openc3/logs/packet_log_reader.rb +345 -0
- data/lib/openc3/logs/packet_log_writer.rb +299 -0
- data/lib/openc3/logs/text_log_writer.rb +68 -0
- data/lib/openc3/logs.rb +25 -0
- data/lib/openc3/microservices/cleanup_microservice.rb +68 -0
- data/lib/openc3/microservices/decom_microservice.rb +136 -0
- data/lib/openc3/microservices/interface_microservice.rb +532 -0
- data/lib/openc3/microservices/log_microservice.rb +108 -0
- data/lib/openc3/microservices/microservice.rb +204 -0
- data/lib/openc3/microservices/plugin_microservice.rb +43 -0
- data/lib/openc3/microservices/reaction_microservice.rb +541 -0
- data/lib/openc3/microservices/reducer_microservice.rb +313 -0
- data/lib/openc3/microservices/router_microservice.rb +44 -0
- data/lib/openc3/microservices/text_log_microservice.rb +84 -0
- data/lib/openc3/microservices/timeline_microservice.rb +363 -0
- data/lib/openc3/microservices/trigger_group_microservice.rb +638 -0
- data/lib/openc3/models/activity_model.rb +319 -0
- data/lib/openc3/models/auth_model.rb +65 -0
- data/lib/openc3/models/cvt_model.rb +185 -0
- data/lib/openc3/models/environment_model.rb +58 -0
- data/lib/openc3/models/gem_model.rb +137 -0
- data/lib/openc3/models/info_model.rb +31 -0
- data/lib/openc3/models/interface_model.rb +281 -0
- data/lib/openc3/models/interface_status_model.rb +117 -0
- data/lib/openc3/models/metadata_model.rb +139 -0
- data/lib/openc3/models/metric_model.rb +59 -0
- data/lib/openc3/models/microservice_model.rb +206 -0
- data/lib/openc3/models/microservice_status_model.rb +74 -0
- data/lib/openc3/models/model.rb +204 -0
- data/lib/openc3/models/note_model.rb +122 -0
- data/lib/openc3/models/notification_model.rb +40 -0
- data/lib/openc3/models/ping_model.rb +35 -0
- data/lib/openc3/models/plugin_model.rb +292 -0
- data/lib/openc3/models/process_status_model.rb +76 -0
- data/lib/openc3/models/reaction_model.rb +322 -0
- data/lib/openc3/models/reducer_model.rb +65 -0
- data/lib/openc3/models/router_model.rb +35 -0
- data/lib/openc3/models/router_status_model.rb +27 -0
- data/lib/openc3/models/scope_model.rb +153 -0
- data/lib/openc3/models/settings_model.rb +55 -0
- data/lib/openc3/models/sorted_model.rb +167 -0
- data/lib/openc3/models/target_model.rb +759 -0
- data/lib/openc3/models/timeline_model.rb +154 -0
- data/lib/openc3/models/tool_config_model.rb +38 -0
- data/lib/openc3/models/tool_model.rb +262 -0
- data/lib/openc3/models/trigger_group_model.rb +186 -0
- data/lib/openc3/models/trigger_model.rb +330 -0
- data/lib/openc3/models/widget_model.rb +138 -0
- data/lib/openc3/operators/microservice_operator.rb +128 -0
- data/lib/openc3/operators/operator.rb +277 -0
- data/lib/openc3/packets/binary_accessor.rb +1207 -0
- data/lib/openc3/packets/commands.rb +373 -0
- data/lib/openc3/packets/json_packet.rb +134 -0
- data/lib/openc3/packets/limits.rb +271 -0
- data/lib/openc3/packets/limits_response.rb +53 -0
- data/lib/openc3/packets/packet.rb +1168 -0
- data/lib/openc3/packets/packet_config.rb +625 -0
- data/lib/openc3/packets/packet_item.rb +586 -0
- data/lib/openc3/packets/packet_item_limits.rb +162 -0
- data/lib/openc3/packets/parsers/format_string_parser.rb +65 -0
- data/lib/openc3/packets/parsers/limits_parser.rb +159 -0
- data/lib/openc3/packets/parsers/limits_response_parser.rb +61 -0
- data/lib/openc3/packets/parsers/packet_item_parser.rb +272 -0
- data/lib/openc3/packets/parsers/packet_parser.rb +134 -0
- data/lib/openc3/packets/parsers/processor_parser.rb +73 -0
- data/lib/openc3/packets/parsers/state_parser.rb +127 -0
- data/lib/openc3/packets/parsers/xtce_converter.rb +442 -0
- data/lib/openc3/packets/parsers/xtce_parser.rb +722 -0
- data/lib/openc3/packets/structure.rb +553 -0
- data/lib/openc3/packets/structure_item.rb +365 -0
- data/lib/openc3/packets/telemetry.rb +487 -0
- data/lib/openc3/processors/processor.rb +86 -0
- data/lib/openc3/processors/statistics_processor.rb +82 -0
- data/lib/openc3/processors/watermark_processor.rb +58 -0
- data/lib/openc3/processors.rb +24 -0
- data/lib/openc3/script/api_shared.rb +828 -0
- data/lib/openc3/script/calendar.rb +89 -0
- data/lib/openc3/script/commands.rb +227 -0
- data/lib/openc3/script/exceptions.rb +29 -0
- data/lib/openc3/script/extract.rb +161 -0
- data/lib/openc3/script/limits.rb +60 -0
- data/lib/openc3/script/script.rb +299 -0
- data/lib/openc3/script/script_runner.rb +238 -0
- data/lib/openc3/script/storage.rb +146 -0
- data/lib/openc3/script/suite.rb +542 -0
- data/lib/openc3/script/suite_results.rb +196 -0
- data/lib/openc3/script/suite_runner.rb +217 -0
- data/lib/openc3/script.rb +21 -0
- data/lib/openc3/streams/serial_stream.rb +167 -0
- data/lib/openc3/streams/stream.rb +63 -0
- data/lib/openc3/streams/tcpip_client_stream.rb +116 -0
- data/lib/openc3/streams/tcpip_socket_stream.rb +195 -0
- data/lib/openc3/system/system.rb +127 -0
- data/lib/openc3/system/system_config.rb +411 -0
- data/lib/openc3/system/target.rb +269 -0
- data/lib/openc3/system.rb +24 -0
- data/lib/openc3/tools/cmd_tlm_server/api.rb +20 -0
- data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +320 -0
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +294 -0
- data/lib/openc3/tools/table_manager/table.rb +77 -0
- data/lib/openc3/tools/table_manager/table_config.rb +273 -0
- data/lib/openc3/tools/table_manager/table_item.rb +90 -0
- data/lib/openc3/tools/table_manager/table_item_parser.rb +66 -0
- data/lib/openc3/tools/table_manager/table_manager_core.rb +333 -0
- data/lib/openc3/tools/table_manager/table_parser.rb +93 -0
- data/lib/openc3/tools/test_runner/test.rb +67 -0
- data/lib/openc3/top_level.rb +595 -0
- data/lib/openc3/topics/autonomic_topic.rb +52 -0
- data/lib/openc3/topics/calendar_topic.rb +44 -0
- data/lib/openc3/topics/command_decom_topic.rb +76 -0
- data/lib/openc3/topics/command_topic.rb +83 -0
- data/lib/openc3/topics/config_topic.rb +68 -0
- data/lib/openc3/topics/interface_topic.rb +73 -0
- data/lib/openc3/topics/limits_event_topic.rb +109 -0
- data/lib/openc3/topics/notifications_topic.rb +28 -0
- data/lib/openc3/topics/router_topic.rb +85 -0
- data/lib/openc3/topics/telemetry_decom_topic.rb +54 -0
- data/lib/openc3/topics/telemetry_topic.rb +36 -0
- data/lib/openc3/topics/timeline_topic.rb +45 -0
- data/lib/openc3/topics/topic.rb +53 -0
- data/lib/openc3/utilities/authentication.rb +141 -0
- data/lib/openc3/utilities/authorization.rb +51 -0
- data/lib/openc3/utilities/crc.rb +278 -0
- data/lib/openc3/utilities/csv.rb +153 -0
- data/lib/openc3/utilities/logger.rb +187 -0
- data/lib/openc3/utilities/message_log.rb +91 -0
- data/lib/openc3/utilities/metric.rb +141 -0
- data/lib/openc3/utilities/process_manager.rb +139 -0
- data/lib/openc3/utilities/quaternion.rb +257 -0
- data/lib/openc3/utilities/ruby_lex_utils.rb +568 -0
- data/lib/openc3/utilities/s3.rb +202 -0
- data/lib/openc3/utilities/s3_autoload.rb +9 -0
- data/lib/openc3/utilities/s3_file_cache.rb +274 -0
- data/lib/openc3/utilities/simulated_target.rb +117 -0
- data/lib/openc3/utilities/sleeper.rb +51 -0
- data/lib/openc3/utilities/store.rb +23 -0
- data/lib/openc3/utilities/store_autoload.rb +237 -0
- data/lib/openc3/utilities/zip.rb +21 -0
- data/lib/openc3/utilities.rb +35 -0
- data/lib/openc3/version.rb +14 -0
- data/lib/openc3/win32/excel.rb +132 -0
- data/lib/openc3/win32/win32.rb +402 -0
- data/lib/openc3/win32/win32_main.rb +333 -0
- data/lib/openc3.rb +49 -0
- data/tasks/gemfile_stats.rake +113 -0
- data/tasks/spec.rake +30 -0
- data/templates/plugin-template/README.md +15 -0
- data/templates/plugin-template/Rakefile +12 -0
- data/templates/plugin-template/plugin.gemspec +23 -0
- data/templates/plugin-template/plugin.txt +9 -0
- data/templates/plugin-template/targets/TARGET/cmd_tlm/cmd.txt +8 -0
- data/templates/plugin-template/targets/TARGET/cmd_tlm/tlm.txt +8 -0
- data/templates/plugin-template/targets/TARGET/lib/target.rb +10 -0
- data/templates/plugin-template/targets/TARGET/procedures/procedure.rb +3 -0
- data/templates/plugin-template/targets/TARGET/screens/status.txt +9 -0
- data/templates/plugin-template/targets/TARGET/target.txt +5 -0
- metadata +849 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 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 Affero 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
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# Modified by OpenC3, Inc.
|
|
17
|
+
# All changes Copyright 2022, OpenC3, Inc.
|
|
18
|
+
# All Rights Reserved
|
|
19
|
+
|
|
20
|
+
# This file contains top level functions in the OpenC3 namespace
|
|
21
|
+
|
|
22
|
+
require 'thread'
|
|
23
|
+
require 'digest'
|
|
24
|
+
require 'open3'
|
|
25
|
+
require 'openc3/core_ext'
|
|
26
|
+
require 'openc3/version'
|
|
27
|
+
require 'openc3/utilities/logger'
|
|
28
|
+
require 'socket'
|
|
29
|
+
require 'pathname'
|
|
30
|
+
|
|
31
|
+
$openc3_chdir_mutex = Mutex.new
|
|
32
|
+
|
|
33
|
+
# If a hazardous command is sent through the {OpenC3::Api} this error is raised.
|
|
34
|
+
# {OpenC3::Script} rescues the error and prompts the user to continue.
|
|
35
|
+
class HazardousError < StandardError
|
|
36
|
+
attr_accessor :target_name
|
|
37
|
+
attr_accessor :cmd_name
|
|
38
|
+
attr_accessor :cmd_params
|
|
39
|
+
attr_accessor :hazardous_description
|
|
40
|
+
attr_accessor :formatted # formatted command for use in resending original
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
string = "#{target_name} #{cmd_name} with #{cmd_params} is Hazardous"
|
|
44
|
+
string << "due to '#{hazardous_description}'" if hazardous_description
|
|
45
|
+
# Pass along the original formatted command so it can be resent
|
|
46
|
+
string << ".\n#{formatted}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# OpenC3 is almost
|
|
51
|
+
# wholly contained within the OpenC3 module. OpenC3 also extends some of the
|
|
52
|
+
# core Ruby classes to add additional functionality.
|
|
53
|
+
|
|
54
|
+
module OpenC3
|
|
55
|
+
BASE_PWD = Dir.pwd
|
|
56
|
+
|
|
57
|
+
# FatalErrors cause an exit but are not as dangerous as other errors.
|
|
58
|
+
# They are used for known issues and thus we don't need a full error report.
|
|
59
|
+
class FatalError < StandardError; end
|
|
60
|
+
|
|
61
|
+
# Global mutex for the OpenC3 module
|
|
62
|
+
OPENC3_MUTEX = Mutex.new
|
|
63
|
+
|
|
64
|
+
# Path to OpenC3 Gem based on location of top_level.rb
|
|
65
|
+
PATH = File.expand_path(File.join(File.dirname(__FILE__), '../..'))
|
|
66
|
+
PATH.freeze
|
|
67
|
+
|
|
68
|
+
# Header to put on all marshal files created by OpenC3
|
|
69
|
+
OPENC3_MARSHAL_HEADER = "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}] OpenC3 #{OPENC3_VERSION}"
|
|
70
|
+
|
|
71
|
+
# Disables the Ruby interpreter warnings such as when redefining a constant
|
|
72
|
+
def self.disable_warnings
|
|
73
|
+
saved_verbose = $VERBOSE
|
|
74
|
+
$VERBOSE = nil
|
|
75
|
+
yield
|
|
76
|
+
ensure
|
|
77
|
+
$VERBOSE = saved_verbose
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Adds a path to the global Ruby search path
|
|
81
|
+
#
|
|
82
|
+
# @param path [String] Directory path
|
|
83
|
+
def self.add_to_search_path(path, front = true)
|
|
84
|
+
path = File.expand_path(path)
|
|
85
|
+
$:.delete(path)
|
|
86
|
+
if front
|
|
87
|
+
$:.unshift(path)
|
|
88
|
+
else # Back
|
|
89
|
+
$: << path
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Creates a marshal file by serializing the given obj
|
|
94
|
+
#
|
|
95
|
+
# @param marshal_filename [String] Name of the marshal file to create
|
|
96
|
+
# @param obj [Object] The object to serialize to the file
|
|
97
|
+
def self.marshal_dump(marshal_filename, obj)
|
|
98
|
+
File.open(marshal_filename, 'wb') do |file|
|
|
99
|
+
file.write(OPENC3_MARSHAL_HEADER)
|
|
100
|
+
file.write(Marshal.dump(obj))
|
|
101
|
+
end
|
|
102
|
+
rescue Exception => exception
|
|
103
|
+
begin
|
|
104
|
+
File.delete(marshal_filename)
|
|
105
|
+
rescue Exception
|
|
106
|
+
# Oh well - we tried
|
|
107
|
+
end
|
|
108
|
+
if exception.class == TypeError and exception.message =~ /Thread::Mutex/
|
|
109
|
+
original_backtrace = exception.backtrace
|
|
110
|
+
exception = exception.exception("Mutex exists in a packet. Note: Packets must not be read during class initializers for Conversions, Limits Responses, etc.: #{exception}")
|
|
111
|
+
exception.set_backtrace(original_backtrace)
|
|
112
|
+
end
|
|
113
|
+
self.handle_fatal_exception(exception)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Loads the marshal file back into a Ruby object
|
|
117
|
+
#
|
|
118
|
+
# @param marshal_filename [String] Name of the marshal file to load
|
|
119
|
+
def self.marshal_load(marshal_filename)
|
|
120
|
+
openc3_marshal_header = nil
|
|
121
|
+
data = nil
|
|
122
|
+
File.open(marshal_filename, 'rb') do |file|
|
|
123
|
+
openc3_marshal_header = file.read(OPENC3_MARSHAL_HEADER.length)
|
|
124
|
+
data = file.read
|
|
125
|
+
end
|
|
126
|
+
if openc3_marshal_header == OPENC3_MARSHAL_HEADER
|
|
127
|
+
return Marshal.load(data)
|
|
128
|
+
else
|
|
129
|
+
Logger.warn "Marshal load failed with invalid marshal file: #{marshal_filename}"
|
|
130
|
+
return nil
|
|
131
|
+
end
|
|
132
|
+
rescue Exception => exception
|
|
133
|
+
if File.exist?(marshal_filename)
|
|
134
|
+
Logger.error "Marshal load failed with exception: #{marshal_filename}\n#{exception.formatted}"
|
|
135
|
+
else
|
|
136
|
+
Logger.info "Marshal file does not exist: #{marshal_filename}"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Try to delete the bad marshal file
|
|
140
|
+
begin
|
|
141
|
+
File.delete(marshal_filename)
|
|
142
|
+
rescue Exception
|
|
143
|
+
# Oh well - we tried
|
|
144
|
+
end
|
|
145
|
+
self.handle_fatal_exception(exception) if File.exist?(marshal_filename)
|
|
146
|
+
return nil
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Executes the command in a new Ruby Thread.
|
|
150
|
+
#
|
|
151
|
+
# @param command [String] The command to execute via the 'system' call
|
|
152
|
+
def self.run_process(command)
|
|
153
|
+
thread = nil
|
|
154
|
+
thread = Thread.new do
|
|
155
|
+
system(command)
|
|
156
|
+
end
|
|
157
|
+
# Wait for the thread and process to start
|
|
158
|
+
sleep 0.01 until !thread.status.nil?
|
|
159
|
+
sleep 0.1
|
|
160
|
+
thread
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Executes the command in a new Ruby Thread. Will print the output if the
|
|
164
|
+
# process produces any output
|
|
165
|
+
#
|
|
166
|
+
# @param command [String] The command to execute via the 'system' call
|
|
167
|
+
def self.run_process_check_output(command)
|
|
168
|
+
thread = nil
|
|
169
|
+
thread = Thread.new do
|
|
170
|
+
output, _ = Open3.capture2e(command)
|
|
171
|
+
if !output.empty?
|
|
172
|
+
# Ignore modalSession messages on Mac Mavericks
|
|
173
|
+
new_output = ''
|
|
174
|
+
output.each_line do |line|
|
|
175
|
+
new_output << line if !/modalSession/.match?(line)
|
|
176
|
+
end
|
|
177
|
+
output = new_output
|
|
178
|
+
|
|
179
|
+
if !output.empty?
|
|
180
|
+
Logger.error output
|
|
181
|
+
self.write_unexpected_file(output)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
# Wait for the thread and process to start
|
|
186
|
+
sleep 0.01 until !thread.status.nil?
|
|
187
|
+
sleep 0.1
|
|
188
|
+
thread
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Runs a hash algorithm over one or more files and returns the Digest object.
|
|
192
|
+
# Handles windows/unix new line differences but changes in whitespace will
|
|
193
|
+
# change the hash sum.
|
|
194
|
+
#
|
|
195
|
+
# Usage:
|
|
196
|
+
# digest = OpenC3.hash_files(files, additional_data, hashing_algorithm)
|
|
197
|
+
# digest.digest # => the 16 bytes of digest
|
|
198
|
+
# digest.hexdigest # => the formatted string in hex
|
|
199
|
+
#
|
|
200
|
+
# @param filenames [Array<String>] List of files to read and calculate a hashing
|
|
201
|
+
# sum on
|
|
202
|
+
# @param additional_data [String] Additional data to add to the hashing sum
|
|
203
|
+
# @param hashing_algorithm [String] Hashing algorithm to use
|
|
204
|
+
# @return [Digest::<algorithm>] The hashing sum object
|
|
205
|
+
def self.hash_files(filenames, additional_data = nil, hashing_algorithm = 'SHA256')
|
|
206
|
+
digest = Digest.const_get(hashing_algorithm).public_send('new')
|
|
207
|
+
|
|
208
|
+
filenames.each do |filename|
|
|
209
|
+
next if File.directory?(filename)
|
|
210
|
+
|
|
211
|
+
# Read the file's data and add to the running hashing sum
|
|
212
|
+
digest << File.read(filename)
|
|
213
|
+
end
|
|
214
|
+
digest << additional_data if additional_data
|
|
215
|
+
digest
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Opens a timestamped log file for writing. The opened file is yielded back
|
|
219
|
+
# to the block.
|
|
220
|
+
#
|
|
221
|
+
# @param filename [String] String to append to the exception log filename.
|
|
222
|
+
# The filename will start with a date/time stamp.
|
|
223
|
+
# @param log_dir [String] By default this method will write to the OpenC3
|
|
224
|
+
# default log directory. By setting this parameter you can override the
|
|
225
|
+
# directory the log will be written to.
|
|
226
|
+
# @yieldparam file [File] The log file
|
|
227
|
+
# @return [String|nil] The fully pathed log filename or nil if there was
|
|
228
|
+
# an error creating the log file.
|
|
229
|
+
def self.create_log_file(filename, log_dir = nil)
|
|
230
|
+
log_file = nil
|
|
231
|
+
begin
|
|
232
|
+
# The following code goes inside a begin rescue because it reads the
|
|
233
|
+
# system.txt configuration file. If this has an error we won't be able
|
|
234
|
+
# to determine the log path but we still want to write the log.
|
|
235
|
+
log_dir = System.instance.paths['LOGS'] unless log_dir
|
|
236
|
+
# Make sure the log directory exists
|
|
237
|
+
raise unless File.exist?(log_dir)
|
|
238
|
+
rescue Exception
|
|
239
|
+
log_dir = nil # Reset log dir since it failed above
|
|
240
|
+
# First check for ./logs
|
|
241
|
+
log_dir = './logs' if File.exist?('./logs')
|
|
242
|
+
# Prefer ./outputs/logs if it exists
|
|
243
|
+
log_dir = './outputs/logs' if File.exist?('./outputs/logs')
|
|
244
|
+
# If all else fails just use the local directory
|
|
245
|
+
log_dir = '.' unless log_dir
|
|
246
|
+
end
|
|
247
|
+
log_file = File.join(log_dir,
|
|
248
|
+
File.build_timestamped_filename([filename]))
|
|
249
|
+
# Check for the log file existing. This could happen if this method gets
|
|
250
|
+
# called more than once in the same second.
|
|
251
|
+
if File.exist?(log_file)
|
|
252
|
+
sleep 1.01 # Sleep before rebuilding the timestamp to get something unique
|
|
253
|
+
log_file = File.join(log_dir,
|
|
254
|
+
File.build_timestamped_filename([filename]))
|
|
255
|
+
end
|
|
256
|
+
begin
|
|
257
|
+
OPENC3_MUTEX.synchronize do
|
|
258
|
+
file = File.open(log_file, 'w')
|
|
259
|
+
yield file
|
|
260
|
+
ensure
|
|
261
|
+
file.close unless file.closed?
|
|
262
|
+
File.chmod(0444, log_file) # Make file read only
|
|
263
|
+
end
|
|
264
|
+
rescue Exception
|
|
265
|
+
# Ensure we always return
|
|
266
|
+
end
|
|
267
|
+
log_file = File.expand_path(log_file)
|
|
268
|
+
return log_file
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Writes a log file with information about the current configuration
|
|
272
|
+
# including the Ruby version, OpenC3 version, whether you are on Windows, the
|
|
273
|
+
# OpenC3 path, and the Ruby path along with the exception that
|
|
274
|
+
# is passed in.
|
|
275
|
+
#
|
|
276
|
+
# @param [String] filename String to append to the exception log filename.
|
|
277
|
+
# The filename will start with a date/time stamp.
|
|
278
|
+
# @param [String] log_dir By default this method will write to the OpenC3
|
|
279
|
+
# default log directory. By setting this parameter you can override the
|
|
280
|
+
# directory the log will be written to.
|
|
281
|
+
# @return [String|nil] The fully pathed log filename or nil if there was
|
|
282
|
+
# an error creating the log file.
|
|
283
|
+
def self.write_exception_file(exception, filename = 'exception', log_dir = nil)
|
|
284
|
+
log_file = create_log_file(filename, log_dir) do |file|
|
|
285
|
+
file.puts "Exception:"
|
|
286
|
+
if exception
|
|
287
|
+
file.puts exception.formatted
|
|
288
|
+
file.puts
|
|
289
|
+
else
|
|
290
|
+
file.puts "No Exception Given"
|
|
291
|
+
file.puts caller.join("\n")
|
|
292
|
+
file.puts
|
|
293
|
+
end
|
|
294
|
+
file.puts "Caller Backtrace:"
|
|
295
|
+
file.puts caller().join("\n")
|
|
296
|
+
file.puts
|
|
297
|
+
|
|
298
|
+
file.puts "Ruby Version: ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]"
|
|
299
|
+
file.puts "Rubygems Version: #{Gem::VERSION}"
|
|
300
|
+
file.puts "OpenC3 Version: #{OpenC3::VERSION}"
|
|
301
|
+
file.puts "OpenC3::PATH: #{OpenC3::PATH}"
|
|
302
|
+
file.puts ""
|
|
303
|
+
file.puts "Environment:"
|
|
304
|
+
file.puts "RUBYOPT: #{ENV['RUBYOPT']}"
|
|
305
|
+
file.puts "RUBYLIB: #{ENV['RUBYLIB']}"
|
|
306
|
+
file.puts "GEM_PATH: #{ENV['GEM_PATH']}"
|
|
307
|
+
file.puts "GEMRC: #{ENV['GEMRC']}"
|
|
308
|
+
file.puts "RI_DEVKIT: #{ENV['RI_DEVKIT']}"
|
|
309
|
+
file.puts "GEM_HOME: #{ENV['GEM_HOME']}"
|
|
310
|
+
file.puts "PATH: #{ENV['PATH']}"
|
|
311
|
+
file.puts ""
|
|
312
|
+
file.puts "Ruby Path:\n #{$:.join("\n ")}\n\n"
|
|
313
|
+
file.puts "Gems:"
|
|
314
|
+
Gem.loaded_specs.values.map { |x| file.puts "#{x.name} #{x.version} #{x.platform}" }
|
|
315
|
+
file.puts ""
|
|
316
|
+
file.puts "All Threads Backtraces:"
|
|
317
|
+
Thread.list.each do |thread|
|
|
318
|
+
file.puts thread.backtrace.join("\n")
|
|
319
|
+
file.puts
|
|
320
|
+
end
|
|
321
|
+
file.puts ""
|
|
322
|
+
file.puts ""
|
|
323
|
+
ensure
|
|
324
|
+
file.close
|
|
325
|
+
end
|
|
326
|
+
return log_file
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Writes a log file with information about unexpected output
|
|
330
|
+
#
|
|
331
|
+
# @param [String] text The unexpected output text
|
|
332
|
+
# @param [String] filename String to append to the exception log filename.
|
|
333
|
+
# The filename will start with a date/time stamp.
|
|
334
|
+
# @param [String] log_dir By default this method will write to the OpenC3
|
|
335
|
+
# default log directory. By setting this parameter you can override the
|
|
336
|
+
# directory the log will be written to.
|
|
337
|
+
# @return [String|nil] The fully pathed log filename or nil if there was
|
|
338
|
+
# an error creating the log file.
|
|
339
|
+
def self.write_unexpected_file(text, filename = 'unexpected', log_dir = nil)
|
|
340
|
+
log_file = create_log_file(filename, log_dir) do |file|
|
|
341
|
+
file.puts "Unexpected Output:\n\n"
|
|
342
|
+
file.puts text
|
|
343
|
+
ensure
|
|
344
|
+
file.close
|
|
345
|
+
end
|
|
346
|
+
return log_file
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Catch fatal exceptions within the block
|
|
350
|
+
# This is intended to catch exceptions before the GUI is available
|
|
351
|
+
def self.catch_fatal_exception
|
|
352
|
+
yield
|
|
353
|
+
rescue Exception => error
|
|
354
|
+
unless error.class == SystemExit or error.class == Interrupt
|
|
355
|
+
Logger.level = Logger::FATAL
|
|
356
|
+
OpenC3.handle_fatal_exception(error, false)
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Write a message to the Logger, write an exception file, and popup a GUI
|
|
361
|
+
# window if try_gui. Finally 'exit 1' is called to end the calling program.
|
|
362
|
+
#
|
|
363
|
+
# @param error [Exception] The exception to handle
|
|
364
|
+
# @param try_gui [Boolean] Whether to try and create a GUI exception popup
|
|
365
|
+
def self.handle_fatal_exception(error, try_gui = true)
|
|
366
|
+
unless error.class == SystemExit or error.class == Interrupt
|
|
367
|
+
$openc3_fatal_exception = error
|
|
368
|
+
self.write_exception_file(error)
|
|
369
|
+
Logger.level = Logger::FATAL
|
|
370
|
+
Logger.fatal "Fatal Exception! Exiting..."
|
|
371
|
+
Logger.fatal error.formatted
|
|
372
|
+
if $stdout != STDOUT
|
|
373
|
+
$stdout = STDOUT
|
|
374
|
+
Logger.fatal "Fatal Exception! Exiting..."
|
|
375
|
+
Logger.fatal error.formatted
|
|
376
|
+
end
|
|
377
|
+
sleep 1 # Allow the messages to be printed and then crash
|
|
378
|
+
exit 1
|
|
379
|
+
else
|
|
380
|
+
exit 0
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# CriticalErrors are errors that need to be brought to a user's attention but
|
|
385
|
+
# do not cause an exit. A good example is if the packet log writer fails and
|
|
386
|
+
# can no longer write the log file. Write a message to the Logger, write an
|
|
387
|
+
# exception file, and popup a GUI window if try_gui. Ensure the GUI only
|
|
388
|
+
# comes up once so this method can be called over and over by failing code.
|
|
389
|
+
#
|
|
390
|
+
# @param error [Exception] The exception to handle
|
|
391
|
+
# @param try_gui [Boolean] Whether to try and create a GUI exception popup
|
|
392
|
+
def self.handle_critical_exception(error, try_gui = true)
|
|
393
|
+
Logger.error "Critical Exception! #{error.formatted}"
|
|
394
|
+
self.write_exception_file(error)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Creates a Ruby Thread to run the given block. Rescues any exceptions and
|
|
398
|
+
# retries the threads the given number of times before handling the thread
|
|
399
|
+
# death by calling {OpenC3.handle_fatal_exception}.
|
|
400
|
+
#
|
|
401
|
+
# @param name [String] Name of the thread
|
|
402
|
+
# @param retry_attempts [Integer] The number of times to allow the thread to
|
|
403
|
+
# restart before exiting
|
|
404
|
+
def self.safe_thread(name, retry_attempts = 0)
|
|
405
|
+
Thread.new do
|
|
406
|
+
retry_count = 0
|
|
407
|
+
begin
|
|
408
|
+
yield
|
|
409
|
+
rescue => error
|
|
410
|
+
Logger.error "#{name} thread unexpectedly died. Retries: #{retry_count} of #{retry_attempts}"
|
|
411
|
+
Logger.error error.formatted
|
|
412
|
+
retry_count += 1
|
|
413
|
+
if retry_count <= retry_attempts
|
|
414
|
+
self.write_exception_file(error)
|
|
415
|
+
retry
|
|
416
|
+
end
|
|
417
|
+
handle_fatal_exception(error)
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Require the class represented by the filename. This uses the standard Ruby
|
|
423
|
+
# convention of having a single class per file where the class name is camel
|
|
424
|
+
# cased and filename is lowercase with underscores.
|
|
425
|
+
#
|
|
426
|
+
# @param class_name_or_class_filename [String] The name of the class or the file which contains the
|
|
427
|
+
# Ruby class to require
|
|
428
|
+
# @param log_error [Boolean] Whether to log an error if we can't require the class
|
|
429
|
+
def self.require_class(class_name_or_class_filename, log_error = true)
|
|
430
|
+
if class_name_or_class_filename.downcase[-3..-1] == '.rb' or (class_name_or_class_filename[0] == class_name_or_class_filename[0].downcase)
|
|
431
|
+
class_filename = class_name_or_class_filename
|
|
432
|
+
class_name = class_filename.filename_to_class_name
|
|
433
|
+
else
|
|
434
|
+
class_name = class_name_or_class_filename
|
|
435
|
+
class_filename = class_name.class_name_to_filename
|
|
436
|
+
end
|
|
437
|
+
return class_name.to_class if class_name.to_class and defined? class_name.to_class
|
|
438
|
+
|
|
439
|
+
self.require_file(class_filename, log_error)
|
|
440
|
+
klass = class_name.to_class
|
|
441
|
+
raise "Ruby class #{class_name} not found" unless klass
|
|
442
|
+
|
|
443
|
+
klass
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
# Requires a file with a standard error message if it fails
|
|
447
|
+
#
|
|
448
|
+
# @param filename [String] The name of the file to require
|
|
449
|
+
# @param log_error [Boolean] Whether to log an error if we can't require the class
|
|
450
|
+
def self.require_file(filename, log_error = true)
|
|
451
|
+
require filename
|
|
452
|
+
rescue Exception => err
|
|
453
|
+
msg = "Unable to require #{filename} due to #{err.message}. "\
|
|
454
|
+
"Ensure #{filename} is in the OpenC3 lib directory."
|
|
455
|
+
Logger.error msg if log_error
|
|
456
|
+
raise $!, msg, $!.backtrace
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# @param filename [String] Name of the file to open in the web browser
|
|
460
|
+
def self.open_in_web_browser(filename)
|
|
461
|
+
if filename
|
|
462
|
+
if Kernel.is_windows?
|
|
463
|
+
self.run_process("cmd /c \"start \"\" \"#{filename.gsub('/', '\\')}\"\"")
|
|
464
|
+
elsif Kernel.is_mac?
|
|
465
|
+
self.run_process("open -a Safari \"#{filename}\"")
|
|
466
|
+
else
|
|
467
|
+
which_firefox = `which firefox`.chomp
|
|
468
|
+
if which_firefox =~ /Command not found/i or which_firefox =~ /no .* in/i
|
|
469
|
+
raise "Firefox not found"
|
|
470
|
+
else
|
|
471
|
+
system_call = "#{which_firefox} \"#{filename}\""
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
self.run_process(system_call)
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# Temporarily set the working directory during a block
|
|
480
|
+
# Working directory is global, so this can make other threads wait
|
|
481
|
+
# Ruby Dir.chdir with block always throws an error if multiple threads
|
|
482
|
+
# call Dir.chdir
|
|
483
|
+
def self.set_working_dir(working_dir, &block)
|
|
484
|
+
if $openc3_chdir_mutex.owned?
|
|
485
|
+
set_working_dir_internal(working_dir, &block)
|
|
486
|
+
else
|
|
487
|
+
$openc3_chdir_mutex.synchronize do
|
|
488
|
+
set_working_dir_internal(working_dir, &block)
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# Private helper method
|
|
494
|
+
def self.set_working_dir_internal(working_dir)
|
|
495
|
+
current_dir = Dir.pwd
|
|
496
|
+
Dir.chdir(working_dir)
|
|
497
|
+
begin
|
|
498
|
+
yield
|
|
499
|
+
ensure
|
|
500
|
+
Dir.chdir(current_dir)
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Attempt to gracefully kill a thread
|
|
505
|
+
# @param owner Object that owns the thread and may have a graceful_kill method
|
|
506
|
+
# @param thread The thread to gracefully kill
|
|
507
|
+
# @param graceful_timeout Timeout in seconds to wait for it to die gracefully
|
|
508
|
+
# @param timeout_interval How often to poll for aliveness
|
|
509
|
+
# @param hard_timeout Timeout in seconds to wait for it to die ungracefully
|
|
510
|
+
def self.kill_thread(owner, thread, graceful_timeout = 1, timeout_interval = 0.01, hard_timeout = 1)
|
|
511
|
+
if thread
|
|
512
|
+
if owner and owner.respond_to? :graceful_kill
|
|
513
|
+
if Thread.current != thread
|
|
514
|
+
owner.graceful_kill
|
|
515
|
+
end_time = Time.now.sys + graceful_timeout
|
|
516
|
+
while thread.alive? && ((end_time - Time.now.sys) > 0)
|
|
517
|
+
sleep(timeout_interval)
|
|
518
|
+
end
|
|
519
|
+
else
|
|
520
|
+
Logger.warn "Threads cannot graceful_kill themselves"
|
|
521
|
+
end
|
|
522
|
+
elsif owner
|
|
523
|
+
Logger.info "Thread owner #{owner.class} does not support graceful_kill"
|
|
524
|
+
end
|
|
525
|
+
if thread.alive?
|
|
526
|
+
# If the thread dies after alive? but before backtrace, bt will be nil.
|
|
527
|
+
bt = thread.backtrace
|
|
528
|
+
|
|
529
|
+
# Graceful failed
|
|
530
|
+
msg = "Failed to gracefully kill thread:\n"
|
|
531
|
+
msg << " Caller Backtrace:\n #{caller().join("\n ")}\n"
|
|
532
|
+
msg << " \n Thread Backtrace:\n #{bt.join("\n ")}\n" if bt
|
|
533
|
+
msg << "\n"
|
|
534
|
+
Logger.warn msg
|
|
535
|
+
thread.kill
|
|
536
|
+
end_time = Time.now.sys + hard_timeout
|
|
537
|
+
while thread.alive? && ((end_time - Time.now.sys) > 0)
|
|
538
|
+
sleep(timeout_interval)
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
if thread.alive?
|
|
542
|
+
Logger.error "Failed to kill thread"
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
# Close a socket in a manner that ensures that any reads blocked in select
|
|
548
|
+
# will unblock across platforms
|
|
549
|
+
# @param socket The socket to close
|
|
550
|
+
def self.close_socket(socket)
|
|
551
|
+
if socket
|
|
552
|
+
# Calling shutdown and then sleep seems to be required
|
|
553
|
+
# to get select to reliably unblock on linux
|
|
554
|
+
begin
|
|
555
|
+
socket.shutdown(:RDWR)
|
|
556
|
+
sleep(0)
|
|
557
|
+
rescue Exception
|
|
558
|
+
# Oh well we tried
|
|
559
|
+
end
|
|
560
|
+
begin
|
|
561
|
+
socket.close unless socket.closed?
|
|
562
|
+
rescue Exception
|
|
563
|
+
# Oh well we tried
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# The following code makes most older COSMOS 5 plugins still work with OpenC3
|
|
570
|
+
# New plugins should only use openc3 paths and module OpenC3
|
|
571
|
+
unless ENV['OPENC3_NO_COSMOS_COMPATIBILITY']
|
|
572
|
+
Cosmos = OpenC3
|
|
573
|
+
ENV['COSMOS_SCOPE'] = ENV['OPENC3_SCOPE']
|
|
574
|
+
module CosmosCompatibility
|
|
575
|
+
def require(*args)
|
|
576
|
+
filename = args[0]
|
|
577
|
+
if filename[0..6] == "cosmos/"
|
|
578
|
+
filename[0..6] = "openc3/"
|
|
579
|
+
end
|
|
580
|
+
args[0] = filename
|
|
581
|
+
super(*args)
|
|
582
|
+
end
|
|
583
|
+
def load(*args)
|
|
584
|
+
filename = args[0]
|
|
585
|
+
if filename[0..6] == "cosmos/"
|
|
586
|
+
filename[0..6] = "openc3/"
|
|
587
|
+
end
|
|
588
|
+
args[0] = filename
|
|
589
|
+
super(*args)
|
|
590
|
+
end
|
|
591
|
+
end
|
|
592
|
+
class Object
|
|
593
|
+
include CosmosCompatibility
|
|
594
|
+
end
|
|
595
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 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 Affero 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
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# Modified by OpenC3, Inc.
|
|
17
|
+
# All changes Copyright 2022, OpenC3, Inc.
|
|
18
|
+
# All Rights Reserved
|
|
19
|
+
|
|
20
|
+
require 'openc3/topics/topic'
|
|
21
|
+
|
|
22
|
+
module OpenC3
|
|
23
|
+
class AutonomicTopic < Topic
|
|
24
|
+
PRIMARY_KEY = "__openc3_autonomic"
|
|
25
|
+
|
|
26
|
+
# Notify to the topic
|
|
27
|
+
#
|
|
28
|
+
# ```json
|
|
29
|
+
# {
|
|
30
|
+
# "kind" => "created",
|
|
31
|
+
# "type" => "trigger",
|
|
32
|
+
# "data" => {
|
|
33
|
+
# "name" => "foobar",
|
|
34
|
+
# "target": "INST",
|
|
35
|
+
# "packet": "ADCS",
|
|
36
|
+
# "left": {
|
|
37
|
+
# "type": "item",
|
|
38
|
+
# "item": "POSX",
|
|
39
|
+
# },
|
|
40
|
+
# "operation": ">",
|
|
41
|
+
# "right": {
|
|
42
|
+
# "type": "value",
|
|
43
|
+
# "value": 690000,
|
|
44
|
+
# }
|
|
45
|
+
# }
|
|
46
|
+
# }
|
|
47
|
+
# ```
|
|
48
|
+
def self.write_notification(notification, scope:)
|
|
49
|
+
Topic.write_topic("#{scope}#{PRIMARY_KEY}", notification, '*', 1000)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 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 Affero 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
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# Modified by OpenC3, Inc.
|
|
17
|
+
# All changes Copyright 2022, OpenC3, Inc.
|
|
18
|
+
# All Rights Reserved
|
|
19
|
+
|
|
20
|
+
require 'openc3/topics/topic'
|
|
21
|
+
|
|
22
|
+
module OpenC3
|
|
23
|
+
class CalendarTopic < Topic
|
|
24
|
+
PRIMARY_KEY = '__openc3_calendar'.freeze
|
|
25
|
+
|
|
26
|
+
# Write an activity to the topic
|
|
27
|
+
#
|
|
28
|
+
# ```json
|
|
29
|
+
# {
|
|
30
|
+
# "type" => "metadata",
|
|
31
|
+
# "kind" => "created",
|
|
32
|
+
# "metadata" => {
|
|
33
|
+
# "target" => "FOO",
|
|
34
|
+
# "start" => 1621875570,
|
|
35
|
+
# "color" => "#FF0000",
|
|
36
|
+
# "metadata" => {"test"=>"123456"}
|
|
37
|
+
# },
|
|
38
|
+
# }
|
|
39
|
+
# ```
|
|
40
|
+
def self.write_entry(entry, scope:)
|
|
41
|
+
Topic.write_topic("#{scope}#{PRIMARY_KEY}", entry, '*', 1000)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|