cosmos 5.0.4 → 5.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a561fd5492c1b282759d45170da4e687b4e53eea086804bde1c549a75a8bdd5
4
- data.tar.gz: c88407b16125e7ef2fb9764dd14338f6508e2fbde1567ff3b7d23b24f1b7dd2a
3
+ metadata.gz: 520339a0daade42a51611f9e17fe6e5a2c1343d9bab3ad6b36dbb03f11f55f28
4
+ data.tar.gz: 59a4d41cc6ef453ea1f375c5e9671aa0b14b390da42d8413bd080ab7bdb18ff4
5
5
  SHA512:
6
- metadata.gz: f80a81b27f8c00611a730ef329b4c4afc01e572419ee03d1c7621295e2670a1e829d41511ee4a82af5874d43d32f7b51280281c26310ee8f1e79e767e987c542
7
- data.tar.gz: 14f36f225ac641ca74dac4eca580ffad8e6ffea7d69bed1c685d387db0ff6d3977c6ad8b148b8a8117914bd7752914423d2691aa899b0ec902fde5c25f4e931a
6
+ metadata.gz: 700274a130767236a08e76ce223a09fa0229e659153c8a5f50896447796d3ca0e4487423704ece2d655511a642c6dfed0a8fc9482f8ee7ef9681f1726c23a2ce
7
+ data.tar.gz: 20773c2fd54d95674f66252edbd51faee8107cca83c05bace69a4607fd5563dc543d10f670513b4fb2df25d6ca6c18d0e58923f517e66f7f186fe7bc0e1eecbb
data/bin/cosmos CHANGED
@@ -24,6 +24,7 @@ require 'cosmos'
24
24
  require 'cosmos/utilities/s3'
25
25
  require 'cosmos/models/scope_model'
26
26
  require 'cosmos/models/plugin_model'
27
+ require 'cosmos/packets/packet_config'
27
28
  require 'cosmos/bridge/bridge'
28
29
  require 'ostruct'
29
30
  require 'optparse'
@@ -32,6 +33,7 @@ require 'fileutils'
32
33
  require 'find'
33
34
  require 'json'
34
35
  require 'redis'
36
+ require 'psych'
35
37
  require 'erb'
36
38
 
37
39
  $redis_url = "redis://#{ENV['COSMOS_REDIS_HOSTNAME']}:#{ENV['COSMOS_REDIS_PORT']}"
@@ -40,25 +42,27 @@ $redis_url = "redis://#{ENV['COSMOS_REDIS_HOSTNAME']}:#{ENV['COSMOS_REDIS_PORT']
40
42
  MIGRATE_OPTIONS = OpenStruct.new
41
43
  MIGRATE_OPTIONS.all = false
42
44
  MIGRATE_PARSER = OptionParser.new do |op|
43
- op.banner = "cosmos migrate PLUGIN [TGT1...] # Create a COSMOS 5 plugin from existing COSMOS 4 targets"
44
- op.on("-a", "--all", "Move all COSMOS 4 targets into a single COSMOS 5 plugin") do
45
+ op.banner = "cosmos migrate PLUGIN [TGT1...] # Create a COSMOS 5 plugin from existing COSMOS 4 targets"
46
+ op.on("-a", "--all", " Move all COSMOS 4 targets into a single COSMOS 5 plugin") do
45
47
  MIGRATE_OPTIONS.all = true
46
48
  end
47
49
  end
50
+ ERROR_CODE = 67 # ASCII 'C' for COSMOS
48
51
 
49
52
  # Prints the usage text for the cosmos executable
50
53
  def print_usage
51
54
  puts "Usage:"
52
55
  puts " cosmos help # Displays this information"
53
56
  puts " cosmos rake # Runs rake in the local directory"
54
- puts " cosmos load /PATH/FILENAME.gem # Loads a COSMOS plugin gem file"
57
+ puts " cosmos validate /PATH/FILENAME.gem SCOPE variables.txt # Validate a COSMOS plugin gem file"
58
+ puts " cosmos load /PATH/FILENAME.gem SCOPE variables.txt # Loads a COSMOS plugin gem file"
55
59
  puts " cosmos generate plugin PLUGIN_NAME # Generate a COSMOS plugin"
