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,206 @@
|
|
|
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/protocols/burst_protocol'
|
|
21
|
+
|
|
22
|
+
module OpenC3
|
|
23
|
+
# Delineates packets using the OpenC3 preidentification system
|
|
24
|
+
class PreidentifiedProtocol < BurstProtocol
|
|
25
|
+
COSMOS4_STORED_FLAG_MASK = 0x80
|
|
26
|
+
COSMOS4_EXTRA_FLAG_MASK = 0x40
|
|
27
|
+
|
|
28
|
+
# @param sync_pattern (see BurstProtocol#initialize)
|
|
29
|
+
# @param max_length [Integer] The maximum allowed value of the length field
|
|
30
|
+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
|
|
31
|
+
def initialize(sync_pattern = nil, max_length = nil, mode = 4, allow_empty_data = nil)
|
|
32
|
+
super(0, sync_pattern, false, allow_empty_data)
|
|
33
|
+
@max_length = ConfigParser.handle_nil(max_length)
|
|
34
|
+
@max_length = Integer(@max_length) if @max_length
|
|
35
|
+
@mode = Integer(mode)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def reset
|
|
39
|
+
super()
|
|
40
|
+
@reduction_state = :START
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def read_packet(packet)
|
|
44
|
+
packet.received_time = @read_received_time
|
|
45
|
+
packet.target_name = @read_target_name
|
|
46
|
+
packet.packet_name = @read_packet_name
|
|
47
|
+
if @mode == 4 # COSMOS4.3+ Protocol
|
|
48
|
+
packet.stored = @read_stored
|
|
49
|
+
packet.extra = @read_extra
|
|
50
|
+
end
|
|
51
|
+
return packet
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def write_packet(packet)
|
|
55
|
+
received_time = packet.received_time
|
|
56
|
+
received_time = Time.now unless received_time
|
|
57
|
+
@write_time_seconds = [received_time.tv_sec].pack('N') # UINT32
|
|
58
|
+
@write_time_microseconds = [received_time.tv_usec].pack('N') # UINT32
|
|
59
|
+
@write_target_name = packet.target_name
|
|
60
|
+
@write_target_name = 'UNKNOWN' unless @write_target_name
|
|
61
|
+
@write_packet_name = packet.packet_name
|
|
62
|
+
@write_packet_name = 'UNKNOWN' unless @write_packet_name
|
|
63
|
+
if @mode == 4 # COSMOS4.3+ Protocol
|
|
64
|
+
@write_flags = 0
|
|
65
|
+
@write_flags |= COSMOS4_STORED_FLAG_MASK if packet.stored
|
|
66
|
+
@write_extra = nil
|
|
67
|
+
if packet.extra
|
|
68
|
+
@write_flags |= COSMOS4_EXTRA_FLAG_MASK
|
|
69
|
+
@write_extra = packet.extra.as_json(:allow_nan => true).to_json(:allow_nan => true)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
return packet
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def write_data(data)
|
|
76
|
+
data_length = [data.length].pack('N') # UINT32
|
|
77
|
+
data_to_send = ''
|
|
78
|
+
data_to_send << @sync_pattern if @sync_pattern
|
|
79
|
+
if @mode == 4 # COSMOS4.3+ Protocol
|
|
80
|
+
data_to_send << @write_flags
|
|
81
|
+
if @write_extra
|
|
82
|
+
data_to_send << [@write_extra.length].pack('N')
|
|
83
|
+
data_to_send << @write_extra
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
data_to_send << @write_time_seconds
|
|
87
|
+
data_to_send << @write_time_microseconds
|
|
88
|
+
data_to_send << @write_target_name.length
|
|
89
|
+
data_to_send << @write_target_name
|
|
90
|
+
data_to_send << @write_packet_name.length
|
|
91
|
+
data_to_send << @write_packet_name
|
|
92
|
+
data_to_send << data_length
|
|
93
|
+
data_to_send << data
|
|
94
|
+
return data_to_send
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
protected
|
|
98
|
+
|
|
99
|
+
def read_length_field_followed_by_string(length_num_bytes)
|
|
100
|
+
# Read bytes for string length
|
|
101
|
+
return :STOP if @data.length < length_num_bytes
|
|
102
|
+
|
|
103
|
+
string_length = @data[0..(length_num_bytes - 1)]
|
|
104
|
+
|
|
105
|
+
case length_num_bytes
|
|
106
|
+
when 1
|
|
107
|
+
string_length = string_length.unpack('C')[0] # UINT8
|
|
108
|
+
when 2
|
|
109
|
+
string_length = string_length.unpack('n')[0] # UINT16
|
|
110
|
+
when 4
|
|
111
|
+
string_length = string_length.unpack('N')[0] # UINT32
|
|
112
|
+
raise "Length value received larger than max_length: #{string_length} > #{@max_length}" if @max_length and string_length > @max_length
|
|
113
|
+
else
|
|
114
|
+
raise "Unsupported length given to read_length_field_followed_by_string: #{length_num_bytes}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Read String
|
|
118
|
+
return :STOP if @data.length < (string_length + length_num_bytes)
|
|
119
|
+
|
|
120
|
+
next_index = string_length + length_num_bytes
|
|
121
|
+
string = @data[length_num_bytes..(next_index - 1)]
|
|
122
|
+
|
|
123
|
+
# Remove data from current_data
|
|
124
|
+
@data.replace(@data[next_index..-1])
|
|
125
|
+
|
|
126
|
+
return string
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def reduce_to_single_packet
|
|
130
|
+
# Discard sync pattern if present
|
|
131
|
+
if @sync_pattern
|
|
132
|
+
if @reduction_state == :START
|
|
133
|
+
return :STOP if @data.length < @sync_pattern.length
|
|
134
|
+
|
|
135
|
+
@data.replace(@data[(@sync_pattern.length)..-1])
|
|
136
|
+
@reduction_state = :SYNC_REMOVED
|
|
137
|
+
end
|
|
138
|
+
elsif @reduction_state == :START
|
|
139
|
+
@reduction_state = :SYNC_REMOVED
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
if @reduction_state == :SYNC_REMOVED and @mode == 4
|
|
143
|
+
# Read and remove flags
|
|
144
|
+
return :STOP if @data.length < 1
|
|
145
|
+
|
|
146
|
+
flags = @data[0].unpack('C')[0] # byte
|
|
147
|
+
@data.replace(@data[1..-1])
|
|
148
|
+
@read_stored = false
|
|
149
|
+
@read_stored = true if (flags & COSMOS4_STORED_FLAG_MASK) != 0
|
|
150
|
+
@read_extra = nil
|
|
151
|
+
if (flags & COSMOS4_EXTRA_FLAG_MASK) != 0
|
|
152
|
+
@reduction_state = :NEED_EXTRA
|
|
153
|
+
else
|
|
154
|
+
@reduction_state = :FLAGS_REMOVED
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
if @reduction_state == :NEED_EXTRA
|
|
159
|
+
# Read and remove extra
|
|
160
|
+
@read_extra = read_length_field_followed_by_string(4)
|
|
161
|
+
return :STOP if @read_extra == :STOP
|
|
162
|
+
|
|
163
|
+
@read_extra = JSON.parse(@read_extra, :allow_nan => true, :create_additions => true)
|
|
164
|
+
@reduction_state = :FLAGS_REMOVED
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
if @reduction_state == :FLAGS_REMOVED or (@reduction_state == :SYNC_REMOVED and @mode != 4)
|
|
168
|
+
# Read and remove packet received time
|
|
169
|
+
return :STOP if @data.length < 8
|
|
170
|
+
|
|
171
|
+
time_seconds = @data[0..3].unpack('N')[0] # UINT32
|
|
172
|
+
time_microseconds = @data[4..7].unpack('N')[0] # UINT32
|
|
173
|
+
@read_received_time = Time.at(time_seconds, time_microseconds).sys
|
|
174
|
+
@data.replace(@data[8..-1])
|
|
175
|
+
@reduction_state = :TIME_REMOVED
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
if @reduction_state == :TIME_REMOVED
|
|
179
|
+
# Read and remove the target name
|
|
180
|
+
@read_target_name = read_length_field_followed_by_string(1)
|
|
181
|
+
return :STOP if @read_target_name == :STOP
|
|
182
|
+
|
|
183
|
+
@reduction_state = :TARGET_NAME_REMOVED
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
if @reduction_state == :TARGET_NAME_REMOVED
|
|
187
|
+
# Read and remove the packet name
|
|
188
|
+
@read_packet_name = read_length_field_followed_by_string(1)
|
|
189
|
+
return :STOP if @read_packet_name == :STOP
|
|
190
|
+
|
|
191
|
+
@reduction_state = :PACKET_NAME_REMOVED
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
if @reduction_state == :PACKET_NAME_REMOVED
|
|
195
|
+
# Read packet data and return
|
|
196
|
+
packet_data = read_length_field_followed_by_string(4)
|
|
197
|
+
return :STOP if packet_data == :STOP
|
|
198
|
+
|
|
199
|
+
@reduction_state = :START
|
|
200
|
+
return packet_data
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
raise "Error should never reach end of method #{@reduction_state}"
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
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 'thread'
|
|
22
|
+
|
|
23
|
+
module OpenC3
|
|
24
|
+
# Base class for all OpenC3 protocols which defines a framework which must be
|
|
25
|
+
# implemented by a subclass.
|
|
26
|
+
class Protocol
|
|
27
|
+
attr_accessor :interface
|
|
28
|
+
attr_accessor :allow_empty_data
|
|
29
|
+
|
|
30
|
+
# @param allow_empty_data [true/false/nil] Whether or not this protocol will allow an empty string
|
|
31
|
+
# to be passed down to later Protocols (instead of returning :STOP). Can be true, false, or nil, where
|
|
32
|
+
# nil is interpreted as true unless the Protocol is the last Protocol of the chain.
|
|
33
|
+
def initialize(allow_empty_data = nil)
|
|
34
|
+
@interface = nil
|
|
35
|
+
@allow_empty_data = ConfigParser.handle_true_false_nil(allow_empty_data)
|
|
36
|
+
reset()
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def reset
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def connect_reset
|
|
43
|
+
reset()
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def disconnect_reset
|
|
47
|
+
reset()
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Ensure we have some data in case this is the only protocol
|
|
51
|
+
def read_data(data)
|
|
52
|
+
if data.length <= 0
|
|
53
|
+
if @allow_empty_data.nil?
|
|
54
|
+
if @interface and @interface.read_protocols[-1] == self
|
|
55
|
+
# Last read interface in chain with auto @allow_empty_data
|
|
56
|
+
return :STOP
|
|
57
|
+
end
|
|
58
|
+
elsif !@allow_empty_data
|
|
59
|
+
# Don't @allow_empty_data means STOP
|
|
60
|
+
return :STOP
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
data
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def read_packet(packet)
|
|
67
|
+
return packet
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def write_packet(packet)
|
|
71
|
+
return packet
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def write_data(data)
|
|
75
|
+
return data
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def post_write_interface(packet, data)
|
|
79
|
+
return packet, data
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,261 @@
|
|
|
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/terminated_protocol'
|
|
22
|
+
require 'thread' # For Queue
|
|
23
|
+
require 'timeout' # For Timeout::Error
|
|
24
|
+
|
|
25
|
+
module OpenC3
|
|
26
|
+
# Protocol which delineates packets using delimiter characters. Designed for
|
|
27
|
+
# text based protocols which expect a command and send a response. The
|
|
28
|
+
# protocol handles sending the command and capturing the response.
|
|
29
|
+
class TemplateProtocol < TerminatedProtocol
|
|
30
|
+
# @param write_termination_characters (see TerminatedProtocol#initialize)
|
|
31
|
+
# @param read_termination_characters (see TerminatedProtocol#initialize)
|
|
32
|
+
# @param ignore_lines [Integer] Number of newline terminated reads to
|
|
33
|
+
# ignore when processing the response
|
|
34
|
+
# @param initial_read_delay [Integer] Initial delay when connecting before
|
|
35
|
+
# trying to read
|
|
36
|
+
# @param response_lines [Integer] Number of newline terminated lines which
|
|
37
|
+
# comprise the response
|
|
38
|
+
# @param strip_read_termination (see TerminatedProtocol#initialize)
|
|
39
|
+
# @param discard_leading_bytes (see TerminatedProtocol#initialize)
|
|
40
|
+
# @param sync_pattern (see TerminatedProtocol#initialize)
|
|
41
|
+
# @param fill_fields (see TerminatedProtocol#initialize)
|
|
42
|
+
# @param response_timeout [Float] Number of seconds to wait before timing out
|
|
43
|
+
# when waiting for a response
|
|
44
|
+
# @param response_polling_period [Float] Number of seconds to wait between polling
|
|
45
|
+
# for a response
|
|
46
|
+
# @param raise_exceptions [String] Whether to raise exceptions when errors
|
|
47
|
+
# occur in the protocol like unexpected responses or response timeouts.
|
|
48
|
+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
|
|
49
|
+
def initialize(
|
|
50
|
+
write_termination_characters,
|
|
51
|
+
read_termination_characters,
|
|
52
|
+
ignore_lines = 0,
|
|
53
|
+
initial_read_delay = nil,
|
|
54
|
+
response_lines = 1,
|
|
55
|
+
strip_read_termination = true,
|
|
56
|
+
discard_leading_bytes = 0,
|
|
57
|
+
sync_pattern = nil,
|
|
58
|
+
fill_fields = false,
|
|
59
|
+
response_timeout = 5.0,
|
|
60
|
+
response_polling_period = 0.02,
|
|
61
|
+
raise_exceptions = false,
|
|
62
|
+
allow_empty_data = nil
|
|
63
|
+
)
|
|
64
|
+
super(
|
|
65
|
+
write_termination_characters,
|
|
66
|
+
read_termination_characters,
|
|
67
|
+
strip_read_termination,
|
|
68
|
+
discard_leading_bytes,
|
|
69
|
+
sync_pattern,
|
|
70
|
+
fill_fields,
|
|
71
|
+
allow_empty_data)
|
|
72
|
+
@response_template = nil
|
|
73
|
+
@response_packet = nil
|
|
74
|
+
@response_target_name = nil
|
|
75
|
+
@response_packets = []
|
|
76
|
+
@write_block_queue = Queue.new
|
|
77
|
+
@ignore_lines = ignore_lines.to_i
|
|
78
|
+
@response_lines = response_lines.to_i
|
|
79
|
+
@initial_read_delay = ConfigParser.handle_nil(initial_read_delay)
|
|
80
|
+
@initial_read_delay = @initial_read_delay.to_f if @initial_read_delay
|
|
81
|
+
@response_timeout = ConfigParser.handle_nil(response_timeout)
|
|
82
|
+
@response_timeout = @response_timeout.to_f if @response_timeout
|
|
83
|
+
@response_polling_period = response_polling_period.to_f
|
|
84
|
+
@connect_complete_time = nil
|
|
85
|
+
@raise_exceptions = ConfigParser.handle_true_false(raise_exceptions)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def reset
|
|
89
|
+
super()
|
|
90
|
+
@initial_read_delay_needed = true
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def connect_reset
|
|
94
|
+
super()
|
|
95
|
+
begin
|
|
96
|
+
@write_block_queue.pop(true) while @write_block_queue.length > 0
|
|
97
|
+
rescue
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
@connect_complete_time = Time.now + @initial_read_delay if @initial_read_delay
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def disconnect_reset
|
|
104
|
+
super()
|
|
105
|
+
@write_block_queue << nil # Unblock the write block queue
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def read_data(data)
|
|
109
|
+
return super(data) if data.length <= 0
|
|
110
|
+
|
|
111
|
+
# Drop all data until the initial_read_delay is complete.
|
|
112
|
+
# This gets rid of unused welcome messages,
|
|
113
|
+
# prompts, and other junk on initial connections
|
|
114
|
+
if @initial_read_delay and @initial_read_delay_needed and @connect_complete_time
|
|
115
|
+
return :STOP if Time.now < @connect_complete_time
|
|
116
|
+
|
|
117
|
+
@initial_read_delay_needed = false
|
|
118
|
+
end
|
|
119
|
+
super(data)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def read_packet(packet)
|
|
123
|
+
if @response_template && @response_packet
|
|
124
|
+
# If lines make it this far they are part of a response
|
|
125
|
+
@response_packets << packet
|
|
126
|
+
return :STOP if @response_packets.length < (@ignore_lines + @response_lines)
|
|
127
|
+
|
|
128
|
+
@ignore_lines.times do
|
|
129
|
+
@response_packets.shift
|
|
130
|
+
end
|
|
131
|
+
response_string = ''
|
|
132
|
+
@response_lines.times do
|
|
133
|
+
response = @response_packets.shift
|
|
134
|
+
response_string << response.buffer
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Grab the response packet specified in the command
|
|
138
|
+
result_packet = System.telemetry.packet(@response_target_name, @response_packet).clone
|
|
139
|
+
result_packet.received_time = nil
|
|
140
|
+
result_packet.id_items.each do |item|
|
|
141
|
+
result_packet.write_item(item, item.id_value, :RAW)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Convert the response template into a Regexp
|
|
145
|
+
response_item_names = []
|
|
146
|
+
response_template = @response_template.clone
|
|
147
|
+
response_template_items = @response_template.scan(/<.*?>/)
|
|
148
|
+
|
|
149
|
+
response_template_items.each do |item|
|
|
150
|
+
response_item_names << item[1..-2]
|
|
151
|
+
response_template.gsub!(item, "(.*)")
|
|
152
|
+
end
|
|
153
|
+
response_regexp = Regexp.new(response_template)
|
|
154
|
+
|
|
155
|
+
# Scan the response for the variables in brackets <VARIABLE>
|
|
156
|
+
# Write the packet value with each of the values received
|
|
157
|
+
response_values = response_string.scan(response_regexp)[0]
|
|
158
|
+
if !response_values || (response_values.length != response_item_names.length)
|
|
159
|
+
handle_error("#{@interface ? @interface.name : ""}: Unexpected response: #{response_string}")
|
|
160
|
+
else
|
|
161
|
+
response_values.each_with_index do |value, i|
|
|
162
|
+
result_packet.write(response_item_names[i], value)
|
|
163
|
+
rescue => error
|
|
164
|
+
handle_error("#{@interface ? @interface.name : ""}: Could not write value #{value} due to #{error.message}")
|
|
165
|
+
break
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
@response_packets.clear
|
|
170
|
+
|
|
171
|
+
# Release the write
|
|
172
|
+
if @response_template && @response_packet
|
|
173
|
+
@write_block_queue << nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
return result_packet
|
|
177
|
+
else
|
|
178
|
+
return packet
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def write_packet(packet)
|
|
183
|
+
# Make sure we are past the initial data dropping period
|
|
184
|
+
if @initial_read_delay and @initial_read_delay_needed and @connect_complete_time and Time.now < @connect_complete_time
|
|
185
|
+
delay_needed = @connect_complete_time - Time.now
|
|
186
|
+
sleep(delay_needed) if delay_needed > 0
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# First grab the response template and response packet (if there is one)
|
|
190
|
+
begin
|
|
191
|
+
@response_template = packet.read("RSP_TEMPLATE").strip
|
|
192
|
+
@response_packet = packet.read("RSP_PACKET").strip
|
|
193
|
+
@response_target_name = packet.target_name
|
|
194
|
+
# If the template or packet are empty set them to nil. This allows for
|
|
195
|
+
# the user to remove the RSP_TEMPLATE and RSP_PACKET values and avoid
|
|
196
|
+
# any response timeouts
|
|
197
|
+
if @response_template.empty? || @response_packet.empty?
|
|
198
|
+
@response_template = nil
|
|
199
|
+
@response_packet = nil
|
|
200
|
+
@response_target_name = nil
|
|
201
|
+
end
|
|
202
|
+
rescue
|
|
203
|
+
# If there is no response template we set to nil
|
|
204
|
+
@response_template = nil
|
|
205
|
+
@response_packet = nil
|
|
206
|
+
@response_target_name = nil
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Grab the command template because that is all we eventually send
|
|
210
|
+
@template = packet.read("CMD_TEMPLATE")
|
|
211
|
+
# Create a new packet to populate with the template
|
|
212
|
+
raw_packet = Packet.new(nil, nil)
|
|
213
|
+
raw_packet.buffer = @template
|
|
214
|
+
raw_packet = super(raw_packet)
|
|
215
|
+
return raw_packet if Symbol === raw_packet
|
|
216
|
+
|
|
217
|
+
data = raw_packet.buffer(false)
|
|
218
|
+
# Scan the template for variables in brackets <VARIABLE>
|
|
219
|
+
# Read these values from the packet and substitute them in the template
|
|
220
|
+
# and in the @response_packet name
|
|
221
|
+
@template.scan(/<(.*?)>/).each do |variable|
|
|
222
|
+
value = packet.read(variable[0], :RAW).to_s
|
|
223
|
+
data.gsub!("<#{variable[0]}>", value)
|
|
224
|
+
@response_packet.gsub!("<#{variable[0]}>", value) if @response_packet
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
return raw_packet
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def post_write_interface(packet, data)
|
|
231
|
+
if @response_template && @response_packet
|
|
232
|
+
if @response_timeout
|
|
233
|
+
response_timeout_time = Time.now + @response_timeout
|
|
234
|
+
else
|
|
235
|
+
response_timeout_time = nil
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Block the write until the response is received
|
|
239
|
+
begin
|
|
240
|
+
@write_block_queue.pop(true)
|
|
241
|
+
rescue
|
|
242
|
+
sleep(@response_polling_period)
|
|
243
|
+
retry if !response_timeout_time
|
|
244
|
+
retry if response_timeout_time and Time.now < response_timeout_time
|
|
245
|
+
handle_error("#{@interface ? @interface.name : ""}: Timeout waiting for response")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
@response_template = nil
|
|
249
|
+
@response_packet = nil
|
|
250
|
+
@response_target_name = nil
|
|
251
|
+
@response_packets.clear
|
|
252
|
+
end
|
|
253
|
+
return super(packet, data)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def handle_error(msg)
|
|
257
|
+
Logger.error(msg)
|
|
258
|
+
raise msg if @raise_exceptions
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
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/burst_protocol'
|
|
22
|
+
|
|
23
|
+
module OpenC3
|
|
24
|
+
# Protocol which delineates packets using termination characters at
|
|
25
|
+
# the end of the data.
|
|
26
|
+
class TerminatedProtocol < BurstProtocol
|
|
27
|
+
# @param write_termination_characters [String] The characters to write
|
|
28
|
+
# after writing the Packet buffer. Must be given as a
|
|
29
|
+
# hexadecimal string such as '0xABCD'.
|
|
30
|
+
# @param read_termination_characters [String] The characters at the end of
|
|
31
|
+
# the data which delineate the end of a Packet. Must be given as a
|
|
32
|
+
# hexadecimal string such as '0xABCD'.
|
|
33
|
+
# @param strip_read_termination [Boolean] Whether to remove the
|
|
34
|
+
# read_termination_characters before turning the data into a
|
|
35
|
+
# Packet.
|
|
36
|
+
# @param discard_leading_bytes (see BurstProtocol#initialize)
|
|
37
|
+
# @param sync_pattern (see BurstProtocol#initialize)
|
|
38
|
+
# @param fill_fields (see BurstProtocol#initialize)
|
|
39
|
+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
|
|
40
|
+
def initialize(
|
|
41
|
+
write_termination_characters,
|
|
42
|
+
read_termination_characters,
|
|
43
|
+
strip_read_termination = true,
|
|
44
|
+
discard_leading_bytes = 0,
|
|
45
|
+
sync_pattern = nil,
|
|
46
|
+
fill_fields = false,
|
|
47
|
+
allow_empty_data = nil
|
|
48
|
+
)
|
|
49
|
+
@write_termination_characters = write_termination_characters.hex_to_byte_string
|
|
50
|
+
@read_termination_characters = read_termination_characters.hex_to_byte_string
|
|
51
|
+
@strip_read_termination = ConfigParser.handle_true_false(strip_read_termination)
|
|
52
|
+
|
|
53
|
+
super(discard_leading_bytes, sync_pattern, fill_fields, allow_empty_data)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def write_data(data)
|
|
57
|
+
raise "Packet contains termination characters!" if data.index(@write_termination_characters)
|
|
58
|
+
|
|
59
|
+
data = super(data)
|
|
60
|
+
@write_termination_characters.each_byte do |byte|
|
|
61
|
+
data << byte
|
|
62
|
+
end
|
|
63
|
+
return data
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
protected
|
|
67
|
+
|
|
68
|
+
def reduce_to_single_packet
|
|
69
|
+
index = @data.index(@read_termination_characters)
|
|
70
|
+
|
|
71
|
+
# Reduce to packet data and setup current_data for next packet
|
|
72
|
+
if index
|
|
73
|
+
if index > 0
|
|
74
|
+
if @strip_read_termination
|
|
75
|
+
packet_data = @data[0..(index - 1)]
|
|
76
|
+
else
|
|
77
|
+
packet_data = @data[0..(index + @read_termination_characters.length - 1)]
|
|
78
|
+
end
|
|
79
|
+
else # @data begins with the termination characters
|
|
80
|
+
if @strip_read_termination
|
|
81
|
+
packet_data = ''
|
|
82
|
+
else # Keep everything
|
|
83
|
+
packet_data = @data[0..(@read_termination_characters.length - 1)]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
@data.replace(@data[(index + @read_termination_characters.length)..-1])
|
|
87
|
+
return packet_data
|
|
88
|
+
else
|
|
89
|
+
return :STOP
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|