Add range validator

This commit is contained in:
Javier Torres 2016-06-09 19:39:43 +02:00
parent 8a5700b44e
commit f1fad2d16b
1 changed files with 44 additions and 2 deletions

View File

@ -24,19 +24,20 @@ _log = getLogger(__name__)
del getLogger
from copy import copy as _copy
import math
from .common import (
NamedInt as _NamedInt,
NamedInts as _NamedInts,
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):
"""A setting descriptor.
@ -81,6 +82,14 @@ class Setting(object):
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):
assert hasattr(self, '_value')
assert hasattr(self, '_device')
@ -356,3 +365,36 @@ class ChoicesValidator(object):
raise ValueError("invalid choice %r" % new_value)
assert isinstance(choice, _NamedInt)
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)