56
60
  puts " #{MIGRATE_PARSER}"
57
61
  puts " cosmos bridge CONFIG_FILENAME # Run COSMOS host bridge"
58
62
  puts " cosmos bridgesetup CONFIG_FILENAME # Create a default config file"
59
63
  puts " cosmos geminstall GEMFILENAME # Install loaded gem to /gems"
60
64
  puts " cosmos rubysloc # Counts Ruby SLOC recursively. Run with --help for more info."
61
- # puts " cosmos xtce_converter # Convert to and from the XTCE format. Run with --help for more info."
65
+ puts " cosmos xtce_converter # Convert to and from the XTCE format. Run with --help for more info."
62
66
  puts " cosmos cstol_converter # Converts CSTOL files (.prc) to COSMOS. Run with --help for more info."
63
67
  puts ""
64
68
  end
@@ -185,6 +189,76 @@ def migrate(args)
185
189
  puts "Plugin complete: #{File.expand_path('.')}" # Remember we're inside the plugin dir
186
190
  end
187
191
 
192
+ def xtce_converter(args)
193
+ options = {}
194
+ option_parser = OptionParser.new do |option_parser|
195
+ option_parser.banner = "Usage: xtce_converter [options] --import input_xtce_filename --output output_dir\n"+
196
+ " xtce_converter [options] --plugin /PATH/FILENAME.gem --output output_dir --variables variables.txt"
197
+ option_parser.separator("")
198
+ option_parser.on("-h", "--help", "Show this message") do
199
+ puts option_parser
200
+ exit
201
+ end
202
+ option_parser.on("-i VALUE", "--import VALUE", "Import the specified .xtce file") do |arg|
203
+ options[:import] = arg
204
+ end
205
+ option_parser.on("-o", "--output DIRECTORY", "Create files in the directory") do |arg|
206
+ options[:output] = arg
207
+ end
208
+ option_parser.on("-p", "--plugin PLUGIN", "Export .xtce file(s) from the plugin") do |arg|
209
+ options[:plugin] = arg
210
+ end
211
+ option_parser.on("-v", "--variables", "Optional variables file to pass to the plugin") do |arg|
212
+ options[:variables] = arg
213
+ end
214
+ end
215
+
216
+ begin
217
+ option_parser.parse!(args)
218
+ rescue => err
219
+ abort(option_parser.to_s)
220
+ end
221
+
222
+ if options[:import] && options[:plugin]
223
+ puts "xtce_converter options --import and --plugin are mutually exclusive"
224
+ abort(option_parser.to_s)
225
+ end
226
+
227
+ ENV['COSMOS_NO_STORE'] = '1' # it can be anything
228
+ Cosmos::Logger.stdout = false
229
+ Cosmos::Logger.level = Cosmos::Logger::DEBUG
230
+
231
+ if options[:import] && options[:output]
232
+ packet_config = Cosmos::PacketConfig.new
233
+ puts "Processing #{options[:import]}..."
234
+ packet_config.process_file(options[:import], nil)
235
+ puts "Writing COSMOS config files to #{options[:output]}/"
236
+ packet_config.to_config(options[:output])
237
+ exit(0)
238
+ elsif options[:plugin] && options[:output]
239
+ begin
240
+ variables = nil
241
+ variables = JSON.parse(File.read(options[:variables])) if options[:variables]
242
+ puts "Installing #{File.basename(options[:plugin])}"
243
+ plugin_hash = Cosmos::PluginModel.install_phase1(options[:plugin], variables, scope: 'DEFAULT', validate_only: true)
244
+ plugin_hash['variables']['xtce_output'] = options[:output]
245
+ Cosmos::PluginModel.install_phase2(plugin_hash['name'], plugin_hash['variables'], scope: 'DEFAULT', validate_only: true,
246
+ gem_file_path: options[:plugin])
247
+ result = 0 # bash and Windows consider 0 success
248
+ rescue => e
249
+ puts "Error: #{e.message}"
250
+ result = ERROR_CODE
251
+ ensure
252
+ name = Psych.safe_load(`gem spec #{options[:plugin]} name`).to_s
253
+ version = Psych.safe_load(`gem spec #{options[:plugin]} version`, permitted_classes: [Gem::Version]).to_s
254
+ Gem::Uninstaller.new(name, {:version => version, :force => true}).uninstall
255
+ exit(result)
256
+ end
257
+ else
258
+ abort(option_parser.to_s)
259
+ end
260
+ end
261
+
188
262
  # A helper method to make the zip writing recursion work
