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,475 @@
|
|
|
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/interfaces/tcpip_client_interface'
|
|
21
|
+
require 'uuidtools'
|
|
22
|
+
|
|
23
|
+
module OpenC3
|
|
24
|
+
# Interface for connecting to Ball Aerospace LINC Labview targets
|
|
25
|
+
class LincInterface < TcpipClientInterface
|
|
26
|
+
# The maximum number of asynchronous commands we can wait for at a time.
|
|
27
|
+
# We don't ever expect to get close to this but we need to limit it
|
|
28
|
+
# to ensure the Array doesn't grow out of control.
|
|
29
|
+
MAX_CONCURRENT_HANDSHAKES = 1000
|
|
30
|
+
|
|
31
|
+
def initialize(
|
|
32
|
+
hostname,
|
|
33
|
+
port,
|
|
34
|
+
handshake_enabled = true,
|
|
35
|
+
response_timeout = 5.0,
|
|
36
|
+
read_timeout = nil,
|
|
37
|
+
write_timeout = 5.0,
|
|
38
|
+
length_bitoffset = 0,
|
|
39
|
+
length_bitsize = 16,
|
|
40
|
+
length_value_offset = 4,
|
|
41
|
+
fieldname_guid = 'HDR_GUID',
|
|
42
|
+
endianness = 'BIG_ENDIAN',
|
|
43
|
+
fieldname_cmd_length = 'HDR_LENGTH'
|
|
44
|
+
)
|
|
45
|
+
# Initialize Super Class
|
|
46
|
+
super(hostname, port, port, write_timeout, read_timeout, 'LENGTH',
|
|
47
|
+
length_bitoffset, length_bitsize, length_value_offset, 1, endianness, 0, nil, nil)
|
|
48
|
+
|
|
49
|
+
# Configuration Settings
|
|
50
|
+
@handshake_enabled = ConfigParser.handle_true_false(handshake_enabled)
|
|
51
|
+
@handshake_enableds = nil
|
|
52
|
+
@response_timeout = response_timeout.to_f
|
|
53
|
+
@length_value_offset = Integer(length_value_offset)
|
|
54
|
+
@fieldname_guid = ConfigParser.handle_nil(fieldname_guid)
|
|
55
|
+
@fieldname_cmd_length = ConfigParser.handle_nil(fieldname_cmd_length)
|
|
56
|
+
|
|
57
|
+
# Other instance variables
|
|
58
|
+
@ignored_error_codes = {}
|
|
59
|
+
@handshake_cmds = []
|
|
60
|
+
@handshakes_mutex = Mutex.new
|
|
61
|
+
|
|
62
|
+
# Call this once now because the first time is slow
|
|
63
|
+
UUIDTools::UUID.random_create.raw
|
|
64
|
+
end # def initialize
|
|
65
|
+
|
|
66
|
+
def connect
|
|
67
|
+
# Packet definitions need to be retrieved here because @target_names is not filled in until after initialize
|
|
68
|
+
unless @handshake_enableds
|
|
69
|
+
@handshake_enableds = {}
|
|
70
|
+
@target_names.each do |target_name|
|
|
71
|
+
@handshake_enableds[target_name] = @handshake_enabled
|
|
72
|
+
@ignored_error_codes[target_name] = []
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
@handshake_packets = []
|
|
76
|
+
@error_packets = []
|
|
77
|
+
@error_ignore_commands = nil
|
|
78
|
+
@error_handle_commands = nil
|
|
79
|
+
@handshake_enable_commands = nil
|
|
80
|
+
@handshake_disable_commands = nil
|
|
81
|
+
|
|
82
|
+
@target_names.each do |target_name|
|
|
83
|
+
@handshake_packets << System.telemetry.packet(target_name, 'HANDSHAKE')
|
|
84
|
+
@error_packets << System.telemetry.packet(target_name, 'ERROR')
|
|
85
|
+
|
|
86
|
+
# Handle not defining the interface configuration commands (Targets may not want to support this functionality)
|
|
87
|
+
begin
|
|
88
|
+
command = System.commands.packet(target_name, 'OPENC3_ERROR_IGNORE')
|
|
89
|
+
@error_ignore_commands ||= []
|
|
90
|
+
@error_ignore_commands << command
|
|
91
|
+
rescue
|
|
92
|
+
end
|
|
93
|
+
begin
|
|
94
|
+
command = System.commands.packet(target_name, 'OPENC3_ERROR_HANDLE')
|
|
95
|
+
@error_handle_commands ||= []
|
|
96
|
+
@error_handle_commands << command
|
|
97
|
+
rescue
|
|
98
|
+
end
|
|
99
|
+
begin
|
|
100
|
+
command = System.commands.packet(target_name, 'OPENC3_HANDSHAKE_EN')
|
|
101
|
+
@handshake_enable_commands ||= []
|
|
102
|
+
@handshake_enable_commands << command
|
|
103
|
+
rescue
|
|
104
|
+
end
|
|
105
|
+
begin
|
|
106
|
+
command = System.commands.packet(target_name, 'OPENC3_HANDSHAKE_DS')
|
|
107
|
+
@handshake_disable_commands ||= []
|
|
108
|
+
@handshake_disable_commands << command
|
|
109
|
+
rescue
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
@handshakes_mutex.synchronize do
|
|
114
|
+
@handshake_cmds = []
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Actually connect
|
|
118
|
+
super()
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def write(packet)
|
|
122
|
+
return if linc_interface_command(packet)
|
|
123
|
+
raise "Interface not connected" unless connected?()
|
|
124
|
+
|
|
125
|
+
# Add a GUID to the GUID field if its defined
|
|
126
|
+
# A GUID means it's an asychronous packet type.
|
|
127
|
+
if @fieldname_guid
|
|
128
|
+
guid = get_guid(packet)
|
|
129
|
+
else
|
|
130
|
+
# If @fieldname_guid is not defined (syncronous) we don't care what the
|
|
131
|
+
# GUID is because we're not trying to match it up with anything.
|
|
132
|
+
# As soon as we get a response we free the command.
|
|
133
|
+
guid = 0
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Fix the length field to handle the cases where a variable length packet
|
|
137
|
+
# is defined. OpenC3 does not do this automatically.
|
|
138
|
+
update_length_field(packet) if @fieldname_cmd_length
|
|
139
|
+
|
|
140
|
+
# Always take the mutex (even if we aren't handshaking)
|
|
141
|
+
# We do not want any incoming telemetry to be missed because
|
|
142
|
+
# it could be the handshake to this command.
|
|
143
|
+
@handshakes_mutex.synchronize do
|
|
144
|
+
super(packet) # Send the command
|
|
145
|
+
wait_for_response(packet, guid) if @handshake_enableds[packet.target_name]
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def linc_interface_command(packet)
|
|
150
|
+
if @error_ignore_commands
|
|
151
|
+
@error_ignore_commands.each do |error_ignore_command|
|
|
152
|
+
if error_ignore_command.identify?(packet.buffer(false))
|
|
153
|
+
linc_cmd = error_ignore_command.clone
|
|
154
|
+
linc_cmd.buffer = packet.buffer
|
|
155
|
+
code = linc_cmd.read('CODE')
|
|
156
|
+
@ignored_error_codes[error_ignore_command.target_name] << code unless @ignored_error_codes[error_ignore_command.target_name].include? code
|
|
157
|
+
return true
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
if @error_handle_commands
|
|
163
|
+
@error_handle_commands.each do |error_handle_command|
|
|
164
|
+
if error_handle_command.identify?(packet.buffer(false))
|
|
165
|
+
linc_cmd = error_handle_command.clone
|
|
166
|
+
linc_cmd.buffer = packet.buffer
|
|
167
|
+
code = linc_cmd.read('CODE')
|
|
168
|
+
@ignored_error_codes[error_handle_command.target_name].delete(code) if @ignored_error_codes[error_handle_command.target_name].include? code
|
|
169
|
+
return true
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
if @handshake_enable_commands
|
|
175
|
+
@handshake_enable_commands.each do |handshake_enable_command|
|
|
176
|
+
if handshake_enable_command.identify?(packet.buffer(false))
|
|
177
|
+
@handshake_enabled = true
|
|
178
|
+
@handshake_enableds[handshake_enable_command.target_name] = true
|
|
179
|
+
return true
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
if @handshake_disable_commands
|
|
185
|
+
@handshake_disable_commands.each do |handshake_disable_command|
|
|
186
|
+
if handshake_disable_command.identify?(packet.buffer(false))
|
|
187
|
+
@handshake_enabled = false
|
|
188
|
+
@handshake_enableds[handshake_disable_command.target_name] = false
|
|
189
|
+
return true
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
return false
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def get_guid(packet)
|
|
198
|
+
if not packet.read(@fieldname_guid) =~ /[\x01-\xFF]/
|
|
199
|
+
# The GUID has not been set already (it has all \x00 values), so make a new one.
|
|
200
|
+
# This enables a router GUI to make the GUIDs so it can process handshakes too.
|
|
201
|
+
guid = UUIDTools::UUID.random_create.raw
|
|
202
|
+
packet.write(@fieldname_guid, guid, :RAW)
|
|
203
|
+
else
|
|
204
|
+
guid = packet.read(@fieldname_guid)
|
|
205
|
+
end
|
|
206
|
+
return guid
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def update_length_field(packet)
|
|
210
|
+
length = packet.length - @length_value_offset
|
|
211
|
+
packet.write(@fieldname_cmd_length, length, :RAW)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def wait_for_response(packet, guid)
|
|
215
|
+
# Check the number of commands waiting for handshakes. This is just for sanity
|
|
216
|
+
# If the number of commands waiting for handshakes is very large then it can't be real
|
|
217
|
+
# So raise an error. Something has gone horribly wrong.
|
|
218
|
+
if @handshake_cmds.length > MAX_CONCURRENT_HANDSHAKES
|
|
219
|
+
len = @handshake_cmds.length
|
|
220
|
+
@handshake_cmds = []
|
|
221
|
+
raise "The number of commands waiting for handshakes to #{len}. Clearing all commands!"
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Create a handshake command object and add it to the list of commands waiting
|
|
225
|
+
handshake_cmd = LincHandshakeCommand.new(@handshakes_mutex, guid)
|
|
226
|
+
@handshake_cmds.push(handshake_cmd)
|
|
227
|
+
|
|
228
|
+
# wait for that handshake. This releases the mutex so that the telemetry and other commands can start running again.
|
|
229
|
+
timed_out = handshake_cmd.wait_for_handshake(@response_timeout)
|
|
230
|
+
# We now have the mutex again. This interface is blocked for the rest of the command handling,
|
|
231
|
+
# which should be quick because it's just checking variables and logging.
|
|
232
|
+
# We want to hold the mutex during that so that the commands get logged in order of handshake from here.
|
|
233
|
+
|
|
234
|
+
if timed_out
|
|
235
|
+
# Clean this command out of the array of items that require handshakes.
|
|
236
|
+
@handshake_cmds.delete_if { |hsc| hsc == handshake_cmd }
|
|
237
|
+
raise "Timeout waiting for handshake from #{System.commands.format(packet, System.targets[packet.target_name].ignored_parameters)}"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
process_handshake_results(handshake_cmd)
|
|
241
|
+
rescue Exception => err
|
|
242
|
+
# If anything goes wrong after successfully writing the packet to the LINC target
|
|
243
|
+
# ensure that the packet gets updated in the CVT and logged to the packet log writer.
|
|
244
|
+
# OpenC3 normally only does this if write returns successfully
|
|
245
|
+
if packet.identified?
|
|
246
|
+
command = System.commands.packet(packet.target_name, packet.packet_name)
|
|
247
|
+
else
|
|
248
|
+
command = System.commands.packet('UNKNOWN', 'UNKNOWN')
|
|
249
|
+
end
|
|
250
|
+
command.buffer = packet.buffer
|
|
251
|
+
|
|
252
|
+
@packet_log_writer_pairs.each do |packet_log_writer_pair|
|
|
253
|
+
packet_log_writer_pair.cmd_log_writer.write(packet)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
raise err
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def process_handshake_results(handshake_cmd)
|
|
260
|
+
status = handshake_cmd.handshake.handshake.read('STATUS')
|
|
261
|
+
code = handshake_cmd.handshake.handshake.read('CODE')
|
|
262
|
+
source = handshake_cmd.handshake.error_source
|
|
263
|
+
|
|
264
|
+
# Handle handshake warnings and errors
|
|
265
|
+
if status == "OK" and code != 0
|
|
266
|
+
unless @ignored_error_codes[handshake_cmd.handshake.handshake.target_name].include? code
|
|
267
|
+
Logger.warn "#{@name}: Warning sending command (#{code}): #{source}"
|
|
268
|
+
end
|
|
269
|
+
elsif status == "ERROR"
|
|
270
|
+
unless @ignored_error_codes[handshake_cmd.handshake.handshake.target_name].include? code
|
|
271
|
+
raise "Error sending command (#{code}): #{source}"
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def read
|
|
277
|
+
packet = super()
|
|
278
|
+
if packet
|
|
279
|
+
@handshake_packets.each do |handshake_packet|
|
|
280
|
+
if handshake_packet.identify?(packet.buffer(false))
|
|
281
|
+
handshake_packet = handshake_packet.clone
|
|
282
|
+
handshake_packet.buffer = packet.buffer
|
|
283
|
+
linc_handshake = LincHandshake.new(handshake_packet, handshake_packet.target_name)
|
|
284
|
+
|
|
285
|
+
# Check for a local handshake
|
|
286
|
+
if handshake_packet.read('origin') == "LCL"
|
|
287
|
+
handle_local_handshake(linc_handshake)
|
|
288
|
+
else
|
|
289
|
+
handle_remote_handshake(linc_handshake) if @handshake_enableds[handshake_packet.target_name]
|
|
290
|
+
end # if handshake_packet.read('origin') == "LCL"
|
|
291
|
+
end # @handshake_packet.identify?(packet.buffer(false))
|
|
292
|
+
end
|
|
293
|
+
end # if packet
|
|
294
|
+
|
|
295
|
+
return packet
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def handle_local_handshake(linc_handshake)
|
|
299
|
+
# Update the current value table for this command
|
|
300
|
+
command = System.commands.packet(linc_handshake.identified_command.target_name, linc_handshake.identified_command.packet_name)
|
|
301
|
+
command.received_time = linc_handshake.identified_command.received_time
|
|
302
|
+
command.buffer = linc_handshake.identified_command.buffer
|
|
303
|
+
command.received_count += 1
|
|
304
|
+
|
|
305
|
+
# Put a log of the command onto the server for the user to see
|
|
306
|
+
Logger.info("#{@name}: External Command: " + System.commands.format(linc_handshake.identified_command, System.targets[linc_handshake.identified_command.target_name].ignored_parameters))
|
|
307
|
+
|
|
308
|
+
# Log the command to the command log(s)
|
|
309
|
+
@packet_log_writer_pairs.each do |packet_log_writer_pair|
|
|
310
|
+
packet_log_writer_pair.cmd_log_writer.write(linc_handshake.identified_command)
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def handle_remote_handshake(linc_handshake)
|
|
315
|
+
# This is a remote packet (sent from here).
|
|
316
|
+
# Add to the array of handshake packet responses
|
|
317
|
+
# The mutex is required by the command task due to the way it
|
|
318
|
+
# first looks up the handshake before removing it.
|
|
319
|
+
@handshakes_mutex.synchronize do
|
|
320
|
+
if @fieldname_guid
|
|
321
|
+
# A GUID means it's an asychronous packet type.
|
|
322
|
+
# So look at the list of incoming handshakes and pick off (deleting)
|
|
323
|
+
# the handshake from the list if it's for this command.
|
|
324
|
+
#
|
|
325
|
+
# The mutex is required because the telemetry task
|
|
326
|
+
# could enqueue a response between the index lookup and the slice
|
|
327
|
+
# function which would remove the wrong response. FAIL!
|
|
328
|
+
|
|
329
|
+
# Loop through all waiting commands to see if this handshake belongs to them
|
|
330
|
+
this_handshake_guid = linc_handshake.get_cmd_guid(@fieldname_guid)
|
|
331
|
+
handshake_cmd_index = @handshake_cmds.index { |hsc| hsc.get_cmd_guid == this_handshake_guid }
|
|
332
|
+
|
|
333
|
+
# If command was waiting (ie the loop above found one), then remove it from waiters and signal it
|
|
334
|
+
if handshake_cmd_index
|
|
335
|
+
handshake_cmd = @handshake_cmds.slice!(handshake_cmd_index)
|
|
336
|
+
handshake_cmd.got_your_handshake(linc_handshake)
|
|
337
|
+
else
|
|
338
|
+
# No command match found! Either it gave up and timed out or this wasn't originated from here.
|
|
339
|
+
# Ignore this typically. This case here for clarity.
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
else
|
|
343
|
+
# Synchronous version: just pop the array (pull the command off) and send it the handshake
|
|
344
|
+
handshake_cmd = @handshakes_cmds.pop
|
|
345
|
+
handshake_cmd.got_your_handshake(linc_handshake)
|
|
346
|
+
end # of handshaking type check
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
end # class LincInterface
|
|
350
|
+
|
|
351
|
+
# The LincHandshakeCommand class is used only by the LincInterface.
|
|
352
|
+
# It is the command with other required items that is passed to the telemetry
|
|
353
|
+
# thread so it can match it with the handshake.
|
|
354
|
+
class LincHandshakeCommand
|
|
355
|
+
attr_accessor :handshake
|
|
356
|
+
|
|
357
|
+
def initialize(handshakes_mutex, cmd_guid)
|
|
358
|
+
@cmd_guid = cmd_guid
|
|
359
|
+
@handshakes_mutex = handshakes_mutex
|
|
360
|
+
@resource = ConditionVariable.new
|
|
361
|
+
@handshake = nil
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def wait_for_handshake(response_timeout)
|
|
365
|
+
timed_out = false
|
|
366
|
+
|
|
367
|
+
@resource.wait(@handshakes_mutex, response_timeout)
|
|
368
|
+
if @handshake
|
|
369
|
+
timed_out = false
|
|
370
|
+
else
|
|
371
|
+
Logger.warn "#{@name}: No handshake - must be timeout."
|
|
372
|
+
timed_out = true
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
return timed_out
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def got_your_handshake(handshake)
|
|
379
|
+
@handshake = handshake
|
|
380
|
+
@resource.signal
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def get_cmd_guid
|
|
384
|
+
return @cmd_guid
|
|
385
|
+
end
|
|
386
|
+
end # class LincHandshakeCommand
|
|
387
|
+
|
|
388
|
+
# The LincHandshake class is used only by the LincInterface. It processes the handshake and
|
|
389
|
+
# helps with finding the information regarding the internal command.
|
|
390
|
+
class LincHandshake
|
|
391
|
+
attr_accessor :handshake
|
|
392
|
+
attr_accessor :identified_command
|
|
393
|
+
attr_accessor :error_source
|
|
394
|
+
|
|
395
|
+
def initialize(handshake, interface_target_name)
|
|
396
|
+
@handshake = handshake
|
|
397
|
+
|
|
398
|
+
# Interpret the command field of the handshake packet
|
|
399
|
+
# Where DATA is defined as:
|
|
400
|
+
# 1 byte target name length
|
|
401
|
+
# X byte target name
|
|
402
|
+
# 1 byte packet name length
|
|
403
|
+
# X byte packet name
|
|
404
|
+
# 4 byte packet data length
|
|
405
|
+
# X byte packet data
|
|
406
|
+
# 4 byte error source length
|
|
407
|
+
# X byte error source
|
|
408
|
+
data = handshake.read('DATA')
|
|
409
|
+
raise "Data field too short for target name length" if data.length == 0
|
|
410
|
+
|
|
411
|
+
# Get target name length
|
|
412
|
+
target_name_length = data[0..0].unpack('C')[0]
|
|
413
|
+
raise "Invalid target name length" if target_name_length == 0
|
|
414
|
+
|
|
415
|
+
data = data[1..-1]
|
|
416
|
+
|
|
417
|
+
# get target name
|
|
418
|
+
raise "Data field too short for target name" if data.length < target_name_length
|
|
419
|
+
|
|
420
|
+
# target_name = data[0..(target_name_length - 1)] # Unused
|
|
421
|
+
data = data[target_name_length..-1]
|
|
422
|
+
|
|
423
|
+
# get packet name length
|
|
424
|
+
raise "Data field too short for packet name length" if data.length == 0
|
|
425
|
+
|
|
426
|
+
packet_name_length = data[0..0].unpack('C')[0]
|
|
427
|
+
raise "Invalid packet name length" if packet_name_length == 0
|
|
428
|
+
|
|
429
|
+
data = data[1..-1]
|
|
430
|
+
|
|
431
|
+
# get packet name
|
|
432
|
+
raise "Data field too short for packet name" if data.length < packet_name_length
|
|
433
|
+
|
|
434
|
+
packet_name = data[0..(packet_name_length - 1)]
|
|
435
|
+
data = data[packet_name_length..-1]
|
|
436
|
+
|
|
437
|
+
# get packet data length
|
|
438
|
+
raise "Data field too short for packet data length" if data.length < 4
|
|
439
|
+
|
|
440
|
+
packet_data_length = data[0..3].unpack('N')[0]
|
|
441
|
+
raise "Invalid data length" if packet_data_length == 0
|
|
442
|
+
|
|
443
|
+
data = data[4..-1]
|
|
444
|
+
|
|
445
|
+
# get packet data
|
|
446
|
+
raise "Data field too short for packet data" if data.length < packet_data_length
|
|
447
|
+
|
|
448
|
+
packet_data = data[0..(packet_data_length - 1)]
|
|
449
|
+
data = data[packet_data_length..-1]
|
|
450
|
+
|
|
451
|
+
# get error source length
|
|
452
|
+
raise "Data field too short for error source length" if data.length < 4
|
|
453
|
+
|
|
454
|
+
error_source_length = data[0..3].unpack('N')[0]
|
|
455
|
+
# note it is OK to have a 0 source length
|
|
456
|
+
data = data[4..-1]
|
|
457
|
+
|
|
458
|
+
# get error source - store on object
|
|
459
|
+
if error_source_length > 0
|
|
460
|
+
@error_source = data[0..(error_source_length - 1)]
|
|
461
|
+
else
|
|
462
|
+
@error_source = ''
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# make packet - store on object as a defined packet of type command that this handshakes
|
|
466
|
+
@identified_command = System.commands.packet(interface_target_name, packet_name).clone
|
|
467
|
+
@identified_command.buffer = packet_data
|
|
468
|
+
@identified_command.received_time = Time.at(handshake.read('TIME_SECONDS'), handshake.read('TIME_MICROSECONDS')).sys
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def get_cmd_guid(fieldname_guid)
|
|
472
|
+
return @identified_command.read(fieldname_guid)
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
end
|
|
@@ -0,0 +1,192 @@
|
|
|
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/config/config_parser'
|
|
21
|
+
require 'openc3/interfaces/protocols/protocol'
|
|
22
|
+
require 'thread'
|
|
23
|
+
|
|
24
|
+
module OpenC3
|
|
25
|
+
# Reads all data available on the interface and creates a packet
|
|
26
|
+
# with that data.
|
|
27
|
+
class BurstProtocol < Protocol
|
|
28
|
+
# @param discard_leading_bytes [Integer] The number of bytes to discard
|
|
29
|
+
# from the binary data after reading. Note that this is often
|
|
30
|
+
# used to remove a sync pattern from the final packet data.
|
|
31
|
+
# @param sync_pattern [String] String representing a hex number ("0x1234")
|
|
32
|
+
# that will be searched for in the raw data. Bytes encountered before
|
|
33
|
+
# this pattern is found are discarded.
|
|
34
|
+
# @param fill_fields [Boolean] Fill any required fields when writing packets
|
|
35
|
+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
|
|
36
|
+
def initialize(discard_leading_bytes = 0, sync_pattern = nil, fill_fields = false, allow_empty_data = nil)
|
|
37
|
+
super(allow_empty_data)
|
|
38
|
+
@discard_leading_bytes = discard_leading_bytes.to_i
|
|
39
|
+
@sync_pattern = ConfigParser.handle_nil(sync_pattern)
|
|
40
|
+
@sync_pattern = @sync_pattern.hex_to_byte_string if @sync_pattern
|
|
41
|
+
@fill_fields = ConfigParser.handle_true_false(fill_fields)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reset
|
|
45
|
+
super()
|
|
46
|
+
@data = ''
|
|
47
|
+
@data.force_encoding('ASCII-8BIT')
|
|
48
|
+
@sync_state = :SEARCHING
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Reads from the interface. It can look for a sync pattern before
|
|
52
|
+
# creating a Packet. It can discard a set number of bytes at the beginning
|
|
53
|
+
# before creating the Packet.
|
|
54
|
+
#
|
|
55
|
+
# @return [String|nil] Data for a packet consisting of the bytes read
|
|
56
|
+
def read_data(data)
|
|
57
|
+
@data << data
|
|
58
|
+
|
|
59
|
+
control = handle_sync_pattern()
|
|
60
|
+
return control if control and data.length > 0
|
|
61
|
+
|
|
62
|
+
# Reduce the data to a single packet
|
|
63
|
+
packet_data = reduce_to_single_packet()
|
|
64
|
+
|
|
65
|
+
# Potentially allow blank string to be sent to other protocols if no packet is ready in this one
|
|
66
|
+
if Symbol === packet_data
|
|
67
|
+
if (data.length <= 0) and packet_data == :STOP
|
|
68
|
+
return super(data)
|
|
69
|
+
else
|
|
70
|
+
return packet_data
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
@sync_state = :SEARCHING
|
|
75
|
+
|
|
76
|
+
# Discard leading bytes if necessary
|
|
77
|
+
packet_data.replace(packet_data[@discard_leading_bytes..-1]) if @discard_leading_bytes > 0
|
|
78
|
+
packet_data
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Called to perform modifications on a command packet before it is sent
|
|
82
|
+
#
|
|
83
|
+
# @param packet [Packet] Original packet
|
|
84
|
+
# @return [Packet] Potentially modified packet
|
|
85
|
+
def write_packet(packet)
|
|
86
|
+
# If we're filling the sync pattern and the sync pattern is part of the
|
|
87
|
+
# packet (since we're not discarding any leading bytes) then we have to
|
|
88
|
+
# fill the sync pattern in the actual packet so do it here.
|
|
89
|
+
if @fill_fields && @sync_pattern && @discard_leading_bytes == 0
|
|
90
|
+
# Directly write the packet buffer and fill in the sync pattern
|
|
91
|
+
BinaryAccessor.write(@sync_pattern, 0, @sync_pattern.length * 8, :BLOCK,
|
|
92
|
+
packet.buffer(false), :BIG_ENDIAN, :ERROR)
|
|
93
|
+
end
|
|
94
|
+
packet
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Called to perform modifications on write data before sending it to the interface
|
|
98
|
+
#
|
|
99
|
+
# @param data [String] Raw packet data
|
|
100
|
+
# @return [String] Potentially modified packet data
|
|
101
|
+
def write_data(data)
|
|
102
|
+
# If we're filling the sync pattern and discarding the leading bytes
|
|
103
|
+
# during a read then we need to put them back during a write.
|
|
104
|
+
# If we're discarding the bytes then by definition they can't be part
|
|
105
|
+
# of the packet so we just modify the data.
|
|
106
|
+
if @fill_fields && @discard_leading_bytes > 0
|
|
107
|
+
data = ("\x00" * @discard_leading_bytes) << data
|
|
108
|
+
if @sync_pattern
|
|
109
|
+
BinaryAccessor.write(@sync_pattern, 0, @sync_pattern.length * 8, :BLOCK,
|
|
110
|
+
data, :BIG_ENDIAN, :ERROR)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
super(data)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @return [Boolean] control code (nil, :STOP)
|
|
117
|
+
def handle_sync_pattern
|
|
118
|
+
if @sync_pattern and @sync_state == :SEARCHING
|
|
119
|
+
loop do
|
|
120
|
+
# Make sure we have some data to look for a sync word in
|
|
121
|
+
return :STOP if @data.length < @sync_pattern.length
|
|
122
|
+
|
|
123
|
+
# Find the beginning of the sync pattern
|
|
124
|
+
sync_index = @data.index(@sync_pattern.getbyte(0).chr)
|
|
125
|
+
if sync_index
|
|
126
|
+
# Make sure we have enough data for the whole sync pattern past this index
|
|
127
|
+
return :STOP if @data.length < (sync_index + @sync_pattern.length)
|
|
128
|
+
|
|
129
|
+
# Check for the rest of the sync pattern
|
|
130
|
+
found = true
|
|
131
|
+
index = sync_index
|
|
132
|
+
@sync_pattern.each_byte do |byte|
|
|
133
|
+
if @data.getbyte(index) != byte
|
|
134
|
+
found = false
|
|
135
|
+
break
|
|
136
|
+
end
|
|
137
|
+
index += 1
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if found
|
|
141
|
+
if sync_index != 0
|
|
142
|
+
discard_length = @data[0..(sync_index - 1)].length
|
|
143
|
+
log_discard(discard_length, true)
|
|
144
|
+
# Delete Data Before Sync Pattern
|
|
145
|
+
@data.replace(@data[sync_index..-1])
|
|
146
|
+
end
|
|
147
|
+
@sync_state = :FOUND
|
|
148
|
+
return nil
|
|
149
|
+
|
|
150
|
+
else # not found
|
|
151
|
+
log_discard(@data[0..sync_index].length, false)
|
|
152
|
+
# Delete Data Before and including first character of suspected sync Pattern
|
|
153
|
+
@data.replace(@data[(sync_index + 1)..-1])
|
|
154
|
+
next
|
|
155
|
+
end # if found
|
|
156
|
+
|
|
157
|
+
else # sync_index = nil
|
|
158
|
+
log_discard(@data.length, false)
|
|
159
|
+
@data.replace('')
|
|
160
|
+
return :STOP
|
|
161
|
+
end # unless sync_index.nil?
|
|
162
|
+
end # end loop
|
|
163
|
+
end # if @sync_pattern
|
|
164
|
+
nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def log_discard(length, found)
|
|
168
|
+
Logger.error("#{@interface ? @interface.name : ""}: Sync #{'not ' unless found}found. Discarding #{length} bytes of data.")
|
|
169
|
+
if @data.length >= 0
|
|
170
|
+
Logger.error(sprintf("Starting: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
|
|
171
|
+
@data.length >= 1 ? @data.getbyte(0) : 0,
|
|
172
|
+
@data.length >= 2 ? @data.getbyte(1) : 0,
|
|
173
|
+
@data.length >= 3 ? @data.getbyte(2) : 0,
|
|
174
|
+
@data.length >= 4 ? @data.getbyte(3) : 0,
|
|
175
|
+
@data.length >= 5 ? @data.getbyte(4) : 0,
|
|
176
|
+
@data.length >= 6 ? @data.getbyte(5) : 0))
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def reduce_to_single_packet
|
|
181
|
+
if @data.length <= 0
|
|
182
|
+
# Need some data
|
|
183
|
+
return :STOP
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Reduce to packet data and clear data for next packet
|
|
187
|
+
packet_data = @data.clone
|
|
188
|
+
@data.replace('')
|
|
189
|
+
packet_data
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|