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,1168 @@
|
|
|
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/packets/structure'
|
|
22
|
+
require 'openc3/packets/packet_item'
|
|
23
|
+
require 'openc3/ext/packet' if RUBY_ENGINE == 'ruby' and !ENV['OPENC3_NO_EXT']
|
|
24
|
+
|
|
25
|
+
module OpenC3
|
|
26
|
+
# Adds features common to all OpenC3 packets of data to the Structure class.
|
|
27
|
+
# This includes the additional attributes listed below. The primary behavior
|
|
28
|
+
# Packet adds is the ability to apply formatting to PacketItem values as well
|
|
29
|
+
# as managing PacketItem's limit states.
|
|
30
|
+
class Packet < Structure
|
|
31
|
+
RESERVED_ITEM_NAMES = ['PACKET_TIMESECONDS'.freeze, 'PACKET_TIMEFORMATTED'.freeze, 'RECEIVED_TIMESECONDS'.freeze, 'RECEIVED_TIMEFORMATTED'.freeze, 'RECEIVED_COUNT'.freeze]
|
|
32
|
+
CATCH_ALL_STATE = 'ANY'
|
|
33
|
+
|
|
34
|
+
# @return [String] Name of the target this packet is associated with
|
|
35
|
+
attr_reader :target_name
|
|
36
|
+
|
|
37
|
+
# @return [String] Name of the packet
|
|
38
|
+
attr_reader :packet_name
|
|
39
|
+
|
|
40
|
+
# @return [String] Description of the packet
|
|
41
|
+
attr_reader :description
|
|
42
|
+
|
|
43
|
+
# @return [Time] Time at which the packet was received
|
|
44
|
+
attr_reader :received_time
|
|
45
|
+
|
|
46
|
+
# @return [Integer] Number of times the packet has been received
|
|
47
|
+
attr_reader :received_count
|
|
48
|
+
|
|
49
|
+
# @return [Boolean] Flag indicating if the packet is hazardous (typically for commands)
|
|
50
|
+
attr_accessor :hazardous
|
|
51
|
+
|
|
52
|
+
# @return [String] Description of why the packet is hazardous
|
|
53
|
+
attr_reader :hazardous_description
|
|
54
|
+
|
|
55
|
+
# Contains the values given by the user for a command (distinguished from defaults)
|
|
56
|
+
# These values should be used within command conversions if present because the order
|
|
57
|
+
# that values are written into the actual packet can vary
|
|
58
|
+
# @return [Hash<Item Name, Value>] Given values when constructing the packet
|
|
59
|
+
attr_reader :given_values
|
|
60
|
+
|
|
61
|
+
# @return [Boolean] Flag indicating if the packet is stale (hasn't been received recently)
|
|
62
|
+
attr_reader :stale
|
|
63
|
+
|
|
64
|
+
# @return [Boolean] Whether or not this is a 'raw' packet
|
|
65
|
+
attr_accessor :raw
|
|
66
|
+
|
|
67
|
+
# @return [Boolean] Whether or not this is a 'hidden' packet
|
|
68
|
+
attr_accessor :hidden
|
|
69
|
+
|
|
70
|
+
# @return [Boolean] Whether or not this is a 'disabled' packet
|
|
71
|
+
attr_accessor :disabled
|
|
72
|
+
|
|
73
|
+
# @return [Boolean] Whether or not messages should be printed for this packet
|
|
74
|
+
attr_accessor :messages_disabled
|
|
75
|
+
|
|
76
|
+
# @return [Boolean] Whether or not this is a 'abstract' packet
|
|
77
|
+
attr_accessor :abstract
|
|
78
|
+
|
|
79
|
+
# @return [Boolean] Whether or not this was a stored packet
|
|
80
|
+
attr_accessor :stored
|
|
81
|
+
|
|
82
|
+
# @return [Hash] Extra data to be logged/transferred with packet
|
|
83
|
+
attr_accessor :extra
|
|
84
|
+
|
|
85
|
+
# @return [Symbol] :CMD or :TLM
|
|
86
|
+
attr_accessor :cmd_or_tlm
|
|
87
|
+
|
|
88
|
+
# Valid format types
|
|
89
|
+
VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED, :WITH_UNITS]
|
|
90
|
+
|
|
91
|
+
if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
|
|
92
|
+
# Creates a new packet by initalizing the attributes.
|
|
93
|
+
#
|
|
94
|
+
# @param target_name [String] Name of the target this packet is associated with
|
|
95
|
+
# @param packet_name [String] Name of the packet
|
|
96
|
+
# @param default_endianness [Symbol] One of {BinaryAccessor::ENDIANNESS}
|
|
97
|
+
# @param description [String] Description of the packet
|
|
98
|
+
# @param buffer [String] String buffer to hold the packet data
|
|
99
|
+
# @param item_class [Class] Class used to instantiate items (Must be a
|
|
100
|
+
# subclass of PacketItem)
|
|
101
|
+
def initialize(target_name, packet_name, default_endianness = :BIG_ENDIAN, description = nil, buffer = nil, item_class = PacketItem)
|
|
102
|
+
super(default_endianness, buffer, item_class)
|
|
103
|
+
# Explictly call the defined setter methods
|
|
104
|
+
self.target_name = target_name
|
|
105
|
+
self.packet_name = packet_name
|
|
106
|
+
self.description = description
|
|
107
|
+
self.received_time = nil
|
|
108
|
+
self.received_count = 0
|
|
109
|
+
@id_items = nil
|
|
110
|
+
@hazardous = false
|
|
111
|
+
@hazardous_description = nil
|
|
112
|
+
@given_values = nil
|
|
113
|
+
@limits_items = nil
|
|
114
|
+
@processors = nil
|
|
115
|
+
@stale = true
|
|
116
|
+
@limits_change_callback = nil
|
|
117
|
+
@read_conversion_cache = nil
|
|
118
|
+
@raw = nil
|
|
119
|
+
@messages_disabled = false
|
|
120
|
+
@meta = nil
|
|
121
|
+
@hidden = false
|
|
122
|
+
@disabled = false
|
|
123
|
+
@stored = false
|
|
124
|
+
@extra = nil
|
|
125
|
+
@cmd_or_tlm = nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Sets the target name this packet is associated with. Unidentified packets
|
|
129
|
+
# will have target name set to nil.
|
|
130
|
+
#
|
|
131
|
+
# @param target_name [String] Name of the target this packet is associated with
|
|
132
|
+
def target_name=(target_name)
|
|
133
|
+
if target_name
|
|
134
|
+
if !(String === target_name)
|
|
135
|
+
raise(ArgumentError, "target_name must be a String but is a #{target_name.class}")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
@target_name = target_name.upcase.freeze
|
|
139
|
+
else
|
|
140
|
+
@target_name = nil
|
|
141
|
+
end
|
|
142
|
+
@target_name
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Sets the packet name. Unidentified packets will have packet name set to
|
|
146
|
+
# nil.
|
|
147
|
+
#
|
|
148
|
+
# @param packet_name [String] Name of the packet
|
|
149
|
+
def packet_name=(packet_name)
|
|
150
|
+
if packet_name
|
|
151
|
+
if !(String === packet_name)
|
|
152
|
+
raise(ArgumentError, "packet_name must be a String but is a #{packet_name.class}")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
@packet_name = packet_name.upcase.freeze
|
|
156
|
+
else
|
|
157
|
+
@packet_name = nil
|
|
158
|
+
end
|
|
159
|
+
@packet_name
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Sets the description of the packet
|
|
163
|
+
#
|
|
164
|
+
# @param description [String] Description of the packet
|
|
165
|
+
def description=(description)
|
|
166
|
+
if description
|
|
167
|
+
if !(String === description)
|
|
168
|
+
raise(ArgumentError, "description must be a String but is a #{description.class}")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
@description = description.to_utf8.freeze
|
|
172
|
+
else
|
|
173
|
+
@description = nil
|
|
174
|
+
end
|
|
175
|
+
@description
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Sets the received time of the packet
|
|
179
|
+
#
|
|
180
|
+
# @param received_time [Time] Time this packet was received
|
|
181
|
+
def received_time=(received_time)
|
|
182
|
+
if received_time
|
|
183
|
+
if !(Time === received_time)
|
|
184
|
+
raise(ArgumentError, "received_time must be a Time but is a #{received_time.class}")
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
@received_time = received_time.clone.freeze
|
|
188
|
+
else
|
|
189
|
+
@received_time = nil
|
|
190
|
+
end
|
|
191
|
+
@read_conversion_cache.clear if @read_conversion_cache
|
|
192
|
+
@received_time
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Sets the received count of the packet
|
|
196
|
+
#
|
|
197
|
+
# @param received_count [Integer] Number of times this packet has been
|
|
198
|
+
# received
|
|
199
|
+
def received_count=(received_count)
|
|
200
|
+
if !(Integer === received_count)
|
|
201
|
+
raise(ArgumentError, "received_count must be an Integer but is a #{received_count.class}")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
@received_count = received_count
|
|
205
|
+
@read_conversion_cache.clear if @read_conversion_cache
|
|
206
|
+
@received_count
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
end # if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
|
|
210
|
+
|
|
211
|
+
# Tries to identify if a buffer represents the currently defined packet. It
|
|
212
|
+
# does this by iterating over all the packet items that were created with
|
|
213
|
+
# an ID value and checking whether that ID value is present at the correct
|
|
214
|
+
# location in the buffer.
|
|
215
|
+
#
|
|
216
|
+
# Incorrectly sized buffers will still positively identify if there is
|
|
217
|
+
# enough data to match the ID values. This is to allow incorrectly sized
|
|
218
|
+
# packets to still be processed as well as possible given the incorrectly
|
|
219
|
+
# sized data.
|
|
220
|
+
#
|
|
221
|
+
# @param buffer [String] Raw buffer of binary data
|
|
222
|
+
# @return [Boolean] Whether or not the buffer of data is this packet
|
|
223
|
+
def identify?(buffer)
|
|
224
|
+
return false unless buffer
|
|
225
|
+
return true unless @id_items
|
|
226
|
+
|
|
227
|
+
@id_items.each do |item|
|
|
228
|
+
begin
|
|
229
|
+
value = read_item(item, :RAW, buffer)
|
|
230
|
+
rescue Exception
|
|
231
|
+
value = nil
|
|
232
|
+
end
|
|
233
|
+
return false if item.id_value != value
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
true
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Reads the values from a buffer at the position of each id_item defined
|
|
240
|
+
# in the packet.
|
|
241
|
+
#
|
|
242
|
+
# @param buffer [String] Raw buffer of binary data
|
|
243
|
+
# @return [Array] Array of read id values in order
|
|
244
|
+
def read_id_values(buffer)
|
|
245
|
+
return [] unless buffer
|
|
246
|
+
return [] unless @id_items
|
|
247
|
+
|
|
248
|
+
values = []
|
|
249
|
+
|
|
250
|
+
@id_items.each do |item|
|
|
251
|
+
values << read_item(item, :RAW, buffer)
|
|
252
|
+
rescue Exception
|
|
253
|
+
values << nil
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
values
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Returns @received_time unless a packet item called PACKET_TIME exists that returns
|
|
260
|
+
# a Ruby Time object that represents a different timestamp for the packet
|
|
261
|
+
def packet_time
|
|
262
|
+
item = @items['PACKET_TIME'.freeze]
|
|
263
|
+
if item
|
|
264
|
+
return read_item(item, :CONVERTED, @buffer)
|
|
265
|
+
else
|
|
266
|
+
return @received_time
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Calculates a unique hashing sum that changes if the parts of the packet configuration change that could affect
|
|
271
|
+
# the "shape" of the packet. This value is cached and that packet should not be changed if this method is being used
|
|
272
|
+
def config_name
|
|
273
|
+
return @config_name if @config_name
|
|
274
|
+
|
|
275
|
+
string = "#{@target_name} #{@packet_name}"
|
|
276
|
+
@sorted_items.each do |item|
|
|
277
|
+
string << " ITEM #{item.name} #{item.bit_offset} #{item.bit_size} #{item.data_type} #{item.array_size} #{item.endianness} #{item.overflow} #{item.states} #{item.read_conversion ? item.read_conversion.class : 'NO_CONVERSION'}"
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Use the hashing algorithm established by OpenC3::System
|
|
281
|
+
digest = Digest::SHA256.new
|
|
282
|
+
digest << string
|
|
283
|
+
@config_name = digest.hexdigest
|
|
284
|
+
@config_name
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# (see Structure#buffer=)
|
|
288
|
+
def buffer=(buffer)
|
|
289
|
+
synchronize() do
|
|
290
|
+
begin
|
|
291
|
+
internal_buffer_equals(buffer)
|
|
292
|
+
rescue RuntimeError
|
|
293
|
+
Logger.instance.error "#{@target_name} #{@packet_name} received with actual packet length of #{buffer.length} but defined length of #{@defined_length}"
|
|
294
|
+
end
|
|
295
|
+
@read_conversion_cache.clear if @read_conversion_cache
|
|
296
|
+
process()
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Sets the received time of the packet (without cloning)
|
|
301
|
+
#
|
|
302
|
+
# @param received_time [Time] Time this packet was received
|
|
303
|
+
def set_received_time_fast(received_time)
|
|
304
|
+
@received_time = received_time
|
|
305
|
+
@received_time.freeze if @received_time
|
|
306
|
+
if @read_conversion_cache
|
|
307
|
+
synchronize() do
|
|
308
|
+
@read_conversion_cache.clear
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Sets the hazardous description of the packet
|
|
314
|
+
#
|
|
315
|
+
# @param hazardous_description [String] Hazardous description of the packet
|
|
316
|
+
def hazardous_description=(hazardous_description)
|
|
317
|
+
if hazardous_description
|
|
318
|
+
raise ArgumentError, "hazardous_description must be a String but is a #{hazardous_description.class}" unless String === hazardous_description
|
|
319
|
+
|
|
320
|
+
@hazardous_description = hazardous_description.to_utf8.freeze
|
|
321
|
+
else
|
|
322
|
+
@hazardous_description = nil
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Saves a hash of the values given by a user when constructing a command
|
|
327
|
+
#
|
|
328
|
+
# @param given_values [Hash<Item Name, Value>] Hash of given command parameters
|
|
329
|
+
def given_values=(given_values)
|
|
330
|
+
if given_values
|
|
331
|
+
raise ArgumentError, "given_values must be a Hash but is a #{given_values.class}" unless Hash === given_values
|
|
332
|
+
|
|
333
|
+
@given_values = given_values.clone
|
|
334
|
+
else
|
|
335
|
+
@given_values = nil
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Sets the callback object called when a limits state changes
|
|
340
|
+
#
|
|
341
|
+
# @param limits_change_callback [#call] Object must respond to the call
|
|
342
|
+
# method and take the following arguments: packet (Packet), item (PacketItem),
|
|
343
|
+
# old_limits_state (Symbol), item_value (Object), log_change (Boolean). The
|
|
344
|
+
# current item state can be found by querying the item object:
|
|
345
|
+
# item.limits.state.
|
|
346
|
+
def limits_change_callback=(limits_change_callback)
|
|
347
|
+
if limits_change_callback
|
|
348
|
+
raise ArgumentError, "limits_change_callback must respond to call" unless limits_change_callback.respond_to?(:call)
|
|
349
|
+
|
|
350
|
+
@limits_change_callback = limits_change_callback
|
|
351
|
+
else
|
|
352
|
+
@limits_change_callback = nil
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Review bit offset to look for overlapping definitions. This will allow
|
|
357
|
+
# gaps in the packet, but not allow the same bits to be used for multiple
|
|
358
|
+
# variables.
|
|
359
|
+
#
|
|
360
|
+
# @return [Array<String>] Warning messages for big definition overlaps
|
|
361
|
+
def check_bit_offsets
|
|
362
|
+
expected_next_offset = nil
|
|
363
|
+
previous_item = nil
|
|
364
|
+
warnings = []
|
|
365
|
+
@sorted_items.each do |item|
|
|
366
|
+
if expected_next_offset and (item.bit_offset < expected_next_offset) and !item.overlap
|
|
367
|
+
msg = "Bit definition overlap at bit offset #{item.bit_offset} for packet #{@target_name} #{@packet_name} items #{item.name} and #{previous_item.name}"
|
|
368
|
+
Logger.instance.warn(msg)
|
|
369
|
+
warnings << msg
|
|
370
|
+
end
|
|
371
|
+
expected_next_offset = Packet.next_bit_offset(item)
|
|
372
|
+
previous_item = item
|
|
373
|
+
end
|
|
374
|
+
warnings
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Checks if the packet has any gaps or overlapped items
|
|
378
|
+
#
|
|
379
|
+
# @return [Boolean] true if the packet has no gaps or overlapped items
|
|
380
|
+
def packed?
|
|
381
|
+
expected_next_offset = nil
|
|
382
|
+
@sorted_items.each do |item|
|
|
383
|
+
if expected_next_offset and item.bit_offset != expected_next_offset
|
|
384
|
+
return false
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
expected_next_offset = Packet.next_bit_offset(item)
|
|
388
|
+
end
|
|
389
|
+
true
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# Returns the bit offset of the next item after the current item if items are packed
|
|
393
|
+
#
|
|
394
|
+
# @param item [PacketItem] The item to calculate the next offset for
|
|
395
|
+
# @return [Integer] Bit Offset of Next Item if Packed
|
|
396
|
+
def self.next_bit_offset(item)
|
|
397
|
+
if item.array_size
|
|
398
|
+
if item.array_size > 0
|
|
399
|
+
next_offset = item.bit_offset + item.array_size
|
|
400
|
+
else
|
|
401
|
+
next_offset = item.array_size
|
|
402
|
+
end
|
|
403
|
+
else
|
|
404
|
+
next_offset = nil
|
|
405
|
+
if item.bit_offset > 0
|
|
406
|
+
if item.little_endian_bit_field?
|
|
407
|
+
# Bit offset always refers to the most significant bit of a bitfield
|
|
408
|
+
bits_remaining_in_last_byte = 8 - (item.bit_offset % 8)
|
|
409
|
+
if item.bit_size > bits_remaining_in_last_byte
|
|
410
|
+
next_offset = item.bit_offset + bits_remaining_in_last_byte
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
unless next_offset
|
|
415
|
+
if item.bit_size > 0
|
|
416
|
+
next_offset = item.bit_offset + item.bit_size
|
|
417
|
+
else
|
|
418
|
+
next_offset = item.bit_size
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
next_offset
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Id items are used by the identify? method to determine if a raw buffer of
|
|
426
|
+
# data represents this packet.
|
|
427
|
+
# @return [Array<PacketItem>] Packet item identifiers
|
|
428
|
+
def id_items
|
|
429
|
+
@id_items ||= []
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# @return [Array<PacketItem>] All items with defined limits
|
|
433
|
+
def limits_items
|
|
434
|
+
@limits_items ||= []
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# @return [Hash] Hash of processors associated with this packet
|
|
438
|
+
def processors
|
|
439
|
+
@processors ||= {}
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# Returns packet specific metadata
|
|
443
|
+
# @return [Hash<Meta Name, Meta Values>]
|
|
444
|
+
def meta
|
|
445
|
+
@meta ||= {}
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Sets packet specific metadata
|
|
449
|
+
def meta=(meta)
|
|
450
|
+
@meta = meta
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Indicates if the packet has been identified
|
|
454
|
+
# @return [TrueClass or FalseClass]
|
|
455
|
+
def identified?
|
|
456
|
+
!@target_name.nil? && !@packet_name.nil?
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# Define an item in the packet. This creates a new instance of the
|
|
460
|
+
# item_class as given in the constructor and adds it to the items hash. It
|
|
461
|
+
# also resizes the buffer to accomodate the new item.
|
|
462
|
+
#
|
|
463
|
+
# @param name [String] Name of the item. Used by the items hash to retrieve
|
|
464
|
+
# the item.
|
|
465
|
+
# @param bit_offset [Integer] Bit offset of the item in the raw buffer
|
|
466
|
+
# @param bit_size [Integer] Bit size of the item in the raw buffer
|
|
467
|
+
# @param data_type [Symbol] Type of data contained by the item. This is
|
|
468
|
+
# dependant on the item_class but by default see StructureItem.
|
|
469
|
+
# @param array_size [Integer] Set to a non nil value if the item is to
|
|
470
|
+
# represented as an array.
|
|
471
|
+
# @param endianness [Symbol] Endianness of this item. By default the
|
|
472
|
+
# endianness as set in the constructure is used.
|
|
473
|
+
# @param overflow [Symbol] How to handle value overflows. This is
|
|
474
|
+
# dependant on the item_class but by default see StructureItem.
|
|
475
|
+
# @param format_string [String] String to pass to Kernel#sprintf
|
|
476
|
+
# @param read_conversion [Conversion] Conversion to apply when reading the
|
|
477
|
+
# item from the packet buffer
|
|
478
|
+
# @param write_conversion [Conversion] Conversion to apply before writing
|
|
479
|
+
# the item to the packet buffer
|
|
480
|
+
# @param id_value [Object] Set to something other than nil to indicate that
|
|
481
|
+
# this item should be used to identify a buffer as this packet. The
|
|
482
|
+
# id_value should make sense according to the data_type.
|
|
483
|
+
# @return [PacketItem] The new packet item
|
|
484
|
+
def define_item(name, bit_offset, bit_size, data_type, array_size = nil, endianness = @default_endianness, overflow = :ERROR, format_string = nil, read_conversion = nil, write_conversion = nil, id_value = nil)
|
|
485
|
+
item = super(name, bit_offset, bit_size, data_type, array_size, endianness, overflow)
|
|
486
|
+
packet_define_item(item, format_string, read_conversion, write_conversion, id_value)
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
# Add an item to the packet by adding it to the items hash. It also
|
|
490
|
+
# resizes the buffer to accomodate the new item.
|
|
491
|
+
#
|
|
492
|
+
# @param item [PacketItem] Item to add to the packet
|
|
493
|
+
# @return [PacketItem] The same packet item
|
|
494
|
+
def define(item)
|
|
495
|
+
item = super(item)
|
|
496
|
+
update_id_items(item)
|
|
497
|
+
update_limits_items_cache(item)
|
|
498
|
+
item
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Define an item at the end of the packet. This creates a new instance of the
|
|
502
|
+
# item_class as given in the constructor and adds it to the items hash. It
|
|
503
|
+
# also resizes the buffer to accomodate the new item.
|
|
504
|
+
#
|
|
505
|
+
# @param name (see #define_item)
|
|
506
|
+
# @param bit_size (see #define_item)
|
|
507
|
+
# @param data_type (see #define_item)
|
|
508
|
+
# @param array_size (see #define_item)
|
|
509
|
+
# @param endianness (see #define_item)
|
|
510
|
+
# @param overflow (see #define_item)
|
|
511
|
+
# @param format_string (see #define_item)
|
|
512
|
+
# @param read_conversion (see #define_item)
|
|
513
|
+
# @param write_conversion (see #define_item)
|
|
514
|
+
# @param id_value (see #define_item)
|
|
515
|
+
# @return (see #define_item)
|
|
516
|
+
def append_item(name, bit_size, data_type, array_size = nil, endianness = @default_endianness, overflow = :ERROR, format_string = nil, read_conversion = nil, write_conversion = nil, id_value = nil)
|
|
517
|
+
item = super(name, bit_size, data_type, array_size, endianness, overflow)
|
|
518
|
+
packet_define_item(item, format_string, read_conversion, write_conversion, id_value)
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# (see Structure#get_item)
|
|
522
|
+
def get_item(name)
|
|
523
|
+
super(name)
|
|
524
|
+
rescue ArgumentError
|
|
525
|
+
raise "Packet item '#{@target_name} #{@packet_name} #{name.upcase}' does not exist"
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
# Read an item in the packet
|
|
529
|
+
#
|
|
530
|
+
# @param item [PacketItem] Instance of PacketItem or one of its subclasses
|
|
531
|
+
# @param value_type [Symbol] How to convert the item before returning it.
|
|
532
|
+
# Must be one of {VALUE_TYPES}
|
|
533
|
+
# @param buffer (see Structure#read_item)
|
|
534
|
+
# @return The value. :FORMATTED and :WITH_UNITS values are always returned
|
|
535
|
+
# as Strings. :RAW values will match their data_type. :CONVERTED values
|
|
536
|
+
# can be any type.
|
|
537
|
+
def read_item(item, value_type = :CONVERTED, buffer = @buffer)
|
|
538
|
+
value = super(item, :RAW, buffer)
|
|
539
|
+
derived_raw = false
|
|
540
|
+
if item.data_type == :DERIVED && value_type == :RAW
|
|
541
|
+
value_type = :CONVERTED
|
|
542
|
+
derived_raw = true
|
|
543
|
+
end
|
|
544
|
+
case value_type
|
|
545
|
+
when :RAW
|
|
546
|
+
# Done above
|
|
547
|
+
when :CONVERTED, :FORMATTED, :WITH_UNITS
|
|
548
|
+
if item.read_conversion
|
|
549
|
+
using_cached_value = false
|
|
550
|
+
|
|
551
|
+
check_cache = buffer.equal?(@buffer)
|
|
552
|
+
if check_cache and @read_conversion_cache
|
|
553
|
+
synchronize_allow_reads() do
|
|
554
|
+
if @read_conversion_cache[item]
|
|
555
|
+
value = @read_conversion_cache[item]
|
|
556
|
+
|
|
557
|
+
# Make sure cached value is not modified by anyone by creating
|
|
558
|
+
# a deep copy
|
|
559
|
+
if String === value
|
|
560
|
+
value = value.clone
|
|
561
|
+
elsif Array === value
|
|
562
|
+
value = Marshal.load(Marshal.dump(value))
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
using_cached_value = true
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
unless using_cached_value
|
|
571
|
+
if item.array_size
|
|
572
|
+
value.map! do |val, index|
|
|
573
|
+
item.read_conversion.call(val, self, buffer)
|
|
574
|
+
end
|
|
575
|
+
else
|
|
576
|
+
value = item.read_conversion.call(value, self, buffer)
|
|
577
|
+
end
|
|
578
|
+
if check_cache
|
|
579
|
+
synchronize_allow_reads() do
|
|
580
|
+
@read_conversion_cache ||= {}
|
|
581
|
+
@read_conversion_cache[item] = value
|
|
582
|
+
|
|
583
|
+
# Make sure cached value is not modified by anyone by creating
|
|
584
|
+
# a deep copy
|
|
585
|
+
if String === value
|
|
586
|
+
value = value.clone
|
|
587
|
+
elsif Array === value
|
|
588
|
+
value = Marshal.load(Marshal.dump(value))
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
end
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Derived raw values perform read_conversions but nothing else
|
|
596
|
+
return value if derived_raw
|
|
597
|
+
|
|
598
|
+
# Convert from value to state if possible
|
|
599
|
+
if item.states
|
|
600
|
+
if Array === value
|
|
601
|
+
value = value.map do |val, index|
|
|
602
|
+
if item.states.key(val)
|
|
603
|
+
item.states.key(val)
|
|
604
|
+
elsif item.states.values.include?(CATCH_ALL_STATE)
|
|
605
|
+
item.states.key(CATCH_ALL_STATE)
|
|
606
|
+
else
|
|
607
|
+
apply_format_string_and_units(item, val, value_type)
|
|
608
|
+
end
|
|
609
|
+
end
|
|
610
|
+
else
|
|
611
|
+
state_value = item.states.key(value)
|
|
612
|
+
if state_value
|
|
613
|
+
value = state_value
|
|
614
|
+
elsif item.states.values.include?(CATCH_ALL_STATE)
|
|
615
|
+
value = item.states.key(CATCH_ALL_STATE)
|
|
616
|
+
else
|
|
617
|
+
value = apply_format_string_and_units(item, value, value_type)
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
else
|
|
621
|
+
if Array === value
|
|
622
|
+
value = value.map do |val, index|
|
|
623
|
+
apply_format_string_and_units(item, val, value_type)
|
|
624
|
+
end
|
|
625
|
+
else
|
|
626
|
+
value = apply_format_string_and_units(item, value, value_type)
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
else
|
|
630
|
+
raise ArgumentError, "Unknown value type on read: #{value_type}"
|
|
631
|
+
end
|
|
632
|
+
return value
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
# Write an item in the packet
|
|
636
|
+
#
|
|
637
|
+
# @param item [PacketItem] Instance of PacketItem or one of its subclasses
|
|
638
|
+
# @param value (see Structure#write_item)
|
|
639
|
+
# @param value_type (see #read_item)
|
|
640
|
+
# @param buffer (see Structure#write_item)
|
|
641
|
+
def write_item(item, value, value_type = :CONVERTED, buffer = @buffer)
|
|
642
|
+
case value_type
|
|
643
|
+
when :RAW
|
|
644
|
+
super(item, value, value_type, buffer)
|
|
645
|
+
when :CONVERTED
|
|
646
|
+
if item.states
|
|
647
|
+
# Convert from state to value if possible
|
|
648
|
+
state_value = item.states[value.to_s.upcase]
|
|
649
|
+
value = state_value if state_value
|
|
650
|
+
end
|
|
651
|
+
if item.write_conversion
|
|
652
|
+
value = item.write_conversion.call(value, self, buffer)
|
|
653
|
+
else
|
|
654
|
+
raise "Cannot write DERIVED item #{item.name} without a write conversion" if item.data_type == :DERIVED
|
|
655
|
+
end
|
|
656
|
+
begin
|
|
657
|
+
super(item, value, :RAW, buffer) unless item.data_type == :DERIVED
|
|
658
|
+
rescue ArgumentError => err
|
|
659
|
+
if item.states and String === value and err.message =~ /invalid value for/
|
|
660
|
+
raise "Unknown state #{value} for #{item.name}"
|
|
661
|
+
else
|
|
662
|
+
raise err
|
|
663
|
+
end
|
|
664
|
+
end
|
|
665
|
+
when :FORMATTED, :WITH_UNITS
|
|
666
|
+
raise ArgumentError, "Invalid value type on write: #{value_type}"
|
|
667
|
+
else
|
|
668
|
+
raise ArgumentError, "Unknown value type on write: #{value_type}"
|
|
669
|
+
end
|
|
670
|
+
if @read_conversion_cache
|
|
671
|
+
synchronize() do
|
|
672
|
+
@read_conversion_cache.clear
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
# Read an item in the packet by name
|
|
678
|
+
#
|
|
679
|
+
# @param name [String] Name of the item to read
|
|
680
|
+
# @param value_type (see #read_item)
|
|
681
|
+
# @param buffer (see #read_item)
|
|
682
|
+
# @return (see #read_item)
|
|
683
|
+
def read(name, value_type = :CONVERTED, buffer = @buffer)
|
|
684
|
+
return super(name, value_type, buffer)
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
# Write an item in the packet by name
|
|
688
|
+
#
|
|
689
|
+
# @param name [String] Name of the item to write
|
|
690
|
+
# @param value (see #write_item)
|
|
691
|
+
# @param value_type (see #write_item)
|
|
692
|
+
# @param buffer (see #write_item)
|
|
693
|
+
def write(name, value, value_type = :CONVERTED, buffer = @buffer)
|
|
694
|
+
super(name, value, value_type, buffer)
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
# Read all items in the packet into an array of arrays
|
|
698
|
+
# [[item name, item value], ...]
|
|
699
|
+
#
|
|
700
|
+
# @param value_type (see #read_item)
|
|
701
|
+
# @param buffer (see Structure#read_all)
|
|
702
|
+
# @param top (See Structure#read_all)
|
|
703
|
+
# @return (see Structure#read_all)
|
|
704
|
+
def read_all(value_type = :CONVERTED, buffer = @buffer, top = true)
|
|
705
|
+
return super(value_type, buffer, top)
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
# Read all items in the packet into an array of arrays
|
|
709
|
+
# [[item name, item value], [item limits state], ...]
|
|
710
|
+
#
|
|
711
|
+
# @param value_type (see #read_all)
|
|
712
|
+
# @param buffer (see #read_all)
|
|
713
|
+
# @return [Array<String, Object, Symbol|nil>] Returns an Array consisting
|
|
714
|
+
# of [item name, item value, item limits state] where the item limits
|
|
715
|
+
# state can be one of {OpenC3::Limits::LIMITS_STATES}
|
|
716
|
+
def read_all_with_limits_states(value_type = :CONVERTED, buffer = @buffer)
|
|
717
|
+
result = nil
|
|
718
|
+
synchronize_allow_reads(true) do
|
|
719
|
+
result = read_all(value_type, buffer, false).map! do |array|
|
|
720
|
+
array << @items[array[0]].limits.state
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
return result
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
# Create a string that shows the name and value of each item in the packet
|
|
727
|
+
#
|
|
728
|
+
# @param value_type (see #read_item)
|
|
729
|
+
# @param indent (see Structure#formatted)
|
|
730
|
+
# @param buffer (see Structure#formatted)
|
|
731
|
+
# @param ignored (see Structure#ignored)
|
|
732
|
+
# @return (see Structure#formatted)
|
|
733
|
+
def formatted(value_type = :CONVERTED, indent = 0, buffer = @buffer, ignored = nil)
|
|
734
|
+
return super(value_type, indent, buffer, ignored)
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
# Restore all items in the packet to their default value
|
|
738
|
+
#
|
|
739
|
+
# @param buffer [String] Raw buffer of binary data
|
|
740
|
+
# @param skip_item_names [Array] Array of item names to skip
|
|
741
|
+
def restore_defaults(buffer = @buffer, skip_item_names = nil)
|
|
742
|
+
upcase_skip_item_names = skip_item_names.map(&:upcase) if skip_item_names
|
|
743
|
+
@sorted_items.each do |item|
|
|
744
|
+
next if RESERVED_ITEM_NAMES.include?(item.name)
|
|
745
|
+
|
|
746
|
+
write_item(item, item.default, :CONVERTED, buffer) unless skip_item_names and upcase_skip_item_names.include?(item.name)
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
# Define the reserved items on the current telemetry packet
|
|
751
|
+
def define_reserved_items
|
|
752
|
+
item = define_item('PACKET_TIMESECONDS', 0, 0, :DERIVED, nil, @default_endianness,
|
|
753
|
+
:ERROR, '%0.6f', PacketTimeSecondsConversion.new)
|
|
754
|
+
item.description = 'OpenC3 Packet Time (UTC, Floating point, Unix epoch)'
|
|
755
|
+
item = define_item('PACKET_TIMEFORMATTED', 0, 0, :DERIVED, nil, @default_endianness,
|
|
756
|
+
:ERROR, nil, PacketTimeFormattedConversion.new)
|
|
757
|
+
item.description = 'OpenC3 Packet Time (Local time zone, Formatted string)'
|
|
758
|
+
item = define_item('RECEIVED_TIMESECONDS', 0, 0, :DERIVED, nil, @default_endianness,
|
|
759
|
+
:ERROR, '%0.6f', ReceivedTimeSecondsConversion.new)
|
|
760
|
+
item.description = 'OpenC3 Received Time (UTC, Floating point, Unix epoch)'
|
|
761
|
+
item = define_item('RECEIVED_TIMEFORMATTED', 0, 0, :DERIVED, nil, @default_endianness,
|
|
762
|
+
:ERROR, nil, ReceivedTimeFormattedConversion.new)
|
|
763
|
+
item.description = 'OpenC3 Received Time (Local time zone, Formatted string)'
|
|
764
|
+
item = define_item('RECEIVED_COUNT', 0, 0, :DERIVED, nil, @default_endianness,
|
|
765
|
+
:ERROR, nil, ReceivedCountConversion.new)
|
|
766
|
+
item.description = 'OpenC3 packet received count'
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
# Enable limits on an item by name
|
|
770
|
+
#
|
|
771
|
+
# @param name [String] Name of the item to enable limits
|
|
772
|
+
def enable_limits(name)
|
|
773
|
+
get_item(name).limits.enabled = true
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
# Disable limits on an item by name
|
|
777
|
+
#
|
|
778
|
+
# @param name [String] Name of the item to disable limits
|
|
779
|
+
def disable_limits(name)
|
|
780
|
+
item = get_item(name)
|
|
781
|
+
item.limits.enabled = false
|
|
782
|
+
unless item.limits.state == :STALE
|
|
783
|
+
old_limits_state = item.limits.state
|
|
784
|
+
item.limits.state = nil
|
|
785
|
+
@limits_change_callback.call(self, item, old_limits_state, nil, false) if @limits_change_callback
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
# Add an item to the limits items cache if necessary.
|
|
790
|
+
# You MUST call this after adding limits to an item
|
|
791
|
+
# This is an optimization so we don't have to iterate through all the items when
|
|
792
|
+
# checking for limits.
|
|
793
|
+
def update_limits_items_cache(item)
|
|
794
|
+
if item.limits.values || item.state_colors
|
|
795
|
+
@limits_items ||= []
|
|
796
|
+
@limits_items_hash ||= {}
|
|
797
|
+
unless @limits_items_hash[item]
|
|
798
|
+
@limits_items << item
|
|
799
|
+
@limits_items_hash[item] = true
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
# Return an array of arrays indicating all items in the packet that are out of limits
|
|
805
|
+
# [[target name, packet name, item name, item limits state], ...]
|
|
806
|
+
#
|
|
807
|
+
# @return [Array<Array<String, String, String, Symbol>>]
|
|
808
|
+
def out_of_limits
|
|
809
|
+
items = []
|
|
810
|
+
return items unless @limits_items
|
|
811
|
+
|
|
812
|
+
@limits_items.each do |item|
|
|
813
|
+
if item.limits.enabled && item.limits.state &&
|
|
814
|
+
PacketItemLimits::OUT_OF_LIMITS_STATES.include?(item.limits.state)
|
|
815
|
+
items << [@target_name, @packet_name, item.name, item.limits.state]
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
return items
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
# Set the limits state for all items to the given state
|
|
822
|
+
#
|
|
823
|
+
# @param state [Symbol] Must be one of PacketItemLimits::LIMITS_STATES
|
|
824
|
+
def set_all_limits_states(state)
|
|
825
|
+
@sorted_items.each { |item| item.limits.state = state }
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
# Check all the items in the packet against their defined limits. Update
|
|
829
|
+
# their internal limits state and persistence and call the
|
|
830
|
+
# limits_change_callback as necessary.
|
|
831
|
+
#
|
|
832
|
+
# @param limits_set [Symbol] Which limits set to check the item values
|
|
833
|
+
# against.
|
|
834
|
+
# @param ignore_persistence [Boolean] Whether to ignore persistence when
|
|
835
|
+
# checking for out of limits
|
|
836
|
+
def check_limits(limits_set = :DEFAULT, ignore_persistence = false)
|
|
837
|
+
# If check_limits is being called, then a new packet has arrived and
|
|
838
|
+
# this packet is no longer stale
|
|
839
|
+
# Stored telemetry doesn't affect the current value table and such doesn't affect stale
|
|
840
|
+
if @stale and !@stored
|
|
841
|
+
@stale = false
|
|
842
|
+
set_all_limits_states(nil)
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
return unless @limits_items
|
|
846
|
+
|
|
847
|
+
@limits_items.each do |item|
|
|
848
|
+
# Verify limits monitoring is enabled for this item
|
|
849
|
+
if item.limits.enabled
|
|
850
|
+
value = read_item(item)
|
|
851
|
+
|
|
852
|
+
# Handle state monitoring and value monitoring differently
|
|
853
|
+
if item.states
|
|
854
|
+
handle_limits_states(item, value)
|
|
855
|
+
elsif item.limits.values
|
|
856
|
+
handle_limits_values(item, value, limits_set, ignore_persistence)
|
|
857
|
+
end
|
|
858
|
+
end
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
# Sets the overall packet stale state to true and sets each packet item
|
|
863
|
+
# limits state to :STALE.
|
|
864
|
+
def set_stale
|
|
865
|
+
@stale = true
|
|
866
|
+
set_all_limits_states(:STALE)
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
# Reset temporary packet data
|
|
870
|
+
# This includes packet received time, received count, and processor state
|
|
871
|
+
def reset
|
|
872
|
+
# The SYSTEM META packet is a special case that does not get reset
|
|
873
|
+
return if @target_name == 'SYSTEM' && @packet_name == 'META'
|
|
874
|
+
|
|
875
|
+
@received_time = nil
|
|
876
|
+
@received_count = 0
|
|
877
|
+
@stored = false
|
|
878
|
+
@extra = nil
|
|
879
|
+
if @read_conversion_cache
|
|
880
|
+
synchronize() do
|
|
881
|
+
@read_conversion_cache.clear
|
|
882
|
+
end
|
|
883
|
+
end
|
|
884
|
+
return unless @processors
|
|
885
|
+
|
|
886
|
+
@processors.each do |processor_name, processor|
|
|
887
|
+
processor.reset
|
|
888
|
+
end
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
# Make a light weight clone of this packet. This only creates a new buffer
|
|
892
|
+
# of data and clones the processors. The defined packet items are the same.
|
|
893
|
+
#
|
|
894
|
+
# @return [Packet] A copy of the current packet with a new underlying
|
|
895
|
+
# buffer of data and processors
|
|
896
|
+
def clone
|
|
897
|
+
packet = super()
|
|
898
|
+
if packet.instance_variable_get("@processors".freeze)
|
|
899
|
+
packet.instance_variable_set("@processors".freeze, packet.processors.clone)
|
|
900
|
+
packet.processors.each do |processor_name, processor|
|
|
901
|
+
packet.processors[processor_name] = processor.clone
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
packet.instance_variable_set("@read_conversion_cache".freeze, nil)
|
|
905
|
+
packet.extra = JSON.parse(packet.extra.as_json(:allow_nan => true).to_json(:allow_nan => true), :allow_nan => true, :create_additions => true) if packet.extra # Deep copy using JSON
|
|
906
|
+
packet
|
|
907
|
+
end
|
|
908
|
+
alias dup clone
|
|
909
|
+
|
|
910
|
+
def update_id_items(item)
|
|
911
|
+
if item.id_value
|
|
912
|
+
@id_items ||= []
|
|
913
|
+
# Add to Id Items
|
|
914
|
+
unless @id_items.empty?
|
|
915
|
+
last_item = @id_items[-1]
|
|
916
|
+
@id_items << item
|
|
917
|
+
# If the current item or last item have a negative offset then we have
|
|
918
|
+
# to re-sort. We also re-sort if the current item is less than the last
|
|
919
|
+
# item because we are inserting.
|
|
920
|
+
if last_item.bit_offset <= 0 or item.bit_offset <= 0 or item.bit_offset < last_item.bit_offset
|
|
921
|
+
@id_items = @id_items.sort
|
|
922
|
+
end
|
|
923
|
+
else
|
|
924
|
+
@id_items << item
|
|
925
|
+
end
|
|
926
|
+
end
|
|
927
|
+
item
|
|
928
|
+
end
|
|
929
|
+
|
|
930
|
+
def to_config(cmd_or_tlm)
|
|
931
|
+
config = ''
|
|
932
|
+
|
|
933
|
+
if cmd_or_tlm == :TELEMETRY
|
|
934
|
+
config << "TELEMETRY #{@target_name.to_s.quote_if_necessary} #{@packet_name.to_s.quote_if_necessary} #{@default_endianness} \"#{@description}\"\n"
|
|
935
|
+
else
|
|
936
|
+
config << "COMMAND #{@target_name.to_s.quote_if_necessary} #{@packet_name.to_s.quote_if_necessary} #{@default_endianness} \"#{@description}\"\n"
|
|
937
|
+
end
|
|
938
|
+
config << " ALLOW_SHORT\n" if @short_buffer_allowed
|
|
939
|
+
config << " HAZARDOUS #{@hazardous_description.to_s.quote_if_necessary}\n" if @hazardous
|
|
940
|
+
config << " DISABLE_MESSAGES\n" if @messages_disabled
|
|
941
|
+
if @disabled
|
|
942
|
+
config << " DISABLED\n"
|
|
943
|
+
elsif @hidden
|
|
944
|
+
config << " HIDDEN\n"
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
if @processors
|
|
948
|
+
@processors.each do |processor_name, processor|
|
|
949
|
+
config << processor.to_config
|
|
950
|
+
end
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
if @meta
|
|
954
|
+
@meta.each do |key, values|
|
|
955
|
+
config << " META #{key.to_s.quote_if_necessary} #{values.map { |a| a..to_s.quote_if_necessary }.join(" ")}\n"
|
|
956
|
+
end
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
# Items with derived items last
|
|
960
|
+
@sorted_items.each do |item|
|
|
961
|
+
if item.data_type != :DERIVED
|
|
962
|
+
config << item.to_config(cmd_or_tlm, @default_endianness)
|
|
963
|
+
end
|
|
964
|
+
end
|
|
965
|
+
@sorted_items.each do |item|
|
|
966
|
+
if item.data_type == :DERIVED
|
|
967
|
+
unless RESERVED_ITEM_NAMES.include?(item.name)
|
|
968
|
+
config << item.to_config(cmd_or_tlm, @default_endianness)
|
|
969
|
+
end
|
|
970
|
+
end
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
config
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
def as_json(*a)
|
|
977
|
+
config = {}
|
|
978
|
+
config['target_name'] = @target_name.to_s
|
|
979
|
+
config['packet_name'] = @packet_name.to_s
|
|
980
|
+
config['endianness'] = @default_endianness.to_s
|
|
981
|
+
config['description'] = @description
|
|
982
|
+
config['short_buffer_allowed'] = true if @short_buffer_allowed
|
|
983
|
+
config['hazardous'] = true if @hazardous
|
|
984
|
+
config['hazardous_description'] = @hazardous_description.to_s if @hazardous_description
|
|
985
|
+
config['messages_disabled'] = true if @messages_disabled
|
|
986
|
+
config['disabled'] = true if @disabled
|
|
987
|
+
config['hidden'] = true if @hidden
|
|
988
|
+
config['stale'] = true if @stale
|
|
989
|
+
|
|
990
|
+
if @processors
|
|
991
|
+
processors = []
|
|
992
|
+
config['processors'] = processors
|
|
993
|
+
@processors.each do |processor_name, processor|
|
|
994
|
+
processors << processor.as_json(*a)
|
|
995
|
+
end
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
config['meta'] = @meta if @meta
|
|
999
|
+
|
|
1000
|
+
items = []
|
|
1001
|
+
config['items'] = items
|
|
1002
|
+
# Items with derived items last
|
|
1003
|
+
@sorted_items.each do |item|
|
|
1004
|
+
if item.data_type != :DERIVED
|
|
1005
|
+
items << item.as_json(*a)
|
|
1006
|
+
end
|
|
1007
|
+
end
|
|
1008
|
+
@sorted_items.each do |item|
|
|
1009
|
+
if item.data_type == :DERIVED
|
|
1010
|
+
items << item.as_json(*a)
|
|
1011
|
+
end
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
config
|
|
1015
|
+
end
|
|
1016
|
+
|
|
1017
|
+
def self.from_json(hash)
|
|
1018
|
+
endianness = hash['endianness'] ? hash['endianness'].intern : nil # Convert to symbol
|
|
1019
|
+
packet = Packet.new(hash['target_name'], hash['packet_name'], endianness, hash['description'])
|
|
1020
|
+
packet.short_buffer_allowed = hash['short_buffer_allowed']
|
|
1021
|
+
packet.hazardous = hash['hazardous']
|
|
1022
|
+
packet.hazardous_description = hash['hazardous_description']
|
|
1023
|
+
packet.messages_disabled = hash['messages_disabled']
|
|
1024
|
+
packet.disabled = hash['disabled']
|
|
1025
|
+
packet.hidden = hash['hidden']
|
|
1026
|
+
# packet.stale is read only
|
|
1027
|
+
packet.meta = hash['meta']
|
|
1028
|
+
# Can't convert processors
|
|
1029
|
+
hash['items'].each do |item|
|
|
1030
|
+
packet.define(PacketItem.from_json(item))
|
|
1031
|
+
end
|
|
1032
|
+
packet
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
protected
|
|
1036
|
+
|
|
1037
|
+
# Performs packet specific processing on the packet.
|
|
1038
|
+
# Intended to only be run once for each packet received
|
|
1039
|
+
def process(buffer = @buffer)
|
|
1040
|
+
return unless @processors
|
|
1041
|
+
|
|
1042
|
+
@processors.each do |processor_name, processor|
|
|
1043
|
+
processor.call(self, buffer)
|
|
1044
|
+
end
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1047
|
+
def handle_limits_states(item, value)
|
|
1048
|
+
# Retrieve limits state for the given value
|
|
1049
|
+
limits_state = item.state_colors[value]
|
|
1050
|
+
|
|
1051
|
+
if item.limits.state != limits_state # PacketItemLimits state has changed
|
|
1052
|
+
# Save old limits state
|
|
1053
|
+
old_limits_state = item.limits.state
|
|
1054
|
+
# Update to new limits state
|
|
1055
|
+
item.limits.state = limits_state
|
|
1056
|
+
|
|
1057
|
+
if old_limits_state == nil # Changing from nil
|
|
1058
|
+
if limits_state != :GREEN && limits_state != :BLUE # Warnings are needed
|
|
1059
|
+
@limits_change_callback.call(self, item, old_limits_state, value, true) if @limits_change_callback
|
|
1060
|
+
end
|
|
1061
|
+
else # Changing from a state other than nil so always call the callback
|
|
1062
|
+
if @limits_change_callback
|
|
1063
|
+
if item.limits.state.nil?
|
|
1064
|
+
@limits_change_callback.call(self, item, old_limits_state, value, false)
|
|
1065
|
+
else
|
|
1066
|
+
@limits_change_callback.call(self, item, old_limits_state, value, true)
|
|
1067
|
+
end
|
|
1068
|
+
end
|
|
1069
|
+
end
|
|
1070
|
+
end
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1073
|
+
def handle_limits_values(item, value, limits_set, ignore_persistence)
|
|
1074
|
+
# Retrieve limits settings for the specified limits_set
|
|
1075
|
+
limits = item.limits.values[limits_set]
|
|
1076
|
+
|
|
1077
|
+
# Use the default limits set if limits aren't specified for the
|
|
1078
|
+
# particular limits set
|
|
1079
|
+
limits = item.limits.values[:DEFAULT] unless limits
|
|
1080
|
+
|
|
1081
|
+
# Extract limits from array
|
|
1082
|
+
red_low = limits[0]
|
|
1083
|
+
yellow_low = limits[1]
|
|
1084
|
+
yellow_high = limits[2]
|
|
1085
|
+
red_high = limits[3]
|
|
1086
|
+
green_low = limits[4]
|
|
1087
|
+
green_high = limits[5]
|
|
1088
|
+
limits_state = nil
|
|
1089
|
+
|
|
1090
|
+
# Determine the limits_state based on the limits values and the current
|
|
1091
|
+
# value of the item
|
|
1092
|
+
if value > yellow_low
|
|
1093
|
+
if value < yellow_high
|
|
1094
|
+
if green_low
|
|
1095
|
+
if value < green_high
|
|
1096
|
+
if value > green_low
|
|
1097
|
+
limits_state = :BLUE
|
|
1098
|
+
else
|
|
1099
|
+
limits_state = :GREEN_LOW
|
|
1100
|
+
end
|
|
1101
|
+
else
|
|
1102
|
+
limits_state = :GREEN_HIGH
|
|
1103
|
+
end
|
|
1104
|
+
else
|
|
1105
|
+
limits_state = :GREEN
|
|
1106
|
+
end
|
|
1107
|
+
elsif value < red_high
|
|
1108
|
+
limits_state = :YELLOW_HIGH
|
|
1109
|
+
else
|
|
1110
|
+
limits_state = :RED_HIGH
|
|
1111
|
+
end
|
|
1112
|
+
else # value <= yellow_low
|
|
1113
|
+
if value > red_low
|
|
1114
|
+
limits_state = :YELLOW_LOW
|
|
1115
|
+
else
|
|
1116
|
+
limits_state = :RED_LOW
|
|
1117
|
+
end
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
if item.limits.state != limits_state # limits state has changed
|
|
1121
|
+
# Save old limits state for use in the callback
|
|
1122
|
+
old_limits_state = item.limits.state
|
|
1123
|
+
|
|
1124
|
+
item.limits.persistence_count += 1
|
|
1125
|
+
|
|
1126
|
+
# Check for item to achieve its persistence which means we
|
|
1127
|
+
# have to update the state and call the callback
|
|
1128
|
+
# Note when going back to green (or blue) persistence is ignored
|
|
1129
|
+
if (item.limits.persistence_count >= item.limits.persistence_setting) || ignore_persistence
|
|
1130
|
+
item.limits.state = limits_state
|
|
1131
|
+
|
|
1132
|
+
# Additional actions for limits change
|
|
1133
|
+
@limits_change_callback.call(self, item, old_limits_state, value, true) if @limits_change_callback
|
|
1134
|
+
|
|
1135
|
+
# Clear persistence since we've entered a new state
|
|
1136
|
+
item.limits.persistence_count = 0
|
|
1137
|
+
end
|
|
1138
|
+
else # limits state has not changed so clear persistence
|
|
1139
|
+
item.limits.persistence_count = 0
|
|
1140
|
+
end
|
|
1141
|
+
end
|
|
1142
|
+
|
|
1143
|
+
def apply_format_string_and_units(item, value, value_type)
|
|
1144
|
+
if value_type == :FORMATTED or value_type == :WITH_UNITS
|
|
1145
|
+
if item.format_string && value
|
|
1146
|
+
value = sprintf(item.format_string, value)
|
|
1147
|
+
else
|
|
1148
|
+
value = value.to_s
|
|
1149
|
+
end
|
|
1150
|
+
end
|
|
1151
|
+
value << ' ' << item.units if value_type == :WITH_UNITS and item.units
|
|
1152
|
+
value
|
|
1153
|
+
end
|
|
1154
|
+
|
|
1155
|
+
def packet_define_item(item, format_string, read_conversion, write_conversion, id_value)
|
|
1156
|
+
item.format_string = format_string
|
|
1157
|
+
item.read_conversion = read_conversion
|
|
1158
|
+
item.write_conversion = write_conversion
|
|
1159
|
+
|
|
1160
|
+
# Change id_value to the correct type
|
|
1161
|
+
if id_value
|
|
1162
|
+
item.id_value = id_value
|
|
1163
|
+
update_id_items(item)
|
|
1164
|
+
end
|
|
1165
|
+
item
|
|
1166
|
+
end
|
|
1167
|
+
end
|
|
1168
|
+
end
|