189
263
  def write_zip_entries(base_dir, entries, zip_path, io)
190
264
  io.add(zip_path, base_dir) # Add the directory whether it has entries or not
@@ -212,7 +286,66 @@ def put_into_archive(disk_file_path, io, zip_file_path)
212
286
  end
213
287
  end
214
288
 
215
- def load_plugin(plugin_file_path, scope:, variables_file: nil)
289
+ def validate_plugin(plugin_file_path, scope:, variables_file: nil)
290
+ ENV['COSMOS_NO_STORE'] = '1' # it can be anything
291
+ Cosmos::Logger.stdout = false
292
+ Cosmos::Logger.level = Cosmos::Logger::DEBUG
293
+ scope ||= 'DEFAULT'
294
+ variables = nil
295
+ variables = JSON.parse(File.read(variables_file)) if variables_file
296
+ puts "Installing #{File.basename(plugin_file_path)}"
297
+ plugin_hash = Cosmos::PluginModel.install_phase1(plugin_file_path, variables, scope: scope, validate_only: true)
298
+ Cosmos::PluginModel.install_phase2(plugin_hash['name'], plugin_hash['variables'], scope: scope, validate_only: true,
299
+ gem_file_path: plugin_file_path)
300
+ puts "Successfully validated #{File.basename(plugin_file_path)}"
301
+ result = 0 # bash and Windows consider 0 success
302
+ rescue => e
303
+ puts "Error: #{e.message}"
304
+ result = ERROR_CODE
305
+ ensure
306
+ name = Psych.safe_load(`gem spec #{plugin_file_path} name`).to_s
307
+ version = Psych.safe_load(`gem spec #{plugin_file_path} version`, permitted_classes: [Gem::Version]).to_s
308
+ Gem::Uninstaller.new(name, {:version => version, :force => true}).uninstall
309
+ exit(result)
310
+ end
311
+
312
+ def update_plugin(plugin_file_path, plugin_name, variables: nil, plugin_txt_lines: nil, scope:)
313
+ new_gem = File.basename(plugin_file_path)
314
+ old_gem = plugin_name.split("__")[0]
315
+ puts "Updating existing plugin: #{plugin_name} with #{File.basename(plugin_file_path)}"
316
+ plugin_model = Cosmos::PluginModel.get_model(name: plugin_name, scope: scope)
317
+ begin
318
+ # Only update if something has changed
319
+ if (new_gem != old_gem) or (variables != plugin_model.variables) or (plugin_txt_lines != plugin_model.plugin_txt_lines)
320
+ variables = plugin_model.variables unless variables
321
+ plugin_model.destroy
322
+ plugin_hash = Cosmos::PluginModel.install_phase1(plugin_file_path, existing_variables: variables, existing_plugin_txt_lines: plugin_txt_lines, process_existing: true, scope: scope)
323
+ Cosmos::PluginModel.install_phase2(plugin_hash, scope: scope)
324
+ else
325
+ puts "No changes detected - Exiting without change"
326
+ end
327
+ rescue => error
328
+ puts error.formatted
329
+ plugin_model.restore if plugin_model.destroyed?
330
+ raise error
331
+ end
332
+ end
333
+
334
+ # Loads a plugin into the COSMOS system
335
+ # This code is used from the command line and is the same code that gets called if you
336
+ # edit/upgrade or install a new plugin from the Admin interface
337
+ #
338
+ # Usage: cosmos load gemfile_path [scope] [plugin_hash_file_path]
339
+ #
340
+ # With just gemfile_path and/or scope: Will do nothing if any plugin
341
+ # with the same gem file already exists
342
+ #
343
+ # Otherwise will do what the plugin_hash_file says to do
344
+ # Plugin hash file must have the exact name of an existing plugin for upgrades and edits
345
+ # Otherwise, it will be assumed that the plugin is intentionally being installed for a second
346
+ # time
347
+ #
348
+ def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil)
216
349
  scope ||= 'DEFAULT'
