class_name sch_3 extends Node ## Модуль Прибора Щ3 const ONLINE_TIMEOUT: int = 5000 ## Время ожидания данных const REQUEST_PERIOD: int = 1000 ## Переиод запроса, мс ## Представление прибора Щ3 class Sch3 extends unit.Unit: var mb_addr: = 0 ## Адрес устройства Modbus. var cmd_state: = CmdState.DONE ## Состояние выполнения текущей команды. var tick_rx: = 0 ## Время приёма крайнего сообщения. var tick_tx: = 0 ## Время отправки крайнего сообщения. var mb_data: Dictionary = {} ## Буфер для записи в регистры модбас static var json_conv: = JSON.new() signal resp_input(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов. signal resp_holding(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения. signal resp_write() ## Вызывается при получении подтверждения, что команда записи выполнена signal info_received(msg: String) ## Вызывается при получении информационного сообщения. signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации. func _init(nm: String, u: int = 0): mb_addr = u name = nm ## Изменяет состояние. Вызывать периодически.[br] ## [param tick] - Текущщее время в мс.[br] ## Возвращает [b]Error.OK[/b] - если данные готовы для отправки.[br] ## Возвращает [b]Error.ERR_BUSY[/b] - если данных для отправки нет.[br] func process(tick: int) -> Error: if online and ((tick - rx_tick) > ONLINE_TIMEOUT): online = false emit_signal('line_changed', self) if cmd_state == CmdState.WAIT: if (tick - tx_tick) > ONLINE_TIMEOUT: cmd_state = CmdState.FAIL emit_signal('command_fail', self) var rc = Error.ERR_BUSY if cmd_state == CmdState.SEND: tx_tick = tick cmd_state = CmdState.WAIT rc = Error.OK return rc ## Производит разбор принятых данных. Вызывать при приёме данных на сокете.[br] ## [param data] - Данные принятые на сокете.[br] ## [param tick] - Текущщее время в мс.[br] func parse(message: Dictionary, tick: int) -> bool: rx_tick = tick if not online: online = true emit_signal('line_changed', self) if message.has('code') and message.has('data'): var rc: = true var message_code = message['code'] var message_data = message['data'] match message_code: 'resp_holding', 'resp_input': var addr = int(message_data[0]) var regs = message_data.slice(1) for i in regs.size(): regs[i] = int(regs[i]) emit_signal(message_code, addr, regs) 'resp_write': emit_signal(message_code) '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) return true ## Отправляет команду "записать в регистры".[br] ## [param addr] - Начальный адрес регистров.[br] ## [param count] - Данные для записи в регистры от начального адреса.[br] func write(addr: int, data: Array) -> bool: if cmd_state != CmdState.DONE: return false mb_data = {'code': 'write', 'data': [addr] + data, 'unit': mb_addr} 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 mb_data = {'code': 'read_holding', 'data': [addr, count], 'unit': mb_addr} 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 mb_data = {'code': 'read_input', 'data': [addr, count], 'unit': mb_addr} cmd_state = CmdState.SEND return true ## Принимает результат команды "читать регистры хранения".[br] ## [param return_code] - Код выполнения команды.[br] ## [param base_addr] - Начальный адрес регистров.[br] ## [param data] - Данные прочитанные из регистров.[br] ## [param tick] - Время приёма пакета.[br] func on_read(return_code, base_addr, data): var tick = Time.get_ticks_msec() var msg: Dictionary if return_code == 0: msg['code'] = 'resp_holding' msg['data'] = [base_addr] + data else: msg['code'] = 'exception' parse(msg, tick) ## Принимает результат команды "читать регистры входов".[br] ## [param return_code] - Код выполнения команды.[br] ## [param base_addr] - Начальный адрес регистров.[br] ## [param data] - Данные прочитанные из регистров.[br] ## [param tick] - Время приёма пакета.[br] func on_read_input(return_code, base_addr, data): var tick = Time.get_ticks_msec() var msg: Dictionary if return_code == 0: msg['code'] = 'resp_input' msg['data'] = [base_addr] + data else: msg['code'] = 'exception' parse(msg, tick) ## Принимает результат команды "записать в регистры".[br] ## [param return_code] - Код выполнения команды.[br] ## [param base_addr] - Начальный адрес регистров.[br] ## [param data] - Данные прочитанные из регистров.[br] ## [param tick] - Время приёма пакета.[br] func on_write(return_code, _base_addr, data): var tick = Time.get_ticks_msec() var msg: Dictionary msg['data'] = 'resp_write' if return_code == 0: msg['code'] = 'resp_write' else: msg['code'] = 'exception' parse(msg, tick)