openc3 5.15.1 → 5.16.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.

Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Rakefile +1 -0
  4. data/bin/openc3cli +20 -0
  5. data/bin/pipinstall +3 -0
  6. data/data/config/interface_modifiers.yaml +4 -1
  7. data/data/config/telemetry_modifiers.yaml +6 -1
  8. data/data/config/widgets.yaml +1 -1
  9. data/ext/openc3/ext/burst_protocol/burst_protocol.c +317 -0
  10. data/ext/openc3/ext/burst_protocol/extconf.rb +13 -0
  11. data/lib/openc3/accessors/accessor.rb +1 -1
  12. data/lib/openc3/accessors/json_accessor.rb +11 -3
  13. data/lib/openc3/api/tlm_api.rb +1 -1
  14. data/lib/openc3/interfaces/http_client_interface.rb +8 -4
  15. data/lib/openc3/interfaces/http_server_interface.rb +22 -6
  16. data/lib/openc3/interfaces/interface.rb +6 -0
  17. data/lib/openc3/interfaces/linc_interface.rb +5 -3
  18. data/lib/openc3/interfaces/mqtt_interface.rb +7 -3
  19. data/lib/openc3/interfaces/mqtt_stream_interface.rb +8 -1
  20. data/lib/openc3/interfaces/protocols/burst_protocol.rb +104 -100
  21. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +11 -3
  22. data/lib/openc3/interfaces/serial_interface.rb +16 -1
  23. data/lib/openc3/interfaces/simulated_target_interface.rb +7 -3
  24. data/lib/openc3/interfaces/tcpip_client_interface.rb +18 -1
  25. data/lib/openc3/interfaces/tcpip_server_interface.rb +24 -15
  26. data/lib/openc3/interfaces/udp_interface.rb +11 -1
  27. data/lib/openc3/io/posix_serial_driver.rb +20 -5
  28. data/lib/openc3/logs/packet_log_writer.rb +1 -1
  29. data/lib/openc3/microservices/decom_microservice.rb +3 -2
  30. data/lib/openc3/microservices/interface_microservice.rb +5 -5
  31. data/lib/openc3/models/activity_model.rb +104 -40
  32. data/lib/openc3/models/gem_model.rb +1 -1
  33. data/lib/openc3/models/plugin_model.rb +5 -3
  34. data/lib/openc3/models/python_package_model.rb +15 -5
  35. data/lib/openc3/models/scope_model.rb +1 -1
  36. data/lib/openc3/models/target_model.rb +1 -1
  37. data/lib/openc3/packets/packet.rb +27 -24
  38. data/lib/openc3/packets/packet_config.rb +18 -1
  39. data/lib/openc3/packets/parsers/packet_item_parser.rb +10 -6
  40. data/lib/openc3/packets/structure.rb +7 -7
  41. data/lib/openc3/packets/structure_item.rb +4 -2
  42. data/lib/openc3/script/api_shared.rb +33 -29
  43. data/lib/openc3/script/plugins.rb +13 -13
  44. data/lib/openc3/script/storage.rb +3 -4
  45. data/lib/openc3/script/web_socket_api.rb +10 -0
  46. data/lib/openc3/version.rb +6 -6
  47. data/templates/target/targets/TARGET/lib/target.py +2 -0
  48. data/templates/tool_angular/package.json +8 -8
  49. data/templates/tool_react/package.json +2 -2
  50. data/templates/tool_svelte/build/smui.css +1 -5
  51. data/templates/tool_svelte/package.json +3 -3
  52. data/templates/tool_vue/package.json +12 -12
  53. data/templates/widget/package.json +11 -11
  54. metadata +21 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e965c2b2463c93d4f1831b6d6cdfc53cae47bac8297e4335be407e420b37545e
4
- data.tar.gz: 1f4a4d4f367daf99411d70d693f511a6550f911787d46f0602e6bc440edc19c5
3
+ metadata.gz: af3e74fa7b78038906c1b2120e62aa7a9b3d835effe03dbd96e500d737a443cb
4
+ data.tar.gz: 8bba305bdd1ac061300aa8676564c0966cf01d68df8da86adfc5bf05d873165f
5
5
  SHA512:
6
- metadata.gz: 37956addc6a7019369e710ea02fcf8c71b114b049e83eeef7b7a0c2e99f17c2f685311db55697cb31a518bea8cc815647d370d0bdb9640259d76df86b79dff9a
7
- data.tar.gz: f90a6beae03680d8fdc256ea2bf4dc937667a4a9d29bc6d3daccd33de02ea485ce808a52ed73a1ce251e0a9a7dc9ef3e9ccf1acdbe5ab8fa360f2dfbfbb104d8
6
+ metadata.gz: '09554021246cc00fca2b1f32e627274eca5ff5ea6fa5851175e2b86cba6b9ff07ef5a05e4cc13a40ee6239793d74557d956384b8fb25acf267721b21208c2fa1'
7
+ data.tar.gz: 6db1a30df9c512df371b69240649947fd40ec78409d94bf7ff466096180c4ebf39958d2247b15e8b50e5a84b4fa066e461e38bad5fa8cc0bc1f7d4b8982112ab
data/Gemfile CHANGED
@@ -8,7 +8,7 @@ gemspec :name => 'openc3'
8
8
 
9
9
  # Include the rails gems for the convenience of custom microservice plugins
10
10
  gem 'bootsnap', '>= 1.9.3', require: false
11
- gem 'mock_redis', '0.41'
11
+ gem 'mock_redis', '0.44'
12
12
  gem 'rack-cors', '~> 2.0'
13
13
  gem 'rails', '~> 7.1.0'
14
14
  gem 'rspec-rails', '~> 6.0'
data/Rakefile CHANGED
@@ -53,6 +53,7 @@ task :build => [:devkit] do
53
53
  shared_extension = 'bundle' if /darwin/.match?(platform)
54
54
 