217
350
  # Only create the scope if it doesn't already exist
218
351
  unless Cosmos::ScopeModel.names.include?(scope)
@@ -226,41 +359,47 @@ def load_plugin(plugin_file_path, scope:, variables_file: nil)
226
359
  end
227
360
 
228
361
  begin
229
- # Try to find an existing plugin with this file to upgrade
230
- gem_filename = File.basename(plugin_file_path, ".gem")
231
- gem_filename = gem_filename.split('-')[0..-2].join('-')
232
- plugin_names = Cosmos::PluginModel.names(scope: scope)
233
- found = false
234
- plugin_names.each do |plugin_name|
235
- gem_name = plugin_name.split("__")[0]
236
- gem_name = File.basename(plugin_name, ".gem")
237
- gem_name = gem_name.split('-')[0..-2].join('-')
238
- if gem_filename == gem_name
239
- puts "Upgrading existing plugin: #{plugin_name} with #{plugin_file_path}"
240
- plugin_model = Cosmos::PluginModel.get_model(name: plugin_name, scope: scope)
241
- variables = plugin_model.variables
242
- plugin_model.destroy
243
- if variables_file
244
- # Assume phase1 is already done
245
- variables = JSON.parse(File.read(variables_file))
246
- plugin_hash = Cosmos::PluginModel.new(name: File.basename(plugin_file_path), variables: variables, scope: scope).as_json
247
- else
248
- plugin_hash = Cosmos::PluginModel.install_phase1(plugin_file_path, variables, scope: scope)
362
+ if plugin_hash_file
363
+ # Admin Create / Edit / or Upgrade Plugin
364
+ Cosmos::PluginModel.install_phase1(plugin_file_path, scope: scope)
365
+ plugin_hash = JSON.parse(File.read(plugin_hash_file))
366
+ else
367
+ # Init or Command Line cosmos load with no plugin_hash_file
368
+ file_full_name = File.basename(plugin_file_path, ".gem")
369
+ file_gem_name = file_full_name.split('-')[0..-2].join('-')
370
+ found = false
371
+ plugin_names = Cosmos::PluginModel.names(scope: scope)
372
+ plugin_names.each do |plugin_name|
373
+ gem_name = plugin_name.split("__")[0]
374
+ full_name = File.basename(gem_name, ".gem")
375
+ gem_name = full_name.split('-')[0..-2].join('-')
376
+ if file_gem_name == gem_name
377
+ found = true
378
+ # Upgrade if version changed else do nothing
379
+ if file_full_name != full_name
380
+ update_plugin(plugin_file_path, plugin_name, scope: scope)
381
+ end
249
382
  end
250
- Cosmos::PluginModel.install_phase2(plugin_hash['name'], plugin_hash['variables'], scope: scope)
251
- found = true
252
383
  end
384
+ return if found
385
+
386
+ plugin_hash = Cosmos::PluginModel.install_phase1(plugin_file_path, scope: scope)
253
387
  end
