Расширить общие API графиков и GAS обмена
This commit is contained in:
@@ -99,12 +99,6 @@ class TrendSignal:
|
||||
if self.source == "CAN_RAW" and not 0 <= self.byteOffset <= 6:
|
||||
raise ValueError("Word offset must be 0..6")
|
||||
|
||||
def word_value(self, word: int) -> float:
|
||||
if not 0 <= word <= 65535:
|
||||
raise ValueError("Not a 16-bit word")
|
||||
return float(word - 65536 if self.valueType == "INT16" and word >= 32768 else word)
|
||||
|
||||
|
||||
def validate_settings(settings: Mapping[str, list[TrendSignal]]) -> None:
|
||||
ids = set()
|
||||
for profile, signals in settings.items():
|
||||
@@ -178,6 +172,20 @@ class NativeTrends:
|
||||
ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint8,
|
||||
ctypes.c_uint32, ctypes.c_uint8, ctypes.c_void_p, ctypes.c_size_t]
|
||||
self.decode.restype = ctypes.c_int32
|
||||
self._word = library.set_trend_word_value
|
||||
self._word.argtypes = [ctypes.c_uint16, ctypes.c_uint8]
|
||||
self._word.restype = ctypes.c_int32
|
||||
self._watch_request = library.set_trend_watch_request
|
||||
self._watch_request.argtypes = [ctypes.c_uint16, ctypes.POINTER(ctypes.c_uint16),
|
||||
ctypes.c_size_t, ctypes.c_void_p, ctypes.c_size_t]
|
||||
self._watch_request.restype = ctypes.c_size_t
|
||||
self._watch_ack = library.set_trend_watch_ack
|
||||
self._watch_ack.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_uint16, ctypes.c_size_t]
|
||||
self._watch_ack.restype = ctypes.c_int
|
||||
self._watch_decode = library.set_trend_watch_decode
|
||||
self._watch_decode.argtypes = [ctypes.c_void_p, ctypes.c_size_t,
|
||||
ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint16), ctypes.c_size_t]
|
||||
self._watch_decode.restype = ctypes.c_int
|
||||
|
||||
def can_value(self, signal: TrendSignal, can_id: int, flags: int, data: bytes) -> float | None:
|
||||
if signal.source not in ("CAN_GAS", "CAN_RAW"):
|
||||
@@ -191,3 +199,33 @@ class NativeTrends:
|
||||
signal.byteOffset, signal.extended, signal.valueType == "INT16", can_id, flags,
|
||||
payload, len(data))
|
||||
return None if value == -2147483648 else float(value)
|
||||
|
||||
def word_value(self, signal: TrendSignal, word: int) -> float:
|
||||
if not 0 <= word <= 65535:
|
||||
raise ValueError("Not a 16-bit word")
|
||||
return float(self._word(word, signal.valueType == "INT16"))
|
||||
|
||||
def watch_request(self, period_ms: int, addresses: list[int]) -> bytes:
|
||||
if not 0 <= period_ms <= 65535 or len(addresses) > MAX_SIGNALS or any(
|
||||
type(address) is not int or not 0 <= address <= 65535 for address in addresses):
|
||||
raise ValueError("Invalid GAS watch request")
|
||||
source = (ctypes.c_uint16 * len(addresses))(*addresses)
|
||||
output = (ctypes.c_uint8 * (4 + len(addresses) * 2))()
|
||||
size = self._watch_request(period_ms, source, len(addresses), output, len(output))
|
||||
if not size:
|
||||
raise ValueError("Invalid GAS watch request")
|
||||
return bytes(output[:size])
|
||||
|
||||
def validate_watch_ack(self, payload: bytes, period_ms: int, count: int) -> None:
|
||||
data = (ctypes.c_uint8 * len(payload)).from_buffer_copy(payload)
|
||||
if not self._watch_ack(data, len(payload), period_ms, count):
|
||||
raise ValueError("Device did not accept the complete GAS subscription")
|
||||
|
||||
def watch_values(self, payload: bytes, expected_count: int | None = None) -> tuple[int, list[int]]:
|
||||
data = (ctypes.c_uint8 * len(payload)).from_buffer_copy(payload)
|
||||
timestamp = ctypes.c_uint32()
|
||||
words = (ctypes.c_uint16 * MAX_SIGNALS)()
|
||||
count = self._watch_decode(data, len(payload), ctypes.byref(timestamp), words, MAX_SIGNALS)
|
||||
if count < 0 or expected_count is not None and count != expected_count:
|
||||
raise ValueError("Invalid GAS watch data")
|
||||
return timestamp.value, list(words[:count])
|
||||
|
||||
Reference in New Issue
Block a user