lib/bit_fields.rb in elia-1.1.0 vs lib/bit_fields.rb in elia-1.2.0

- old
+ new

@@ -80,11 +80,10 @@ # # Also defines the attribute reader method # def field name, unpack_recipe = 'C', &bit_fields_definitions_block include InstanceMethods # when used we include instance methods - logger.debug { self.ancestors.inspect } # Setup class "instance" vars @fields ||= [] @bit_fields ||= {} @unpack_recipe ||= "" @@ -93,19 +92,18 @@ @unpack_recipe << unpack_recipe @fields << name # Define the attribute reader class_eval "def #{name}; self.attributes[#{name.inspect}]; end;", __FILE__, __LINE__ - # define_method(name) { self.fields[name] } # There's a bit-structure too? if block_given? @_current_bit_fields = [] bit_fields_definitions_block.call - @bit_fields[name] = @_current_bit_fields + @bit_fields[name] = @_current_bit_fields.reverse @_current_bit_fields = nil end end ## @@ -116,11 +114,11 @@ # 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] + @_current_bit_fields << [name, width, bit_mask(width)] # Define the attribute reader class_eval "def #{name}; self.attributes[#{name.inspect}]; end\n", __FILE__, __LINE__ if width == 1 or name.to_s =~ /_flag$/ @@ -132,14 +130,19 @@ # Define another question mark method if ends with "_flag" class_eval "alias #{flag_method_name} #{name}?\n", __FILE__, __LINE__ end end - logger.debug { @_current_bit_fields.inspect } end + def bit_mask size + 2 ** size - 1 + end + + + module InstanceMethods # Contains the raw string attr_reader :raw # caches the bit field values @@ -158,14 +161,14 @@ self.attributes[name] end private - def eat_right_bits original_value, bits_number + def eat_right_bits original_value, bits_number, bit_mask # Filter the original value with the # proper bitmask to get the rightmost bits - new_value = original_value & bit_mask(bits_number) + new_value = original_value & bit_mask # Eat those rightmost bits # wich we have just consumed remaning = original_value >> bits_number @@ -176,43 +179,30 @@ # Parses the raw value extracting the defined bit fields def parse_bit_fields raw @raw = raw # Setup - unpack_recipe = self.class.unpack_recipe - logger.debug "Unpacking #{@raw.inspect} with #{unpack_recipe.inspect}" - @unpacked = @raw.unpack(unpack_recipe) + @unpacked = @raw.unpack( self.class.unpack_recipe ) @attributes ||= {} - logger.debug { "Parsing #{@raw.inspect} with fields #{self.class.fields.inspect}" } self.class.fields.each_with_index do |name, position| - logger.debug { "Parsing field #{name.inspect}" } - attributes[name] = @unpacked[position] + @attributes[name] = @unpacked[position] # We must extract bits from end since # ruby doesn't have types (and fixed lengths) - if bit_definitions = self.class.bit_fields[name] - logger.debug { "Parsing value #{attributes[name]} with bit fields #{bit_definitions.inspect}" } + if bit_fields = self.class.bit_fields[name] bit_value = attributes[name] - bit_definitions.reverse.each do |bit_field| - logger.debug "Parsing bit field: #{bit_field.inspect} current value: #{bit_value} (#{bit_value.to_s 2})" - bit_name, bit_size = *bit_field - attributes[bit_name], bit_value = eat_right_bits(bit_value, bit_size) - - logger.debug { - "#{bit_name}: #{attributes[bit_name]} 0b#{attributes[bit_name].to_s(2).rjust(16, '0')}" - } + bit_fields.each do |(bit_name, bits_number, bit_mask)| + # @attributes[bit_name], bit_value = eat_right_bits(bit_value, bits_number, bit_mask) + # logger.debug "#{bit_name.to_s.rjust(20)}: #{bit_value.to_s(2).rjust(40)} & #{bit_mask.to_s(2).rjust(20)} = #{(bit_value & bit_mask).to_s(2).rjust(20)}" + + @attributes[bit_name] = bit_value & bit_mask + bit_value = bit_value >> bits_number end end end - - @parsed = true - end - - def bit_mask size - 2 ** size - 1 end def to_s raw.to_s end