68 lines
3.6 KiB
Python
68 lines
3.6 KiB
Python
"""ctypes port of the shared wave generator RTU codec."""
|
|
import ctypes as C
|
|
from .signal_reconstruction import library
|
|
|
|
class WaveProtocol:
|
|
def __init__(self, address=16):
|
|
if not 1 <= address <= 247:
|
|
raise ValueError("Адрес должен быть 1…247")
|
|
self.address = address
|
|
self.lib = library()
|
|
p = C.POINTER(C.c_uint8)
|
|
self.lib.set_wave_request.argtypes = [C.c_uint, C.c_uint, C.c_uint, C.c_uint, p, C.c_size_t]
|
|
self.lib.set_wave_request.restype = C.c_size_t
|
|
self.lib.set_wave_response.argtypes = [p, p, C.c_size_t, C.POINTER(C.c_uint16), C.c_size_t]
|
|
self.lib.set_wave_response.restype = C.c_int
|
|
self.lib.set_wave_block_request.argtypes = [C.c_uint, C.c_uint, C.POINTER(C.c_uint16), C.c_size_t, p, C.c_size_t]
|
|
self.lib.set_wave_block_request.restype = C.c_size_t
|
|
self.lib.set_wave_block_response.argtypes = [p, C.c_size_t, p, C.c_size_t, C.POINTER(C.c_uint16), C.c_size_t]
|
|
self.lib.set_wave_block_response.restype = C.c_int
|
|
|
|
def block_request(self, index, values=None, count=None):
|
|
count = len(values) if values is not None else count
|
|
if count is None or not 1 <= count <= 120:
|
|
raise ValueError("Блок должен содержать 1…120 отсчётов")
|
|
if values is not None and any(not 0 <= value <= 4095 for value in values):
|
|
raise ValueError("Коды ЦАП должны быть 0…4095")
|
|
samples = (C.c_uint16 * count)(*values) if values is not None else None
|
|
output = (C.c_uint8 * 249)()
|
|
size = self.lib.set_wave_block_request(self.address, index, samples, count, output, len(output))
|
|
if not size:
|
|
raise ValueError("Недопустимый блок генератора")
|
|
return bytes(output[:size])
|
|
|
|
def block_response(self, request, reply):
|
|
words = (C.c_uint16 * 120)()
|
|
code = self.lib.set_wave_block_response((C.c_uint8 * len(request)).from_buffer_copy(request), len(request),
|
|
(C.c_uint8 * len(reply)).from_buffer_copy(reply), len(reply), words, len(words))
|
|
if code == 0:
|
|
return None
|
|
if code < 0:
|
|
raise ValueError(f"Неверный ответ блока генератора ({code})")
|
|
return tuple(words[:code])
|
|
|
|
def request(self, operation, index=0, value=0):
|
|
output = (C.c_uint8 * 8)()
|
|
if self.lib.set_wave_request(self.address, operation, index, value, output, 8) != 8:
|
|
raise ValueError("Недопустимая команда генератора")
|
|
return bytes(output)
|
|
|
|
def response(self, request, reply):
|
|
if len(request) != 8:
|
|
raise ValueError("Неверный запрос")
|
|
words = (C.c_uint16 * 8)()
|
|
code = self.lib.set_wave_response((C.c_uint8 * 8).from_buffer_copy(request),
|
|
(C.c_uint8 * len(reply)).from_buffer_copy(reply), len(reply), words, len(words))
|
|
if code == 0:
|
|
return None
|
|
if code < 0:
|
|
raise ValueError(f"Неверный ответ генератора или исключение устройства ({code})")
|
|
return tuple(words[:code])
|
|
|
|
@staticmethod
|
|
def status(words, rate_high=0):
|
|
if len(words) != 8 or words[0] != 0x5747 or words[1] not in (1, 2, 3):
|
|
raise ValueError("Устройство не поддерживает генератор WG v1/v2/v3")
|
|
return dict(version=words[1], running=bool(words[2]), rate=(rate_high << 16) | words[3], count=words[4],
|
|
received=words[5], ready=bool(words[6]), capacity=words[7])
|