openc3 5.2.0 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- 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
|