"""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])