Add range validator
This commit is contained in:
parent
8a5700b44e
commit
f1fad2d16b
|
@ -24,19 +24,20 @@ _log = getLogger(__name__)
|
||||||
del getLogger
|
del getLogger
|
||||||
|
|
||||||
from copy import copy as _copy
|
from copy import copy as _copy
|
||||||
|
import math
|
||||||
|
|
||||||
from .common import (
|
from .common import (
|
||||||
NamedInt as _NamedInt,
|
NamedInt as _NamedInt,
|
||||||
NamedInts as _NamedInts,
|
NamedInts as _NamedInts,
|
||||||
bytes2int as _bytes2int,
|
bytes2int as _bytes2int,
|
||||||
|
int2bytes as _int2bytes,
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
KIND = _NamedInts(toggle=0x01, choice=0x02, range=0x12)
|
KIND = _NamedInts(toggle=0x01, choice=0x02, range=0x04)
|
||||||
|
|
||||||
class Setting(object):
|
class Setting(object):
|
||||||
"""A setting descriptor.
|
"""A setting descriptor.
|
||||||
|
@ -81,6 +82,14 @@ class Setting(object):
|
||||||
|
|
||||||
return self._validator.choices if self._validator.kind & KIND.choice else None
|
return self._validator.choices if self._validator.kind & KIND.choice else None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def range(self):
|
||||||
|
assert hasattr(self, '_value')
|
||||||
|
assert hasattr(self, '_device')
|
||||||
|
|
||||||
|
if self._validator.kind == KIND.range:
|
||||||
|
return (self._validator.min_value, self._validator.max_value)
|
||||||
|
|
||||||
def read(self, cached=True):
|
def read(self, cached=True):
|
||||||
assert hasattr(self, '_value')
|
assert hasattr(self, '_value')
|
||||||
assert hasattr(self, '_device')
|
assert hasattr(self, '_device')
|
||||||
|
@ -356,3 +365,36 @@ class ChoicesValidator(object):
|
||||||
raise ValueError("invalid choice %r" % new_value)
|
raise ValueError("invalid choice %r" % new_value)
|
||||||
assert isinstance(choice, _NamedInt)
|
assert isinstance(choice, _NamedInt)
|
||||||
return choice.bytes(self._bytes_count)
|
return choice.bytes(self._bytes_count)
|
||||||
|
|
||||||
|
class RangeValidator(object):
|
||||||
|
__slots__ = ('min_value', 'max_value', 'flag', '_bytes_count', 'needs_current_value')
|
||||||
|
|
||||||
|
kind = KIND.range
|
||||||
|
|
||||||
|
"""Translates between integers and a byte sequence.
|
||||||
|
:param min_value: minimum accepted value (inclusive)
|
||||||
|
:param max_value: maximum accepted value (inclusive)
|
||||||
|
:param bytes_count: the size of the derived byte sequence. If None, it
|
||||||
|
will be calculated from the range."""
|
||||||
|
def __init__(self, min_value, max_value, bytes_count=None):
|
||||||
|
assert max_value > min_value
|
||||||
|
self.min_value = min_value
|
||||||
|
self.max_value = max_value
|
||||||
|
self.needs_current_value = False
|
||||||
|
|
||||||
|
self._bytes_count = math.ceil(math.log(max_value + 1, 256))
|
||||||
|
if bytes_count:
|
||||||
|
assert self._bytes_count <= bytes_count
|
||||||
|
self._bytes_count = bytes_count
|
||||||
|
assert self._bytes_count < 8
|
||||||
|
|
||||||
|
def validate_read(self, reply_bytes):
|
||||||
|
reply_value = _bytes2int(reply_bytes[:self._bytes_count])
|
||||||
|
assert reply_value >= self.min_value, "%s: failed to validate read value %02X" % (self.__class__.__name__, reply_value)
|
||||||
|
assert reply_value <= self.max_value, "%s: failed to validate read value %02X" % (self.__class__.__name__, reply_value)
|
||||||
|
return reply_value
|
||||||
|
|
||||||
|
def prepare_write(self, new_value, current_value=None):
|
||||||
|
if new_value < self.min_value or new_value > self.max_value:
|
||||||
|
raise ValueError("invalid choice %r" % new_value)
|
||||||
|
return _int2bytes(new_value, self._bytes_count)
|
||||||
|
|
Loading…
Reference in New Issue