254
- unless found
255
- puts "Loading new plugin: #{plugin_file_path}"
256
- if variables_file
257
- # Assume phase1 is already done
258
- variables = JSON.parse(File.read(variables_file))
259
- plugin_hash = Cosmos::PluginModel.new(name: File.basename(plugin_file_path), variables: variables, scope: scope).as_json
260
- else
261
- plugin_hash = Cosmos::PluginModel.install_phase1(plugin_file_path, scope: scope)
262
- end
263
- Cosmos::PluginModel.install_phase2(plugin_hash['name'], plugin_hash['variables'], scope: scope)
388
+
389
+ # Determine if plugin named in plugin_hash exists
390
+ existing_plugin_hash = Cosmos::PluginModel.get(name: plugin_hash['name'], scope: scope)
391
+
392
+ # Existing plugin hash will be present if plugin is being edited or upgraded
393
+ # If editing, gem name will match existing hash name
394
+ # If upgrading, gem name will not match the existing hash name
395
+
396
+ if existing_plugin_hash
397
+ # Upgrade or Edit
398
+ update_plugin(plugin_file_path, plugin_hash['name'], variables: plugin_hash['variables'], plugin_txt_lines: plugin_hash['plugin_txt_lines'], scope: scope)
399
+ else
400
+ # New Install
401
+ puts "Loading new plugin: #{plugin_file_path}\n#{plugin_hash}"
402
+ Cosmos::PluginModel.install_phase2(plugin_hash, scope: scope)
264
403
  end
265
404
  rescue => err
266
405
  abort("Error installing plugin: #{scope}: #{plugin_file_path}: #{err.formatted}")
@@ -305,8 +444,11 @@ if not ARGV[0].nil? # argument(s) given
305
444
  when 'rake'
306
445
  puts `rake #{ARGV[1..-1].join(' ')}`
307
446
 
447
+ when 'validate'
448
+ validate_plugin(ARGV[1], scope: ARGV[2], variables_file: ARGV[3])
449
+
308
450
  when 'load'
309
- load_plugin(ARGV[1], scope: ARGV[2], variables_file: ARGV[3])
451
+ load_plugin(ARGV[1], scope: ARGV[2], plugin_hash_file: ARGV[3])
310
452
 
311
453
  when 'geminstall'
312
454
  gem_install(ARGV[1])
@@ -333,9 +475,8 @@ if not ARGV[0].nil? # argument(s) given
333
475
  when 'cstol_converter'
334
476
  puts `ruby /cosmos/bin/cstol_converter #{ARGV[1..-1].join(' ')}`
335
477
 
336
- # TODO: This still needs work in COSMOS 5
337
- # when 'xtce_converter'
338
- # puts `ruby /cosmos/bin/xtce_converter #{ARGV[1..-1].join(' ')}`
478
+ when 'xtce_converter'
479
+ xtce_converter(ARGV[1..-1])
339
480
 
340
481
  when 'bridge'
341
482
  ENV['COSMOS_NO_STORE'] = '1'
@@ -68,3 +68,13 @@ ROUTER:
68
68
  <%= MetaConfigParser.load('target.yaml').to_meta_config_yaml() %>
69
69
  <%= MetaConfigParser.load('microservice.yaml').to_meta_config_yaml() %>
70
70
  <%= MetaConfigParser.load('tool.yaml').to_meta_config_yaml() %>
71
+ WIDGET:
72
+ summary: Define a custom widget
73
+ example: WIDGET HELLOWORLD
74
+ description: Defines a custom widget that can be used in Telemetry Viewer screens.
75
+ parameters:
76
+ - name: Widget Name
77
+ description: The name of the widget wil be used to build a path to the widget implementation. For example, `WIDGET HELLOWORLD` will find the as-built file tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js. See the [Custom Widgets](/docs/v5/custom-widgets)
78
+ guide for more details.
79
+ required: true
80
+ values: .+
@@ -30,19 +30,19 @@ VALUE mCosmosIO = Qnil;
30
30
  static ID id_method_read = 0;
31
31
 
