from bitarray import bitarray
import os
import errno
import functools
from collections import OrderedDict
from .. import bitarrayhelper as bah
from .. import configs
from . import BaseConfiguration, _Smart_List
[docs]class Configuration_v2(BaseConfiguration):
'''
Represents the desired configuration state of a LArPix v2 chip.
Each register name is available as its own attribute for inspecting and
setting the value of the corresponding register.
Certain configuration values are set channel-by-channel. These are
represented by a list of values. For example:
>>> conf.pixel_trim_dac[2:5]
[16, 16, 16]
>>> conf.channel_mask[20] = 1
>>> conf.external_trigger_mask = [0] * 64
Additionally, other configuration values take up more than or less
than one complete register. These are still set by referencing the
appropriate name. For example, ``cross_trigger_mode`` shares a
register with a few other values, and adjusting the value of the
``cross_trigger_mode`` attribute will leave the other values
unchanged.
Each register name can cover more than one 'physical' register depending on
the size of the data it holds. You can see which physical registers a
given register name corresponds to by using the `register_map` attribute, e.g.::
>>> conf.register_map['digital_threshold'] # 64 registers, 1 per channel
range(173, 237)
>>> conf.register_map['enable_dynamic_reset'] # Register 170
range(170, 171)
>>> conf.register_map['enable_min_delta_adc'] # Shares register 170
range(170, 171)
'''
asic_version = 2
default_configuration_file = 'chip/default_v2.json'
num_registers = 237
num_bits = 1896
num_channels = 64
# Additional class properties regarding configuration registers are set at the end of the file.
_endian = 'little'
def __init__(self):
# Note: properties, getters and setters are constructed after this class definition at the bottom of the file.
super(Configuration_v2, self).__init__()
return
def all_data(self, endian='little'):
bits = []
for register_name in self.register_names:
register_data = getattr(self, register_name+'_data')
for register_addr, register_bits in register_data:
if len(bits) == register_addr:
if endian[0] == 'l':
bits += [register_bits]
else:
bits += [register_bits[::-1]]
return bits
[docs] def from_dict_registers(self, d, endian='little'):
'''
Load in the configuration specified by a dict of (register,
value) pairs.
'''
for address, value in d.items():
register_names = self.register_map_inv[address]
for register_name in register_names:
setattr(self, register_names[0] + '_data', (address, bah.fromuint(value,8,endian=endian)))
return
def _is_register_value_pair(self, item):
'''
Helper function to determine if item is a register, bitarray pair
'''
if isinstance(item, tuple) and len(item) == 2 and \
isinstance(item[0], int) and isinstance(item[1], bitarray)\
and len(item[1]) == 8 and item[0] >= 0 and item[0] < self.num_registers:
return True
return False
### Stuff for generating the v2 configuration properties
## Getter function formulas
#
def _basic_getter(register_name):
'''
Function formula for getting a named register
'''
def basic_getter_func(self):
return getattr(self, '_'+register_name)
return basic_getter_func
# /Getter function formulas
## Setter function formulas
#
def _basic_setter(register_name):
'''
Function formula for setting a named register
'''
def basic_setter_func(self, value):
setattr(self, '_'+register_name, value)
return basic_setter_func
def _list_setter(register_name, min_value, max_value):
'''
Function formula for setting a named register
'''
def list_setter_func(self, value):
setattr(self, '_'+register_name, _Smart_List(value, min_value, max_value))
return list_setter_func
# /Setter function formulas
## Data getter function formulas
#
def _basic_data_getter(register_name):
'''
Function formula for getting a "simple" register's data
A simple register has a one-to-many relationship between the register
name and register addresses.
Returns a list of register_addr, bitarray pairs
'''
def basic_data_getter_func(self):
register_range = self.register_map[register_name]
value = getattr(self, register_name)
all_data = bah.fromuint(value, 8*(register_range[-1]-register_range[0]+1), endian=self._endian)
return_data = [(register, all_data[idx*8:idx*8+8]) for idx, register in enumerate(register_range)]
return return_data
return basic_data_getter_func
def _list_data_getter(register_name, n_bits):
'''
Function formula for getting a list-like register's data
A list-like register contains repeated functionality every ``n_bits``
over 1 or more register addresses.
Returns a list of register_addr, bitarray pairs
'''
def list_data_getter_func(self):
register_range = self.register_map[register_name]
values = getattr(self, register_name)
all_data = bitarray([])
for value in values:
all_data += bah.fromuint(value, n_bits, endian=self._endian)
if len(all_data) < 8:
all_data += bitarray([0]*(8-len(all_data)%8)) # pad up to full register
return [(register_addr, all_data[idx*8:idx*8+8]) for idx, register_addr in enumerate(register_range)]
return list_data_getter_func
def _compound_data_getter(registers):
'''
Function formula for getting a compound register's data
A compound register has a one-to-many mapping of register address to
register names.
``registers`` should be the register names contained within the
register address (in order of lowest bit to highest)
Returns a list of register, bitarray pairs
'''
def compound_data_getter_func(self):
bits = bitarray([0]*8)
for register_name in registers:
start_bit, end_bit = self.bit_map[register_name]
bits[start_bit%8:end_bit-start_bit+start_bit%8] = bah.fromuint(getattr(self, register_name), end_bit-start_bit, endian=self._endian)
return [(self.register_map[registers[0]][0], bits)]
return compound_data_getter_func
def _compound_list_data_getter(registers, n_bits):
'''
Function formula for getting a compound list register's data
A compound list register has a one-to-many mapping of register
addresses to register names, but with repeating functionality within
each register name of size ``n_bits``. For example, you might store two
1bit arrays of length 2 within the same register address.
``registers`` should be the register names contained within the
register address (in order of lowest bit to highest)
Returns a list of register, bitarray pairs
'''
def compound_list_data_getter_func(self):
bits = bitarray([])
for register_name in registers:
values = getattr(self, register_name)
for value in values:
bits += bah.fromuint(value, n_bits, endian=self._endian)
if len(bits)%8 != 0:
bits += bitarray([0]*(8-len(bits)%8)) # pad up to full register
return [(self.register_map[registers[0]][0], bits)]
return compound_list_data_getter_func
# /Data getter function formulas
## Data setter function formulas
#
def _basic_data_setter(register_name):
'''
Function formula for setting a simple register's data
Data can be specified as a register, bitarray pair or via a full-length
bitarray
'''
def basic_data_setter_func(self, value):
if self._is_register_value_pair(value):
# regenerate complete list of bits and set
set_register, set_bits = value
data = getattr(self, register_name+'_data')
all_bits = bitarray([])
for register, bits in data:
if register == set_register:
all_bits += set_bits
else:
all_bits += bits
start_bit, end_bit = self.bit_map[register_name]
setattr(self, register_name+'_data', all_bits[start_bit%8:end_bit-start_bit+start_bit%8])
else:
# use all bits to set values
bits = value
value = bah.touint(bits, endian=self._endian)
setattr(self, register_name, value)
return basic_data_setter_func
def _list_data_setter(register_name, n_bits, min_value, max_value):
'''
Function formula for setting a list-like register's data
A list-like register contains repeated functionality every ``n_bits``
over 1 or more register addresses.
Data can be specified as a register, bitarray pair or via a full-length
bitarray
'''
def list_data_setter_func(self, values):
if self._is_register_value_pair(values):
# regenerate complete list of bits and set
set_register, set_bits = values
data = getattr(self, register_name+'_data')
all_bits = bitarray([])
for register, bits in data:
if register == set_register:
all_bits += set_bits
else:
all_bits += bits
start_bit, end_bit = self.bit_map[register_name]
setattr(self, register_name+'_data', all_bits[start_bit%8:end_bit-start_bit+start_bit%8])
else:
# use all bits to set values
bits = values
item_values = [bah.touint(bits[idx:idx+n_bits], endian=self._endian) for idx in range(0, len(bits), n_bits)]
setattr(self, register_name, _Smart_List(item_values, min_value, max_value))
return list_data_setter_func
def _compound_data_setter(registers, register_name):
'''
Function formula for setting a compound register's data
A compound register has a one-to-many mapping of register address to
register names.
``registers`` should be the register names contained within the
register address (in order of lowest bit to highest)
Data can be specified as a register, bitarray pair or via a full-length
bitarray
'''
def compound_data_setter_func(self, value):
if self._is_register_value_pair(value):
set_register_addr, set_bits = value
for register in registers:
start_bit, end_bit = self.bit_map[register]
setattr(self, register + '_data', set_bits[start_bit%8:end_bit-start_bit+start_bit%8])
else:
# use all bits to set values
set_bits = value
setattr(self, register_name, bah.touint(set_bits, endian=self._endian))
return compound_data_setter_func
def _compound_list_data_setter(registers, register_name, n_bits, min_value, max_value):
'''
Function formula for setting a compound list register's data
A compound list register has a one-to-many mapping of register address to
register names with repeating functionality every ``n_bits``.
``registers`` should be the register names contained within the
register address (in order of lowest bit to highest)
Data can be specified as a register, bitarray pair or via a full-length
bitarray
'''
def compound_list_data_setter_func(self, value):
if self._is_register_value_pair(value):
set_register_addr, set_bits = value
for register in registers:
start_bit, end_bit = self.bit_map[register]
setattr(self, register + '_data', set_bits[start_bit%8:end_bit-start_bit+start_bit%8])
else:
set_bits = value
values = [bah.touint(set_bits[idx:idx+n_bits], endian=self._endian) for idx in range(0,len(set_bits),n_bits)]
setattr(self, register_name, _Smart_List(values, min_value, max_value))
return compound_list_data_setter_func
# /Data setter function formulas
## Value validation function formulas
#
def _value_validator(value_types, min_value, max_value):
'''
Function formula for validating a register that contains a single value
Accepts values of types ``value_types``, greater than ``min_value``,
and less than ``max_value``.
'''
def value_validator(func):
@functools.wraps(func)
def value_validated_func(self, value):
if not isinstance(value, value_types):
raise TypeError('value must be of type {}'.format(value_types))
if value > max_value or value < min_value:
raise ValueError('value must be between {} and {}'.format(min_value,max_value))
return func(self, value)
return value_validated_func
return value_validator
def _list_validator(value_types, min_value, max_value, n_values):
'''
Function formula for validating a register that contains list-like data
Accepts lists of length ``n_values`` with objects with types
``value_types``, greater than ``min_value``, and less than ``max_value``.
'''
def list_validator(func):
@functools.wraps(func)
def list_validated_func(self, values):
if not isinstance(values, (list, _Smart_List, tuple)):
raise TypeError('argument must be a list or tuple')
if len(values) != n_values:
raise ValueError('length of list must be {}'.format(n_values))
if any([not isinstance(value, value_types) for value in values]):
raise TypeError('values must be of type {}'.format(value_types))
if any([value > max_value or value < min_value for value in values]):
raise ValueError('values must be between {} and {}'.format(min_value,max_value))
return func(self, values)
return list_validated_func
return list_validator
def _data_validator(register_name):
'''
Function formula for validating setting a register via a register
address, bitarray pair or direct bitarray
'''
def data_validator(func):
@functools.wraps(func)
def data_validated_func(self, value):
print('validate',register_name,value)
if self._is_register_value_pair(value):
register_addr, bits = value
if register_addr < self.register_map[register_name][0] \
or register_addr > self.register_map[register_name][-1] \
or len(bits) != 8:
raise ValueError('invalid register, value pair {}'
' for register {}'.format(value,register_name))
return func(self, value)
elif isinstance(value, bitarray):
bits = value
start_bit, stop_bit = self.bit_map[register_name]
if len(bits) != stop_bit - start_bit:
raise ValueError('invalid bitarray {}'
' for register {}'.format(value,register_name))
return func(self, value)
else:
raise TypeError('{} data must be assigned with '
'register, value pair or bitarray'.format(register_name))
return data_validated_func
return data_validator
# /Value validation function formulas
## Property function formulas
#
def _basic_property(name, registers, bits, types, min, max):
docstring = '''
simple value property
registers: ``{}``
valid types: ``{}``
value range: ``{}`` to ``{}``
'''.format(registers, types, min, max)
return (
property(
_basic_getter(name),
_value_validator(types,min,max)(
_basic_setter(name)),
doc=docstring),
property(
_basic_data_getter(name),
_data_validator(name)(
_basic_data_setter(name))))
def _list_property(name, registers, bits, types, min, max, length, n_bits):
docstring = '''
list-like property
list length: ``{}``
registers: ``{}``
element valid types: ``{}``
element value range: ``{}`` to ``{}``
'''.format(length, registers, types, min, max)
return (
property(
_basic_getter(name),
_list_validator(types,min,max,length)(
_list_setter(name,min,max)),
doc=docstring),
property(
_list_data_getter(name,n_bits),
_data_validator(name)(
_list_data_setter(name,n_bits,min,max))))
def _compound_property(name, registers, bits, names, types, min, max):
docstring = '''
compound property
registers: ``{}``
bits: ``{}``
valid types: ``{}``
value range: ``{}`` to ``{}``
shares a register with: ``{}``
'''.format(registers, [bit%8 for bit in bits], types, min, max, [n for n in names if not n == name])
return (
property(
_basic_getter(name),
_value_validator(types,min,max)(
_basic_setter(name)),
doc=docstring
),
property(
_compound_data_getter(names),
_data_validator(name)(
_compound_data_setter(names, name))))
def _compound_list_property(name, registers, bits, names, types, min, max, length, n_bits):
docstring = '''
compound list-like property
list length: ``{}``
registers: ``{}``
element valid types: ``{}``
element value range: ``{}`` to ``{}``
shares a register with: ``{}``
'''.format(length, registers, types, min, max, [n for n in names if not n == name])
return (
property(
_basic_getter(name),
_list_validator(types,min,max,length)(
_list_setter(name,min,max)),
doc=docstring
),
property(
_compound_list_data_getter(names,n_bits),
_data_validator(name)(
_compound_list_data_setter(names,name,n_bits,min,max))))
# /Property function formulas
## Set up property info
#
_property_configuration = OrderedDict([
('pixel_trim_dac',
(_list_property, (int, 0, 31, Configuration_v2.num_channels, 8), (0,512))),
('threshold_global',
(_basic_property, (int, 0, 255), (512, 520))),
('csa_gain',
(_compound_property, (['csa_gain', 'csa_bypass_enable','bypass_caps_en'], (int,bool), 0, 1), (520,521))),
('csa_bypass_enable',
(_compound_property, (['csa_gain', 'csa_bypass_enable','bypass_caps_en'], (int,bool), 0, 1), (521,522))),
('bypass_caps_en',
(_compound_property, (['csa_gain', 'csa_bypass_enable','bypass_caps_en'], (int,bool), 0, 1), (522,523))),
('csa_enable',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (528, 592))),
('ibias_tdac',
(_basic_property, (int, 0, 15), (592, 596))),
('ibias_comp',
(_basic_property, (int, 0, 15), (600, 604))),
('ibias_buffer',
(_basic_property, (int, 0, 15), (608, 612))),
('ibias_csa',
(_basic_property, (int, 0, 15), (616, 620))),
('ibias_vref_buffer',
(_basic_property, (int, 0, 15), (624, 628))),
('ibias_vcm_buffer',
(_basic_property, (int, 0, 15), (632, 636))),
('ibias_tpulse',
(_basic_property, (int, 0, 15), (640, 644))),
('ref_current_trim',
(_compound_property, (['ref_current_trim','override_ref','ref_kickstart'], int, 0, 31), (648, 653))),
('override_ref',
(_compound_property, (['ref_current_trim','override_ref','ref_kickstart'], (int,bool), 0, 1), (653, 654))),
('ref_kickstart',
(_compound_property, (['ref_current_trim','override_ref','ref_kickstart'], (int,bool), 0, 1), (654, 655))),
('vref_dac',
(_basic_property, (int, 0, 255), (656, 664))),
('vcm_dac',
(_basic_property, (int, 0, 255), (664,672))),
('csa_bypass_select',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (672,736))),
('csa_monitor_select',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (736,800))),
('csa_testpulse_enable',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (800,864))),
('csa_testpulse_dac',
(_basic_property, (int, 0, 255), (864,872))),
('current_monitor_bank0',
(_list_property, ((int,bool), 0, 1, 4, 1), (872,876))),
('current_monitor_bank1',
(_list_property, ((int,bool), 0, 1, 4, 1), (880,884))),
('current_monitor_bank2',
(_list_property, ((int,bool), 0, 1, 4, 1), (888,892))),
('current_monitor_bank3',
(_list_property, ((int,bool), 0, 1, 4, 1), (896,900))),
('voltage_monitor_bank0',
(_list_property, ((int,bool), 0, 1, 3, 1), (904,907))),
('voltage_monitor_bank1',
(_list_property, ((int,bool), 0, 1, 3, 1), (912,915))),
('voltage_monitor_bank2',
(_list_property, ((int,bool), 0, 1, 3, 1), (920,923))),
('voltage_monitor_bank3',
(_list_property, ((int,bool), 0, 1, 3, 1), (928,931))),
('voltage_monitor_refgen',
(_list_property, ((int,bool), 0, 1, 8, 1), (936,944))),
('digital_monitor_enable',
(_compound_property, (['digital_monitor_enable','digital_monitor_select'], (int,bool), 0, 1), (944,945))),
('digital_monitor_select',
(_compound_property, (['digital_monitor_enable','digital_monitor_select'], (int,bool), 0, 10), (945,949))),
('digital_monitor_chan',
(_basic_property, (int, 0, 63), (952,958))),
('slope_control0',
(_compound_property, (['slope_control0', 'slope_control1'], int, 0, 15), (960,964))),
('slope_control1',
(_compound_property, (['slope_control0', 'slope_control1'], int, 0, 15), (964,968))),
('slope_control2',
(_compound_property, (['slope_control2', 'slope_control3'], int, 0, 15), (968,972))),
('slope_control3',
(_compound_property, (['slope_control2', 'slope_control3'], int, 0, 15), (972,976))),
('chip_id',
(_basic_property, (int, 0, 255), (976,984))),
('load_config_defaults',
(_compound_property, (['load_config_defaults', 'enable_fifo_diagnostics', 'clk_ctrl'], (int,bool), 0, 1), (985,986))),
('enable_fifo_diagnostics',
(_compound_property, (['load_config_defaults', 'enable_fifo_diagnostics', 'clk_ctrl'], (int,bool), 0, 1), (986,987))),
('clk_ctrl',
(_compound_property, (['load_config_defaults', 'enable_fifo_diagnostics', 'clk_ctrl'], (int), 0, 2), (987,989))),
('enable_miso_upstream',
(_list_property, ((int,bool), 0, 1, 4, 1), (992,996))),
('enable_miso_downstream',
(_compound_list_property, (['enable_miso_downstream', 'enable_miso_differential'], (int,bool), 0, 1, 4, 1), (1000,1004))),
('enable_miso_differential',
(_compound_list_property, (['enable_miso_downstream', 'enable_miso_differential'], (int,bool), 0, 1, 4, 1), (1004,1008))),
('enable_mosi',
(_list_property, ((int,bool), 0, 1, 4, 1), (1008,1012))),
('test_mode_uart0',
(_compound_property, (['test_mode_uart0', 'test_mode_uart1', 'test_mode_uart2', 'test_mode_uart3'], int, 0, 4), (1016,1018))),
('test_mode_uart1',
(_compound_property, (['test_mode_uart0', 'test_mode_uart1', 'test_mode_uart2', 'test_mode_uart3'], int, 0, 4), (1018,1020))),
('test_mode_uart2',
(_compound_property, (['test_mode_uart0', 'test_mode_uart1', 'test_mode_uart2', 'test_mode_uart3'], int, 0, 4), (1020,1022))),
('test_mode_uart3',
(_compound_property, (['test_mode_uart0', 'test_mode_uart1', 'test_mode_uart2', 'test_mode_uart3'], int, 0, 4), (1022,1024))),
('enable_cross_trigger',
(_compound_property, (['enable_cross_trigger', 'enable_periodic_reset', 'enable_rolling_periodic_reset', 'enable_periodic_trigger', 'enable_rolling_periodic_trigger', 'enable_periodic_trigger_veto', 'enable_hit_veto'], (int,bool), 0, 1), (1024,1025))),
('enable_periodic_reset',
(_compound_property, (['enable_cross_trigger', 'enable_periodic_reset', 'enable_rolling_periodic_reset', 'enable_periodic_trigger', 'enable_rolling_periodic_trigger', 'enable_periodic_trigger_veto', 'enable_hit_veto'], (int,bool), 0, 1), (1025,1026))),
('enable_rolling_periodic_reset',
(_compound_property, (['enable_cross_trigger', 'enable_periodic_reset', 'enable_rolling_periodic_reset', 'enable_periodic_trigger', 'enable_rolling_periodic_trigger', 'enable_periodic_trigger_veto', 'enable_hit_veto'], (int,bool), 0, 1), (1026,1027))),
('enable_periodic_trigger',
(_compound_property, (['enable_cross_trigger', 'enable_periodic_reset', 'enable_rolling_periodic_reset', 'enable_periodic_trigger', 'enable_rolling_periodic_trigger', 'enable_periodic_trigger_veto', 'enable_hit_veto'], (int,bool), 0, 1), (1027,1028))),
('enable_rolling_periodic_trigger',
(_compound_property, (['enable_cross_trigger', 'enable_periodic_reset', 'enable_rolling_periodic_reset', 'enable_periodic_trigger', 'enable_rolling_periodic_trigger', 'enable_periodic_trigger_veto', 'enable_hit_veto'], (int,bool), 0, 1), (1028,1029))),
('enable_periodic_trigger_veto',
(_compound_property, (['enable_cross_trigger', 'enable_periodic_reset', 'enable_rolling_periodic_reset', 'enable_periodic_trigger', 'enable_rolling_periodic_trigger', 'enable_periodic_trigger_veto', 'enable_hit_veto'], (int,bool), 0, 1), (1029,1030))),
('enable_hit_veto',
(_compound_property, (['enable_cross_trigger', 'enable_periodic_reset', 'enable_rolling_periodic_reset', 'enable_periodic_trigger', 'enable_rolling_periodic_trigger', 'enable_periodic_trigger_veto', 'enable_hit_veto'], (int,bool), 0, 1), (1030,1031))),
('adc_hold_delay',
(_basic_property, (int, 0, 15), (1032,1036))),
('adc_burst_length',
(_basic_property, (int, 0, 255), (1040,1048))),
('channel_mask',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (1048,1112))),
('external_trigger_mask',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (1112,1176))),
('cross_trigger_mask',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (1176,1240))),
('periodic_trigger_mask',
(_list_property, ((int,bool), 0, 1, Configuration_v2.num_channels, 1), (1240,1304))),
('periodic_reset_cycles',
(_basic_property, (int, 0, 2**24-1), (1304,1328))),
('periodic_trigger_cycles',
(_basic_property, (int, 0, 2**32-1), (1328,1360))),
('enable_dynamic_reset',
(_compound_property, (['enable_dynamic_reset', 'enable_min_delta_adc', 'threshold_polarity', 'reset_length', 'mark_first_packet'], (int,bool), 0, 1), (1360,1361))),
('enable_min_delta_adc',
(_compound_property, (['enable_dynamic_reset', 'enable_min_delta_adc', 'threshold_polarity', 'reset_length', 'mark_first_packet'], (int,bool), 0, 1), (1361,1362))),
('threshold_polarity',
(_compound_property, (['enable_dynamic_reset', 'enable_min_delta_adc', 'threshold_polarity', 'reset_length', 'mark_first_packet'], (int,bool), 0, 1), (1362,1363))),
('reset_length',
(_compound_property, (['enable_dynamic_reset', 'enable_min_delta_adc', 'threshold_polarity', 'reset_length', 'mark_first_packet'], (int), 0, 7), (1363,1366))),
('mark_first_packet',
(_compound_property, (['enable_dynamic_reset', 'enable_min_delta_adc', 'threshold_polarity', 'reset_length', 'mark_first_packet'], (int,bool), 0, 1), (1366,1367))),
('reset_threshold',
(_basic_property, (int, 0, 255), (1368,1376))),
('min_delta_adc',
(_basic_property, (int, 0, 255), (1376,1384))),
('digital_threshold',
(_list_property, (int, 0, 255, Configuration_v2.num_channels, 8), (1384,1896))),
])
# GENERATE THE PROPERTIES!
Configuration_v2.bit_map = OrderedDict()
Configuration_v2.register_map = OrderedDict()
Configuration_v2.register_names = []
for _name, _prop_config in _property_configuration.items():
_prop_formula = _prop_config[0]
_formula_args = _prop_config[1]
_bit_range = _prop_config[2]
# Add to class attributes
Configuration_v2.register_names += [_name]
Configuration_v2.bit_map[_name] = _bit_range
Configuration_v2.register_map[_name] = range(_bit_range[0]//8, max(_bit_range[1]//8,_bit_range[0]//8+1))
# Create properties
_prop, _prop_data = _prop_formula(_name, Configuration_v2.register_map[_name],
range(*Configuration_v2.bit_map[_name]), *_formula_args)
setattr(Configuration_v2, _name, _prop)
setattr(Configuration_v2, _name+'_data', _prop_data)
# Create a look up table from register address to names
Configuration_v2.register_map_inv = OrderedDict()
for register_name, register_addr_range in Configuration_v2.register_map.items():
for register_addr in register_addr_range:
try:
Configuration_v2.register_map_inv[register_addr] += [register_name]
except KeyError:
Configuration_v2.register_map_inv[register_addr] = [register_name]