class_name sch_3 extends Node const ONLINE_TIMEOUT: int = 5000 ## Время ожидания данных const REQUEST_PERIOD: int = 3000 ## Переиод запроса, мс class Sch3 extends unit.Unit: ## Состояние автомата выполнения команды. enum CmdState { DONE, ## Команда выполнена. FAIL, ## Команда не выполнена. SEND, ## Буфер готов для отправки. WAIT ## Ожидание выполнения. } var unit: = 1 ## Адрес устройства Modbus. var cmd_state: = CmdState.DONE ## Состояние выполнения текущей команды. var tick_rx: = 0 ## Время приёма крайнего сообщения. var tick_tx: = 0 ## Время отправки крайнего сообщения. static var json_conv: = JSON.new() signal responce_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения. signal info_received(msg: String) ## Вызывается при получении информационного сообщения. signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации. func _init(nm: String, u: int = 1): unit = u name = nm ## Изменяет состояние. Вызывать периодически.[br] ## [param tick] - Текущщее время в мс.[br] func process(tick: int): if online and ((tick - rx_tick) > ONLINE_TIMEOUT): online = false emit_signal('line_changed', self) if cmd_state == CmdState.WAIT: cmd_state = CmdState.FAIL emit_signal('command_fail', self) var rc = Error.ERR_BUSY if (tick - tx_tick) > REQUEST_PERIOD: if read_input(0, 4): tx_tick = tick cmd_state = CmdState.WAIT rc = Error.OK return rc ## Производит разбор принятых данных. Вызывать при приёме данных на сокете.[br] ## [param data] - Данные принятые на сокете.[br] ## [param tick] - Текущщее время в мс.[br] func parse(data: PackedByteArray, tick: int) -> bool: rx_tick = tick if not online: online = true emit_signal('line_changed', self) var utf8_data = data.get_string_from_utf8() if Error.OK == json_conv.parse(utf8_data): emit_signal('data_received') var message: Dictionary = json_conv.get_data() if message.has('code') and message.has('data'): var rc: = true var message_code = message['code'] var message_data = message['data'] match message_code: 'response': var addr = message_data[0] var regs = message_data.slice(1) emit_signal('responce_received', addr, regs) rc = true 'info': var msg = message['data'] emit_signal('info_received', msg) 'exception': var msg = message['data'] cmd_state = CmdState.FAIL emit_signal('except_received', msg) rc = false _: var msg: String = 'код команды \"%s\" - не распознан' % message_code cmd_state = CmdState.FAIL emit_signal('parse_failed', msg) rc = false if (cmd_state == CmdState.WAIT) and rc: cmd_state = CmdState.DONE emit_signal('command_done') elif (cmd_state == CmdState.WAIT) and (not rc): cmd_state = CmdState.FAIL emit_signal('command_fail', self) else: var message = json_conv.get_error_message() emit_signal('parse_failed', message) return true ## Отправляет команду "записать в регистры".[br] ## [param addr] - Начальный адрес регистров.[br] ## [param count] - Данные для записи в регистры от начального адреса.[br] func write(addr: int, data: Array) -> bool: if cmd_state != CmdState.DONE: return false var json_dict = {'code': 'write', 'data': [addr] + data} tx_data = JSON.stringify(json_dict).to_utf8_buffer() cmd_state = CmdState.SEND return true ## Отправляет команду "читать регистры хранения".[br] ## [param addr] - Начальный адрес регистров.[br] ## [param count] - Количество регистров от начального адреса.[br] func read_holding(addr: int, count: int = 1) -> bool: if cmd_state != CmdState.DONE: return false var json_dict = {'code': 'read_holding', 'data': [addr, count]} tx_data = JSON.stringify(json_dict).to_utf8_buffer() cmd_state = CmdState.SEND return true ## Отправляет команду "читать регистры входов".[br] ## [param addr] - Начальный адрес регистров.[br] ## [param count] - Количество регистров от начального адреса.[br] func read_input(addr: int, count: int = 1) -> bool: if cmd_state != CmdState.DONE: return false var json_dict = {'code': 'read_input', 'data': [addr, count]} tx_data = JSON.stringify(json_dict).to_utf8_buffer() cmd_state = CmdState.SEND return true