Module: BitFields
- Extended by:
- InstanceMethods
- Defined in:
- lib/bit_fields.rb
Overview
BitFields provides a simple way to extract a values from bit fields, especially if they don’t correspond to standard sizes (such as char
, int
, long
, etc., see String#unpack
for further informations).
For example the Primary Header of the Telemetry Frame in the ESA PSS Standard has this specification:
| TRANSFER FRAME PRIMARY HEADER |
___________|_____________________________________________________________________________________|
|SYNC MARKER| FRAME IDENTIFICATION | MASTER | VIRTUAL | FRAME DATA FIELD STATUS |
| |----------------------| CHANNEL | CHANNEL |------------------------------------------|
| |Ver. |S/C.|Virt.|Op.Co| FRAME | FRAME |2nd head.|Sync|Pkt ord|Seg. |First Header|
| | no. | ID | Chn.| Flag| COUNT | COUNT | flag |flag|flag |len.ID| Pointer |
| |_____|____|_____|_____| | |_________|____|_______|______|____________|
| | 2 | 10 | 3 | 1 | | | 1 | 1 | 1 | 2 | 11 |
|-----------|----------------------|---------|---------|------------------------------------------|
| 32 | 16 | 8 | 8 | 16 |
Will become:
class PrimaryHeader
include BitFields
field :frame_identification, 'n' do
bit_field :version, 2
bit_field :spacecraft_id, 10
bit_field :virtual_channel, 3
bit_field :op_control_field_flag, 2
end
field :master_channel_frame_count
field :virtual_channel_frame_count
field :frame_data_field_status, 'n' do
bit_field :secondary_header_flag, 1
bit_field :sync_flag, 1
bit_field :packet_order_flag, 1
bit_field :segment_length_id, 2
bit_field :first_header_pointer, 11
end
end
And can be used like:
packed_ph = [0b10100111_11111111, 11, 23, 0b10100111_11111111].pack('nCCn') # => "\247\377\v\027\247\377"
ph = PrimaryHeader.new packed_ph
ph.virtual_channel_frame_count # => 23
ph.secondary_header_flag # => 0b1
ph.sync_flag # => 0b0
ph.first_header_pointer # => 0b111_11111111
ph[:first_header_pointer] # => 0b111_11111111
Defined Under Namespace
Modules: InstanceMethods
Instance Attribute Summary collapse
-
#bit_fields ⇒ Object
readonly
Collects the bit_fields definitions for later parsing.
-
#fields ⇒ Object
readonly
Collects the fields definitions for later parsing.
-
#unpack_recipe ⇒ Object
readonly
Collects the full
String#unpack
directive used to parse the raw value.
Attributes included from InstanceMethods
Instance Method Summary collapse
-
#bit_field(name, width) ⇒ Object
Defines a bit field to be extracted from a
field
. - #bit_mask(size) ⇒ Object
-
#bits_attr_accessor(name) ⇒ Object
Defines accessors for the attributes hash.
-
#field(name, unpack_recipe = 'C', &bit_fields_definitions_block) ⇒ Object
Defines a field to be extracted with String#unpack from the raw value.
Methods included from InstanceMethods
[], initialize, method_missing, pack_bit_fields, to_s
Instance Attribute Details
#bit_fields ⇒ Object (readonly)
Collects the bit_fields definitions for later parsing
69 70 71 |
# File 'lib/bit_fields.rb', line 69 def bit_fields @bit_fields end |
#fields ⇒ Object (readonly)
Collects the fields definitions for later parsing
66 67 68 |
# File 'lib/bit_fields.rb', line 66 def fields @fields end |
#unpack_recipe ⇒ Object (readonly)
Collects the full String#unpack
directive used to parse the raw value.
72 73 74 |
# File 'lib/bit_fields.rb', line 72 def unpack_recipe @unpack_recipe end |
Instance Method Details
#bit_field(name, width) ⇒ Object
Defines a bit field to be extracted from a field
name
-
the name of the bit field (that will be used to access it)
width
-
the number of bits from which this value should be extracted
TODO: add options to enable method aliases TODO: add a skip bits syntax
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/bit_fields.rb', line 126 def bit_field name, width raise "'bit_field' can be used only inside a 'field' block." if @_current_bit_fields.nil? # Register the bit field definition @_current_bit_fields << [name, width, bit_mask(width)] # Define the attribute accessor bits_attr_accessor(name) if width == 1 or name.to_s =~ /_flag$/ # Define a question mark method if the size is 1 bit class_eval "def #{name}?; self.attributes[#{name.inspect}] != 0; end\n", __FILE__, __LINE__ # returns nil if no substitution happens... if flag_method_name = name.to_s.gsub!(/_flag$/, '?') # Define another question mark method if ends with "_flag" class_eval "alias #{flag_method_name} #{name}?\n", __FILE__, __LINE__ end end end |
#bit_mask(size) ⇒ Object
148 149 150 |
# File 'lib/bit_fields.rb', line 148 def bit_mask size 2 ** size - 1 end |
#bits_attr_accessor(name) ⇒ Object
Defines accessors for the attributes hash
75 76 77 78 |
# File 'lib/bit_fields.rb', line 75 def bits_attr_accessor name class_eval "def #{name}; self.attributes[#{name.inspect}]; end;", __FILE__, __LINE__ class_eval "def #{name}=(val); self.attributes[#{name.inspect}]=val; end;", __FILE__, __LINE__ end |
#field(name, unpack_recipe = 'C', &bit_fields_definitions_block) ⇒ Object
Defines a field to be extracted with String#unpack from the raw value
name
-
the name of the field (that will be used to access it)
unpack_recipe
-
the
String#unpack
directive corresponding to this field (optional, defaults to char: “C”) bit_fields_definitions_block
-
the block in which
bit_fields
can be defined (optional)
Also defines the attribute reader method
TODO: add a skip bits syntax
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/bit_fields.rb', line 91 def field name, unpack_recipe = 'C', &bit_fields_definitions_block include InstanceMethods # when used we include instance methods # Setup class "instance" vars @fields ||= [] @bit_fields ||= {} @unpack_recipe ||= "" # Register the field definition @unpack_recipe << unpack_recipe @fields << name # Define the attribute accessor bits_attr_accessor(name) # There's a bit-structure too? if block_given? @_current_bit_fields = [] bit_fields_definitions_block.call @bit_fields[name] = @_current_bit_fields @_current_bit_fields = nil end end |