openc3 5.2.0 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/data/config/interface_modifiers.yaml +22 -4
- data/data/config/microservice.yaml +18 -0
- data/lib/openc3/api/interface_api.rb +12 -0
- data/lib/openc3/api/router_api.rb +14 -2
- data/lib/openc3/api/target_api.rb +24 -3
- data/lib/openc3/api/tlm_api.rb +3 -3
- data/lib/openc3/interfaces/interface.rb +27 -26
- data/lib/openc3/interfaces/mqtt_interface.rb +240 -0
- data/lib/openc3/interfaces/protocols/override_protocol.rb +2 -61
- data/lib/openc3/interfaces/protocols/protocol.rb +6 -1
- data/lib/openc3/interfaces/simulated_target_interface.rb +1 -3
- data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -11
- data/lib/openc3/interfaces.rb +2 -3
- data/lib/openc3/logs/buffered_packet_log_reader.rb +2 -2
- data/lib/openc3/microservices/interface_microservice.rb +47 -3
- data/lib/openc3/microservices/microservice.rb +6 -0
- data/lib/openc3/models/cvt_model.rb +103 -47
- data/lib/openc3/models/interface_model.rb +23 -0
- data/lib/openc3/models/microservice_model.rb +7 -0
- data/lib/openc3/models/model.rb +1 -1
- data/lib/openc3/models/secret_model.rb +53 -0
- data/lib/openc3/operators/microservice_operator.rb +25 -0
- data/lib/openc3/script/api_shared.rb +18 -2
- data/lib/openc3/topics/interface_topic.rb +16 -0
- data/lib/openc3/topics/router_topic.rb +16 -0
- data/lib/openc3/utilities/redis_secrets.rb +46 -0
- data/lib/openc3/utilities/secrets.rb +63 -0
- data/lib/openc3/version.rb +5 -5
- data/templates/plugin-template/README.md +4 -3
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 883789b740b96ae3fac34c78b5a643a2fa1fb087d601a0f87c46d0062eec3dec
|
4
|
+
data.tar.gz: 510b9f4c8f98735f033f6dd6d31ebd86ffaeb8df0664d77720e15a3df3df6dcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 999476145415b7f6b160319fee0f67174ad2cdf415ef3a87628177964e37bf690e5c368bf3da9c6a08ca663679999b71b3e7d4c176c2a302724073b7c5c8faca
|
7
|
+
data.tar.gz: 206852353795f779b2d8481f68bcf881c465ceaf3c6a48b852a61dab34275b7736249def97edd7932e7fa9286d71f07f210ca340c0363dbce30839504d548640
|
@@ -78,10 +78,6 @@ PROTOCOL:
|
|
78
78
|
Protocols can be either READ, WRITE, or READ_WRITE. READ protocols act on the data
|
79
79
|
received by the interface while write acts on the data before it is sent out. READ_WRITE applies
|
80
80
|
the protocol to both reading and writing.<br/><br/>
|
81
|
-
There is only one built in protocol implemented by override_protocol.rb.
|
82
|
-
This protocol allows for Scripts to use the override_tlm() and normalize_tlm() methods to permanently
|
83
|
-
change a telemetry value. Note, this differs from set_tlm() as set_tlm() is over-written by new
|
84
|
-
incoming telemetry.<br/><br/>
|
85
81
|
For information on creating your own custom protocol please see <a href="https://openc3.com/docs/v5/protocols">https://openc3.com/docs/v5/protocols</a>
|
86
82
|
since: 4.0.0
|
87
83
|
parameters:
|
@@ -116,3 +112,25 @@ OPTION:
|
|
116
112
|
required: false
|
117
113
|
description: Parameters to pass to the option
|
118
114
|
values: .*
|
115
|
+
SECRET:
|
116
|
+
summary: Define a secret needed by this interface
|
117
|
+
description: Defines a secret for this interface and optionally assigns its value to an option
|
118
|
+
parameters:
|
119
|
+
- name: Type
|
120
|
+
required: true
|
121
|
+
description:
|
122
|
+
ENV or FILE. ENV will mount the secret into an environment variable.
|
123
|
+
FILE mounts the secret into a file.
|
124
|
+
values: .*
|
125
|
+
- name: Secret Name
|
126
|
+
required: true
|
127
|
+
description: The name of the secret to retrieve
|
128
|
+
values: .*
|
129
|
+
- name: Environment Variable of File Path
|
130
|
+
required: true
|
131
|
+
description: Environment variable name or file path to store secret
|
132
|
+
values: .*
|
133
|
+
- name: Option Name
|
134
|
+
required: false
|
135
|
+
description: Interface option to pass the secret value
|
136
|
+
values: .*
|
@@ -88,3 +88,21 @@ MICROSERVICE:
|
|
88
88
|
required: false
|
89
89
|
description: Name of the container
|
90
90
|
values: .+
|
91
|
+
SECRET:
|
92
|
+
summary: Define a secret needed by this microservice
|
93
|
+
description: Defines a secret for this microservice
|
94
|
+
parameters:
|
95
|
+
- name: Type
|
96
|
+
required: true
|
97
|
+
description:
|
98
|
+
ENV or FILE. ENV will mount the secret into an environment variable.
|
99
|
+
FILE mounts the secret into a file.
|
100
|
+
values: .*
|
101
|
+
- name: Secret Name
|
102
|
+
required: true
|
103
|
+
description: The name of the secret to retrieve
|
104
|
+
values: .*
|
105
|
+
- name: Environment Variable of File Path
|
106
|
+
required: true
|
107
|
+
description: Environment variable name or file path to store secret
|
108
|
+
values: .*
|
@@ -36,6 +36,8 @@ module OpenC3
|
|
36
36
|
'stop_raw_logging_interface',
|
37
37
|
'get_all_interface_info',
|
38
38
|
'map_target_to_interface',
|
39
|
+
'interface_cmd',
|
40
|
+
'interface_protocol_cmd'
|
39
41
|
])
|
40
42
|
|
41
43
|
# Get information about an interface
|
@@ -139,5 +141,15 @@ module OpenC3
|
|
139
141
|
end
|
140
142
|
nil
|
141
143
|
end
|
144
|
+
|
145
|
+
def interface_cmd(interface_name, cmd_name, *cmd_params, scope: $openc3_scope, token: $openc3_token)
|
146
|
+
authorize(permission: 'system_set', interface_name: interface_name, scope: scope, token: token)
|
147
|
+
InterfaceTopic.interface_cmd(interface_name, cmd_name, *cmd_params, scope: scope)
|
148
|
+
end
|
149
|
+
|
150
|
+
def interface_protocol_cmd(interface_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope: $openc3_scope, token: $openc3_token)
|
151
|
+
authorize(permission: 'system_set', interface_name: interface_name, scope: scope, token: token)
|
152
|
+
InterfaceTopic.protocol_cmd(interface_name, cmd_name, *cmd_params, read_write: read_write, index: index, scope: scope)
|
153
|
+
end
|
142
154
|
end
|
143
155
|
end
|
@@ -35,6 +35,8 @@ module OpenC3
|
|
35
35
|
'start_raw_logging_router',
|
36
36
|
'stop_raw_logging_router',
|
37
37
|
'get_all_router_info',
|
38
|
+
'router_cmd',
|
39
|
+
'router_protocol_cmd'
|
38
40
|
])
|
39
41
|
|
40
42
|
# Get information about a router
|
@@ -74,7 +76,7 @@ module OpenC3
|
|
74
76
|
|
75
77
|
# Starts raw logging for a router
|
76
78
|
#
|
77
|
-
# @param router_name [String] The name of the
|
79
|
+
# @param router_name [String] The name of the router
|
78
80
|
def start_raw_logging_router(router_name = 'ALL', scope: $openc3_scope, token: $openc3_token)
|
79
81
|
authorize(permission: 'system_set', router_name: router_name, scope: scope, token: token)
|
80
82
|
if router_name == 'ALL'
|
@@ -88,7 +90,7 @@ module OpenC3
|
|
88
90
|
|
89
91
|
# Stop raw logging for a router
|
90
92
|
#
|
91
|
-
# @param router_name [String] The name of the
|
93
|
+
# @param router_name [String] The name of the router
|
92
94
|
def stop_raw_logging_router(router_name = 'ALL', scope: $openc3_scope, token: $openc3_token)
|
93
95
|
authorize(permission: 'system_set', router_name: router_name, scope: scope, token: token)
|
94
96
|
if router_name == 'ALL'
|
@@ -116,5 +118,15 @@ module OpenC3
|
|
116
118
|
info.sort! { |a, b| a[0] <=> b[0] }
|
117
119
|
info
|
118
120
|
end
|
121
|
+
|
122
|
+
def router_cmd(router_name, cmd_name, *cmd_params, scope: $openc3_scope, token: $openc3_token)
|
123
|
+
authorize(permission: 'system_set', router_name: router_name, scope: scope, token: token)
|
124
|
+
RouterTopic.router_cmd(router_name, cmd_name, *cmd_params, scope: scope)
|
125
|
+
end
|
126
|
+
|
127
|
+
def router_protocol_cmd(router_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope: $openc3_scope, token: $openc3_token)
|
128
|
+
authorize(permission: 'system_set', router_name: router_name, scope: scope, token: token)
|
129
|
+
RouterTopic.protocol_cmd(router_name, cmd_name, *cmd_params, read_write: read_write, index: index, scope: scope)
|
130
|
+
end
|
119
131
|
end
|
120
132
|
end
|
@@ -28,7 +28,8 @@ module OpenC3
|
|
28
28
|
WHITELIST.concat([
|
29
29
|
'get_target_list',
|
30
30
|
'get_target',
|
31
|
-
'
|
31
|
+
'get_target_interfaces',
|
32
|
+
'get_all_target_info', # DEPRECATED
|
32
33
|
])
|
33
34
|
|
34
35
|
# Returns the list of all target names
|
@@ -49,9 +50,29 @@ module OpenC3
|
|
49
50
|
TargetModel.get(name: target_name, scope: scope)
|
50
51
|
end
|
51
52
|
|
52
|
-
# Get
|
53
|
+
# Get all targets and their interfaces
|
53
54
|
#
|
54
|
-
# @return [Array<Array<String,
|
55
|
+
# @return [Array<Array<String, String] Array of Arrays \[name, interfaces]
|
56
|
+
def get_target_interfaces(scope: $openc3_scope, token: $openc3_token)
|
57
|
+
authorize(permission: 'system', scope: scope, token: token)
|
58
|
+
info = []
|
59
|
+
interfaces = InterfaceModel.all(scope: scope)
|
60
|
+
get_target_list(scope: scope, token: token).each do |target_name|
|
61
|
+
interface_names = []
|
62
|
+
interfaces.each do |name, interface|
|
63
|
+
if interface['target_names'].include? target_name
|
64
|
+
interface_names << interface['name']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
info << [target_name, interface_names.join(",")]
|
68
|
+
end
|
69
|
+
info
|
70
|
+
end
|
71
|
+
|
72
|
+
# DEPRECATED: Get information about all targets
|
73
|
+
# Warning this call can take a long time with many defined packets
|
74
|
+
#
|
75
|
+
# @return [Array<Array<String, String, Numeric, Numeric>] Array of Arrays \[name, interface, cmd_cnt, tlm_cnt]
|
55
76
|
def get_all_target_info(scope: $openc3_scope, token: $openc3_token)
|
56
77
|
authorize(permission: 'system', scope: scope, token: token)
|
57
78
|
info = []
|
data/lib/openc3/api/tlm_api.rb
CHANGED
@@ -161,8 +161,8 @@ module OpenC3
|
|
161
161
|
# @param args The args must either be a string followed by a value or
|
162
162
|
# three strings followed by a value (see the calling style in the
|
163
163
|
# description).
|
164
|
-
# @param type [Symbol] Telemetry type, :RAW, :CONVERTED
|
165
|
-
def override_tlm(*args, type: :
|
164
|
+
# @param type [Symbol] Telemetry type, :ALL (default), :RAW, :CONVERTED, :FORMATTED, :WITH_UNITS
|
165
|
+
def override_tlm(*args, type: :ALL, scope: $openc3_scope, token: $openc3_token)
|
166
166
|
target_name, packet_name, item_name, value = set_tlm_process_args(args, __method__, scope: scope)
|
167
167
|
authorize(permission: 'tlm_set', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
168
168
|
CvtModel.override(target_name, packet_name, item_name, value, type: type.intern, scope: scope)
|
@@ -179,7 +179,7 @@ module OpenC3
|
|
179
179
|
#
|
180
180
|
# @param args The args must either be a string or three strings
|
181
181
|
# (see the calling style in the description).
|
182
|
-
# @param type [Symbol] Telemetry type, :RAW, :CONVERTED
|
182
|
+
# @param type [Symbol] Telemetry type, :ALL (default), :RAW, :CONVERTED, :FORMATTED, :WITH_UNITS
|
183
183
|
# Also takes :ALL which means to normalize all telemetry types
|
184
184
|
def normalize_tlm(*args, type: :ALL, scope: $openc3_scope, token: $openc3_token)
|
185
185
|
target_name, packet_name, item_name = tlm_process_args(args, __method__, scope: scope)
|
@@ -22,6 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'openc3/api/api'
|
24
24
|
require 'openc3/io/raw_logger_pair'
|
25
|
+
require 'openc3/utilities/secrets'
|
25
26
|
|
26
27
|
module OpenC3
|
27
28
|
# Defines all the attributes and methods common to all interface classes
|
@@ -112,9 +113,6 @@ module OpenC3
|
|
112
113
|
# @return [Array<[Protocol Class, Protocol Args, Protocol kind (:READ, :WRITE, :READ_WRITE)>] Info to recreate protocols
|
113
114
|
attr_accessor :protocol_info
|
114
115
|
|
115
|
-
# @return [Hash or nil] Hash of overridden telemetry points
|
116
|
-
attr_accessor :override_tlm
|
117
|
-
|
118
116
|
# @return [String] Most recently read raw data
|
119
117
|
attr_accessor :read_raw_data
|
120
118
|
|
@@ -134,6 +132,9 @@ module OpenC3
|
|
134
132
|
# (when used as a BridgeRouter)
|
135
133
|
attr_accessor :interfaces
|
136
134
|
|
135
|
+
# @return [Secrets] Interface secrets manager class
|
136
|
+
attr_accessor :secrets
|
137
|
+
|
137
138
|
# Initialize default attribute values
|
138
139
|
def initialize
|
139
140
|
@name = self.class.to_s.split("::")[-1] # Remove namespacing if present
|
@@ -166,13 +167,13 @@ module OpenC3
|
|
166
167
|
@read_protocols = []
|
167
168
|
@write_protocols = []
|
168
169
|
@protocol_info = []
|
169
|
-
@override_tlm = nil
|
170
170
|
@read_raw_data = ''
|
171
171
|
@written_raw_data = ''
|
172
172
|
@read_raw_data_time = nil
|
173
173
|
@written_raw_data_time = nil
|
174
174
|
@config_params = []
|
175
175
|
@interfaces = []
|
176
|
+
@secrets = Secrets.getClient
|
176
177
|
end
|
177
178
|
|
178
179
|
# Connects the interface to its target(s). Must be implemented by a
|
@@ -406,13 +407,13 @@ module OpenC3
|
|
406
407
|
# num_clients is per interface so don't copy
|
407
408
|
# read_queue_size is the number of packets in the queue so don't copy
|
408
409
|
# write_queue_size is the number of packets in the queue so don't copy
|
409
|
-
|
410
|
+
self.options.each do |option_name, option_values|
|
411
|
+
other_interface.set_option(option_name, option_values)
|
412
|
+
end
|
410
413
|
other_interface.protocol_info = []
|
411
414
|
self.protocol_info.each do |protocol_class, protocol_args, read_write|
|
412
415
|
other_interface.add_protocol(protocol_class, protocol_args, read_write)
|
413
416
|
end
|
414
|
-
other_interface.override_tlm = nil
|
415
|
-
other_interface.override_tlm = self.override_tlm.clone if self.override_tlm
|
416
417
|
end
|
417
418
|
|
418
419
|
# Set an interface or router specific option
|
@@ -484,28 +485,28 @@ module OpenC3
|
|
484
485
|
protocol.interface = self
|
485
486
|
end
|
486
487
|
|
487
|
-
def
|
488
|
-
|
488
|
+
def interface_cmd(cmd_name, *cmd_args)
|
489
|
+
# Default do nothing - Implemented by subclasses
|
490
|
+
return false
|
489
491
|
end
|
490
492
|
|
491
|
-
def
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
493
|
+
def protocol_cmd(cmd_name, *cmd_args, read_write: :READ_WRITE, index: -1)
|
494
|
+
read_write = read_write.to_s.upcase.intern
|
495
|
+
protocols = nil
|
496
|
+
case read_write
|
497
|
+
when :READ, :READ_WRITE
|
498
|
+
protocols = @read_protocols
|
499
|
+
when :WRITE
|
500
|
+
protocols = @write_protocols.reverse # Reverse so ordering matches configuration ordering
|
501
|
+
else
|
502
|
+
raise "Unknown protocol descriptor: #{read_write}. Must be :READ, :WRITE, or :READ_WRITE."
|
501
503
|
end
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
@override_tlm[target_name][packet_name][item_name] = [value, type]
|
504
|
+
handled = false
|
505
|
+
protocols.each_with_index do |protocol, protocol_index|
|
506
|
+
result = protocol.protocol_cmd(cmd_name, @cmd_args) if index == protocol_index or index == -1
|
507
|
+
handled = true if result
|
508
|
+
end
|
509
|
+
return handled
|
509
510
|
end
|
510
511
|
end
|
511
512
|
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 OpenC3, Inc.
|
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
|
+
# This file may also be used under the terms of a commercial license
|
17
|
+
# if purchased from OpenC3, Inc.
|
18
|
+
|
19
|
+
# You can quickly setup an unauthenticated MQTT server in Docker with
|
20
|
+
# docker run -it -p 1883:1883 eclipse-mosquitto:2.0.15 mosquitto -c /mosquitto-no-auth.conf
|
21
|
+
|
22
|
+
require 'openc3/interfaces/interface'
|
23
|
+
require 'openc3/config/config_parser'
|
24
|
+
require 'mqtt'
|
25
|
+
|
26
|
+
# Patches to the Ruby MQTT library so that it will work reliably with COSMOS
|
27
|
+
saved_verbose = $VERBOSE
|
28
|
+
$VERBOSE = nil
|
29
|
+
module MQTT
|
30
|
+
class Client
|
31
|
+
def get(topic = nil, options = {})
|
32
|
+
if block_given?
|
33
|
+
get_packet(topic) do |packet|
|
34
|
+
yield(packet.topic, packet.payload) unless packet.retain && options[:omit_retained]
|
35
|
+
end
|
36
|
+
else
|
37
|
+
loop do
|
38
|
+
# Wait for one packet to be available
|
39
|
+
packet = get_packet(topic)
|
40
|
+
return nil unless packet # Patch for COSMOS
|
41
|
+
return packet.topic, packet.payload unless packet.retain && options[:omit_retained]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_packet(topic = nil)
|
47
|
+
# Subscribe to a topic, if an argument is given
|
48
|
+
subscribe(topic) unless topic.nil?
|
49
|
+
|
50
|
+
if block_given?
|
51
|
+
# Loop forever!
|
52
|
+
loop do
|
53
|
+
packet = @read_queue.pop
|
54
|
+
return nil unless packet # Patch for COSMOS
|
55
|
+
yield(packet)
|
56
|
+
puback_packet(packet) if packet.qos > 0
|
57
|
+
end
|
58
|
+
else
|
59
|
+
# Wait for one packet to be available
|
60
|
+
packet = @read_queue.pop
|
61
|
+
return nil unless packet # Patch for COSMOS
|
62
|
+
puback_packet(packet) if packet.qos > 0
|
63
|
+
return packet
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def disconnect(send_msg = true)
|
68
|
+
# Stop reading packets from the socket first
|
69
|
+
@read_thread.kill if @read_thread && @read_thread.alive?
|
70
|
+
@read_thread = nil
|
71
|
+
|
72
|
+
@read_queue << nil # Patch for COSMOS
|
73
|
+
|
74
|
+
# Close the socket if it is open
|
75
|
+
if connected?
|
76
|
+
if send_msg
|
77
|
+
packet = MQTT::Packet::Disconnect.new
|
78
|
+
send_packet(packet)
|
79
|
+
end
|
80
|
+
@socket.close unless @socket.nil?
|
81
|
+
@socket = nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
$VERBOSE = saved_verbose
|
88
|
+
|
89
|
+
module OpenC3
|
90
|
+
# Base class for interfaces that send and receive messages over MQTT
|
91
|
+
class MqttInterface < Interface
|
92
|
+
# @param hostname [String] MQTT server to connect to
|
93
|
+
# @param port [Integer] MQTT port
|
94
|
+
# @param ssl [Boolean] Use SSL true/false
|
95
|
+
def initialize(hostname, port = 1883, ssl = false)
|
96
|
+
super()
|
97
|
+
@hostname = hostname
|
98
|
+
@port = Integer(port)
|
99
|
+
@ssl = ConfigParser.handle_true_false(ssl)
|
100
|
+
@username = nil
|
101
|
+
@password = nil
|
102
|
+
@cert = nil
|
103
|
+
@key = nil
|
104
|
+
@ca_file = nil
|
105
|
+
|
106
|
+
@write_topics = []
|
107
|
+
@read_topics = []
|
108
|
+
|
109
|
+
# Build list of packets by topic
|
110
|
+
@read_packets_by_topic = {}
|
111
|
+
System.telemetry.all.each do |target_name, target_packets|
|
112
|
+
target_packets.each do |packet_name, packet|
|
113
|
+
topics = packet.meta['TOPIC']
|
114
|
+
topics = packet.meta['TOPICS'] unless topics
|
115
|
+
if topics
|
116
|
+
topics.each do |topic|
|
117
|
+
@read_packets_by_topic[topic] = packet
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Connects the interface to its target(s)
|
125
|
+
def connect
|
126
|
+
@write_topics = []
|
127
|
+
@read_topics = []
|
128
|
+
@client = MQTT::Client.new
|
129
|
+
@client.host = @hostname
|
130
|
+
@client.port = @port
|
131
|
+
@client.ssl = @ssl
|
132
|
+
@client.username = @username if @username
|
133
|
+
@client.password = @password if @password
|
134
|
+
@client.cert = @cert if @cert
|
135
|
+
@client.key = @key if @key
|
136
|
+
@client.ca_file = @ca_file.path if @ca_file
|
137
|
+
@client.connect
|
138
|
+
@read_packets_by_topic.each do |topic, _|
|
139
|
+
Logger.info "#{@name}: Subscribing to #{topic}"
|
140
|
+
@client.subscribe(topic)
|
141
|
+
end
|
142
|
+
super()
|
143
|
+
end
|
144
|
+
|
145
|
+
# @return [Boolean] Whether the active ports (read and/or write) have
|
146
|
+
# created sockets. Since UDP is connectionless, creation of the sockets
|
147
|
+
# is used to determine connection.
|
148
|
+
def connected?
|
149
|
+
if @client
|
150
|
+
return @client.connected?
|
151
|
+
else
|
152
|
+
return false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Disconnects the interface from its target(s)
|
157
|
+
def disconnect
|
158
|
+
@client.disconnect
|
159
|
+
@client = nil
|
160
|
+
super()
|
161
|
+
end
|
162
|
+
|
163
|
+
def read
|
164
|
+
topic = @read_topics.shift
|
165
|
+
packet = super()
|
166
|
+
return nil unless packet
|
167
|
+
identified_packet = @read_packets_by_topic[topic]
|
168
|
+
if identified_packet
|
169
|
+
identified_packet = identified_packet.dup
|
170
|
+
identified_packet.buffer = packet.buffer
|
171
|
+
packet = identified_packet
|
172
|
+
end
|
173
|
+
packet.received_time = nil
|
174
|
+
return packet
|
175
|
+
end
|
176
|
+
|
177
|
+
def write(packet)
|
178
|
+
topics = packet.meta['TOPIC']
|
179
|
+
topics = packet.meta['TOPICS'] unless topics
|
180
|
+
if topics
|
181
|
+
topics.each do |topic|
|
182
|
+
@write_topics << topic
|
183
|
+
super(packet)
|
184
|
+
end
|
185
|
+
else
|
186
|
+
raise "Command packet #{packet.target_name} #{packet.packet_name} requires a META TOPIC or TOPICS"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Reads from the socket if the read_port is defined
|
191
|
+
def read_interface
|
192
|
+
topic, data = @client.get
|
193
|
+
if data.nil? or data.length <= 0
|
194
|
+
Logger.info "#{@name}: read returned nil" if data.nil?
|
195
|
+
Logger.info "#{@name}: read returned 0 bytes" if not data.nil? and data.length <= 0
|
196
|
+
return nil
|
197
|
+
end
|
198
|
+
@read_topics << topic
|
199
|
+
read_interface_base(data)
|
200
|
+
return data
|
201
|
+
rescue IOError # Disconnected
|
202
|
+
return nil
|
203
|
+
end
|
204
|
+
|
205
|
+
# Writes to the socket
|
206
|
+
# @param data [String] Raw packet data
|
207
|
+
def write_interface(data)
|
208
|
+
write_interface_base(data)
|
209
|
+
topic = @write_topics.shift
|
210
|
+
@client.publish(topic, data)
|
211
|
+
data
|
212
|
+
end
|
213
|
+
|
214
|
+
# Supported Options
|
215
|
+
# USERNAME - Username for Mqtt Server
|
216
|
+
# PASSWORD - Password for Mqtt Server
|
217
|
+
# CERT - Public Key for Client Cert Auth
|
218
|
+
# KEY - Private Key for Client Cert Auth
|
219
|
+
# CA_FILE - Certificate Authority for Client Cert Auth
|
220
|
+
# (see Interface#set_option)
|
221
|
+
def set_option(option_name, option_values)
|
222
|
+
super(option_name, option_values)
|
223
|
+
case option_name.upcase
|
224
|
+
when 'USERNAME'
|
225
|
+
@username = option_values[0]
|
226
|
+
when 'PASSWORD'
|
227
|
+
@password = option_values[0]
|
228
|
+
when 'CERT'
|
229
|
+
@cert = option_values[0]
|
230
|
+
when 'KEY'
|
231
|
+
@key = option_values[0]
|
232
|
+
when 'CA_FILE'
|
233
|
+
# CA_FILE must be given as a file
|
234
|
+
@ca_file = Tempfile.new('ca_file')
|
235
|
+
@ca_file.write(option_values[0])
|
236
|
+
@ca_file.close
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -1,63 +1,4 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# This program is free software; you can modify and/or redistribute it
|
7
|
-
# under the terms of the GNU Affero General Public License
|
8
|
-
# as published by the Free Software Foundation; version 3 with
|
9
|
-
# attribution addendums as found in the LICENSE.txt
|
10
|
-
#
|
11
|
-
# This program is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
# GNU Affero General Public License for more details.
|
15
|
-
|
16
|
-
# Modified by OpenC3, Inc.
|
17
|
-
# All changes Copyright 2022, OpenC3, Inc.
|
18
|
-
# All Rights Reserved
|
19
|
-
#
|
20
|
-
# This file may also be used under the terms of a commercial license
|
21
|
-
# if purchased from OpenC3, Inc.
|
22
|
-
|
23
|
-
require 'openc3/interfaces/protocols/protocol'
|
24
|
-
|
25
|
-
module OpenC3
|
26
|
-
# Protocol which permanently overrides an item value such that reading the
|
27
|
-
# item returns the overriden value. Methods are prefixed with underscores
|
28
|
-
# so the API can include the original name which calls out to these
|
29
|
-
# methods. Clearing the override requires calling normalize_tlm.
|
30
|
-
class OverrideProtocol < Protocol
|
31
|
-
# @param allow_empty_data [true/false/nil] See Protocol#initialize
|
32
|
-
def initialize(allow_empty_data = nil)
|
33
|
-
super(allow_empty_data)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Called to perform modifications on a read packet before it is given to the user
|
37
|
-
#
|
38
|
-
# @param packet [Packet] Original packet
|
39
|
-
# @return [Packet] Potentially modified packet
|
40
|
-
def read_packet(packet)
|
41
|
-
if @interface.override_tlm && !@interface.override_tlm.empty?
|
42
|
-
# Need to make sure packet is identified and defined
|
43
|
-
target_names = nil
|
44
|
-
target_names = @interface.tlm_target_names if @interface
|
45
|
-
identified_packet = System.telemetry.identify_and_define_packet(packet, target_names)
|
46
|
-
if identified_packet
|
47
|
-
packet = identified_packet
|
48
|
-
packets = @interface.override_tlm[packet.target_name]
|
49
|
-
if packets
|
50
|
-
items = packets[packet.packet_name]
|
51
|
-
if items
|
52
|
-
items.each do |item_name, value|
|
53
|
-
# This should be safe because we check at the API level it exists
|
54
|
-
packet.write(item_name, value[0], value[1])
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
return packet
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
3
|
+
# This class is deprecated and this file exists only to satisfy existing code requiring it
|
4
|
+
# TODO: Remove this in a future release
|
@@ -17,7 +17,7 @@
|
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
|
-
# This file may also be used under the terms of a commercial license
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
require 'openc3/config/config_parser'
|
@@ -81,5 +81,10 @@ module OpenC3
|
|
81
81
|
def post_write_interface(packet, data)
|
82
82
|
return packet, data
|
83
83
|
end
|
84
|
+
|
85
|
+
def protocol_cmd(cmd_name, *cmd_args)
|
86
|
+
# Default do nothing - Implemented by subclasses
|
87
|
+
return false
|
88
|
+
end
|
84
89
|
end
|
85
90
|
end
|
@@ -17,11 +17,10 @@
|
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
|
-
# This file may also be used under the terms of a commercial license
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
require 'openc3/interfaces/interface'
|
24
|
-
require 'openc3/interfaces/protocols/override_protocol'
|
25
24
|
|
26
25
|
module OpenC3
|
27
26
|
# An interface class that provides simulated telemetry and command responses
|
@@ -38,7 +37,6 @@ module OpenC3
|
|
38
37
|
@sim_target = nil
|
39
38
|
@write_raw_allowed = false
|
40
39
|
@raw_logger_pair = nil
|
41
|
-
add_protocol(OverrideProtocol, [], :READ)
|
42
40
|
end
|
43
41
|
|
44
42
|
# Initialize the simulated target object and "connect" to the target
|