Files
uarep-ctl/scenes/pribor-uyep/sch3-view.gd

185 lines
8.8 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.

@tool
class_name sch3_view
extends 'res://scenes/контроль/элемент-я.gd'
## Дополнение №1 к протоколу №120-23900-18
## информационного взаимодействия изделия 5П-28
## с аппаратурой УА-РЭП на кораблях проекта 23900
@export var base_input_address: = 0 ## Базовый адрес регистров входов
@export var base_holding_address: = 0 ## Базовый адрес регистров хранения
@export var regs_input_count: = 5 ## Количество регистров входов
@export var regs_holding_count: = 4 ## Количество регистров хранения
@export var modbus_address: = 3 ## Адрес устройства на шине Modbus
@export var request_period: = 1.0 ## Период отправки команд на шину Modbus
var regs_input: = {} ## Регистры входные
var regs_holding: = {} ## Регистры хранения
var write_stack: = [] ## Стек команд для записи
var holding_stack: = [] ## Стек команд для чтения регистров хранения
var input_stack: = [] ## Стек команд для чтения регистров входов
var read_step: = 0
var switches_sync: = false
var timer = Timer.new()
class StackItem:
var addr: = 0
var data = null
func _init(a: int, d): addr = a; data = d
func _to_string() -> String: return '%s: %s' % [addr, data]
func on_data_received(_data: PackedByteArray): pass
## Обработчик таймера
func _on_timeout(unit_sch3) -> void:
if write_stack.size():
var ad = write_stack.pop_front()
if not unit_sch3.write(ad.addr, ad.data):
write_stack.push_back(ad)
if (read_step == 0) and (input_stack.size() == 0):
var ad = StackItem.new(base_input_address, regs_input_count)
input_stack.push_back(ad)
elif (read_step == 1) and (holding_stack.size() == 0):
var ad = StackItem.new(base_holding_address, regs_holding_count)
holding_stack.push_back(ad)
if input_stack.size():
var ad = input_stack.pop_front()
if not unit_sch3.read_input(ad.addr, ad.data):
input_stack.push_back(ad)
if holding_stack.size():
var ad = holding_stack.pop_front()
if not unit_sch3.read_holding(ad.addr, ad.data):
holding_stack.push_back(ad)
read_step += 1
read_step %= 2
## Вызывается при изменении состояния выключателя[br]
## [param val] - Состояние выключателя[br]
## [param meta] - Адреса регистров и индексы битов назначенных выключателю[br]
func on_toggled_switch(val: bool, meta: Array):
var on_addr = meta[0]
var on_bit = meta[1]
var off_addr = meta[2]
var off_bit = meta[3]
if regs_holding.has(on_addr) and regs_holding.has(off_addr):
regs_holding[on_addr] = tools.set_bit(regs_holding[on_addr], on_bit, val)
regs_holding[off_addr] = tools.set_bit(regs_holding[off_addr], off_bit, not val)
push_write_holding()
## Заносит в очередь команду чтения регистров хранения
func push_write_holding():
var regs_data: = []
var keys = regs_holding.keys()
keys.sort() # Ключи в словаре хранятся не упорядочено
for addr in keys:
regs_data.append(regs_holding[addr])
write_stack.push_back(StackItem.new(keys[0], regs_data))
func _ready() -> void:
if Engine.is_editor_hint(): return
var unit_key = settings.get_unit_key(unit_name)
var unit_sch3 = network.units[unit_key]
unit_sch3.mb_addr = modbus_address
var items = get_tree().get_nodes_in_group('bits_items_switch')
for item in items:
var meta = item.get_meta('bits')
item.connect('toggled', on_toggled_switch.bind(meta))
item.disabled = true
unit_sch3.connect('resp_input', on_resp_input)
unit_sch3.connect('resp_holding', on_resp_holding)
unit_sch3.connect('command_fail', on_command_fail)
timer.connect('timeout', _on_timeout.bind(unit_sch3))
add_child(timer)
timer.start(request_period)
func on_command_fail(unit_sch3):
unit_sch3.cmd_state = unit.Unit.CmdState.DONE
timer.stop()
## Вызывается, когда состояния прибора Щ3 "на связи" изменяется[br]
## [param unit_sch3] - Экземпляр представления прибора Щ3
func on_line_changed(unit_sch3: sch_3.Sch3):
for item in get_tree().get_nodes_in_group('bits_items_good'):
item.texture = textures[STATE_VAL.NONE]
if not unit_sch3.online:
for item in get_tree().get_nodes_in_group('bits_items_switch'):
item.disabled = true
regs_holding.clear()
regs_input.clear()
write_stack.clear()
input_stack.clear()
holding_stack.clear()
switches_sync = false
$margin/vbox/grid1/lbl_freq.text = '<нет данных>'
$margin/vbox/grid1/state_freq.texture = textures[STATE_VAL.NONE]
$margin/vbox/grid/state.texture = textures[STATE_VAL.NONE]
else:
timer.start(request_period)
## Вызывается по сигналу "приняты данные чтения регистров хранения"[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Массив значений прочитанных из регистров.
func on_resp_holding(base_addr: int, data: Array):
if (base_addr != base_holding_address) or (data.size() < regs_holding_count):
return
for i in data.size():
regs_holding[base_addr + i] = data[i]
# Разрешить работу выключателей только когда прочитано их реальное состояние
if not switches_sync:
switches_sync = true
for item in get_tree().get_nodes_in_group('bits_items_switch'):
var bits = item.get_meta('bits')
var byte0: int = bits[0] # Адрес регистра
var bit0: int = bits[1] # Индекс бита
var byte1: int = bits[2] # Адрес регистра
var bit1: int = bits[3] # Индекс бита
var val0: bool = regs_holding[byte0] & (1 << bit0) > 0
item.button_pressed = val0
item.disabled = false
regs_holding[byte1] = tools.set_bit(regs_holding[byte1], bit1, not val0)
push_write_holding()
## Вызывается по сигналу "приняты данные чтения регистров входов".[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Массив значений прочитанных из регистров.[br]
func on_resp_input(base_addr: int, data: Array):
if (base_addr != base_input_address) or (data.size() < regs_input_count):
return
# "Для контроля состояния управляющего элемента подачи электроэнергии на приборы ..."
# "Для контроля подачи электроэнергии на приборы ..."
# Таблицы 3.13 и 3.14. Ecли значения соответствующих битов в этих
# регистрах равны, то "исправно".
var items = get_tree().get_nodes_in_group('bits_items_good')
for i in data.size():
regs_input[base_addr + i] = data[i]
# Таблица 3.15, Регистр PowerState
$margin/vbox/grid1/lbl_freq.text = '%d' % (regs_input[4] & 0x1ff)
$margin/vbox/grid1/state_freq.texture \
= textures[STATE_VAL.GOOD] if regs_input[4] & (1 << 15) \
else textures[STATE_VAL.ERROR]
var cnt_good: int = 0
for item in items:
var bits: Array = item.get_meta('bits')
var byte0: int = bits[0] # Индекс байта в данных "состояния управляющего элемента"
var bit0: int = bits[1] # Индекс бита в данных "состояния управляющего элемента"
var byte1: int = bits[2] # Индекс байта в данных "подачи электроэнергии на приборы"
var bit1: int = bits[3] # Индекс бита в данных "подачи электроэнергии на приборы"
var v = STATE_VAL.GOOD \
if (data[byte0] & (1 << bit0)) \
== (data[byte1] & (1 << bit1)) \
else STATE_VAL.ERROR
cnt_good += int(v == STATE_VAL.GOOD)
item.texture = textures[v]
state = STATE_VAL.GOOD if cnt_good == items.size() else STATE_VAL.ERROR