55
55
  extensions = [
56
+ 'burst_protocol',
56
57
  'crc',
57
58
  'polynomial_conversion',
58
59
  'config_parser',
data/bin/openc3cli CHANGED
@@ -66,6 +66,7 @@ def print_usage
66
66
  puts " cli irb # Runs irb in the local directory"
67
67
  puts " cli validate /PATH/FILENAME.gem SCOPE variables.txt # Validate a COSMOS plugin gem file"
68
68
  puts " cli load /PATH/FILENAME.gem SCOPE variables.txt # Loads a COSMOS plugin gem file"
69
+ puts " cli list <SCOPE> # Lists installed plugins, SCOPE is DEFAULT if not given"
69
70
  puts " cli generate TYPE OPTIONS # Generate various COSMOS entities"
70
71
  puts " OPTIONS: --ruby or --python to specify the language in the generated code"
71
72
  puts " #{MIGRATE_PARSER}"
@@ -381,6 +382,22 @@ def wait_process_complete(process_name)
381
382
  end
382
383
  end
383
384
 
385
+ # Outputs list of installed plugins
386
+ def list_plugins(scope:)
387
+ scope ||= 'DEFAULT'
388
+ check_environment()
389
+ names = []
390
+ if $openc3_in_cluster
391
+ names = OpenC3::PluginModel.names(scope: scope)
392
+ else
393
+ require 'openc3/script'
394
+ names = plugin_list(scope: scope)
395
+ end
396
+ names.each do |name|
397
+ puts name
398
+ end
399
+ end
400
+
384
401
  # Loads a plugin into the OpenC3 system
385
402
  # This code is used from the command line and is the same code that gets called if you
386
403
  # edit/upgrade or install a new plugin from the Admin interface
@@ -655,6 +672,9 @@ if not ARGV[0].nil? # argument(s) given
655
672
  # See plugins_controller.rb install for usage
656
673
  load_plugin(ARGV[1], scope: ARGV[2], plugin_hash_file: ARGV[3], force: ARGV[4] == 'force')
657
674
 
675
+ when 'list'
676
+ list_plugins(scope: ARGV[1])
677
+
658
678
  when 'unload'
659
679
  unload_plugin(ARGV[1], scope: ARGV[2])
660
680
 
data/bin/pipinstall CHANGED
@@ -6,4 +6,7 @@ if [ $? -eq 0 ]; then
6
6
  else
7
7
  echo "Command failed - retrying with --no-index"
8
8
  pip install --no-index "$@"
9
+ if [ $? -eq 0 ]; then
10
+ echo "ERROR: pip install failed"
11
+ fi
9
12
  fi
@@ -127,7 +127,7 @@ OPTION:
127
127
  The option to set. OpenC3 defines several options on the core provided
128
128
  interfaces. The SerialInterface defines FLOW_CONTROL which can be NONE (default) or RTSCTS
129
129
  and DATA_BITS which changes the data bits of the serial interface.
130
- The TcpipServerInterface defines LISTEN_ADDRESS which is the IP address to accept
130
+ The TcpipServerInterface and HttpServerInterface define LISTEN_ADDRESS which is the IP address to accept
131
131
  connections on (default 0.0.0.0).
132
132
  values: .*
133
133
  - name: Parameters
@@ -138,6 +138,9 @@ OPTION:
138
138
  INTERFACE SERIAL_INT serial_interface.rb COM1 COM1 115200 NONE 1 10.0 nil
139
139
  OPTION FLOW_CONTROL RTSCTS
140
140
  OPTION DATA_BITS 8
141
+ ROUTER SERIAL_ROUTER tcpip_server_interface.rb 2950 2950 10.0 nil BURST
142
+ ROUTE SERIAL_INT
143
+ OPTION LISTEN_ADDRESS 127.0.0.1
141
144
  SECRET:
142
145
  summary: Define a secret needed by this interface
143
146
  description: Defines a secret for this interface and optionally assigns its value to an option
@@ -170,4 +170,9 @@ ACCESSOR:
170
170
  required: true
171
171
  description: The name of the accessor class
172
172
  values: .+
173
- since: 5.0.10
173
+ since: 5.0.10
174
+ IGNORE_OVERLAP:
175
+ summary: Ignores any packet items which overlap
176
+ description: Packet items which overlap normally generate a warning unless each individual item has the OVERLAP keyword.
177
+ This ignores overlaps across the entire packet.
178
+ since: 5.15.3
@@ -1302,7 +1302,7 @@ Interactive Widgets:
1302
1302
 
1303
1303
  Button code can get rather complex so remember to use string concatenation
1304
1304
  to make things more readable. If you use `+` newlines are inserted automatically
1305
- during string concatenation. If you use `\` you'll need to separate lines with a
1305
+ during string concatenation. If you use `\\` you'll need to separate lines with a
1306
1306
  single semicolon `;`. COSMOS uses double semicolon `;;` to indicate lines should
1307
1307
  be evaluated separately. Note that all OpenC3 commands (using api.cmd) must be
1308
1308
  separated by `;;`.
@@ -0,0 +1,317 @@
1
+ /*
2
+ # Copyright 2024 OpenC3, Inc.
3
+ # All Rights Reserved.
4
+ #
5
+ # This program is free software; you can modify and/or redistribute it
6
+ # under the terms of the GNU Affero General Public License
7
+ # as published by the Free Software Foundation; version 3 with
8
+ # attribution addendums as found in the LICENSE.txt
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # This file may also be used under the terms of a commercial license
16
+ # if purchased from OpenC3, Inc.
17
+ */
18
+
19
+ #include "ruby.h"
20
+ #include "stdio.h"
21
+
22
+ static VALUE mOpenC3 = Qnil;
23
+ static VALUE cProtocol = Qnil;
24
+ static VALUE cBurstProtocol = Qnil;
25
+
26
+ static ID id_method_handle_sync_pattern = 0;
27
+ static ID id_method_reduce_to_single_packet = 0;
28
+ static ID id_method_replace = 0;
29
+ static ID id_method_clone = 0;
30
+ static ID id_method_log_discard = 0;
31
+
32
+ static ID id_ivar_data = 0;
33
+ static ID id_ivar_extra = 0;
34
+ static ID id_ivar_sync_pattern = 0;
35
+ static ID id_ivar_sync_state = 0;
36
+ static ID id_ivar_discard_leading_bytes = 0;
37
+
38
+ static VALUE symbol_RESYNC = Qnil;
39
+ static VALUE symbol_SEARCHING = Qnil;
40
+ static VALUE symbol_DISCONNECT = Qnil;
41
+ static VALUE symbol_STOP = Qnil;
42
+ static VALUE symbol_FOUND = Qnil;
43
+
44
+ /* Reads from the interface. It can look for a sync pattern before
45
+ * creating a Packet. It can discard a set number of bytes at the beginning
46
+ * before creating the Packet.
47
+ *
48
+ * Note: On the first call to this from any interface read(), data will contain a blank
49
+ * string. Blank string is an opportunity for protocols to return any queued up packets.
50
+ * If they have no queued up packets, they should pass the blank string down to chained
51
+ * protocols giving them the same opportunity.
52
+ *
53
+ * @return [String|nil] Data for a packet consisting of the bytes read */
54
+ static VALUE burst_protocol_read_data(int argc, VALUE *argv, VALUE self)
55
+ {
56
+ /* Arguments */
57
+ volatile VALUE data = Qnil;
58
+ volatile VALUE extra = Qnil;
59
+
60
+ /* Internal variables */
61
+ volatile VALUE result = Qnil;
62
+ volatile VALUE control = Qnil;
63
+ volatile VALUE packet_data = Qnil;
64
+ volatile VALUE super_args[3] = {Qnil, Qnil, Qnil};
65
+
66
+ long discard_leading_bytes = 0;
67
+
68
+ switch (argc)
69
+ {
70
+ case 1:
71
+ data = argv[0];
72
+ break;
73
+ case 2:
74
+ data = argv[0];
75
+ extra = argv[1];
76
+ break;
77
+ default:
78
+ /* Invalid number of arguments given */
79
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc);
80
+ break;
81
+ };
82
+
83
+ rb_str_concat(rb_ivar_get(self, id_ivar_data), data);
84
+ rb_ivar_set(self, id_ivar_extra, extra);
85
+
86
+ while (1)
87
+ {
88
+ control = rb_funcall(self, id_method_handle_sync_pattern, 0);
89
+ /* Only return here if not blank string test */
90
+ if (RTEST(control) && (RSTRING_LEN(data) > 0))
91
+ {
92
+ return control;
93
+ }
94
+
95
+ /* Reduce the data to a single packet */
96
+ result = rb_funcall(self, id_method_reduce_to_single_packet, 0);
97
+ if (RB_TYPE_P(result, T_ARRAY))
98
+ {
99
+ if (RARRAY_LEN(result) > 0)
100
+ {
101
+ packet_data = rb_ary_entry(result, 0);
102
+ if (RARRAY_LEN(result) > 1)
103
+ {
104
+ extra = rb_ary_entry(result, 1);
105
+ }
106
+ else
107
+ {
108
+ extra = Qnil;
109
+ }
110
+ }
111
+ else
112
+ {
113
+ packet_data = Qnil;
114
+ extra = Qnil;
115
+ }
116
+ }
117
+ else
118
+ {
119
+ packet_data = result;
120
+ extra = Qnil;
121
+ }
122
+ if (packet_data == symbol_RESYNC)
123
+ {
124
+ rb_ivar_set(self, id_ivar_sync_state, symbol_SEARCHING);
125
+
126
+ /* Only immediately resync if not blank string test */
127
+ if (RSTRING_LEN(data) > 0)
128
+ {
129
+ continue;
130
+ }
131
+ }
132
+
133
+ /* Potentially allow blank string to be sent to other protocols if no packet is ready in this one */
134
+ if (SYMBOL_P(packet_data))
135
+ {
136
+ if ((RSTRING_LEN(data) <= 0) && (packet_data != symbol_DISCONNECT))
137
+ {
138
+ /* On blank string test, return blank string (unless we had a packet or need disconnect)
139
+ * The base class handles the special case of returning STOP if on the last protocol in the
140
+ * chain */
141
+ super_args[0] = data;
142
+ super_args[1] = extra;
143
+ return rb_call_super(2, (VALUE *)super_args);
144
+ }
145
+ else
146
+ {
147
+ /* Return any control code if not on blank string test */
148
+ result = rb_ary_new();
149
+ rb_ary_push(result, packet_data);
150
+ rb_ary_push(result, extra);
151
+ return result;
152
+ }
153
+ }
154
+
155
+ rb_ivar_set(self, id_ivar_sync_state, symbol_SEARCHING);
156
+
157
+ /* Discard leading bytes if necessary */
158
+ if (FIX2INT(rb_ivar_get(self, id_ivar_discard_leading_bytes)) > 0)
159
+ {
160
+ discard_leading_bytes = FIX2INT(rb_ivar_get(self, id_ivar_discard_leading_bytes));
161
+ rb_str_replace(packet_data, rb_str_substr(packet_data, discard_leading_bytes, RSTRING_LEN(packet_data) - discard_leading_bytes));
162
+ }
163
+
164
+ result = rb_ary_new();
165
+ rb_ary_push(result, packet_data);
166
+ rb_ary_push(result, extra);
167
+ return result;
168
+ }
169
+ }
170
+
171
+ /* @return [Boolean] control code (nil, :STOP) */
172
+ static VALUE burst_protocol_handle_sync_pattern(VALUE self)
173
+ {
174
+ volatile VALUE sync_pattern = rb_ivar_get(self, id_ivar_sync_pattern);
175
+ volatile VALUE data = Qnil;
176
+ long sync_index = -1;
177
+ char *char_data = NULL;
178
+ char *char_sync_pattern = NULL;
179
+ long data_length = 0;
180
+ long sync_pattern_length = 0;
181
+ long i = 0;
182
+ long index = 0;
183
+ int found = 0;
184
+
185
+ if (RTEST(sync_pattern) && (rb_ivar_get(self, id_ivar_sync_state) == symbol_SEARCHING))
186
+ {
187
+ data = rb_ivar_get(self, id_ivar_data);
188
+ char_sync_pattern = RSTRING_PTR(sync_pattern);
189
+
190
+ while (1)
191
+ {
192
+ data_length = RSTRING_LEN(data);
193
+ sync_pattern_length = RSTRING_LEN(sync_pattern);
194
+
195
+ /* Make sure we have some data to look for a sync word in */
196
+ if (data_length < sync_pattern_length)
197
+ {
198
+ return symbol_STOP;
199
+ }
200
+
201
+ /* Find the beginning of the sync pattern */
202
+ sync_index = -1;
203
+ char_data = RSTRING_PTR(data);
204
+ for (i = 0; i < data_length; i++)
205
+ {
206
+ if (char_data[i] == char_sync_pattern[0])
207
+ {
208
+ sync_index = i;
209
+ break;
210
+ }
211
+ }
212
+
213
+ if (sync_index != -1)
214
+ {
215
+ /* Make sure we have enough data for the whole sync pattern past this index */
216
+ if (data_length < (sync_index + sync_pattern_length))
217
+ {
218
+ return symbol_STOP;
219
+ }
220
+
221
+ /* Check for the rest of the sync pattern */
222
+ found = 1;
223
+ index = sync_index;
224
+ for (i = 0; i < sync_pattern_length; i++)
225
+ {
226
+ if (char_data[index] != char_sync_pattern[i])
227
+ {
228
+ found = 0;
229
+ break;
230
+ }
231
+ index += 1;
232
+ }
233
+
234
+ if (found)
235
+ {
236
+ if (sync_index != 0)
237
+ {
238
+ rb_funcall(self, id_method_log_discard, 2, INT2FIX(sync_index), Qtrue);
239
+ /* Delete Data Before Sync Pattern */
240
+ rb_str_replace(data, rb_str_substr(data, sync_index, RSTRING_LEN(data) - sync_index));
241
+ }
242
+ rb_ivar_set(self, id_ivar_sync_state, symbol_FOUND);
243
+ return Qnil;
244
+ }
245
+ else
246
+ {
247
+ rb_funcall(self, id_method_log_discard, 2, INT2FIX(sync_index + 1), Qfalse);
248
+ /* Delete Data Before and including first character of suspected sync Pattern */
249
+ rb_str_replace(data, rb_str_substr(data, sync_index + 1, RSTRING_LEN(data) - sync_index - 1));
250
+ continue;
251
+ } /* if found */
252
+ }
253
+ else
254
+ {
255
+ rb_funcall(self, id_method_log_discard, 2, INT2FIX(data_length), Qfalse);
256
+ rb_str_replace(data, rb_str_new2(""));
257
+ return symbol_STOP;
258
+ }
259
+ } /* end loop */
260
+ } /* if @sync_pattern */
261
+
262
+ return Qnil;
263
+ }
264
+
265
+ static VALUE burst_protocol_reduce_to_single_packet(VALUE self)
266
+ {
267
+ volatile VALUE result = Qnil;
268
+ volatile VALUE packet_data = Qnil;
269
+ volatile VALUE data = rb_ivar_get(self, id_ivar_data);
270
+
271
+ if (RSTRING_LEN(data) <= 0)
272
+ {
273
+ /* Need some data */
274
+ return symbol_STOP;
275
+ }
276
+
277
+ /* Reduce to packet data and clear data for next packet */
278
+ packet_data = rb_funcall(data, id_method_clone, 0);
279
+ rb_str_replace(data, rb_str_new2(""));
280
+
281
+ result = rb_ary_new();
282
+ rb_ary_push(result, packet_data);
283
+ rb_ary_push(result, rb_ivar_get(self, id_ivar_extra));
284
+ return result;
285
+ }
286
+
287
+ /*
288
+ * Initialize all BurstProtocol methods
289
+ */
290
+ void Init_burst_protocol(void)
291
+ {
292
+ mOpenC3 = rb_define_module("OpenC3");
293
+
294
+ symbol_RESYNC = ID2SYM(rb_intern("RESYNC"));
295
+ symbol_SEARCHING = ID2SYM(rb_intern("SEARCHING"));
296
+ symbol_DISCONNECT = ID2SYM(rb_intern("DISCONNECT"));
297
+ symbol_STOP = ID2SYM(rb_intern("STOP"));
298
+ symbol_FOUND = ID2SYM(rb_intern("FOUND"));
299
+
300
+ id_method_handle_sync_pattern = rb_intern("handle_sync_pattern");
301
+ id_method_reduce_to_single_packet = rb_intern("reduce_to_single_packet");
302
+ id_method_replace = rb_intern("replace");
303
+ id_method_clone = rb_intern("clone");
304
+ id_method_log_discard = rb_intern("log_discard");
305
+
306
+ id_ivar_data = rb_intern("@data");
307
+ id_ivar_extra = rb_intern("@extra");
308
+ id_ivar_sync_pattern = rb_intern("@sync_pattern");
309
+ id_ivar_sync_state = rb_intern("@sync_state");
310
+ id_ivar_discard_leading_bytes = rb_intern("@discard_leading_bytes");
311
+
312
+ cProtocol = rb_define_class_under(mOpenC3, "Protocol", rb_cObject);
313
+ cBurstProtocol = rb_define_class_under(mOpenC3, "BurstProtocol", cProtocol);
314
+ rb_define_method(cBurstProtocol, "read_data", burst_protocol_read_data, -1);
315
+ rb_define_method(cBurstProtocol, "reduce_to_single_packet", burst_protocol_reduce_to_single_packet, 0);
316
+ rb_define_method(cBurstProtocol, "handle_sync_pattern", burst_protocol_handle_sync_pattern, 0);
317
+ }
@@ -0,0 +1,13 @@
1
+ require 'mkmf'
2
+
3
+ unless $CFLAGS.gsub!(/ -O[\dsz]?/, ' -O3')
4
+ $CFLAGS << ' -O3'
5
+ end
6
+ if /gcc/.match?(CONFIG['CC'])
7
+ $CFLAGS << ' -Wall'
8
+ if $DEBUG && !$CFLAGS.gsub!(/ -O[\dsz]?/, ' -O0 -ggdb')
9
+ $CFLAGS << ' -O0 -ggdb'
10
+ end
11
+ end
12
+
13
+ create_makefile 'openc3/ext/burst_protocol'
@@ -105,7 +105,7 @@ module OpenC3
105
105
 
106
106
  def self.convert_to_type(value, item)
107
107
  case item.data_type
108
- when :OBJECT
108
+ when :OBJECT, :ARRAY
109
109
  # Do nothing for complex object types
110
110
  when :STRING, :BLOCK
111
111
  if item.array_size
@@ -18,8 +18,16 @@
18
18
 
19
19
  require 'json'
20
20
  require 'jsonpath'
21
+ require 'openc3/io/json_rpc'
21
22
  require 'openc3/accessors/accessor'
22
23
 
24
+ # Monkey patch JsonPath to enable create_additions and allow_nan to support binary strings, and NaN, Infinity, -Infinity
25
+ class JsonPath
26
+ def self.process_object(obj_or_str, opts = {})
27
+ obj_or_str.is_a?(String) ? MultiJson.decode(obj_or_str, max_nesting: opts[:max_nesting], create_additions: true, allow_nan: true) : obj_or_str
28
+ end
29
+ end
30
+
23
31
  module OpenC3
24
32
  class JsonAccessor < Accessor
25
33
  def self.read_item(item, buffer)
@@ -33,7 +41,7 @@ module OpenC3
33
41
 
34
42
  # Convert to ruby objects
35
43
  if String === buffer
36
- decoded = JSON.parse(buffer, :allow_nan => true)
44
+ decoded = JSON.parse(buffer, :allow_nan => true, :create_additions => true)
37
45
  else
38
46
  decoded = buffer
39
47
  end
@@ -43,7 +51,7 @@ module OpenC3
43
51
 
44
52
  # Update buffer
45
53
  if String === buffer
46
- buffer.replace(JSON.generate(decoded, :allow_nan => true))
54
+ buffer.replace(JSON.generate(decoded.as_json, :allow_nan => true))
47
55
  end
48
56
 
49
57
  return value
@@ -52,7 +60,7 @@ module OpenC3
52
60
  def self.read_items(items, buffer)
53
61
  # Prevent JsonPath from decoding every call
54
62
  if String === buffer
55
- decoded = JSON.parse(buffer, :allow_nan => true)
63
+ decoded = JSON.parse(buffer, :allow_nan => true, :create_additions => true)
56
64
  else
57
65
  decoded = buffer
58
66
  end
@@ -458,7 +458,7 @@ module OpenC3
458
458
  raise "ERROR: Invalid number of arguments (#{args.length}) passed to #{method_name}()"
459
459
  end
460
460
  if target_name.nil? or packet_name.nil? or item_name.nil?
461
- raise "ERROR: Target name, packet name, and item name are required. Usage: #{method_name}(\"TGT PKT ITEM\") or #{method_name}(\"TGT\", \"PKT\", \"ITEM\")"
461
+ raise "ERROR: Target name, packet name and item name are required. Usage: #{method_name}(\"TGT PKT ITEM\") or #{method_name}(\"TGT\", \"PKT\", \"ITEM\")"
462
462
  end
463
463
  return [target_name, packet_name, item_name]
464
464
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- # Copyright 2023 OpenC3, Inc.
3
+ # Copyright 2024 OpenC3, Inc.
4
4
  # All Rights Reserved.
5
5
  #
6
6
  # This program is free software; you can modify and/or redistribute it
@@ -34,10 +34,10 @@ module OpenC3
34
34
  @hostname = hostname
35
35
  @port = Integer(port)
36
36
  @protocol = protocol
37
- if (port == 80 and protocol == 'http') or (port == 443 and protocol == 'https')
38
- @url = "#{protocol}://#{hostname}"
37
+ if (@port == 80 and @protocol == 'http') or (@port == 443 and @protocol == 'https')
38
+ @url = "#{@protocol}://#{@hostname}"
39
39
  else
40
- @url = "#{protocol}://#{hostname}:#{port}"
40
+ @url = "#{@protocol}://#{@hostname}:#{@port}"
41
41
  end
42
42
  @write_timeout = ConfigParser.handle_nil(write_timeout)
43
43
  @write_timeout = Float(@write_timeout) if @write_timeout
@@ -50,6 +50,10 @@ module OpenC3
50
50
  @response_queue = Queue.new
51
51
  end
52
52
 
53
+ def connection_string
54
+ return @url
55
+ end
56
+
53
57
  # Connects the interface to its target(s)
54
58
  def connect
55
59
  # Per https://github.com/lostisland/faraday/blob/main/lib/faraday/options/env.rb
@@ -1,6 +1,6 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- # Copyright 2023 OpenC3, Inc.
3
+ # Copyright 2024 OpenC3, Inc.
4
4
  # All Rights Reserved.
5
5
  #
6
6
  # This program is free software; you can modify and/or redistribute it
@@ -26,14 +26,30 @@ module OpenC3
26
26
  # @param port [Integer] HTTP port
27
27
  def initialize(port = 80)
28
28
  super()
29
+ @listen_address = '0.0.0.0' # Default to ANY
29
30
  @port = Integer(port)
30
31
  @server = nil
31
32
  @request_queue = Queue.new
32
33
  end
33
34
 
35
+ # Supported Options
36
+ # LISTEN_ADDRESS - Ip address of the interface to accept connections on
37
+ # (see Interface#set_option)
38
+ def set_option(option_name, option_values)
39
+ super(option_name, option_values)
40
+ case option_name.upcase
41
+ when 'LISTEN_ADDRESS'
42
+ @listen_address = option_values[0]
43
+ end
44
+ end
45
+
46
+ def connection_string
47
+ return "listening on #{@listen_address}:#{@port}"
48
+ end
49
+
34
50
  # Connects the interface to its target(s)
35
51
  def connect
36
- @server = WEBrick::HTTPServer.new :Port => @port
52
+ @server = WEBrick::HTTPServer.new(:BindAddress => @listen_address, :Port => @port)
37
53
  @request_queue = Queue.new
38
54
 
39
55
  # Create a response hook for every command packet
@@ -43,9 +59,9 @@ module OpenC3
43
59
  path = nil
44
60
  begin
45
61
  path = packet.read('HTTP_PATH')
46
- rescue => err
62
+ rescue => e
47
63
  # No HTTP_PATH is an error
48
- Logger.error("HttpServerInterface Packet #{target_name} #{packet_name} unable to read HTTP_PATH\n#{err.formatted}")
64
+ Logger.error("HttpServerInterface Packet #{target_name} #{packet_name} unable to read HTTP_PATH\n#{e.formatted}")
49
65
  end
50
66
  if path
51
67
  @server.mount_proc path do |req, res|
@@ -145,7 +161,7 @@ module OpenC3
145
161
 
146
162
  # Writes to the socket
147
163
  # @param data [Hash] For the HTTP Interface, data is a hash with the needed request info
148
- def write_interface(data, extra = nil)
164
+ def write_interface(_data, _extra = nil)
149
165
  raise "Commands cannot be sent to HttpServerInterface"
150
166
  end
151
167
 
@@ -176,7 +192,7 @@ module OpenC3
176
192
  #
177
193
  # @param packet [Packet] Packet to extract data from
178
194
  # @return data
179
- def convert_packet_to_data(packet)
195
+ def convert_packet_to_data(_packet)
180
196
  raise "Commands cannot be sent to HttpServerInterface"
181
197
  end
182
198
  end
@@ -184,6 +184,12 @@ module OpenC3
184
184
  @scheduler = nil
185
185
  end
186
186
 
187
+ # Should be implemented by subclass to return human readable connection string
188
+ # which will be placed in log messages when connecting and during connection failures
189
+ def connection_string
190
+ return @name
191
+ end
192
+
187
193
  # Connects the interface to its target(s). Must be implemented by a
188
194
  # subclass.
189
195
  def connect
@@ -17,13 +17,15 @@
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/tcpip_client_interface'
24
24
  require 'uuidtools'
25
25
 
26
26
  module OpenC3
27
+ # TODO: Deprecated ... Will remove in next major version of COSMOS (COSMOS 6)
28
+
27
29
  # Interface for connecting to Ball Aerospace LINC Labview targets
28
30
  class LincInterface < TcpipClientInterface
29
31
  # The maximum number of asynchronous commands we can wait for at a time.
@@ -241,7 +243,7 @@ module OpenC3
241
243
  end
242
244
 
243
245
  process_handshake_results(handshake_cmd)
244
- rescue Exception => err
246
+ rescue Exception => e
245
247
  # If anything goes wrong after successfully writing the packet to the LINC target
246
248
  # ensure that the packet gets updated in the CVT and logged to the packet log writer.
247
249
  # OpenC3 normally only does this if write returns successfully
@@ -256,7 +258,7 @@ module OpenC3
256
258
  packet_log_writer_pair.cmd_log_writer.write(packet)
257
259
  end
258
260
 
259
- raise err
261
+ raise e
260
262
  end
261
263
 
262
264
  def process_handshake_results(handshake_cmd)