cosmos 3.3.3 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitattributes +2 -0
- data/.travis.yml +2 -1
- data/Gemfile +4 -3
- data/Manifest.txt +22 -0
- data/autohotkey/tools/handbook_creator.ahk +9 -0
- data/autohotkey/tools/packet_viewer.ahk +4 -0
- data/bin/exchndl20-x64.dll +0 -0
- data/bin/exchndl20.dll +0 -0
- data/bin/exchndl21-x64.dll +0 -0
- data/bin/exchndl21.dll +0 -0
- data/bin/exchndl22-x64.dll +0 -0
- data/bin/exchndl22.dll +0 -0
- data/bin/mgwhelp-x64.dll +0 -0
- data/bin/mgwhelp.dll +0 -0
- data/cosmos.gemspec +1 -0
- data/data/crc.txt +30 -24
- data/demo/config/data/crc.txt +3 -3
- data/demo/config/tools/handbook_creator/templates/command_packets.html.erb +3 -1
- data/demo/config/tools/handbook_creator/templates/telemetry_packets.html.erb +3 -1
- data/demo/procedures/cosmos_api_test.rb +1 -1
- data/ext/cosmos/ext/low_fragmentation_array/low_fragmentation_array.c +4 -0
- data/ext/cosmos/ext/platform/platform.c +22 -2
- data/ext/cosmos/ext/structure/structure.c +631 -104
- data/ext/cosmos/ext/telemetry/telemetry.c +3 -2
- data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +71 -92
- data/lib/cosmos/gui/line_graph/overview_graph.rb +1 -1
- data/lib/cosmos/gui/qt.rb +38 -24
- data/lib/cosmos/gui/text/ruby_editor.rb +1 -1
- data/lib/cosmos/packets/binary_accessor.rb +1 -288
- data/lib/cosmos/packets/telemetry.rb +2 -1
- data/lib/cosmos/script/cmd_tlm_server.rb +110 -0
- data/lib/cosmos/script/commands.rb +166 -0
- data/lib/cosmos/script/extract.rb +2 -2
- data/lib/cosmos/script/limits.rb +108 -0
- data/lib/cosmos/script/script.rb +28 -1487
- data/lib/cosmos/script/scripting.rb +889 -0
- data/lib/cosmos/script/telemetry.rb +174 -0
- data/lib/cosmos/script/tools.rb +138 -0
- data/lib/cosmos/streams/stream_protocol.rb +9 -6
- data/lib/cosmos/system/target.rb +55 -38
- data/lib/cosmos/tools/cmd_tlm_server/api.rb +6 -3
- data/lib/cosmos/tools/cmd_tlm_server/connections.rb +0 -1
- data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +17 -7
- data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +15 -4
- data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +15 -8
- data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +41 -13
- data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +18 -1
- data/lib/cosmos/tools/tlm_viewer/widgets/canvasline_widget.rb +1 -1
- data/lib/cosmos/tools/tlm_viewer/widgets/canvaslinevalue_widget.rb +1 -1
- data/lib/cosmos/tools/tlm_viewer/widgets/limitsbar_widget.rb +1 -1
- data/lib/cosmos/tools/tlm_viewer/widgets/rangebar_widget.rb +1 -1
- data/lib/cosmos/top_level.rb +1 -1
- data/lib/cosmos/utilities/ruby_lex_utils.rb +1 -1
- data/lib/cosmos/version.rb +5 -5
- data/spec/gui/line_graph/line_clip_spec.rb +6 -6
- data/spec/gui/qt_spec.rb +102 -0
- data/spec/interfaces/interface_spec.rb +9 -9
- data/spec/interfaces/linc_interface_spec.rb +72 -15
- data/spec/interfaces/serial_interface_spec.rb +9 -9
- data/spec/interfaces/simulated_target_interface_spec.rb +7 -7
- data/spec/interfaces/stream_interface_spec.rb +4 -4
- data/spec/interfaces/tcpip_client_interface_spec.rb +8 -8
- data/spec/interfaces/tcpip_server_interface_spec.rb +9 -9
- data/spec/interfaces/udp_interface_spec.rb +20 -20
- data/spec/io/json_drb_spec.rb +4 -4
- data/spec/io/raw_logger_pair_spec.rb +20 -20
- data/spec/io/raw_logger_spec.rb +3 -3
- data/spec/io/tcpip_server_spec.rb +9 -9
- data/spec/io/udp_sockets_spec.rb +2 -2
- data/spec/io/win32_serial_driver_spec.rb +2 -2
- data/spec/packets/binary_accessor_spec.rb +143 -6
- data/spec/packets/commands_spec.rb +5 -5
- data/spec/packets/limits_spec.rb +15 -15
- data/spec/packets/packet_config_spec.rb +19 -19
- data/spec/packets/packet_item_limits_spec.rb +3 -3
- data/spec/packets/packet_item_spec.rb +4 -4
- data/spec/packets/packet_spec.rb +33 -33
- data/spec/packets/structure_item_spec.rb +19 -19
- data/spec/packets/telemetry_spec.rb +6 -6
- data/spec/script/cmd_tlm_server_spec.rb +110 -0
- data/spec/script/commands_disconnect_spec.rb +270 -0
- data/spec/script/commands_spec.rb +288 -0
- data/spec/script/limits_spec.rb +153 -0
- data/spec/script/script_spec.rb +32 -696
- data/spec/script/scripting_spec.rb +436 -0
- data/spec/script/telemetry_spec.rb +130 -0
- data/spec/script/tools_spec.rb +117 -0
- data/spec/spec_helper.rb +10 -5
- data/spec/streams/preidentified_stream_protocol_spec.rb +4 -4
- data/spec/streams/serial_stream_spec.rb +8 -8
- data/spec/streams/stream_protocol_spec.rb +4 -4
- data/spec/streams/tcpip_client_stream_spec.rb +3 -3
- data/spec/streams/tcpip_socket_stream_spec.rb +7 -7
- data/spec/streams/template_stream_protocol_spec.rb +1 -1
- data/spec/system/system_spec.rb +6 -6
- data/spec/system/target_spec.rb +2 -0
- data/spec/tools/cmd_tlm_server/api_spec.rb +17 -17
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +5 -5
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +3 -3
- data/spec/top_level/top_level_spec.rb +8 -8
- data/spec/utilities/csv_spec.rb +3 -3
- data/spec/utilities/message_log_spec.rb +3 -3
- data/spec/utilities/ruby_lex_utils_spec.rb +7 -7
- data/test/performance/config/tools/launcher/launcher_threads.txt +8 -1
- data/test/performance/tools/CmdTlmServerMemProf +1 -1
- data/test/performance/tools/TlmGrapherMemProf +19 -0
- data/test/performance/tools/TlmGrapherMemProf.bat +59 -0
- metadata +38 -2
|
@@ -11,11 +11,27 @@
|
|
|
11
11
|
#include "ruby.h"
|
|
12
12
|
#include "stdio.h"
|
|
13
13
|
|
|
14
|
+
#define TO_BIGNUM(x) (FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x)
|
|
15
|
+
#define BYTE_ALIGNED(x) (((x) % 8) == 0)
|
|
16
|
+
|
|
14
17
|
static const int endianness_check = 1;
|
|
15
18
|
static VALUE HOST_ENDIANNESS = Qnil;
|
|
16
19
|
static VALUE ZERO_STRING = Qnil;
|
|
17
20
|
static VALUE ASCII_8BIT_STRING = Qnil;
|
|
18
21
|
|
|
22
|
+
static VALUE MIN_INT8 = Qnil;
|
|
23
|
+
static VALUE MAX_INT8 = Qnil;
|
|
24
|
+
static VALUE MAX_UINT8 = Qnil;
|
|
25
|
+
static VALUE MIN_INT16 = Qnil;
|
|
26
|
+
static VALUE MAX_INT16 = Qnil;
|
|
27
|
+
static VALUE MAX_UINT16 = Qnil;
|
|
28
|
+
static VALUE MIN_INT32 = Qnil;
|
|
29
|
+
static VALUE MAX_INT32 = Qnil;
|
|
30
|
+
static VALUE MAX_UINT32 = Qnil;
|
|
31
|
+
static VALUE MIN_INT64 = Qnil;
|
|
32
|
+
static VALUE MAX_INT64 = Qnil;
|
|
33
|
+
static VALUE MAX_UINT64 = Qnil;
|
|
34
|
+
|
|
19
35
|
static VALUE mCosmos = Qnil;
|
|
20
36
|
static VALUE cBinaryAccessor = Qnil;
|
|
21
37
|
static VALUE cStructure = Qnil;
|
|
@@ -26,6 +42,10 @@ static ID id_method_raise_buffer_error = 0;
|
|
|
26
42
|
static ID id_method_read_array = 0;
|
|
27
43
|
static ID id_method_force_encoding = 0;
|
|
28
44
|
static ID id_method_freeze = 0;
|
|
45
|
+
static ID id_method_slice = 0;
|
|
46
|
+
static ID id_method_reverse = 0;
|
|
47
|
+
static ID id_method_Integer = 0;
|
|
48
|
+
static ID id_method_Float = 0;
|
|
29
49
|
|
|
30
50
|
static ID id_ivar_buffer = 0;
|
|
31
51
|
static ID id_ivar_bit_offset = 0;
|
|
@@ -56,6 +76,11 @@ static VALUE symbol_STRING = Qnil;
|
|
|
56
76
|
static VALUE symbol_BLOCK = Qnil;
|
|
57
77
|
static VALUE symbol_DERIVED = Qnil;
|
|
58
78
|
static VALUE symbol_read = Qnil;
|
|
79
|
+
static VALUE symbol_write = Qnil;
|
|
80
|
+
static VALUE symbol_TRUNCATE = Qnil;
|
|
81
|
+
static VALUE symbol_SATURATE = Qnil;
|
|
82
|
+
static VALUE symbol_ERROR = Qnil;
|
|
83
|
+
static VALUE symbol_ERROR_ALLOW_HEX = Qnil;
|
|
59
84
|
|
|
60
85
|
/*
|
|
61
86
|
* Perform an left bit shift on a string
|
|
@@ -267,6 +292,124 @@ static void read_bitfield(int lower_bound, int upper_bound, int bit_offset, int
|
|
|
267
292
|
unsigned_shift_byte_array(read_value, num_bytes, -start_bits);
|
|
268
293
|
}
|
|
269
294
|
|
|
295
|
+
static void write_bitfield(int lower_bound, int upper_bound, int bit_offset, int bit_size, int given_bit_offset, int given_bit_size, VALUE endianness, unsigned char* buffer, int buffer_length, unsigned char* write_value) {
|
|
296
|
+
/* Local variables */
|
|
297
|
+
int num_bytes = 0;
|
|
298
|
+
int total_bits = 0;
|
|
299
|
+
int start_bits = 0;
|
|
300
|
+
int end_bits = 0;
|
|
301
|
+
int temp_upper = 0;
|
|
302
|
+
unsigned char start_mask = 0;
|
|
303
|
+
unsigned char end_mask = 0;
|
|
304
|
+
|
|
305
|
+
if (endianness == symbol_LITTLE_ENDIAN)
|
|
306
|
+
{
|
|
307
|
+
/* Bitoffset always refers to the most significant bit of a bitfield */
|
|
308
|
+
num_bytes = (((bit_offset % 8) + bit_size - 1) / 8) + 1;
|
|
309
|
+
upper_bound = bit_offset / 8;
|
|
310
|
+
lower_bound = upper_bound - num_bytes + 1;
|
|
311
|
+
|
|
312
|
+
if (lower_bound < 0) {
|
|
313
|
+
rb_raise(rb_eArgError, "LITTLE_ENDIAN bitfield with bit_offset %d and bit_size %d is invalid", given_bit_offset, given_bit_size);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else
|
|
317
|
+
{
|
|
318
|
+
num_bytes = upper_bound - lower_bound + 1;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* Determine temp upper bound */
|
|
322
|
+
temp_upper = upper_bound - lower_bound;
|
|
323
|
+
|
|
324
|
+
/* Handle Bitfield */
|
|
325
|
+
total_bits = (temp_upper + 1) * 8;
|
|
326
|
+
start_bits = bit_offset % 8;
|
|
327
|
+
start_mask = 0xFF << (8 - start_bits);
|
|
328
|
+
end_bits = total_bits - start_bits - bit_size;
|
|
329
|
+
end_mask = 0xFF >> (8 - end_bits);
|
|
330
|
+
|
|
331
|
+
/* Shift to the right position */
|
|
332
|
+
unsigned_shift_byte_array(write_value, num_bytes, start_bits);
|
|
333
|
+
|
|
334
|
+
if (endianness == symbol_LITTLE_ENDIAN)
|
|
335
|
+
{
|
|
336
|
+
/* Mask in wanted bits at beginning */
|
|
337
|
+
write_value[0] |= buffer[upper_bound] & start_mask;
|
|
338
|
+
|
|
339
|
+
/* Mask in wanted bits at the end */
|
|
340
|
+
write_value[temp_upper] |= buffer[lower_bound] & end_mask;
|
|
341
|
+
|
|
342
|
+
reverse_bytes(write_value, num_bytes);
|
|
343
|
+
}
|
|
344
|
+
else
|
|
345
|
+
{
|
|
346
|
+
/* Mask in wanted bits at beginning */
|
|
347
|
+
write_value[0] |= buffer[lower_bound] & start_mask;
|
|
348
|
+
|
|
349
|
+
/* Mask in wanted bits at the end */
|
|
350
|
+
write_value[temp_upper] |= buffer[upper_bound] & end_mask;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/* Write the bytes into the buffer */
|
|
354
|
+
memcpy(&buffer[lower_bound], write_value, num_bytes);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* Check the bit size and bit offset for problems. Recalulate the bit offset
|
|
358
|
+
* and return back through the passed in pointer. */
|
|
359
|
+
static void check_bit_offset_and_size(VALUE self, VALUE type_param, VALUE bit_offset_param, VALUE bit_size_param, VALUE data_type_param, VALUE buffer_param, int *new_bit_offset)
|
|
360
|
+
{
|
|
361
|
+
int bit_offset = NUM2INT(bit_offset_param);
|
|
362
|
+
int bit_size = NUM2INT(bit_size_param);
|
|
363
|
+
|
|
364
|
+
if ((bit_size <= 0) && (data_type_param != symbol_STRING) && (data_type_param != symbol_BLOCK)) {
|
|
365
|
+
rb_raise(rb_eArgError, "bit_size %d must be positive for data types other than :STRING and :BLOCK", bit_size);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if ((bit_size <= 0) && (bit_offset < 0)) {
|
|
369
|
+
rb_raise(rb_eArgError, "negative or zero bit_sizes (%d) cannot be given with negative bit_offsets (%d)", bit_size, bit_offset);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (bit_offset < 0) {
|
|
373
|
+
bit_offset = ((RSTRING_LEN(buffer_param)* 8) + bit_offset);
|
|
374
|
+
if (bit_offset < 0) {
|
|
375
|
+
rb_funcall(self, id_method_raise_buffer_error, 5, type_param, buffer_param, data_type_param, bit_offset_param, bit_size_param);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
*new_bit_offset = bit_offset;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* Returns true if the bit_size is 8, 16, 32, or 64 */
|
|
383
|
+
static int even_bit_size(int bit_size)
|
|
384
|
+
{
|
|
385
|
+
return ((bit_size == 8) || (bit_size == 16) || (bit_size == 32) || (bit_size == 64));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* Calculate the bounds of the string to access the item based on the bit_offset and bit_size.
|
|
389
|
+
* Also determine if the buffer size is sufficient. */
|
|
390
|
+
static int check_bounds_and_buffer_size(int bit_offset, int bit_size, int buffer_length, VALUE endianness, VALUE data_type, int *lower_bound, int *upper_bound)
|
|
391
|
+
{
|
|
392
|
+
int result = 1; /* Assume ok */
|
|
393
|
+
|
|
394
|
+
/* Define bounds of string to access this item */
|
|
395
|
+
*lower_bound = bit_offset / 8;
|
|
396
|
+
*upper_bound = (bit_offset + bit_size - 1) / 8;
|
|
397
|
+
|
|
398
|
+
/* Sanity check buffer size */
|
|
399
|
+
if (*upper_bound >= buffer_length) {
|
|
400
|
+
/* If it's not the special case of little endian bit field then we fail and return 0 */
|
|
401
|
+
if (!( (endianness == symbol_LITTLE_ENDIAN) &&
|
|
402
|
+
((data_type == symbol_INT) || (data_type == symbol_UINT)) &&
|
|
403
|
+
/* Not byte aligned with an even bit size */
|
|
404
|
+
(!( (BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)) )) &&
|
|
405
|
+
(*lower_bound < buffer_length)
|
|
406
|
+
)) {
|
|
407
|
+
result = 0;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
|
|
270
413
|
/*
|
|
271
414
|
* Reads binary data of any data type from a buffer
|
|
272
415
|
*
|
|
@@ -310,7 +453,6 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
310
453
|
int num_words = 0;
|
|
311
454
|
int upper_bound = 0;
|
|
312
455
|
int lower_bound = 0;
|
|
313
|
-
int byte_aligned = 0;
|
|
314
456
|
VALUE temp_value = Qnil;
|
|
315
457
|
VALUE return_value = Qnil;
|
|
316
458
|
|
|
@@ -321,56 +463,31 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
321
463
|
buffer = (unsigned char*) RSTRING_PTR(param_buffer);
|
|
322
464
|
buffer_length = RSTRING_LEN(param_buffer);
|
|
323
465
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (given_bit_size <= 0) {
|
|
327
|
-
rb_raise(rb_eArgError, "negative or zero bit_sizes (%d) cannot be given with negative bit_offsets (%d)", given_bit_size, given_bit_offset);
|
|
328
|
-
} else {
|
|
329
|
-
bit_offset = (((int)buffer_length * 8) + bit_offset);
|
|
330
|
-
if (bit_offset < 0) {
|
|
331
|
-
rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
466
|
+
check_bit_offset_and_size(self, symbol_read, param_bit_offset, param_bit_size,
|
|
467
|
+
param_data_type, param_buffer, &bit_offset);
|
|
335
468
|
|
|
336
|
-
/*
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
} else {
|
|
346
|
-
rb_raise(rb_eArgError, "bit_size %d must be positive for data types other than :STRING and :BLOCK", given_bit_size);
|
|
469
|
+
/* If passed a negative bit size with strings or blocks
|
|
470
|
+
* recalculate based on the buffer length */
|
|
471
|
+
if ((bit_size <= 0) && ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK))) {
|
|
472
|
+
bit_size = (((int)buffer_length * 8) - bit_offset + bit_size);
|
|
473
|
+
if (bit_size == 0) {
|
|
474
|
+
return rb_str_new2("");
|
|
475
|
+
} else if (bit_size < 0) {
|
|
476
|
+
rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
|
|
347
477
|
}
|
|
348
478
|
}
|
|
349
479
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
/* Check for byte alignment */
|
|
355
|
-
byte_aligned = ((bit_offset % 8) == 0);
|
|
356
|
-
|
|
357
|
-
/* Sanity check buffer size */
|
|
358
|
-
if (upper_bound >= buffer_length) {
|
|
359
|
-
/* Check special case of little endian bit field */
|
|
360
|
-
if ((param_endianness == symbol_LITTLE_ENDIAN) && ((param_data_type == symbol_INT) || (param_data_type == symbol_UINT)) && (!((byte_aligned) && ((bit_size == 8) || (bit_size == 16) || (bit_size == 32) || (bit_size == 64)))) && (lower_bound < buffer_length)) {
|
|
361
|
-
/* Ok little endian bit field */
|
|
362
|
-
} else {
|
|
363
|
-
rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
|
|
364
|
-
}
|
|
480
|
+
if (!check_bounds_and_buffer_size(bit_offset, bit_size, buffer_length, param_endianness, param_data_type, &lower_bound, &upper_bound))
|
|
481
|
+
{
|
|
482
|
+
rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
|
|
365
483
|
}
|
|
366
484
|
|
|
367
485
|
if ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK)) {
|
|
368
|
-
|
|
369
486
|
/*#######################################
|
|
370
|
-
|
|
371
|
-
|
|
487
|
+
*# Handle :STRING and :BLOCK data types
|
|
488
|
+
*#######################################*/
|
|
372
489
|
|
|
373
|
-
if (
|
|
490
|
+
if (BYTE_ALIGNED(bit_offset)) {
|
|
374
491
|
string_length = upper_bound - lower_bound + 1;
|
|
375
492
|
string = malloc(string_length + 1);
|
|
376
493
|
memcpy(string, buffer + lower_bound, string_length);
|
|
@@ -386,35 +503,33 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
386
503
|
}
|
|
387
504
|
|
|
388
505
|
} else if (param_data_type == symbol_INT) {
|
|
389
|
-
|
|
390
506
|
/*###################################
|
|
391
|
-
|
|
392
|
-
|
|
507
|
+
*# Handle :INT data type
|
|
508
|
+
*###################################*/
|
|
393
509
|
|
|
394
|
-
if ((
|
|
510
|
+
if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
|
|
511
|
+
{
|
|
395
512
|
/*###########################################################
|
|
396
|
-
|
|
397
|
-
|
|
513
|
+
*# Handle byte-aligned 8, 16, 32, and 64 bit :INT
|
|
514
|
+
*###########################################################*/
|
|
398
515
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_long_long_value);
|
|
417
|
-
return_value = LL2NUM(signed_long_long_value);
|
|
516
|
+
switch (bit_size) {
|
|
517
|
+
case 8:
|
|
518
|
+
signed_char_value = *((signed char*) &buffer[lower_bound]);
|
|
519
|
+
return_value = INT2FIX(signed_char_value);
|
|
520
|
+
break;
|
|
521
|
+
case 16:
|
|
522
|
+
read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_short_value);
|
|
523
|
+
return_value = INT2FIX(signed_short_value);
|
|
524
|
+
break;
|
|
525
|
+
case 32:
|
|
526
|
+
read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_int_value);
|
|
527
|
+
return_value = INT2NUM(signed_int_value);
|
|
528
|
+
break;
|
|
529
|
+
case 64:
|
|
530
|
+
read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_long_long_value);
|
|
531
|
+
return_value = LL2NUM(signed_long_long_value);
|
|
532
|
+
break;
|
|
418
533
|
}
|
|
419
534
|
} else {
|
|
420
535
|
string_length = ((bit_size - 1)/ 8) + 1;
|
|
@@ -466,7 +581,7 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
466
581
|
signed_long_value = FIX2LONG(return_value);
|
|
467
582
|
return_value = rb_int2big(signed_long_value);
|
|
468
583
|
}
|
|
469
|
-
return_value = rb_big_plus(return_value,
|
|
584
|
+
return_value = rb_big_plus(return_value, UINT2NUM(*((unsigned int*) &(unsigned_char_array[index]))));
|
|
470
585
|
if (FIXNUM_P(return_value)) {
|
|
471
586
|
signed_long_value = FIX2LONG(return_value);
|
|
472
587
|
return_value = rb_int2big(signed_long_value);
|
|
@@ -479,35 +594,33 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
479
594
|
}
|
|
480
595
|
|
|
481
596
|
} else if (param_data_type == symbol_UINT) {
|
|
482
|
-
|
|
483
597
|
/*###################################
|
|
484
|
-
|
|
485
|
-
|
|
598
|
+
*# Handle :UINT data type
|
|
599
|
+
*###################################*/
|
|
486
600
|
|
|
487
|
-
if ((
|
|
601
|
+
if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
|
|
602
|
+
{
|
|
488
603
|
/*###########################################################
|
|
489
|
-
|
|
490
|
-
|
|
604
|
+
*# Handle byte-aligned 8, 16, 32, and 64 bit :UINT
|
|
605
|
+
*###########################################################*/
|
|
491
606
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_long_long_value);
|
|
510
|
-
return_value = ULL2NUM(unsigned_long_long_value);
|
|
607
|
+
switch (bit_size) {
|
|
608
|
+
case 8:
|
|
609
|
+
unsigned_char_value = buffer[lower_bound];
|
|
610
|
+
return_value = INT2FIX(unsigned_char_value);
|
|
611
|
+
break;
|
|
612
|
+
case 16:
|
|
613
|
+
read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_short_value);
|
|
614
|
+
return_value = INT2FIX(unsigned_short_value);
|
|
615
|
+
break;
|
|
616
|
+
case 32:
|
|
617
|
+
read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_int_value);
|
|
618
|
+
return_value = UINT2NUM(unsigned_int_value);
|
|
619
|
+
break;
|
|
620
|
+
case 64:
|
|
621
|
+
read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_long_long_value);
|
|
622
|
+
return_value = ULL2NUM(unsigned_long_long_value);
|
|
623
|
+
break;
|
|
511
624
|
}
|
|
512
625
|
} else {
|
|
513
626
|
string_length = ((bit_size - 1)/ 8) + 1;
|
|
@@ -549,7 +662,7 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
549
662
|
signed_long_value = FIX2LONG(return_value);
|
|
550
663
|
return_value = rb_int2big(signed_long_value);
|
|
551
664
|
}
|
|
552
|
-
return_value = rb_big_plus(return_value,
|
|
665
|
+
return_value = rb_big_plus(return_value, UINT2NUM(*((unsigned int*) &(unsigned_char_array[index]))));
|
|
553
666
|
if (FIXNUM_P(return_value)) {
|
|
554
667
|
signed_long_value = FIX2LONG(return_value);
|
|
555
668
|
return_value = rb_int2big(signed_long_value);
|
|
@@ -562,12 +675,11 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
562
675
|
}
|
|
563
676
|
|
|
564
677
|
} else if (param_data_type == symbol_FLOAT) {
|
|
565
|
-
|
|
566
678
|
/*##########################
|
|
567
|
-
|
|
568
|
-
|
|
679
|
+
*# Handle :FLOAT data type
|
|
680
|
+
*##########################*/
|
|
569
681
|
|
|
570
|
-
if (
|
|
682
|
+
if (BYTE_ALIGNED(bit_offset)) {
|
|
571
683
|
switch (bit_size) {
|
|
572
684
|
case 32:
|
|
573
685
|
read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &float_value);
|
|
@@ -588,10 +700,9 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
588
700
|
}
|
|
589
701
|
|
|
590
702
|
} else {
|
|
591
|
-
|
|
592
703
|
/*############################
|
|
593
|
-
|
|
594
|
-
|
|
704
|
+
*# Handle Unknown data types
|
|
705
|
+
*############################*/
|
|
595
706
|
|
|
596
707
|
rb_raise(rb_eArgError, "data_type %s is not recognized", RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
|
|
597
708
|
}
|
|
@@ -599,6 +710,381 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
|
|
|
599
710
|
return return_value;
|
|
600
711
|
}
|
|
601
712
|
|
|
713
|
+
static VALUE check_overflow(VALUE value, int bit_size, VALUE data_type, VALUE overflow)
|
|
714
|
+
{
|
|
715
|
+
VALUE hex_max_value = Qnil;
|
|
716
|
+
VALUE max_value = Qnil;
|
|
717
|
+
VALUE min_value = INT2NUM(0); /* Default for UINT cases */
|
|
718
|
+
|
|
719
|
+
switch (bit_size) {
|
|
720
|
+
case 8:
|
|
721
|
+
hex_max_value = MAX_UINT8;
|
|
722
|
+
if (data_type == symbol_INT) {
|
|
723
|
+
min_value = MIN_INT8;
|
|
724
|
+
max_value = MAX_INT8;
|
|
725
|
+
} else {
|
|
726
|
+
max_value = MAX_UINT8;
|
|
727
|
+
}
|
|
728
|
+
break;
|
|
729
|
+
case 16:
|
|
730
|
+
hex_max_value = MAX_UINT16;
|
|
731
|
+
if (data_type == symbol_INT) {
|
|
732
|
+
min_value = MIN_INT16;
|
|
733
|
+
max_value = MAX_INT16;
|
|
734
|
+
} else {
|
|
735
|
+
max_value = MAX_UINT16;
|
|
736
|
+
}
|
|
737
|
+
break;
|
|
738
|
+
case 32:
|
|
739
|
+
hex_max_value = MAX_UINT32;
|
|
740
|
+
if (data_type == symbol_INT) {
|
|
741
|
+
min_value = MIN_INT32;
|
|
742
|
+
max_value = MAX_INT32;
|
|
743
|
+
} else {
|
|
744
|
+
max_value = MAX_UINT32;
|
|
745
|
+
}
|
|
746
|
+
break;
|
|
747
|
+
case 64:
|
|
748
|
+
hex_max_value = MAX_UINT64;
|
|
749
|
+
if (data_type == symbol_INT) {
|
|
750
|
+
min_value = MIN_INT64;
|
|
751
|
+
max_value = MAX_INT64;
|
|
752
|
+
} else {
|
|
753
|
+
max_value = MAX_UINT64;
|
|
754
|
+
}
|
|
755
|
+
break;
|
|
756
|
+
default: /* Bitfield */
|
|
757
|
+
if (data_type == symbol_INT) {
|
|
758
|
+
/* Note signed integers must allow up to the maximum unsigned value to support values given in hex */
|
|
759
|
+
if (bit_size > 1) {
|
|
760
|
+
max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size - 1));
|
|
761
|
+
/* min_value = -(2 ** bit_size - 1) */
|
|
762
|
+
min_value = rb_big_minus(TO_BIGNUM(INT2NUM(0)), max_value);
|
|
763
|
+
/* max_value = (2 ** bit_size - 1) - 1 */
|
|
764
|
+
max_value = rb_big_minus(TO_BIGNUM(max_value), INT2NUM(1));
|
|
765
|
+
/* hex_max_value = (2 ** bit_size) - 1 */
|
|
766
|
+
hex_max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size));
|
|
767
|
+
hex_max_value = rb_big_minus(TO_BIGNUM(hex_max_value), INT2NUM(1));
|
|
768
|
+
} else { /* 1-bit signed */
|
|
769
|
+
min_value = INT2NUM(-1);
|
|
770
|
+
max_value = INT2NUM(1);
|
|
771
|
+
hex_max_value = INT2NUM(1);
|
|
772
|
+
}
|
|
773
|
+
} else {
|
|
774
|
+
max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size));
|
|
775
|
+
max_value = rb_big_minus(TO_BIGNUM(max_value), INT2NUM(1));
|
|
776
|
+
hex_max_value = max_value;
|
|
777
|
+
}
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
780
|
+
/* Convert all to Bignum objects so we can do the math the same way */
|
|
781
|
+
value = TO_BIGNUM(value);
|
|
782
|
+
min_value = TO_BIGNUM(min_value);
|
|
783
|
+
max_value = TO_BIGNUM(max_value);
|
|
784
|
+
hex_max_value = TO_BIGNUM(hex_max_value);
|
|
785
|
+
|
|
786
|
+
if (overflow == symbol_TRUNCATE) {
|
|
787
|
+
/* Note this will always convert to unsigned equivalent for signed integers */
|
|
788
|
+
value = rb_big_modulo(value, TO_BIGNUM(rb_big_plus(hex_max_value, INT2NUM(1))));
|
|
789
|
+
} else {
|
|
790
|
+
if (rb_big_cmp(value, max_value) == INT2FIX(1)) {
|
|
791
|
+
if (overflow == symbol_SATURATE) {
|
|
792
|
+
value = max_value;
|
|
793
|
+
} else {
|
|
794
|
+
if ((overflow == symbol_ERROR) || (rb_big_cmp(value, hex_max_value) == INT2FIX(1))) {
|
|
795
|
+
rb_raise(rb_eArgError, "value of %s invalid for %d-bit %s",
|
|
796
|
+
RSTRING_PTR(rb_funcall(value, id_method_to_s, 0)),
|
|
797
|
+
bit_size,
|
|
798
|
+
RSTRING_PTR(rb_funcall(data_type, id_method_to_s, 0)));
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
} else if (rb_big_cmp(value, min_value) == INT2FIX(-1)) {
|
|
802
|
+
if (overflow == symbol_SATURATE) {
|
|
803
|
+
value = min_value;
|
|
804
|
+
} else {
|
|
805
|
+
rb_raise(rb_eArgError, "value of %s invalid for %d-bit %s",
|
|
806
|
+
RSTRING_PTR(rb_funcall(value, id_method_to_s, 0)),
|
|
807
|
+
bit_size,
|
|
808
|
+
RSTRING_PTR(rb_funcall(data_type, id_method_to_s, 0)));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
return rb_big_norm(value);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/*
|
|
817
|
+
* Writes binary data of any data type to a buffer
|
|
818
|
+
*
|
|
819
|
+
* @param bit_offset [Integer] Bit offset to the start of the item. A
|
|
820
|
+
* negative number means to offset from the end of the buffer.
|
|
821
|
+
* @param bit_size [Integer] Size of the item in bits
|
|
822
|
+
* @param data_type [Symbol] {DATA_TYPES}
|
|
823
|
+
* @param buffer [String] Binary string buffer to read from
|
|
824
|
+
* @param endianness [Symbol] {ENDIANNESS}
|
|
825
|
+
* @return [Integer] value read from the buffer
|
|
826
|
+
*/
|
|
827
|
+
static VALUE binary_accessor_write(VALUE self, VALUE value, VALUE param_bit_offset, VALUE param_bit_size, VALUE param_data_type, VALUE param_buffer, VALUE param_endianness, VALUE param_overflow)
|
|
828
|
+
{
|
|
829
|
+
/* Convert Parameters to C Data Types */
|
|
830
|
+
int bit_offset = NUM2INT(param_bit_offset);
|
|
831
|
+
int bit_size = NUM2INT(param_bit_size);
|
|
832
|
+
/* Local Variables */
|
|
833
|
+
int given_bit_offset = bit_offset;
|
|
834
|
+
int given_bit_size = bit_size;
|
|
835
|
+
int upper_bound = 0;
|
|
836
|
+
int lower_bound = 0;
|
|
837
|
+
int end_bytes = 0;
|
|
838
|
+
int old_upper_bound = 0;
|
|
839
|
+
int byte_size = 0;
|
|
840
|
+
|
|
841
|
+
unsigned long long c_value = 0;
|
|
842
|
+
float float_value = 0.0;
|
|
843
|
+
double double_value = 0.0;
|
|
844
|
+
|
|
845
|
+
unsigned char* buffer = NULL;
|
|
846
|
+
long buffer_length = 0;
|
|
847
|
+
long value_length = 0;
|
|
848
|
+
VALUE temp_shift = Qnil;
|
|
849
|
+
VALUE temp_mask = Qnil;
|
|
850
|
+
VALUE temp_result = Qnil;
|
|
851
|
+
|
|
852
|
+
int string_length = 0;
|
|
853
|
+
unsigned char* unsigned_char_array = NULL;
|
|
854
|
+
int array_length = 0;
|
|
855
|
+
int shift_needed = 0;
|
|
856
|
+
int shift_count = 0;
|
|
857
|
+
int index = 0;
|
|
858
|
+
int num_bits = 0;
|
|
859
|
+
int num_bytes = 0;
|
|
860
|
+
int num_words = 0;
|
|
861
|
+
|
|
862
|
+
Check_Type(param_buffer, T_STRING);
|
|
863
|
+
buffer = (unsigned char*) RSTRING_PTR(param_buffer);
|
|
864
|
+
buffer_length = RSTRING_LEN(param_buffer);
|
|
865
|
+
|
|
866
|
+
check_bit_offset_and_size(self, symbol_write, param_bit_offset, param_bit_size,
|
|
867
|
+
param_data_type, param_buffer, &bit_offset);
|
|
868
|
+
|
|
869
|
+
/* If passed a negative bit size with strings or blocks
|
|
870
|
+
* recalculate based on the value length in bytes */
|
|
871
|
+
if ((bit_size <= 0) && ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK))) {
|
|
872
|
+
if (!RB_TYPE_P(value, T_STRING)) {
|
|
873
|
+
value = rb_funcall(value, id_method_to_s, 0);
|
|
874
|
+
}
|
|
875
|
+
bit_size = RSTRING_LEN(value) * 8;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if ((!check_bounds_and_buffer_size(bit_offset, bit_size, buffer_length, param_endianness, param_data_type, &lower_bound, &upper_bound)) && (given_bit_size > 0)) {
|
|
879
|
+
rb_funcall(self, id_method_raise_buffer_error, 5, symbol_write, param_buffer, param_data_type, param_bit_offset, param_bit_size);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/* Check overflow type */
|
|
883
|
+
if ((param_overflow != symbol_TRUNCATE) &&
|
|
884
|
+
(param_overflow != symbol_SATURATE) &&
|
|
885
|
+
(param_overflow != symbol_ERROR) &&
|
|
886
|
+
(param_overflow != symbol_ERROR_ALLOW_HEX)) {
|
|
887
|
+
rb_raise(rb_eArgError, "unknown overflow type %s", RSTRING_PTR(rb_funcall(param_overflow, id_method_to_s, 0)));
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK)) {
|
|
891
|
+
/*#######################################
|
|
892
|
+
*# Handle :STRING and :BLOCK data types
|
|
893
|
+
*#######################################*/
|
|
894
|
+
/* Force value to be a string */
|
|
895
|
+
if (!RB_TYPE_P(value, T_STRING)) {
|
|
896
|
+
value = rb_funcall(value, id_method_to_s, 0);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (BYTE_ALIGNED(bit_offset)) {
|
|
900
|
+
value_length = RSTRING_LEN(value);
|
|
901
|
+
|
|
902
|
+
if (given_bit_size <= 0) {
|
|
903
|
+
end_bytes = -(given_bit_size / 8);
|
|
904
|
+
old_upper_bound = buffer_length - 1 - end_bytes;
|
|
905
|
+
if (old_upper_bound < lower_bound) {
|
|
906
|
+
/* String was completely empty */
|
|
907
|
+
if (end_bytes > 0) {
|
|
908
|
+
/* Preserve bytes at end of buffer */
|
|
909
|
+
rb_str_concat(param_buffer, rb_str_times(ZERO_STRING, INT2FIX(value_length)));
|
|
910
|
+
buffer = (unsigned char*) RSTRING_PTR(param_buffer);
|
|
911
|
+
memmove((buffer + lower_bound + value_length), (buffer + lower_bound), value_length);
|
|
912
|
+
}
|
|
913
|
+
} else if (bit_size == 0) {
|
|
914
|
+
/* Remove entire string */
|
|
915
|
+
rb_str_update(param_buffer, lower_bound, old_upper_bound - lower_bound + 1, rb_str_new2(""));
|
|
916
|
+
} else if (upper_bound < old_upper_bound) {
|
|
917
|
+
/* Remove extra bytes from old string */
|
|
918
|
+
rb_str_update(param_buffer, upper_bound + 1, old_upper_bound + 1, rb_str_new2(""));
|
|
919
|
+
} else if ((upper_bound > old_upper_bound) && (end_bytes > 0)) {
|
|
920
|
+
/* Preserve bytes at end of buffer */
|
|
921
|
+
rb_str_concat(param_buffer, rb_str_times(ZERO_STRING, INT2FIX(upper_bound - old_upper_bound)));
|
|
922
|
+
buffer = (unsigned char*) RSTRING_PTR(param_buffer);
|
|
923
|
+
memmove((buffer + upper_bound + 1), (buffer + old_upper_bound + 1), upper_bound - old_upper_bound);
|
|
924
|
+
}
|
|
925
|
+
} else {
|
|
926
|
+
byte_size = bit_size / 8;
|
|
927
|
+
if (value_length < byte_size) {
|
|
928
|
+
/* Pad the requested size with zeros.
|
|
929
|
+
* Tell Ruby we are going to be modifying the buffer with a memset */
|
|
930
|
+
rb_str_modify(param_buffer);
|
|
931
|
+
memset(RSTRING_PTR(param_buffer) + lower_bound + value_length, 0, byte_size - value_length);
|
|
932
|
+
} else if (value_length > byte_size) {
|
|
933
|
+
if (param_overflow == symbol_TRUNCATE) {
|
|
934
|
+
/* Resize the value to fit the field */
|
|
935
|
+
rb_str_update(value, byte_size, RSTRING_LEN(value) - byte_size, rb_str_new2(""));
|
|
936
|
+
} else {
|
|
937
|
+
rb_raise(rb_eArgError, "value of %d bytes does not fit into %d bytes for data_type %s", (int)value_length, byte_size, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
if (bit_size != 0) {
|
|
942
|
+
rb_str_update(param_buffer, lower_bound, RSTRING_LEN(value), value);
|
|
943
|
+
}
|
|
944
|
+
} else {
|
|
945
|
+
rb_raise(rb_eArgError, "bit_offset %d is not byte aligned for data_type %s", given_bit_offset, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
} else if ((param_data_type == symbol_INT) || (param_data_type == symbol_UINT)) {
|
|
949
|
+
/*###################################
|
|
950
|
+
*# Handle :INT data type
|
|
951
|
+
*###################################*/
|
|
952
|
+
value = rb_funcall(rb_mKernel, id_method_Integer, 1, value);
|
|
953
|
+
|
|
954
|
+
if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
|
|
955
|
+
{
|
|
956
|
+
/*###########################################################
|
|
957
|
+
*# Handle byte-aligned 8, 16, 32, and 64 bit
|
|
958
|
+
*###########################################################*/
|
|
959
|
+
|
|
960
|
+
value = check_overflow(value, bit_size, param_data_type, param_overflow);
|
|
961
|
+
switch (bit_size) {
|
|
962
|
+
case 8:
|
|
963
|
+
c_value = NUM2CHR(value);
|
|
964
|
+
break;
|
|
965
|
+
case 16:
|
|
966
|
+
c_value = NUM2USHORT(value);
|
|
967
|
+
break;
|
|
968
|
+
case 32:
|
|
969
|
+
c_value = NUM2UINT(value);
|
|
970
|
+
break;
|
|
971
|
+
case 64:
|
|
972
|
+
c_value = NUM2ULL(value);
|
|
973
|
+
break;
|
|
974
|
+
}
|
|
975
|
+
/* If the passed endianess doesn't match the host we reverse the bytes.
|
|
976
|
+
* Then shift the result over so it's at the bottom of the long long value. */
|
|
977
|
+
if (param_endianness != HOST_ENDIANNESS) {
|
|
978
|
+
reverse_bytes((unsigned char *)&c_value, 8);
|
|
979
|
+
c_value = (c_value >> (64 - bit_size));
|
|
980
|
+
}
|
|
981
|
+
/* Tell Ruby we are going to be modifying the buffer with a memcpy */
|
|
982
|
+
rb_str_modify(param_buffer);
|
|
983
|
+
memcpy((RSTRING_PTR(param_buffer) + lower_bound), &c_value, bit_size / 8);
|
|
984
|
+
|
|
985
|
+
} else {
|
|
986
|
+
/*###########################################################
|
|
987
|
+
*# Handle bit fields
|
|
988
|
+
*###########################################################*/
|
|
989
|
+
value = check_overflow(value, bit_size, param_data_type, param_overflow);
|
|
990
|
+
|
|
991
|
+
string_length = ((bit_size - 1)/ 8) + 1;
|
|
992
|
+
array_length = string_length + 4; /* Required number of bytes plus slack */
|
|
993
|
+
unsigned_char_array = (unsigned char*) malloc(array_length);
|
|
994
|
+
|
|
995
|
+
num_words = ((string_length - 1) / 4) + 1;
|
|
996
|
+
num_bytes = num_words * 4;
|
|
997
|
+
num_bits = num_bytes * 8;
|
|
998
|
+
shift_needed = num_bits - bit_size;
|
|
999
|
+
shift_count = shift_needed / 8;
|
|
1000
|
+
shift_needed = shift_needed % 8;
|
|
1001
|
+
|
|
1002
|
+
/* Convert value into array of bytes */
|
|
1003
|
+
if (bit_size <= 30) {
|
|
1004
|
+
*((int *)unsigned_char_array) = FIX2INT(value);
|
|
1005
|
+
} else if (bit_size <= 32) {
|
|
1006
|
+
*((unsigned int *)unsigned_char_array) = NUM2UINT(value);
|
|
1007
|
+
} else {
|
|
1008
|
+
temp_mask = UINT2NUM(0xFFFFFFFF);
|
|
1009
|
+
temp_shift = INT2FIX(32);
|
|
1010
|
+
temp_result = rb_big_and(TO_BIGNUM(value), temp_mask);
|
|
1011
|
+
/* Work around bug where rb_big_and will return Qfalse if given a first parameter of 0 */
|
|
1012
|
+
if (temp_result == Qfalse) { temp_result = INT2FIX(0); }
|
|
1013
|
+
*((unsigned int *)&(unsigned_char_array[num_bytes - 4])) = NUM2UINT(temp_result);
|
|
1014
|
+
for (index = num_bytes - 8; index >= 0; index -= 4) {
|
|
1015
|
+
value = rb_big_rshift(TO_BIGNUM(value), temp_shift);
|
|
1016
|
+
temp_result = rb_big_and(TO_BIGNUM(value), temp_mask);
|
|
1017
|
+
/* Work around bug where rb_big_and will return Qfalse if given a first parameter of 0 */
|
|
1018
|
+
if (temp_result == Qfalse) { temp_result = INT2FIX(0); }
|
|
1019
|
+
*((unsigned int *)&(unsigned_char_array[index])) = NUM2UINT(temp_result);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
if (HOST_ENDIANNESS == symbol_LITTLE_ENDIAN) {
|
|
1024
|
+
for (index = 0; index < num_bytes; index += 4) {
|
|
1025
|
+
reverse_bytes(&(unsigned_char_array[index]), 4);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
for (index = 0; index < shift_count; index++) {
|
|
1030
|
+
left_shift_byte_array(unsigned_char_array, num_bytes, 8);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
if (shift_needed > 0) {
|
|
1034
|
+
left_shift_byte_array(unsigned_char_array, num_bytes, shift_needed);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
rb_str_modify(param_buffer);
|
|
1038
|
+
write_bitfield(lower_bound, upper_bound, bit_offset, bit_size, given_bit_offset, given_bit_size, param_endianness, (unsigned char*) RSTRING_PTR(param_buffer), (int)buffer_length, unsigned_char_array);
|
|
1039
|
+
|
|
1040
|
+
free(unsigned_char_array);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
} else if (param_data_type == symbol_FLOAT) {
|
|
1044
|
+
/*##########################
|
|
1045
|
+
*# Handle :FLOAT data type
|
|
1046
|
+
*##########################*/
|
|
1047
|
+
value = rb_funcall(rb_mKernel, id_method_Float, 1, value);
|
|
1048
|
+
|
|
1049
|
+
if (BYTE_ALIGNED(bit_offset)) {
|
|
1050
|
+
switch (bit_size) {
|
|
1051
|
+
case 32:
|
|
1052
|
+
float_value = (float)RFLOAT_VALUE(value);
|
|
1053
|
+
if (param_endianness != HOST_ENDIANNESS) {
|
|
1054
|
+
reverse_bytes((unsigned char *)&float_value, 4);
|
|
1055
|
+
}
|
|
1056
|
+
rb_str_modify(param_buffer);
|
|
1057
|
+
memcpy((RSTRING_PTR(param_buffer) + lower_bound), &float_value, 4);
|
|
1058
|
+
break;
|
|
1059
|
+
|
|
1060
|
+
case 64:
|
|
1061
|
+
double_value = RFLOAT_VALUE(value);
|
|
1062
|
+
if (param_endianness != HOST_ENDIANNESS) {
|
|
1063
|
+
reverse_bytes((unsigned char *)&double_value, 8);
|
|
1064
|
+
}
|
|
1065
|
+
rb_str_modify(param_buffer);
|
|
1066
|
+
memcpy((RSTRING_PTR(param_buffer) + lower_bound), &double_value, 8);
|
|
1067
|
+
break;
|
|
1068
|
+
|
|
1069
|
+
default:
|
|
1070
|
+
rb_raise(rb_eArgError, "bit_size is %d but must be 32 or 64 for data_type %s", given_bit_size, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
|
|
1071
|
+
break;
|
|
1072
|
+
};
|
|
1073
|
+
} else {
|
|
1074
|
+
rb_raise(rb_eArgError, "bit_offset %d is not byte aligned for data_type %s", given_bit_offset, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
} else {
|
|
1078
|
+
/*############################
|
|
1079
|
+
*# Handle Unknown data types
|
|
1080
|
+
*############################*/
|
|
1081
|
+
|
|
1082
|
+
rb_raise(rb_eArgError, "data_type %s is not recognized", RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
return value;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
602
1088
|
/*
|
|
603
1089
|
* Returns the actual length as an integer.
|
|
604
1090
|
*
|
|
@@ -830,11 +1316,18 @@ void Init_structure (void)
|
|
|
830
1316
|
{
|
|
831
1317
|
int zero = 0;
|
|
832
1318
|
|
|
1319
|
+
mCosmos = rb_define_module("Cosmos");
|
|
1320
|
+
cBinaryAccessor = rb_define_class_under(mCosmos, "BinaryAccessor", rb_cObject);
|
|
1321
|
+
|
|
833
1322
|
id_method_to_s = rb_intern("to_s");
|
|
834
1323
|
id_method_raise_buffer_error = rb_intern("raise_buffer_error");
|
|
835
1324
|
id_method_read_array = rb_intern("read_array");
|
|
836
1325
|
id_method_force_encoding = rb_intern("force_encoding");
|
|
837
1326
|
id_method_freeze = rb_intern("freeze");
|
|
1327
|
+
id_method_slice = rb_intern("slice");
|
|
1328
|
+
id_method_reverse = rb_intern("reverse");
|
|
1329
|
+
id_method_Integer = rb_intern("Integer");
|
|
1330
|
+
id_method_Float = rb_intern("Float");
|
|
838
1331
|
|
|
839
1332
|
ASCII_8BIT_STRING = rb_str_new2("ASCII-8BIT");
|
|
840
1333
|
rb_funcall(ASCII_8BIT_STRING, id_method_freeze, 0);
|
|
@@ -843,6 +1336,37 @@ void Init_structure (void)
|
|
|
843
1336
|
rb_funcall(ZERO_STRING, id_method_freeze, 0);
|
|
844
1337
|
id_const_ZERO_STRING = rb_intern("ZERO_STRING");
|
|
845
1338
|
|
|
1339
|
+
MIN_INT8 = INT2NUM(-128);
|
|
1340
|
+
MAX_INT8 = INT2NUM(127);
|
|
1341
|
+
MAX_UINT8 = INT2NUM(255);
|
|
1342
|
+
MIN_INT16 = INT2NUM(-32768);
|
|
1343
|
+
MAX_INT16 = INT2NUM(32767);
|
|
1344
|
+
MAX_UINT16 = INT2NUM(65535);
|
|
1345
|
+
MIN_INT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(31));
|
|
1346
|
+
MIN_INT32 = rb_big_minus(TO_BIGNUM(INT2NUM(0)), MIN_INT32);
|
|
1347
|
+
MAX_INT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(31));
|
|
1348
|
+
MAX_INT32 = rb_big_minus(TO_BIGNUM(MAX_INT32), INT2NUM(1));
|
|
1349
|
+
MAX_UINT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(32));
|
|
1350
|
+
MAX_UINT32 = rb_big_minus(TO_BIGNUM(MAX_UINT32), INT2NUM(1));
|
|
1351
|
+
MIN_INT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(63));
|
|
1352
|
+
MIN_INT64 = rb_big_minus(TO_BIGNUM(INT2NUM(0)), MIN_INT64);
|
|
1353
|
+
MAX_INT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(63));
|
|
1354
|
+
MAX_INT64 = rb_big_minus(TO_BIGNUM(MAX_INT64), INT2NUM(1));
|
|
1355
|
+
MAX_UINT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(64));
|
|
1356
|
+
MAX_UINT64 = rb_big_minus(TO_BIGNUM(MAX_UINT64), INT2NUM(1));
|
|
1357
|
+
rb_define_const(cBinaryAccessor, "MIN_INT8", MIN_INT8);
|
|
1358
|
+
rb_define_const(cBinaryAccessor, "MAX_INT8", MAX_INT8);
|
|
1359
|
+
rb_define_const(cBinaryAccessor, "MAX_UINT8", MAX_UINT8);
|
|
1360
|
+
rb_define_const(cBinaryAccessor, "MIN_INT16", MIN_INT16);
|
|
1361
|
+
rb_define_const(cBinaryAccessor, "MAX_INT16", MAX_INT16);
|
|
1362
|
+
rb_define_const(cBinaryAccessor, "MAX_UINT16", MAX_UINT16);
|
|
1363
|
+
rb_define_const(cBinaryAccessor, "MIN_INT32", MIN_INT32);
|
|
1364
|
+
rb_define_const(cBinaryAccessor, "MAX_INT32", MAX_INT32);
|
|
1365
|
+
rb_define_const(cBinaryAccessor, "MAX_UINT32", MAX_UINT32);
|
|
1366
|
+
rb_define_const(cBinaryAccessor, "MIN_INT64", MIN_INT64);
|
|
1367
|
+
rb_define_const(cBinaryAccessor, "MAX_INT64", MAX_INT64);
|
|
1368
|
+
rb_define_const(cBinaryAccessor, "MAX_UINT64", MAX_UINT64);
|
|
1369
|
+
|
|
846
1370
|
id_ivar_buffer = rb_intern("@buffer");
|
|
847
1371
|
id_ivar_bit_offset = rb_intern("@bit_offset");
|
|
848
1372
|
id_ivar_bit_size = rb_intern("@bit_size");
|
|
@@ -870,6 +1394,11 @@ void Init_structure (void)
|
|
|
870
1394
|
symbol_BLOCK = ID2SYM(rb_intern("BLOCK"));
|
|
871
1395
|
symbol_DERIVED = ID2SYM(rb_intern("DERIVED"));
|
|
872
1396
|
symbol_read = ID2SYM(rb_intern("read"));
|
|
1397
|
+
symbol_write = ID2SYM(rb_intern("write"));
|
|
1398
|
+
symbol_TRUNCATE = ID2SYM(rb_intern("TRUNCATE"));
|
|
1399
|
+
symbol_SATURATE = ID2SYM(rb_intern("SATURATE"));
|
|
1400
|
+
symbol_ERROR = ID2SYM(rb_intern("ERROR"));
|
|
1401
|
+
symbol_ERROR_ALLOW_HEX = ID2SYM(rb_intern("ERROR_ALLOW_HEX"));
|
|
873
1402
|
|
|
874
1403
|
if ((*((char *) &endianness_check)) == 1) {
|
|
875
1404
|
HOST_ENDIANNESS = symbol_LITTLE_ENDIAN;
|
|
@@ -877,10 +1406,8 @@ void Init_structure (void)
|
|
|
877
1406
|
HOST_ENDIANNESS = symbol_BIG_ENDIAN;
|
|
878
1407
|
}
|
|
879
1408
|
|
|
880
|
-
mCosmos = rb_define_module("Cosmos");
|
|
881
|
-
|
|
882
|
-
cBinaryAccessor = rb_define_class_under(mCosmos, "BinaryAccessor", rb_cObject);
|
|
883
1409
|
rb_define_singleton_method(cBinaryAccessor, "read", binary_accessor_read, 5);
|
|
1410
|
+
rb_define_singleton_method(cBinaryAccessor, "write", binary_accessor_write, 7);
|
|
884
1411
|
|
|
885
1412
|
cStructure = rb_define_class_under(mCosmos, "Structure", rb_cObject);
|
|
886
1413
|
rb_const_set(cStructure, id_const_ZERO_STRING, ZERO_STRING);
|