32
32
  /* Reads a length field and then return the String resulting from reading the
33
- * number of bytes the length field indicates
34
- *
35
- * For example:
36
- * io = StringIO.new
37
- * # where io is "\x02\x01\x02\x03\x04...."
38
- * result = io.read_length_bytes(1)
39
- * # result will be "\x01x02" because the length field was given
40
- * # to be 1 byte. We read 1 byte which is a 2. So we then read two
41
- * # bytes and return.
42
- *
43
- * @param length_num_bytes [Integer] Number of bytes in the length field
44
- * @return [String] A String of "length field" number of bytes
45
- */
33
+ * number of bytes the length field indicates
34
+ *
35
+ * For example:
36
+ * io = StringIO.new
37
+ * # where io is "\x02\x01\x02\x03\x04...."
38
+ * result = io.read_length_bytes(1)
39
+ * # result will be "\x01x02" because the length field was given
40
+ * # to be 1 byte. We read 1 byte which is a 2. So we then read two
41
+ * # bytes and return.
42
+ *
43
+ * @param length_num_bytes [Integer] Number of bytes in the length field
44
+ * @return [String] A String of "length field" number of bytes
45
+ */
46
46
  static VALUE read_length_bytes(int argc, VALUE *argv, VALUE self)
47
47
  {
48
48
  int length_num_bytes = 0;
@@ -134,7 +134,7 @@ static VALUE read_length_bytes(int argc, VALUE *argv, VALUE self)
134
134
  }
135
135
 
136
136
  /* Read String */
137
- temp_string_length = UINT2NUM(string_length);
137
+ temp_string_length = UINT2NUM((unsigned int)string_length);
138
138
  return_value = rb_funcall(self, id_method_read, 1, temp_string_length);
139
139
  if (NIL_P(return_value) || (RSTRING_LEN(return_value) != string_length))
