Files
uarep-ctl/scripts/sch3.gd
2025-11-14 13:23:15 +03:00

177 lines
7.5 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class_name sch_3 extends Node
const ONLINE_TIMEOUT = 5000
## Представление прибора Щ3
class Sch3 extends unit.Unit:
enum Sch3Fsm {
READ_INPUT,
READ_HOLDING,
WRITE,
CONNECT,
IDLE,
DISCONNECT }
var step_fsm: Sch3Fsm = Sch3Fsm.CONNECT
var base_input_address: int = 0
var regs_input_count: int = 5
var base_holding_address: int = 0
var regs_holding_count: int = 0
var request_period: int = 300
var reconnect_period: int = ONLINE_TIMEOUT
var reconnect_failed: bool = false
var write_stack: Array
var tick_fsm: int = 0
var mbc: = ModbusClientRtu.new()
var tick_fsm_delta: = reconnect_period
var port: String
var params: Array
func try_disconnect():
mbc.thread_stop()
mbc.queue_clear()
mbc.flush()
mbc.close()
func try_connect() -> bool:
var rc: = mbc.open(port, params[0], params[1], params[2], params[3], params[4])
if rc != Error.OK: # TODO: убрать это отсюда (неуместный вывод сообщения)
if not reconnect_failed:
log.error('%s: невозможно открыть \"%s\" %s' % [name, port, params])
reconnect_failed = true
return false
if reconnect_failed: # TODO: убрать это отсюда (неуместный вывод сообщения)
log.warning('%s: открыто после сбоя \"%s\" %s' % [name, port, params])
reconnect_failed = false
mbc.set_response_timeout(params[5])
mbc.thread_run()
return true
func push_write_holding(regs: Dictionary):
var keys: = regs.keys()
keys.sort()
var data: = []
for k in keys:
data.append(regs[k])
write_stack.append([keys[0], data])
func _on_timeout(tick: int) -> void:
if step_fsm == Sch3Fsm.WRITE:
while write_stack.size():
var write_command = write_stack.pop_front()
mbc.request_write(write_command[0], write_command[1])
cmd_state = CmdState.WAIT
tx_tick = tick
step_fsm = Sch3Fsm.READ_INPUT
elif step_fsm == Sch3Fsm.READ_INPUT:
mbc.request_read_input(base_input_address, regs_input_count)
cmd_state = CmdState.WAIT
tx_tick = tick
step_fsm = Sch3Fsm.WRITE
elif step_fsm == Sch3Fsm.CONNECT:
try_disconnect()
try_connect()
mbc.request_read_input(base_input_address, regs_input_count)
cmd_state = CmdState.WAIT
tx_tick = tick
elif step_fsm == Sch3Fsm.DISCONNECT:
try_disconnect()
step_fsm = Sch3Fsm.IDLE
elif step_fsm == Sch3Fsm.IDLE:
pass
signal write (addr: int, data: Array) ## Вызывается при получении сообщения подтверждения записи
signal read (addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов.
signal read_input (addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения.
signal error(msg: String) ## Вызывается при получении сообщения об исключительной ситуации.
func _init(unit_name: String):
name = unit_name
mbc.connect('read', on_read)
mbc.connect('read_input', on_read_input)
mbc.connect('write', on_write)
ProjectSettings.connect('settings_changed', _on_settings_changed)
func _on_settings_changed():
var external_ctl = ProjectSettings.get_setting('application/config/Внешнее управление', false)
if external_ctl and (step_fsm not in [Sch3Fsm.DISCONNECT, Sch3Fsm.IDLE]):
step_fsm = Sch3Fsm.DISCONNECT
elif (not external_ctl) and (step_fsm in [Sch3Fsm.DISCONNECT, Sch3Fsm.IDLE]):
var unit_sch3 = network.get_unit_instance('уарэп-щ3')
var unit_prof = ProjectSettings.get_setting('application/config/%s' % unit_sch3.name)
if unit_prof:
unit_sch3.port = unit_prof[0]
unit_sch3.params = unit_prof.slice(1, -1)
step_fsm = Sch3Fsm.CONNECT
func parse(return_code: Error, base_addr: int, data: Array, code: String):
if return_code == Error.OK:
rx_tick = Time.get_ticks_msec()
if cmd_state == CmdState.WAIT:
cmd_state = CmdState.DONE
emit_signal('command_done', self)
emit_signal(code, base_addr, data)
if not online:
online = true
emit_signal('line_changed', self)
step_fsm = Sch3Fsm.READ_INPUT
tick_fsm_delta = request_period
else:
if cmd_state == CmdState.WAIT:
cmd_state = CmdState.FAIL
if online:
emit_signal('command_fail', self)
emit_signal('error', [code, return_code, base_addr, data])
## Изменяет состояние. Вызывается периодически.[br]
## [param tick] - Текущее время в мс.[br]
## Возвращает [b]Error.OK[/b] - если данные готовы для отправки.[br]
## Возвращает [b]Error.ERR_BUSY[/b] - если данных для отправки нет.[br]
func process(tick: int) -> Error:
if online:
if (tick - rx_tick) > ONLINE_TIMEOUT:
online = false
if cmd_state == CmdState.WAIT:
cmd_state = CmdState.FAIL
emit_signal('command_fail', self)
emit_signal('line_changed', self)
if step_fsm != Sch3Fsm.IDLE:
step_fsm = Sch3Fsm.CONNECT
tick_fsm_delta = reconnect_period
if (tick - tick_fsm) > tick_fsm_delta:
tick_fsm = tick
_on_timeout(tick)
return Error.ERR_BUSY
## Принимает результат команды "читать регистры хранения".[br]
## [param return_code] - Код выполнения команды.[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Данные прочитанные из регистров.[br]
func on_read(return_code: Error, base_addr: int, data: Array):
parse(return_code, base_addr, data, 'read')
## Принимает результат команды "читать регистры входов".[br]
## [param return_code] - Код выполнения команды.[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Данные прочитанные из регистров.[br]
func on_read_input(return_code: Error, base_addr: int, data: Array):
parse(return_code, base_addr, data, 'read_input')
## Принимает результат команды "записать в регистры".[br]
## [param return_code] - Код выполнения команды.[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Данные прочитанные из регистров.[br]
func on_write(return_code: Error, base_addr: int, data: Array):
parse(return_code, base_addr, data, 'write')