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,319 @@
|
|
|
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
|
+
# https://www.rubydoc.info/gems/redis/Redis/Commands/SortedSets
|
|
21
|
+
|
|
22
|
+
require 'openc3/models/model'
|
|
23
|
+
require 'openc3/topics/timeline_topic'
|
|
24
|
+
|
|
25
|
+
module OpenC3
|
|
26
|
+
class ActivityError < StandardError; end
|
|
27
|
+
|
|
28
|
+
class ActivityInputError < ActivityError; end
|
|
29
|
+
|
|
30
|
+
class ActivityOverlapError < ActivityError; end
|
|
31
|
+
|
|
32
|
+
class ActivityModel < Model
|
|
33
|
+
MAX_DURATION = Time::SEC_PER_DAY
|
|
34
|
+
PRIMARY_KEY = '__openc3_timelines'.freeze # MUST be equal to `TimelineModel::PRIMARY_KEY` minus the leading __
|
|
35
|
+
|
|
36
|
+
# Called via the microservice this gets the previous 00:00:15 to 01:01:00. This should allow
|
|
37
|
+
# for a small buffer around the timeline to make sure the schedule doesn't get stale.
|
|
38
|
+
# 00:00:15 was selected as the schedule queue used in the microservice has round robin array
|
|
39
|
+
# with 15 slots to make sure we don't miss a planned task.
|
|
40
|
+
# @return [Array|nil] Array of the next hour in the sorted set
|
|
41
|
+
def self.activities(name:, scope:)
|
|
42
|
+
now = Time.now.to_i
|
|
43
|
+
start_score = now - 15
|
|
44
|
+
stop_score = (now + 3660)
|
|
45
|
+
array = Store.zrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", start_score, stop_score)
|
|
46
|
+
ret_array = Array.new
|
|
47
|
+
array.each do |value|
|
|
48
|
+
ret_array << ActivityModel.from_json(value, name: name, scope: scope)
|
|
49
|
+
end
|
|
50
|
+
return ret_array
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [Array|nil] Array up to 100 of this model or empty array if name not found under primary_key
|
|
54
|
+
def self.get(name:, start:, stop:, scope:, limit: 100)
|
|
55
|
+
if start > stop
|
|
56
|
+
raise ActivityInputError.new "start: #{start} must be before stop: #{stop}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
array = Store.zrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", start, stop, :limit => [0, limit])
|
|
60
|
+
ret_array = Array.new
|
|
61
|
+
array.each do |value|
|
|
62
|
+
ret_array << JSON.parse(value, :allow_nan => true, :create_additions => true)
|
|
63
|
+
end
|
|
64
|
+
return ret_array
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [Array<Hash>] Array up to the limit of the models (as Hash objects) stored under the primary key
|
|
68
|
+
def self.all(name:, scope:, limit: 100)
|
|
69
|
+
array = Store.zrange("#{scope}#{PRIMARY_KEY}__#{name}", 0, -1, :limit => [0, limit])
|
|
70
|
+
ret_array = Array.new
|
|
71
|
+
array.each do |value|
|
|
72
|
+
ret_array << JSON.parse(value, :allow_nan => true, :create_additions => true)
|
|
73
|
+
end
|
|
74
|
+
return ret_array
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @return [String|nil] String of the saved json or nil if score not found under primary_key
|
|
78
|
+
def self.score(name:, score:, scope:)
|
|
79
|
+
array = Store.zrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", score, score, :limit => [0, 1])
|
|
80
|
+
array.each do |value|
|
|
81
|
+
return ActivityModel.from_json(value, name: name, scope: scope)
|
|
82
|
+
end
|
|
83
|
+
return nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [Integer] count of the members stored under the primary key
|
|
87
|
+
def self.count(name:, scope:)
|
|
88
|
+
return Store.zcard("#{scope}#{PRIMARY_KEY}__#{name}")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Remove one member from a sorted set.
|
|
92
|
+
# @return [Integer] count of the members removed
|
|
93
|
+
def self.destroy(name:, scope:, score:)
|
|
94
|
+
Store.zremrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", score, score)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Remove members from min to max of the sorted set.
|
|
98
|
+
# @return [Integer] count of the members removed
|
|
99
|
+
def self.range_destroy(name:, scope:, min:, max:)
|
|
100
|
+
Store.zremrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", min, max)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @return [ActivityModel] Model generated from the passed JSON
|
|
104
|
+
def self.from_json(json, name:, scope:)
|
|
105
|
+
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
|
106
|
+
raise "json data is nil" if json.nil?
|
|
107
|
+
|
|
108
|
+
json.transform_keys!(&:to_sym)
|
|
109
|
+
self.new(**json, name: name, scope: scope)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
attr_reader :duration, :start, :stop, :kind, :data, :events, :fulfillment
|
|
113
|
+
|
|
114
|
+
def initialize(
|
|
115
|
+
name:,
|
|
116
|
+
start:,
|
|
117
|
+
stop:,
|
|
118
|
+
kind:,
|
|
119
|
+
data:,
|
|
120
|
+
scope:,
|
|
121
|
+
updated_at: 0,
|
|
122
|
+
duration: 0,
|
|
123
|
+
fulfillment: nil,
|
|
124
|
+
events: nil
|
|
125
|
+
)
|
|
126
|
+
super("#{scope}#{PRIMARY_KEY}__#{name}", name: name, scope: scope)
|
|
127
|
+
set_input(
|
|
128
|
+
fulfillment: fulfillment,
|
|
129
|
+
start: start,
|
|
130
|
+
stop: stop,
|
|
131
|
+
kind: kind,
|
|
132
|
+
data: data,
|
|
133
|
+
events: events,
|
|
134
|
+
)
|
|
135
|
+
@updated_at = updated_at
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# validate_time will be called on create this will pull the time up to MAX_DURATION of an activity
|
|
139
|
+
# this will make sure that the activity is the only activity on the timeline for the duration of the
|
|
140
|
+
# activity. Score is the Seconds since the Unix Epoch: (%s) Number of seconds since 1970-01-01 00:00:00 UTC.
|
|
141
|
+
# We then search back from the stop of the activity and check to see if any activities are in the
|
|
142
|
+
# last x seconds (MAX_DURATION), if the zrange rev byscore finds activites from in reverse order so the
|
|
143
|
+
# first task is the closest task to the current score. In this a parameter ignore_score allows the request
|
|
144
|
+
# to ignore that time and skip to the next time but if nothing is found in the time range we can return nil.
|
|
145
|
+
#
|
|
146
|
+
# @param [Integer] ignore_score - should be nil unless you want to ignore a time when doing an update
|
|
147
|
+
def validate_time(ignore_score = nil)
|
|
148
|
+
max_score = @start - MAX_DURATION
|
|
149
|
+
array = Store.zrevrangebyscore(@primary_key, @stop, max_score)
|
|
150
|
+
array.each do |value|
|
|
151
|
+
activity = JSON.parse(value, :allow_nan => true, :create_additions => true)
|
|
152
|
+
if ignore_score == activity['start']
|
|
153
|
+
next
|
|
154
|
+
elsif activity['stop'] > @start
|
|
155
|
+
return activity['start']
|
|
156
|
+
else
|
|
157
|
+
return nil
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
return nil
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# validate the input to the rules we have created for timelines.
|
|
164
|
+
# - A task's start MUST NOT be in the past.
|
|
165
|
+
# - A task's start MUST be before the stop.
|
|
166
|
+
# - A task CAN NOT be longer than MAX_DURATION (86400) in seconds.
|
|
167
|
+
# - A task MUST have a kind.
|
|
168
|
+
# - A task MUST have a data object/hash.
|
|
169
|
+
def validate_input(start:, stop:, kind:, data:)
|
|
170
|
+
begin
|
|
171
|
+
DateTime.strptime(start.to_s, '%s')
|
|
172
|
+
DateTime.strptime(stop.to_s, '%s')
|
|
173
|
+
rescue Date::Error
|
|
174
|
+
raise ActivityInputError.new "failed validation input must be seconds: #{start}, #{stop}"
|
|
175
|
+
end
|
|
176
|
+
now_i = Time.now.to_i + 10
|
|
177
|
+
duration = stop - start
|
|
178
|
+
if now_i >= start
|
|
179
|
+
raise ActivityInputError.new "activity must be in the future, current_time: #{now_i} vs #{start}"
|
|
180
|
+
elsif duration >= MAX_DURATION
|
|
181
|
+
raise ActivityInputError.new "activity can not be longer than #{MAX_DURATION} seconds"
|
|
182
|
+
elsif duration <= 0
|
|
183
|
+
raise ActivityInputError.new "start: #{start} must be before stop: #{stop}"
|
|
184
|
+
elsif kind.nil?
|
|
185
|
+
raise ActivityInputError.new "kind must not be nil: #{kind}"
|
|
186
|
+
elsif data.nil?
|
|
187
|
+
raise ActivityInputError.new "data must not be nil: #{data}"
|
|
188
|
+
elsif data.is_a?(Hash) == false
|
|
189
|
+
raise ActivityInputError.new "data must be a json object/hash: #{data}"
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Set the values of the instance, @start, @kind, @data, @events...
|
|
194
|
+
def set_input(start:, stop:, kind: nil, data: nil, events: nil, fulfillment: nil)
|
|
195
|
+
begin
|
|
196
|
+
DateTime.strptime(start.to_s, '%s')
|
|
197
|
+
DateTime.strptime(stop.to_s, '%s')
|
|
198
|
+
rescue ArgumentError
|
|
199
|
+
raise ActivityInputError.new "invalid input must be seconds: #{start}, #{stop}"
|
|
200
|
+
end
|
|
201
|
+
@start = start
|
|
202
|
+
@stop = stop
|
|
203
|
+
@duration = @stop - @start
|
|
204
|
+
@fulfillment = fulfillment.nil? ? false : fulfillment
|
|
205
|
+
@kind = kind.nil? ? @kind : kind
|
|
206
|
+
@data = data.nil? ? @data : data
|
|
207
|
+
@events = events.nil? ? Array.new : events
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Update the Redis hash at primary_key and set the score equal to the start Epoch time
|
|
211
|
+
# the member is set to the JSON generated via calling as_json
|
|
212
|
+
def create
|
|
213
|
+
validate_input(start: @start, stop: @stop, kind: @kind, data: @data)
|
|
214
|
+
collision = validate_time()
|
|
215
|
+
unless collision.nil?
|
|
216
|
+
raise ActivityOverlapError.new "no activities can overlap, collision: #{collision}"
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
@updated_at = Time.now.to_nsec_from_epoch
|
|
220
|
+
add_event(status: 'created')
|
|
221
|
+
Store.zadd(@primary_key, @start, JSON.generate(self.as_json(:allow_nan => true)))
|
|
222
|
+
notify(kind: 'created')
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Update the Redis hash at primary_key and remove the current activity at the current score
|
|
226
|
+
# and update the score to the new score equal to the start Epoch time this uses a multi
|
|
227
|
+
# to execute both the remove and create. The member via the JSON generated via calling as_json
|
|
228
|
+
def update(start:, stop:, kind:, data:)
|
|
229
|
+
array = Store.zrangebyscore(@primary_key, @start, @start)
|
|
230
|
+
if array.length == 0
|
|
231
|
+
raise ActivityError.new "failed to find activity at: #{@start}"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
validate_input(start: start, stop: stop, kind: kind, data: data)
|
|
235
|
+
old_start = @start
|
|
236
|
+
set_input(start: start, stop: stop, kind: kind, data: data, events: @events)
|
|
237
|
+
@updated_at = Time.now.to_nsec_from_epoch
|
|
238
|
+
# copy of create
|
|
239
|
+
collision = validate_time(old_start)
|
|
240
|
+
unless collision.nil?
|
|
241
|
+
raise ActivityOverlapError.new "failed to update #{old_start}, no activities can overlap, collision: #{collision}"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
add_event(status: 'updated')
|
|
245
|
+
Store.multi do |multi|
|
|
246
|
+
multi.zremrangebyscore(@primary_key, old_start, old_start)
|
|
247
|
+
multi.zadd(@primary_key, @start, JSON.generate(self.as_json(:allow_nan => true)))
|
|
248
|
+
end
|
|
249
|
+
notify(kind: 'updated', extra: old_start)
|
|
250
|
+
return @start
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# commit will make an event and save the object to the redis database
|
|
254
|
+
# @param [String] status - the event status such as "complete" or "failed"
|
|
255
|
+
# @param [String] message - an optional message to include in the event
|
|
256
|
+
def commit(status:, message: nil, fulfillment: nil)
|
|
257
|
+
event = {
|
|
258
|
+
'time' => Time.now.to_i,
|
|
259
|
+
'event' => status,
|
|
260
|
+
'commit' => true
|
|
261
|
+
}
|
|
262
|
+
event['message'] = message unless message.nil?
|
|
263
|
+
@fulfillment = fulfillment.nil? ? @fulfillment : fulfillment
|
|
264
|
+
@events << event
|
|
265
|
+
Store.multi do |multi|
|
|
266
|
+
multi.zremrangebyscore(@primary_key, @start, @start)
|
|
267
|
+
multi.zadd(@primary_key, @start, JSON.generate(self.as_json(:allow_nan => true)))
|
|
268
|
+
end
|
|
269
|
+
notify(kind: 'event')
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# add_event will make an event. This will NOT save the object to the redis database
|
|
273
|
+
# @param [String] status - the event status such as "queued" or "updated" or "created"
|
|
274
|
+
def add_event(status:)
|
|
275
|
+
event = {
|
|
276
|
+
'time' => Time.now.to_i,
|
|
277
|
+
'event' => status
|
|
278
|
+
}
|
|
279
|
+
@events << event
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# destroy the activity from the redis database
|
|
283
|
+
def destroy
|
|
284
|
+
Store.zremrangebyscore(@primary_key, @start, @start)
|
|
285
|
+
notify(kind: 'deleted')
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# @return [] update the redis stream / timeline topic that something has changed
|
|
289
|
+
def notify(kind:, extra: nil)
|
|
290
|
+
notification = {
|
|
291
|
+
'data' => JSON.generate(as_json(:allow_nan => true)),
|
|
292
|
+
'kind' => kind,
|
|
293
|
+
'type' => 'activity',
|
|
294
|
+
'timeline' => @name
|
|
295
|
+
}
|
|
296
|
+
notification['extra'] = extra unless extra.nil?
|
|
297
|
+
begin
|
|
298
|
+
TimelineTopic.write_activity(notification, scope: @scope)
|
|
299
|
+
rescue StandardError => e
|
|
300
|
+
raise ActivityError.new "Failed to write to stream: #{notification}, #{e}"
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# @return [Hash] generated from the ActivityModel
|
|
305
|
+
def as_json(*a)
|
|
306
|
+
{
|
|
307
|
+
'name' => @name,
|
|
308
|
+
'updated_at' => @updated_at,
|
|
309
|
+
'fulfillment' => @fulfillment,
|
|
310
|
+
'duration' => @duration,
|
|
311
|
+
'start' => @start,
|
|
312
|
+
'stop' => @stop,
|
|
313
|
+
'kind' => @kind,
|
|
314
|
+
'events' => @events,
|
|
315
|
+
'data' => @data.as_json(*a)
|
|
316
|
+
}
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
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 'digest'
|
|
21
|
+
require 'openc3/utilities/store'
|
|
22
|
+
|
|
23
|
+
module OpenC3
|
|
24
|
+
class AuthModel
|
|
25
|
+
PRIMARY_KEY = 'OPENC3__TOKEN'
|
|
26
|
+
SERVICE_KEY = 'OPENC3__SERVICE__TOKEN'
|
|
27
|
+
|
|
28
|
+
def self.is_set?(key = PRIMARY_KEY)
|
|
29
|
+
Store.exists(key) == 1
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.verify(token, permission: nil)
|
|
33
|
+
return false if token.nil? or token.empty?
|
|
34
|
+
|
|
35
|
+
token_hash = hash(token)
|
|
36
|
+
return true if Store.get(PRIMARY_KEY) == token_hash
|
|
37
|
+
|
|
38
|
+
service_hash = Store.get(SERVICE_KEY)
|
|
39
|
+
if ENV['OPENC3_SERVICE_PASSWORD'] and hash(ENV['OPENC3_SERVICE_PASSWORD']) != service_hash
|
|
40
|
+
set_hash = hash(ENV['OPENC3_SERVICE_PASSWORD'])
|
|
41
|
+
OpenC3::Store.set(SERVICE_KEY, set_hash)
|
|
42
|
+
service_hash = set_hash
|
|
43
|
+
end
|
|
44
|
+
return true if service_hash == token_hash and permission != 'admin'
|
|
45
|
+
|
|
46
|
+
return false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.set(token, old_token, key = PRIMARY_KEY)
|
|
50
|
+
raise "token must not be nil or empty" if token.nil? or token.empty?
|
|
51
|
+
|
|
52
|
+
if is_set?(key)
|
|
53
|
+
raise "old_token must not be nil or empty" if old_token.nil? or old_token.empty?
|
|
54
|
+
raise "old_token incorrect" unless verify(old_token)
|
|
55
|
+
end
|
|
56
|
+
Store.set(key, hash(token))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def self.hash(token)
|
|
62
|
+
Digest::SHA2.hexdigest token
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
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/utilities/store'
|
|
21
|
+
|
|
22
|
+
module OpenC3
|
|
23
|
+
class CvtModel
|
|
24
|
+
VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED, :WITH_UNITS]
|
|
25
|
+
# Stores telemetry item overrides which are returned on every request to get_item
|
|
26
|
+
@overrides = {}
|
|
27
|
+
|
|
28
|
+
def self.build_json_from_packet(packet)
|
|
29
|
+
json_hash = {}
|
|
30
|
+
packet.sorted_items.each do |item|
|
|
31
|
+
json_hash[item.name] = packet.read_item(item, :RAW)
|
|
32
|
+
json_hash["#{item.name}__C"] = packet.read_item(item, :CONVERTED) if item.read_conversion or item.states
|
|
33
|
+
json_hash["#{item.name}__F"] = packet.read_item(item, :FORMATTED) if item.format_string
|
|
34
|
+
json_hash["#{item.name}__U"] = packet.read_item(item, :WITH_UNITS) if item.units
|
|
35
|
+
limits_state = item.limits.state
|
|
36
|
+
json_hash["#{item.name}__L"] = limits_state if limits_state
|
|
37
|
+
end
|
|
38
|
+
json_hash
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Delete the current value table for a target
|
|
42
|
+
def self.del(target_name:, packet_name:, scope:)
|
|
43
|
+
EphemeralStore.hdel("#{scope}__tlm__#{target_name}", packet_name)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Set the current value table for a target, packet
|
|
47
|
+
def self.set(hash, target_name:, packet_name:, scope:)
|
|
48
|
+
EphemeralStore.hset("#{scope}__tlm__#{target_name}", packet_name, JSON.generate(hash.as_json(:allow_nan => true)))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Set an item in the current value table
|
|
52
|
+
def self.set_item(target_name, packet_name, item_name, value, type:, scope:)
|
|
53
|
+
case type
|
|
54
|
+
when :WITH_UNITS
|
|
55
|
+
field = "#{item_name}__U"
|
|
56
|
+
when :FORMATTED
|
|
57
|
+
field = "#{item_name}__F"
|
|
58
|
+
when :CONVERTED
|
|
59
|
+
field = "#{item_name}__C"
|
|
60
|
+
when :RAW
|
|
61
|
+
field = item_name
|
|
62
|
+
else
|
|
63
|
+
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
|
64
|
+
end
|
|
65
|
+
hash = JSON.parse(EphemeralStore.hget("#{scope}__tlm__#{target_name}", packet_name), :allow_nan => true, :create_additions => true)
|
|
66
|
+
hash[field] = value
|
|
67
|
+
EphemeralStore.hset("#{scope}__tlm__#{target_name}", packet_name, JSON.generate(hash.as_json(:allow_nan => true)))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Get an item from the current value table
|
|
71
|
+
def self.get_item(target_name, packet_name, item_name, type:, scope:)
|
|
72
|
+
if @overrides["#{target_name}__#{packet_name}__#{item_name}__#{type}"]
|
|
73
|
+
return @overrides["#{target_name}__#{packet_name}__#{item_name}__#{type}"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
types = []
|
|
77
|
+
case type
|
|
78
|
+
when :WITH_UNITS
|
|
79
|
+
types = ["#{item_name}__U", "#{item_name}__F", "#{item_name}__C", item_name]
|
|
80
|
+
when :FORMATTED
|
|
81
|
+
types = ["#{item_name}__F", "#{item_name}__C", item_name]
|
|
82
|
+
when :CONVERTED
|
|
83
|
+
types = ["#{item_name}__C", item_name]
|
|
84
|
+
when :RAW
|
|
85
|
+
types = [item_name]
|
|
86
|
+
else
|
|
87
|
+
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
|
88
|
+
end
|
|
89
|
+
hash = JSON.parse(EphemeralStore.hget("#{scope}__tlm__#{target_name}", packet_name), :allow_nan => true, :create_additions => true)
|
|
90
|
+
hash.values_at(*types).each do |result|
|
|
91
|
+
return result if result
|
|
92
|
+
end
|
|
93
|
+
return nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Return all item values and limit state from the CVT
|
|
97
|
+
#
|
|
98
|
+
# @param items [Array<String>] Items to return. Must be formatted as TGT__PKT__ITEM__TYPE
|
|
99
|
+
# @return [Array] Array of values
|
|
100
|
+
def self.get_tlm_values(items, scope: $openc3_scope)
|
|
101
|
+
results = []
|
|
102
|
+
lookups = []
|
|
103
|
+
packet_lookup = {}
|
|
104
|
+
# First generate a lookup hash of all the items represented so we can query the CVT
|
|
105
|
+
items.each { |item| _parse_item(lookups, item) }
|
|
106
|
+
|
|
107
|
+
lookups.each do |target_packet_key, target_name, packet_name, packet_values|
|
|
108
|
+
unless packet_lookup[target_packet_key]
|
|
109
|
+
packet = EphemeralStore.hget("#{scope}__tlm__#{target_name}", packet_name)
|
|
110
|
+
raise "Packet '#{target_name} #{packet_name}' does not exist" unless packet
|
|
111
|
+
packet_lookup[target_packet_key] = JSON.parse(packet, :allow_nan => true, :create_additions => true)
|
|
112
|
+
end
|
|
113
|
+
hash = packet_lookup[target_packet_key]
|
|
114
|
+
item_result = []
|
|
115
|
+
packet_values.each do |value|
|
|
116
|
+
item_result[0] = hash[value]
|
|
117
|
+
break if item_result[0] # We want the first value
|
|
118
|
+
end
|
|
119
|
+
# If we were able to find a value, try to get the limits state
|
|
120
|
+
if item_result[0]
|
|
121
|
+
# The last key is simply the name (RAW) so we can append __L
|
|
122
|
+
# If there is no limits then it returns nil which is acceptable
|
|
123
|
+
item_result[1] = hash["#{packet_values[-1]}__L"]
|
|
124
|
+
item_result[1] = item_result[1].intern if item_result[1] # Convert to symbol
|
|
125
|
+
else
|
|
126
|
+
raise "Item '#{target_name} #{packet_name} #{packet_values[-1]}' does not exist" unless hash.key?(packet_values[-1])
|
|
127
|
+
item_result[1] = nil
|
|
128
|
+
end
|
|
129
|
+
results << item_result
|
|
130
|
+
end
|
|
131
|
+
results
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Override a current value table item such that it always returns the same value
|
|
135
|
+
# for the given type
|
|
136
|
+
def self.override(target_name, packet_name, item_name, value, type:, scope: $openc3_scope)
|
|
137
|
+
if VALUE_TYPES.include?(type)
|
|
138
|
+
@overrides["#{target_name}__#{packet_name}__#{item_name}__#{type}"] = value
|
|
139
|
+
else
|
|
140
|
+
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Normalize a current value table item such that it returns the actual value
|
|
145
|
+
def self.normalize(target_name, packet_name, item_name, type: :ALL, scope: $openc3_scope)
|
|
146
|
+
if type == :ALL
|
|
147
|
+
VALUE_TYPES.each do |type|
|
|
148
|
+
@overrides.delete("#{target_name}__#{packet_name}__#{item_name}__#{type}")
|
|
149
|
+
end
|
|
150
|
+
else
|
|
151
|
+
if VALUE_TYPES.include?(type)
|
|
152
|
+
@overrides.delete("#{target_name}__#{packet_name}__#{item_name}__#{type}")
|
|
153
|
+
else
|
|
154
|
+
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# PRIVATE METHODS
|
|
160
|
+
|
|
161
|
+
def self._parse_item(lookups, item)
|
|
162
|
+
# parse item and update lookups with packet_name and target_name and keys
|
|
163
|
+
#
|
|
164
|
+
# return an ordered array of hash with keys
|
|
165
|
+
target_name, packet_name, item_name, value_type = item.split('__')
|
|
166
|
+
raise ArgumentError, "items must be formatted as TGT__PKT__ITEM__TYPE" if target_name.nil? || packet_name.nil? || item_name.nil? || value_type.nil?
|
|
167
|
+
|
|
168
|
+
# We build lookup keys by including all the less formatted types to gracefully degrade lookups
|
|
169
|
+
# This allows the user to specify WITH_UNITS and if there is no conversions it will simply return the RAW value
|
|
170
|
+
case value_type.upcase
|
|
171
|
+
when 'RAW'
|
|
172
|
+
keys = [item_name]
|
|
173
|
+
when 'CONVERTED'
|
|
174
|
+
keys = ["#{item_name}__C", item_name]
|
|
175
|
+
when 'FORMATTED'
|
|
176
|
+
keys = ["#{item_name}__F", "#{item_name}__C", item_name]
|
|
177
|
+
when 'WITH_UNITS'
|
|
178
|
+
keys = ["#{item_name}__U", "#{item_name}__F", "#{item_name}__C", item_name]
|
|
179
|
+
else
|
|
180
|
+
raise "Unknown value type #{value_type}"
|
|
181
|
+
end
|
|
182
|
+
lookups << ["#{target_name}__#{packet_name}", target_name, packet_name, keys]
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
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/models/model'
|
|
21
|
+
|
|
22
|
+
module OpenC3
|
|
23
|
+
|
|
24
|
+
class EnvironmentError < StandardError; end
|
|
25
|
+
|
|
26
|
+
class EnvironmentModel < Model
|
|
27
|
+
PRIMARY_KEY = '__openc3__environment'.freeze
|
|
28
|
+
|
|
29
|
+
# NOTE: The following three class methods are used by the ModelController
|
|
30
|
+
# and are reimplemented to enable various Model class methods to work
|
|
31
|
+
def self.get(name:, scope:)
|
|
32
|
+
super("#{scope}#{PRIMARY_KEY}", name: name)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.all(scope:)
|
|
36
|
+
super("#{scope}#{PRIMARY_KEY}")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.destroy(scope:, name:)
|
|
40
|
+
Store.hdel("#{scope}#{PRIMARY_KEY}", name)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def initialize(name:, scope:, key:, value:)
|
|
44
|
+
super("#{scope}#{PRIMARY_KEY}", name: name, scope: scope)
|
|
45
|
+
@key = key
|
|
46
|
+
@value = value
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def as_json(*a)
|
|
50
|
+
{
|
|
51
|
+
'name' => @name,
|
|
52
|
+
'updated_at' => @updated_at,
|
|
53
|
+
'key' => @key,
|
|
54
|
+
'value' => @value
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|