140
140
  {
@@ -196,7 +196,7 @@ static VALUE packet_initialize(int argc, VALUE *argv, VALUE self)
196
196
  packet_name = argv[1];
197
197
  default_endianness = symbol_BIG_ENDIAN;
198
198
  description = Qnil;
199
- buffer = rb_str_new2("");
199
+ buffer = Qnil;
200
200
  item_class = cPacketItem;
201
201
  break;
202
202
  case 3:
@@ -204,7 +204,7 @@ static VALUE packet_initialize(int argc, VALUE *argv, VALUE self)
204
204
  packet_name = argv[1];
205
205
  default_endianness = argv[2];
206
206
  description = Qnil;
207
- buffer = rb_str_new2("");
207
+ buffer = Qnil;
208
208
  item_class = cPacketItem;
209
209
  break;
210
210
  case 4:
@@ -212,7 +212,7 @@ static VALUE packet_initialize(int argc, VALUE *argv, VALUE self)
212
212
  packet_name = argv[1];
213
213
  default_endianness = argv[2];
214
214
  description = argv[3];
215
- buffer = rb_str_new2("");
215
+ buffer = Qnil;
216
216
  item_class = cPacketItem;
217
217
  break;
218
218
  case 5:
@@ -56,6 +56,7 @@ static ID id_method_reverse = 0;
56
56
  static ID id_method_Integer = 0;
57
57
  static ID id_method_Float = 0;
58
58
  static ID id_method_kind_of = 0;
59
+ static ID id_method_allocate_buffer_if_needed = 0;
59
60
 
60
61
  static ID id_ivar_buffer = 0;
61
62
  static ID id_ivar_bit_offset = 0;
@@ -520,7 +521,8 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
520
521
  {
521
522
  string_length = upper_bound - lower_bound + 1;
522
523
  string = malloc(string_length + 1);
523
- if (string == NULL) {
524
+ if (string == NULL)
525
+ {
524
526
  rb_raise(rb_eNoMemError, "malloc of %d returned NULL", string_length + 1);
525
527
  }
526
528
  memcpy(string, buffer + lower_bound, string_length);
@@ -577,7 +579,8 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
577
579
  string_length = ((bit_size - 1) / 8) + 1;
578
580
  array_length = string_length + 4; /* Required number of bytes plus slack */
579
581
  unsigned_char_array = (unsigned char *)malloc(array_length);
580
- if (unsigned_char_array == NULL) {
582
+ if (unsigned_char_array == NULL)
583
+ {
581
584
  rb_raise(rb_eNoMemError, "malloc of %d returned NULL", array_length);
582
585
  }
583
586
  read_bitfield(lower_bound, upper_bound, bit_offset, bit_size, given_bit_offset, given_bit_size, param_endianness, buffer, (int)buffer_length, unsigned_char_array);
@@ -692,7 +695,8 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
692
695
  string_length = ((bit_size - 1) / 8) + 1;
693
696
  array_length = string_length + 4; /* Required number of bytes plus slack */
694
697
  unsigned_char_array = (unsigned char *)malloc(array_length);
695
- if (unsigned_char_array == NULL) {
698
+ if (unsigned_char_array == NULL)
699
+ {
696
700
  rb_raise(rb_eNoMemError, "malloc of %d returned NULL", array_length);
697
701
  }
698
702
  read_bitfield(lower_bound, upper_bound, bit_offset, bit_size, given_bit_offset, given_bit_size, param_endianness, buffer, (int)buffer_length, unsigned_char_array);
@@ -1147,7 +1151,8 @@ static VALUE binary_accessor_write(VALUE self, VALUE value, VALUE param_bit_offs
1147
1151
  string_length = ((bit_size - 1) / 8) + 1;
1148
1152
  array_length = string_length + 4; /* Required number of bytes plus slack */
1149
1153
  unsigned_char_array = (unsigned char *)malloc(array_length);
1150
- if (unsigned_char_array == NULL) {
1154
+ if (unsigned_char_array == NULL)
1155
+ {
1151
1156
  rb_raise(rb_eNoMemError, "malloc of %d returned NULL", array_length);
1152
1157
  }
1153
1158
 
@@ -1275,15 +1280,8 @@ static VALUE binary_accessor_write(VALUE self, VALUE value, VALUE param_bit_offs
1275
1280
  */
1276
1281
  static int get_int_length(VALUE self)
1277
1282
  {
1278
- volatile VALUE buffer = rb_ivar_get(self, id_ivar_buffer);
1279
- if (RTEST(buffer))
1280
- {
1281
- return (int)RSTRING_LEN(buffer);
1282
- }
1283
- else
1284
- {
1285
- return 0;
1286
- }
1283
+ rb_funcall(self, id_method_allocate_buffer_if_needed, 0);
1284
+ return (int)RSTRING_LEN(rb_ivar_get(self, id_ivar_buffer));
1287
1285
  }
1288
1286
 
1289
1287
  /*
@@ -1310,24 +1308,21 @@ static VALUE read_item_internal(VALUE self, VALUE item, VALUE buffer)
1310
1308
  return Qnil;
1311
1309
  }
1312
1310
 
1313
- if (RTEST(buffer))
1311
+ if (!(RTEST(buffer)))
1314
1312
  {
1315
- bit_offset = rb_ivar_get(item, id_ivar_bit_offset);
1316
- bit_size = rb_ivar_get(item, id_ivar_bit_size);
1317
- array_size = rb_ivar_get(item, id_ivar_array_size);
1318
- endianness = rb_ivar_get(item, id_ivar_endianness);
1319
- if (RTEST(array_size))
1320
- {
1321
- return rb_funcall(cBinaryAccessor, id_method_read_array, 6, bit_offset, bit_size, data_type, array_size, buffer, endianness);
1322
- }
1323
- else
1324
- {
1325
- return binary_accessor_read(cBinaryAccessor, bit_offset, bit_size, data_type, buffer, endianness);
1326
- }
1313
+ buffer = rb_funcall(self, id_method_allocate_buffer_if_needed, 0);
1314
+ }
1315
+ bit_offset = rb_ivar_get(item, id_ivar_bit_offset);
1316
+ bit_size = rb_ivar_get(item, id_ivar_bit_size);
1317
+ array_size = rb_ivar_get(item, id_ivar_array_size);
1318
+ endianness = rb_ivar_get(item, id_ivar_endianness);
1319
+ if (RTEST(array_size))
1320
+ {
1321
+ return rb_funcall(cBinaryAccessor, id_method_read_array, 6, bit_offset, bit_size, data_type, array_size, buffer, endianness);
1327
1322
  }
1328
1323
  else
1329
1324
  {
1330
- rb_raise(rb_eRuntimeError, "No buffer given to read_item");
1325
+ return binary_accessor_read(cBinaryAccessor, bit_offset, bit_size, data_type, buffer, endianness);
1331
1326
  }
1332
1327
  }
1333
1328
 
@@ -1404,8 +1399,8 @@ static VALUE structure_item_spaceship(VALUE self, VALUE other_item)
1404
1399
  if ((bit_offset == 0) && (other_bit_offset == 0))
1405
1400
  {
1406
1401
  /* Both bit_offsets are 0 so sort by bit_size
1407
- * This allows derived items with bit_size of 0 to be listed first
1408
- * Compare based on bit size */
1402
+ * This allows derived items with bit_size of 0 to be listed first
1403
+ * Compare based on bit size */
1409
1404
  bit_size = FIX2INT(rb_ivar_get(self, id_ivar_bit_size));
1410
1405
  other_bit_size = FIX2INT(rb_ivar_get(other_item, id_ivar_bit_size));
1411
1406
  if (bit_size == other_bit_size)
@@ -1518,12 +1513,12 @@ static VALUE structure_initialize(int argc, VALUE *argv, VALUE self)
1518
1513
  {
1519
1514
  case 0:
1520
1515
  default_endianness = HOST_ENDIANNESS;
1521
- buffer = rb_str_new2("");
1516
+ buffer = Qnil;
1522
1517
  item_class = cStructureItem;
1523
1518
  break;
1524
1519
  case 1:
1525
1520
  default_endianness = argv[0];
1526
- buffer = rb_str_new2("");
1521
+ buffer = Qnil;
1527
1522
  item_class = cStructureItem;
1528
1523
  break;
1529
1524
  case 2:
@@ -1592,6 +1587,10 @@ static VALUE resize_buffer(VALUE self)
1592
1587
  rb_str_concat(buffer, rb_str_times(ZERO_STRING, INT2FIX(defined_length - current_length)));
1593
1588
  }
1594
1589
  }
1590
+ else
1591
+ {
1592
+ rb_funcall(self, id_method_allocate_buffer_if_needed, 0);
1593
+ }
1595
1594
 
1596
1595
  return self;
1597
1596
  }
@@ -1618,6 +1617,7 @@ void Init_structure(void)
1618
1617
  id_method_Integer = rb_intern("Integer");
1619
1618
  id_method_Float = rb_intern("Float");
1620
1619
  id_method_kind_of = rb_intern("kind_of?");
1620
+ id_method_allocate_buffer_if_needed = rb_intern("allocate_buffer_if_needed");
1621
1621
 
1622
1622
  MIN_INT8 = INT2NUM(-128);
1623
1623
  MAX_INT8 = INT2NUM(127);
@@ -111,11 +111,11 @@ module Cosmos
111
111
 
112
112
  # Injects a packet into the system as if it was received from an interface
113
113
  #
114
- # @param target_name[String] Target name of the packet
115
- # @param packet_name[String] Packet name of the packet
116
- # @param item_hash[Hash] Hash of item_name and value for each item you want to change from the current value table
114
+ # @param target_name [String] Target name of the packet
115
+ # @param packet_name [String] Packet name of the packet
116
+ # @param item_hash [Hash] Hash of item_name and value for each item you want to change from the current value table
117
117
  # @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
118
- def inject_tlm(target_name, packet_name, item_hash = nil, log: true, type: :CONVERTED, scope: $cosmos_scope, token: $cosmos_token)
118
+ def inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, scope: $cosmos_scope, token: $cosmos_token)
119
119
  authorize(permission: 'tlm_set', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
120
120
  unless CvtModel::VALUE_TYPES.include?(type.intern)
121
121
  raise "Unknown type '#{type}' for #{target_name} #{packet_name}"