ltr390uv

Форк
0
/
bitfield.py 
143 строки · 7.1 Кб
1
# micropython
2
# MIT license
3
# Copyright (c) 2024 Roman Shevchik   goctaprog@gmail.com
4
"""Представление битового поля"""
5
from collections import namedtuple
6
from sensor_pack_2.base_sensor import check_value, get_error_str
7

8
# информация о битовом поле в виде именованного кортежа
9
# name: str  - имя
10
# position: range - место в номерах битах. position.start = первый бит, position.stop-1 - последний бит
11
# valid_values: range - диапазон допустимых значений, если проверка не требуется, следует передать None
12
bit_field_info = namedtuple("bit_field_info", "name position valid_values")
13

14

15
'''
16
def _bitmask(bit_rng: range) -> int:
17
    """возвращает битовую маску по занимаемым битам"""
18
    res = 0
19
    for i in bit_rng:
20
        res |= 1 << i
21
    return res
22
'''
23

24

25
def _bitmask(bit_rng: range) -> int:
26
    """возвращает битовую маску по занимаемым битам"""
27
    # if bit_rng.step < 0 or bit_rng.start <= bit_rng.stop:
28
    #    raise ValueError(f"_bitmask: {bit_rng.start}; {bit_rng.stop}; {bit_rng.step}")
29
    return sum(map(lambda x: 2 ** x, bit_rng))
30

31

32
class BitFields:
33
    """Хранилище информации о битовых полях с доступом по индексу.
34
    _source - кортеж именованных кортежей, описывающих битовые поля;"""
35
    def __init__(self, fields_info: tuple[bit_field_info, ...]):
36
        self._fields_info = fields_info
37
        self._idx = 0
38
        # имя битового поля, которое будет параметром у методов get_value/set_value
39
        self._active_field_name = fields_info[0].name
40
        # значение, из которого будут извлекаться битовые поля
41
        self._source_val = 0
42

43
    def _get_field(self, field: [str, int, None]) -> bit_field_info:
44
        """для внутреннего использования"""
45
        return self.__getitem__(field if field else self.field_name)
46

47
    def _get_source(self, source: [int, None]) -> int:
48
        return source if source else self._source_val
49

50
    @property
51
    def source(self) -> int:
52
        """значение, из которого будут извлекаться/в котором будут изменятся битовые поля"""
53
        return self._source_val
54

55
    @source.setter
56
    def source(self, value):
57
        """значение, из которого будут извлекаться/изменятся битовые поля"""
58
        self._source_val = value
59

60
    @property
61
    def field_name(self) -> str:
62
        """имя битового поля, значение которого извлекается/изменяется методами get_value/set_value, если их
63
        параметр field is None"""
64
        return self._active_field_name
65

66
    @field_name.setter
67
    def field_name(self, value):
68
        """имя битового поля, значение которого извлекается/изменяется методами get_value/set_value, если их
69
        параметр field is None"""
70
        self._active_field_name = value
71

72
    def _by_name(self, name: str) -> [bit_field_info, None]:
73
        """возвращает информацию о битовом поле по его имени (поле name именованного кортежа) или None"""
74
        items = self._fields_info
75
        for item in items:
76
            if name == item.name:
77
                return item
78

79
    def __len__(self) -> int:
80
        return len(self._fields_info)
81

82
    def __getitem__(self, key: [int, str]) -> [bit_field_info, None]:
83
        """возвращает информацию о битовом поле по его имени/индексу или None"""
84
        fi = self._fields_info
85
        if isinstance(key, int):
86
            return fi[key]
87
        if isinstance(key, str):
88
            return self._by_name(key)
89

90
#    def get_field_value(self, source: int, field: [str, int, None] = None, validate: bool = False) -> int:
91
#        """возвращает значение битового поля, по его имени, из source."""
92
#        item = self._get_field(field=field)
93
#        pos = item.position
94
#        bitmask = _bitmask(pos)
95
#        val = (source & bitmask) >> pos.start  # выделение маской битового диапазона и его сдвиг вправо
96
#        if item.valid_values and validate:
97
#            raise NotImplemented("get_value validate")
98
#        return val
99

100
    def set_field_value(self, value: int, source: [int, None] = None, field: [str, int, None] = None,
101
                        validate: bool = True) -> int:
102
        """Записывает value в битовый диапазон, определяемый параметром field, в source.
103
        Возвращает значение с измененным битовым полем.
104
        Если field is None, то имя поля берется из свойства self._active_field_name.
105
        Если source is None, то значение поля, подлежащее изменению, изменяется в свойстве self._source_val"""
106
        item = self._get_field(field=field)
107
        rng = item.valid_values
108
        if rng and validate:
109
            check_value(value, rng, get_error_str("value", value, rng))
110
        pos = item.position
111
        bitmask = _bitmask(pos)
112
        src = self._get_source(source) & ~bitmask  # чистка битового диапазона
113
        src |= (value << pos.start) & bitmask  # установка битов в заданном диапазоне
114
        # print(f"DBG:set_field_value: {value}; {source}; {field}")
115
        if source is None:
116
            self._source_val = src
117
            # print(f"DBG:set_field_value: self._source_val: {self._source_val}")
118
        return src
119

120
    def get_field_value(self, validate: bool = False) -> [int, bool]:
121
        """возвращает значение битового поля, по его имени(self.field_name), из self.source."""
122
        item = self._get_field(field=self.field_name)
123
        pos = item.position
124
        bitmask = _bitmask(pos)
125
        val = (self.source & bitmask) >> pos.start  # выделение маской битового диапазона и его сдвиг вправо
126
        if item.valid_values and validate:
127
            raise NotImplemented("get_value validate")
128
        if 1 == len(pos):
129
            return 0 != val     # bool
130
        return val              # int
131

132
    # протокол итератора
133
    def __iter__(self):
134
        return self
135

136
    def __next__(self) -> bit_field_info:
137
        ss = self._fields_info
138
        try:
139
            self._idx += 1
140
            return ss[self._idx - 1]
141
        except IndexError:
142
            self._idx = 0   # для возможности выполнения повторной итерации!
143
            raise StopIteration
144

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.